diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx
index 593ffab8c958c..77ad4a406e4fb 100644
--- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx
+++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx
@@ -46,6 +46,7 @@ import {
workspaceWrapper,
} from './index.css';
import { AppSidebarJournalButton } from './journal-button';
+import { TemplateDocEntrance } from './template-doc-entrance';
import { TrashButton } from './trash-button';
import { UpdaterButton } from './updater-button';
import { UserInfo } from './user-info';
@@ -192,6 +193,7 @@ export const RootAppSidebar = memo((): ReactElement => {
>
{t['Import']()}
+
}
diff --git a/packages/frontend/core/src/components/root-app-sidebar/template-doc-entrance.tsx b/packages/frontend/core/src/components/root-app-sidebar/template-doc-entrance.tsx
new file mode 100644
index 0000000000000..c2204a853e8df
--- /dev/null
+++ b/packages/frontend/core/src/components/root-app-sidebar/template-doc-entrance.tsx
@@ -0,0 +1,89 @@
+import { Menu, MenuItem, MenuSeparator } from '@affine/component';
+import { MenuItem as SidebarMenuItem } from '@affine/core/modules/app-sidebar/views';
+import { DocsService } from '@affine/core/modules/doc';
+import { FeatureFlagService } from '@affine/core/modules/feature-flag';
+import { TemplateListMenuContentScrollable } from '@affine/core/modules/template-doc';
+import { WorkbenchService } from '@affine/core/modules/workbench';
+import { inferOpenMode } from '@affine/core/utils';
+import { useI18n } from '@affine/i18n';
+import { TemplateIcon, TemplateOutlineIcon } from '@blocksuite/icons/rc';
+import { useLiveData, useService } from '@toeverything/infra';
+import { useCallback, useState } from 'react';
+
+import { useAsyncCallback } from '../hooks/affine-async-hooks';
+
+export const TemplateDocEntrance = () => {
+ const t = useI18n();
+ const [menuOpen, setMenuOpen] = useState(false);
+ const docsService = useService(DocsService);
+ const featureFlagService = useService(FeatureFlagService);
+ const workbench = useService(WorkbenchService).workbench;
+ const enabled = useLiveData(featureFlagService.flags.enable_template_doc.$);
+
+ const toggleMenu = useCallback(() => {
+ setMenuOpen(prev => !prev);
+ }, []);
+
+ const createDocFromTemplate = useAsyncCallback(
+ async (templateId: string) => {
+ const docId = await docsService.duplicateFromTemplate(templateId);
+ workbench.openDoc(docId);
+ },
+ [docsService, workbench]
+ );
+
+ if (!enabled) {
+ return null;
+ }
+
+ return (
+ } onClick={toggleMenu}>
+
+
+ );
+};
+
+const CreateNewTemplateMenuItem = () => {
+ const t = useI18n();
+ const docsService = useService(DocsService);
+ const workbench = useService(WorkbenchService).workbench;
+
+ const createNewTemplate = useCallback(
+ (e: React.MouseEvent) => {
+ const record = docsService.createDoc({ isTemplate: true });
+ workbench.openDoc(record.id, { at: inferOpenMode(e) });
+ },
+ [docsService, workbench]
+ );
+
+ return (
+ }
+ onClick={createNewTemplate}
+ onAuxClick={createNewTemplate}
+ >
+ {t['com.affine.template-list.create-new']()}
+
+ );
+};
diff --git a/packages/frontend/core/src/modules/doc/services/docs.ts b/packages/frontend/core/src/modules/doc/services/docs.ts
index 202657a0b2f97..d4d45d82cc8e1 100644
--- a/packages/frontend/core/src/modules/doc/services/docs.ts
+++ b/packages/frontend/core/src/modules/doc/services/docs.ts
@@ -102,6 +102,7 @@ export class DocsService extends Service {
options: {
primaryMode?: DocMode;
docProps?: DocProps;
+ isTemplate?: boolean;
} = {}
) {
const doc = this.store.createBlockSuiteDoc();
@@ -114,6 +115,9 @@ export class DocsService extends Service {
if (options.primaryMode) {
docRecord.setPrimaryMode(options.primaryMode);
}
+ if (options.isTemplate) {
+ docRecord.setProperty('isTemplate', true);
+ }
this.eventBus.emit(DocCreated, docRecord);
return docRecord;
}
diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json
index 2e0ed059db37d..4328b43249313 100644
--- a/packages/frontend/i18n/src/resources/en.json
+++ b/packages/frontend/i18n/src/resources/en.json
@@ -1631,6 +1631,7 @@
"com.affine.page-starter-bar.edgeless": "Edgeless",
"Template": "Template",
"com.affine.template-list.empty": "No template",
+ "com.affine.template-list.create-new": "Create new template",
"com.affine.settings.workspace.template.title": "My Templates",
"com.affine.settings.workspace.template.journal": "Template for journal",
"com.affine.settings.workspace.template.journal-desc": "Select a template for your journal",