feat(mobile): search page ui (#8012)

feat(mobile): search page ui

fix(core): quick search tags performance issue
This commit is contained in:
CatsJuice
2024-08-29 09:05:23 +00:00
parent 5e8683c9be
commit f1bb1fc9b8
26 changed files with 731 additions and 50 deletions

View 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);
}
}

View File

@@ -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,

View File

@@ -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({

View File

@@ -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>
);
};