JimmFly
2024-10-09 03:48:17 +00:00
parent bfeb05ca45
commit 5213431d51
14 changed files with 173 additions and 120 deletions

View File

@@ -6,6 +6,7 @@ export const resizeHandleVerticalPadding = createVar(
'resize-handle-vertical-padding' 'resize-handle-vertical-padding'
); );
export const animationTimeout = createVar(); export const animationTimeout = createVar();
export const root = style({ export const root = style({
vars: { vars: {
[panelWidthVar]: '256px', [panelWidthVar]: '256px',
@@ -15,23 +16,28 @@ export const root = style({
width: panelWidthVar, width: panelWidthVar,
minWidth: panelWidthVar, minWidth: panelWidthVar,
height: '100%', height: '100%',
selectors: {
'&[data-is-floating="true"]': {
position: 'absolute',
width: `calc(${panelWidthVar})`,
zIndex: 4, zIndex: 4,
}, transform: 'translateX(0)',
'&[data-open="true"]': {
maxWidth: '50%', maxWidth: '50%',
}, selectors: {
'&[data-open="false"][data-handle-position="right"]': { '&[data-open="false"][data-handle-position="right"],&[data-is-floating="true"][data-handle-position="right"]':
{
marginLeft: `calc(${panelWidthVar} * -1)`, marginLeft: `calc(${panelWidthVar} * -1)`,
}, },
'&[data-open="false"][data-handle-position="left"]': { '&[data-open="false"][data-handle-position="left"],&[data-is-floating="true"][data-handle-position="left"]':
{
marginRight: `calc(${panelWidthVar} * -1)`, marginRight: `calc(${panelWidthVar} * -1)`,
}, },
'&[data-open="true"][data-handle-position="right"][data-is-floating="true"]':
{
transform: `translateX(${panelWidthVar})`,
},
'&[data-open="true"][data-handle-position="left"][data-is-floating="true"]':
{
transform: `translateX(-${panelWidthVar})`,
},
'&[data-enable-animation="true"]': { '&[data-enable-animation="true"]': {
transition: `margin-left ${animationTimeout} .05s, margin-right ${animationTimeout} .05s, width ${animationTimeout} .05s`, transition: `margin-left ${animationTimeout}, margin-right ${animationTimeout}, transform ${animationTimeout}, background ${animationTimeout}`,
}, },
'&[data-transition-state="exited"]': { '&[data-transition-state="exited"]': {
// avoid focus on hidden panel // avoid focus on hidden panel

View File

@@ -1,13 +1,6 @@
import { assignInlineVars } from '@vanilla-extract/dynamic'; import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx'; import clsx from 'clsx';
import { import { forwardRef, useCallback, useLayoutEffect, useRef } from 'react';
forwardRef,
useCallback,
useEffect,
useLayoutEffect,
useRef,
useState,
} from 'react';
import { useTransition } from 'react-transition-state'; import { useTransition } from 'react-transition-state';
import * as styles from './resize-panel.css'; import * as styles from './resize-panel.css';
@@ -129,17 +122,6 @@ const ResizeHandle = ({
); );
}; };
// delay initial animation to avoid flickering
function useEnableAnimation() {
const [enable, setEnable] = useState(false);
useEffect(() => {
window.setTimeout(() => {
setEnable(true);
}, 500);
}, []);
return enable;
}
const animationTimeout = 300; const animationTimeout = 300;
export const ResizePanel = forwardRef<HTMLDivElement, ResizePanelProps>( export const ResizePanel = forwardRef<HTMLDivElement, ResizePanelProps>(
@@ -152,7 +134,7 @@ export const ResizePanel = forwardRef<HTMLDivElement, ResizePanelProps>(
maxWidth, maxWidth,
width, width,
floating, floating,
enableAnimation: _enableAnimation = true, enableAnimation = true,
open, open,
unmountOnExit, unmountOnExit,
onOpen, onOpen,
@@ -165,7 +147,6 @@ export const ResizePanel = forwardRef<HTMLDivElement, ResizePanelProps>(
}, },
ref ref
) { ) {
const enableAnimation = useEnableAnimation() && _enableAnimation;
const safeWidth = Math.min(maxWidth, Math.max(minWidth, width)); const safeWidth = Math.min(maxWidth, Math.max(minWidth, width));
const [{ status }, toggle] = useTransition({ const [{ status }, toggle] = useTransition({
timeout: animationTimeout, timeout: animationTimeout,

View File

@@ -18,14 +18,8 @@ interface HeaderPros {
export const Header = ({ left, center, right }: HeaderPros) => { export const Header = ({ left, center, right }: HeaderPros) => {
const appSidebarService = useService(AppSidebarService).sidebar; const appSidebarService = useService(AppSidebarService).sidebar;
const open = useLiveData(appSidebarService.open$); const open = useLiveData(appSidebarService.open$);
const appSidebarFloating = useLiveData(appSidebarService.responsiveFloating$);
return ( return (
<div <div className={clsx(style.header)} data-open={open} data-testid="header">
className={clsx(style.header)}
data-open={open}
data-sidebar-floating={appSidebarFloating}
data-testid="header"
>
<div className={clsx(style.headerSideContainer)}> <div className={clsx(style.headerSideContainer)}>
<div className={clsx(style.headerItem, 'left')}> <div className={clsx(style.headerItem, 'left')}>
<div>{left}</div> <div>{left}</div>

View File

@@ -1,5 +1,7 @@
import { cssVar, lightCssVariables } from '@toeverything/theme'; import { cssVar, lightCssVariables } from '@toeverything/theme';
import { globalStyle, style } from '@vanilla-extract/css'; import { createVar, globalStyle, style } from '@vanilla-extract/css';
export const panelWidthVar = createVar('panel-width');
export const appStyle = style({ export const appStyle = style({
width: '100%', width: '100%',
@@ -48,7 +50,7 @@ export const mainContainerStyle = style({
flex: 1, flex: 1,
overflow: 'clip', overflow: 'clip',
maxWidth: '100%', maxWidth: '100%',
transition: 'margin-left 0.2s ease',
selectors: { selectors: {
'&[data-client-border="true"]': { '&[data-client-border="true"]': {
borderRadius: 6, borderRadius: 6,

View File

@@ -49,9 +49,9 @@ export const MainContainer = forwardRef<
HTMLDivElement, HTMLDivElement,
PropsWithChildren<MainContainerProps> PropsWithChildren<MainContainerProps>
>(function MainContainer({ className, children, ...props }, ref): ReactElement { >(function MainContainer({ className, children, ...props }, ref): ReactElement {
const appSidebarService = useService(AppSidebarService).sidebar;
const appSideBarOpen = useLiveData(appSidebarService.open$);
const { appSettings } = useAppSettingHelper(); const { appSettings } = useAppSettingHelper();
const appSidebarService = useService(AppSidebarService).sidebar;
const open = useLiveData(appSidebarService.open$);
return ( return (
<div <div
@@ -60,7 +60,7 @@ export const MainContainer = forwardRef<
data-is-desktop={BUILD_CONFIG.isElectron} data-is-desktop={BUILD_CONFIG.isElectron}
data-transparent={false} data-transparent={false}
data-client-border={appSettings.clientBorder} data-client-border={appSettings.clientBorder}
data-side-bar-open={appSideBarOpen} data-side-bar-open={open}
data-testid="main-container" data-testid="main-container"
ref={ref} ref={ref}
> >

View File

@@ -16,7 +16,6 @@ import { useRegisterCopyLinkCommands } from '@affine/core/components/hooks/affin
import { useDocCollectionPageTitle } from '@affine/core/components/hooks/use-block-suite-workspace-page-title'; import { useDocCollectionPageTitle } from '@affine/core/components/hooks/use-block-suite-workspace-page-title';
import { useJournalInfoHelper } from '@affine/core/components/hooks/use-journal'; import { useJournalInfoHelper } from '@affine/core/components/hooks/use-journal';
import { HeaderDivider } from '@affine/core/components/pure/header'; import { HeaderDivider } from '@affine/core/components/pure/header';
import { AppSidebarService } from '@affine/core/modules/app-sidebar';
import { EditorService } from '@affine/core/modules/editor'; import { EditorService } from '@affine/core/modules/editor';
import { ViewIcon, ViewTitle } from '@affine/core/modules/workbench'; import { ViewIcon, ViewTitle } from '@affine/core/modules/workbench';
import type { Doc } from '@blocksuite/affine/store'; import type { Doc } from '@blocksuite/affine/store';
@@ -34,16 +33,8 @@ const Header = forwardRef<
style?: React.CSSProperties; style?: React.CSSProperties;
} }
>(({ children, style, className }, ref) => { >(({ children, style, className }, ref) => {
const appSidebarService = useService(AppSidebarService).sidebar;
const appSidebarFloating = useLiveData(appSidebarService.responsiveFloating$);
return ( return (
<div <div data-testid="header" style={style} className={className} ref={ref}>
data-testid="header"
style={style}
className={className}
ref={ref}
data-sidebar-floating={appSidebarFloating}
>
{children} {children}
</div> </div>
); );

View File

@@ -3,8 +3,6 @@ import { map } from 'rxjs';
import type { AppSidebarState } from '../providers/storage'; import type { AppSidebarState } from '../providers/storage';
const isMobile = !BUILD_CONFIG.isElectron && window.innerWidth < 768;
enum APP_SIDEBAR_STATE { enum APP_SIDEBAR_STATE {
OPEN = 'open', OPEN = 'open',
WIDTH = 'width', WIDTH = 'width',
@@ -15,11 +13,15 @@ export class AppSidebar extends Entity {
super(); super();
} }
/**
* whether the sidebar is open,
* even if the sidebar is not open, hovering can show the floating sidebar
*/
open$ = LiveData.from( open$ = LiveData.from(
this.appSidebarState this.appSidebarState
.watch<boolean>(APP_SIDEBAR_STATE.OPEN) .watch<boolean>(APP_SIDEBAR_STATE.OPEN)
.pipe(map(value => value ?? !isMobile)), .pipe(map(value => value ?? true)),
!isMobile true
); );
width$ = LiveData.from( width$ = LiveData.from(
@@ -28,8 +30,16 @@ export class AppSidebar extends Entity {
.pipe(map(value => value ?? 248)), .pipe(map(value => value ?? 248)),
248 248
); );
responsiveFloating$ = new LiveData<boolean>(isMobile);
hoverFloating$ = new LiveData<boolean>(false); /**
* hovering can show the floating sidebar, without open it
*/
hovering$ = new LiveData<boolean>(false);
/**
* small screen mode, will disable hover effect
*/
smallScreenMode$ = new LiveData<boolean>(false);
resizing$ = new LiveData<boolean>(false); resizing$ = new LiveData<boolean>(false);
getCachedAppSidebarOpenState = () => { getCachedAppSidebarOpenState = () => {
@@ -42,23 +52,15 @@ export class AppSidebar extends Entity {
setOpen = (open: boolean) => { setOpen = (open: boolean) => {
this.appSidebarState.set(APP_SIDEBAR_STATE.OPEN, open); this.appSidebarState.set(APP_SIDEBAR_STATE.OPEN, open);
if (!open && this.hoverFloating$.value) {
const timeout = setTimeout(() => {
this.setHoverFloating(false);
}, 500);
return () => {
clearTimeout(timeout);
};
}
return; return;
}; };
setResponsiveFloating = (floating: boolean) => { setSmallScreenMode = (smallScreenMode: boolean) => {
this.responsiveFloating$.next(floating); this.smallScreenMode$.next(smallScreenMode);
}; };
setHoverFloating = (hoverFloating: boolean) => { setHovering = (hoverFloating: boolean) => {
this.hoverFloating$.next(hoverFloating); this.hovering$.next(hoverFloating);
}; };
setResizing = (resizing: boolean) => { setResizing = (resizing: boolean) => {

View File

@@ -1,4 +1,5 @@
import { cssVar } from '@toeverything/theme'; import { cssVar } from '@toeverything/theme';
import { cssVarV2 } from '@toeverything/theme/v2';
import { style } from '@vanilla-extract/css'; import { style } from '@vanilla-extract/css';
export const floatingMaxWidth = 768; export const floatingMaxWidth = 768;
export const navWrapperStyle = style({ export const navWrapperStyle = style({
@@ -10,16 +11,45 @@ export const navWrapperStyle = style({
}, },
selectors: { selectors: {
'&[data-has-border=true]': { '&[data-has-border=true]': {
borderRight: `0.5px solid ${cssVar('borderColor')}`, borderRight: `0.5px solid ${cssVarV2('layer/insideBorder/border')}`,
}, },
'&[data-is-floating="true"]': { '&[data-is-floating="true"]': {
backgroundColor: cssVar('backgroundPrimaryColor'), backgroundColor: cssVarV2('layer/background/primary'),
}, },
'&[data-client-border="true"]': { '&[data-client-border="true"]': {
paddingBottom: 8, paddingBottom: 8,
}, },
}, },
}); });
export const hoverNavWrapperStyle = style({
selectors: {
'&[data-is-floating="true"]': {
backgroundColor: cssVarV2('layer/background/primary'),
height: 'calc(100% - 60px)',
marginTop: '52px',
marginLeft: '4px',
boxShadow: cssVar('--affine-popover-shadow'),
borderRadius: '6px',
},
'&[data-is-floating="true"][data-is-electron="true"]': {
height: '100%',
marginTop: '-4px',
},
'&[data-is-floating="true"][data-client-border="true"]': {
backgroundColor: cssVarV2('layer/background/overlayPanel'),
},
'&[data-is-floating="true"][data-client-border="true"]::before': {
content: '""',
position: 'absolute',
inset: 0,
opacity: `var(--affine-noise-opacity, 0)`,
backgroundRepeat: 'repeat',
backgroundSize: '50px',
// TODO(@Peng): figure out how to use vanilla-extract webpack plugin to inject img url
backgroundImage: `var(--noise-background)`,
},
},
});
export const navHeaderButton = style({ export const navHeaderButton = style({
width: '32px', width: '32px',
height: '32px', height: '32px',
@@ -62,7 +92,7 @@ export const sidebarFloatMaskStyle = style({
left: 0, left: 0,
right: '100%', right: '100%',
bottom: 0, bottom: 0,
background: cssVar('backgroundModalColor'), background: cssVarV2('layer/background/modal'),
selectors: { selectors: {
'&[data-open="true"][data-is-floating="true"]': { '&[data-open="true"][data-is-floating="true"]': {
opacity: 1, opacity: 1,

View File

@@ -9,14 +9,16 @@ import {
useServiceOptional, useServiceOptional,
WorkspaceService, WorkspaceService,
} from '@toeverything/infra'; } from '@toeverything/infra';
import clsx from 'clsx';
import { debounce } from 'lodash-es'; import { debounce } from 'lodash-es';
import type { PropsWithChildren, ReactElement } from 'react'; import type { PropsWithChildren, ReactElement } from 'react';
import { useCallback, useContext, useEffect, useMemo } from 'react'; import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { AppSidebarService } from '../services/app-sidebar'; import { AppSidebarService } from '../services/app-sidebar';
import * as styles from './fallback.css'; import * as styles from './fallback.css';
import { import {
floatingMaxWidth, floatingMaxWidth,
hoverNavWrapperStyle,
navBodyStyle, navBodyStyle,
navHeaderStyle, navHeaderStyle,
navStyle, navStyle,
@@ -32,6 +34,7 @@ export type History = {
const MAX_WIDTH = 480; const MAX_WIDTH = 480;
const MIN_WIDTH = 248; const MIN_WIDTH = 248;
const isMacosDesktop = BUILD_CONFIG.isElectron && environment.isMacOs;
export function AppSidebar({ children }: PropsWithChildren) { export function AppSidebar({ children }: PropsWithChildren) {
const { appSettings } = useAppSettingHelper(); const { appSettings } = useAppSettingHelper();
@@ -42,8 +45,35 @@ export function AppSidebar({ children }: PropsWithChildren) {
const open = useLiveData(appSidebarService.open$); const open = useLiveData(appSidebarService.open$);
const width = useLiveData(appSidebarService.width$); const width = useLiveData(appSidebarService.width$);
const floating = useLiveData(appSidebarService.responsiveFloating$); const smallScreenMode = useLiveData(appSidebarService.smallScreenMode$);
const hovering = useLiveData(appSidebarService.hovering$) && open !== true;
const resizing = useLiveData(appSidebarService.resizing$); const resizing = useLiveData(appSidebarService.resizing$);
const [deferredHovering, setDeferredHovering] = useState(false);
useEffect(() => {
if (open) {
// if open, we don't need to show the floating sidebar
setDeferredHovering(false);
return;
}
// we make a little delay here.
// this allow the sidebar close animation to complete.
const timeout = setTimeout(() => {
setDeferredHovering(hovering);
}, 150);
return () => {
clearTimeout(timeout);
};
}, [hovering, open]);
const sidebarState = smallScreenMode
? open
? 'floating-with-mask'
: 'close'
: open
? 'open'
: deferredHovering
? 'floating'
: 'close';
useEffect(() => { useEffect(() => {
// do not float app sidebar on desktop // do not float app sidebar on desktop
@@ -55,19 +85,8 @@ export function AppSidebar({ children }: PropsWithChildren) {
const isFloatingMaxWidth = window.matchMedia( const isFloatingMaxWidth = window.matchMedia(
`(max-width: ${floatingMaxWidth}px)` `(max-width: ${floatingMaxWidth}px)`
).matches; ).matches;
const isOverflowWidth = window.matchMedia( const isFloating = isFloatingMaxWidth;
`(max-width: ${width / 0.4}px)` appSidebarService.setSmallScreenMode(isFloating);
).matches;
const isFloating = isFloatingMaxWidth || isOverflowWidth;
if (
open === undefined &&
appSidebarService.getCachedAppSidebarOpenState() === undefined
) {
// give the initial value,
// so that the sidebar can be closed on mobile by default
appSidebarService.setOpen(!isFloating);
}
appSidebarService.setResponsiveFloating(isFloating);
} }
const dOnResize = debounce(onResize, 50); const dOnResize = debounce(onResize, 50);
@@ -75,10 +94,9 @@ export function AppSidebar({ children }: PropsWithChildren) {
return () => { return () => {
window.removeEventListener('resize', dOnResize); window.removeEventListener('resize', dOnResize);
}; };
}, [appSidebarService, open, width]); }, [appSidebarService]);
const hasRightBorder = !BUILD_CONFIG.isElectron && !clientBorder; const hasRightBorder = !BUILD_CONFIG.isElectron && !clientBorder;
const isMacosDesktop = BUILD_CONFIG.isElectron && environment.isMacOs;
const handleOpenChange = useCallback( const handleOpenChange = useCallback(
(open: boolean) => { (open: boolean) => {
@@ -105,11 +123,21 @@ export function AppSidebar({ children }: PropsWithChildren) {
appSidebarService.setOpen(false); appSidebarService.setOpen(false);
}, [appSidebarService]); }, [appSidebarService]);
const onMouseEnter = useCallback(() => {
appSidebarService.setHovering(true);
}, [appSidebarService]);
const onMouseLeave = useCallback(() => {
appSidebarService.setHovering(false);
}, [appSidebarService]);
return ( return (
<> <>
<ResizePanel <ResizePanel
floating={floating} floating={
open={open} sidebarState === 'floating' || sidebarState === 'floating-with-mask'
}
open={sidebarState !== 'close'}
resizing={resizing} resizing={resizing}
maxWidth={MAX_WIDTH} maxWidth={MAX_WIDTH}
minWidth={MIN_WIDTH} minWidth={MIN_WIDTH}
@@ -118,18 +146,25 @@ export function AppSidebar({ children }: PropsWithChildren) {
onOpen={handleOpenChange} onOpen={handleOpenChange}
onResizing={handleResizing} onResizing={handleResizing}
onWidthChange={handleWidthChange} onWidthChange={handleWidthChange}
className={navWrapperStyle} className={clsx(navWrapperStyle, {
[hoverNavWrapperStyle]: sidebarState === 'floating',
})}
resizeHandleOffset={0} resizeHandleOffset={0}
resizeHandleVerticalPadding={clientBorder ? 16 : 0} resizeHandleVerticalPadding={clientBorder ? 16 : 0}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
data-transparent data-transparent
data-open={open} data-open={sidebarState !== 'close'}
data-has-border={hasRightBorder} data-has-border={hasRightBorder}
data-testid="app-sidebar-wrapper" data-testid="app-sidebar-wrapper"
data-is-macos-electron={isMacosDesktop} data-is-macos-electron={isMacosDesktop}
data-client-border={clientBorder} data-client-border={clientBorder}
data-is-electron={BUILD_CONFIG.isElectron}
> >
<nav className={navStyle} data-testid="app-sidebar"> <nav className={navStyle} data-testid="app-sidebar">
{!BUILD_CONFIG.isElectron && <SidebarHeader />} {!BUILD_CONFIG.isElectron && sidebarState !== 'floating' && (
<SidebarHeader />
)}
<div className={navBodyStyle} data-testid="sliderBar-inner"> <div className={navBodyStyle} data-testid="sliderBar-inner">
{children} {children}
</div> </div>
@@ -138,7 +173,7 @@ export function AppSidebar({ children }: PropsWithChildren) {
<div <div
data-testid="app-sidebar-float-mask" data-testid="app-sidebar-float-mask"
data-open={open} data-open={open}
data-is-floating={floating} data-is-floating={sidebarState === 'floating-with-mask'}
className={sidebarFloatMaskStyle} className={sidebarFloatMaskStyle}
onClick={handleClose} onClick={handleClose}
/> />

View File

@@ -2,7 +2,7 @@ import { IconButton } from '@affine/component';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { SidebarIcon } from '@blocksuite/icons/rc'; import { SidebarIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import { useCallback } from 'react'; import { useCallback, useRef } from 'react';
import { AppSidebarService } from '../../services/app-sidebar'; import { AppSidebarService } from '../../services/app-sidebar';
import * as styles from './sidebar-switch.css'; import * as styles from './sidebar-switch.css';
@@ -16,21 +16,33 @@ export const SidebarSwitch = ({
}) => { }) => {
const appSidebarService = useService(AppSidebarService).sidebar; const appSidebarService = useService(AppSidebarService).sidebar;
const open = useLiveData(appSidebarService.open$); const open = useLiveData(appSidebarService.open$);
const switchRef = useRef<HTMLDivElement>(null);
const handleMouseEnter = useCallback(() => {
appSidebarService.setHovering(true);
}, [appSidebarService]);
const handleClickSwitch = useCallback(() => {
appSidebarService.toggleSidebar();
}, [appSidebarService]);
const handleMouseLeave = useCallback(() => {
appSidebarService.setHovering(false);
}, [appSidebarService]);
const t = useI18n(); const t = useI18n();
const tooltipContent = open const tooltipContent = open
? t['com.affine.sidebarSwitch.collapse']() ? t['com.affine.sidebarSwitch.collapse']()
: t['com.affine.sidebarSwitch.expand'](); : t['com.affine.sidebarSwitch.expand']();
const toggleSidebar = useCallback(() => {
appSidebarService.toggleSidebar();
}, [appSidebarService]);
return ( return (
<div <div
ref={switchRef}
data-show={show} data-show={show}
className={styles.sidebarSwitchClip} className={styles.sidebarSwitchClip}
data-testid={`app-sidebar-arrow-button-${open ? 'collapse' : 'expand'}`} data-testid={`app-sidebar-arrow-button-${open ? 'collapse' : 'expand'}`}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
> >
<IconButton <IconButton
tooltip={tooltipContent} tooltip={tooltipContent}
@@ -41,7 +53,7 @@ export const SidebarSwitch = ({
style={{ style={{
zIndex: 1, zIndex: 1,
}} }}
onClick={toggleSidebar} onClick={handleClickSwitch}
> >
<SidebarIcon /> <SidebarIcon />
</IconButton> </IconButton>

View File

@@ -26,7 +26,7 @@ export const SidebarContainer = ({
return ( return (
<div className={clsx(styles.sidebarContainerInner, className)} {...props}> <div className={clsx(styles.sidebarContainerInner, className)} {...props}>
<Header floating={false} onToggle={handleToggleOpen}> <Header onToggle={handleToggleOpen}>
<SidebarHeaderSwitcher /> <SidebarHeaderSwitcher />
</Header> </Header>
{sidebarTabs.length > 0 ? ( {sidebarTabs.length > 0 ? (

View File

@@ -4,7 +4,6 @@ import { RightSidebarIcon } from '@blocksuite/icons/rc';
import * as styles from './sidebar-header.css'; import * as styles from './sidebar-header.css';
export type HeaderProps = { export type HeaderProps = {
floating: boolean;
onToggle?: () => void; onToggle?: () => void;
children?: React.ReactNode; children?: React.ReactNode;
}; };
@@ -13,20 +12,13 @@ function Container({
children, children,
style, style,
className, className,
floating,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
style?: React.CSSProperties; style?: React.CSSProperties;
floating?: boolean;
}) { }) {
return ( return (
<div <div data-testid="header" style={style} className={className}>
data-testid="header"
style={style}
className={className}
data-sidebar-floating={floating}
>
{children} {children}
</div> </div>
); );
@@ -40,9 +32,9 @@ const ToggleButton = ({ onToggle }: { onToggle?: () => void }) => {
); );
}; };
export const Header = ({ floating, children, onToggle }: HeaderProps) => { export const Header = ({ children, onToggle }: HeaderProps) => {
return ( return (
<Container className={styles.header} floating={floating}> <Container className={styles.header}>
{children} {children}
{!BUILD_CONFIG.isElectron && ( {!BUILD_CONFIG.isElectron && (
<> <>

View File

@@ -92,6 +92,7 @@ test('Collapse Sidebar', async ({ page }) => {
await page await page
.locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]') .locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]')
.click(); .click();
await page.mouse.move(500, 500);
const sliderBarArea = page.getByTestId('app-sidebar'); const sliderBarArea = page.getByTestId('app-sidebar');
await expect(sliderBarArea).not.toBeInViewport(); await expect(sliderBarArea).not.toBeInViewport();
}); });
@@ -100,6 +101,7 @@ test('Expand Sidebar', async ({ page }) => {
await page await page
.locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]') .locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]')
.click(); .click();
await page.mouse.move(500, 500);
const sliderBarArea = page.getByTestId('sliderBar-inner'); const sliderBarArea = page.getByTestId('sliderBar-inner');
await expect(sliderBarArea).not.toBeInViewport(); await expect(sliderBarArea).not.toBeInViewport();

View File

@@ -10,6 +10,9 @@ test('Collapse Sidebar', async ({ page }) => {
.locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]') .locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]')
.click(); .click();
const sliderBarArea = page.getByTestId('app-sidebar'); const sliderBarArea = page.getByTestId('app-sidebar');
await sliderBarArea.hover();
await page.mouse.move(300, 300);
await page.waitForTimeout(5000);
await expect(sliderBarArea).not.toBeInViewport(); await expect(sliderBarArea).not.toBeInViewport();
}); });
@@ -20,6 +23,9 @@ test('Expand Sidebar', async ({ page }) => {
.locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]') .locator('[data-testid=app-sidebar-arrow-button-collapse][data-show=true]')
.click(); .click();
const sliderBarArea = page.getByTestId('sliderBar-inner'); const sliderBarArea = page.getByTestId('sliderBar-inner');
await sliderBarArea.hover();
await page.mouse.move(300, 300);
await page.waitForTimeout(5000);
await expect(sliderBarArea).not.toBeInViewport(); await expect(sliderBarArea).not.toBeInViewport();
await page await page