Left Column: Support resizing; Better support for large displays (#1484)
This commit is contained in:
parent
03ea0cb152
commit
5180eb0d2e
@ -1 +1 @@
|
|||||||
> 2%, last 2 edge versions
|
> 2%, last 2 edge versions, iOS >= 13.4, firefox >= 68, firefoxandroid >= 68, last 2 safari major versions
|
||||||
|
|||||||
51
package-lock.json
generated
51
package-lock.json
generated
@ -5329,17 +5329,44 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"autoprefixer": {
|
"autoprefixer": {
|
||||||
"version": "10.3.1",
|
"version": "10.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.7.tgz",
|
||||||
"integrity": "sha512-L8AmtKzdiRyYg7BUXJTzigmhbQRCXFKz6SA1Lqo0+AR2FBbQ4aTAPFSDlOutnFkjhiz8my4agGXog1xlMjPJ6A==",
|
"integrity": "sha512-EmGpu0nnQVmMhX8ROoJ7Mx8mKYPlcUHuxkwrRYEYMz85lu7H09v8w6R1P0JPdn/hKU32GjpLBFEOuIlDWCRWvg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"browserslist": "^4.16.6",
|
"browserslist": "^4.17.3",
|
||||||
"caniuse-lite": "^1.0.30001243",
|
"caniuse-lite": "^1.0.30001264",
|
||||||
"colorette": "^1.2.2",
|
|
||||||
"fraction.js": "^4.1.1",
|
"fraction.js": "^4.1.1",
|
||||||
"normalize-range": "^0.1.2",
|
"normalize-range": "^0.1.2",
|
||||||
|
"picocolors": "^0.2.1",
|
||||||
"postcss-value-parser": "^4.1.0"
|
"postcss-value-parser": "^4.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"browserslist": {
|
||||||
|
"version": "4.17.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz",
|
||||||
|
"integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"caniuse-lite": "^1.0.30001264",
|
||||||
|
"electron-to-chromium": "^1.3.857",
|
||||||
|
"escalade": "^3.1.1",
|
||||||
|
"node-releases": "^1.1.77",
|
||||||
|
"picocolors": "^0.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"electron-to-chromium": {
|
||||||
|
"version": "1.3.864",
|
||||||
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz",
|
||||||
|
"integrity": "sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node-releases": {
|
||||||
|
"version": "1.1.77",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz",
|
||||||
|
"integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aws-sign2": {
|
"aws-sign2": {
|
||||||
@ -6085,9 +6112,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001249",
|
"version": "1.0.30001265",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001249.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz",
|
||||||
"integrity": "sha512-vcX4U8lwVXPdqzPWi6cAJ3FnQaqXbBqy/GZseKNQzRj37J7qZdGcBtxq/QLFNLLlfsoXLUdHw8Iwenri86Tagw==",
|
"integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"caseless": {
|
"caseless": {
|
||||||
@ -15697,6 +15724,12 @@
|
|||||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"picocolors": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"picomatch": {
|
"picomatch": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz",
|
||||||
|
|||||||
@ -53,7 +53,7 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
||||||
"@typescript-eslint/parser": "^4.29.1",
|
"@typescript-eslint/parser": "^4.29.1",
|
||||||
"@webpack-cli/serve": "^1.5.1",
|
"@webpack-cli/serve": "^1.5.1",
|
||||||
"autoprefixer": "^10.3.1",
|
"autoprefixer": "^10.3.7",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"browserlist": "^1.0.1",
|
"browserlist": "^1.0.1",
|
||||||
|
|||||||
@ -11,16 +11,33 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 1680px;
|
max-width: 1920px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: var(--z-ui-loader-mask);
|
z-index: var(--z-ui-loader-mask);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-template-rows: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background: var(--color-background);
|
background: var(--color-background);
|
||||||
min-width: 15.5rem;
|
min-width: 18rem;
|
||||||
max-width: 26.5rem;
|
width: 26.5rem;
|
||||||
|
max-width: 33vw;
|
||||||
|
|
||||||
|
@media (min-width: 926px) {
|
||||||
|
width: 25vw;
|
||||||
|
max-width: 40vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1276px) {
|
||||||
|
max-width: 33vw;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 1680px) {
|
@media (min-width: 1680px) {
|
||||||
border-left: 1px solid var(--color-borders);
|
border-left: 1px solid var(--color-borders);
|
||||||
|
|||||||
@ -32,6 +32,7 @@ type StateProps = Pick<GlobalState, 'uiReadyState' | 'shouldSkipHistoryAnimation
|
|||||||
hasCustomBackground?: boolean;
|
hasCustomBackground?: boolean;
|
||||||
hasCustomBackgroundColor: boolean;
|
hasCustomBackgroundColor: boolean;
|
||||||
isRightColumnShown?: boolean;
|
isRightColumnShown?: boolean;
|
||||||
|
leftColumnWidth?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchProps = Pick<GlobalActions, 'setIsUiReady'>;
|
type DispatchProps = Pick<GlobalActions, 'setIsUiReady'>;
|
||||||
@ -83,6 +84,7 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
hasCustomBackgroundColor,
|
hasCustomBackgroundColor,
|
||||||
isRightColumnShown,
|
isRightColumnShown,
|
||||||
shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations,
|
||||||
|
leftColumnWidth,
|
||||||
setIsUiReady,
|
setIsUiReady,
|
||||||
}) => {
|
}) => {
|
||||||
const [isReady, markReady] = useFlag();
|
const [isReady, markReady] = useFlag();
|
||||||
@ -131,7 +133,11 @@ const UiLoader: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
<div className={buildClassName('mask', transitionClassNames)}>
|
<div className={buildClassName('mask', transitionClassNames)}>
|
||||||
{page === 'main' ? (
|
{page === 'main' ? (
|
||||||
<>
|
<>
|
||||||
<div className="left" />
|
<div
|
||||||
|
className="left"
|
||||||
|
// @ts-ignore teact feature
|
||||||
|
style={leftColumnWidth ? `width: ${leftColumnWidth}px` : undefined}
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
'middle',
|
'middle',
|
||||||
@ -162,6 +168,7 @@ export default withGlobal<OwnProps>(
|
|||||||
hasCustomBackground: Boolean(background),
|
hasCustomBackground: Boolean(background),
|
||||||
hasCustomBackgroundColor: Boolean(backgroundColor),
|
hasCustomBackgroundColor: Boolean(backgroundColor),
|
||||||
isRightColumnShown: selectIsRightColumnShown(global),
|
isRightColumnShown: selectIsRightColumnShown(global),
|
||||||
|
leftColumnWidth: global.leftColumnWidth,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(setGlobal, actions): DispatchProps => pick(actions, ['setIsUiReady']),
|
(setGlobal, actions): DispatchProps => pick(actions, ['setIsUiReady']),
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
#LeftColumn {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#NewChat {
|
#NewChat {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useCallback, useEffect, useState,
|
FC, memo, useCallback, useEffect, useRef, useState,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
import { withGlobal } from '../../lib/teact/teactn';
|
import { withGlobal } from '../../lib/teact/teactn';
|
||||||
|
|
||||||
@ -10,6 +10,7 @@ import { LAYERS_ANIMATION_NAME } from '../../util/environment';
|
|||||||
import captureEscKeyListener from '../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../util/captureEscKeyListener';
|
||||||
import { pick } from '../../util/iteratees';
|
import { pick } from '../../util/iteratees';
|
||||||
import useFoldersReducer from '../../hooks/reducers/useFoldersReducer';
|
import useFoldersReducer from '../../hooks/reducers/useFoldersReducer';
|
||||||
|
import { useResize } from '../../hooks/useResize';
|
||||||
|
|
||||||
import Transition from '../ui/Transition';
|
import Transition from '../ui/Transition';
|
||||||
import LeftMain from './main/LeftMain';
|
import LeftMain from './main/LeftMain';
|
||||||
@ -24,11 +25,12 @@ type StateProps = {
|
|||||||
searchDate?: number;
|
searchDate?: number;
|
||||||
activeChatFolder: number;
|
activeChatFolder: number;
|
||||||
shouldSkipHistoryAnimations?: boolean;
|
shouldSkipHistoryAnimations?: boolean;
|
||||||
|
leftColumnWidth?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchProps = Pick<GlobalActions, (
|
type DispatchProps = Pick<GlobalActions, (
|
||||||
'setGlobalSearchQuery' | 'setGlobalSearchChatId' | 'resetChatCreation' | 'setGlobalSearchDate' |
|
'setGlobalSearchQuery' | 'setGlobalSearchChatId' | 'resetChatCreation' | 'setGlobalSearchDate' |
|
||||||
'loadPasswordInfo' | 'clearTwoFaError'
|
'loadPasswordInfo' | 'clearTwoFaError' | 'setLeftColumnWidth' | 'resetLeftColumnWidth'
|
||||||
)>;
|
)>;
|
||||||
|
|
||||||
enum ContentType {
|
enum ContentType {
|
||||||
@ -50,13 +52,18 @@ const LeftColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
searchDate,
|
searchDate,
|
||||||
activeChatFolder,
|
activeChatFolder,
|
||||||
shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations,
|
||||||
|
leftColumnWidth,
|
||||||
setGlobalSearchQuery,
|
setGlobalSearchQuery,
|
||||||
setGlobalSearchChatId,
|
setGlobalSearchChatId,
|
||||||
resetChatCreation,
|
resetChatCreation,
|
||||||
setGlobalSearchDate,
|
setGlobalSearchDate,
|
||||||
loadPasswordInfo,
|
loadPasswordInfo,
|
||||||
clearTwoFaError,
|
clearTwoFaError,
|
||||||
|
setLeftColumnWidth,
|
||||||
|
resetLeftColumnWidth,
|
||||||
}) => {
|
}) => {
|
||||||
|
// eslint-disable-next-line no-null/no-null
|
||||||
|
const resizeRef = useRef<HTMLDivElement>(null);
|
||||||
const [content, setContent] = useState<LeftColumnContent>(LeftColumnContent.ChatList);
|
const [content, setContent] = useState<LeftColumnContent>(LeftColumnContent.ChatList);
|
||||||
const [settingsScreen, setSettingsScreen] = useState(SettingsScreens.Main);
|
const [settingsScreen, setSettingsScreen] = useState(SettingsScreens.Main);
|
||||||
const [contactsFilter, setContactsFilter] = useState<string>('');
|
const [contactsFilter, setContactsFilter] = useState<string>('');
|
||||||
@ -257,81 +264,95 @@ const LeftColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
}
|
}
|
||||||
}, [clearTwoFaError, loadPasswordInfo, settingsScreen]);
|
}, [clearTwoFaError, loadPasswordInfo, settingsScreen]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
initResize, resetResize, handleMouseUp,
|
||||||
|
} = useResize(resizeRef, setLeftColumnWidth, resetLeftColumnWidth, leftColumnWidth);
|
||||||
|
|
||||||
const handleSettingsScreenSelect = (screen: SettingsScreens) => {
|
const handleSettingsScreenSelect = (screen: SettingsScreens) => {
|
||||||
setContent(LeftColumnContent.Settings);
|
setContent(LeftColumnContent.Settings);
|
||||||
setSettingsScreen(screen);
|
setSettingsScreen(screen);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition
|
<div
|
||||||
id="LeftColumn"
|
id="LeftColumn"
|
||||||
name={shouldSkipHistoryAnimations ? 'none' : LAYERS_ANIMATION_NAME}
|
ref={resizeRef}
|
||||||
renderCount={RENDER_COUNT}
|
|
||||||
activeKey={contentType}
|
|
||||||
shouldCleanup
|
|
||||||
cleanupExceptionKey={ContentType.Main}
|
|
||||||
>
|
>
|
||||||
{(isActive) => {
|
<Transition
|
||||||
switch (contentType) {
|
name={shouldSkipHistoryAnimations ? 'none' : LAYERS_ANIMATION_NAME}
|
||||||
case ContentType.Archived:
|
renderCount={RENDER_COUNT}
|
||||||
return (
|
activeKey={contentType}
|
||||||
<ArchivedChats
|
shouldCleanup
|
||||||
isActive={isActive}
|
cleanupExceptionKey={ContentType.Main}
|
||||||
onReset={handleReset}
|
>
|
||||||
onContentChange={setContent}
|
{(isActive) => {
|
||||||
/>
|
switch (contentType) {
|
||||||
);
|
case ContentType.Archived:
|
||||||
case ContentType.Settings:
|
return (
|
||||||
return (
|
<ArchivedChats
|
||||||
<Settings
|
isActive={isActive}
|
||||||
isActive={isActive}
|
onReset={handleReset}
|
||||||
currentScreen={settingsScreen}
|
onContentChange={setContent}
|
||||||
foldersState={foldersState}
|
/>
|
||||||
foldersDispatch={foldersDispatch}
|
);
|
||||||
onScreenSelect={handleSettingsScreenSelect}
|
case ContentType.Settings:
|
||||||
onReset={handleReset}
|
return (
|
||||||
shouldSkipTransition={shouldSkipHistoryAnimations}
|
<Settings
|
||||||
/>
|
isActive={isActive}
|
||||||
);
|
currentScreen={settingsScreen}
|
||||||
case ContentType.NewChannel:
|
foldersState={foldersState}
|
||||||
return (
|
foldersDispatch={foldersDispatch}
|
||||||
<NewChat
|
onScreenSelect={handleSettingsScreenSelect}
|
||||||
key={lastResetTime}
|
onReset={handleReset}
|
||||||
isActive={isActive}
|
shouldSkipTransition={shouldSkipHistoryAnimations}
|
||||||
isChannel
|
/>
|
||||||
content={content}
|
);
|
||||||
onContentChange={setContent}
|
case ContentType.NewChannel:
|
||||||
onReset={handleReset}
|
return (
|
||||||
/>
|
<NewChat
|
||||||
);
|
key={lastResetTime}
|
||||||
case ContentType.NewGroup:
|
isActive={isActive}
|
||||||
return (
|
isChannel
|
||||||
<NewChat
|
content={content}
|
||||||
key={lastResetTime}
|
onContentChange={setContent}
|
||||||
isActive={isActive}
|
onReset={handleReset}
|
||||||
content={content}
|
/>
|
||||||
onContentChange={setContent}
|
);
|
||||||
onReset={handleReset}
|
case ContentType.NewGroup:
|
||||||
/>
|
return (
|
||||||
);
|
<NewChat
|
||||||
default:
|
key={lastResetTime}
|
||||||
return (
|
isActive={isActive}
|
||||||
<LeftMain
|
content={content}
|
||||||
content={content}
|
onContentChange={setContent}
|
||||||
searchQuery={searchQuery}
|
onReset={handleReset}
|
||||||
searchDate={searchDate}
|
/>
|
||||||
contactsFilter={contactsFilter}
|
);
|
||||||
foldersDispatch={foldersDispatch}
|
default:
|
||||||
onContentChange={setContent}
|
return (
|
||||||
onSearchQuery={handleSearchQuery}
|
<LeftMain
|
||||||
onScreenSelect={handleSettingsScreenSelect}
|
content={content}
|
||||||
onReset={handleReset}
|
searchQuery={searchQuery}
|
||||||
shouldSkipTransition={shouldSkipHistoryAnimations}
|
searchDate={searchDate}
|
||||||
/>
|
contactsFilter={contactsFilter}
|
||||||
);
|
foldersDispatch={foldersDispatch}
|
||||||
}
|
onContentChange={setContent}
|
||||||
}}
|
onSearchQuery={handleSearchQuery}
|
||||||
</Transition>
|
onScreenSelect={handleSettingsScreenSelect}
|
||||||
|
onReset={handleReset}
|
||||||
|
shouldSkipTransition={shouldSkipHistoryAnimations}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
</Transition>
|
||||||
|
<div
|
||||||
|
className="resize-handle"
|
||||||
|
onMouseDown={initResize}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
onDoubleClick={resetResize}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -346,13 +367,14 @@ export default memo(withGlobal(
|
|||||||
activeChatFolder,
|
activeChatFolder,
|
||||||
},
|
},
|
||||||
shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations,
|
||||||
|
leftColumnWidth,
|
||||||
} = global;
|
} = global;
|
||||||
return {
|
return {
|
||||||
searchQuery: query, searchDate: date, activeChatFolder, shouldSkipHistoryAnimations,
|
searchQuery: query, searchDate: date, activeChatFolder, shouldSkipHistoryAnimations, leftColumnWidth,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(setGlobal, actions): DispatchProps => pick(actions, [
|
(setGlobal, actions): DispatchProps => pick(actions, [
|
||||||
'setGlobalSearchQuery', 'setGlobalSearchChatId', 'resetChatCreation', 'setGlobalSearchDate',
|
'setGlobalSearchQuery', 'setGlobalSearchChatId', 'resetChatCreation', 'setGlobalSearchDate',
|
||||||
'loadPasswordInfo', 'clearTwoFaError',
|
'loadPasswordInfo', 'clearTwoFaError', 'setLeftColumnWidth', 'resetLeftColumnWidth',
|
||||||
]),
|
]),
|
||||||
)(LeftColumn));
|
)(LeftColumn));
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#Main {
|
#Main {
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -11,13 +10,25 @@
|
|||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
height: calc(var(--vh, 1vh) * 100);
|
height: calc(var(--vh, 1vh) * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 926px) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-template-rows: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#LeftColumn {
|
#LeftColumn {
|
||||||
flex: 1;
|
min-width: 12rem;
|
||||||
min-width: 18rem;
|
width: 25vw;
|
||||||
max-width: 26.5rem;
|
max-width: 26.5rem;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
height: calc(var(--vh, 1vh) * 100);
|
height: calc(var(--vh, 1vh) * 100);
|
||||||
@ -27,8 +38,12 @@
|
|||||||
border-left: 1px solid var(--color-borders);
|
border-left: 1px solid var(--color-borders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1275px) {
|
@media (min-width: 926px) {
|
||||||
flex: 2;
|
max-width: 40vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1276px) {
|
||||||
|
max-width: 33vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 925px) {
|
@media (max-width: 925px) {
|
||||||
@ -36,7 +51,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
height: calc(var(--vh, 1vh) * 100);
|
height: calc(var(--vh, 1vh) * 100);
|
||||||
width: 26.5rem;
|
width: 26.5rem !important;
|
||||||
|
|
||||||
transform: translate3d(-5rem, 0, 0);
|
transform: translate3d(-5rem, 0, 0);
|
||||||
transition: transform var(--layer-transition);
|
transition: transform var(--layer-transition);
|
||||||
@ -92,7 +107,7 @@
|
|||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
max-width: none;
|
max-width: none;
|
||||||
width: 100vw;
|
width: 100vw !important;
|
||||||
transform: translate3d(-20vw, 0, 0);
|
transform: translate3d(-20vw, 0, 0);
|
||||||
|
|
||||||
@supports (left: env(safe-area-inset-left)) {
|
@supports (left: env(safe-area-inset-left)) {
|
||||||
@ -125,21 +140,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#MiddleColumn {
|
#MiddleColumn {
|
||||||
flex: 3;
|
|
||||||
border-left: 1px solid var(--color-borders);
|
border-left: 1px solid var(--color-borders);
|
||||||
max-width: 75vw;
|
|
||||||
|
|
||||||
@media (max-width: 1275px) {
|
|
||||||
max-width: calc(100vw - 26.5rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 66.25rem) {
|
|
||||||
max-width: 60vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1680px) {
|
@media (min-width: 1680px) {
|
||||||
border-right: 1px solid var(--color-borders);
|
border-right: 1px solid var(--color-borders);
|
||||||
max-width: calc(1680px - 26.5rem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 925px) {
|
@media (max-width: 925px) {
|
||||||
|
|||||||
@ -76,6 +76,7 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@ -76,6 +76,10 @@
|
|||||||
.ListItem-button {
|
.ListItem-button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
body.cursor-ew-resize & {
|
||||||
|
cursor: ew-resize !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
&:hover, &:focus {
|
&:hover, &:focus {
|
||||||
--background-color: var(--color-chat-hover);
|
--background-color: var(--color-chat-hover);
|
||||||
|
|||||||
@ -164,6 +164,7 @@ function updateCache() {
|
|||||||
'recentEmojis',
|
'recentEmojis',
|
||||||
'push',
|
'push',
|
||||||
'shouldShowContextMenuHint',
|
'shouldShowContextMenuHint',
|
||||||
|
'leftColumnWidth',
|
||||||
]),
|
]),
|
||||||
isChatInfoShown: reduceShowChatInfo(global),
|
isChatInfoShown: reduceShowChatInfo(global),
|
||||||
users: reduceUsers(global),
|
users: reduceUsers(global),
|
||||||
|
|||||||
@ -83,6 +83,7 @@ export type GlobalState = {
|
|||||||
currentUserId?: number;
|
currentUserId?: number;
|
||||||
lastSyncTime?: number;
|
lastSyncTime?: number;
|
||||||
serverTimeOffset: number;
|
serverTimeOffset: number;
|
||||||
|
leftColumnWidth?: number;
|
||||||
|
|
||||||
// TODO Move to `auth`.
|
// TODO Move to `auth`.
|
||||||
isLoggingOut?: boolean;
|
isLoggingOut?: boolean;
|
||||||
@ -447,7 +448,7 @@ export type ActionTypes = (
|
|||||||
// ui
|
// ui
|
||||||
'toggleChatInfo' | 'setIsUiReady' | 'addRecentEmoji' | 'addRecentSticker' | 'toggleLeftColumn' |
|
'toggleChatInfo' | 'setIsUiReady' | 'addRecentEmoji' | 'addRecentSticker' | 'toggleLeftColumn' |
|
||||||
'toggleSafeLinkModal' | 'openHistoryCalendar' | 'closeHistoryCalendar' | 'disableContextMenuHint' |
|
'toggleSafeLinkModal' | 'openHistoryCalendar' | 'closeHistoryCalendar' | 'disableContextMenuHint' |
|
||||||
'setNewChatMembersDialogState' | 'disableHistoryAnimations' |
|
'setNewChatMembersDialogState' | 'disableHistoryAnimations' | 'setLeftColumnWidth' | 'resetLeftColumnWidth' |
|
||||||
// auth
|
// auth
|
||||||
'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' |
|
'setAuthPhoneNumber' | 'setAuthCode' | 'setAuthPassword' | 'signUp' | 'returnToAuthPhoneNumber' | 'signOut' |
|
||||||
'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'goToAuthQrCode' | 'clearCache' |
|
'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'goToAuthQrCode' | 'clearCache' |
|
||||||
|
|||||||
64
src/hooks/useResize.ts
Normal file
64
src/hooks/useResize.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { RefObject } from 'react';
|
||||||
|
import { useState, useEffect } from '../lib/teact/teact';
|
||||||
|
import useFlag from './useFlag';
|
||||||
|
|
||||||
|
export const useResize = (
|
||||||
|
elementRef: RefObject<HTMLElement>,
|
||||||
|
onResize: (width: number) => void,
|
||||||
|
onReset: NoneToVoidFunction,
|
||||||
|
initialWidth?: number,
|
||||||
|
) => {
|
||||||
|
const [isActive, markIsActive, unmarkIsActive] = useFlag();
|
||||||
|
const [initialMouseX, setInitialMouseX] = useState<number>();
|
||||||
|
const [initialElementWidth, setInitialElementWidth] = useState<number>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!elementRef.current || !initialWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elementRef.current.style.width = `${initialWidth}px`;
|
||||||
|
}, [elementRef, initialWidth]);
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
document.body.classList.remove('no-selection', 'cursor-ew-resize');
|
||||||
|
};
|
||||||
|
|
||||||
|
const initResize = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||||
|
document.body.classList.add('no-selection', 'cursor-ew-resize');
|
||||||
|
|
||||||
|
setInitialMouseX(event.clientX);
|
||||||
|
setInitialElementWidth(elementRef.current!.offsetWidth);
|
||||||
|
markIsActive();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetResize = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
elementRef.current!.style.width = '';
|
||||||
|
onReset();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isActive) return;
|
||||||
|
|
||||||
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
|
const newWidth = Math.ceil(initialElementWidth + event.clientX - initialMouseX);
|
||||||
|
elementRef.current!.style.width = `${newWidth}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopDrag = () => {
|
||||||
|
handleMouseUp();
|
||||||
|
document.removeEventListener('mousemove', handleMouseMove, false);
|
||||||
|
document.removeEventListener('mouseup', stopDrag, false);
|
||||||
|
document.removeEventListener('blur', stopDrag, false);
|
||||||
|
onResize(elementRef.current!.offsetWidth);
|
||||||
|
unmarkIsActive();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', handleMouseMove, false);
|
||||||
|
document.addEventListener('mouseup', stopDrag, false);
|
||||||
|
document.addEventListener('blur', stopDrag, false);
|
||||||
|
}, [initialElementWidth, initialMouseX, elementRef, onResize, isActive, unmarkIsActive]);
|
||||||
|
|
||||||
|
return { initResize, resetResize, handleMouseUp };
|
||||||
|
};
|
||||||
@ -17,6 +17,22 @@ addReducer('toggleChatInfo', (global) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addReducer('setLeftColumnWidth', (global, actions, payload) => {
|
||||||
|
const leftColumnWidth = payload;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
leftColumnWidth,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
addReducer('resetLeftColumnWidth', (global) => {
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
leftColumnWidth: undefined,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
addReducer('toggleManagement', (global): GlobalState | undefined => {
|
addReducer('toggleManagement', (global): GlobalState | undefined => {
|
||||||
const { chatId } = selectCurrentMessageList(global) || {};
|
const { chatId } = selectCurrentMessageList(global) || {};
|
||||||
|
|
||||||
|
|||||||
@ -194,6 +194,7 @@ $color-user-8: #faa774;
|
|||||||
--z-sticky-date: 9;
|
--z-sticky-date: 9;
|
||||||
--z-register-add-avatar: 5;
|
--z-register-add-avatar: 5;
|
||||||
--z-media-viewer-head: 3;
|
--z-media-viewer-head: 3;
|
||||||
|
--z-resize-handle: 2;
|
||||||
--z-below: -1;
|
--z-below: -1;
|
||||||
|
|
||||||
--spinner-white-data: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEwLjggMjIuNEM2IDIxLjkgMi4xIDE4IDEuNiAxMy4yLjkgNy4xIDUuNCAxLjkgMTEuMyAxLjVjLjQgMCAuNy0uMy43LS43IDAtLjQtLjQtLjgtLjgtLjhDNC44LjQtLjIgNS45IDAgMTIuNS4yIDE4LjYgNS40IDIzLjggMTEuNSAyNGM2LjYuMiAxMi00LjggMTIuNC0xMS4yIDAtLjQtLjMtLjgtLjgtLjgtLjQgMC0uNy4zLS43LjctLjMgNS45LTUuNSAxMC40LTExLjYgOS43eiIgZmlsbD0iI2ZmZmZmZiIvPjwvc3ZnPg==);
|
--spinner-white-data: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEwLjggMjIuNEM2IDIxLjkgMi4xIDE4IDEuNiAxMy4yLjkgNy4xIDUuNCAxLjkgMTEuMyAxLjVjLjQgMCAuNy0uMy43LS43IDAtLjQtLjQtLjgtLjgtLjhDNC44LjQtLjIgNS45IDAgMTIuNS4yIDE4LjYgNS40IDIzLjggMTEuNSAyNGM2LjYuMiAxMi00LjggMTIuNC0xMS4yIDAtLjQtLjMtLjgtLjgtLjgtLjQgMC0uNy4zLS43LjctLjMgNS45LTUuNSAxMC40LTExLjYgOS43eiIgZmlsbD0iI2ZmZmZmZiIvPjwvc3ZnPg==);
|
||||||
|
|||||||
@ -49,9 +49,13 @@ body.cursor-grabbing, body.cursor-grabbing * {
|
|||||||
cursor: grabbing !important;
|
cursor: grabbing !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.cursor-ew-resize {
|
||||||
|
cursor: ew-resize !important;
|
||||||
|
}
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
max-width: 1680px;
|
max-width: 1920px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
height: calc(var(--vh, 1vh) * 100);
|
height: calc(var(--vh, 1vh) * 100);
|
||||||
@ -75,6 +79,21 @@ body.cursor-grabbing, body.cursor-grabbing * {
|
|||||||
-webkit-user-select: none !important;
|
-webkit-user-select: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resize-handle {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -.1875rem;
|
||||||
|
bottom: 0;
|
||||||
|
width: .1875rem;
|
||||||
|
z-index: var(--z-resize-handle);
|
||||||
|
cursor: ew-resize;
|
||||||
|
|
||||||
|
@media (min-width: 926px) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
See the article for more information on this visually-hidden pattern.
|
See the article for more information on this visually-hidden pattern.
|
||||||
https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
|
https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user