mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
feat(mobile): search page ui (#8012)
feat(mobile): search page ui fix(core): quick search tags performance issue
This commit is contained in:
91
packages/frontend/core/src/modules/quicksearch/impls/tags.ts
Normal file
91
packages/frontend/core/src/modules/quicksearch/impls/tags.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { Entity, LiveData } from '@toeverything/infra';
|
||||
import Fuse from 'fuse.js';
|
||||
|
||||
import type { TagService } from '../../tag';
|
||||
import type { QuickSearchSession } from '../providers/quick-search-provider';
|
||||
import type { QuickSearchGroup } from '../types/group';
|
||||
import type { QuickSearchItem } from '../types/item';
|
||||
import { highlighter } from '../utils/highlighter';
|
||||
import { QuickSearchTagIcon } from '../views/tag-icon';
|
||||
|
||||
const group: QuickSearchGroup = {
|
||||
id: 'tags',
|
||||
label: {
|
||||
key: 'com.affine.cmdk.affine.category.affine.tags',
|
||||
},
|
||||
score: 10,
|
||||
};
|
||||
|
||||
export class TagsQuickSearchSession
|
||||
extends Entity
|
||||
implements QuickSearchSession<'tags', { tagId: string }>
|
||||
{
|
||||
constructor(private readonly tagService: TagService) {
|
||||
super();
|
||||
}
|
||||
|
||||
query$ = new LiveData('');
|
||||
|
||||
items$: LiveData<QuickSearchItem<'tags', { tagId: string }>[]> =
|
||||
LiveData.computed(get => {
|
||||
const query = get(this.query$);
|
||||
|
||||
// has performance issues with `tagList.tagMetas$`
|
||||
const tags = get(this.tagService.tagList.tags$).map(tag => ({
|
||||
id: tag.id,
|
||||
title: get(tag.value$),
|
||||
color: get(tag.color$),
|
||||
}));
|
||||
|
||||
const fuse = new Fuse(tags, {
|
||||
keys: ['title'],
|
||||
includeMatches: true,
|
||||
includeScore: true,
|
||||
ignoreLocation: true,
|
||||
threshold: 0.0,
|
||||
});
|
||||
|
||||
const result = fuse.search(query);
|
||||
|
||||
return result.map<QuickSearchItem<'tags', { tagId: string }>>(
|
||||
({ item, matches, score = 1 }) => {
|
||||
const normalizedRange = ([start, end]: [number, number]) =>
|
||||
[
|
||||
start,
|
||||
end +
|
||||
1 /* in fuse, the `end` is different from the `substring` */,
|
||||
] as [number, number];
|
||||
const titleMatches = matches
|
||||
?.filter(match => match.key === 'title')
|
||||
.flatMap(match => match.indices.map(normalizedRange));
|
||||
|
||||
const Icon = () => QuickSearchTagIcon({ color: item.color });
|
||||
|
||||
return {
|
||||
id: 'tag:' + item.id,
|
||||
source: 'tags',
|
||||
label: {
|
||||
title: (highlighter(
|
||||
item.title,
|
||||
'<b>',
|
||||
'</b>',
|
||||
titleMatches ?? []
|
||||
) ??
|
||||
item.title) || {
|
||||
key: 'Untitled',
|
||||
},
|
||||
},
|
||||
group,
|
||||
score: 1 - score,
|
||||
icon: Icon,
|
||||
matches: titleMatches,
|
||||
payload: { tagId: item.id },
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
query(query: string) {
|
||||
this.query$.next(query);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { CollectionService } from '../collection';
|
||||
import { DocsSearchService } from '../docs-search';
|
||||
import { WorkspacePropertiesAdapter } from '../properties';
|
||||
import { TagService } from '../tag';
|
||||
import { WorkbenchService } from '../workbench';
|
||||
import { QuickSearch } from './entities/quick-search';
|
||||
import { CollectionsQuickSearchSession } from './impls/collections';
|
||||
@@ -16,6 +17,7 @@ import { CommandsQuickSearchSession } from './impls/commands';
|
||||
import { CreationQuickSearchSession } from './impls/creation';
|
||||
import { DocsQuickSearchSession } from './impls/docs';
|
||||
import { RecentDocsQuickSearchSession } from './impls/recent-docs';
|
||||
import { TagsQuickSearchSession } from './impls/tags';
|
||||
import { CMDKQuickSearchService } from './services/cmdk';
|
||||
import { DocDisplayMetaService } from './services/doc-display-meta';
|
||||
import { QuickSearchService } from './services/quick-search';
|
||||
@@ -28,8 +30,10 @@ export { CommandsQuickSearchSession } from './impls/commands';
|
||||
export { CreationQuickSearchSession } from './impls/creation';
|
||||
export { DocsQuickSearchSession } from './impls/docs';
|
||||
export { RecentDocsQuickSearchSession } from './impls/recent-docs';
|
||||
export { TagsQuickSearchSession } from './impls/tags';
|
||||
export type { QuickSearchItem } from './types/item';
|
||||
export { QuickSearchContainer } from './views/container';
|
||||
export { QuickSearchTagIcon } from './views/tag-icon';
|
||||
|
||||
export function configureQuickSearchModule(framework: Framework) {
|
||||
framework
|
||||
@@ -51,6 +55,7 @@ export function configureQuickSearchModule(framework: Framework) {
|
||||
])
|
||||
.entity(CreationQuickSearchSession)
|
||||
.entity(CollectionsQuickSearchSession, [CollectionService])
|
||||
.entity(TagsQuickSearchSession, [TagService])
|
||||
.entity(RecentDocsQuickSearchSession, [
|
||||
RecentDocsService,
|
||||
DocDisplayMetaService,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { CommandsQuickSearchSession } from '../impls/commands';
|
||||
import { CreationQuickSearchSession } from '../impls/creation';
|
||||
import { DocsQuickSearchSession } from '../impls/docs';
|
||||
import { RecentDocsQuickSearchSession } from '../impls/recent-docs';
|
||||
import { TagsQuickSearchSession } from '../impls/tags';
|
||||
import type { QuickSearchService } from './quick-search';
|
||||
|
||||
export class CMDKQuickSearchService extends Service {
|
||||
@@ -30,6 +31,7 @@ export class CMDKQuickSearchService extends Service {
|
||||
this.framework.createEntity(CommandsQuickSearchSession),
|
||||
this.framework.createEntity(CreationQuickSearchSession),
|
||||
this.framework.createEntity(DocsQuickSearchSession),
|
||||
this.framework.createEntity(TagsQuickSearchSession),
|
||||
],
|
||||
result => {
|
||||
if (!result) {
|
||||
@@ -60,6 +62,8 @@ export class CMDKQuickSearchService extends Service {
|
||||
this.workbenchService.workbench.openCollection(
|
||||
result.payload.collectionId
|
||||
);
|
||||
} else if (result.source === 'tags') {
|
||||
this.workbenchService.workbench.openTag(result.payload.tagId);
|
||||
} else if (result.source === 'creation') {
|
||||
if (result.id === 'creation:create-page') {
|
||||
const newDoc = this.docsService.createDoc({
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export const QuickSearchTagIcon = ({ color }: { color: string }) => {
|
||||
return (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="12" cy="12" fill={color} r="5" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user