mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-25 06:18:45 +08:00
feat(core): hide all sidebars when resizing to a small screen (#11105)
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { observeResize } from '@affine/component';
|
||||
import { AppSidebarService } from '@affine/core/modules/app-sidebar';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
let OBSERVED = false;
|
||||
|
||||
export const useResponsiveSidebar = (
|
||||
hideThreshold = 540,
|
||||
floatThreshold = 768
|
||||
) => {
|
||||
const previousWidthRef = useRef<number | null>(null);
|
||||
|
||||
const appSidebarService = useService(AppSidebarService);
|
||||
const workbenchService = useService(WorkbenchService);
|
||||
|
||||
const handleHideSidebar = useCallback(() => {
|
||||
appSidebarService.sidebar.setOpen(false);
|
||||
workbenchService.workbench.setSidebarOpen(false);
|
||||
}, [appSidebarService, workbenchService]);
|
||||
|
||||
const handleFloatSidebar = useCallback(
|
||||
(float: boolean) => {
|
||||
appSidebarService.sidebar.setSmallScreenMode(float);
|
||||
},
|
||||
[appSidebarService.sidebar]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (OBSERVED) {
|
||||
console.warn(
|
||||
`"${useResponsiveSidebar.name}" already observed, do not call it multiple times`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
OBSERVED = true;
|
||||
const unobserve = observeResize(document.body, entry => {
|
||||
if (BUILD_CONFIG.isMobileEdition) {
|
||||
return;
|
||||
}
|
||||
|
||||
const width = entry.contentRect.width;
|
||||
const previousWidth = previousWidthRef.current;
|
||||
|
||||
if (previousWidth === null) {
|
||||
previousWidthRef.current = width;
|
||||
return;
|
||||
}
|
||||
|
||||
// should hide sidebar
|
||||
if (width <= hideThreshold && previousWidth > hideThreshold) {
|
||||
handleHideSidebar();
|
||||
}
|
||||
|
||||
if (!BUILD_CONFIG.isElectron) {
|
||||
if (width >= floatThreshold && previousWidth < floatThreshold) {
|
||||
handleFloatSidebar(false);
|
||||
}
|
||||
if (width <= floatThreshold && previousWidth > floatThreshold) {
|
||||
handleFloatSidebar(true);
|
||||
}
|
||||
}
|
||||
|
||||
previousWidthRef.current = width;
|
||||
});
|
||||
|
||||
return () => {
|
||||
OBSERVED = false;
|
||||
unobserve();
|
||||
};
|
||||
}, [floatThreshold, handleFloatSidebar, handleHideSidebar, hideThreshold]);
|
||||
};
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
CloudQuotaModal,
|
||||
LocalQuotaModal,
|
||||
} from '@affine/core/components/affine/quota-reached-modal';
|
||||
import { useResponsiveSidebar } from '@affine/core/components/hooks/use-responsive-siedebar';
|
||||
import { SWRConfigProvider } from '@affine/core/components/providers/swr-config-provider';
|
||||
import { WorkspaceSideEffects } from '@affine/core/components/providers/workspace-side-effects';
|
||||
import { AIIsland } from '@affine/core/desktop/components/ai-island';
|
||||
@@ -59,6 +60,7 @@ const WorkspaceLayoutUIContainer = ({ children }: PropsWithChildren) => {
|
||||
return get(workbench.basename$) + get(workbench.location$).pathname;
|
||||
})
|
||||
);
|
||||
useResponsiveSidebar();
|
||||
|
||||
return (
|
||||
<AppContainer data-current-path={currentPath}>{children}</AppContainer>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
export const floatingMaxWidth = 768;
|
||||
export const navWrapperStyle = style({
|
||||
'@media': {
|
||||
print: {
|
||||
|
||||
@@ -11,9 +11,8 @@ import {
|
||||
useServiceOptional,
|
||||
} from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { debounce } from 'lodash-es';
|
||||
import type { PropsWithChildren, ReactElement } from 'react';
|
||||
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useContext, useEffect, useMemo } from 'react';
|
||||
|
||||
import { WorkbenchService } from '../../workbench';
|
||||
import { allowedSplitViewEntityTypes } from '../../workbench/view/split-view/types';
|
||||
@@ -21,7 +20,6 @@ import { WorkspaceService } from '../../workspace';
|
||||
import { AppSidebarService } from '../services/app-sidebar';
|
||||
import * as styles from './fallback.css';
|
||||
import {
|
||||
floatingMaxWidth,
|
||||
hoverNavWrapperStyle,
|
||||
navBodyStyle,
|
||||
navHeaderStyle,
|
||||
@@ -54,21 +52,6 @@ export function AppSidebar({ children }: PropsWithChildren) {
|
||||
const smallScreenMode = useLiveData(appSidebarService.smallScreenMode$);
|
||||
const hovering = useLiveData(appSidebarService.hovering$) && open !== true;
|
||||
const resizing = useLiveData(appSidebarService.resizing$);
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (BUILD_CONFIG.isElectron) {
|
||||
setInitialized(true);
|
||||
return;
|
||||
}
|
||||
const shouldFloating = window.matchMedia(
|
||||
`(max-width: ${floatingMaxWidth}px)`
|
||||
).matches;
|
||||
|
||||
appSidebarService.setSmallScreenMode(shouldFloating);
|
||||
setInitialized(true);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const sidebarState = smallScreenMode
|
||||
? open
|
||||
@@ -80,27 +63,6 @@ export function AppSidebar({ children }: PropsWithChildren) {
|
||||
? 'floating'
|
||||
: 'close';
|
||||
|
||||
useEffect(() => {
|
||||
// do not float app sidebar on desktop
|
||||
if (BUILD_CONFIG.isElectron) {
|
||||
return;
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
const isFloatingMaxWidth = window.matchMedia(
|
||||
`(max-width: ${floatingMaxWidth}px)`
|
||||
).matches;
|
||||
const isFloating = isFloatingMaxWidth;
|
||||
appSidebarService.setSmallScreenMode(isFloating);
|
||||
}
|
||||
|
||||
const dOnResize = debounce(onResize, 50);
|
||||
window.addEventListener('resize', dOnResize);
|
||||
return () => {
|
||||
window.removeEventListener('resize', dOnResize);
|
||||
};
|
||||
}, [appSidebarService]);
|
||||
|
||||
const hasRightBorder = !BUILD_CONFIG.isElectron && !clientBorder;
|
||||
|
||||
const handleOpenChange = useCallback(
|
||||
@@ -176,10 +138,6 @@ export function AppSidebar({ children }: PropsWithChildren) {
|
||||
});
|
||||
}, [workbenchService.views$.value]);
|
||||
|
||||
if (!initialized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResizePanel
|
||||
|
||||
Reference in New Issue
Block a user