mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-21 20:16:26 +08:00
milestone: publish alpha version (#637)
- document folder - full-text search - blob storage - basic edgeless support Co-authored-by: tzhangchi <terry.zhangchi@outlook.com> Co-authored-by: QiShaoXuan <qishaoxuan777@gmail.com> Co-authored-by: DiamondThree <diamond.shx@gmail.com> Co-authored-by: MingLiang Wang <mingliangwang0o0@gmail.com> Co-authored-by: JimmFly <yangjinfei001@gmail.com> Co-authored-by: Yifeng Wang <doodlewind@toeverything.info> Co-authored-by: Himself65 <himself65@outlook.com> Co-authored-by: lawvs <18554747+lawvs@users.noreply.github.com> Co-authored-by: Qi <474021214@qq.com>
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import {
|
||||
useRef,
|
||||
useEffect,
|
||||
useState,
|
||||
ReactElement,
|
||||
PropsWithChildren,
|
||||
} from 'react';
|
||||
import { styled } from '@/styles';
|
||||
import { EditorHeader } from '@/components/header';
|
||||
import EdgelessToolbar from '@/components/edgeless-toolbar';
|
||||
import MobileModal from '@/components/mobile-modal';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-v2.0.md';
|
||||
import type { NextPageWithLayout } from '../..//_app';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
import { useRouter } from 'next/router';
|
||||
import { usePageHelper } from '@/hooks/use-page-helper';
|
||||
const StyledEditorContainer = styled('div')(() => {
|
||||
return {
|
||||
height: 'calc(100vh - 60px)',
|
||||
};
|
||||
});
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const editorContainer = useRef<HTMLDivElement>(null);
|
||||
const { createEditor, setEditor, currentPage, currentWorkspace } =
|
||||
useAppState();
|
||||
|
||||
useEffect(() => {
|
||||
const ret = () => {
|
||||
const node = editorContainer.current;
|
||||
while (node?.firstChild) {
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
const editor = createEditor?.current?.(currentPage!);
|
||||
if (editor) {
|
||||
editorContainer.current?.appendChild(editor);
|
||||
setEditor?.current?.(editor);
|
||||
if (currentPage!.isEmpty) {
|
||||
const isFirstPage = currentWorkspace?.meta.pageMetas.length === 1;
|
||||
// Can not use useCurrentPageMeta to get new title, cause meta title will trigger rerender, but the second time can not remove title
|
||||
const { title: metaTitle } = currentPage!.meta;
|
||||
const title = metaTitle
|
||||
? metaTitle
|
||||
: isFirstPage
|
||||
? 'Welcome to AFFiNE Alpha "Abbey Wood"'
|
||||
: '';
|
||||
currentWorkspace?.setPageMeta(currentPage!.id, { title });
|
||||
|
||||
const pageId = currentPage!.addBlock({
|
||||
flavour: 'affine:page',
|
||||
title,
|
||||
});
|
||||
const groupId = currentPage!.addBlock(
|
||||
{ flavour: 'affine:group' },
|
||||
pageId
|
||||
);
|
||||
currentPage!.addBlock({ flavour: 'affine:group' }, pageId);
|
||||
// If this is a first page in workspace, init an introduction markdown
|
||||
if (isFirstPage) {
|
||||
editor.clipboard.importMarkdown(exampleMarkdown, `${groupId}`);
|
||||
currentWorkspace!.setPageMeta(currentPage!.id, { title });
|
||||
}
|
||||
currentPage!.resetHistory();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}, [currentWorkspace, currentPage, createEditor, setEditor]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EditorHeader />
|
||||
<MobileModal />
|
||||
<StyledEditorContainer ref={editorContainer} />
|
||||
<EdgelessToolbar />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const PageDefender = ({ children }: PropsWithChildren) => {
|
||||
const router = useRouter();
|
||||
const [pageLoaded, setPageLoaded] = useState(false);
|
||||
const { currentWorkspace, loadPage } = useAppState();
|
||||
const { createPage } = usePageHelper();
|
||||
|
||||
useEffect(() => {
|
||||
const initPage = async () => {
|
||||
const pageId = router.query.pageId as string;
|
||||
const isPageExist = !!currentWorkspace!.meta.pageMetas.find(
|
||||
p => p.id === pageId
|
||||
);
|
||||
if (!isPageExist) {
|
||||
await createPage({ pageId });
|
||||
}
|
||||
await loadPage(pageId);
|
||||
setPageLoaded(true);
|
||||
};
|
||||
initPage();
|
||||
}, [createPage, currentWorkspace, loadPage, router.query.pageId]);
|
||||
|
||||
return <>{pageLoaded ? children : null}</>;
|
||||
};
|
||||
|
||||
Page.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<WorkspaceLayout>
|
||||
<PageDefender>{page}</PageDefender>
|
||||
</WorkspaceLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { PageList } from '@/components/page-list';
|
||||
import { AllPagesIcon } from '@blocksuite/icons';
|
||||
import usePageMetaList from '@/hooks/use-page-meta-list';
|
||||
import { PageListHeader } from '@/components/header';
|
||||
import { ReactElement } from 'react';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
|
||||
const All = () => {
|
||||
const pageMetaList = usePageMetaList();
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageListHeader icon={<AllPagesIcon />}>All Page</PageListHeader>
|
||||
<PageList
|
||||
pageList={pageMetaList.filter(p => !p.trash)}
|
||||
showFavoriteTag={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
All.getLayout = function getLayout(page: ReactElement) {
|
||||
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
||||
};
|
||||
|
||||
export default All;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { PageListHeader } from '@/components/header';
|
||||
import { PageList } from '@/components/page-list';
|
||||
import { FavouritesIcon } from '@blocksuite/icons';
|
||||
import usePageMetaList from '@/hooks/use-page-meta-list';
|
||||
import { ReactElement } from 'react';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
|
||||
export const Favorite = () => {
|
||||
const pageMetaList = usePageMetaList();
|
||||
return (
|
||||
<>
|
||||
<PageListHeader icon={<FavouritesIcon />}>Favourites</PageListHeader>
|
||||
<PageList pageList={pageMetaList.filter(p => p.favorite && !p.trash)} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
Favorite.getLayout = function getLayout(page: ReactElement) {
|
||||
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
||||
};
|
||||
export default Favorite;
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider/context';
|
||||
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
|
||||
import { PageLoading } from '@/components/loading';
|
||||
import usePageHelper from '@/hooks/use-page-helper';
|
||||
|
||||
const WorkspaceIndex = () => {
|
||||
const router = useRouter();
|
||||
const { currentWorkspaceId, currentWorkspace } = useAppState();
|
||||
const { createPage } = usePageHelper();
|
||||
const { workspaceLoaded } = useEnsureWorkspace();
|
||||
|
||||
useEffect(() => {
|
||||
const initPage = async () => {
|
||||
if (!workspaceLoaded) {
|
||||
return;
|
||||
}
|
||||
const savedPageId = currentWorkspace?.meta.pageMetas[0]?.id;
|
||||
if (savedPageId) {
|
||||
router.replace(`/workspace/${currentWorkspaceId}/${savedPageId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const pageId = await createPage();
|
||||
router.replace(`/workspace/${currentWorkspaceId}/${pageId}`);
|
||||
};
|
||||
initPage();
|
||||
}, [
|
||||
currentWorkspace,
|
||||
currentWorkspaceId,
|
||||
createPage,
|
||||
router,
|
||||
workspaceLoaded,
|
||||
]);
|
||||
|
||||
return <PageLoading />;
|
||||
};
|
||||
|
||||
export default WorkspaceIndex;
|
||||
@@ -0,0 +1,22 @@
|
||||
import { PageListHeader } from '@/components/header';
|
||||
import { PageList } from '@/components/page-list';
|
||||
import { TrashIcon } from '@blocksuite/icons';
|
||||
import usePageMetaList from '@/hooks/use-page-meta-list';
|
||||
import { ReactElement } from 'react';
|
||||
import WorkspaceLayout from '@/components/workspace-layout';
|
||||
|
||||
export const Trash = () => {
|
||||
const pageMetaList = usePageMetaList();
|
||||
return (
|
||||
<>
|
||||
<PageListHeader icon={<TrashIcon />}>Trash</PageListHeader>
|
||||
<PageList pageList={pageMetaList.filter(p => p.trash)} isTrash={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Trash.getLayout = function getLayout(page: ReactElement) {
|
||||
return <WorkspaceLayout>{page}</WorkspaceLayout>;
|
||||
};
|
||||
|
||||
export default Trash;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useAppState } from '@/providers/app-state-provider';
|
||||
import useEnsureWorkspace from '@/hooks/use-ensure-workspace';
|
||||
import { PageLoading } from '@/components/loading';
|
||||
|
||||
export const WorkspaceIndex = () => {
|
||||
const router = useRouter();
|
||||
const { currentWorkspaceId } = useAppState();
|
||||
const { workspaceLoaded } = useEnsureWorkspace();
|
||||
|
||||
useEffect(() => {
|
||||
if (workspaceLoaded) {
|
||||
router.push(`/workspace/${currentWorkspaceId}`);
|
||||
}
|
||||
}, [currentWorkspaceId, router, workspaceLoaded]);
|
||||
|
||||
return <PageLoading />;
|
||||
};
|
||||
|
||||
export default WorkspaceIndex;
|
||||
Reference in New Issue
Block a user