mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-18 02:26:21 +08:00
Feat/sidebar&top bar (#1454)
This commit is contained in:
@@ -1,85 +0,0 @@
|
||||
import { CSSProperties, DOMAttributes } from 'react';
|
||||
|
||||
type IconProps = {
|
||||
style?: CSSProperties;
|
||||
} & DOMAttributes<SVGElement>;
|
||||
|
||||
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 (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="6"
|
||||
height="16"
|
||||
viewBox="0 0 6 16"
|
||||
fill="currentColor"
|
||||
{...props}
|
||||
style={style}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M0.602933 0.305738C0.986547 0.0865297 1.47523 0.219807 1.69444 0.603421L5.41093 7.10728C5.72715 7.66066 5.72715 8.34 5.41093 8.89338L1.69444 15.3972C1.47523 15.7809 0.986547 15.9141 0.602933 15.6949C0.219319 15.4757 0.0860414 14.987 0.305249 14.6034L4.02174 8.09956C4.05688 8.03807 4.05688 7.96259 4.02174 7.9011L0.305249 1.39724C0.0860414 1.01363 0.219319 0.524946 0.602933 0.305738Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const PaperIcon = ({ style = {}, ...props }: IconProps) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
style={style}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M17 9.8H7V8.2h10v1.6ZM12 12.8H7v-1.6h5v1.6Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
<path d="m14 19 7-7h-5a2 2 0 0 0-2 2v5Z" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5 6.6h14c.22 0 .4.18.4.4v6.6L21 12V7a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h9l1.6-1.6H5a.4.4 0 0 1-.4-.4V7c0-.22.18-.4.4-.4Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const EdgelessIcon = ({ style = {}, ...props }: IconProps) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
style={style}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12 17.4a5.4 5.4 0 1 0 0-10.8 5.4 5.4 0 0 0 0 10.8Zm7-5.4a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M18.565 8a.8.8 0 0 1 .8-.8c.797 0 1.511.07 2.07.24.5.15 1.172.477 1.334 1.202v.004c.089.405-.026.776-.186 1.065a3.165 3.165 0 0 1-.652.782c-.52.471-1.265.947-2.15 1.407-1.783.927-4.28 1.869-7.077 2.62-2.796.752-5.409 1.184-7.381 1.266-.98.04-1.848-.003-2.516-.162-.333-.079-.662-.196-.937-.38-.282-.19-.547-.48-.639-.892v-.002c-.138-.63.202-1.173.518-1.532.343-.39.836-.768 1.413-1.129a.8.8 0 0 1 .848 1.357c-.515.322-.862.605-1.06.83a1.524 1.524 0 0 0-.078.096c.07.03.169.064.304.095.461.11 1.163.158 2.08.12 1.822-.075 4.314-.481 7.033-1.212 2.718-.73 5.1-1.635 6.753-2.494.832-.433 1.441-.835 1.814-1.173.127-.115.213-.21.268-.284a1.67 1.67 0 0 0-.153-.053c-.342-.104-.878-.171-1.606-.171a.8.8 0 0 1-.8-.8Zm2.692 1.097-.004-.004a.026.026 0 0 1 .004.004Zm-18.46 5 .001-.002v.002Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -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 <PaperIcon style={{ color: active ? primaryColor : iconColor }} />;
|
||||
};
|
||||
|
||||
const EdgelessItem = ({ active }: { active?: boolean }) => {
|
||||
const {
|
||||
colors: { iconColor, primaryColor },
|
||||
} = useTheme();
|
||||
|
||||
return <EdgelessIcon style={{ color: active ? primaryColor : iconColor }} />;
|
||||
};
|
||||
|
||||
const AnimateRadioItem = ({
|
||||
active,
|
||||
status,
|
||||
icon: propsIcon,
|
||||
label,
|
||||
isLeft,
|
||||
...props
|
||||
}: AnimateRadioItemProps) => {
|
||||
const icon = (
|
||||
<StyledIcon shrink={status === 'shrink'} isLeft={isLeft}>
|
||||
{cloneElement(propsIcon, {
|
||||
active,
|
||||
})}
|
||||
</StyledIcon>
|
||||
);
|
||||
return (
|
||||
<StyledRadioItem title={label} active={active} status={status} {...props}>
|
||||
{isLeft ? icon : null}
|
||||
<StyledLabel shrink={status !== 'stretch'} isLeft={isLeft}>
|
||||
{label}
|
||||
</StyledLabel>
|
||||
{isLeft ? null : icon}
|
||||
</StyledRadioItem>
|
||||
);
|
||||
};
|
||||
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<EditorModeSwitchProps> = ({
|
||||
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<EditorModeSwitchProps> = ({
|
||||
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<RadioItemStatus>(
|
||||
modifyRadioItemStatus
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setRadioItemStatus(modifyRadioItemStatus());
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isHover, mode]);
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<StyledAnimateRadioContainer
|
||||
data-testid="editor-mode-switcher"
|
||||
shrink={!isHover}
|
||||
<StyledEditorModeSwitch
|
||||
style={style}
|
||||
disabled={!!trash}
|
||||
switchLeft={mode === 'page'}
|
||||
showAlone={trash}
|
||||
>
|
||||
<AnimateRadioItem
|
||||
isLeft={true}
|
||||
label={t('Page')}
|
||||
icon={<PaperItem />}
|
||||
<StyledSwitchItem
|
||||
data-testid="switch-page-mode-button"
|
||||
active={mode === 'page'}
|
||||
status={radioItemStatus.left}
|
||||
hide={trash && mode !== 'page'}
|
||||
onClick={() => {
|
||||
setPageMeta(pageId, { mode: 'page' });
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
setRadioItemStatus({
|
||||
right: 'normal',
|
||||
left: 'stretch',
|
||||
});
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setRadioItemStatus(modifyRadioItemStatus());
|
||||
}}
|
||||
/>
|
||||
<StyledMiddleLine
|
||||
hidden={!isHover}
|
||||
dark={theme.palette.mode === 'dark'}
|
||||
/>
|
||||
<AnimateRadioItem
|
||||
isLeft={false}
|
||||
label={t('Edgeless')}
|
||||
data-testid="switch-edgeless-item"
|
||||
icon={<EdgelessItem />}
|
||||
>
|
||||
<PaperIcon />
|
||||
</StyledSwitchItem>
|
||||
<StyledSwitchItem
|
||||
data-testid="switch-edgeless-mode-button"
|
||||
active={mode === 'edgeless'}
|
||||
status={radioItemStatus.right}
|
||||
hide={trash && mode !== 'edgeless'}
|
||||
onClick={() => {
|
||||
setPageMeta(pageId, { mode: 'edgeless' });
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
setRadioItemStatus({
|
||||
left: 'normal',
|
||||
right: 'stretch',
|
||||
});
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setRadioItemStatus(modifyRadioItemStatus());
|
||||
}}
|
||||
/>
|
||||
</StyledAnimateRadioContainer>
|
||||
>
|
||||
<EdgelessIcon />
|
||||
</StyledSwitchItem>
|
||||
</StyledEditorModeSwitch>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditorModeSwitch;
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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<HTMLDivElement>;
|
||||
@@ -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 ? (
|
||||
<FavoritedIcon style={{ color: theme.colors.primaryColor }} />
|
||||
@@ -64,6 +65,7 @@ export const EditorOptionMenu = () => {
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon={mode === 'page' ? <EdgelessIcon /> : <PaperIcon />}
|
||||
iconSize={[20, 20]}
|
||||
data-testid="editor-option-menu-edgeless"
|
||||
onClick={() => {
|
||||
setPageMeta(pageId, {
|
||||
@@ -84,6 +86,7 @@ export const EditorOptionMenu = () => {
|
||||
globalThis.editor.contentParser.onExportHtml();
|
||||
}}
|
||||
icon={<ExportToHtmlIcon />}
|
||||
iconSize={[20, 20]}
|
||||
>
|
||||
{t('Export to HTML')}
|
||||
</MenuItem>
|
||||
@@ -93,13 +96,14 @@ export const EditorOptionMenu = () => {
|
||||
globalThis.editor.contentParser.onExportMarkdown();
|
||||
}}
|
||||
icon={<ExportToMarkdownIcon />}
|
||||
iconSize={[20, 20]}
|
||||
>
|
||||
{t('Export to Markdown')}
|
||||
</MenuItem>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<MenuItem icon={<ExportIcon />} isDir={true}>
|
||||
<MenuItem icon={<ExportIcon />} iconSize={[20, 20]} isDir={true}>
|
||||
{t('Export')}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
@@ -109,6 +113,7 @@ export const EditorOptionMenu = () => {
|
||||
setOpen(true);
|
||||
}}
|
||||
icon={<DeleteTemporarilyIcon />}
|
||||
iconSize={[20, 20]}
|
||||
>
|
||||
{t('Delete')}
|
||||
</MenuItem>
|
||||
@@ -124,7 +129,7 @@ export const EditorOptionMenu = () => {
|
||||
disablePortal={true}
|
||||
trigger="click"
|
||||
>
|
||||
<IconButton data-testid="editor-option-menu" iconSize={[20, 20]}>
|
||||
<IconButton data-testid="editor-option-menu" iconSize={[24, 24]}>
|
||||
<MoreVerticalIcon />
|
||||
</IconButton>
|
||||
</Menu>
|
||||
|
||||
@@ -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]}
|
||||
>
|
||||
<LocalWorkspaceIcon />
|
||||
</IconButton>
|
||||
|
||||
+11
-8
@@ -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;
|
||||
|
||||
@@ -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<HeaderProps> = ({
|
||||
useEffect(() => {
|
||||
setShowWarning(shouldShowWarning());
|
||||
}, []);
|
||||
const [open] = useSidebarStatus();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<StyledHeaderContainer hasWarning={showWarning}>
|
||||
<BrowserWarning
|
||||
@@ -69,6 +75,12 @@ export const Header: React.FC<HeaderProps> = ({
|
||||
data-testid="editor-header-items"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<SidebarSwitch
|
||||
visible={!open}
|
||||
tooltipContent={t('Expand sidebar')}
|
||||
testid="sliderBar-arrowButton-expand"
|
||||
/>
|
||||
|
||||
{children}
|
||||
<StyledHeaderRightSide>
|
||||
{useMemo(
|
||||
|
||||
@@ -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<BlockSuiteEditorHeaderProps> = ({
|
||||
);
|
||||
assertExists(pageMeta);
|
||||
const title = pageMeta.title;
|
||||
const [isHover, setIsHover] = useState(false);
|
||||
const { trash: isTrash } = pageMeta;
|
||||
return (
|
||||
<Header
|
||||
@@ -57,25 +56,12 @@ export const BlockSuiteEditorHeader: React.FC<BlockSuiteEditorHeaderProps> = ({
|
||||
>
|
||||
{children}
|
||||
{title && !isPublic && (
|
||||
<StyledTitle
|
||||
data-tauri-drag-region
|
||||
onMouseEnter={() => {
|
||||
if (isTrash) return;
|
||||
|
||||
setIsHover(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (isTrash) return;
|
||||
|
||||
setIsHover(false);
|
||||
}}
|
||||
>
|
||||
<StyledTitle data-tauri-drag-region>
|
||||
<StyledTitleWrapper>
|
||||
<StyledSwitchWrapper>
|
||||
<EditorModeSwitch
|
||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
||||
pageId={pageId}
|
||||
isHover={isHover}
|
||||
style={{
|
||||
marginRight: '12px',
|
||||
}}
|
||||
|
||||
@@ -10,7 +10,7 @@ export const StyledHeaderContainer = styled('div')<{ hasWarning: boolean }>(
|
||||
export const StyledHeader = styled('div')<{ hasWarning: boolean }>(
|
||||
({ theme }) => {
|
||||
return {
|
||||
height: '60px',
|
||||
height: '64px',
|
||||
width: '100%',
|
||||
padding: '0 28px',
|
||||
...displayFlex('flex-end', 'center'),
|
||||
|
||||
Reference in New Issue
Block a user