Skip to content

Commit

Permalink
feat: custom the items of linked menu by configuration (#7554)
Browse files Browse the repository at this point in the history
Close issue [BS-719](https://linear.app/affine-design/issue/BS-719) and [BS-791](https://linear.app/affine-design/issue/BS-791).
Related PR in [BlockSuite](toeverything/blocksuite#7693).

### What Changed?
- Support config in BlockSpec
-  AFFiNE’s Custom @menu
   - ignore docs in trash
   - ignore unedited journal
   - customized journal icon

![截屏2024-07-19 16.03.55.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/cdf6f198-8288-4152-8893-65f17bc9983c.png)

### What's next?
- getMenus returns an observable array
- Add commands field to BlockSpec and encapsulated insertLinkedNode into a command
  • Loading branch information
akumatus committed Jul 24, 2024
1 parent 20c4224 commit 1871c15
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
import { PeekViewService } from '@affine/core/modules/peek-view';
import { WorkbenchService } from '@affine/core/modules/workbench';
import type { DocMode } from '@blocksuite/blocks';
import {
DocMetaTags,
DocTitle,
Expand All @@ -14,7 +15,6 @@ import {
} from '@blocksuite/presets';
import type { Doc } from '@blocksuite/store';
import {
type DocMode,
DocService,
DocsService,
useFramework,
Expand Down Expand Up @@ -44,8 +44,8 @@ import {
patchReferenceRenderer,
type ReferenceReactRenderer,
} from './specs/custom/spec-patchers';
import { EdgelessModeSpecs } from './specs/edgeless';
import { PageModeSpecs } from './specs/page';
import { createEdgelessModeSpecs } from './specs/edgeless';
import { createPageModeSpecs } from './specs/page';
import * as styles from './styles.css';

const adapted = {
Expand Down Expand Up @@ -88,7 +88,11 @@ const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => {
};
}, [page.collection]);

const specs = mode === 'page' ? PageModeSpecs : EdgelessModeSpecs;
const specs = useMemo(() => {
return mode === 'edgeless'
? createEdgelessModeSpecs(framework)
: createPageModeSpecs(framework);
}, [mode, framework]);

const confirmModal = useConfirmModal();
const patchedSpecs = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties';
import { mixpanel } from '@affine/core/utils';
import type { EditorHost } from '@blocksuite/block-std';
import type { AffineInlineEditor } from '@blocksuite/blocks';
import { LinkedWidgetUtils } from '@blocksuite/blocks';
import {
LinkedEdgelessIcon,
LinkedPageIcon,
TodayIcon,
} from '@blocksuite/icons/lit';
import type { DocMeta } from '@blocksuite/store';
import {
DocsService,
type FrameworkProvider,
WorkspaceService,
} from '@toeverything/infra';

export function createLinkedWidgetConfig(framework: FrameworkProvider) {
return {
getMenus: (
query: string,
abort: () => void,
editorHost: EditorHost,
inlineEditor: AffineInlineEditor
) => {
const currentWorkspace = framework.get(WorkspaceService).workspace;
const rawMetas = currentWorkspace.docCollection.meta.docMetas;
const adapter = framework.get(WorkspacePropertiesAdapter);
const isJournal = (d: DocMeta) =>
!!adapter.getJournalPageDateString(d.id);

const docMetas = rawMetas
.filter(meta => {
if (isJournal(meta) && !meta.updatedDate) {
return false;
}
return !meta.trash;
})
.filter(({ title }) => isFuzzyMatch(title, query));

// TODO need i18n if BlockSuite supported
const MAX_DOCS = 6;
const DEFAULT_DOC_NAME = 'Untitled';
const docsService = framework.get(DocsService);
const isEdgeless = (d: DocMeta) =>
docsService.list.getMode(d.id) === 'edgeless';
return Promise.resolve([
{
name: 'Link to Doc',
items: docMetas.map(doc => ({
key: doc.id,
name: doc.title || DEFAULT_DOC_NAME,
icon: isJournal(doc)
? TodayIcon
: isEdgeless(doc)
? LinkedEdgelessIcon
: LinkedPageIcon,
action: () => {
abort();
LinkedWidgetUtils.insertLinkedNode({
inlineEditor,
docId: doc.id,
});
mixpanel.track('LinkedDocCreated', {
control: 'linked doc',
module: 'inline @',
type: 'doc',
other: 'existing doc',
});
},
})),
maxDisplay: MAX_DOCS,
overflowText: `${docMetas.length - MAX_DOCS} more docs`,
},
LinkedWidgetUtils.createNewDocMenuGroup(
query,
abort,
editorHost,
inlineEditor
),
]);
},
};
}

/**
* Checks if the name is a fuzzy match of the query.
*
* @example
* ```ts
* const name = 'John Smith';
* const query = 'js';
* const isMatch = isFuzzyMatch(name, query);
* // isMatch: true
* ```
*/
function isFuzzyMatch(name: string, query: string) {
const pureName = name
.trim()
.toLowerCase()
.split('')
.filter(char => char !== ' ')
.join('');

const regex = new RegExp(
query
.split('')
.filter(char => char !== ' ')
.map(item => `${escapeRegExp(item)}.*`)
.join(''),
'i'
);
return regex.test(pureName);
}

function escapeRegExp(input: string) {
// escape regex characters in the input string to prevent regex format errors
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ import {
AIPageRootBlockSpec,
} from '@affine/core/blocksuite/presets/ai';
import { mixpanel } from '@affine/core/utils';
import type { BlockSpec } from '@blocksuite/block-std';
import type { RootService, TelemetryEventMap } from '@blocksuite/blocks';
import type {
EdgelessRootBlockSpecType,
PageRootBlockSpecType,
RootService,
TelemetryEventMap,
} from '@blocksuite/blocks';
import {
AffineCanvasTextFonts,
EdgelessRootService,
PageRootService,
} from '@blocksuite/blocks';
import { type FrameworkProvider } from '@toeverything/infra';

import { createLinkedWidgetConfig } from './linked-widget';

function customLoadFonts(service: RootService): void {
if (runtimeConfig.isSelfHosted) {
Expand Down Expand Up @@ -41,12 +48,26 @@ function withAffineRootService(Service: typeof RootService) {
};
}

export const CustomPageRootBlockSpec: BlockSpec = {
...AIPageRootBlockSpec,
service: withAffineRootService(PageRootService),
};
export function createPageRootBlockSpec(
framework: FrameworkProvider
): PageRootBlockSpecType {
return {
...AIPageRootBlockSpec,
service: withAffineRootService(PageRootService),
config: {
linkedWidget: createLinkedWidgetConfig(framework),
},
};
}

export const CustomEdgelessRootBlockSpec: BlockSpec = {
...AIEdgelessRootBlockSpec,
service: withAffineRootService(EdgelessRootService),
};
export function createEdgelessRootBlockSpec(
framework: FrameworkProvider
): EdgelessRootBlockSpecType {
return {
...AIEdgelessRootBlockSpec,
service: withAffineRootService(EdgelessRootService),
config: {
linkedWidget: createLinkedWidgetConfig(framework),
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@ import {
EdgelessTextBlockSpec,
FrameBlockSpec,
} from '@blocksuite/blocks';
import type { FrameworkProvider } from '@toeverything/infra';

import { CommonBlockSpecs } from './common';
import { CustomEdgelessRootBlockSpec } from './custom/root-block';
import { createEdgelessRootBlockSpec } from './custom/root-block';

export const EdgelessModeSpecs: BlockSpec[] = [
...CommonBlockSpecs,
EdgelessSurfaceBlockSpec,
EdgelessSurfaceRefBlockSpec,
FrameBlockSpec,
EdgelessTextBlockSpec,
EdgelessNoteBlockSpec,
// special
CustomEdgelessRootBlockSpec,
];
export function createEdgelessModeSpecs(
framework: FrameworkProvider
): BlockSpec[] {
return [
...CommonBlockSpecs,
EdgelessSurfaceBlockSpec,
EdgelessSurfaceRefBlockSpec,
FrameBlockSpec,
EdgelessTextBlockSpec,
EdgelessNoteBlockSpec,
// special
createEdgelessRootBlockSpec(framework),
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import {
PageSurfaceBlockSpec,
PageSurfaceRefBlockSpec,
} from '@blocksuite/blocks';
import { type FrameworkProvider } from '@toeverything/infra';

import { CommonBlockSpecs } from './common';
import { CustomPageRootBlockSpec } from './custom/root-block';
import { createPageRootBlockSpec } from './custom/root-block';

export const PageModeSpecs: BlockSpec[] = [
...CommonBlockSpecs,
PageSurfaceBlockSpec,
PageSurfaceRefBlockSpec,
// special
CustomPageRootBlockSpec,
];
export function createPageModeSpecs(framework: FrameworkProvider): BlockSpec[] {
return [
...CommonBlockSpecs,
PageSurfaceBlockSpec,
PageSurfaceRefBlockSpec,
// special
createPageRootBlockSpec(framework),
];
}

0 comments on commit 1871c15

Please sign in to comment.