diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx
index 489d4fd0e..97464e369 100644
--- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx
+++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx
@@ -20,6 +20,7 @@ import {
RecentDocsQuickSearchSession,
} from '@affine/core/modules/quicksearch';
import { ExternalLinksQuickSearchSession } from '@affine/core/modules/quicksearch/impls/external-links';
+import { JournalsQuickSearchSession } from '@affine/core/modules/quicksearch/impls/journals';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { isNewTabTrigger } from '@affine/core/utils';
import { DebugLogger } from '@affine/debug';
@@ -331,7 +332,7 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
const QuickSearch = QuickSearchExtension({
async openQuickSearch() {
let searchResult: QuickSearchResult = null;
- searchResult = await new Promise(resolve =>
+ searchResult = await new Promise((resolve, reject) =>
framework.get(QuickSearchService).quickSearch.show(
[
framework.get(RecentDocsQuickSearchSession),
@@ -339,6 +340,7 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
framework.get(DocsQuickSearchSession),
framework.get(LinksQuickSearchSession),
framework.get(ExternalLinksQuickSearchSession),
+ framework.get(JournalsQuickSearchSession),
],
result => {
if (result === null) {
@@ -372,6 +374,18 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
return;
}
+ if (result.source === 'date-picker') {
+ result.payload
+ .getDocId()
+ .then(docId => {
+ if (docId) {
+ resolve({ docId });
+ }
+ })
+ .catch(reject);
+ return;
+ }
+
if (result.source === 'external-link') {
const externalUrl = result.payload.url;
resolve({ externalUrl });
diff --git a/packages/frontend/core/src/desktop/dialogs/selectors/date.tsx b/packages/frontend/core/src/desktop/dialogs/selectors/date.tsx
index 0761bf7e0..c690f2154 100644
--- a/packages/frontend/core/src/desktop/dialogs/selectors/date.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/selectors/date.tsx
@@ -63,13 +63,23 @@ export const DateSelectorDialog = ({
>
{/* hack the menu positioning using the following fixed anchor */}
);
diff --git a/packages/frontend/core/src/modules/dialogs/constant.ts b/packages/frontend/core/src/modules/dialogs/constant.ts
index 9eaa9855a..1537e3991 100644
--- a/packages/frontend/core/src/modules/dialogs/constant.ts
+++ b/packages/frontend/core/src/modules/dialogs/constant.ts
@@ -60,7 +60,7 @@ export type WORKSPACE_DIALOG_SCHEMA = {
onBeforeConfirm?: (ids: string[], cb: () => void) => void;
}) => string[];
'date-selector': (props: {
- position: [number, number, number, number]; // [x, y, width, height]
+ position?: [number, number, number, number]; // [x, y, width, height]
onSelect?: (date?: string) => void;
}) => string;
import: () => {
diff --git a/packages/frontend/core/src/modules/quicksearch/impls/journals.ts b/packages/frontend/core/src/modules/quicksearch/impls/journals.ts
new file mode 100644
index 000000000..8d21e5cb0
--- /dev/null
+++ b/packages/frontend/core/src/modules/quicksearch/impls/journals.ts
@@ -0,0 +1,110 @@
+import { I18n, i18nTime } from '@affine/i18n';
+import { DateTimeIcon } from '@blocksuite/icons/rc';
+import { Entity, LiveData } from '@toeverything/infra';
+
+import type { WorkspaceDialogService } from '../../dialogs';
+import type { DocDisplayMetaService } from '../../doc-display-meta';
+import { type JournalService, suggestJournalDate } from '../../journal';
+import type { QuickSearchSession } from '../providers/quick-search-provider';
+import type { QuickSearchGroup } from '../types/group';
+import type { QuickSearchItem } from '../types/item';
+
+const group: QuickSearchGroup = {
+ id: 'journals',
+ label: {
+ i18nKey: 'com.affine.cmdk.affine.category.affine.journal',
+ },
+ score: 0,
+};
+
+type JournalQuickSearchItem = QuickSearchItem<
+ 'date-picker',
+ { getDocId: () => Promise }
+>;
+
+export class JournalsQuickSearchSession
+ extends Entity
+ implements
+ QuickSearchSession<
+ 'date-picker',
+ { getDocId: () => Promise }
+ >
+{
+ constructor(
+ private readonly journalService: JournalService,
+ private readonly dialogService: WorkspaceDialogService,
+ private readonly docDisplayMetaService: DocDisplayMetaService
+ ) {
+ super();
+ }
+
+ query$ = new LiveData('');
+
+ items$: LiveData = LiveData.computed(get => {
+ const getDateDocId = (date?: string) => {
+ if (date) {
+ return this.journalService.ensureJournalByDate(date).id;
+ }
+ return undefined;
+ };
+
+ const items: JournalQuickSearchItem[] = [
+ {
+ icon: DateTimeIcon,
+ id: 'journal:pick-a-date',
+ source: 'date-picker',
+ group: group,
+ label: {
+ title: I18n.t('com.affine.cmdk.affine.category.affine.date-picker'),
+ },
+ score: 0,
+ payload: {
+ getDocId: () => {
+ return new Promise(resolve => {
+ const id = this.dialogService.open('date-selector', {
+ onSelect: date => {
+ resolve(getDateDocId(date));
+ this.dialogService.close(id);
+ },
+ });
+ });
+ },
+ },
+ },
+ ];
+
+ const query = get(this.query$);
+ const suggestedDate = suggestJournalDate(query);
+
+ if (suggestedDate) {
+ const { dateString, alias } = suggestedDate;
+ const dateDisplay = i18nTime(dateString, {
+ absolute: { accuracy: 'day' },
+ });
+
+ const icon = this.docDisplayMetaService.getJournalIcon(dateString, {
+ type: 'rc',
+ });
+
+ items.unshift({
+ icon,
+ id: 'journal:date-' + dateString,
+ source: 'date-picker',
+ group: group,
+ label: {
+ title: alias ? `${alias}, ${dateDisplay}` : dateDisplay,
+ },
+ score: 0,
+ payload: {
+ getDocId: () => Promise.resolve(getDateDocId(dateString)),
+ },
+ });
+ }
+
+ return items;
+ });
+
+ query(query: string) {
+ this.query$.next(query);
+ }
+}
diff --git a/packages/frontend/core/src/modules/quicksearch/index.ts b/packages/frontend/core/src/modules/quicksearch/index.ts
index e0de6f7c7..85cd2445e 100644
--- a/packages/frontend/core/src/modules/quicksearch/index.ts
+++ b/packages/frontend/core/src/modules/quicksearch/index.ts
@@ -8,8 +8,10 @@ import {
} from '@toeverything/infra';
import { CollectionService } from '../collection';
+import { WorkspaceDialogService } from '../dialogs';
import { DocDisplayMetaService } from '../doc-display-meta/services/doc-display-meta';
import { DocsSearchService } from '../docs-search';
+import { JournalService } from '../journal';
import { TagService } from '../tag';
import { WorkbenchService } from '../workbench';
import { QuickSearch } from './entities/quick-search';
@@ -18,6 +20,7 @@ import { CommandsQuickSearchSession } from './impls/commands';
import { CreationQuickSearchSession } from './impls/creation';
import { DocsQuickSearchSession } from './impls/docs';
import { ExternalLinksQuickSearchSession } from './impls/external-links';
+import { JournalsQuickSearchSession } from './impls/journals';
import { LinksQuickSearchSession } from './impls/links';
import { RecentDocsQuickSearchSession } from './impls/recent-docs';
import { TagsQuickSearchSession } from './impls/tags';
@@ -68,5 +71,10 @@ export function configureQuickSearchModule(framework: Framework) {
.entity(RecentDocsQuickSearchSession, [
RecentDocsService,
DocDisplayMetaService,
+ ])
+ .entity(JournalsQuickSearchSession, [
+ JournalService,
+ WorkspaceDialogService,
+ DocDisplayMetaService,
]);
}
diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json
index c35e36f9a..60709d924 100644
--- a/packages/frontend/i18n/src/resources/en.json
+++ b/packages/frontend/i18n/src/resources/en.json
@@ -1596,5 +1596,7 @@
"com.affine.upgrade-to-team-page.create-and-upgrade-confirm.description": "A workspace is your virtual space to capture, create and plan as just one person or together as a team.",
"com.affine.upgrade-to-team-page.create-and-upgrade-confirm.placeholder": "Set a workspace name",
"com.affine.upgrade-to-team-page.create-and-upgrade-confirm.confirm": "Continue to Pricing",
- "com.affine.workspace.storage": "Workspace storage"
+ "com.affine.workspace.storage": "Workspace storage",
+ "com.affine.cmdk.affine.category.affine.journal": "Journal",
+ "com.affine.cmdk.affine.category.affine.date-picker": "Select a specific date"
}
diff --git a/tests/affine-local/e2e/quick-search.spec.ts b/tests/affine-local/e2e/quick-search.spec.ts
index 44240a199..64023e4b5 100644
--- a/tests/affine-local/e2e/quick-search.spec.ts
+++ b/tests/affine-local/e2e/quick-search.spec.ts
@@ -479,7 +479,7 @@ test('can use @ to open quick search to search for doc and insert into canvas',
await insertInputText(page, url);
// expect the default page to be selected
- await expect(page.locator('[cmdk-group-items] [cmdk-item]')).toHaveCount(3);
+ await expect(page.locator('[cmdk-group-items] [cmdk-item]')).toHaveCount(5);
// press enter to insert the page to canvas
await page.keyboard.press('Enter');