Dark Theme
This commit is contained in:
parent
b37ec8bca2
commit
ee1b137d0e
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
node_modules
|
||||
dist
|
||||
.cache
|
||||
.env
|
||||
src/lib/gramjs/build/
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import React, {
|
||||
FC, memo, useCallback, useEffect, useMemo, useRef, useState,
|
||||
} from '../../lib/teact/teact';
|
||||
import { withGlobal } from '../../lib/teact/teactn';
|
||||
|
||||
import {
|
||||
ApiAudio, ApiMessage, ApiVoice,
|
||||
} from '../../api/types';
|
||||
import { ISettings } from '../../types';
|
||||
|
||||
import { IS_MOBILE_SCREEN } from '../../util/environment';
|
||||
import { formatMediaDateTime, formatMediaDuration, formatPastTimeShort } from '../../util/dateFormat';
|
||||
@ -49,6 +51,10 @@ type OwnProps = {
|
||||
onDateClick?: (messageId: number, chatId: number) => void;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
theme: ISettings['theme'];
|
||||
};
|
||||
|
||||
interface ISeekMethods {
|
||||
handleStartSeek: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
handleSeek: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
@ -61,7 +67,8 @@ const MAX_SPIKES = IS_MOBILE_SCREEN ? 50 : 75;
|
||||
// This is needed for browsers requiring user interaction before playing.
|
||||
const PRELOAD = true;
|
||||
|
||||
const Audio: FC<OwnProps> = ({
|
||||
const Audio: FC<OwnProps & StateProps> = ({
|
||||
theme,
|
||||
message,
|
||||
senderTitle,
|
||||
uploadProgress,
|
||||
@ -201,8 +208,8 @@ const Audio: FC<OwnProps> = ({
|
||||
const seekHandlers = { handleStartSeek, handleSeek, handleStopSeek };
|
||||
const isOwn = isOwnMessage(message);
|
||||
const renderedWaveform = useMemo(
|
||||
() => voice && renderWaveform(voice, playProgress, isOwn, seekHandlers),
|
||||
[voice, playProgress, isOwn, seekHandlers],
|
||||
() => voice && renderWaveform(voice, playProgress, isOwn, seekHandlers, theme),
|
||||
[voice, playProgress, isOwn, seekHandlers, theme],
|
||||
);
|
||||
|
||||
const fullClassName = buildClassName(
|
||||
@ -346,7 +353,11 @@ function renderVoice(voice: ApiVoice, renderedWaveform: any, isMediaUnread?: boo
|
||||
}
|
||||
|
||||
function renderWaveform(
|
||||
voice: ApiVoice, playProgress = 0, isOwn = false, { handleStartSeek, handleSeek, handleStopSeek }: ISeekMethods,
|
||||
voice: ApiVoice,
|
||||
playProgress = 0,
|
||||
isOwn = false,
|
||||
{ handleStartSeek, handleSeek, handleStopSeek }: ISeekMethods,
|
||||
theme: ISettings['theme'],
|
||||
) {
|
||||
const { waveform, duration } = voice;
|
||||
|
||||
@ -354,14 +365,18 @@ function renderWaveform(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const fillColor = theme === 'dark' ? '#494B75' : '#CBCBCB';
|
||||
const fillOwnColor = theme === 'dark' ? '#C69C85' : '#B0DEA6';
|
||||
const progressFillColor = theme === 'dark' ? '#868DF5' : '#54a3e6';
|
||||
const progressFillOwnColor = theme === 'dark' ? '#FFFFFF' : '#53ad53';
|
||||
const durationFactor = Math.min(duration / AVG_VOICE_DURATION, 1);
|
||||
const spikesCount = Math.round(MIN_SPIKES + (MAX_SPIKES - MIN_SPIKES) * durationFactor);
|
||||
const decodedWaveform = decodeWaveform(new Uint8Array(waveform));
|
||||
const { data: spikes, peak } = interpolateArray(decodedWaveform, spikesCount);
|
||||
const { src, width, height } = renderWaveformToDataUri(spikes, playProgress, {
|
||||
peak,
|
||||
fillStyle: isOwn ? '#B0DEA6' : '#CBCBCB',
|
||||
progressFillStyle: isOwn ? '#53ad53' : '#54a3e6',
|
||||
fillStyle: isOwn ? fillOwnColor : fillColor,
|
||||
progressFillStyle: isOwn ? progressFillOwnColor : progressFillColor,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -414,4 +429,4 @@ function renderSeekline(
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(Audio);
|
||||
export default memo(withGlobal<OwnProps>((global) => ({ theme: global.settings.byKey.theme }))(Audio));
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
width: 3.375rem;
|
||||
height: 3.375rem;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(white -125%, var(--color-user));
|
||||
background: linear-gradient(var(--color-white) -125%, var(--color-user));
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
@ -109,7 +109,7 @@
|
||||
width: 0.875rem;
|
||||
height: 0.875rem;
|
||||
border-radius: 50%;
|
||||
border: 2px solid white;
|
||||
border: 2px solid var(--color-background);
|
||||
background-color: #0ac630;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
padding: 0.5rem;
|
||||
margin: 0;
|
||||
background-color: var(--background-color);
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
|
||||
&::before {
|
||||
left: .625rem;
|
||||
|
||||
@ -158,7 +158,7 @@
|
||||
}
|
||||
|
||||
&.smaller {
|
||||
--background-color: #fff;
|
||||
--background-color: var(--color-background);
|
||||
--border-radius-messages-small: .3125rem;
|
||||
|
||||
.icon-download,
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
align-items: center;
|
||||
|
||||
.MessageOutgoingStatus {
|
||||
color: var(--color-text-green);
|
||||
color: var(--color-text-meta-colored);
|
||||
margin-right: 0.1rem;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
.button-wrapper {
|
||||
padding: 0.5rem 0;
|
||||
border-top: 1px solid var(--color-borders);
|
||||
box-shadow: 0 0 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 0 2px var(--color-default-shadow);
|
||||
|
||||
button {
|
||||
display: inline-block;
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
.left {
|
||||
flex: 1;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
min-width: 15.5rem;
|
||||
max-width: 26.5rem;
|
||||
|
||||
@ -56,10 +56,19 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: rgb(230, 235, 238) url('../../assets/chat-bg.jpg') no-repeat center;
|
||||
background: no-repeat center;
|
||||
background-size: cover;
|
||||
z-index: -1;
|
||||
transform-origin: left center;
|
||||
|
||||
.theme-dark body.initial & {
|
||||
background-color: #0f0f0f;
|
||||
}
|
||||
|
||||
.theme-light body.initial &,
|
||||
body:not(.initial) & {
|
||||
background-image: url('../../assets/chat-bg.jpg');
|
||||
}
|
||||
}
|
||||
|
||||
&.with-right-column::before {
|
||||
@ -97,12 +106,12 @@
|
||||
min-width: 15.5rem;
|
||||
max-width: 26.5rem;
|
||||
border-left: 1px solid var(--color-borders);
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
}
|
||||
}
|
||||
|
||||
.blank {
|
||||
flex: 1;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ type OwnProps = {
|
||||
|
||||
type StateProps = Pick<GlobalState, 'uiReadyState'> & {
|
||||
hasCustomBackground?: boolean;
|
||||
isCustomBackgroundColor: boolean;
|
||||
isRightColumnShown?: boolean;
|
||||
};
|
||||
|
||||
@ -84,6 +85,7 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
page,
|
||||
children,
|
||||
hasCustomBackground,
|
||||
isCustomBackgroundColor,
|
||||
isRightColumnShown,
|
||||
setIsUiReady,
|
||||
}) => {
|
||||
@ -129,7 +131,8 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div
|
||||
className={buildClassName(
|
||||
'middle',
|
||||
hasCustomBackground && 'custom-bg-image',
|
||||
hasCustomBackground && !isCustomBackgroundColor && 'custom-bg-image',
|
||||
hasCustomBackground && isCustomBackgroundColor && 'custom-bg-color',
|
||||
isRightColumnShown && 'with-right-column',
|
||||
)}
|
||||
/>
|
||||
@ -149,6 +152,7 @@ export default withGlobal<OwnProps>(
|
||||
return {
|
||||
uiReadyState: global.uiReadyState,
|
||||
hasCustomBackground: Boolean(global.settings.byKey.customBackground),
|
||||
isCustomBackgroundColor: Boolean((global.settings.byKey.customBackground || '').match(/^#[a-f\d]{6,8}$/i)),
|
||||
isRightColumnShown: selectIsRightColumnShown(global),
|
||||
};
|
||||
},
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.Chat {
|
||||
--background-color: white;
|
||||
--background-color: var(--color-background);
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
@ -118,7 +118,6 @@ const LeftMain: FC<OwnProps & StateProps> = ({
|
||||
onSearchQuery={onSearchQuery}
|
||||
onSelectSettings={handleSelectSettings}
|
||||
onSelectContacts={handleSelectContacts}
|
||||
onSelectNewGroup={handleSelectNewGroup}
|
||||
onSelectArchived={handleSelectArchived}
|
||||
onReset={onReset}
|
||||
/>
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
.archived-badge {
|
||||
min-width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
margin-left: 2rem;
|
||||
margin-left: auto;
|
||||
background: var(--color-gray);
|
||||
border-radius: 0.75rem;
|
||||
padding: 0 .45rem;
|
||||
|
||||
@ -4,7 +4,7 @@ import React, {
|
||||
import { withGlobal } from '../../../lib/teact/teactn';
|
||||
|
||||
import { GlobalActions } from '../../../global/types';
|
||||
import { LeftColumnContent } from '../../../types';
|
||||
import { LeftColumnContent, ISettings } from '../../../types';
|
||||
import { ApiChat } from '../../../api/types';
|
||||
|
||||
import { IS_MOBILE_SCREEN } from '../../../util/environment';
|
||||
@ -12,6 +12,7 @@ import buildClassName from '../../../util/buildClassName';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import { isChatArchived } from '../../../modules/helpers';
|
||||
import { formatDateToString } from '../../../util/dateFormat';
|
||||
import switchTheme from '../../../util/switchTheme';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
|
||||
import DropdownMenu from '../../ui/DropdownMenu';
|
||||
@ -19,6 +20,7 @@ import MenuItem from '../../ui/MenuItem';
|
||||
import Button from '../../ui/Button';
|
||||
import SearchInput from '../../ui/SearchInput';
|
||||
import PickerSelectedItem from '../../common/PickerSelectedItem';
|
||||
import Switcher from '../../ui/Switcher';
|
||||
|
||||
import './LeftMainHeader.scss';
|
||||
|
||||
@ -28,7 +30,6 @@ type OwnProps = {
|
||||
onSearchQuery: (query: string) => void;
|
||||
onSelectSettings: () => void;
|
||||
onSelectContacts: () => void;
|
||||
onSelectNewGroup: () => void;
|
||||
onSelectArchived: () => void;
|
||||
onReset: () => void;
|
||||
};
|
||||
@ -39,11 +40,15 @@ type StateProps = {
|
||||
currentUserId?: number;
|
||||
globalSearchChatId?: number;
|
||||
searchDate?: number;
|
||||
theme: ISettings['theme'];
|
||||
animationLevel: 0 | 1 | 2;
|
||||
chatsById?: Record<number, ApiChat>;
|
||||
};
|
||||
|
||||
type DispatchProps = Pick<GlobalActions,
|
||||
'openChat'| 'openSupportChat' | 'setGlobalSearchDate' | 'setGlobalSearchChatId'>;
|
||||
'openChat'| 'openSupportChat' | 'setGlobalSearchDate' | 'setGlobalSearchChatId' | 'setSettingOption'>;
|
||||
|
||||
const ANIMATION_LEVEL_OPTIONS = [0, 1, 2];
|
||||
|
||||
const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
content,
|
||||
@ -51,7 +56,6 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
onSearchQuery,
|
||||
onSelectSettings,
|
||||
onSelectContacts,
|
||||
onSelectNewGroup,
|
||||
onSelectArchived,
|
||||
setGlobalSearchChatId,
|
||||
onReset,
|
||||
@ -60,10 +64,13 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
currentUserId,
|
||||
globalSearchChatId,
|
||||
searchDate,
|
||||
theme,
|
||||
animationLevel,
|
||||
chatsById,
|
||||
openChat,
|
||||
openSupportChat,
|
||||
setGlobalSearchDate,
|
||||
setSettingOption,
|
||||
}) => {
|
||||
const hasMenu = content === LeftColumnContent.ChatList;
|
||||
const clearedDateSearchParam = { date: undefined };
|
||||
@ -113,6 +120,28 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
openChat({ id: currentUserId });
|
||||
}, [currentUserId, openChat]);
|
||||
|
||||
const handleDarkModeToggle = useCallback((e: React.SyntheticEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
const newTheme = theme === 'light' ? 'dark' : 'light';
|
||||
|
||||
setSettingOption({
|
||||
theme: newTheme,
|
||||
customBackground: newTheme === 'dark' ? '#0F0F0F' : undefined,
|
||||
});
|
||||
switchTheme(newTheme, animationLevel > 0);
|
||||
}, [animationLevel, setSettingOption, theme]);
|
||||
|
||||
const handleAnimationLevelChange = useCallback((e: React.SyntheticEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const newLevel = animationLevel === 0 ? 2 : 0;
|
||||
ANIMATION_LEVEL_OPTIONS.forEach((_, i) => {
|
||||
document.body.classList.toggle(`animation-level-${i}`, newLevel === i);
|
||||
});
|
||||
|
||||
setSettingOption({ animationLevel: newLevel });
|
||||
}, [animationLevel, setSettingOption]);
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const isSearchFocused = Boolean(globalSearchChatId)
|
||||
@ -130,10 +159,19 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
trigger={MainButton}
|
||||
>
|
||||
<MenuItem
|
||||
icon="group"
|
||||
onClick={onSelectNewGroup}
|
||||
icon="saved-messages"
|
||||
onClick={handleSelectSaved}
|
||||
>
|
||||
{lang('NewGroup')}
|
||||
{lang('SavedMessages')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="archive"
|
||||
onClick={onSelectArchived}
|
||||
>
|
||||
<span className="menu-item-name">{lang('ArchivedChats')}</span>
|
||||
{archivedUnreadChatsCount > 0 && (
|
||||
<div className="archived-badge">{archivedUnreadChatsCount}</div>
|
||||
)}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="user"
|
||||
@ -141,27 +179,34 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
>
|
||||
{lang('Contacts')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="archive"
|
||||
onClick={onSelectArchived}
|
||||
>
|
||||
{lang('Archived')}
|
||||
{archivedUnreadChatsCount > 0 && (
|
||||
<div className="archived-badge">{archivedUnreadChatsCount}</div>
|
||||
)}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="saved-messages"
|
||||
onClick={handleSelectSaved}
|
||||
>
|
||||
{lang('Saved')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="settings"
|
||||
onClick={onSelectSettings}
|
||||
>
|
||||
{lang('Settings')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="darkmode"
|
||||
onClick={handleDarkModeToggle}
|
||||
>
|
||||
<span className="menu-item-name">Dark Mode</span>
|
||||
<Switcher
|
||||
id="darkmode"
|
||||
label="Toggle Dark Mode"
|
||||
checked={theme === 'dark'}
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="animations"
|
||||
onClick={handleAnimationLevelChange}
|
||||
>
|
||||
<span className="menu-item-name">{lang('SettingsSearch.Synonyms.Appearance.Animations')}</span>
|
||||
<Switcher
|
||||
id="animations"
|
||||
label="Toggle Animations"
|
||||
checked={animationLevel > 0}
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon="help"
|
||||
onClick={openSupportChat}
|
||||
@ -213,6 +258,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
} = global.globalSearch;
|
||||
const { currentUserId } = global;
|
||||
const { byId: chatsById } = global.chats;
|
||||
const { theme, animationLevel } = global.settings.byKey;
|
||||
|
||||
return {
|
||||
searchQuery,
|
||||
@ -221,6 +267,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
chatsById,
|
||||
globalSearchChatId: chatId,
|
||||
searchDate: date,
|
||||
theme,
|
||||
animationLevel,
|
||||
};
|
||||
},
|
||||
(setGlobal, actions): DispatchProps => pick(actions, [
|
||||
@ -228,5 +276,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
'openSupportChat',
|
||||
'setGlobalSearchDate',
|
||||
'setGlobalSearchChatId',
|
||||
'setSettingOption',
|
||||
]),
|
||||
)(LeftMainHeader));
|
||||
|
||||
@ -163,7 +163,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
box-shadow: inset 0 -1px 0 0 var(--color-borders);
|
||||
background-color: white;
|
||||
background-color: var(--color-background);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
left: -0.75rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border: 0.125rem solid white;
|
||||
border: 0.125rem solid var(--color-white);
|
||||
border-radius: 0.75rem;
|
||||
cursor: grab;
|
||||
}
|
||||
@ -66,12 +66,12 @@
|
||||
|
||||
div {
|
||||
cursor: pointer;
|
||||
box-shadow: inset 0 0 0 0 white;
|
||||
box-shadow: inset 0 0 0 0 var(--color-background);
|
||||
transition: box-shadow 300ms ease;
|
||||
|
||||
&.active {
|
||||
border: 0.125rem solid var(--color-primary);
|
||||
box-shadow: inset 0 0 0 0.3125rem white;
|
||||
box-shadow: inset 0 0 0 0.3125rem var(--color-background);
|
||||
}
|
||||
|
||||
// A hack to make a square
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
height: calc(100% - var(--header-height));
|
||||
|
||||
.picker-header {
|
||||
box-shadow: 0 0 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 0 2px var(--color-default-shadow);
|
||||
|
||||
.max-items-reached {
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
@ -9,6 +9,7 @@ import { pick } from '../../util/iteratees';
|
||||
import { selectIsForwardModalOpen, selectIsMediaViewerOpen, selectIsRightColumnShown } from '../../modules/selectors';
|
||||
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
import LeftColumn from '../left/LeftColumn';
|
||||
import MiddleColumn from '../middle/MiddleColumn';
|
||||
@ -19,7 +20,6 @@ import Notifications from './Notifications.async';
|
||||
import Errors from './Errors.async';
|
||||
|
||||
import './Main.scss';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
type StateProps = {
|
||||
animationLevel: number;
|
||||
|
||||
@ -74,7 +74,7 @@
|
||||
width: .75rem;
|
||||
height: .75rem;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
background-color: var(--color-white);
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translate(.325rem, -50%);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
const units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'];
|
||||
|
||||
export default (bytes: number) => {
|
||||
const number = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
const number = bytes === 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
|
||||
return `${(bytes / 1024 ** Math.floor(number)).toFixed(1)} ${units[number]}`;
|
||||
};
|
||||
|
||||
@ -5,14 +5,17 @@
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
overflow-y: overlay;
|
||||
padding-bottom: .3125rem;
|
||||
|
||||
body.hide-mask-shadow .mask-image-disabled &,
|
||||
.mask-image-enabled & {
|
||||
mask-image: linear-gradient(to top, transparent 0, #000 1rem);
|
||||
}
|
||||
|
||||
.custom-bg-color.mask-image-disabled &,
|
||||
.custom-bg-image.mask-image-disabled & {
|
||||
margin-bottom: .3rem;
|
||||
margin-bottom: .3125rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
|
||||
@ -77,9 +77,9 @@
|
||||
align-items: center;
|
||||
padding: 0.25rem;
|
||||
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
border-radius: var(--border-radius-messages);
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
font-weight: 500;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
overflow: hidden;
|
||||
z-index: -1;
|
||||
|
||||
&::before {
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
@ -15,13 +16,18 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: rgb(230, 235, 238);
|
||||
background-color: #F2EBCE;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background-image: url('../../assets/chat-bg.jpg');
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
|
||||
transition: background-image .3s ease;
|
||||
.disable-animations #root & {
|
||||
transition: opacity .2s !important;
|
||||
}
|
||||
|
||||
body.animation-level-0 & {
|
||||
transition: none;
|
||||
@ -32,19 +38,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
.custom-bg-image > &::before {
|
||||
.custom-bg-image > &::after {
|
||||
background-image: var(--custom-background) !important;
|
||||
filter: blur(0);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.custom-bg-color > &::before {
|
||||
background-color: var(--custom-background) !important;
|
||||
filter: blur(0);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.custom-bg-image.blurred > &::before {
|
||||
.custom-bg-image.blurred > &::after {
|
||||
filter: blur(12px);
|
||||
}
|
||||
|
||||
.custom-bg-color > &::after {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1276px) {
|
||||
body.animation-level-2 &::before {
|
||||
body.animation-level-2 &::before,
|
||||
body.animation-level-2 &::after {
|
||||
margin: -16rem -5rem -20rem 0;
|
||||
overflow: hidden;
|
||||
transform: scale(1);
|
||||
@ -52,12 +68,12 @@
|
||||
transition: transform var(--layer-transition);
|
||||
}
|
||||
|
||||
body.animation-level-2 .custom-bg-image > &::before {
|
||||
body.animation-level-2 .custom-bg-image > &::after {
|
||||
margin: -16rem -5rem -20rem -1rem;
|
||||
transition: transform var(--layer-transition), background .3s ease;
|
||||
transition: transform var(--layer-transition);
|
||||
}
|
||||
|
||||
body.animation-level-2 #Main.right-column-open :not(.custom-bg-image) > &::before {
|
||||
body.animation-level-2 #Main.right-column-open :not(.custom-bg-image) > &::after {
|
||||
transform: scale(0.67);
|
||||
}
|
||||
}
|
||||
@ -101,10 +117,10 @@
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
border-radius: var(--border-radius-messages);
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
color: var(--color-text-secondary);
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,6 +328,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.custom-bg-color &::before,
|
||||
.custom-bg-image &::before {
|
||||
display: none;
|
||||
}
|
||||
@ -330,7 +347,7 @@
|
||||
color: var(--color-black);
|
||||
height: 3.125rem;
|
||||
overflow: visible;
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
|
||||
&:hover {
|
||||
.icon-unpin {
|
||||
|
||||
@ -59,6 +59,7 @@ type StateProps = {
|
||||
messageSendingRestrictionReason?: string;
|
||||
hasPinnedOrAudioMessage?: boolean;
|
||||
customBackground?: string;
|
||||
isCustomBackgroundColor?: boolean;
|
||||
isRightColumnShown?: boolean;
|
||||
isBackgroundBlurred?: boolean;
|
||||
isMobileSearchActive?: boolean;
|
||||
@ -84,6 +85,7 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
||||
messageSendingRestrictionReason,
|
||||
hasPinnedOrAudioMessage,
|
||||
customBackground,
|
||||
isCustomBackgroundColor,
|
||||
isRightColumnShown,
|
||||
isBackgroundBlurred,
|
||||
isMobileSearchActive,
|
||||
@ -166,7 +168,8 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
||||
|
||||
const className = buildClassName(
|
||||
hasTools && 'has-header-tools',
|
||||
customBackground && 'custom-bg-image',
|
||||
customBackground && !isCustomBackgroundColor && 'custom-bg-image',
|
||||
customBackground && isCustomBackgroundColor && 'custom-bg-color',
|
||||
customBackground && isBackgroundBlurred && 'blurred',
|
||||
MASK_IMAGE_ENABLED ? 'mask-image-enabled' : 'mask-image-disabled',
|
||||
);
|
||||
@ -293,12 +296,14 @@ export default memo(withGlobal(
|
||||
(global): StateProps => {
|
||||
const { isBackgroundBlurred, customBackground } = global.settings.byKey;
|
||||
|
||||
const isCustomBackgroundColor = Boolean((customBackground || '').match(/^#[a-f\d]{6,8}$/i));
|
||||
const currentMessageList = selectCurrentMessageList(global);
|
||||
const { chats: { listIds } } = global;
|
||||
if (!currentMessageList || !listIds.active) {
|
||||
return {
|
||||
customBackground,
|
||||
isBackgroundBlurred,
|
||||
isCustomBackgroundColor,
|
||||
};
|
||||
}
|
||||
|
||||
@ -320,6 +325,7 @@ export default memo(withGlobal(
|
||||
messageSendingRestrictionReason: chat && getMessageSendingRestrictionReason(chat),
|
||||
hasPinnedOrAudioMessage: Boolean(pinnedIds && pinnedIds.length) || Boolean(audioChatId && audioMessageId),
|
||||
customBackground,
|
||||
isCustomBackgroundColor,
|
||||
isRightColumnShown: selectIsRightColumnShown(global),
|
||||
isBackgroundBlurred,
|
||||
isMobileSearchActive: Boolean(IS_MOBILE_SCREEN && selectCurrentTextSearch(global)),
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
right: 0;
|
||||
height: 2.875rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 2px rgba(114, 114, 114, 0.17);
|
||||
box-shadow: 0 2px 2px var(--color-light-shadow);
|
||||
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
@ -25,7 +25,7 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
box-shadow: 0 2px 2px rgba(114, 114, 114, 0.17);
|
||||
box-shadow: 0 2px 2px var(--color-light-shadow);
|
||||
}
|
||||
|
||||
.HeaderPinnedMessage {
|
||||
@ -73,8 +73,8 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
box-shadow: 0 2px 2px rgba(114, 114, 114, 0.17);
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 2px var(--color-light-shadow);
|
||||
background: var(--color-background);
|
||||
padding: .5rem .8125rem .5rem 1.5rem;
|
||||
position: relative;
|
||||
z-index: var(--z-middle-header);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
z-index: var(--z-mobile-search);
|
||||
width: 100%;
|
||||
height: 3.5rem;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.5rem 0 0.25rem;
|
||||
@ -23,7 +23,7 @@
|
||||
z-index: var(--z-mobile-search);
|
||||
width: 100%;
|
||||
height: 3.5rem;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 1rem;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
align-items: center;
|
||||
|
||||
> .Button {
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
|
||||
i {
|
||||
font-size: 1.75rem;
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
position: relative;
|
||||
|
||||
.form-control {
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
}
|
||||
|
||||
.MentionMenu {
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
min-height: 3.0625rem;
|
||||
border-radius: var(--border-radius-messages-small);
|
||||
border: 2px solid var(--color-primary);
|
||||
background: #fff;
|
||||
background: var(--color-background);
|
||||
color: var(--color-primary);
|
||||
font-weight: 500;
|
||||
text-transform: none;
|
||||
|
||||
@ -150,10 +150,10 @@
|
||||
#message-compose {
|
||||
flex-grow: 1;
|
||||
max-width: calc(100% - 4rem);
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
border-radius: var(--border-radius-messages);
|
||||
border-bottom-right-radius: 0;
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
@ -169,6 +169,10 @@
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSIyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnM+PGZpbHRlciB4PSItNTAlIiB5PSItMTQuNyUiIHdpZHRoPSIyMDAlIiBoZWlnaHQ9IjE0MS4yJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iYSI+PGZlT2Zmc2V0IGR5PSIxIiBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0ic2hhZG93T2Zmc2V0T3V0ZXIxIi8+PGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMSIgaW49InNoYWRvd09mZnNldE91dGVyMSIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAuMDYyMTk2MjQ4MiAwIDAgMCAwIDAuMTM4NTc0MTQ0IDAgMCAwIDAgMC4xODUwMzczNjQgMCAwIDAgMC4xNSAwIiBpbj0ic2hhZG93Qmx1ck91dGVyMSIvPjwvZmlsdGVyPjxwYXRoIGQ9Ik0zIDE3aDZWMGMtLjE5MyAyLjg0LS44NzYgNS43NjctMi4wNSA4Ljc4Mi0uOTA0IDIuMzI1LTIuNDQ2IDQuNDg1LTQuNjI1IDYuNDhBMSAxIDAgMDAzIDE3eiIgaWQ9ImIiLz48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48dXNlIGZpbGw9IiMwMDAiIGZpbHRlcj0idXJsKCNhKSIgeGxpbms6aHJlZj0iI2IiLz48dXNlIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PC9nPjwvc3ZnPg==);
|
||||
background-position: bottom left;
|
||||
transform: scaleX(-1);
|
||||
|
||||
.theme-dark & {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSIyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZGVmcz48ZmlsdGVyIGlkPSJhIiB4PSIwIiB5PSIwIiB3aWR0aD0iMjA1IiBoZWlnaHQ9IjIwMCI+PGZlT2Zmc2V0IHJlc3VsdD0ib2ZmT3V0IiBpbj0iU291cmNlQWxwaGEiIGR5PSIxIi8+PGZlQ29sb3JNYXRyaXggcmVzdWx0PSJtYXRyaXhPdXQiIGluPSJvZmZPdXQiIHZhbHVlcz0iMC4xMyAwIDAgMCAwIDAgMC4xMyAwIDAgMCAwIDAgMC4xMyAwIDAgMCAwIDAgMC42IDAiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyT3V0IiBpbj0ibWF0cml4T3V0IiBzdGREZXZpYXRpb249IjEiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJibHVyT3V0Ii8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PHBhdGggZD0iTTMgMTdoNlYwYy0uMTkzIDIuODQtLjg3NiA1Ljc2Ny0yLjA1IDguNzgyLS45MDQgMi4zMjUtMi40NDYgNC40ODUtNC42MjUgNi40OEExIDEgMCAwMDMgMTd6IiBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiLz48cGF0aCBkPSJNMyAxN2g2VjBjLS4xOTMgMi44NC0uODc2IDUuNzY3LTIuMDUgOC43ODItLjkwNCAyLjMyNS0yLjQ0NiA0LjQ4NS00LjYyNSA2LjQ4QTEgMSAwIDAwMyAxN3oiIGZpbGw9IiMyMTIxMjEiLz48L2c+PC9zdmc+);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
@ -203,13 +207,13 @@
|
||||
position: absolute;
|
||||
top: .75rem;
|
||||
right: .75rem;
|
||||
border: .1875rem solid #fff;
|
||||
border: .1875rem solid var(--color-background);
|
||||
box-sizing: content-box;
|
||||
width: .5rem;
|
||||
height: .5rem;
|
||||
border-radius: 50%;
|
||||
background: var(--color-green-darker);
|
||||
box-shadow: -.375rem -.25rem 0 -.1875rem #fff;
|
||||
box-shadow: -.375rem -.25rem 0 -.1875rem var(--color-background);
|
||||
@media (max-width: 600px) {
|
||||
top: .5rem;
|
||||
right: .5rem;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
.DropTarget {
|
||||
border-radius: var(--border-radius-default);
|
||||
background: #fff;
|
||||
background: var(--color-background);
|
||||
padding: 1.25rem;
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
@ -10,7 +10,7 @@
|
||||
margin-bottom: .3125rem;
|
||||
display: flex;
|
||||
color: #A4ACB3;
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
|
||||
@media (max-height: 350px) {
|
||||
padding: .75rem;
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
box-shadow: 0 0 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 0 2px var(--color-default-shadow);
|
||||
|
||||
@media (max-width: 600px) {
|
||||
overflow-x: auto;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
bottom: calc(100% + .5rem);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
border-radius: var(--border-radius-messages);
|
||||
padding: 0.5rem 0;
|
||||
max-height: 15rem;
|
||||
@ -15,7 +15,7 @@
|
||||
grid-auto-rows: auto;
|
||||
place-items: center;
|
||||
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
|
||||
opacity: 0;
|
||||
transform: translateY(1.5rem);
|
||||
|
||||
@ -4,14 +4,14 @@
|
||||
left: 0;
|
||||
width: calc(100% - 4rem);
|
||||
max-width: 20rem;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
border-radius: var(--border-radius-messages);
|
||||
padding: 0.5rem 0;
|
||||
max-height: 15rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
box-shadow: 3px 3px 5px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 3px 3px 5px var(--color-default-shadow);
|
||||
z-index: -1;
|
||||
|
||||
opacity: 0;
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 0 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 0 2px var(--color-default-shadow);
|
||||
|
||||
scrollbar-width: none;
|
||||
scrollbar-color: rgba(0, 0, 0, 0);
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 0 2px var(--color-default-shadow);
|
||||
position: relative;
|
||||
|
||||
.Button {
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
|
||||
&, &-link-control {
|
||||
position: absolute;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
border-radius: var(--border-radius-messages);
|
||||
padding: 0.5rem 0.375rem;
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
}
|
||||
|
||||
&-link-control {
|
||||
@ -24,6 +24,8 @@
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
width: 100%;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,12 +64,12 @@
|
||||
|
||||
&::before {
|
||||
left: 0;
|
||||
background: linear-gradient(to right, #fff .25rem, transparent 1rem)
|
||||
background: linear-gradient(to right, var(--color-background) .25rem, transparent 1rem)
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: 0;
|
||||
background: linear-gradient(to left, #fff .25rem, transparent 1rem)
|
||||
background: linear-gradient(to left, var(--color-background) .25rem, transparent 1rem)
|
||||
}
|
||||
|
||||
&.mask-left {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
.CommentButton {
|
||||
--background-color: #fff;
|
||||
--hover-color: #f4f4f4;
|
||||
--background-color: var(--color-background);
|
||||
--hover-color: var(--color-chat-hover);
|
||||
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@ -30,9 +30,13 @@
|
||||
width: .5625rem;
|
||||
height: 1.25rem;
|
||||
background-position: bottom left;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='9' height='20' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cfilter x='-50%25' y='-14.7%25' width='200%25' height='141.2%25' filterUnits='objectBoundingBox' id='a'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur stdDeviation='1' in='shadowOffsetOuter1' result='shadowBlurOuter1'/%3E%3CfeColorMatrix values='0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0' in='shadowBlurOuter1'/%3E%3C/filter%3E%3Cpath d='M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z' id='b'/%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cuse fill='%23000' filter='url(%23a)' xlink:href='%23b'/%3E%3Cuse fill='%23f4f4f4' xlink:href='%23b'/%3E%3C/g%3E%3C/svg%3E");
|
||||
background-image: url('data:image/svg+xml,%3Csvg width="9" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"%3E%3Cdefs%3E%3Cfilter x="-50%25" y="-14.7%25" width="200%25" height="141.2%25" filterUnits="objectBoundingBox" id="a"%3E%3CfeOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/%3E%3CfeGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"/%3E%3CfeColorMatrix values="0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0" in="shadowBlurOuter1"/%3E%3C/filter%3E%3Cpath d="M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z" id="b"/%3E%3C/defs%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cuse fill="%23000" filter="url(%23a)" xlink:href="%23b"/%3E%3Cuse fill="%23FFF" xlink:href="%23b"/%3E%3C/g%3E%3C/svg%3E');
|
||||
opacity: 0;
|
||||
transition: opacity .15s;
|
||||
transition: opacity .15s, filter .15s;
|
||||
|
||||
.theme-dark #root & {
|
||||
filter: invert(.83);
|
||||
}
|
||||
|
||||
body.animation-level-0 & {
|
||||
transition: none !important;
|
||||
@ -162,7 +166,7 @@
|
||||
|
||||
.Avatar {
|
||||
transition: border .15s;
|
||||
border: 2px solid #fff;
|
||||
border: 2px solid var(--color-background);
|
||||
margin-right: 0;
|
||||
z-index: 3;
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
height: 10rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.description-text {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -24,10 +24,10 @@
|
||||
margin: .25rem;
|
||||
background-color: rgba(90, 110, 70, 0.6);
|
||||
border-radius: var(--border-radius-messages-small);
|
||||
color: var(--color-white);
|
||||
color: var(--color-text);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
margin-bottom: 0.375rem;
|
||||
position: relative;
|
||||
|
||||
--background-color: white;
|
||||
--background-color: var(--color-background);
|
||||
--hover-color: rgba(var(--color-text-secondary-rgb), 0.08);
|
||||
--active-color: rgba(var(--color-text-secondary-rgb), 0.16);
|
||||
--max-width: 29rem;
|
||||
@ -81,16 +81,19 @@
|
||||
&.own {
|
||||
flex-direction: row-reverse;
|
||||
--background-color: var(--color-background-own);
|
||||
--hover-color: rgba(var(--color-text-green-rgb), 0.12);
|
||||
--active-color: rgba(var(--color-text-green-rgb), 0.24);
|
||||
--hover-color: var(--color-reply-own-hover);
|
||||
--active-color: var(--color-reply-own-active);
|
||||
--max-width: 30rem;
|
||||
--accent-color: var(--color-text-green);
|
||||
--accent-color: var(--color-accent-own);
|
||||
--accent-shade-color: var(--color-green);
|
||||
--secondary-color: var(--color-text-green);
|
||||
--secondary-color: var(--color-accent-own);
|
||||
--color-code: var(--color-code-own);
|
||||
--color-code-bg: var(--color-code-own-bg);
|
||||
--color-links: var(--color-own-links);
|
||||
--color-links-hover: var(--color-own-links);
|
||||
--meta-safe-area-base: 3.5rem;
|
||||
--deleting-translate-x: 50%;
|
||||
--color-text-green: var(--color-accent-own);
|
||||
|
||||
@media (max-width: 600px) {
|
||||
padding-right: 0.25rem;
|
||||
@ -177,6 +180,15 @@
|
||||
bottom: 0.813rem;
|
||||
}
|
||||
|
||||
html.theme-dark &.own .Audio .ProgressSpinner {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUiIGhlaWdodD0iMTUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTguMjE4IDcuNWw1LjYzMy01LjYzM2EuNTA4LjUwOCAwIDEwLS43MTgtLjcxOEw3LjUgNi43ODIgMS44NjcgMS4xNDlhLjUwOC41MDggMCAxMC0uNzE4LjcxOEw2Ljc4MiA3LjVsLTUuNjMzIDUuNjMzYS41MDguNTA4IDAgMTAuNzE4LjcxOEw3LjUgOC4yMThsNS42MzMgNS42MzNhLjUwNi41MDYgMCAwMC43MTggMCAuNTA4LjUwOCAwIDAwMC0uNzE4TDguMjE4IDcuNXoiIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSIjQTQ1RDM3IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9zdmc+);
|
||||
|
||||
circle {
|
||||
stroke: var(--background-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.File {
|
||||
position: relative;
|
||||
|
||||
|
||||
@ -72,12 +72,15 @@
|
||||
}
|
||||
|
||||
.Message.own .has-solid-background & {
|
||||
color: var(--color-text-green);
|
||||
color: var(--color-message-meta-own);
|
||||
}
|
||||
|
||||
.MessageOutgoingStatus {
|
||||
margin-left: -.1875rem;
|
||||
font-size: 1.1875rem;
|
||||
.Message.own & {
|
||||
color: var(--color-accent-own);
|
||||
}
|
||||
}
|
||||
|
||||
.message-content.has-replies:not(.custom-shape) & {
|
||||
|
||||
@ -109,7 +109,7 @@
|
||||
margin-top: -2px;
|
||||
|
||||
.Avatar {
|
||||
border: 1px solid #fff;
|
||||
border: 1px solid var(--color-white);
|
||||
margin-right: 0;
|
||||
box-sizing: content-box;
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
background: var(--accent-color);
|
||||
color: #fff;
|
||||
color: var(--background-color);
|
||||
border-radius: .5rem;
|
||||
font-size: .75rem;
|
||||
text-align: center;
|
||||
|
||||
@ -98,7 +98,7 @@
|
||||
}
|
||||
|
||||
&.has-shadow {
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
}
|
||||
|
||||
&.has-solid-background, .is-album & {
|
||||
@ -123,6 +123,10 @@
|
||||
background-position: bottom right;
|
||||
background-image: url('data:image/svg+xml,%3Csvg width="9" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"%3E%3Cdefs%3E%3Cfilter x="-50%25" y="-14.7%25" width="200%25" height="141.2%25" filterUnits="objectBoundingBox" id="a"%3E%3CfeOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/%3E%3CfeGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"/%3E%3CfeColorMatrix values="0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0" in="shadowBlurOuter1"/%3E%3C/filter%3E%3Cpath d="M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z" id="b"/%3E%3C/defs%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cuse fill="%23000" filter="url(%23a)" xlink:href="%23b"/%3E%3Cuse fill="%23EEFFDE" xlink:href="%23b"/%3E%3C/g%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.theme-dark &:not([data-has-custom-appendix])::before {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSIyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnM+PGZpbHRlciBpZD0iYSIgeD0iMCIgeT0iMCIgd2lkdGg9IjIwNSIgaGVpZ2h0PSIyMDAiPjxmZU9mZnNldCByZXN1bHQ9Im9mZk91dCIgaW49IlNvdXJjZUFscGhhIiBkeD0iLTEiIGR5PSIxIi8+PGZlQ29sb3JNYXRyaXggcmVzdWx0PSJtYXRyaXhPdXQiIGluPSJvZmZPdXQiIHZhbHVlcz0iMC4xMyAwIDAgMCAwIDAgMC4xMyAwIDAgMCAwIDAgMC4xMyAwIDAgMCAwIDAgMC42IDAiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyT3V0IiBpbj0ibWF0cml4T3V0IiBzdGREZXZpYXRpb249IjEiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJibHVyT3V0Ii8+PC9maWx0ZXI+PHBhdGggZD0iTTYgMTdIMFYwYy4xOTMgMi44NC44NzYgNS43NjcgMi4wNSA4Ljc4Mi45MDQgMi4zMjUgMi40NDYgNC40ODUgNC42MjUgNi40OEExIDEgMCAwMTYgMTd6IiBpZD0iYiIvPjwvZGVmcz48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjx1c2UgZmlsbD0iIzAwMCIgZmlsdGVyPSJ1cmwoI2EpIiB4bGluazpocmVmPSIjYiIvPjx1c2UgZmlsbD0iIzlBNUYzRiIgeGxpbms6aHJlZj0iI2IiLz48L2c+PC9zdmc+);
|
||||
}
|
||||
}
|
||||
|
||||
.Message:not(.own) & {
|
||||
@ -131,6 +135,10 @@
|
||||
background-position: bottom left;
|
||||
background-image: url('data:image/svg+xml,%3Csvg width="9" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"%3E%3Cdefs%3E%3Cfilter x="-50%25" y="-14.7%25" width="200%25" height="141.2%25" filterUnits="objectBoundingBox" id="a"%3E%3CfeOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/%3E%3CfeGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"/%3E%3CfeColorMatrix values="0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0" in="shadowBlurOuter1"/%3E%3C/filter%3E%3Cpath d="M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z" id="b"/%3E%3C/defs%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cuse fill="%23000" filter="url(%23a)" xlink:href="%23b"/%3E%3Cuse fill="%23FFF" xlink:href="%23b"/%3E%3C/g%3E%3C/svg%3E');
|
||||
}
|
||||
|
||||
.theme-dark &:not([data-has-custom-appendix])::before {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSIyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZGVmcz48ZmlsdGVyIGlkPSJhIiB4PSIwIiB5PSIwIiB3aWR0aD0iMjA1IiBoZWlnaHQ9IjIwMCI+PGZlT2Zmc2V0IHJlc3VsdD0ib2ZmT3V0IiBpbj0iU291cmNlQWxwaGEiIGR5PSIxIi8+PGZlQ29sb3JNYXRyaXggcmVzdWx0PSJtYXRyaXhPdXQiIGluPSJvZmZPdXQiIHZhbHVlcz0iMC4xMyAwIDAgMCAwIDAgMC4xMyAwIDAgMCAwIDAgMC4xMyAwIDAgMCAwIDAgMC42IDAiLz48ZmVHYXVzc2lhbkJsdXIgcmVzdWx0PSJibHVyT3V0IiBpbj0ibWF0cml4T3V0IiBzdGREZXZpYXRpb249IjEiLz48ZmVCbGVuZCBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJibHVyT3V0Ii8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PHBhdGggZD0iTTMgMTdoNlYwYy0uMTkzIDIuODQtLjg3NiA1Ljc2Ny0yLjA1IDguNzgyLS45MDQgMi4zMjUtMi40NDYgNC40ODUtNC42MjUgNi40OEExIDEgMCAwMDMgMTd6IiBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiLz48cGF0aCBkPSJNMyAxN2g2VjBjLS4xOTMgMi44NC0uODc2IDUuNzY3LTIuMDUgOC43ODItLjkwNCAyLjMyNS0yLjQ0NiA0LjQ4NS00LjYyNSA2LjQ4QTEgMSAwIDAwMyAxN3oiIGZpbGw9IiMyMTIxMjEiLz48L2c+PC9zdmc+);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.has-solid-background) {
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
border-bottom: 1px var(--color-borders) solid;
|
||||
|
||||
h3 {
|
||||
@ -51,7 +51,7 @@
|
||||
border-bottom-right-radius: 10px;
|
||||
width: 100%;
|
||||
padding: .75rem 1rem;
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
border-top: 1px var(--color-borders) solid;
|
||||
|
||||
button {
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
padding: 1rem .75rem .5rem 1rem;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: #fff;
|
||||
background: var(--color-background);
|
||||
|
||||
@media (max-width: 600px) {
|
||||
padding: .5rem .25rem .5rem .5rem;
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
flex-direction: column-reverse;
|
||||
|
||||
.TabList {
|
||||
background: #fff;
|
||||
background: var(--color-background);
|
||||
top: -1px;
|
||||
.Tab {
|
||||
padding: .6875rem .25rem;
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 1275px) {
|
||||
box-shadow: 0 .25rem .5rem .1rem rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 .25rem .5rem .1rem var(--color-default-shadow);
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
}
|
||||
|
||||
&.filled {
|
||||
background-color: white;
|
||||
background-color: var(--color-background);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
|
||||
@ -79,7 +79,7 @@
|
||||
&::before {
|
||||
border: 2px solid var(--color-borders);
|
||||
border-radius: .25rem;
|
||||
background-color: white;
|
||||
background-color: var(--color-white);
|
||||
transition: border-color .1s ease;
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
box-shadow: 0 1px 2px rgba(114, 114, 114, 0.25);
|
||||
box-shadow: 0 1px 2px var(--color-default-shadow);
|
||||
}
|
||||
|
||||
#avatar-crop {
|
||||
|
||||
@ -19,8 +19,8 @@
|
||||
padding: 0.5rem 0;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
box-shadow: 0 .25rem .5rem .1rem rgba(114, 114, 114, 0.25);
|
||||
background-color: var(--color-background);
|
||||
box-shadow: 0 .25rem .5rem .1rem var(--color-default-shadow);
|
||||
border-radius: var(--border-radius-default);
|
||||
min-width: 13.5rem;
|
||||
z-index: var(--z-menu-bubble);
|
||||
|
||||
@ -24,6 +24,10 @@
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.menu-item-name {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5 !important;
|
||||
cursor: default !important;
|
||||
@ -41,4 +45,8 @@
|
||||
background-color: var(--color-chat-active);
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
& > .Switcher {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,8 +47,8 @@
|
||||
max-width: 35rem;
|
||||
min-width: 17.5rem;
|
||||
margin: 2rem auto;
|
||||
background-color: white;
|
||||
box-shadow: 0 .25rem .5rem .1rem rgba(114, 114, 114, 0.25);
|
||||
background-color: var(--color-background);
|
||||
box-shadow: 0 .25rem .5rem .1rem var(--color-default-shadow);
|
||||
border-radius: var(--border-radius-default);
|
||||
transform: translate3d(0, -1rem, 0);
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
&::before {
|
||||
border: 2px solid var(--color-borders);
|
||||
border-radius: 50%;
|
||||
background-color: white;
|
||||
background-color: var(--color-white);
|
||||
opacity: 1;
|
||||
transition: border-color .1s ease, opacity .1s ease;
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
&.has-focus {
|
||||
border-color: var(--color-primary);
|
||||
caret-color: var(--color-primary);
|
||||
background-color: #fff;
|
||||
background-color: var(--color-background);
|
||||
|
||||
input {
|
||||
& + i {
|
||||
|
||||
53
src/components/ui/Switcher.scss
Normal file
53
src/components/ui/Switcher.scss
Normal file
@ -0,0 +1,53 @@
|
||||
.Switcher {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
input {
|
||||
height: 0;
|
||||
width: 0;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
z-index: var(--z-below);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.widget {
|
||||
cursor: pointer;
|
||||
text-indent: -999px;
|
||||
width: 2.125rem;
|
||||
height: 0.875rem;
|
||||
background: var(--color-gray);
|
||||
display: inline-block;
|
||||
border-radius: .5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.widget:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -.125rem;
|
||||
left: 0;
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
background: var(--color-background);
|
||||
border-radius: .75rem;
|
||||
border: .125rem solid var(--color-gray);
|
||||
}
|
||||
|
||||
input:checked + .widget {
|
||||
background: var(--color-primary);
|
||||
}
|
||||
|
||||
input:checked + .widget:after {
|
||||
left: calc(100% - 1.125rem);
|
||||
transform: translateX(calc(-100% + 1.125rem));
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
60
src/components/ui/Switcher.tsx
Normal file
60
src/components/ui/Switcher.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import { ChangeEvent } from 'react';
|
||||
import React, { FC, memo, useCallback } from '../../lib/teact/teact';
|
||||
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
import './Switcher.scss';
|
||||
|
||||
type OwnProps = {
|
||||
id?: string;
|
||||
name?: string;
|
||||
value?: string;
|
||||
label: string;
|
||||
checked?: boolean;
|
||||
disabled?: boolean;
|
||||
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
onCheck?: (isChecked: boolean) => void;
|
||||
};
|
||||
|
||||
const Switcher: FC<OwnProps> = ({
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
label,
|
||||
checked = false,
|
||||
disabled,
|
||||
onChange,
|
||||
onCheck,
|
||||
}) => {
|
||||
const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (onChange) {
|
||||
onChange(event);
|
||||
}
|
||||
|
||||
if (onCheck) {
|
||||
onCheck(event.currentTarget.checked);
|
||||
}
|
||||
}, [onChange, onCheck]);
|
||||
|
||||
const className = buildClassName(
|
||||
'Switcher',
|
||||
disabled && 'disabled',
|
||||
);
|
||||
|
||||
return (
|
||||
<label className={className} title={label}>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={id}
|
||||
name={name}
|
||||
value={value}
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<span className="widget" />
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Switcher);
|
||||
@ -7,8 +7,8 @@
|
||||
align-items: flex-end;
|
||||
font-size: 0.875rem;
|
||||
flex-wrap: nowrap;
|
||||
box-shadow: 0 2px 2px rgba(114, 114, 114, 0.17);
|
||||
background-color: white;
|
||||
box-shadow: 0 2px 2px var(--color-light-shadow);
|
||||
background-color: var(--color-background);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation-fill-mode: forwards !important;
|
||||
transition: background-color .2s;
|
||||
|
||||
&.from, &.to {
|
||||
position: absolute;
|
||||
@ -245,7 +246,7 @@
|
||||
*/
|
||||
|
||||
&.slide-layers {
|
||||
--background-color: var(--color-white);
|
||||
--background-color: var(--color-background);
|
||||
background: black;
|
||||
|
||||
> div {
|
||||
@ -290,7 +291,7 @@
|
||||
|
||||
&.push-slide {
|
||||
> div {
|
||||
background: white;
|
||||
background: var(--color-background);
|
||||
}
|
||||
|
||||
> .from {
|
||||
|
||||
@ -103,6 +103,7 @@ export const INITIAL_STATE: GlobalState = {
|
||||
isBackgroundBlurred: true,
|
||||
animationLevel: ANIMATION_LEVEL_DEFAULT,
|
||||
messageSendKeyCombo: 'enter',
|
||||
theme: 'light',
|
||||
shouldAutoDownloadMediaFromContacts: true,
|
||||
shouldAutoDownloadMediaInPrivateChats: true,
|
||||
shouldAutoDownloadMediaInGroups: true,
|
||||
|
||||
@ -4,15 +4,20 @@ import {
|
||||
IS_ANDROID, IS_IOS, IS_SAFARI, IS_TOUCH_ENV,
|
||||
} from '../../../util/environment';
|
||||
import { setLanguage } from '../../../util/langProvider';
|
||||
import switchTheme from '../../../util/switchTheme';
|
||||
|
||||
addReducer('init', (global) => {
|
||||
const { animationLevel, messageTextSize, language } = global.settings.byKey;
|
||||
const {
|
||||
theme, animationLevel, messageTextSize, language,
|
||||
} = global.settings.byKey;
|
||||
|
||||
setLanguage(language);
|
||||
|
||||
document.documentElement.style.setProperty('--message-text-size', `${messageTextSize}px`);
|
||||
document.body.classList.add('initial');
|
||||
document.body.classList.add(`animation-level-${animationLevel}`);
|
||||
document.body.classList.add(IS_TOUCH_ENV ? 'is-touch-env' : 'is-pointer-env');
|
||||
switchTheme(theme, animationLevel > 0);
|
||||
|
||||
if (IS_SAFARI) {
|
||||
document.body.classList.add('is-safari');
|
||||
@ -27,6 +32,10 @@ addReducer('init', (global) => {
|
||||
addReducer('setIsUiReady', (global, actions, payload) => {
|
||||
const { uiReadyState } = payload!;
|
||||
|
||||
if (uiReadyState === 2) {
|
||||
document.body.classList.remove('initial');
|
||||
}
|
||||
|
||||
return {
|
||||
...global,
|
||||
uiReadyState,
|
||||
|
||||
@ -70,9 +70,10 @@
|
||||
width: 100%;
|
||||
height: 3.375rem;
|
||||
padding: calc(0.75rem - var(--border-width)) calc(.9rem - var(--border-width));
|
||||
border: var(--border-width) solid var(--color-borders);
|
||||
border: var(--border-width) solid var(--color-borders-input);
|
||||
border-radius: var(--border-radius-default);
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-background);
|
||||
outline: none;
|
||||
transition: border-color 0.15s ease;
|
||||
word-break: break-word;
|
||||
@ -82,7 +83,11 @@
|
||||
line-height: 1.25rem;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-gray);
|
||||
border-color: var(--color-primary);
|
||||
|
||||
& + label {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus,
|
||||
|
||||
@ -64,9 +64,11 @@ $color-user-8: #faa774;
|
||||
--color-text-secondary-rgb: #{toRGB($color-text-secondary)};
|
||||
--color-text-meta: #{$color-text-meta};
|
||||
--color-text-meta-rgb: #{toRGB($color-text-meta)};
|
||||
--color-text-meta-colored: #{$color-text-green};
|
||||
--color-text-green: #{$color-text-green};
|
||||
--color-text-green-rgb: #{toRGB($color-text-green)};
|
||||
--color-borders: #{$color-borders};
|
||||
--color-borders-input: #{$color-borders};
|
||||
--color-webpage-initial-background: #{$color-dark-gray};
|
||||
--color-interactive-active: var(--color-primary);
|
||||
--color-interactive-inactive: rgba(var(--color-text-secondary-rgb), 0.25);
|
||||
@ -94,6 +96,8 @@ $color-user-8: #faa774;
|
||||
--color-links-darker: #{darken($color-links, 15%)};
|
||||
--color-links-darker-hover: #{darken($color-links, 23%)};
|
||||
|
||||
--color-own-links: #{$color-white};
|
||||
|
||||
--color-placeholders: #{$color-placeholders};
|
||||
|
||||
--color-code: #4a729a;
|
||||
@ -101,6 +105,9 @@ $color-user-8: #faa774;
|
||||
--color-code-own: #3c7940;
|
||||
--color-code-own-bg: #{rgba($color-text-secondary, .08)};
|
||||
|
||||
--color-accent-own: #{$color-text-green};
|
||||
--color-message-meta-own: #{$color-text-green};
|
||||
|
||||
--color-reply-hover: #{blend-normal(rgba($color-text-secondary, 0.08), $color-white)};
|
||||
--color-reply-active: #{blend-normal(rgba($color-text-secondary, 0.16), $color-white)};
|
||||
--color-reply-own-hover: #{blend-normal(rgba($color-text-green, 0.12), $color-light-green)};
|
||||
@ -123,6 +130,9 @@ $color-user-8: #faa774;
|
||||
--color-user-7: #{$color-user-7};
|
||||
--color-user-8: #{$color-user-8};
|
||||
|
||||
--color-default-shadow: #72727240;
|
||||
--color-light-shadow: #7272722B;
|
||||
|
||||
--border-radius-default: 0.75rem;
|
||||
--border-radius-default-small: 0.625rem;
|
||||
--border-radius-default-tiny: 0.375rem;
|
||||
|
||||
@ -83,6 +83,10 @@ body.cursor-grabbing, body.cursor-grabbing * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.disable-animations #root * {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.custom-scroll,
|
||||
.custom-scroll-x {
|
||||
scrollbar-width: thin;
|
||||
|
||||
23
src/styles/themes.json
Normal file
23
src/styles/themes.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"--color-primary": ["#50A2E9", "#868DF5"],
|
||||
"--color-background": ["#FFFFFF", "#212121"],
|
||||
"--color-background-own": ["#EEFEDF", "#A45D37"],
|
||||
"--color-chat-hover": ["#F4F4F5", "#2C2C2C"],
|
||||
"--color-chat-active": ["#ededed", "#292929"],
|
||||
"--color-text": ["#000000", "#FFFFFF"],
|
||||
"--color-text-secondary": ["#707579", "#AAAAAA"],
|
||||
"--color-borders": ["#DADCE0", "#100F10"],
|
||||
"--color-borders-input": ["#DADCE0", "#5B5B5A"],
|
||||
"--color-links": ["#52A1EF", "#868DF6"],
|
||||
"--color-gray": ["#C4C9CC", "#808080"],
|
||||
"--color-default-shadow": ["#72727240", "#00000099"],
|
||||
"--color-light-shadow": ["#7272722B", "#00000040"],
|
||||
"--color-green": ["#4DCD5E", "#868DF5"],
|
||||
"--color-text-meta-colored": ["#4DCD5E", "#868DF5"],
|
||||
"--color-reply-own-hover": ["#DBF4CE", "#A26947"],
|
||||
"--color-reply-own-active": ["#C8EBBC", "#B0714C"],
|
||||
"--color-accent-own": ["#4FAE4E", "#FFFFFF"],
|
||||
"--color-message-meta-own": ["#4FAE4E", "#D9BDAD"],
|
||||
"--color-own-links": ["#52A1EF", "#FFFFFF"],
|
||||
"--color-code-own": ["#3C7940", "#FFFFFF"]
|
||||
}
|
||||
@ -26,6 +26,7 @@ export interface ISettings extends Record<string, any> {
|
||||
isBackgroundBlurred?: boolean;
|
||||
animationLevel: 0 | 1 | 2;
|
||||
messageSendKeyCombo: 'enter' | 'ctrl-enter';
|
||||
theme: 'light' | 'dark';
|
||||
shouldAutoDownloadMediaFromContacts: boolean;
|
||||
shouldAutoDownloadMediaInPrivateChats: boolean;
|
||||
shouldAutoDownloadMediaInGroups: boolean;
|
||||
|
||||
85
src/util/switchTheme.ts
Normal file
85
src/util/switchTheme.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { ISettings } from '../types';
|
||||
|
||||
import { animateSingle } from './animation';
|
||||
|
||||
import themeColors from '../styles/themes.json';
|
||||
|
||||
type RGBAColor = {
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
a?: number;
|
||||
};
|
||||
|
||||
let isInitialized = false;
|
||||
|
||||
const HEX_COLOR_REGEX = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i;
|
||||
const DURATION_MS = 200;
|
||||
const ENABLE_ANIMATION_DELAY_MS = 500;
|
||||
|
||||
const lerp = (start: number, end: number, interpolationRatio: number) => {
|
||||
return (1 - interpolationRatio) * start + interpolationRatio * end;
|
||||
};
|
||||
|
||||
const colors = (Object.keys(themeColors) as Array<keyof typeof themeColors>).map((property) => ({
|
||||
property,
|
||||
colors: [hexToRgb(themeColors[property][0]), hexToRgb(themeColors[property][1])],
|
||||
}));
|
||||
|
||||
export default (theme: ISettings['theme'], withAnimation: boolean) => {
|
||||
const shouldAnimate = isInitialized && withAnimation;
|
||||
const startIndex = theme === 'dark' ? 0 : 1;
|
||||
const endIndex = theme === 'dark' ? 1 : 0;
|
||||
const startAt = Date.now();
|
||||
|
||||
document.documentElement.classList.remove(`theme-${theme === 'dark' ? 'light' : 'dark'}`);
|
||||
if (isInitialized) {
|
||||
document.documentElement.classList.add('disable-animations');
|
||||
}
|
||||
document.documentElement.classList.add(`theme-${theme}`);
|
||||
|
||||
setTimeout(() => {
|
||||
document.documentElement.classList.remove('disable-animations');
|
||||
}, ENABLE_ANIMATION_DELAY_MS);
|
||||
|
||||
isInitialized = true;
|
||||
|
||||
if (shouldAnimate) {
|
||||
animateSingle(() => {
|
||||
const t = Math.min((Date.now() - startAt) / DURATION_MS, 1);
|
||||
|
||||
applyColorAnimationStep(startIndex, endIndex, transition(t));
|
||||
|
||||
return t < 1;
|
||||
});
|
||||
} else {
|
||||
applyColorAnimationStep(startIndex, endIndex);
|
||||
}
|
||||
};
|
||||
|
||||
function transition(t: number) {
|
||||
return 1 - ((1 - t) ** 3.5);
|
||||
}
|
||||
|
||||
function hexToRgb(hex: string): RGBAColor {
|
||||
const result = HEX_COLOR_REGEX.exec(hex)!;
|
||||
|
||||
return {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16),
|
||||
a: result[4] ? parseInt(result[4], 16) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function applyColorAnimationStep(startIndex: number, endIndex: number, interpolationRatio: number = 1) {
|
||||
colors.forEach(({ property, colors: propertyColors }) => {
|
||||
const r = Math.round(lerp(propertyColors[startIndex].r, propertyColors[endIndex].r, interpolationRatio));
|
||||
const g = Math.round(lerp(propertyColors[startIndex].g, propertyColors[endIndex].g, interpolationRatio));
|
||||
const b = Math.round(lerp(propertyColors[startIndex].b, propertyColors[endIndex].b, interpolationRatio));
|
||||
const a = propertyColors[startIndex].a
|
||||
&& Math.round(lerp(propertyColors[startIndex].a!, propertyColors[endIndex].a!, interpolationRatio));
|
||||
|
||||
document.documentElement.style.setProperty(property, a ? `rgba(${r},${g},${b},${a / 255})` : `rgb(${r},${g},${b})`);
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user