mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
refactor: move non-affine hooks (#1857)
This commit is contained in:
6
apps/web/src/hooks/affine/README.md
Normal file
6
apps/web/src/hooks/affine/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# AFFiNE Hooks
|
||||
|
||||
> This directory will be moved to `@affine/worksapce/affine/hooks` in the future.
|
||||
|
||||
Only put hooks in this directory if they are specific to AFFiNE, for example
|
||||
if they are using the AFFiNE API, or if the `AffineWorkspace` is required.
|
||||
@@ -1,74 +0,0 @@
|
||||
import { config } from '@affine/env';
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import {
|
||||
guideHiddenAtom,
|
||||
guideHiddenUntilNextUpdateAtom,
|
||||
lastVersionAtom,
|
||||
} from '../../atoms/first-load';
|
||||
|
||||
export function useLastVersion() {
|
||||
return useAtom(lastVersionAtom);
|
||||
}
|
||||
|
||||
export function useGuideHidden() {
|
||||
return useAtom(guideHiddenAtom);
|
||||
}
|
||||
|
||||
export function useGuideHiddenUntilNextUpdate() {
|
||||
return useAtom(guideHiddenUntilNextUpdateAtom);
|
||||
}
|
||||
|
||||
const TIPS = {
|
||||
quickSearchTips: true,
|
||||
changeLog: true,
|
||||
};
|
||||
|
||||
export function useTipsDisplayStatus() {
|
||||
const permanentlyHiddenTips = useAtomValue(guideHiddenAtom);
|
||||
const hiddenUntilNextUpdateTips = useAtomValue(
|
||||
guideHiddenUntilNextUpdateAtom
|
||||
);
|
||||
|
||||
return {
|
||||
quickSearchTips: {
|
||||
permanentlyHidden: permanentlyHiddenTips.quickSearchTips || true,
|
||||
hiddenUntilNextUpdate: hiddenUntilNextUpdateTips.quickSearchTips || true,
|
||||
},
|
||||
changeLog: {
|
||||
permanentlyHidden: permanentlyHiddenTips.changeLog || true,
|
||||
hiddenUntilNextUpdate: hiddenUntilNextUpdateTips.changeLog || true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function useUpdateTipsOnVersionChange() {
|
||||
const [lastVersion, setLastVersion] = useLastVersion();
|
||||
const currentVersion = config.gitVersion;
|
||||
const tipsDisplayStatus = useTipsDisplayStatus();
|
||||
const setPermanentlyHiddenTips = useSetAtom(guideHiddenAtom);
|
||||
const setHiddenUntilNextUpdateTips = useSetAtom(
|
||||
guideHiddenUntilNextUpdateAtom
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (lastVersion !== currentVersion) {
|
||||
setLastVersion(currentVersion);
|
||||
const newHiddenUntilNextUpdateTips = { ...TIPS };
|
||||
const newPermanentlyHiddenTips = { ...TIPS, changeLog: false };
|
||||
Object.keys(tipsDisplayStatus).forEach(tipKey => {
|
||||
newHiddenUntilNextUpdateTips[tipKey as keyof typeof TIPS] = false;
|
||||
});
|
||||
setHiddenUntilNextUpdateTips(newHiddenUntilNextUpdateTips);
|
||||
setPermanentlyHiddenTips(newPermanentlyHiddenTips);
|
||||
}
|
||||
}, [
|
||||
currentVersion,
|
||||
lastVersion,
|
||||
setLastVersion,
|
||||
setPermanentlyHiddenTips,
|
||||
setHiddenUntilNextUpdateTips,
|
||||
tipsDisplayStatus,
|
||||
]);
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import type { Node } from '@affine/component';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import type { MouseEvent } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { BlockSuiteWorkspace } from '../../shared';
|
||||
|
||||
export type RenderProps = {
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
onClick?: (e: MouseEvent<HTMLDivElement>, node: PinboardNode) => void;
|
||||
showOperationButton?: boolean;
|
||||
};
|
||||
|
||||
export type NodeRenderProps = RenderProps & {
|
||||
metas: PageMeta[];
|
||||
currentMeta: PageMeta;
|
||||
};
|
||||
|
||||
export type PinboardNode = Node<NodeRenderProps>;
|
||||
|
||||
function flattenToTree(
|
||||
metas: PageMeta[],
|
||||
pinboardRender: PinboardNode['render'],
|
||||
renderProps: RenderProps
|
||||
): PinboardNode[] {
|
||||
const rootMeta = metas.find(meta => meta.isRootPinboard);
|
||||
const helper = (internalMetas: PageMeta[]): PinboardNode[] => {
|
||||
return internalMetas.reduce<PinboardNode[]>(
|
||||
(returnedMetas, internalMeta) => {
|
||||
const { subpageIds = [] } = internalMeta;
|
||||
const childrenMetas = subpageIds
|
||||
.map(id => metas.find(m => m.id === id)!)
|
||||
.filter(m => m);
|
||||
// @ts-ignore
|
||||
const returnedMeta: PinboardNode = {
|
||||
...internalMeta,
|
||||
children: helper(childrenMetas),
|
||||
render: (node, props) =>
|
||||
pinboardRender(node, props, {
|
||||
...renderProps,
|
||||
currentMeta: internalMeta,
|
||||
metas,
|
||||
}),
|
||||
};
|
||||
returnedMetas.push(returnedMeta);
|
||||
return returnedMetas;
|
||||
},
|
||||
[]
|
||||
);
|
||||
};
|
||||
return helper(rootMeta ? [{ ...rootMeta, renderTopLine: false }] : []);
|
||||
}
|
||||
|
||||
export function usePinboardData({
|
||||
metas,
|
||||
pinboardRender,
|
||||
blockSuiteWorkspace,
|
||||
onClick,
|
||||
showOperationButton,
|
||||
}: {
|
||||
metas: PageMeta[];
|
||||
pinboardRender: PinboardNode['render'];
|
||||
} & RenderProps) {
|
||||
const data = useMemo(
|
||||
() =>
|
||||
flattenToTree(metas, pinboardRender, {
|
||||
blockSuiteWorkspace,
|
||||
onClick,
|
||||
showOperationButton,
|
||||
}),
|
||||
[blockSuiteWorkspace, metas, onClick, pinboardRender, showOperationButton]
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
export default usePinboardData;
|
||||
@@ -1,163 +0,0 @@
|
||||
import type { TreeViewProps } from '@affine/component';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import type { BlockSuiteWorkspace } from '../../shared';
|
||||
import { useBlockSuiteWorkspaceHelper } from '../use-blocksuite-workspace-helper';
|
||||
import { usePageMetaHelper } from '../use-page-meta';
|
||||
import type { NodeRenderProps, PinboardNode } from './use-pinboard-data';
|
||||
|
||||
const logger = new DebugLogger('pinboard');
|
||||
|
||||
function findRootIds(metas: PageMeta[], id: string): string[] {
|
||||
const parentMeta = metas.find(m => m.subpageIds?.includes(id));
|
||||
if (!parentMeta) {
|
||||
return [id];
|
||||
}
|
||||
return [parentMeta.id, ...findRootIds(metas, parentMeta.id)];
|
||||
}
|
||||
export function usePinboardHandler({
|
||||
blockSuiteWorkspace,
|
||||
metas,
|
||||
onAdd,
|
||||
onDelete,
|
||||
onDrop,
|
||||
}: {
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
metas: PageMeta[];
|
||||
onAdd?: (addedId: string, parentId: string) => void;
|
||||
onDelete?: TreeViewProps<NodeRenderProps>['onDelete'];
|
||||
onDrop?: TreeViewProps<NodeRenderProps>['onDrop'];
|
||||
}) {
|
||||
const { createPage } = useBlockSuiteWorkspaceHelper(blockSuiteWorkspace);
|
||||
const { getPageMeta, setPageMeta } = usePageMetaHelper(blockSuiteWorkspace);
|
||||
|
||||
const handleAdd = useCallback(
|
||||
(node: PinboardNode) => {
|
||||
const id = nanoid();
|
||||
createPage(id, node.id);
|
||||
onAdd?.(id, node.id);
|
||||
},
|
||||
[createPage, onAdd]
|
||||
);
|
||||
|
||||
const handleDelete = useCallback(
|
||||
(node: PinboardNode) => {
|
||||
const removeToTrash = (currentMeta: PageMeta) => {
|
||||
const { subpageIds = [] } = currentMeta;
|
||||
setPageMeta(currentMeta.id, {
|
||||
trash: true,
|
||||
trashDate: +new Date(),
|
||||
});
|
||||
subpageIds.forEach(id => {
|
||||
const subcurrentMeta = getPageMeta(id);
|
||||
subcurrentMeta && removeToTrash(subcurrentMeta);
|
||||
});
|
||||
};
|
||||
removeToTrash(metas.find(m => m.id === node.id)!);
|
||||
onDelete?.(node);
|
||||
},
|
||||
[metas, getPageMeta, onDelete, setPageMeta]
|
||||
);
|
||||
|
||||
const handleDrop = useCallback(
|
||||
(
|
||||
dragId: string,
|
||||
dropId: string,
|
||||
position: {
|
||||
topLine: boolean;
|
||||
bottomLine: boolean;
|
||||
internal: boolean;
|
||||
}
|
||||
) => {
|
||||
if (dragId === dropId) {
|
||||
return;
|
||||
}
|
||||
const dropRootIds = findRootIds(metas, dropId);
|
||||
if (dropRootIds.includes(dragId)) {
|
||||
return;
|
||||
}
|
||||
logger.info('handleDrop', {
|
||||
dragId,
|
||||
dropId,
|
||||
position,
|
||||
metas,
|
||||
});
|
||||
|
||||
const { topLine, bottomLine } = position;
|
||||
|
||||
const dragParentMeta = metas.find(meta =>
|
||||
meta.subpageIds?.includes(dragId)
|
||||
);
|
||||
if (bottomLine || topLine) {
|
||||
const insertOffset = bottomLine ? 1 : 0;
|
||||
|
||||
const dropParentMeta = metas.find(m => m.subpageIds?.includes(dropId));
|
||||
if (dropParentMeta?.id === dragParentMeta?.id) {
|
||||
// same parent
|
||||
const newSubpageIds = [...(dragParentMeta?.subpageIds ?? [])];
|
||||
const deleteIndex = newSubpageIds.findIndex(id => id === dragId);
|
||||
newSubpageIds.splice(deleteIndex, 1);
|
||||
const insertIndex =
|
||||
newSubpageIds.findIndex(id => id === dropId) + insertOffset;
|
||||
newSubpageIds.splice(insertIndex, 0, dragId);
|
||||
dragParentMeta &&
|
||||
setPageMeta(dragParentMeta.id, {
|
||||
subpageIds: newSubpageIds,
|
||||
});
|
||||
return onDrop?.(dragId, dropId, position);
|
||||
}
|
||||
const newDragParentSubpageIds = [...(dragParentMeta?.subpageIds ?? [])];
|
||||
const deleteIndex = newDragParentSubpageIds.findIndex(
|
||||
id => id === dragId
|
||||
);
|
||||
newDragParentSubpageIds.splice(deleteIndex, 1);
|
||||
|
||||
const newDropParentSubpageIds = [...(dropParentMeta?.subpageIds ?? [])];
|
||||
const insertIndex =
|
||||
newDropParentSubpageIds.findIndex(id => id === dropId) + insertOffset;
|
||||
newDropParentSubpageIds.splice(insertIndex, 0, dragId);
|
||||
dragParentMeta &&
|
||||
setPageMeta(dragParentMeta.id, {
|
||||
subpageIds: newDragParentSubpageIds,
|
||||
});
|
||||
dropParentMeta &&
|
||||
setPageMeta(dropParentMeta.id, {
|
||||
subpageIds: newDropParentSubpageIds,
|
||||
});
|
||||
return onDrop?.(dragId, dropId, position);
|
||||
}
|
||||
|
||||
// drop into the node
|
||||
if (dragParentMeta && dragParentMeta.id === dropId) {
|
||||
return;
|
||||
}
|
||||
if (dragParentMeta) {
|
||||
const metaIndex = dragParentMeta.subpageIds.findIndex(
|
||||
id => id === dragId
|
||||
);
|
||||
const newSubpageIds = [...dragParentMeta.subpageIds];
|
||||
newSubpageIds.splice(metaIndex, 1);
|
||||
setPageMeta(dragParentMeta.id, {
|
||||
subpageIds: newSubpageIds,
|
||||
});
|
||||
}
|
||||
const dropMeta = metas.find(meta => meta.id === dropId)!;
|
||||
const newSubpageIds = [dragId, ...(dropMeta.subpageIds ?? [])];
|
||||
setPageMeta(dropMeta.id, {
|
||||
subpageIds: newSubpageIds,
|
||||
});
|
||||
},
|
||||
[metas, onDrop, setPageMeta]
|
||||
);
|
||||
|
||||
return {
|
||||
handleDrop,
|
||||
handleAdd,
|
||||
handleDelete,
|
||||
};
|
||||
}
|
||||
|
||||
export default usePinboardHandler;
|
||||
@@ -1,43 +0,0 @@
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import type { NextRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import {
|
||||
workspacePreferredModeAtom,
|
||||
workspaceRecentViewsAtom,
|
||||
workspaceRecentViresWriteAtom,
|
||||
} from '../../atoms';
|
||||
import { useCurrentWorkspace } from '../current/use-current-workspace';
|
||||
import { usePageMeta } from '../use-page-meta';
|
||||
|
||||
export function useRecentlyViewed() {
|
||||
const [workspace] = useCurrentWorkspace();
|
||||
const workspaceId = workspace?.id || null;
|
||||
const recentlyViewed = useAtomValue(workspaceRecentViewsAtom);
|
||||
|
||||
if (!workspaceId) return [];
|
||||
return recentlyViewed[workspaceId] ?? [];
|
||||
}
|
||||
|
||||
export function useSyncRecentViewsWithRouter(router: NextRouter) {
|
||||
const [workspace] = useCurrentWorkspace();
|
||||
const workspaceId = workspace?.id || null;
|
||||
const blockSuiteWorkspace = workspace?.blockSuiteWorkspace || null;
|
||||
const pageId = router.query.pageId;
|
||||
const set = useSetAtom(workspaceRecentViresWriteAtom);
|
||||
const meta = usePageMeta(blockSuiteWorkspace).find(
|
||||
meta => meta.id === pageId
|
||||
);
|
||||
const currentMode = useAtomValue(workspacePreferredModeAtom)[
|
||||
pageId as string
|
||||
];
|
||||
useEffect(() => {
|
||||
if (!workspaceId) return;
|
||||
if (pageId && meta) {
|
||||
set(workspaceId, {
|
||||
id: pageId as string,
|
||||
mode: currentMode ?? 'page',
|
||||
});
|
||||
}
|
||||
}, [pageId, meta, workspaceId, set, currentMode]);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { atomWithSyncStorage } from '@affine/jotai';
|
||||
import { useMediaQuery, useTheme } from '@mui/material';
|
||||
import { atom, useAtom } from 'jotai';
|
||||
|
||||
const sideBarOpenAtom = atomWithSyncStorage('sidebarOpen', true);
|
||||
const sideBarWidthAtom = atomWithSyncStorage('sidebarWidth', 256);
|
||||
const sidebarResizingAtom = atom(false);
|
||||
|
||||
export function useSidebarStatus() {
|
||||
return useAtom(sideBarOpenAtom);
|
||||
}
|
||||
|
||||
export function useSidebarWidth() {
|
||||
return useAtom(sideBarWidthAtom);
|
||||
}
|
||||
|
||||
export function useSidebarFloating() {
|
||||
const theme = useTheme();
|
||||
return useMediaQuery(theme.breakpoints.down('md'));
|
||||
}
|
||||
|
||||
export function useSidebarResizing() {
|
||||
return useAtom(sidebarResizingAtom);
|
||||
}
|
||||
Reference in New Issue
Block a user