mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-22 20:41:50 +08:00
refactor!: remove next.js (#3267)
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { Button, displayFlex, styled } from '@affine/component';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
import { useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||
|
||||
export const StyledContainer = styled('div')(() => {
|
||||
return {
|
||||
...displayFlex('center', 'center'),
|
||||
flexDirection: 'column',
|
||||
height: '100vh',
|
||||
|
||||
img: {
|
||||
width: '360px',
|
||||
height: '270px',
|
||||
},
|
||||
p: {
|
||||
fontSize: '22px',
|
||||
fontWeight: 600,
|
||||
margin: '24px 0',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const NotfoundPage = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const { jumpToSubPath, jumpToIndex } = useNavigateHelper();
|
||||
return (
|
||||
<StyledContainer data-testid="notFound">
|
||||
<img alt="404" src="/imgs/invite-error.svg" width={360} height={270} />
|
||||
|
||||
<p>{t['404 - Page Not Found']()}</p>
|
||||
<Button
|
||||
shape="round"
|
||||
onClick={() => {
|
||||
const id = localStorage.getItem('last_workspace_id');
|
||||
if (id) {
|
||||
jumpToSubPath(id, WorkspaceSubPath.ALL);
|
||||
} else {
|
||||
jumpToIndex();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t['Back Home']()}
|
||||
</Button>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const Component = (): ReactElement => {
|
||||
return <NotfoundPage></NotfoundPage>;
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { WorkspaceSubPath, WorkspaceVersion } from '@affine/env/workspace';
|
||||
import {
|
||||
type RootWorkspaceMetadataV2,
|
||||
rootWorkspacesMetadataAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import { getWorkspace } from '@toeverything/plugin-infra/__internal__/workspace';
|
||||
import { rootStore } from '@toeverything/plugin-infra/manager';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { lazy, useEffect, useRef } from 'react';
|
||||
|
||||
import { WorkspaceAdapters } from '../adapters/workspace';
|
||||
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||
import { useWorkspace } from '../hooks/use-workspace';
|
||||
|
||||
const AllWorkspaceModals = lazy(() =>
|
||||
import('../providers/modal-provider').then(({ AllWorkspaceModals }) => ({
|
||||
default: AllWorkspaceModals,
|
||||
}))
|
||||
);
|
||||
|
||||
type WorkspaceLoaderProps = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const createFirst = (): RootWorkspaceMetadataV2[] => {
|
||||
const Plugins = Object.values(WorkspaceAdapters).sort(
|
||||
(a, b) => a.loadPriority - b.loadPriority
|
||||
);
|
||||
|
||||
return Plugins.flatMap(Plugin => {
|
||||
return Plugin.Events['app:init']?.().map(
|
||||
id =>
|
||||
({
|
||||
id,
|
||||
flavour: Plugin.flavour,
|
||||
// new workspace should all support sub-doc feature
|
||||
version: WorkspaceVersion.SubDoc,
|
||||
}) satisfies RootWorkspaceMetadataV2
|
||||
);
|
||||
}).filter((ids): ids is RootWorkspaceMetadataV2 => !!ids);
|
||||
};
|
||||
|
||||
rootStore
|
||||
.get(rootWorkspacesMetadataAtom)
|
||||
.then(meta => {
|
||||
if (meta.length === 0 && localStorage.getItem('is-first-open') === null) {
|
||||
const result = createFirst();
|
||||
console.info('create first workspace', result);
|
||||
localStorage.setItem('is-first-open', 'false');
|
||||
rootStore.set(rootWorkspacesMetadataAtom, result).catch(console.error);
|
||||
}
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
const WorkspaceLoader = (props: WorkspaceLoaderProps): null => {
|
||||
useWorkspace(props.id);
|
||||
return null;
|
||||
};
|
||||
|
||||
const logger = new DebugLogger('index-page');
|
||||
|
||||
export const Component = () => {
|
||||
const meta = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const navigateHelper = useNavigateHelper();
|
||||
const jumpOnceRef = useRef(false);
|
||||
useEffect(() => {
|
||||
if (jumpOnceRef.current) {
|
||||
return;
|
||||
}
|
||||
const lastId = localStorage.getItem('last_workspace_id');
|
||||
const lastPageId = localStorage.getItem('last_page_id');
|
||||
const target =
|
||||
(lastId && meta.find(({ id }) => id === lastId)) || meta.at(0);
|
||||
if (target) {
|
||||
const targetWorkspace = getWorkspace(target.id);
|
||||
const nonTrashPages = targetWorkspace.meta.pageMetas.filter(
|
||||
({ trash }) => !trash
|
||||
);
|
||||
const pageId =
|
||||
nonTrashPages.find(({ id }) => id === lastPageId)?.id ??
|
||||
nonTrashPages.at(0)?.id;
|
||||
if (pageId) {
|
||||
logger.debug('Found target workspace. Jump to page', pageId);
|
||||
navigateHelper.jumpToPage(
|
||||
targetWorkspace.id,
|
||||
pageId,
|
||||
RouteLogic.REPLACE
|
||||
);
|
||||
jumpOnceRef.current = true;
|
||||
} else {
|
||||
const clearId = setTimeout(() => {
|
||||
dispose.dispose();
|
||||
logger.debug('Found target workspace. Jump to all pages');
|
||||
navigateHelper.jumpToSubPath(
|
||||
targetWorkspace.id,
|
||||
WorkspaceSubPath.ALL,
|
||||
RouteLogic.REPLACE
|
||||
);
|
||||
jumpOnceRef.current = true;
|
||||
}, 1000);
|
||||
const dispose = targetWorkspace.slots.pageAdded.once(pageId => {
|
||||
clearTimeout(clearId);
|
||||
navigateHelper.jumpToPage(
|
||||
targetWorkspace.id,
|
||||
pageId,
|
||||
RouteLogic.REPLACE
|
||||
);
|
||||
jumpOnceRef.current = true;
|
||||
});
|
||||
return () => {
|
||||
clearTimeout(clearId);
|
||||
dispose.dispose();
|
||||
jumpOnceRef.current = false;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
console.warn('No workspace found');
|
||||
}
|
||||
return;
|
||||
}, [meta, navigateHelper]);
|
||||
return (
|
||||
<>
|
||||
{meta.map(({ id }) => (
|
||||
<WorkspaceLoader id={id} key={id} />
|
||||
))}
|
||||
<AllWorkspaceModals />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import { useCollectionManager } from '@affine/component/page-list';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { getUIAdapter } from '../../adapters/workspace';
|
||||
import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace';
|
||||
import { useNavigateHelper } from '../../hooks/use-navigate-helper';
|
||||
import { WorkspaceLayout } from '../../layouts/workspace-layout';
|
||||
|
||||
const AllPage = () => {
|
||||
const { jumpToPage } = useNavigateHelper();
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const setting = useCollectionManager(currentWorkspace.id);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
assertExists(currentWorkspace);
|
||||
if (newTab) {
|
||||
window.open(`/workspace/${currentWorkspace?.id}/${pageId}`, '_blank');
|
||||
} else {
|
||||
jumpToPage(currentWorkspace.id, pageId);
|
||||
}
|
||||
},
|
||||
[currentWorkspace, jumpToPage]
|
||||
);
|
||||
const { PageList, Header } = getUIAdapter(currentWorkspace.flavour);
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
currentWorkspaceId={currentWorkspace.id}
|
||||
currentEntry={{
|
||||
subPath: WorkspaceSubPath.ALL,
|
||||
}}
|
||||
/>
|
||||
<PageList
|
||||
collection={setting.currentCollection}
|
||||
onOpenPage={onClickPage}
|
||||
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
return (
|
||||
<WorkspaceLayout>
|
||||
<AllPage />
|
||||
</WorkspaceLayout>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
import { PageDetailSkeleton } from '@affine/component/page-detail-skeleton';
|
||||
import {
|
||||
createTagFilter,
|
||||
useCollectionManager,
|
||||
} from '@affine/component/page-list';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { currentPageIdAtom } from '@toeverything/plugin-infra/manager';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useAtom } from 'jotai/react';
|
||||
import { type ReactElement, useCallback, useEffect } from 'react';
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { getUIAdapter } from '../../adapters/workspace';
|
||||
import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace';
|
||||
import { useNavigateHelper } from '../../hooks/use-navigate-helper';
|
||||
import { WorkspaceLayout } from '../../layouts/workspace-layout';
|
||||
|
||||
const WorkspaceDetailPageImpl = (): ReactElement => {
|
||||
const { openPage, jumpToSubPath } = useNavigateHelper();
|
||||
const currentPageId = useAtomValue(currentPageIdAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
assertExists(currentWorkspace);
|
||||
assertExists(currentPageId);
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
const collectionManager = useCollectionManager(currentWorkspace.id);
|
||||
const onLoad = useCallback(
|
||||
(page: Page, editor: EditorContainer) => {
|
||||
const dispose = editor.slots.pageLinkClicked.on(({ pageId }) => {
|
||||
return openPage(blockSuiteWorkspace.id, pageId);
|
||||
});
|
||||
const disposeTagClick = editor.slots.tagClicked.on(async ({ tagId }) => {
|
||||
await jumpToSubPath(currentWorkspace.id, WorkspaceSubPath.ALL);
|
||||
collectionManager.backToAll();
|
||||
collectionManager.setTemporaryFilter([createTagFilter(tagId)]);
|
||||
});
|
||||
return () => {
|
||||
dispose.dispose();
|
||||
disposeTagClick.dispose();
|
||||
};
|
||||
},
|
||||
[
|
||||
blockSuiteWorkspace.id,
|
||||
collectionManager,
|
||||
currentWorkspace.id,
|
||||
jumpToSubPath,
|
||||
openPage,
|
||||
]
|
||||
);
|
||||
|
||||
const { PageDetail, Header } = getUIAdapter(currentWorkspace.flavour);
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
currentWorkspaceId={currentWorkspace.id}
|
||||
currentEntry={{
|
||||
pageId: currentPageId,
|
||||
}}
|
||||
/>
|
||||
<PageDetail
|
||||
currentWorkspaceId={currentWorkspace.id}
|
||||
currentPageId={currentPageId}
|
||||
onLoadEditor={onLoad}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const WorkspaceDetailPage = (): ReactElement => {
|
||||
const { workspaceId, pageId } = useParams();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const [currentPageId, setCurrentPageId] = useAtom(currentPageIdAtom);
|
||||
const page = currentPageId
|
||||
? currentWorkspace.blockSuiteWorkspace.getPage(currentPageId)
|
||||
: null;
|
||||
|
||||
//#region check if page is valid
|
||||
useEffect(() => {
|
||||
// if the workspace changed, ignore the page check
|
||||
if (currentWorkspace.id !== workspaceId) {
|
||||
return;
|
||||
}
|
||||
if (typeof pageId === 'string' && currentPageId) {
|
||||
if (currentPageId !== pageId) {
|
||||
setCurrentPageId(pageId);
|
||||
} else {
|
||||
const page =
|
||||
currentWorkspace.blockSuiteWorkspace.getPage(currentPageId);
|
||||
if (!page) {
|
||||
navigate('/404');
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
currentPageId,
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
currentWorkspace.id,
|
||||
location.pathname,
|
||||
navigate,
|
||||
pageId,
|
||||
setCurrentPageId,
|
||||
workspaceId,
|
||||
]);
|
||||
//#endregion
|
||||
|
||||
if (!currentPageId || !page) {
|
||||
return <PageDetailSkeleton key="current-page-is-null" />;
|
||||
}
|
||||
return <WorkspaceDetailPageImpl />;
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
return (
|
||||
<WorkspaceLayout>
|
||||
<WorkspaceDetailPage />
|
||||
</WorkspaceLayout>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { getUIAdapter } from '../../adapters/workspace';
|
||||
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
|
||||
import { useCurrentWorkspace } from '../../hooks/current/use-current-workspace';
|
||||
import { useNavigateHelper } from '../../hooks/use-navigate-helper';
|
||||
import { WorkspaceLayout } from '../../layouts/workspace-layout';
|
||||
|
||||
const TrashPage = () => {
|
||||
const { jumpToPage } = useNavigateHelper();
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
assertExists(currentWorkspace);
|
||||
if (newTab) {
|
||||
window.open(`/workspace/${currentWorkspace?.id}/${pageId}`, '_blank');
|
||||
} else {
|
||||
jumpToPage(currentWorkspace.id, pageId);
|
||||
}
|
||||
},
|
||||
[currentWorkspace, jumpToPage]
|
||||
);
|
||||
// todo(himself65): refactor to plugin
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
assertExists(blockSuiteWorkspace);
|
||||
const { Header } = getUIAdapter(currentWorkspace.flavour);
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
currentWorkspaceId={currentWorkspace.id}
|
||||
currentEntry={{
|
||||
subPath: WorkspaceSubPath.TRASH,
|
||||
}}
|
||||
/>
|
||||
<BlockSuitePageList
|
||||
blockSuiteWorkspace={blockSuiteWorkspace}
|
||||
onOpenPage={onClickPage}
|
||||
listType="trash"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
return (
|
||||
<WorkspaceLayout>
|
||||
<TrashPage />
|
||||
</WorkspaceLayout>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user