feat: support sidebar zoom (#1190)
This commit is contained in:
92
apps/web/src/components/workspace-slider-bar/DragLine.tsx
Normal file
92
apps/web/src/components/workspace-slider-bar/DragLine.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { styled } from '@affine/component';
|
||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
const StyledDragLine = styled.div(({ theme }) => {
|
||||||
|
return {
|
||||||
|
width: '5px',
|
||||||
|
height: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
top: '0',
|
||||||
|
right: '-10px',
|
||||||
|
cursor: 'col-resize',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export type DragLineProps = {
|
||||||
|
onDrag?: (params: { movementX: number; movementY: number }) => void;
|
||||||
|
initialPosition?: { x: number; y: number };
|
||||||
|
leftOffset?: number;
|
||||||
|
rightOffset?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DragLine = ({
|
||||||
|
onDrag,
|
||||||
|
leftOffset,
|
||||||
|
rightOffset,
|
||||||
|
initialPosition,
|
||||||
|
}: DragLineProps) => {
|
||||||
|
const isDragging = useRef(false);
|
||||||
|
const lineRef = useRef<HTMLDivElement>(null);
|
||||||
|
const recordPosition = useRef({ x: 0, y: 0 });
|
||||||
|
useEffect(() => {
|
||||||
|
const onMouseMove = (e: MouseEvent) => {
|
||||||
|
if (!isDragging.current) return;
|
||||||
|
|
||||||
|
const movementX = e.clientX - recordPosition.current.x;
|
||||||
|
const movementY = e.clientY - recordPosition.current.y;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(rightOffset !== undefined &&
|
||||||
|
initialPosition &&
|
||||||
|
initialPosition.x + rightOffset < recordPosition.current.x) ||
|
||||||
|
(leftOffset !== undefined &&
|
||||||
|
initialPosition &&
|
||||||
|
recordPosition.current.x - initialPosition.x < leftOffset)
|
||||||
|
) {
|
||||||
|
recordPosition.current.x = e.clientX;
|
||||||
|
recordPosition.current.y = e.clientY;
|
||||||
|
document.body.style.cursor = 'not-allowed';
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.body.style.cursor = 'col-resize';
|
||||||
|
|
||||||
|
onDrag?.({ movementX, movementY });
|
||||||
|
recordPosition.current.x = e.clientX;
|
||||||
|
recordPosition.current.y = e.clientY;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseUp = () => {
|
||||||
|
isDragging.current = false;
|
||||||
|
document.body.style.cursor = '';
|
||||||
|
};
|
||||||
|
document.addEventListener('mousemove', onMouseMove);
|
||||||
|
document.addEventListener('mouseup', onMouseUp);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousemove', onMouseMove);
|
||||||
|
document.removeEventListener('mouseup', onMouseUp);
|
||||||
|
};
|
||||||
|
}, [initialPosition, leftOffset, onDrag, rightOffset]);
|
||||||
|
return (
|
||||||
|
<StyledDragLine
|
||||||
|
ref={lineRef}
|
||||||
|
//The mouse event is used instead of the drag event because the drag event triggers the drag image display
|
||||||
|
onMouseDown={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
isDragging.current = true;
|
||||||
|
const position = lineRef.current?.getBoundingClientRect();
|
||||||
|
recordPosition.current = {
|
||||||
|
x: position?.x || 0,
|
||||||
|
y: position?.y || 0,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
onMouseUp={() => {
|
||||||
|
isDragging.current = false;
|
||||||
|
|
||||||
|
console.log('onMouseUp');
|
||||||
|
}}
|
||||||
|
></StyledDragLine>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DragLine;
|
||||||
@@ -20,6 +20,7 @@ import { usePageHelper } from '@/hooks/use-page-helper';
|
|||||||
import { useGlobalState } from '@/store/app';
|
import { useGlobalState } from '@/store/app';
|
||||||
import { useModal } from '@/store/globalModal';
|
import { useModal } from '@/store/globalModal';
|
||||||
|
|
||||||
|
import StyledDragLine from './DragLine';
|
||||||
import { Arrow } from './icons';
|
import { Arrow } from './icons';
|
||||||
import {
|
import {
|
||||||
StyledArrowButton,
|
StyledArrowButton,
|
||||||
@@ -32,6 +33,8 @@ import {
|
|||||||
} from './style';
|
} from './style';
|
||||||
import { WorkspaceSelector } from './WorkspaceSelector/WorkspaceSelector';
|
import { WorkspaceSelector } from './WorkspaceSelector/WorkspaceSelector';
|
||||||
|
|
||||||
|
const MAX_WIDTH = 534;
|
||||||
|
const MIN_WIDTH = 256;
|
||||||
const FavoriteList = ({ showList }: { showList: boolean }) => {
|
const FavoriteList = ({ showList }: { showList: boolean }) => {
|
||||||
const { openPage } = usePageHelper();
|
const { openPage } = usePageHelper();
|
||||||
const pageList = useGlobalState(store => store.dataCenterPageList);
|
const pageList = useGlobalState(store => store.dataCenterPageList);
|
||||||
@@ -67,6 +70,7 @@ const FavoriteList = ({ showList }: { showList: boolean }) => {
|
|||||||
export const WorkSpaceSliderBar = () => {
|
export const WorkSpaceSliderBar = () => {
|
||||||
const { triggerQuickSearchModal } = useModal();
|
const { triggerQuickSearchModal } = useModal();
|
||||||
const [showSubFavorite, setShowSubFavorite] = useState(true);
|
const [showSubFavorite, setShowSubFavorite] = useState(true);
|
||||||
|
const [sideBarWidth, setSideBarWidth] = useState(256);
|
||||||
const currentWorkspace = useGlobalState(
|
const currentWorkspace = useGlobalState(
|
||||||
useCallback(store => store.currentDataCenterWorkspace, [])
|
useCallback(store => store.currentDataCenterWorkspace, [])
|
||||||
);
|
);
|
||||||
@@ -88,7 +92,17 @@ export const WorkSpaceSliderBar = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledSliderBar show={show}>
|
<StyledSliderBar show={show} width={sideBarWidth}>
|
||||||
|
{show && (
|
||||||
|
<StyledDragLine
|
||||||
|
initialPosition={{ x: MIN_WIDTH, y: 0 }}
|
||||||
|
rightOffset={MAX_WIDTH - MIN_WIDTH}
|
||||||
|
leftOffset={0}
|
||||||
|
onDrag={({ movementX }) => {
|
||||||
|
setSideBarWidth(sideBarWidth + movementX);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={show ? t('Collapse sidebar') : t('Expand sidebar')}
|
content={show ? t('Collapse sidebar') : t('Expand sidebar')}
|
||||||
placement="right"
|
placement="right"
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { displayFlex, styled, textEllipsis } from '@affine/component';
|
import { displayFlex, styled, textEllipsis } from '@affine/component';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { CSSProperties } from 'react';
|
||||||
|
|
||||||
export const StyledSliderBar = styled.div<{ show: boolean }>(
|
export const StyledSliderBar = styled.div<{
|
||||||
({ theme, show }) => {
|
show: boolean;
|
||||||
|
width: CSSProperties['width'];
|
||||||
|
}>(({ theme, show, width }) => {
|
||||||
return {
|
return {
|
||||||
width: show ? '256px' : '0',
|
width: show ? width : '0',
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
minHeight: '450px',
|
minHeight: '450px',
|
||||||
background: theme.colors.hubBackground,
|
background: theme.colors.hubBackground,
|
||||||
@@ -15,8 +18,7 @@ export const StyledSliderBar = styled.div<{ show: boolean }>(
|
|||||||
padding: show ? '24px 12px' : '24px 0',
|
padding: show ? '24px 12px' : '24px 0',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
);
|
|
||||||
export const StyledSliderBarWrapper = styled.div(() => {
|
export const StyledSliderBarWrapper = styled.div(() => {
|
||||||
return {
|
return {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
|||||||
Reference in New Issue
Block a user