diff --git a/apps/web/src/components/affine/sidebar-switch/icons.tsx b/apps/web/src/components/affine/sidebar-switch/icons.tsx
new file mode 100644
index 0000000000..622e30d3de
--- /dev/null
+++ b/apps/web/src/components/affine/sidebar-switch/icons.tsx
@@ -0,0 +1,26 @@
+export const SidebarSwitchIcon = () => {
+ return (
+
+ );
+};
diff --git a/apps/web/src/components/affine/sidebar-switch/index.tsx b/apps/web/src/components/affine/sidebar-switch/index.tsx
new file mode 100644
index 0000000000..4cdc7bb487
--- /dev/null
+++ b/apps/web/src/components/affine/sidebar-switch/index.tsx
@@ -0,0 +1,49 @@
+import { Tooltip } from '@affine/component';
+import { useTranslation } from '@affine/i18n';
+import React, { useCallback, useState } from 'react';
+
+import { useSidebarStatus } from '../../../hooks/affine/use-sidebar-status';
+import { SidebarSwitchIcon } from './icons';
+import { StyledSidebarSwitch } from './style';
+type SidebarSwitchProps = {
+ visible?: boolean;
+ tooltipContent?: string;
+ testid?: string;
+};
+export const SidebarSwitch = ({
+ visible = true,
+ tooltipContent,
+ testid = '',
+}: SidebarSwitchProps) => {
+ const [open, setOpen] = useSidebarStatus();
+ const [tooltipVisible, setTooltipVisible] = useState(false);
+ const { t } = useTranslation();
+ tooltipContent =
+ tooltipContent || (open ? t('Collapse sidebar') : t('Expand sidebar'));
+
+ return (
+
+ {
+ setOpen(!open);
+ setTooltipVisible(false);
+ }, [open, setOpen])}
+ onMouseEnter={useCallback(() => {
+ setTooltipVisible(true);
+ }, [])}
+ onMouseLeave={useCallback(() => {
+ setTooltipVisible(false);
+ }, [])}
+ >
+
+
+
+ );
+};
diff --git a/apps/web/src/components/affine/sidebar-switch/style.ts b/apps/web/src/components/affine/sidebar-switch/style.ts
new file mode 100644
index 0000000000..b70d32390d
--- /dev/null
+++ b/apps/web/src/components/affine/sidebar-switch/style.ts
@@ -0,0 +1,23 @@
+import { styled } from '@affine/component';
+
+export const StyledSidebarSwitch = styled('button')<{ visible: boolean }>(
+ ({ theme, visible }) => {
+ return {
+ display: 'inline-flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ color: theme.colors.innerHoverBackground,
+ width: '32px',
+ height: '32px',
+ borderRadius: '8px',
+ opacity: visible ? 1 : 0,
+ transition: 'all 0.2s ease-in-out',
+ ...(visible ? {} : { cursor: 'not-allowed', pointerEvents: 'none' }),
+
+ ':hover': {
+ background: '#F1F1F4',
+ color: theme.colors.iconColor,
+ },
+ };
+ }
+);
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/Icons.tsx b/apps/web/src/components/blocksuite/header/editor-mode-switch/Icons.tsx
deleted file mode 100644
index e59abf234f..0000000000
--- a/apps/web/src/components/blocksuite/header/editor-mode-switch/Icons.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import { CSSProperties, DOMAttributes } from 'react';
-
-type IconProps = {
- style?: CSSProperties;
-} & DOMAttributes;
-
-export const ArrowIcon = ({
- style: propsStyle = {},
- direction = 'right',
- ...props
-}: IconProps & { direction?: 'left' | 'right' | 'middle' }) => {
- const style = {
- transform: `rotate(${direction === 'left' ? '0' : '180deg'})`,
- opacity: direction === 'middle' ? 0 : 1,
- ...propsStyle,
- };
- return (
-
- );
-};
-
-export const PaperIcon = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
-
-export const EdgelessIcon = ({ style = {}, ...props }: IconProps) => {
- return (
-
- );
-};
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx b/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx
index 7697c80e83..ad16c913b0 100644
--- a/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx
+++ b/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx
@@ -1,80 +1,26 @@
-import { useTranslation } from '@affine/i18n';
+import { EdgelessIcon, PaperIcon } from '@blocksuite/icons';
import { assertExists } from '@blocksuite/store';
-import { useTheme } from '@mui/material';
-import React, { cloneElement, CSSProperties, useEffect, useState } from 'react';
+import { CSSProperties } from 'react';
import {
usePageMeta,
usePageMetaHelper,
} from '../../../../hooks/use-page-meta';
-// todo(himself65): remove `useTheme` hook
import { BlockSuiteWorkspace } from '../../../../shared';
-import { EdgelessIcon, PaperIcon } from './Icons';
-import {
- StyledAnimateRadioContainer,
- StyledIcon,
- StyledLabel,
- StyledMiddleLine,
- StyledRadioItem,
-} from './style';
-import type { AnimateRadioItemProps, RadioItemStatus } from './type';
-const PaperItem = ({ active }: { active?: boolean }) => {
- const {
- colors: { iconColor, primaryColor },
- } = useTheme();
-
- return ;
-};
-
-const EdgelessItem = ({ active }: { active?: boolean }) => {
- const {
- colors: { iconColor, primaryColor },
- } = useTheme();
-
- return ;
-};
-
-const AnimateRadioItem = ({
- active,
- status,
- icon: propsIcon,
- label,
- isLeft,
- ...props
-}: AnimateRadioItemProps) => {
- const icon = (
-
- {cloneElement(propsIcon, {
- active,
- })}
-
- );
- return (
-
- {isLeft ? icon : null}
-
- {label}
-
- {isLeft ? null : icon}
-
- );
-};
+import { StyledEditorModeSwitch, StyledSwitchItem } from './style';
export type EditorModeSwitchProps = {
// todo(himself65): combine these two properties
blockSuiteWorkspace: BlockSuiteWorkspace;
pageId: string;
- isHover: boolean;
- style: CSSProperties;
+ style?: CSSProperties;
};
-export const EditorModeSwitch: React.FC = ({
- isHover,
- style = {},
+export const EditorModeSwitch = ({
+ style,
blockSuiteWorkspace,
pageId,
-}) => {
- const theme = useTheme();
+}: EditorModeSwitchProps) => {
const { setPageMeta } = usePageMetaHelper(blockSuiteWorkspace);
const pageMeta = usePageMeta(blockSuiteWorkspace).find(
meta => meta.id === pageId
@@ -82,85 +28,32 @@ export const EditorModeSwitch: React.FC = ({
assertExists(pageMeta);
const { trash, mode = 'page' } = pageMeta;
- const modifyRadioItemStatus = (): RadioItemStatus => {
- return {
- left: isHover
- ? mode === 'page'
- ? 'stretch'
- : 'normal'
- : mode === 'page'
- ? 'shrink'
- : 'hidden',
- right: isHover
- ? mode === 'edgeless'
- ? 'stretch'
- : 'normal'
- : mode === 'edgeless'
- ? 'shrink'
- : 'hidden',
- };
- };
- const [radioItemStatus, setRadioItemStatus] = useState(
- modifyRadioItemStatus
- );
-
- useEffect(() => {
- setRadioItemStatus(modifyRadioItemStatus());
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [isHover, mode]);
- const { t } = useTranslation();
return (
-
- }
+ {
setPageMeta(pageId, { mode: 'page' });
}}
- onMouseEnter={() => {
- setRadioItemStatus({
- right: 'normal',
- left: 'stretch',
- });
- }}
- onMouseLeave={() => {
- setRadioItemStatus(modifyRadioItemStatus());
- }}
- />
-
- }
+ >
+
+
+ {
setPageMeta(pageId, { mode: 'edgeless' });
}}
- onMouseEnter={() => {
- setRadioItemStatus({
- left: 'normal',
- right: 'stretch',
- });
- }}
- onMouseLeave={() => {
- setRadioItemStatus(modifyRadioItemStatus());
- }}
- />
-
+ >
+
+
+
);
};
-
-export default EditorModeSwitch;
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts b/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts
index 4067a4558b..b3682dbcbc 100644
--- a/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts
+++ b/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts
@@ -1,179 +1,58 @@
-import { css, displayFlex, keyframes, styled } from '@affine/component';
-// @ts-ignore
-import spring, { toString } from 'css-spring';
-
-// @ts-ignore
-import type { ItemStatus } from './type';
-
-const ANIMATE_DURATION = 500;
-
-export const StyledAnimateRadioContainer = styled('div')<{
- shrink: boolean;
- disabled: boolean;
-}>(({ shrink, theme, disabled }) => {
- const animateScaleStretch = toString(
- spring({ width: '36px' }, { width: '160px' }, { preset: 'gentle' })
- );
- const animateScaleShrink = toString(
- spring({ width: '160px' }, { width: '36px' }, { preset: 'gentle' })
- );
- const shrinkStyle: any = shrink
- ? {
- animation: css`
- ${keyframes`${animateScaleShrink}`} ${ANIMATE_DURATION}ms forwards
- `,
- background: 'transparent',
- }
- : {
- animation: css`
- ${keyframes`${animateScaleStretch}`} ${ANIMATE_DURATION}ms forwards
- `,
- };
- return css`
- height: 36px;
- border-radius: 18px;
- background: ${disabled ? 'transparent' : theme.colors.hoverBackground}
- position: relative;
- display: flex;
- transition: background ${ANIMATE_DURATION}ms, border ${ANIMATE_DURATION}ms;
- border: 1px solid transparent;
- ${
- disabled
- ? css`
- pointer-events: none;
- `
- : css`
- animation: ${shrinkStyle.animation};
- background: ${shrinkStyle.background};
- `
- }
-
- //...(disabled ? { pointerEvents: 'none' } : shrinkStyle),
- :hover {
- border: ${disabled ? '' : `1px solid ${theme.colors.primaryColor}`}
- }
- `;
-});
-
-export const StyledMiddleLine = styled('div')<{
- hidden: boolean;
- dark: boolean;
-}>(({ hidden, dark }) => {
- return {
- width: '1px',
- height: '16px',
- background: dark ? '#4d4c53' : '#D0D7E3',
- top: '0',
- bottom: '0',
- margin: 'auto',
- opacity: hidden ? '0' : '1',
- };
-});
-
-export const StyledRadioItem = styled('div')<{
- status: ItemStatus;
- active: boolean;
-}>(({ status, active, theme }) => {
- const animateScaleStretch = toString(
- spring({ width: '44px' }, { width: '112px' })
- );
- const animateScaleOrigin = toString(
- spring({ width: '112px' }, { width: '44px' })
- );
- const animateScaleShrink = toString(
- spring({ width: '0px' }, { width: '36px' })
- );
- const dynamicStyle =
- status === 'stretch'
- ? {
- animation: css`
- ${keyframes`${animateScaleStretch}`} ${ANIMATE_DURATION}ms forwards
- `,
- flexShrink: '0',
- }
- : status === 'shrink'
- ? {
- animation: css`
- ${keyframes`${animateScaleShrink}`} ${ANIMATE_DURATION}ms forwards
- `,
- }
- : status === 'normal'
- ? {
- animation: css`
- ${keyframes`${animateScaleOrigin}`} ${ANIMATE_DURATION}ms forwards
- `,
- }
- : {};
+import { displayFlex, styled } from '@affine/component';
+export const StyledEditorModeSwitch = styled('div')<{
+ switchLeft: boolean;
+ showAlone?: boolean;
+}>(({ theme, switchLeft, showAlone }) => {
const {
- colors: { iconColor, primaryColor },
+ palette: { mode },
} = theme;
- return css`
- width: 0;
- height: 100%;
- display: flex;
- cursor: pointer;
- overflow: hidden;
- color: ${active ? primaryColor : iconColor};
- animation: ${dynamicStyle.animation};
- flex-shrink: ${dynamicStyle.flexShrink};
- `;
-});
-
-export const StyledLabel = styled('div')<{
- shrink: boolean;
- isLeft: boolean;
-}>(({ shrink, isLeft }) => {
- const animateScaleStretch = toString(
- spring(
- { width: '0px' },
- { width: isLeft ? '65px' : '75px' },
- { preset: 'gentle' }
- )
- );
- const animateScaleShrink = toString(
- spring(
- { width: isLeft ? '65px' : '75px' },
- { width: '0px' },
- { preset: 'gentle' }
- )
- );
- const shrinkStyle = shrink
- ? {
- animation: css`
- ${keyframes`${animateScaleShrink}`} ${ANIMATE_DURATION}ms forwards
- `,
- }
- : {
- animation: css`
- ${keyframes`${animateScaleStretch}`} ${ANIMATE_DURATION}ms forwards
- `,
- };
-
- return css`
- display: flex;
- align-items: center;
- justify-content: ${isLeft ? 'flex-start' : 'flex-end'};
- font-size: 16px;
- flex-shrink: 0;
- transition: transform ${ANIMATE_DURATION}ms;
- font-weight: normal;
- overflow: hidden;
- white-space: nowrap;
- animation: ${shrinkStyle.animation};
- `;
-});
-
-export const StyledIcon = styled('div')<{
- shrink: boolean;
- isLeft: boolean;
-}>(({ shrink, isLeft }) => {
- const dynamicStyle = shrink
- ? { width: '36px' }
- : { width: isLeft ? '44px' : '34px' };
return {
- ...displayFlex('center', 'center'),
- flexShrink: '0',
- ...dynamicStyle,
+ width: showAlone ? '40px' : '78px',
+ height: '32px',
+ background: showAlone
+ ? 'transparent'
+ : mode === 'dark'
+ ? '#242424'
+ : '#F9F9FB',
+ borderRadius: '12px',
+ ...displayFlex('space-between', 'center'),
+ padding: '0 8px',
+ position: 'relative',
+
+ '::after': {
+ content: '""',
+ display: showAlone ? 'none' : 'block',
+ width: '24px',
+ height: '24px',
+ background: theme.colors.pageBackground,
+ boxShadow:
+ mode === 'dark'
+ ? '0px 0px 6px rgba(22, 22, 22, 0.6)'
+ : '0px 0px 6px #E2E2E2',
+ borderRadius: '8px',
+ zIndex: 1,
+ position: 'absolute',
+ transform: `translateX(${switchLeft ? '0' : '38px'})`,
+ transition: 'all .15s',
+ },
+ };
+});
+
+export const StyledSwitchItem = styled('button')<{
+ active: boolean;
+ hide?: boolean;
+}>(({ theme, active, hide = false }) => {
+ return {
+ width: '24px',
+ height: '24px',
+ borderRadius: '8px',
+ color: active ? theme.colors.primaryColor : theme.colors.iconColor,
+ display: hide ? 'none' : 'inline-flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ position: 'relative',
+ zIndex: 2,
+ fontSize: '20px',
};
});
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/type.ts b/apps/web/src/components/blocksuite/header/editor-mode-switch/type.ts
deleted file mode 100644
index 0909c6b1ba..0000000000
--- a/apps/web/src/components/blocksuite/header/editor-mode-switch/type.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { DOMAttributes, ReactElement } from 'react';
-
-export type ItemStatus = 'normal' | 'stretch' | 'shrink' | 'hidden';
-
-export type RadioItemStatus = {
- left: ItemStatus;
- right: ItemStatus;
-};
-export type AnimateRadioItemProps = {
- active: boolean;
- status: ItemStatus;
- label: string;
- icon: ReactElement;
- isLeft: boolean;
-} & DOMAttributes;
diff --git a/apps/web/src/components/blocksuite/header/header-right-items/EditorOptionMenu.tsx b/apps/web/src/components/blocksuite/header/header-right-items/EditorOptionMenu.tsx
index 052e13568a..833823a697 100644
--- a/apps/web/src/components/blocksuite/header/header-right-items/EditorOptionMenu.tsx
+++ b/apps/web/src/components/blocksuite/header/header-right-items/EditorOptionMenu.tsx
@@ -12,6 +12,7 @@ import {
FavoriteIcon,
MoreVerticalIcon,
} from '@blocksuite/icons';
+import { EdgelessIcon, PaperIcon } from '@blocksuite/icons';
import { assertExists } from '@blocksuite/store';
import { useTheme } from '@mui/material';
import { useState } from 'react';
@@ -22,7 +23,6 @@ import {
usePageMeta,
usePageMetaHelper,
} from '../../../../hooks/use-page-meta';
-import { EdgelessIcon, PaperIcon } from '../editor-mode-switch/Icons';
export const EditorOptionMenu = () => {
const { t } = useTranslation();
@@ -52,6 +52,7 @@ export const EditorOptionMenu = () => {
favorite ? t('Removed from Favorites') : t('Added to Favorites')
);
}}
+ iconSize={[20, 20]}
icon={
favorite ? (
@@ -64,6 +65,7 @@ export const EditorOptionMenu = () => {
: }
+ iconSize={[20, 20]}
data-testid="editor-option-menu-edgeless"
onClick={() => {
setPageMeta(pageId, {
@@ -84,6 +86,7 @@ export const EditorOptionMenu = () => {
globalThis.editor.contentParser.onExportHtml();
}}
icon={}
+ iconSize={[20, 20]}
>
{t('Export to HTML')}
@@ -93,13 +96,14 @@ export const EditorOptionMenu = () => {
globalThis.editor.contentParser.onExportMarkdown();
}}
icon={}
+ iconSize={[20, 20]}
>
{t('Export to Markdown')}
>
}
>
- } isDir={true}>
+ } iconSize={[20, 20]} isDir={true}>
{t('Export')}
@@ -109,6 +113,7 @@ export const EditorOptionMenu = () => {
setOpen(true);
}}
icon={}
+ iconSize={[20, 20]}
>
{t('Delete')}
@@ -124,7 +129,7 @@ export const EditorOptionMenu = () => {
disablePortal={true}
trigger="click"
>
-
+
diff --git a/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx b/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx
index 04e9dd6552..aaec733412 100644
--- a/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx
+++ b/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx
@@ -24,7 +24,7 @@ const IconWrapper = styled('div')(({ theme }) => {
width: '32px',
height: '32px',
marginRight: '12px',
- fontSize: '20px',
+ fontSize: '24px',
color: theme.colors.iconColor,
...displayFlex('center', 'center'),
};
@@ -102,7 +102,6 @@ export const SyncUser = () => {
setOpen(true);
}}
style={{ marginRight: '12px' }}
- iconSize={[20, 20]}
>
diff --git a/apps/web/src/components/blocksuite/header/header-right-items/theme-mode-switch/style.ts b/apps/web/src/components/blocksuite/header/header-right-items/theme-mode-switch/style.ts
index 70119c010f..35253beb72 100644
--- a/apps/web/src/components/blocksuite/header/header-right-items/theme-mode-switch/style.ts
+++ b/apps/web/src/components/blocksuite/header/header-right-items/theme-mode-switch/style.ts
@@ -4,13 +4,17 @@ import spring, { toString } from 'css-spring';
const ANIMATE_DURATION = 400;
-export const StyledThemeModeSwitch = styled('div')({
- width: '32px',
- height: '32px',
- borderRadius: '6px',
- overflow: 'hidden',
- backgroundColor: 'transparent',
- position: 'relative',
+export const StyledThemeModeSwitch = styled('div')(({ theme }) => {
+ return {
+ width: '32px',
+ height: '32px',
+ borderRadius: '6px',
+ overflow: 'hidden',
+ backgroundColor: 'transparent',
+ position: 'relative',
+ color: theme.colors.iconColor,
+ fontSize: '24px',
+ };
});
export const StyledSwitchItem = styled('div')<{
active: boolean;
@@ -63,7 +67,6 @@ export const StyledSwitchItem = styled('div')<{
background-color: ${activeStyle.backgroundColor};
animation: ${activeStyle.animation};
animation-direction: ${activeStyle.animationDirection};
- font-size: 20px;
//svg {
// width: 24px;
// height: 24px;
diff --git a/apps/web/src/components/blocksuite/header/header.tsx b/apps/web/src/components/blocksuite/header/header.tsx
index f83fad9680..97f66c8538 100644
--- a/apps/web/src/components/blocksuite/header/header.tsx
+++ b/apps/web/src/components/blocksuite/header/header.tsx
@@ -1,6 +1,9 @@
+import { useTranslation } from '@affine/i18n';
import { CloseIcon } from '@blocksuite/icons';
import React, { PropsWithChildren, useEffect, useMemo, useState } from 'react';
+import { useSidebarStatus } from '../../../hooks/affine/use-sidebar-status';
+import { SidebarSwitch } from '../../affine/sidebar-switch';
import { EditorOptionMenu } from './header-right-items/EditorOptionMenu';
import SyncUser from './header-right-items/SyncUser';
import ThemeModeSwitch from './header-right-items/theme-mode-switch';
@@ -56,6 +59,9 @@ export const Header: React.FC = ({
useEffect(() => {
setShowWarning(shouldShowWarning());
}, []);
+ const [open] = useSidebarStatus();
+ const { t } = useTranslation();
+
return (
= ({
data-testid="editor-header-items"
data-tauri-drag-region
>
+
+
{children}
{useMemo(
diff --git a/apps/web/src/components/blocksuite/header/index.tsx b/apps/web/src/components/blocksuite/header/index.tsx
index 0ee4f3806d..cbe699926f 100644
--- a/apps/web/src/components/blocksuite/header/index.tsx
+++ b/apps/web/src/components/blocksuite/header/index.tsx
@@ -1,7 +1,7 @@
import { Content } from '@affine/component';
import { assertExists } from '@blocksuite/store';
import { useSetAtom } from 'jotai';
-import React, { useState } from 'react';
+import React from 'react';
import { openQuickSearchModalAtom } from '../../../atoms';
import { usePageMeta } from '../../../hooks/use-page-meta';
@@ -42,7 +42,6 @@ export const BlockSuiteEditorHeader: React.FC = ({
);
assertExists(pageMeta);
const title = pageMeta.title;
- const [isHover, setIsHover] = useState(false);
const { trash: isTrash } = pageMeta;
return (
= ({
>
{children}
{title && !isPublic && (
- {
- if (isTrash) return;
-
- setIsHover(true);
- }}
- onMouseLeave={() => {
- if (isTrash) return;
-
- setIsHover(false);
- }}
- >
+
(
export const StyledHeader = styled('div')<{ hasWarning: boolean }>(
({ theme }) => {
return {
- height: '60px',
+ height: '64px',
width: '100%',
padding: '0 28px',
...displayFlex('flex-end', 'center'),
diff --git a/apps/web/src/components/pure/workspace-avatar/index.tsx b/apps/web/src/components/pure/workspace-avatar/index.tsx
index bb0e38e41b..c2ef888598 100644
--- a/apps/web/src/components/pure/workspace-avatar/index.tsx
+++ b/apps/web/src/components/pure/workspace-avatar/index.tsx
@@ -54,10 +54,10 @@ export const Avatar: React.FC = React.memo(
fontSize: Math.ceil(0.5 * size) + 'px',
background: stringToColour(name || 'AFFiNE'),
borderRadius: '50%',
- textAlign: 'center',
- lineHeight: size + 'px',
- display: 'inline-block',
- verticalAlign: 'middle',
+ display: 'inline-flex',
+ lineHeight: '1',
+ justifyContent: 'center',
+ alignItems: 'center',
}}
>
{(name || 'AFFiNE').substring(0, 1)}
diff --git a/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts b/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts
index 5ec6881e2a..8faff4070d 100644
--- a/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts
+++ b/apps/web/src/components/pure/workspace-slider-bar/WorkspaceSelector/styles.ts
@@ -2,12 +2,13 @@ import { MuiAvatar, textEllipsis } from '@affine/component';
import { styled } from '@affine/component';
export const SelectorWrapper = styled('div')(({ theme }) => {
return {
- height: '52px',
+ height: '64px',
display: 'flex',
alignItems: 'center',
- padding: '0 12px',
+ padding: '0 44px 0 12px',
borderRadius: '5px',
color: theme.colors.textColor,
+ position: 'relative',
':hover': {
cursor: 'pointer',
background: theme.colors.hoverBackground,
@@ -25,7 +26,6 @@ export const WorkspaceName = styled('span')(({ theme }) => {
marginLeft: '12px',
fontSize: theme.font.h6,
fontWeight: 500,
- marginTop: '4px',
flexGrow: 1,
...textEllipsis(1),
};
diff --git a/apps/web/src/components/pure/workspace-slider-bar/index.tsx b/apps/web/src/components/pure/workspace-slider-bar/index.tsx
index ffa0afdc49..85f672a9ad 100644
--- a/apps/web/src/components/pure/workspace-slider-bar/index.tsx
+++ b/apps/web/src/components/pure/workspace-slider-bar/index.tsx
@@ -1,5 +1,4 @@
import { MuiCollapse } from '@affine/component';
-import { Tooltip } from '@affine/component';
import { IconButton } from '@affine/component';
import { useTranslation } from '@affine/i18n';
import {
@@ -16,14 +15,15 @@ import Link from 'next/link';
import { useRouter } from 'next/router';
import React, { useCallback, useMemo, useState } from 'react';
+import { useSidebarStatus } from '../../../hooks/affine/use-sidebar-status';
import { usePageMeta } from '../../../hooks/use-page-meta';
import { RemWorkspace } from '../../../shared';
-import { Arrow } from './icons';
+import { SidebarSwitch } from '../../affine/sidebar-switch';
import {
- StyledArrowButton,
StyledLink,
StyledListItem,
StyledNewPageButton,
+ StyledSidebarWrapper,
StyledSliderBar,
StyledSliderBarWrapper,
StyledSubListItem,
@@ -83,8 +83,6 @@ export type WorkSpaceSliderBarProps = {
currentPageId: string | null;
openPage: (pageId: string) => void;
createPage: () => Promise;
- show: boolean;
- setShow: (show: boolean) => void;
currentPath: string;
paths: {
all: (workspaceId: string) => string;
@@ -100,17 +98,17 @@ export const WorkSpaceSliderBar: React.FC = ({
currentPageId,
openPage,
createPage,
- show,
- setShow,
currentPath,
paths,
onOpenQuickSearchModal,
onOpenWorkspaceListModal,
}) => {
const currentWorkspaceId = currentWorkspace?.id || null;
- const [showSubFavorite, setShowSubFavorite] = useState(true);
- const [showTip, setShowTip] = useState(false);
+ const [showSubFavorite, setOpenSubFavorite] = useState(true);
const { t } = useTranslation();
+ const [open] = useSidebarStatus();
+
+ const [sidebarOpen] = useSidebarStatus();
const pageMeta = usePageMeta(currentWorkspace?.blockSuiteWorkspace ?? null);
const onClickNewPage = useCallback(async () => {
const pageId = await createPage();
@@ -120,33 +118,14 @@ export const WorkSpaceSliderBar: React.FC = ({
}, [createPage, openPage]);
return (
<>
-
-
- {
- setShow(!show);
- setShowTip(false);
- }, [setShow, show])}
- onMouseEnter={useCallback(() => {
- setShowTip(true);
- }, [])}
- onMouseLeave={useCallback(() => {
- setShowTip(false);
- }, [])}
- >
-
-
-
-
+
+
+
+
= ({
{
- setShowSubFavorite(!showSubFavorite);
+ setOpenSubFavorite(!showSubFavorite);
}, [showSubFavorite])}
>
= ({
{/* {
- setShowWorkspaceSetting(false);
+ setOpenWorkspaceSetting(false);
}}
/> */}
{/* TODO: will finish the feature next version */}
diff --git a/apps/web/src/components/pure/workspace-slider-bar/style.ts b/apps/web/src/components/pure/workspace-slider-bar/style.ts
index 4729f042a0..e962d08605 100644
--- a/apps/web/src/components/pure/workspace-slider-bar/style.ts
+++ b/apps/web/src/components/pure/workspace-slider-bar/style.ts
@@ -12,11 +12,19 @@ export const StyledSliderBar = styled('div')<{ show: boolean }>(
transition: 'width .15s, padding .15s',
position: 'relative',
zIndex: theme.zIndex.modal,
- padding: show ? '24px 12px' : '24px 0',
+ padding: show ? '0 12px' : '0',
flexShrink: 0,
};
}
);
+export const StyledSidebarWrapper = styled('div')(() => {
+ return {
+ position: 'absolute',
+ right: '12px',
+ top: '16px',
+ zIndex: 1,
+ };
+});
export const StyledSliderBarWrapper = styled('div')(() => {
return {
height: '100%',
@@ -26,31 +34,6 @@ export const StyledSliderBarWrapper = styled('div')(() => {
};
});
-export const StyledArrowButton = styled('button')<{ isShow: boolean }>(
- ({ theme, isShow }) => {
- return {
- width: '32px',
- height: '32px',
- ...displayFlex('center', 'center'),
- color: theme.colors.primaryColor,
- backgroundColor: theme.colors.hoverBackground,
- borderRadius: '50%',
- transition: 'all .15s',
- position: 'absolute',
- top: '34px',
- right: '-20px',
- zIndex: theme.zIndex.modal,
- svg: {
- transform: isShow ? 'rotate(180deg)' : 'unset',
- },
- ':hover': {
- color: '#fff',
- backgroundColor: theme.colors.primaryColor,
- },
- };
- }
-);
-
export const StyledListItem = styled('div')<{
active?: boolean;
disabled?: boolean;
diff --git a/apps/web/src/hooks/affine/use-sidebar-status.ts b/apps/web/src/hooks/affine/use-sidebar-status.ts
new file mode 100644
index 0000000000..f2dd9d050f
--- /dev/null
+++ b/apps/web/src/hooks/affine/use-sidebar-status.ts
@@ -0,0 +1,8 @@
+import { useAtom } from 'jotai';
+import { atomWithStorage } from 'jotai/utils';
+
+const sideBarOpenAtom = atomWithStorage('sidebarOpen', true);
+
+export function useSidebarStatus() {
+ return useAtom(sideBarOpenAtom);
+}
diff --git a/apps/web/src/layouts/index.tsx b/apps/web/src/layouts/index.tsx
index 2648ce1f1b..fdf65b900a 100644
--- a/apps/web/src/layouts/index.tsx
+++ b/apps/web/src/layouts/index.tsx
@@ -3,7 +3,6 @@ import { setUpLanguage, useTranslation } from '@affine/i18n';
import { assertExists, nanoid } from '@blocksuite/store';
import { NoSsr } from '@mui/material';
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
-import { atomWithStorage } from 'jotai/utils';
import dynamic from 'next/dynamic';
import Head from 'next/head';
import { useRouter } from 'next/router';
@@ -35,8 +34,6 @@ const QuickSearchModal = dynamic(
() => import('../components/pure/quick-search-modal')
);
-const sideBarOpenAtom = atomWithStorage('sideBarOpen', true);
-
const logger = new DebugLogger('workspace-layout');
export const WorkspaceLayout: React.FC =
function WorkspacesSuspense({ children }) {
@@ -91,7 +88,6 @@ export const WorkspaceLayout: React.FC =
export const WorkspaceLayoutInner: React.FC = ({
children,
}) => {
- const [show, setShow] = useAtom(sideBarOpenAtom);
const [currentWorkspace] = useCurrentWorkspace();
const [currentPageId] = useCurrentPageId();
const workspaces = useWorkspaces();
@@ -183,8 +179,6 @@ export const WorkspaceLayoutInner: React.FC = ({
onOpenWorkspaceListModal={handleOpenWorkspaceListModal}
openPage={handleOpenPage}
createPage={handleCreatePage}
- show={show}
- setShow={setShow}
currentPath={router.asPath}
paths={isPublicWorkspace ? publicPathGenerator : pathGenerator}
/>
diff --git a/packages/component/src/ui/menu/MenuItem.tsx b/packages/component/src/ui/menu/MenuItem.tsx
index 746a3331e1..97f53f30ad 100644
--- a/packages/component/src/ui/menu/MenuItem.tsx
+++ b/packages/component/src/ui/menu/MenuItem.tsx
@@ -10,17 +10,19 @@ import { StyledArrow, StyledMenuItem } from './styles';
export type IconMenuProps = PropsWithChildren<{
isDir?: boolean;
icon?: ReactElement;
+ iconSize?: [number, number];
}> &
HTMLAttributes;
export const MenuItem = forwardRef(
- ({ isDir = false, icon, children, ...props }, ref) => {
+ ({ isDir = false, icon, iconSize, children, ...props }, ref) => {
+ const [iconWidth, iconHeight] = iconSize || [16, 16];
return (
{icon &&
cloneElement(icon, {
- width: 16,
- height: 16,
+ width: iconWidth,
+ height: iconHeight,
style: {
marginRight: 14,
...icon.props?.style,
diff --git a/tests/change-page-mode.spec.ts b/tests/change-page-mode.spec.ts
index 2cfdb33a17..1a1295390b 100644
--- a/tests/change-page-mode.spec.ts
+++ b/tests/change-page-mode.spec.ts
@@ -7,31 +7,8 @@ loadPage();
test.describe('Change page mode(Page or Edgeless)', () => {
test('Switch to edgeless by switch edgeless item', async ({ page }) => {
- const switcher = page.locator('[data-testid=editor-mode-switcher]');
- const box = await switcher.boundingBox();
- expect(box?.x).not.toBeUndefined();
-
- // mouse hover trigger animation for showing full switcher
- // await page.mouse.move((box?.x ?? 0) + 5, (box?.y ?? 0) + 5);
- await page.mouse.move((box?.x ?? 0) + 10, (box?.y ?? 0) + 10);
-
- // await page.waitForTimeout(1000);
- const edgelessButton = page.getByTestId('switch-edgeless-item'); // page.getByText('Edgeless').click()
- await edgelessButton.click();
-
- // // mouse move to edgeless button
- // await page.mouse.move(
- // (box?.x ?? 0) + (box?.width ?? 0) - 5,
- // (box?.y ?? 0) + 5
- // );
-
- // await page.waitForTimeout(1000);
-
- // // click switcher
- // await page.mouse.click(
- // (box?.x ?? 0) + (box?.width ?? 0) - 5,
- // (box?.y ?? 0) + 5
- // );
+ const btn = await page.getByTestId('switch-edgeless-mode-button');
+ await btn.click();
const edgeless = page.locator('affine-edgeless-page');
expect(await edgeless.isVisible()).toBe(true);
diff --git a/tests/layout.spec.ts b/tests/layout.spec.ts
index 4a997693c7..d8984b0bac 100644
--- a/tests/layout.spec.ts
+++ b/tests/layout.spec.ts
@@ -7,17 +7,17 @@ loadPage();
test.describe('Layout ui', () => {
test('Collapse Sidebar', async ({ page }) => {
- await page.getByTestId('sliderBar-arrowButton').click();
+ await page.getByTestId('sliderBar-arrowButton-collapse').click();
const sliderBarArea = page.getByTestId('sliderBar');
await expect(sliderBarArea).not.toBeVisible();
});
test('Expand Sidebar', async ({ page }) => {
- await page.getByTestId('sliderBar-arrowButton').click();
+ await page.getByTestId('sliderBar-arrowButton-collapse').click();
const sliderBarArea = page.getByTestId('sliderBar');
await expect(sliderBarArea).not.toBeVisible();
- await page.getByTestId('sliderBar-arrowButton').click();
+ await page.getByTestId('sliderBar-arrowButton-expand').click();
await expect(sliderBarArea).toBeVisible();
});
});