refactor: workspace header (#1880)

This commit is contained in:
Himself65
2023-04-11 21:39:39 -05:00
committed by GitHub
parent 2e823c2fee
commit a06113d48c
42 changed files with 1653 additions and 470 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,119 +0,0 @@
import { useTranslation } from '@affine/i18n';
import { CloseIcon } from '@blocksuite/icons';
import type { HTMLAttributes, PropsWithChildren } from 'react';
import type React from 'react';
import { forwardRef, useEffect, useMemo, useState } from 'react';
import {
useSidebarFloating,
useSidebarStatus,
} from '../../../hooks/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';
import TrashButtonGroup from './header-right-items/TrashButtonGroup';
import {
StyledBrowserWarning,
StyledCloseButton,
StyledHeader,
StyledHeaderContainer,
StyledHeaderRightSide,
} from './styles';
import { OSWarningMessage, shouldShowWarning } from './utils';
const BrowserWarning = ({
show,
onClose,
}: {
show: boolean;
onClose: () => void;
}) => {
return (
<StyledBrowserWarning show={show}>
<OSWarningMessage />
<StyledCloseButton onClick={onClose}>
<CloseIcon />
</StyledCloseButton>
</StyledBrowserWarning>
);
};
type HeaderRightItemNames =
| 'editorOptionMenu'
| 'trashButtonGroup'
| 'themeModeSwitch'
| 'syncUser';
const HeaderRightItems: Record<HeaderRightItemNames, React.FC> = {
editorOptionMenu: EditorOptionMenu,
trashButtonGroup: TrashButtonGroup,
themeModeSwitch: ThemeModeSwitch,
syncUser: SyncUser,
};
export type HeaderProps = PropsWithChildren<{
rightItems?: HeaderRightItemNames[];
}>;
export const Header = forwardRef<
HTMLDivElement,
HeaderProps & HTMLAttributes<HTMLDivElement>
>(
(
{ rightItems = ['syncUser', 'themeModeSwitch'], children, ...props },
ref
) => {
const [showWarning, setShowWarning] = useState(false);
useEffect(() => {
setShowWarning(shouldShowWarning());
}, []);
const [open] = useSidebarStatus();
const sidebarFloating = useSidebarFloating();
const { t } = useTranslation();
return (
<StyledHeaderContainer
sidebarFloating={sidebarFloating && open}
ref={ref}
hasWarning={showWarning}
{...props}
>
<BrowserWarning
show={showWarning}
onClose={() => {
setShowWarning(false);
}}
/>
<StyledHeader
hasWarning={showWarning}
data-testid="editor-header-items"
data-tauri-drag-region
>
<SidebarSwitch
visible={!open}
tooltipContent={t('Expand sidebar')}
testid="sliderBar-arrowButton-expand"
/>
{children}
<StyledHeaderRightSide>
{useMemo(
() =>
rightItems.map(itemName => {
const Item = HeaderRightItems[itemName];
return <Item key={itemName} />;
}),
[rightItems]
)}
{/*<ShareMenu />*/}
</StyledHeaderRightSide>
</StyledHeader>
</StyledHeaderContainer>
);
}
);
Header.displayName = 'Header';
export default Header;
@@ -1,158 +0,0 @@
import type { PopperProps } from '@affine/component';
import { QuickSearchTips } from '@affine/component';
import { getEnvironment } from '@affine/env';
import { ArrowDownSmallIcon } from '@blocksuite/icons';
import { assertExists } from '@blocksuite/store';
import { useAtomValue, useSetAtom } from 'jotai';
import type { HTMLAttributes } from 'react';
import { forwardRef, useCallback, useRef } from 'react';
import { currentEditorAtom, openQuickSearchModalAtom } from '../../../atoms';
import { useGuideHidden } from '../../../hooks/use-is-first-load';
import { usePageMeta } from '../../../hooks/use-page-meta';
import { useElementResizeEffect } from '../../../hooks/use-workspaces';
import type { BlockSuiteWorkspace } from '../../../shared';
import { PageNotFoundError } from '../../affine/affine-error-eoundary';
import { QuickSearchButton } from '../../pure/quick-search-button';
import { EditorModeSwitch } from './editor-mode-switch';
import Header from './header';
import {
StyledQuickSearchTipButton,
StyledQuickSearchTipContent,
StyledSearchArrowWrapper,
StyledSwitchWrapper,
StyledTitle,
StyledTitleContainer,
StyledTitleWrapper,
} from './styles';
export type BlockSuiteEditorHeaderProps = React.PropsWithChildren<{
blockSuiteWorkspace: BlockSuiteWorkspace;
pageId: string;
isPublic?: boolean;
isPreview?: boolean;
}>;
export const BlockSuiteEditorHeader = forwardRef<
HTMLDivElement,
BlockSuiteEditorHeaderProps & HTMLAttributes<HTMLDivElement>
>(
(
{ blockSuiteWorkspace, pageId, children, isPublic, isPreview, ...props },
ref
) => {
const page = blockSuiteWorkspace.getPage(pageId);
// fixme(himself65): remove this atom and move it to props
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
if (!page) {
throw new PageNotFoundError(blockSuiteWorkspace, pageId);
}
const pageMeta = usePageMeta(blockSuiteWorkspace).find(
meta => meta.id === pageId
);
assertExists(pageMeta);
const title = pageMeta.title;
const { trash: isTrash } = pageMeta;
const [isTipsHidden, setTipsHidden] = useGuideHidden();
const isMac = () => {
const env = getEnvironment();
return env.isBrowser && env.isMacOs;
};
const popperRef: PopperProps['popperRef'] = useRef(null);
useElementResizeEffect(
useAtomValue(currentEditorAtom),
useCallback(() => {
if (isTipsHidden.quickSearchTips || !popperRef.current) {
return;
}
popperRef.current.update();
}, [isTipsHidden.quickSearchTips])
);
const TipsContent = (
<StyledQuickSearchTipContent>
<div>
Click button
{
<span
style={{
fontSize: '24px',
verticalAlign: 'middle',
}}
>
<ArrowDownSmallIcon />
</span>
}
or use
{isMac() ? ' ⌘ + K' : ' Ctrl + K'} to activate Quick Search. Then you
can search keywords or quickly open recently viewed pages.
</div>
<StyledQuickSearchTipButton
data-testid="quick-search-got-it"
onClick={() =>
setTipsHidden({ ...isTipsHidden, quickSearchTips: true })
}
>
Got it
</StyledQuickSearchTipButton>
</StyledQuickSearchTipContent>
);
return (
<Header
ref={ref}
rightItems={
// fixme(himself65): other right items not supported in public mode
isPublic || isPreview
? ['themeModeSwitch']
: isTrash
? ['trashButtonGroup']
: [
'syncUser',
/* 'shareMenu', */ 'themeModeSwitch',
'editorOptionMenu',
]
}
{...props}
>
{children}
{!isPublic && (
<StyledTitleContainer data-tauri-drag-region>
<StyledTitleWrapper>
<StyledSwitchWrapper>
<EditorModeSwitch
blockSuiteWorkspace={blockSuiteWorkspace}
pageId={pageId}
style={{
marginRight: '12px',
}}
/>
</StyledSwitchWrapper>
<StyledTitle>{title || 'Untitled'}</StyledTitle>
<QuickSearchTips
data-testid="quick-search-tips"
content={TipsContent}
placement="bottom"
popperRef={popperRef}
open={!isTipsHidden.quickSearchTips}
offset={[0, -5]}
>
<StyledSearchArrowWrapper>
<QuickSearchButton
onClick={() => {
setOpenQuickSearch(true);
}}
/>
</StyledSearchArrowWrapper>
</QuickSearchTips>
</StyledTitleWrapper>
</StyledTitleContainer>
)}
</Header>
);
}
);
BlockSuiteEditorHeader.displayName = 'BlockSuiteEditorHeader';
@@ -0,0 +1,669 @@
{
"v": "5.9.0",
"fr": 29.9700012207031,
"ip": 0,
"op": 60.0000024438501,
"w": 500,
"h": 500,
"nm": "edgeless-hover",
"ddd": 0,
"assets": [],
"layers": [
{
"ddd": 0,
"ind": 1,
"ty": 4,
"nm": "Layer 3/paper-edgeless-icons Outlines",
"sr": 1,
"ks": {
"o": { "a": 0, "k": 100, "ix": 11 },
"r": { "a": 0, "k": 0, "ix": 10 },
"p": { "a": 0, "k": [250, 250, 0], "ix": 2, "l": 2 },
"a": { "a": 0, "k": [183.5, 183.5, 0], "ix": 1, "l": 2 },
"s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 }
},
"ao": 0,
"shapes": [
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[0, 0],
[0, -5.604],
[0, 0],
[-5.614, 0],
[0, 0],
[0, 5.605],
[0, 0],
[5.615, 0]
],
"o": [
[-5.614, 0],
[0, 0],
[0, 5.605],
[0, 0],
[5.615, 0],
[0, 0],
[0, -5.604],
[0, 0]
],
"v": [
[-30.525, -40.7],
[-40.699, -30.525],
[-40.699, 30.524],
[-30.525, 40.699],
[30.525, 40.699],
[40.699, 30.524],
[40.699, -30.525],
[30.525, -40.7]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ind": 1,
"ty": "sh",
"ix": 2,
"ks": {
"a": 0,
"k": {
"i": [
[22.447, 0],
[0, 0],
[0, 22.437],
[0, 0],
[-22.446, 0],
[0, 0],
[0, -22.437],
[0, 0]
],
"o": [
[0, 0],
[-22.446, 0],
[0, 0],
[0, -22.437],
[0, 0],
[22.447, 0],
[0, 0],
[0, 22.437]
],
"v": [
[30.525, 71.224],
[-30.525, 71.224],
[-71.225, 30.524],
[-71.225, -30.525],
[-30.525, -71.225],
[30.525, -71.225],
[71.224, -30.525],
[71.224, 30.524]
],
"c": true
},
"ix": 2
},
"nm": "Path 2",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "mm",
"mm": 1,
"nm": "Merge Paths 1",
"mn": "ADBE Vector Filter - Merge",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [295.322, 295.323],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [315.322, 315.323],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [295.322, 295.323] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 1",
"np": 4,
"cix": 2,
"bm": 0,
"ix": 1,
"mn": "ADBE Vector Group",
"hd": false
},
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[8.426, 0],
[0, 8.426],
[0, 0],
[-8.426, 0],
[0, -8.426],
[0, 0]
],
"o": [
[-8.426, 0],
[0, 0],
[0, -8.426],
[8.426, 0],
[0, 0],
[0, 8.426]
],
"v": [
[0, 30.525],
[-15.262, 15.263],
[-15.262, -15.262],
[0, -30.525],
[15.262, -15.262],
[15.262, 15.263]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [76.561, 183.399],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [56.561, 183.399],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [76.561, 183.399] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 2",
"np": 2,
"cix": 2,
"bm": 0,
"ix": 2,
"mn": "ADBE Vector Group",
"hd": false
},
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[8.426, 0],
[0, 8.426],
[5.395, 13.057],
[9.956, 9.956],
[13.037, 5.406],
[14.1, 0],
[0, 8.426],
[-8.426, 0],
[-16.753, -6.955],
[-12.808, -12.818],
[-6.955, -16.773],
[0, -18.105]
],
"o": [
[-8.426, 0],
[0, -14.09],
[-5.416, -13.016],
[-9.957, -9.956],
[-13.026, -5.385],
[-8.426, 0],
[0, -8.426],
[18.134, 0],
[16.763, 6.936],
[12.788, 12.778],
[6.936, 16.773],
[0, 8.426]
],
"v": [
[61.049, 76.312],
[45.788, 61.05],
[37.66, 20.151],
[14.497, -14.487],
[-20.161, -37.659],
[-61.049, -45.787],
[-76.311, -61.049],
[-61.049, -76.312],
[-8.475, -65.839],
[36.09, -36.069],
[65.858, 8.486],
[76.311, 61.05]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [254.447, 112.349],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [274.447, 92.349],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [254.447, 112.349] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 3",
"np": 2,
"cix": 2,
"bm": 0,
"ix": 3,
"mn": "ADBE Vector Group",
"hd": false
},
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[22.446, 0],
[0, -22.437],
[-22.446, 0],
[0, 22.436]
],
"o": [
[-22.446, 0],
[0, 22.436],
[22.446, 0],
[0, -22.437]
],
"v": [
[0, -40.7],
[-40.7, 0],
[0, 40.699],
[40.7, 0]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ind": 1,
"ty": "sh",
"ix": 2,
"ks": {
"a": 0,
"k": {
"i": [
[39.269, 0],
[0, 39.268],
[-39.269, 0],
[0, -39.269]
],
"o": [
[-39.269, 0],
[0, -39.269],
[39.269, 0],
[0, 39.268]
],
"v": [
[0, 71.224],
[-71.224, 0],
[0, -71.225],
[71.224, 0]
],
"c": true
},
"ix": 2
},
"nm": "Path 2",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "mm",
"mm": 1,
"nm": "Merge Paths 1",
"mn": "ADBE Vector Filter - Merge",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [71.474, 295.323],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [51.474, 315.323],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [71.474, 295.323] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 4",
"np": 4,
"cix": 2,
"bm": 0,
"ix": 4,
"mn": "ADBE Vector Group",
"hd": false
},
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[22.446, 0],
[0, -22.437],
[-22.446, 0],
[0, 22.436]
],
"o": [
[-22.446, 0],
[0, 22.436],
[22.446, 0],
[0, -22.437]
],
"v": [
[0, -40.7],
[-40.7, 0.001],
[0, 40.7],
[40.7, 0.001]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ind": 1,
"ty": "sh",
"ix": 2,
"ks": {
"a": 0,
"k": {
"i": [
[39.269, 0],
[0, 39.268],
[-39.269, 0],
[0, -39.269]
],
"o": [
[-39.269, 0],
[0, -39.269],
[39.269, 0],
[0, 39.268]
],
"v": [
[0, 71.225],
[-71.224, 0.001],
[0, -71.225],
[71.224, 0.001]
],
"c": true
},
"ix": 2
},
"nm": "Path 2",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "mm",
"mm": 1,
"nm": "Merge Paths 1",
"mn": "ADBE Vector Filter - Merge",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [71.474, 71.475],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [51.474, 51.475],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [71.474, 71.475] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 5",
"np": 4,
"cix": 2,
"bm": 0,
"ix": 5,
"mn": "ADBE Vector Group",
"hd": false
}
],
"ip": 0,
"op": 60.0000024438501,
"st": 0,
"bm": 0
}
],
"markers": []
}
@@ -0,0 +1,521 @@
{
"v": "5.9.0",
"fr": 29.9700012207031,
"ip": 0,
"op": 60.0000024438501,
"w": 500,
"h": 500,
"nm": "page-hover",
"ddd": 0,
"assets": [],
"layers": [
{
"ddd": 0,
"ind": 1,
"ty": 4,
"nm": "Layer 1/paper-edgeless-icons Outlines",
"sr": 1,
"ks": {
"o": { "a": 0, "k": 100, "ix": 11 },
"r": { "a": 0, "k": 0, "ix": 10 },
"p": { "a": 0, "k": [250, 250, 0], "ix": 2, "l": 2 },
"a": { "a": 0, "k": [183, 183, 0], "ix": 1, "l": 2 },
"s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 }
},
"ao": 0,
"shapes": [
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[22.557, 0],
[0, 0],
[0, 8.639],
[-8.64, 0],
[0, 0],
[-2.201, 1.651],
[0, 9.536],
[0, 0],
[-8.64, 0],
[0, -8.64],
[0, 0],
[16.892, -16.892]
],
"o": [
[0, 0],
[-8.64, 0],
[0, -8.64],
[0, 0],
[17.442, 0],
[10.412, -10.453],
[0, 0],
[0, -8.64],
[8.639, 0],
[0, 0],
[0, 18.155],
[-9.027, 8.987]
],
"v": [
[46.947, 182.579],
[-109.545, 182.579],
[-125.194, 166.93],
[-109.545, 151.281],
[46.947, 151.281],
[78.001, 145.086],
[93.895, 114.766],
[93.895, -166.93],
[109.545, -182.579],
[125.194, -166.93],
[125.194, 114.766],
[99.743, 167.561]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [240.204, 182.829],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [260.204, 202.829],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [240.204, 182.829] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 1",
"np": 2,
"cix": 2,
"bm": 0,
"ix": 1,
"mn": "ADBE Vector Group",
"hd": false
},
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[8.64, 0],
[0, 8.639],
[0, 0],
[-16.892, 16.882],
[-22.598, 0],
[0, 0],
[0, -8.64],
[8.639, 0],
[0, 0],
[2.171, -1.65],
[0, -9.546],
[0, 0]
],
"o": [
[-8.64, 0],
[0, 0],
[0, -18.145],
[8.976, -8.986],
[0, 0],
[8.639, 0],
[0, 8.64],
[0, 0],
[-17.453, 0],
[-10.443, 10.484],
[0, 0],
[0, 8.639]
],
"v": [
[-109.545, 182.579],
[-125.194, 166.93],
[-125.194, -114.766],
[-99.743, -167.562],
[-46.948, -182.579],
[109.545, -182.579],
[125.194, -166.93],
[109.545, -151.281],
[-46.948, -151.281],
[-77.972, -145.107],
[-93.896, -114.766],
[-93.896, 166.93]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [125.443, 182.829],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [105.443, 162.829],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [125.443, 182.829] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 2",
"np": 2,
"cix": 2,
"bm": 0,
"ix": 2,
"mn": "ADBE Vector Group",
"hd": false
},
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[8.64, 0],
[0, 0],
[0, 8.639],
[-8.64, 0],
[0, 0],
[0, -8.64]
],
"o": [
[0, 0],
[-8.64, 0],
[0, -8.64],
[0, 0],
[8.64, 0],
[0, 8.639]
],
"v": [
[67.813, 15.649],
[-67.813, 15.649],
[-83.463, 0],
[-67.813, -15.649],
[67.813, -15.649],
[83.462, 0]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [182.824, 271.513],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [212.824, 281.513],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [182.824, 271.513] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 3",
"np": 2,
"cix": 2,
"bm": 0,
"ix": 3,
"mn": "ADBE Vector Group",
"hd": false
},
{
"ty": "gr",
"it": [
{
"ind": 0,
"ty": "sh",
"ix": 1,
"ks": {
"a": 0,
"k": {
"i": [
[0, 0],
[0, -5.757],
[0, 0],
[-5.756, 0],
[0, 0],
[0, 5.756],
[0, 0],
[5.747, 0]
],
"o": [
[-5.756, 0],
[0, 0],
[0, 5.756],
[0, 0],
[5.747, 0],
[0, 0],
[0, -5.757],
[0, 0]
],
"v": [
[-41.732, -31.294],
[-52.165, -20.86],
[-52.165, 20.87],
[-41.732, 31.303],
[41.73, 31.303],
[52.163, 20.87],
[52.163, -20.86],
[41.73, -31.294]
],
"c": true
},
"ix": 2
},
"nm": "Path 1",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ind": 1,
"ty": "sh",
"ix": 2,
"ks": {
"a": 0,
"k": {
"i": [
[23.006, 0],
[0, 0],
[0, 23.015],
[0, 0],
[-23.015, 0],
[0, 0],
[0, -23.016],
[0, 0]
],
"o": [
[0, 0],
[-23.015, 0],
[0, 0],
[0, -23.016],
[0, 0],
[23.006, 0],
[0, 0],
[0, 23.015]
],
"v": [
[41.73, 62.592],
[-41.732, 62.592],
[-83.463, 20.87],
[-83.463, -20.86],
[-41.732, -62.592],
[41.73, -62.592],
[83.463, -20.86],
[83.463, 20.87]
],
"c": true
},
"ix": 2
},
"nm": "Path 2",
"mn": "ADBE Vector Shape - Group",
"hd": false
},
{
"ty": "mm",
"mm": 1,
"nm": "Merge Paths 1",
"mn": "ADBE Vector Filter - Merge",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [0.466666696586, 0.458823559331, 0.490196108351, 1],
"ix": 4
},
"o": { "a": 0, "k": 100, "ix": 5 },
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 1,
"k": [
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 0,
"s": [182.824, 141.088],
"to": [0, 0],
"ti": [0, 0]
},
{
"i": { "x": 0.833, "y": 0.833 },
"o": { "x": 0.167, "y": 0.167 },
"t": 30,
"s": [152.824, 131.088],
"to": [0, 0],
"ti": [0, 0]
},
{ "t": 58.0000023623884, "s": [182.824, 141.088] }
],
"ix": 2
},
"a": { "a": 0, "k": [0, 0], "ix": 1 },
"s": { "a": 0, "k": [100, 100], "ix": 3 },
"r": { "a": 0, "k": 0, "ix": 6 },
"o": { "a": 0, "k": 100, "ix": 7 },
"sk": { "a": 0, "k": 0, "ix": 4 },
"sa": { "a": 0, "k": 0, "ix": 5 },
"nm": "Transform"
}
],
"nm": "Group 4",
"np": 4,
"cix": 2,
"bm": 0,
"ix": 4,
"mn": "ADBE Vector Group",
"hd": false
}
],
"ip": 0,
"op": 60.0000024438501,
"st": 0,
"bm": 0
}
],
"markers": []
}
@@ -0,0 +1,177 @@
import { useTranslation } from '@affine/i18n';
import { CloseIcon } from '@blocksuite/icons';
import type { Page } from '@blocksuite/store';
import type { HTMLAttributes, PropsWithChildren } from 'react';
import type React from 'react';
import { forwardRef, useEffect, useMemo, useState } from 'react';
import {
useSidebarFloating,
useSidebarStatus,
} from '../../../hooks/use-sidebar-status';
import type { AffineOfficialWorkspace } from '../../../shared';
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';
import TrashButtonGroup from './header-right-items/TrashButtonGroup';
import {
StyledBrowserWarning,
StyledCloseButton,
StyledHeader,
StyledHeaderContainer,
StyledHeaderRightSide,
} from './styles';
import { OSWarningMessage, shouldShowWarning } from './utils';
const BrowserWarning = ({
show,
onClose,
}: {
show: boolean;
onClose: () => void;
}) => {
return (
<StyledBrowserWarning show={show}>
<OSWarningMessage />
<StyledCloseButton onClick={onClose}>
<CloseIcon />
</StyledCloseButton>
</StyledBrowserWarning>
);
};
export type BaseHeaderProps<
Workspace extends AffineOfficialWorkspace = AffineOfficialWorkspace
> = {
workspace: Workspace;
currentPage: Page | null;
isPublic: boolean;
isPreview: boolean;
};
export const enum HeaderRightItemName {
EditorOptionMenu = 'editorOptionMenu',
TrashButtonGroup = 'trashButtonGroup',
ThemeModeSwitch = 'themeModeSwitch',
SyncUser = 'syncUser',
ShareMenu = 'shareMenu',
}
type HeaderItem = {
Component: React.FC<BaseHeaderProps>;
// todo: public workspace should be one of the flavour
availableWhen: (
workspace: AffineOfficialWorkspace,
currentPage: Page | null,
status: {
isPublic: boolean;
isPreview: boolean;
}
) => boolean;
};
const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
[HeaderRightItemName.TrashButtonGroup]: {
Component: TrashButtonGroup,
availableWhen: (_, currentPage) => {
return currentPage?.meta.trash === true;
},
},
[HeaderRightItemName.SyncUser]: {
Component: SyncUser,
availableWhen: (_, currentPage, { isPublic, isPreview }) => {
return !isPublic && !isPreview;
},
},
[HeaderRightItemName.ThemeModeSwitch]: {
Component: ThemeModeSwitch,
availableWhen: (_, currentPage) => {
return currentPage?.meta.trash !== true;
},
},
[HeaderRightItemName.EditorOptionMenu]: {
Component: EditorOptionMenu,
availableWhen: (_, currentPage, { isPublic, isPreview }) => {
return !!currentPage && !isPublic && !isPreview;
},
},
[HeaderRightItemName.ShareMenu]: {
Component: () => null,
availableWhen: (_, currentPage, { isPublic, isPreview }) => {
return false;
},
},
};
export type HeaderProps = BaseHeaderProps;
export const Header = forwardRef<
HTMLDivElement,
PropsWithChildren<HeaderProps> & HTMLAttributes<HTMLDivElement>
>((props, ref) => {
const [showWarning, setShowWarning] = useState(false);
useEffect(() => {
setShowWarning(shouldShowWarning());
}, []);
const [open] = useSidebarStatus();
const sidebarFloating = useSidebarFloating();
const { t } = useTranslation();
return (
<StyledHeaderContainer
sidebarFloating={sidebarFloating && open}
ref={ref}
hasWarning={showWarning}
{...props}
>
<BrowserWarning
show={showWarning}
onClose={() => {
setShowWarning(false);
}}
/>
<StyledHeader
hasWarning={showWarning}
data-testid="editor-header-items"
data-tauri-drag-region
>
<SidebarSwitch
visible={!open}
tooltipContent={t('Expand sidebar')}
testid="sliderBar-arrowButton-expand"
/>
{props.children}
<StyledHeaderRightSide>
{useMemo(() => {
return Object.entries(HeaderRightItems).map(
([name, { availableWhen, Component }]) => {
if (
availableWhen(props.workspace, props.currentPage, {
isPreview: props.isPreview,
isPublic: props.isPublic,
})
) {
return (
<Component
workspace={props.workspace}
currentPage={props.currentPage}
isPreview={props.isPreview}
isPublic={props.isPublic}
key={name}
/>
);
}
return null;
}
);
}, [props])}
{/*<ShareMenu />*/}
</StyledHeaderRightSide>
</StyledHeader>
</StyledHeaderContainer>
);
});
Header.displayName = 'Header';
@@ -0,0 +1,128 @@
import type { PopperProps } from '@affine/component';
import { QuickSearchTips } from '@affine/component';
import { getEnvironment } from '@affine/env';
import { ArrowDownSmallIcon } from '@blocksuite/icons';
import { assertExists } from '@blocksuite/store';
import { useAtomValue, useSetAtom } from 'jotai';
import type { HTMLAttributes, PropsWithChildren } from 'react';
import { forwardRef, useCallback, useRef } from 'react';
import { currentEditorAtom, openQuickSearchModalAtom } from '../../../atoms';
import { useGuideHidden } from '../../../hooks/use-is-first-load';
import { usePageMeta } from '../../../hooks/use-page-meta';
import { useElementResizeEffect } from '../../../hooks/use-workspaces';
import { QuickSearchButton } from '../../pure/quick-search-button';
import { EditorModeSwitch } from './editor-mode-switch';
import type { BaseHeaderProps } from './header';
import { Header } from './header';
import {
StyledQuickSearchTipButton,
StyledQuickSearchTipContent,
StyledSearchArrowWrapper,
StyledSwitchWrapper,
StyledTitle,
StyledTitleContainer,
StyledTitleWrapper,
} from './styles';
export type WorkspaceHeaderProps = BaseHeaderProps;
export const WorkspaceHeader = forwardRef<
HTMLDivElement,
PropsWithChildren<WorkspaceHeaderProps> & HTMLAttributes<HTMLDivElement>
>((props, ref) => {
const { workspace, currentPage, children, isPublic } = props;
// fixme(himself65): remove this atom and move it to props
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
const pageMeta = usePageMeta(workspace.blockSuiteWorkspace).find(
meta => meta.id === currentPage?.id
);
assertExists(pageMeta);
const title = pageMeta.title;
const [isTipsHidden, setTipsHidden] = useGuideHidden();
const isMac = () => {
const env = getEnvironment();
return env.isBrowser && env.isMacOs;
};
const popperRef: PopperProps['popperRef'] = useRef(null);
useElementResizeEffect(
useAtomValue(currentEditorAtom),
useCallback(() => {
if (isTipsHidden.quickSearchTips || !popperRef.current) {
return;
}
popperRef.current.update();
}, [isTipsHidden.quickSearchTips])
);
const TipsContent = (
<StyledQuickSearchTipContent>
<div>
Click button
{
<span
style={{
fontSize: '24px',
verticalAlign: 'middle',
}}
>
<ArrowDownSmallIcon />
</span>
}
or use
{isMac() ? ' ⌘ + K' : ' Ctrl + K'} to activate Quick Search. Then you
can search keywords or quickly open recently viewed pages.
</div>
<StyledQuickSearchTipButton
data-testid="quick-search-got-it"
onClick={() =>
setTipsHidden({ ...isTipsHidden, quickSearchTips: true })
}
>
Got it
</StyledQuickSearchTipButton>
</StyledQuickSearchTipContent>
);
return (
<Header ref={ref} {...props}>
{children}
{!isPublic && currentPage && (
<StyledTitleContainer data-tauri-drag-region>
<StyledTitleWrapper>
<StyledSwitchWrapper>
<EditorModeSwitch
blockSuiteWorkspace={workspace.blockSuiteWorkspace}
pageId={currentPage.id}
style={{
marginRight: '12px',
}}
/>
</StyledSwitchWrapper>
<StyledTitle>{title || 'Untitled'}</StyledTitle>
<QuickSearchTips
data-testid="quick-search-tips"
content={TipsContent}
placement="bottom"
popperRef={popperRef}
open={!isTipsHidden.quickSearchTips}
offset={[0, -5]}
>
<StyledSearchArrowWrapper>
<QuickSearchButton
onClick={() => {
setOpenQuickSearch(true);
}}
/>
</StyledSearchArrowWrapper>
</QuickSearchTips>
</StyledTitleWrapper>
</StyledTitleContainer>
)}
</Header>
);
});
WorkspaceHeader.displayName = 'BlockSuiteEditorHeader';
+11 -10
View File
@@ -10,14 +10,14 @@ import { useCallback } from 'react';
import { currentEditorAtom, workspacePreferredModeAtom } from '../atoms';
import { usePageMeta } from '../hooks/use-page-meta';
import type { BlockSuiteWorkspace } from '../shared';
import type { AffineOfficialWorkspace } from '../shared';
import { PageNotFoundError } from './affine/affine-error-eoundary';
import { BlockSuiteEditorHeader } from './blocksuite/header';
import { WorkspaceHeader } from './blocksuite/workspace-header';
export type PageDetailEditorProps = {
isPublic?: boolean;
isPreview?: boolean;
blockSuiteWorkspace: BlockSuiteWorkspace;
workspace: AffineOfficialWorkspace;
pageId: string;
onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
onLoad?: (page: Page, editor: EditorContainer) => void;
@@ -33,7 +33,7 @@ const Editor = dynamic(
);
export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
blockSuiteWorkspace,
workspace,
pageId,
onInit,
onLoad,
@@ -41,6 +41,7 @@ export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
isPublic,
isPreview,
}) => {
const blockSuiteWorkspace = workspace.blockSuiteWorkspace;
const page = blockSuiteWorkspace.getPage(pageId);
if (!page) {
throw new PageNotFoundError(blockSuiteWorkspace, pageId);
@@ -58,14 +59,14 @@ export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
<Head>
<title>{title}</title>
</Head>
<BlockSuiteEditorHeader
isPublic={isPublic}
isPreview={isPreview}
blockSuiteWorkspace={blockSuiteWorkspace}
pageId={pageId}
<WorkspaceHeader
isPublic={isPublic ?? false}
isPreview={isPreview ?? false}
workspace={workspace}
currentPage={page}
>
{header}
</BlockSuiteEditorHeader>
</WorkspaceHeader>
<Editor
style={{
height: 'calc(100% - 52px)',
@@ -7,6 +7,8 @@ import {
import { WorkspaceList } from '@affine/component/workspace-list';
import { useTranslation } from '@affine/i18n';
import type { AccessTokenMessage } from '@affine/workspace/affine/login';
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { HelpIcon, PlusIcon } from '@blocksuite/icons';
import type { DragEndEvent } from '@dnd-kit/core';
import { useCallback } from 'react';
@@ -99,7 +101,11 @@ export const WorkspaceListModal = ({
<StyledModalContent>
<WorkspaceList
disabled={disabled}
items={workspaces}
items={
workspaces.filter(
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
) as (AffineWorkspace | LocalWorkspace)[]
}
currentWorkspaceId={currentWorkspaceId}
onClick={onClickWorkspace}
onSettingClick={onClickWorkspaceSetting}
@@ -3,21 +3,25 @@ import type { ReactNode } from 'react';
import type React from 'react';
import { openQuickSearchModalAtom } from '../../../atoms';
import Header from '../../blocksuite/header/header';
import { StyledPageListTittleWrapper } from '../../blocksuite/header/styles';
import type { HeaderProps } from '../../blocksuite/workspace-header/header';
import { Header } from '../../blocksuite/workspace-header/header';
import { StyledPageListTittleWrapper } from '../../blocksuite/workspace-header/styles';
import { QuickSearchButton } from '../quick-search-button';
export type WorkspaceTitleProps = React.PropsWithChildren<{
icon?: ReactNode;
}>;
export type WorkspaceTitleProps = React.PropsWithChildren<
HeaderProps & {
icon?: ReactNode;
}
>;
export const WorkspaceTitle: React.FC<WorkspaceTitleProps> = ({
icon,
children,
...props
}) => {
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
return (
<Header>
<Header {...props}>
<StyledPageListTittleWrapper>
{icon}
{children}