mirror of https://github.com/fantasticit/think.git
fix: fix layout drag width
parent
8847133683
commit
af358c1e04
|
@ -0,0 +1,9 @@
|
||||||
|
export function clamp(val: number, min: number, max: number): number {
|
||||||
|
if (val < min) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
if (val > max) {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
export function getStorage(key) {
|
export function getStorage(key, defaultValue = null) {
|
||||||
if (typeof window === 'undefined') throw new Error();
|
if (typeof window === 'undefined') throw new Error();
|
||||||
|
|
||||||
const value = localStorage.getItem(key);
|
const value = localStorage.getItem(key);
|
||||||
if (!value) return undefined;
|
if (!value) return defaultValue;
|
||||||
try {
|
try {
|
||||||
return JSON.parse(value);
|
return JSON.parse(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,56 +1,85 @@
|
||||||
import { useCallback, useEffect, useRef } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { useWindowSize } from 'hooks/use-window-size';
|
import { useWindowSize } from 'hooks/use-window-size';
|
||||||
import { setStorage, getStorage } from 'helpers/storage';
|
import { setStorage, getStorage } from 'helpers/storage';
|
||||||
|
import { clamp } from 'helpers/clamp';
|
||||||
|
|
||||||
const key = 'dragable-menu-width';
|
const key = 'dragable-menu-width';
|
||||||
export const MIN_WIDTH = 240;
|
|
||||||
export const MAX_WIDTH = 600;
|
|
||||||
|
|
||||||
|
const DEFAULT_PC_MIN_WIDTH = 240;
|
||||||
|
const DEFAULT_PC_MAX_WIDTH = 600;
|
||||||
|
|
||||||
|
const DEFAULT_MOBILE_MIN_WIDTH = 24;
|
||||||
|
const DEFAULT_MOBILE_MAX_WIDTH = 240;
|
||||||
|
|
||||||
|
// 收起宽度:24
|
||||||
const COLLAPSED_WIDTH = 24;
|
const COLLAPSED_WIDTH = 24;
|
||||||
|
|
||||||
|
const PC_MOBILE_CRITICAL_WIDTH = 765;
|
||||||
|
|
||||||
export const useDragableWidth = () => {
|
export const useDragableWidth = () => {
|
||||||
const runTimeWidthRef = useRef(null);
|
const { width: windowWidth } = useWindowSize();
|
||||||
const { data, mutate } = useSWR<number>(key, getStorage);
|
const [minWidth, setMinWidth] = useState(DEFAULT_MOBILE_MIN_WIDTH);
|
||||||
const windowSize = useWindowSize();
|
const [maxWidth, setMaxWidth] = useState(DEFAULT_MOBILE_MAX_WIDTH);
|
||||||
const isCollapsed = data <= COLLAPSED_WIDTH;
|
const { data: currentWidth, mutate } = useSWR<number>(key, () => {
|
||||||
|
const nextWidth = getStorage(key, minWidth);
|
||||||
|
|
||||||
const updateWidth = (size) => {
|
if (nextWidth <= COLLAPSED_WIDTH) {
|
||||||
|
return COLLAPSED_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clamp(nextWidth, minWidth, maxWidth);
|
||||||
|
});
|
||||||
|
const prevWidthRef = useRef<number>(maxWidth);
|
||||||
|
|
||||||
|
const updateWidth = useCallback(
|
||||||
|
(size) => {
|
||||||
|
const isMobile = windowWidth <= PC_MOBILE_CRITICAL_WIDTH;
|
||||||
|
|
||||||
|
if (isMobile && size < maxWidth) {
|
||||||
|
size = minWidth;
|
||||||
|
}
|
||||||
setStorage(key, size);
|
setStorage(key, size);
|
||||||
|
prevWidthRef.current = size;
|
||||||
mutate();
|
mutate();
|
||||||
runTimeWidthRef.current = size;
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleCollapsed = useCallback(
|
|
||||||
(collapsed = null) => {
|
|
||||||
const isBool = typeof collapsed === 'boolean';
|
|
||||||
const nextCollapsed = isBool ? collapsed : !isCollapsed;
|
|
||||||
const nextWidth = nextCollapsed ? COLLAPSED_WIDTH : MIN_WIDTH;
|
|
||||||
setStorage(key, nextWidth);
|
|
||||||
mutate();
|
|
||||||
runTimeWidthRef.current = nextWidth;
|
|
||||||
},
|
},
|
||||||
[isCollapsed, mutate]
|
[mutate, windowWidth, minWidth, maxWidth]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
const toggleCollapsed = useCallback(() => {
|
||||||
mutate();
|
const isCollapsed = currentWidth <= COLLAPSED_WIDTH;
|
||||||
|
|
||||||
return () => {
|
if (!isCollapsed) {
|
||||||
runTimeWidthRef.current = null;
|
prevWidthRef.current = currentWidth;
|
||||||
};
|
setStorage(key, COLLAPSED_WIDTH);
|
||||||
}, [mutate]);
|
} else {
|
||||||
|
let nextWidth = prevWidthRef.current;
|
||||||
|
|
||||||
useEffect(() => {
|
if (nextWidth >= maxWidth) {
|
||||||
if (!windowSize.width) return;
|
nextWidth = maxWidth;
|
||||||
if (windowSize.width <= 765) {
|
|
||||||
toggleCollapsed(true);
|
|
||||||
}
|
}
|
||||||
}, [windowSize.width, toggleCollapsed]);
|
|
||||||
|
if (nextWidth <= minWidth) {
|
||||||
|
nextWidth = minWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
setStorage(key, nextWidth);
|
||||||
|
}
|
||||||
|
mutate();
|
||||||
|
}, [mutate, currentWidth, minWidth]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const min = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MIN_WIDTH : DEFAULT_PC_MIN_WIDTH;
|
||||||
|
const max = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MAX_WIDTH : DEFAULT_PC_MAX_WIDTH;
|
||||||
|
setMinWidth(min);
|
||||||
|
setMaxWidth(max);
|
||||||
|
}, [windowWidth, mutate, currentWidth]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: data,
|
minWidth,
|
||||||
isCollapsed,
|
maxWidth,
|
||||||
|
width: currentWidth,
|
||||||
|
isCollapsed: currentWidth <= COLLAPSED_WIDTH,
|
||||||
toggleCollapsed,
|
toggleCollapsed,
|
||||||
updateWidth,
|
updateWidth,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ import cls from 'classnames';
|
||||||
import { Layout as SemiLayout, Button } from '@douyinfe/semi-ui';
|
import { Layout as SemiLayout, Button } from '@douyinfe/semi-ui';
|
||||||
import { IconChevronLeft, IconChevronRight } from '@douyinfe/semi-icons';
|
import { IconChevronLeft, IconChevronRight } from '@douyinfe/semi-icons';
|
||||||
import SplitPane from 'react-split-pane';
|
import SplitPane from 'react-split-pane';
|
||||||
import { useDragableWidth, MIN_WIDTH, MAX_WIDTH } from 'hooks/use-dragable-width';
|
import { useDragableWidth } from 'hooks/use-dragable-width';
|
||||||
import { RouterHeader } from '../router-header';
|
import { RouterHeader } from '../router-header';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
@ -15,13 +15,13 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DoubleColumnLayout: React.FC<IProps> = ({ leftNode, rightNode }) => {
|
export const DoubleColumnLayout: React.FC<IProps> = ({ leftNode, rightNode }) => {
|
||||||
const { width, isCollapsed, updateWidth, toggleCollapsed } = useDragableWidth();
|
const { minWidth, maxWidth, width, isCollapsed, updateWidth, toggleCollapsed } = useDragableWidth();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SemiLayout className={styles.wrap}>
|
<SemiLayout className={styles.wrap}>
|
||||||
<RouterHeader />
|
<RouterHeader />
|
||||||
<SemiLayout className={styles.contentWrap}>
|
<SemiLayout className={styles.contentWrap}>
|
||||||
<SplitPane minSize={MIN_WIDTH} maxSize={MAX_WIDTH} size={width} onChange={updateWidth}>
|
<SplitPane minSize={minWidth} maxSize={maxWidth} size={width} onChange={updateWidth}>
|
||||||
<Sider style={{ width: '100%', height: '100%' }} className={styles.leftWrap}>
|
<Sider style={{ width: '100%', height: '100%' }} className={styles.leftWrap}>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -1,9 +1 @@
|
||||||
export function clamp(val: number, min: number, max: number): number {
|
export * from 'helpers/clamp';
|
||||||
if (val < min) {
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
if (val > max) {
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue