refactor: workspace header (#1880)
This commit is contained in:
@@ -1,11 +1,16 @@
|
|||||||
import { getLoginStorage } from '@affine/workspace/affine/login';
|
import { getLoginStorage } from '@affine/workspace/affine/login';
|
||||||
|
import type { AffinePublicWorkspace } from '@affine/workspace/type';
|
||||||
|
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||||
import { atom } from 'jotai';
|
import { atom } from 'jotai';
|
||||||
|
|
||||||
import { BlockSuiteWorkspace } from '../../shared';
|
import { BlockSuiteWorkspace } from '../../shared';
|
||||||
import { affineApis } from '../../shared/apis';
|
import { affineApis } from '../../shared/apis';
|
||||||
|
|
||||||
function createPublicWorkspace(workspaceId: string, binary: ArrayBuffer) {
|
function createPublicWorkspace(
|
||||||
|
workspaceId: string,
|
||||||
|
binary: ArrayBuffer
|
||||||
|
): AffinePublicWorkspace {
|
||||||
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
||||||
workspaceId,
|
workspaceId,
|
||||||
(k: string) =>
|
(k: string) =>
|
||||||
@@ -22,12 +27,18 @@ function createPublicWorkspace(workspaceId: string, binary: ArrayBuffer) {
|
|||||||
blockSuiteWorkspace.awarenessStore.setFlag('enable_edgeless_toolbar', false);
|
blockSuiteWorkspace.awarenessStore.setFlag('enable_edgeless_toolbar', false);
|
||||||
blockSuiteWorkspace.awarenessStore.setFlag('enable_slash_menu', false);
|
blockSuiteWorkspace.awarenessStore.setFlag('enable_slash_menu', false);
|
||||||
blockSuiteWorkspace.awarenessStore.setFlag('enable_drag_handle', false);
|
blockSuiteWorkspace.awarenessStore.setFlag('enable_drag_handle', false);
|
||||||
return blockSuiteWorkspace;
|
return {
|
||||||
|
flavour: WorkspaceFlavour.PUBLIC,
|
||||||
|
id: workspaceId,
|
||||||
|
blockSuiteWorkspace,
|
||||||
|
// maybe we can add some sync providers here
|
||||||
|
providers: [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const publicWorkspaceIdAtom = atom<string | null>(null);
|
export const publicWorkspaceIdAtom = atom<string | null>(null);
|
||||||
export const publicWorkspacePageIdAtom = atom<string | null>(null);
|
export const publicWorkspacePageIdAtom = atom<string | null>(null);
|
||||||
export const publicPageBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
|
export const publicPageBlockSuiteAtom = atom<Promise<AffinePublicWorkspace>>(
|
||||||
async get => {
|
async get => {
|
||||||
const workspaceId = get(publicWorkspaceIdAtom);
|
const workspaceId = get(publicWorkspaceIdAtom);
|
||||||
const pageId = get(publicWorkspacePageIdAtom);
|
const pageId = get(publicWorkspacePageIdAtom);
|
||||||
@@ -41,7 +52,7 @@ export const publicPageBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
|
|||||||
return createPublicWorkspace(workspaceId, binary);
|
return createPublicWorkspace(workspaceId, binary);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
export const publicBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
|
export const publicWorkspaceAtom = atom<Promise<AffinePublicWorkspace>>(
|
||||||
async get => {
|
async get => {
|
||||||
const workspaceId = get(publicWorkspaceIdAtom);
|
const workspaceId = get(publicWorkspaceIdAtom);
|
||||||
if (!workspaceId) {
|
if (!workspaceId) {
|
||||||
|
|||||||
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": []
|
||||||
|
}
|
||||||
177
apps/web/src/components/blocksuite/workspace-header/header.tsx
Normal file
177
apps/web/src/components/blocksuite/workspace-header/header.tsx
Normal file
@@ -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';
|
||||||
128
apps/web/src/components/blocksuite/workspace-header/index.tsx
Normal file
128
apps/web/src/components/blocksuite/workspace-header/index.tsx
Normal file
@@ -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';
|
||||||
@@ -10,14 +10,14 @@ import { useCallback } from 'react';
|
|||||||
|
|
||||||
import { currentEditorAtom, workspacePreferredModeAtom } from '../atoms';
|
import { currentEditorAtom, workspacePreferredModeAtom } from '../atoms';
|
||||||
import { usePageMeta } from '../hooks/use-page-meta';
|
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 { PageNotFoundError } from './affine/affine-error-eoundary';
|
||||||
import { BlockSuiteEditorHeader } from './blocksuite/header';
|
import { WorkspaceHeader } from './blocksuite/workspace-header';
|
||||||
|
|
||||||
export type PageDetailEditorProps = {
|
export type PageDetailEditorProps = {
|
||||||
isPublic?: boolean;
|
isPublic?: boolean;
|
||||||
isPreview?: boolean;
|
isPreview?: boolean;
|
||||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
workspace: AffineOfficialWorkspace;
|
||||||
pageId: string;
|
pageId: string;
|
||||||
onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
|
onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
|
||||||
onLoad?: (page: Page, editor: EditorContainer) => void;
|
onLoad?: (page: Page, editor: EditorContainer) => void;
|
||||||
@@ -33,7 +33,7 @@ const Editor = dynamic(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
|
export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
|
||||||
blockSuiteWorkspace,
|
workspace,
|
||||||
pageId,
|
pageId,
|
||||||
onInit,
|
onInit,
|
||||||
onLoad,
|
onLoad,
|
||||||
@@ -41,6 +41,7 @@ export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
|
|||||||
isPublic,
|
isPublic,
|
||||||
isPreview,
|
isPreview,
|
||||||
}) => {
|
}) => {
|
||||||
|
const blockSuiteWorkspace = workspace.blockSuiteWorkspace;
|
||||||
const page = blockSuiteWorkspace.getPage(pageId);
|
const page = blockSuiteWorkspace.getPage(pageId);
|
||||||
if (!page) {
|
if (!page) {
|
||||||
throw new PageNotFoundError(blockSuiteWorkspace, pageId);
|
throw new PageNotFoundError(blockSuiteWorkspace, pageId);
|
||||||
@@ -58,14 +59,14 @@ export const PageDetailEditor: React.FC<PageDetailEditorProps> = ({
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
</Head>
|
</Head>
|
||||||
<BlockSuiteEditorHeader
|
<WorkspaceHeader
|
||||||
isPublic={isPublic}
|
isPublic={isPublic ?? false}
|
||||||
isPreview={isPreview}
|
isPreview={isPreview ?? false}
|
||||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
workspace={workspace}
|
||||||
pageId={pageId}
|
currentPage={page}
|
||||||
>
|
>
|
||||||
{header}
|
{header}
|
||||||
</BlockSuiteEditorHeader>
|
</WorkspaceHeader>
|
||||||
<Editor
|
<Editor
|
||||||
style={{
|
style={{
|
||||||
height: 'calc(100% - 52px)',
|
height: 'calc(100% - 52px)',
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
import { WorkspaceList } from '@affine/component/workspace-list';
|
import { WorkspaceList } from '@affine/component/workspace-list';
|
||||||
import { useTranslation } from '@affine/i18n';
|
import { useTranslation } from '@affine/i18n';
|
||||||
import type { AccessTokenMessage } from '@affine/workspace/affine/login';
|
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 { HelpIcon, PlusIcon } from '@blocksuite/icons';
|
||||||
import type { DragEndEvent } from '@dnd-kit/core';
|
import type { DragEndEvent } from '@dnd-kit/core';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
@@ -99,7 +101,11 @@ export const WorkspaceListModal = ({
|
|||||||
<StyledModalContent>
|
<StyledModalContent>
|
||||||
<WorkspaceList
|
<WorkspaceList
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
items={workspaces}
|
items={
|
||||||
|
workspaces.filter(
|
||||||
|
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||||
|
) as (AffineWorkspace | LocalWorkspace)[]
|
||||||
|
}
|
||||||
currentWorkspaceId={currentWorkspaceId}
|
currentWorkspaceId={currentWorkspaceId}
|
||||||
onClick={onClickWorkspace}
|
onClick={onClickWorkspace}
|
||||||
onSettingClick={onClickWorkspaceSetting}
|
onSettingClick={onClickWorkspaceSetting}
|
||||||
|
|||||||
@@ -3,21 +3,25 @@ import type { ReactNode } from 'react';
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
|
||||||
import { openQuickSearchModalAtom } from '../../../atoms';
|
import { openQuickSearchModalAtom } from '../../../atoms';
|
||||||
import Header from '../../blocksuite/header/header';
|
import type { HeaderProps } from '../../blocksuite/workspace-header/header';
|
||||||
import { StyledPageListTittleWrapper } from '../../blocksuite/header/styles';
|
import { Header } from '../../blocksuite/workspace-header/header';
|
||||||
|
import { StyledPageListTittleWrapper } from '../../blocksuite/workspace-header/styles';
|
||||||
import { QuickSearchButton } from '../quick-search-button';
|
import { QuickSearchButton } from '../quick-search-button';
|
||||||
|
|
||||||
export type WorkspaceTitleProps = React.PropsWithChildren<{
|
export type WorkspaceTitleProps = React.PropsWithChildren<
|
||||||
icon?: ReactNode;
|
HeaderProps & {
|
||||||
}>;
|
icon?: ReactNode;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
export const WorkspaceTitle: React.FC<WorkspaceTitleProps> = ({
|
export const WorkspaceTitle: React.FC<WorkspaceTitleProps> = ({
|
||||||
icon,
|
icon,
|
||||||
children,
|
children,
|
||||||
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
|
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
|
||||||
return (
|
return (
|
||||||
<Header>
|
<Header {...props}>
|
||||||
<StyledPageListTittleWrapper>
|
<StyledPageListTittleWrapper>
|
||||||
{icon}
|
{icon}
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { PermissionType } from '@affine/workspace/affine/api';
|
import { PermissionType } from '@affine/workspace/affine/api';
|
||||||
|
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||||
|
|
||||||
import type { AffineOfficialWorkspace } from '../../shared';
|
import type { AffineOfficialWorkspace } from '../../shared';
|
||||||
|
|
||||||
export function useIsWorkspaceOwner(workspace: AffineOfficialWorkspace) {
|
export function useIsWorkspaceOwner(workspace: AffineOfficialWorkspace) {
|
||||||
if (workspace.flavour === 'local') return true;
|
if (workspace.flavour === WorkspaceFlavour.LOCAL) return true;
|
||||||
|
if (workspace.flavour === WorkspaceFlavour.PUBLIC) return false;
|
||||||
return workspace.permission === PermissionType.Owner;
|
return workspace.permission === PermissionType.Owner;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ export function findSuitablePageId(
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
case WorkspaceFlavour.PUBLIC: {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
openWorkspacesModalAtom,
|
openWorkspacesModalAtom,
|
||||||
} from '../atoms';
|
} from '../atoms';
|
||||||
import {
|
import {
|
||||||
publicBlockSuiteAtom,
|
publicWorkspaceAtom,
|
||||||
publicWorkspaceIdAtom,
|
publicWorkspaceIdAtom,
|
||||||
} from '../atoms/public-workspace';
|
} from '../atoms/public-workspace';
|
||||||
import { HelpIsland } from '../components/pure/help-island';
|
import { HelpIsland } from '../components/pure/help-island';
|
||||||
@@ -62,14 +62,14 @@ const QuickSearchModal = dynamic(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const PublicQuickSearch: FC = () => {
|
export const PublicQuickSearch: FC = () => {
|
||||||
const blockSuiteWorkspace = useAtomValue(publicBlockSuiteAtom);
|
const publicWorkspace = useAtomValue(publicWorkspaceAtom);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom(
|
const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom(
|
||||||
openQuickSearchModalAtom
|
openQuickSearchModalAtom
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<QuickSearchModal
|
<QuickSearchModal
|
||||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
blockSuiteWorkspace={publicWorkspace.blockSuiteWorkspace}
|
||||||
open={openQuickSearchModal}
|
open={openQuickSearchModal}
|
||||||
setOpen={setOpenQuickSearchModalAtom}
|
setOpen={setOpenQuickSearchModalAtom}
|
||||||
router={router}
|
router={router}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Suspense } from 'react';
|
|||||||
|
|
||||||
import { openQuickSearchModalAtom } from '../atoms';
|
import { openQuickSearchModalAtom } from '../atoms';
|
||||||
import {
|
import {
|
||||||
publicBlockSuiteAtom,
|
publicWorkspaceAtom,
|
||||||
publicWorkspaceIdAtom,
|
publicWorkspaceIdAtom,
|
||||||
} from '../atoms/public-workspace';
|
} from '../atoms/public-workspace';
|
||||||
import { StyledTableContainer } from '../components/blocksuite/block-suite-page-list/page-list/styles';
|
import { StyledTableContainer } from '../components/blocksuite/block-suite-page-list/page-list/styles';
|
||||||
@@ -21,14 +21,14 @@ const QuickSearchModal = dynamic(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const PublicQuickSearch: React.FC = () => {
|
export const PublicQuickSearch: React.FC = () => {
|
||||||
const blockSuiteWorkspace = useAtomValue(publicBlockSuiteAtom);
|
const publicWorkspace = useAtomValue(publicWorkspaceAtom);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom(
|
const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom(
|
||||||
openQuickSearchModalAtom
|
openQuickSearchModalAtom
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<QuickSearchModal
|
<QuickSearchModal
|
||||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
blockSuiteWorkspace={publicWorkspace.blockSuiteWorkspace}
|
||||||
open={openQuickSearchModal}
|
open={openQuickSearchModal}
|
||||||
setOpen={setOpenQuickSearchModalAtom}
|
setOpen={setOpenQuickSearchModalAtom}
|
||||||
router={router}
|
router={router}
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
|
||||||
import { ContentParser } from '@blocksuite/blocks/content-parser';
|
|
||||||
import type {
|
|
||||||
GetStaticPaths,
|
|
||||||
GetStaticProps,
|
|
||||||
InferGetStaticPropsType,
|
|
||||||
NextPage,
|
|
||||||
} from 'next';
|
|
||||||
import Head from 'next/head';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import { PageDetailEditor } from '../../components/page-detail-editor';
|
|
||||||
import { PageLoading } from '../../components/pure/loading';
|
|
||||||
import {
|
|
||||||
StyledPage,
|
|
||||||
StyledToolWrapper,
|
|
||||||
StyledWrapper,
|
|
||||||
} from '../../layouts/styles';
|
|
||||||
import type { BlockSuiteWorkspace } from '../../shared';
|
|
||||||
|
|
||||||
export type PreviewPageProps = {
|
|
||||||
text: string;
|
|
||||||
title: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PreviewPageParams = {
|
|
||||||
previewId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const PreviewPage: NextPage<PreviewPageProps> = ({
|
|
||||||
text,
|
|
||||||
title,
|
|
||||||
}: InferGetStaticPropsType<typeof getStaticProps>) => {
|
|
||||||
const [blockSuiteWorkspace, setBlockSuiteWorkspace] =
|
|
||||||
useState<BlockSuiteWorkspace | null>(null);
|
|
||||||
useEffect(() => {
|
|
||||||
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
|
||||||
'preview',
|
|
||||||
(_: string) => undefined
|
|
||||||
);
|
|
||||||
blockSuiteWorkspace.slots.pageAdded.once(() => {
|
|
||||||
setBlockSuiteWorkspace(blockSuiteWorkspace);
|
|
||||||
});
|
|
||||||
blockSuiteWorkspace.createPage('preview');
|
|
||||||
return () => {
|
|
||||||
blockSuiteWorkspace.removePage('preview');
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
if (!blockSuiteWorkspace || !blockSuiteWorkspace.getPage('preview')) {
|
|
||||||
return <PageLoading />;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>{title}</title>
|
|
||||||
</Head>
|
|
||||||
<StyledPage>
|
|
||||||
<StyledWrapper>
|
|
||||||
<PageDetailEditor
|
|
||||||
isPreview
|
|
||||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
|
||||||
pageId="preview"
|
|
||||||
onInit={(page, editor) => {
|
|
||||||
blockSuiteWorkspace.setPageMeta(page.id, { title });
|
|
||||||
const pageBlockId = page.addBlock('affine:page', {
|
|
||||||
title: new page.Text(title),
|
|
||||||
});
|
|
||||||
page.addBlock('affine:surface', {}, null);
|
|
||||||
const frameId = page.addBlock('affine:frame', {}, pageBlockId);
|
|
||||||
page.addBlock('affine:paragraph', {}, frameId);
|
|
||||||
const contentParser = new ContentParser(page);
|
|
||||||
contentParser.importMarkdown(text, frameId).then(() => {
|
|
||||||
page.resetHistory();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<StyledToolWrapper>
|
|
||||||
{/* fixme(himself65): remove this */}
|
|
||||||
<div id="toolWrapper" style={{ marginBottom: '12px' }}>
|
|
||||||
{/* Slot for block hub */}
|
|
||||||
</div>
|
|
||||||
</StyledToolWrapper>
|
|
||||||
</StyledWrapper>
|
|
||||||
</StyledPage>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PreviewPage;
|
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps<
|
|
||||||
PreviewPageProps,
|
|
||||||
PreviewPageParams
|
|
||||||
> = async context => {
|
|
||||||
const name = context.params?.previewId;
|
|
||||||
const fs = await import('node:fs/promises');
|
|
||||||
const path = await import('node:path');
|
|
||||||
const markdown: string = await fs.readFile(
|
|
||||||
path.resolve(
|
|
||||||
process.cwd(),
|
|
||||||
'..',
|
|
||||||
'..',
|
|
||||||
'packages',
|
|
||||||
'templates',
|
|
||||||
'src',
|
|
||||||
`${name}.md`
|
|
||||||
),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
const title = markdown
|
|
||||||
.split('\n')
|
|
||||||
.splice(0, 1)
|
|
||||||
.join('')
|
|
||||||
.replaceAll('#', '')
|
|
||||||
.trim();
|
|
||||||
if (!name) {
|
|
||||||
return {
|
|
||||||
redirect: {
|
|
||||||
destination: '/404',
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
text: '',
|
|
||||||
title: '',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
text: markdown.split('\n').slice(1).join('\n'),
|
|
||||||
title,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getStaticPaths: GetStaticPaths<PreviewPageParams> = () => {
|
|
||||||
return {
|
|
||||||
paths: [
|
|
||||||
{ params: { previewId: 'AFFiNE-Docs' } },
|
|
||||||
{ params: { previewId: 'Welcome-to-AFFiNE-Abbey-Alpha-Wood' } },
|
|
||||||
{ params: { previewId: 'Welcome-to-AFFiNE-Alpha-Downhills' } },
|
|
||||||
{ params: { previewId: 'Welcome-to-the-AFFiNE-Alpha' } },
|
|
||||||
],
|
|
||||||
fallback: false,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -10,7 +10,7 @@ import { Suspense, useCallback, useEffect } from 'react';
|
|||||||
|
|
||||||
import { currentWorkspaceIdAtom, openQuickSearchModalAtom } from '../../atoms';
|
import { currentWorkspaceIdAtom, openQuickSearchModalAtom } from '../../atoms';
|
||||||
import {
|
import {
|
||||||
publicBlockSuiteAtom,
|
publicWorkspaceAtom,
|
||||||
publicWorkspaceIdAtom,
|
publicWorkspaceIdAtom,
|
||||||
} from '../../atoms/public-workspace';
|
} from '../../atoms/public-workspace';
|
||||||
import { QueryParamError } from '../../components/affine/affine-error-eoundary';
|
import { QueryParamError } from '../../components/affine/affine-error-eoundary';
|
||||||
@@ -31,7 +31,8 @@ const ListPageInner: React.FC<{
|
|||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}> = ({ workspaceId }) => {
|
}> = ({ workspaceId }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const blockSuiteWorkspace = useAtomValue(publicBlockSuiteAtom);
|
const publicWorkspace = useAtomValue(publicWorkspaceAtom);
|
||||||
|
const blockSuiteWorkspace = publicWorkspace.blockSuiteWorkspace;
|
||||||
const handleClickPage = useCallback(
|
const handleClickPage = useCallback(
|
||||||
(pageId: string) => {
|
(pageId: string) => {
|
||||||
return router.push({
|
return router.push({
|
||||||
@@ -84,6 +85,7 @@ const ListPage: NextPageWithLayout = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const workspaceId = router.query.workspaceId;
|
const workspaceId = router.query.workspaceId;
|
||||||
const setWorkspaceId = useSetAtom(publicWorkspaceIdAtom);
|
const setWorkspaceId = useSetAtom(publicWorkspaceIdAtom);
|
||||||
|
// todo: remove this atom usage here
|
||||||
const setCurrentWorkspaceId = useSetAtom(currentWorkspaceIdAtom);
|
const setCurrentWorkspaceId = useSetAtom(currentWorkspaceIdAtom);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!router.isReady) {
|
if (!router.isReady) {
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ export const StyledBreadcrumbs = styled(Link)(({ theme }) => {
|
|||||||
const PublicWorkspaceDetailPageInner: React.FC<{
|
const PublicWorkspaceDetailPageInner: React.FC<{
|
||||||
pageId: string;
|
pageId: string;
|
||||||
}> = ({ pageId }) => {
|
}> = ({ pageId }) => {
|
||||||
const blockSuiteWorkspace = useAtomValue(publicPageBlockSuiteAtom);
|
const publicWorkspace = useAtomValue(publicPageBlockSuiteAtom);
|
||||||
|
const blockSuiteWorkspace = publicWorkspace.blockSuiteWorkspace;
|
||||||
if (!blockSuiteWorkspace) {
|
if (!blockSuiteWorkspace) {
|
||||||
throw new Error('cannot find workspace');
|
throw new Error('cannot find workspace');
|
||||||
}
|
}
|
||||||
@@ -83,7 +84,7 @@ const PublicWorkspaceDetailPageInner: React.FC<{
|
|||||||
<PageDetailEditor
|
<PageDetailEditor
|
||||||
isPublic={true}
|
isPublic={true}
|
||||||
pageId={pageId}
|
pageId={pageId}
|
||||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
workspace={publicWorkspace}
|
||||||
onLoad={(_, editor) => {
|
onLoad={(_, editor) => {
|
||||||
const { page } = editor;
|
const { page } = editor;
|
||||||
page.awarenessStore.setReadonly(page, true);
|
page.awarenessStore.setReadonly(page, true);
|
||||||
|
|||||||
@@ -92,7 +92,15 @@ const AllPage: NextPageWithLayout = () => {
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{t('All Pages')} - AFFiNE</title>
|
<title>{t('All Pages')} - AFFiNE</title>
|
||||||
</Head>
|
</Head>
|
||||||
<WorkspaceTitle icon={<FolderIcon />}>{t('All pages')}</WorkspaceTitle>
|
<WorkspaceTitle
|
||||||
|
workspace={currentWorkspace}
|
||||||
|
currentPage={null}
|
||||||
|
isPreview={false}
|
||||||
|
isPublic={false}
|
||||||
|
icon={<FolderIcon />}
|
||||||
|
>
|
||||||
|
{t('All pages')}
|
||||||
|
</WorkspaceTitle>
|
||||||
<PageList
|
<PageList
|
||||||
onOpenPage={onClickPage}
|
onOpenPage={onClickPage}
|
||||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||||
@@ -106,7 +114,15 @@ const AllPage: NextPageWithLayout = () => {
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{t('All Pages')} - AFFiNE</title>
|
<title>{t('All Pages')} - AFFiNE</title>
|
||||||
</Head>
|
</Head>
|
||||||
<WorkspaceTitle icon={<FolderIcon />}>{t('All pages')}</WorkspaceTitle>
|
<WorkspaceTitle
|
||||||
|
workspace={currentWorkspace}
|
||||||
|
currentPage={null}
|
||||||
|
isPreview={false}
|
||||||
|
isPublic={false}
|
||||||
|
icon={<FolderIcon />}
|
||||||
|
>
|
||||||
|
{t('All pages')}
|
||||||
|
</WorkspaceTitle>
|
||||||
<PageList
|
<PageList
|
||||||
onOpenPage={onClickPage}
|
onOpenPage={onClickPage}
|
||||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||||
|
|||||||
@@ -41,7 +41,15 @@ const FavouritePage: NextPageWithLayout = () => {
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{t('Favorites')} - AFFiNE</title>
|
<title>{t('Favorites')} - AFFiNE</title>
|
||||||
</Head>
|
</Head>
|
||||||
<WorkspaceTitle icon={<FavoriteIcon />}>{t('Favorites')}</WorkspaceTitle>
|
<WorkspaceTitle
|
||||||
|
workspace={currentWorkspace}
|
||||||
|
currentPage={null}
|
||||||
|
isPreview={false}
|
||||||
|
isPublic={false}
|
||||||
|
icon={<FavoriteIcon />}
|
||||||
|
>
|
||||||
|
{t('Favorites')}
|
||||||
|
</WorkspaceTitle>
|
||||||
<PageList
|
<PageList
|
||||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
blockSuiteWorkspace={blockSuiteWorkspace}
|
||||||
onClickPage={onClickPage}
|
onClickPage={onClickPage}
|
||||||
|
|||||||
@@ -148,7 +148,13 @@ const SettingPage: NextPageWithLayout = () => {
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{t('Settings')} - AFFiNE</title>
|
<title>{t('Settings')} - AFFiNE</title>
|
||||||
</Head>
|
</Head>
|
||||||
<WorkspaceTitle icon={<SettingsIcon />}>
|
<WorkspaceTitle
|
||||||
|
workspace={currentWorkspace}
|
||||||
|
currentPage={null}
|
||||||
|
isPreview={false}
|
||||||
|
isPublic={false}
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
>
|
||||||
{t('Workspace Settings')}
|
{t('Workspace Settings')}
|
||||||
</WorkspaceTitle>
|
</WorkspaceTitle>
|
||||||
<Setting
|
<Setting
|
||||||
@@ -168,7 +174,13 @@ const SettingPage: NextPageWithLayout = () => {
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{t('Settings')} - AFFiNE</title>
|
<title>{t('Settings')} - AFFiNE</title>
|
||||||
</Head>
|
</Head>
|
||||||
<WorkspaceTitle icon={<SettingsIcon />}>
|
<WorkspaceTitle
|
||||||
|
workspace={currentWorkspace}
|
||||||
|
currentPage={null}
|
||||||
|
isPreview={false}
|
||||||
|
isPublic={false}
|
||||||
|
icon={<SettingsIcon />}
|
||||||
|
>
|
||||||
{t('Workspace Settings')}
|
{t('Workspace Settings')}
|
||||||
</WorkspaceTitle>
|
</WorkspaceTitle>
|
||||||
<Setting
|
<Setting
|
||||||
|
|||||||
@@ -44,7 +44,13 @@ const TrashPage: NextPageWithLayout = () => {
|
|||||||
<Head>
|
<Head>
|
||||||
<title>{t('Trash')} - AFFiNE</title>
|
<title>{t('Trash')} - AFFiNE</title>
|
||||||
</Head>
|
</Head>
|
||||||
<WorkspaceTitle icon={<DeleteTemporarilyIcon />}>
|
<WorkspaceTitle
|
||||||
|
workspace={currentWorkspace}
|
||||||
|
currentPage={null}
|
||||||
|
isPreview={false}
|
||||||
|
isPublic={false}
|
||||||
|
icon={<DeleteTemporarilyIcon />}
|
||||||
|
>
|
||||||
{t('Trash')}
|
{t('Trash')}
|
||||||
</WorkspaceTitle>
|
</WorkspaceTitle>
|
||||||
<PageList
|
<PageList
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ export const AffinePlugin: WorkspacePlugin<WorkspaceFlavour.AFFINE> = {
|
|||||||
<>
|
<>
|
||||||
<PageDetailEditor
|
<PageDetailEditor
|
||||||
pageId={currentPageId}
|
pageId={currentPageId}
|
||||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
workspace={currentWorkspace}
|
||||||
onInit={initPage}
|
onInit={initPage}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import type {
|
import type {
|
||||||
AppEvents,
|
AppEvents,
|
||||||
LoadPriority,
|
|
||||||
WorkspaceCRUD,
|
WorkspaceCRUD,
|
||||||
WorkspaceUISchema,
|
WorkspaceUISchema,
|
||||||
} from '@affine/workspace/type';
|
} from '@affine/workspace/type';
|
||||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
import { LoadPriority, WorkspaceFlavour } from '@affine/workspace/type';
|
||||||
|
|
||||||
import { AffinePlugin } from './affine';
|
import { AffinePlugin } from './affine';
|
||||||
import { LocalPlugin } from './local';
|
import { LocalPlugin } from './local';
|
||||||
@@ -19,9 +18,33 @@ export interface WorkspacePlugin<Flavour extends WorkspaceFlavour> {
|
|||||||
UI: WorkspaceUISchema<Flavour>;
|
UI: WorkspaceUISchema<Flavour>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unimplemented = () => {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
};
|
||||||
export const WorkspacePlugins = {
|
export const WorkspacePlugins = {
|
||||||
[WorkspaceFlavour.AFFINE]: AffinePlugin,
|
[WorkspaceFlavour.AFFINE]: AffinePlugin,
|
||||||
[WorkspaceFlavour.LOCAL]: LocalPlugin,
|
[WorkspaceFlavour.LOCAL]: LocalPlugin,
|
||||||
|
[WorkspaceFlavour.PUBLIC]: {
|
||||||
|
flavour: WorkspaceFlavour.PUBLIC,
|
||||||
|
loadPriority: LoadPriority.LOW,
|
||||||
|
Events: {
|
||||||
|
'app:first-init': async () => {},
|
||||||
|
},
|
||||||
|
// todo: implement this
|
||||||
|
CRUD: {
|
||||||
|
get: unimplemented,
|
||||||
|
list: unimplemented,
|
||||||
|
delete: unimplemented,
|
||||||
|
create: unimplemented,
|
||||||
|
},
|
||||||
|
// todo: implement this
|
||||||
|
UI: {
|
||||||
|
Provider: unimplemented,
|
||||||
|
PageDetail: unimplemented,
|
||||||
|
PageList: unimplemented,
|
||||||
|
SettingsDetail: unimplemented,
|
||||||
|
},
|
||||||
|
},
|
||||||
} satisfies {
|
} satisfies {
|
||||||
[Key in WorkspaceFlavour]: WorkspacePlugin<Key>;
|
[Key in WorkspaceFlavour]: WorkspacePlugin<Key>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const LocalPlugin: WorkspacePlugin<WorkspaceFlavour.LOCAL> = {
|
|||||||
<PageDetailEditor
|
<PageDetailEditor
|
||||||
pageId={currentPageId}
|
pageId={currentPageId}
|
||||||
onInit={initPage}
|
onInit={initPage}
|
||||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
workspace={currentWorkspace}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
||||||
|
import type { AffinePublicWorkspace } from '@affine/workspace/type';
|
||||||
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import type { ReactElement, ReactNode } from 'react';
|
import type { ReactElement, ReactNode } from 'react';
|
||||||
|
|
||||||
export { BlockSuiteWorkspace };
|
export { BlockSuiteWorkspace };
|
||||||
|
|
||||||
export type AffineOfficialWorkspace = AffineWorkspace | LocalWorkspace;
|
export type AffineOfficialWorkspace =
|
||||||
|
| AffineWorkspace
|
||||||
|
| LocalWorkspace
|
||||||
|
| AffinePublicWorkspace;
|
||||||
|
|
||||||
export type AllWorkspace = AffineOfficialWorkspace;
|
export type AllWorkspace = AffineOfficialWorkspace;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import type { AffineWorkspace, LocalWorkspace } from '@affine/workspace/type';
|
import type {
|
||||||
|
AffinePublicWorkspace,
|
||||||
|
AffineWorkspace,
|
||||||
|
LocalWorkspace,
|
||||||
|
} from '@affine/workspace/type';
|
||||||
import type { Workspace } from '@blocksuite/store';
|
import type { Workspace } from '@blocksuite/store';
|
||||||
import * as RadixAvatar from '@radix-ui/react-avatar';
|
import * as RadixAvatar from '@radix-ui/react-avatar';
|
||||||
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-blocksuite-workspace-avatar-url';
|
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-blocksuite-workspace-avatar-url';
|
||||||
@@ -31,7 +35,7 @@ function stringToColour(str: string) {
|
|||||||
|
|
||||||
export type WorkspaceAvatarProps = {
|
export type WorkspaceAvatarProps = {
|
||||||
size?: number;
|
size?: number;
|
||||||
workspace: LocalWorkspace | AffineWorkspace | null;
|
workspace: AffineWorkspace | LocalWorkspace | AffinePublicWorkspace | null;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ export interface LocalWorkspace {
|
|||||||
providers: Provider[];
|
providers: Provider[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AffinePublicWorkspace {
|
||||||
|
flavour: WorkspaceFlavour.PUBLIC;
|
||||||
|
id: string;
|
||||||
|
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||||
|
providers: Provider[];
|
||||||
|
}
|
||||||
|
|
||||||
export const enum LoadPriority {
|
export const enum LoadPriority {
|
||||||
HIGH = 1,
|
HIGH = 1,
|
||||||
MEDIUM = 2,
|
MEDIUM = 2,
|
||||||
@@ -63,6 +70,7 @@ export const enum LoadPriority {
|
|||||||
export const enum WorkspaceFlavour {
|
export const enum WorkspaceFlavour {
|
||||||
AFFINE = 'affine',
|
AFFINE = 'affine',
|
||||||
LOCAL = 'local',
|
LOCAL = 'local',
|
||||||
|
PUBLIC = 'affine-public',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const settingPanel = {
|
export const settingPanel = {
|
||||||
@@ -79,6 +87,7 @@ export type SettingPanel = (typeof settingPanel)[keyof typeof settingPanel];
|
|||||||
export interface WorkspaceRegistry {
|
export interface WorkspaceRegistry {
|
||||||
[WorkspaceFlavour.AFFINE]: AffineWorkspace;
|
[WorkspaceFlavour.AFFINE]: AffineWorkspace;
|
||||||
[WorkspaceFlavour.LOCAL]: LocalWorkspace;
|
[WorkspaceFlavour.LOCAL]: LocalWorkspace;
|
||||||
|
[WorkspaceFlavour.PUBLIC]: AffinePublicWorkspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WorkspaceCRUD<Flavour extends keyof WorkspaceRegistry> {
|
export interface WorkspaceCRUD<Flavour extends keyof WorkspaceRegistry> {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
import { test } from '../libs/playwright';
|
import { test } from '../libs/playwright';
|
||||||
import { assertCurrentWorkspaceFlavour } from '../libs/workspace';
|
import { assertCurrentWorkspaceFlavour } from '../libs/workspace';
|
||||||
|
|
||||||
test.describe('Local first favorite and cancel favorite page', () => {
|
test.describe('Local first favorite and cancel favorite page', () => {
|
||||||
test('New a page and open it ,then favorite it', async ({ page }) => {
|
test('New a page and open it ,then favorite it', async ({ page }) => {
|
||||||
await openHomePage(page);
|
await openHomePage(page);
|
||||||
await waitMarkdownImported(page);
|
await waitMarkdownImported(page);
|
||||||
|
|||||||
Reference in New Issue
Block a user