mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-22 19:11:32 +03:00
refactor(core): remove outline plugin and layout atom (#5326)
@affine/outline is no longer used, this PR deletes this plugin and deletes the code that is no longer used
This commit is contained in:
parent
a10aeca820
commit
05025bf59a
@ -126,7 +126,6 @@ If you have questions, you are welcome to contact us. One of the best places to
|
||||
| ---------------------------------------------------------------- | ----------------------------------------- | ------ |
|
||||
| [@affine/copilot-plugin](./packages/plugins/copilot) | AI Copilot that help you document writing | 🚧 |
|
||||
| [@affine/image-preview-plugin](./packages/plugins/image-preview) | Component for previewing an image | ✅ |
|
||||
| [@affine/outline](./packages/plugins/outline) | Outline for your document | ✅ |
|
||||
|
||||
## Upstreams
|
||||
|
||||
|
@ -36,7 +36,6 @@ export const pluginPackageJson = atom<
|
||||
|
||||
export const enabledPluginAtom = atomWithStorage('affine-enabled-plugin', [
|
||||
'@affine/image-preview-plugin',
|
||||
'@affine/outline-plugin',
|
||||
]);
|
||||
|
||||
export const pluginHeaderItemAtom = atom<
|
||||
|
@ -2,7 +2,6 @@ import { atom } from 'jotai';
|
||||
|
||||
export const loadedPluginNameAtom = atom<string[]>([]);
|
||||
|
||||
export * from './layout';
|
||||
export * from './root-store';
|
||||
export * from './settings';
|
||||
export * from './workspace';
|
||||
|
@ -1,34 +0,0 @@
|
||||
import type { ExpectedLayout } from '@affine/sdk/entry';
|
||||
import { atom } from 'jotai';
|
||||
|
||||
const contentLayoutBaseAtom = atom<ExpectedLayout>('editor');
|
||||
|
||||
type SetStateAction<Value> = Value | ((prev: Value) => Value);
|
||||
export const contentLayoutAtom = atom<
|
||||
ExpectedLayout,
|
||||
[SetStateAction<ExpectedLayout>],
|
||||
void
|
||||
>(
|
||||
get => get(contentLayoutBaseAtom),
|
||||
(_, set, layout) => {
|
||||
set(contentLayoutBaseAtom, prev => {
|
||||
let setV: (prev: ExpectedLayout) => ExpectedLayout;
|
||||
if (typeof layout !== 'function') {
|
||||
setV = () => layout;
|
||||
} else {
|
||||
setV = layout;
|
||||
}
|
||||
const nextValue = setV(prev);
|
||||
if (nextValue === 'editor') {
|
||||
return nextValue;
|
||||
}
|
||||
if (nextValue.first !== 'editor') {
|
||||
throw new Error('The first element of the layout should be editor.');
|
||||
}
|
||||
if (nextValue.splitPercentage && nextValue.splitPercentage < 70) {
|
||||
throw new Error('The split percentage should be greater than 70.');
|
||||
}
|
||||
return nextValue;
|
||||
});
|
||||
}
|
||||
);
|
@ -1,6 +1,4 @@
|
||||
import type { ExpectedLayout } from '@affine/sdk/entry';
|
||||
import type Buffer from 'buffer';
|
||||
import type { WritableAtom } from 'jotai';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { AppConfigSchema } from './app-config-storage.js';
|
||||
@ -33,14 +31,6 @@ export const packageJsonOutputSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
type SetStateAction<Value> = Value | ((prev: Value) => Value);
|
||||
|
||||
export type ContentLayoutAtom = WritableAtom<
|
||||
ExpectedLayout,
|
||||
[SetStateAction<ExpectedLayout>],
|
||||
void
|
||||
>;
|
||||
|
||||
export abstract class HandlerManager<
|
||||
Namespace extends string,
|
||||
Handlers extends Record<string, PrimitiveHandlers>,
|
||||
|
@ -63,7 +63,6 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
'/plugins/hello-world',
|
||||
'/plugins/image-preview',
|
||||
'/plugins/vue-hello-world',
|
||||
'/plugins/outline',
|
||||
],
|
||||
enableTestProperties: true,
|
||||
enableBroadcastChannelProvider: true,
|
||||
@ -105,7 +104,6 @@ export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
'/plugins/hello-world',
|
||||
'/plugins/image-preview',
|
||||
'/plugins/vue-hello-world',
|
||||
'/plugins/outline',
|
||||
],
|
||||
enablePlugin: process.env.ENABLE_PLUGIN
|
||||
? process.env.ENABLE_PLUGIN === 'true'
|
||||
|
@ -1,10 +1,5 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import type {
|
||||
CallbackMap,
|
||||
ExpectedLayout,
|
||||
LayoutNode,
|
||||
PluginContext,
|
||||
} from '@affine/sdk/entry';
|
||||
import type { CallbackMap, PluginContext } from '@affine/sdk/entry';
|
||||
import { AffineFormatBarWidget } from '@blocksuite/blocks';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import {
|
||||
@ -12,10 +7,7 @@ import {
|
||||
pluginEditorAtom,
|
||||
pluginHeaderItemAtom,
|
||||
pluginSettingAtom,
|
||||
pluginWindowAtom,
|
||||
} from '@toeverything/infra/__internal__/plugin';
|
||||
import { contentLayoutAtom, currentPageIdAtom } from '@toeverything/infra/atom';
|
||||
import { atom } from 'jotai';
|
||||
import { Provider } from 'jotai/react';
|
||||
import type { createStore } from 'jotai/vanilla';
|
||||
import { createElement, type PropsWithChildren } from 'react';
|
||||
@ -31,83 +23,6 @@ const permissionLogger = new DebugLogger('plugins:permission');
|
||||
const importLogger = new DebugLogger('plugins:import');
|
||||
const entryLogger = new DebugLogger('plugins:entry');
|
||||
|
||||
const pushLayoutAtom = atom<
|
||||
null,
|
||||
// fixme: check plugin name here
|
||||
[
|
||||
pluginName: string,
|
||||
create: (root: HTMLElement) => () => void,
|
||||
options:
|
||||
| {
|
||||
maxWidth: (number | undefined)[];
|
||||
}
|
||||
| undefined,
|
||||
],
|
||||
void
|
||||
>(null, (_, set, pluginName, callback, options) => {
|
||||
set(pluginWindowAtom, items => ({
|
||||
...items,
|
||||
[pluginName]: callback,
|
||||
}));
|
||||
set(contentLayoutAtom, layout => {
|
||||
if (layout === 'editor') {
|
||||
return {
|
||||
direction: 'horizontal',
|
||||
first: 'editor',
|
||||
second: pluginName,
|
||||
splitPercentage: 70,
|
||||
maxWidth: options?.maxWidth,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
direction: 'horizontal',
|
||||
first: 'editor',
|
||||
splitPercentage: 70,
|
||||
second: {
|
||||
direction: 'horizontal',
|
||||
first: pluginName,
|
||||
second: layout.second,
|
||||
splitPercentage: 50,
|
||||
},
|
||||
} satisfies ExpectedLayout;
|
||||
}
|
||||
});
|
||||
addCleanup(pluginName, () => {
|
||||
set(deleteLayoutAtom, pluginName);
|
||||
});
|
||||
});
|
||||
|
||||
const deleteLayoutAtom = atom<null, [string], void>(null, (_, set, id) => {
|
||||
set(pluginWindowAtom, items => {
|
||||
const newItems = { ...items };
|
||||
delete newItems[id];
|
||||
return newItems;
|
||||
});
|
||||
const removeLayout = (layout: LayoutNode): LayoutNode | string => {
|
||||
if (typeof layout === 'string') {
|
||||
return layout;
|
||||
}
|
||||
if (layout.first === id) {
|
||||
return layout.second;
|
||||
} else if (layout.second === id) {
|
||||
return layout.first;
|
||||
} else {
|
||||
return {
|
||||
...layout,
|
||||
second: removeLayout(layout.second),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
set(contentLayoutAtom, layout => {
|
||||
if (layout === 'editor') {
|
||||
return 'editor';
|
||||
} else {
|
||||
return removeLayout(layout) as ExpectedLayout;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const setupWeakMap = new WeakMap<
|
||||
ReturnType<typeof createStore>,
|
||||
ReturnType<typeof createSetupImpl>
|
||||
@ -124,11 +39,6 @@ export function createSetup(rootStore: ReturnType<typeof createStore>) {
|
||||
}
|
||||
|
||||
function createSetupImpl(rootStore: ReturnType<typeof createStore>) {
|
||||
// clean up plugin windows when switching to other pages
|
||||
rootStore.sub(currentPageIdAtom, () => {
|
||||
rootStore.set(contentLayoutAtom, 'editor');
|
||||
});
|
||||
|
||||
// module -> importName -> updater[]
|
||||
const _rootImportsMap = new Map<string, Map<string, any>>();
|
||||
const rootImportsMapSetupPromise = setupImportsMap(_rootImportsMap, {
|
||||
@ -145,9 +55,6 @@ function createSetupImpl(rootStore: ReturnType<typeof createStore>) {
|
||||
'@blocksuite/inline': import('@blocksuite/inline'),
|
||||
'@affine/sdk/entry': {
|
||||
rootStore,
|
||||
currentPageIdAtom: currentPageIdAtom,
|
||||
pushLayoutAtom: pushLayoutAtom,
|
||||
deleteLayoutAtom: deleteLayoutAtom,
|
||||
},
|
||||
'@blocksuite/global/utils': import('@blocksuite/global/utils'),
|
||||
'@toeverything/infra/atom': import('@toeverything/infra/atom'),
|
||||
|
@ -28,7 +28,6 @@
|
||||
"@affine/hello-world-plugin": "workspace:*",
|
||||
"@affine/image-preview-plugin": "workspace:*",
|
||||
"@affine/native": "workspace:*",
|
||||
"@affine/outline-plugin": "workspace:*",
|
||||
"@affine/sdk": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@affine/vue-hello-world-plugin": "workspace:*",
|
||||
|
@ -1,28 +0,0 @@
|
||||
{
|
||||
"name": "@affine/outline-plugin",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"description": "Outline plugin",
|
||||
"version": "0.11.0",
|
||||
"scripts": {
|
||||
"dev": "af dev",
|
||||
"build": "af build"
|
||||
},
|
||||
"affinePlugin": {
|
||||
"release": "development",
|
||||
"entry": {
|
||||
"core": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
"@affine/sdk": "workspace:*",
|
||||
"@blocksuite/icons": "2.1.36"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@affine/plugin-cli": "workspace:*",
|
||||
"jotai": "^2.5.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"name": "@affine/outline-plugin",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"namedInputs": {
|
||||
"default": [
|
||||
"{projectRoot}/**/*",
|
||||
"{workspaceRoot}/tools/plugin-cli/src/**/*",
|
||||
"sharedGlobals"
|
||||
]
|
||||
},
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "nx:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
},
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": ["default"],
|
||||
"outputs": [
|
||||
"{workspaceRoot}/packages/frontend/core/public/plugins/outline",
|
||||
"{workspaceRoot}/packages/frontend/electron/dist/plugins/outline"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tags": ["plugin"]
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
import { IconButton } from '@affine/component/ui/button';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import {
|
||||
currentPageIdAtom,
|
||||
currentWorkspaceAtom,
|
||||
deleteLayoutAtom,
|
||||
pushLayoutAtom,
|
||||
} from '@affine/sdk/entry';
|
||||
import { TOCNotesPanel } from '@blocksuite/blocks';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { RightSidebarIcon } from '@blocksuite/icons';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import type { ComponentType, PropsWithChildren } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const Outline = () => {
|
||||
const tocPanelRef = useRef<TOCNotesPanel | null>(null);
|
||||
const currentPageId = useAtomValue(currentPageIdAtom);
|
||||
assertExists(currentPageId, 'current page id');
|
||||
const currentWorkspace = useAtomValue(currentWorkspaceAtom);
|
||||
const currentPage = currentWorkspace.getPage(currentPageId);
|
||||
assertExists(currentPage, 'current page');
|
||||
|
||||
if (!tocPanelRef.current) {
|
||||
tocPanelRef.current = new TOCNotesPanel();
|
||||
}
|
||||
|
||||
if (currentPage !== tocPanelRef.current?.page) {
|
||||
(tocPanelRef.current as TOCNotesPanel).page = currentPage;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`outline-wrapper`}
|
||||
style={{
|
||||
height: '100%',
|
||||
borderLeft: `1px solid var(--affine-border-color)`,
|
||||
}}
|
||||
ref={useCallback((container: HTMLDivElement | null) => {
|
||||
if (container) {
|
||||
assertExists(tocPanelRef.current);
|
||||
container.append(tocPanelRef.current);
|
||||
}
|
||||
}, [])}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const HeaderItem = ({
|
||||
Provider,
|
||||
}: {
|
||||
Provider: ComponentType<PropsWithChildren>;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const pushLayout = useSetAtom(pushLayoutAtom);
|
||||
const deleteLayout = useSetAtom(deleteLayoutAtom);
|
||||
const [container, setContainer] = useState<HTMLButtonElement | null>(null);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={`${open ? 'Collapse' : 'Expand'} table of contents`}
|
||||
portalOptions={{
|
||||
container,
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
size="large"
|
||||
ref={setContainer}
|
||||
style={{
|
||||
width: '32px',
|
||||
fontSize: '24px',
|
||||
}}
|
||||
onClick={useCallback(() => {
|
||||
if (!open) {
|
||||
setOpen(true);
|
||||
pushLayout(
|
||||
'@affine/outline-plugin',
|
||||
div => {
|
||||
const root = createRoot(div);
|
||||
|
||||
div.style.height = '100%';
|
||||
|
||||
root.render(
|
||||
<Provider>
|
||||
<Outline />
|
||||
</Provider>
|
||||
);
|
||||
return () => {
|
||||
root.unmount();
|
||||
};
|
||||
},
|
||||
{
|
||||
maxWidth: [undefined, 300],
|
||||
}
|
||||
);
|
||||
} else {
|
||||
setOpen(false);
|
||||
deleteLayout('@affine/outline-plugin');
|
||||
}
|
||||
}, [Provider, deleteLayout, open, pushLayout])}
|
||||
>
|
||||
<RightSidebarIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
@ -1,41 +0,0 @@
|
||||
import type { PluginContext } from '@affine/sdk/entry';
|
||||
import { registerTOCComponents } from '@blocksuite/blocks';
|
||||
import { createElement } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { HeaderItem } from './app';
|
||||
|
||||
export const entry = (context: PluginContext) => {
|
||||
console.log('register outline');
|
||||
|
||||
context.register('headerItem', div => {
|
||||
registerTOCComponents(components => {
|
||||
for (const compName in components) {
|
||||
if (window.customElements.get(compName)) continue;
|
||||
|
||||
window.customElements.define(
|
||||
compName,
|
||||
components[compName as keyof typeof components]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
div.style.height = '100%';
|
||||
|
||||
const root = createRoot(div);
|
||||
root.render(
|
||||
createElement(
|
||||
context.utils.PluginProvider,
|
||||
{},
|
||||
createElement(HeaderItem, {
|
||||
Provider: context.utils.PluginProvider,
|
||||
})
|
||||
)
|
||||
);
|
||||
return () => {
|
||||
root.unmount();
|
||||
};
|
||||
});
|
||||
|
||||
return () => {};
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["./src"],
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"outDir": "lib",
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../../common/sdk"
|
||||
},
|
||||
{
|
||||
"path": "../../frontend/component"
|
||||
}
|
||||
]
|
||||
}
|
@ -236,7 +236,8 @@ test('can sync svg between different browsers', async ({ page, browser }) => {
|
||||
const image = page.locator('affine-image');
|
||||
|
||||
page.evaluate(async () => {
|
||||
window.showOpenFilePicker = undefined;
|
||||
// https://github.com/toeverything/blocksuite/blob/master/packages/blocks/src/_common/utils/filesys.ts#L20
|
||||
(window as any).showOpenFilePicker = undefined;
|
||||
});
|
||||
|
||||
const title = getBlockSuiteEditorTitle(page);
|
||||
|
@ -26,7 +26,6 @@ test('plugin should exist', async ({ page }) => {
|
||||
'@affine/hello-world-plugin',
|
||||
'@affine/image-preview-plugin',
|
||||
'@affine/vue-hello-world-plugin',
|
||||
'@affine/outline-plugin',
|
||||
];
|
||||
expect(packageJson).toEqual(
|
||||
plugins
|
||||
|
15
yarn.lock
15
yarn.lock
@ -464,7 +464,6 @@ __metadata:
|
||||
"@affine/hello-world-plugin": "workspace:*"
|
||||
"@affine/image-preview-plugin": "workspace:*"
|
||||
"@affine/native": "workspace:*"
|
||||
"@affine/outline-plugin": "workspace:*"
|
||||
"@affine/sdk": "workspace:*"
|
||||
"@affine/templates": "workspace:*"
|
||||
"@affine/vue-hello-world-plugin": "workspace:*"
|
||||
@ -675,20 +674,6 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@affine/outline-plugin@workspace:*, @affine/outline-plugin@workspace:packages/plugins/outline":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@affine/outline-plugin@workspace:packages/plugins/outline"
|
||||
dependencies:
|
||||
"@affine/component": "workspace:*"
|
||||
"@affine/plugin-cli": "workspace:*"
|
||||
"@affine/sdk": "workspace:*"
|
||||
"@blocksuite/icons": "npm:2.1.36"
|
||||
jotai: "npm:^2.5.1"
|
||||
react: "npm:18.2.0"
|
||||
react-dom: "npm:18.2.0"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@affine/plugin-cli@workspace:*, @affine/plugin-cli@workspace:tools/plugin-cli":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@affine/plugin-cli@workspace:tools/plugin-cli"
|
||||
|
Loading…
Reference in New Issue
Block a user