diff --git a/src/main/engine/MenuEngine.ts b/src/main/engine/MenuEngine.ts
index c151633..e2fabae 100644
--- a/src/main/engine/MenuEngine.ts
+++ b/src/main/engine/MenuEngine.ts
@@ -5,14 +5,14 @@ import { randomUUID } from 'crypto';
import { app } from 'electron';
import { XMLBuilder, XMLParser } from 'fast-xml-parser';
-export type MenuItemKind = 'page' | 'submenu' | 'category-archive';
+export type MenuItemKind = 'page' | 'submenu' | 'category-archive' | 'home';
const HOME_MENU_ID = 'menu-home';
const DEFAULT_HOME_ITEM: MenuItemData = {
id: HOME_MENU_ID,
title: 'Home',
- kind: 'page',
+ kind: 'home',
pageId: undefined,
pageSlug: 'home',
categoryName: undefined,
@@ -79,6 +79,8 @@ function sanitizeMenuItem(input: unknown): MenuItemData {
? 'submenu'
: candidate.kind === 'category-archive'
? 'category-archive'
+ : candidate.kind === 'home'
+ ? 'home'
: 'page';
const childrenSource = Array.isArray(candidate.children) ? candidate.children : [];
const title = normalizeNonEmptyString(candidate.title) || 'Untitled';
@@ -88,7 +90,7 @@ function sanitizeMenuItem(input: unknown): MenuItemData {
title,
kind,
pageId: kind === 'page' ? normalizeNonEmptyString(candidate.pageId) : undefined,
- pageSlug: kind === 'page' ? normalizeNonEmptyString(candidate.pageSlug) : undefined,
+ pageSlug: kind === 'page' || kind === 'home' ? normalizeNonEmptyString(candidate.pageSlug) : undefined,
categoryName: kind === 'category-archive' ? normalizeNonEmptyString(candidate.categoryName) : undefined,
children: childrenSource.map((child) => sanitizeMenuItem(child)),
};
@@ -99,7 +101,7 @@ function normalizeHomeItem(item: MenuItemData): MenuItemData {
...item,
id: HOME_MENU_ID,
title: 'Home',
- kind: 'page',
+ kind: 'home',
pageId: undefined,
pageSlug: 'home',
categoryName: undefined,
@@ -167,6 +169,8 @@ function parseOutlineNode(node: OpmlOutlineNode): MenuItemData {
? 'submenu'
: rawType === 'category-archive'
? 'category-archive'
+ : rawType === 'home'
+ ? 'home'
: 'page';
const title = normalizeNonEmptyString(node['@_text']) || normalizeNonEmptyString(node['@_title']) || 'Untitled';
@@ -175,7 +179,7 @@ function parseOutlineNode(node: OpmlOutlineNode): MenuItemData {
title,
kind,
pageId: kind === 'page' ? normalizeNonEmptyString(node['@_pageId']) : undefined,
- pageSlug: kind === 'page' ? normalizeNonEmptyString(node['@_pageSlug']) : undefined,
+ pageSlug: kind === 'page' || kind === 'home' ? normalizeNonEmptyString(node['@_pageSlug']) : undefined,
categoryName: kind === 'category-archive' ? normalizeNonEmptyString(node['@_categoryName']) : undefined,
children: normalizeOutlineNodes(node.outline).map((child) => parseOutlineNode(child)),
};
@@ -192,7 +196,7 @@ function toOpmlOutlineNode(item: MenuItemData): OpmlOutlineNode {
outlineNode['@_pageId'] = item.pageId;
}
- if (item.kind === 'page' && item.pageSlug) {
+ if ((item.kind === 'page' || item.kind === 'home') && item.pageSlug) {
outlineNode['@_pageSlug'] = item.pageSlug;
}
diff --git a/src/main/shared/electronApi.ts b/src/main/shared/electronApi.ts
index 980bd4a..8a02eaa 100644
--- a/src/main/shared/electronApi.ts
+++ b/src/main/shared/electronApi.ts
@@ -422,7 +422,7 @@ export interface SiteValidationApplyResult {
removedEmptyDirCount: number;
}
-export type MenuItemKind = 'page' | 'submenu' | 'category-archive';
+export type MenuItemKind = 'page' | 'submenu' | 'category-archive' | 'home';
export interface MenuItemData {
id: string;
diff --git a/src/renderer/components/MenuEditorView/MenuEditorView.css b/src/renderer/components/MenuEditorView/MenuEditorView.css
index 36f7005..633c1e9 100644
--- a/src/renderer/components/MenuEditorView/MenuEditorView.css
+++ b/src/renderer/components/MenuEditorView/MenuEditorView.css
@@ -124,8 +124,19 @@
}
.menu-editor-row-kind {
- font-size: 0.75rem;
- opacity: 0.85;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 1rem;
+ min-width: 1rem;
+ opacity: 0.9;
+}
+
+.menu-editor-row-kind-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: inherit;
}
.menu-editor-row-title {
diff --git a/src/renderer/components/MenuEditorView/MenuEditorView.tsx b/src/renderer/components/MenuEditorView/MenuEditorView.tsx
index 14c0149..dcbb714 100644
--- a/src/renderer/components/MenuEditorView/MenuEditorView.tsx
+++ b/src/renderer/components/MenuEditorView/MenuEditorView.tsx
@@ -167,6 +167,22 @@ function createDraftEntry(kind: MenuItemData['kind'] = 'submenu'): MenuItemData
};
}
+function renderMenuKindIcon(kind: MenuItemData['kind']): React.ReactNode {
+ if (kind === 'home') {
+ return ;
+ }
+
+ if (kind === 'page') {
+ return ;
+ }
+
+ if (kind === 'category-archive') {
+ return ;
+ }
+
+ return ;
+}
+
export const MenuEditorView: React.FC = () => {
const { t: tr } = useI18n();
const [items, setItems] = useState([]);
@@ -718,11 +734,30 @@ export const MenuEditorView: React.FC = () => {
>
<>
- {node.data.kind === 'page'
- ? tr('menuEditor.type.page')
- : node.data.kind === 'category-archive'
- ? tr('menuEditor.type.categoryArchive')
- : tr('menuEditor.type.submenu')}
+
+ {renderMenuKindIcon(node.data.kind)}
+
{editingEntryId === node.data.id ? (
diff --git a/src/renderer/i18n/locales/de.json b/src/renderer/i18n/locales/de.json
index b231484..dcbe98b 100644
--- a/src/renderer/i18n/locales/de.json
+++ b/src/renderer/i18n/locales/de.json
@@ -76,6 +76,7 @@
"menuEditor.field.pageSlug": "Seiten-Slug",
"menuEditor.field.pageId": "Seiten-ID",
"menuEditor.type.page": "Seite",
+ "menuEditor.type.home": "Startseite",
"menuEditor.type.submenu": "Untermenü",
"menuEditor.type.categoryArchive": "Kategorie-Archiv",
"menuEditor.empty": "Noch keine Menüeinträge. Füge eine Seite oder ein Untermenü hinzu.",
diff --git a/src/renderer/i18n/locales/en.json b/src/renderer/i18n/locales/en.json
index bc56e3a..854f522 100644
--- a/src/renderer/i18n/locales/en.json
+++ b/src/renderer/i18n/locales/en.json
@@ -76,6 +76,7 @@
"menuEditor.field.pageSlug": "Page Slug",
"menuEditor.field.pageId": "Page ID",
"menuEditor.type.page": "Page",
+ "menuEditor.type.home": "Home",
"menuEditor.type.submenu": "Submenu",
"menuEditor.type.categoryArchive": "Category Archive",
"menuEditor.empty": "No menu entries yet. Add a page or submenu to start.",
diff --git a/src/renderer/i18n/locales/es.json b/src/renderer/i18n/locales/es.json
index f3e408b..d854ae7 100644
--- a/src/renderer/i18n/locales/es.json
+++ b/src/renderer/i18n/locales/es.json
@@ -76,6 +76,7 @@
"menuEditor.field.pageSlug": "Slug de página",
"menuEditor.field.pageId": "ID de página",
"menuEditor.type.page": "Página",
+ "menuEditor.type.home": "Inicio",
"menuEditor.type.submenu": "Submenú",
"menuEditor.type.categoryArchive": "Archivo de categoría",
"menuEditor.empty": "Aún no hay entradas de menú. Añade una página o un submenú para empezar.",
diff --git a/src/renderer/i18n/locales/fr.json b/src/renderer/i18n/locales/fr.json
index 47501d6..6f284a0 100644
--- a/src/renderer/i18n/locales/fr.json
+++ b/src/renderer/i18n/locales/fr.json
@@ -76,6 +76,7 @@
"menuEditor.field.pageSlug": "Slug de page",
"menuEditor.field.pageId": "ID de page",
"menuEditor.type.page": "Page",
+ "menuEditor.type.home": "Accueil",
"menuEditor.type.submenu": "Sous-menu",
"menuEditor.type.categoryArchive": "Archive de catégorie",
"menuEditor.empty": "Aucune entrée de menu. Ajoutez une page ou un sous-menu pour commencer.",
diff --git a/src/renderer/i18n/locales/it.json b/src/renderer/i18n/locales/it.json
index e27788f..aad747c 100644
--- a/src/renderer/i18n/locales/it.json
+++ b/src/renderer/i18n/locales/it.json
@@ -76,6 +76,7 @@
"menuEditor.field.pageSlug": "Slug pagina",
"menuEditor.field.pageId": "ID pagina",
"menuEditor.type.page": "Pagina",
+ "menuEditor.type.home": "Home",
"menuEditor.type.submenu": "Sottomenu",
"menuEditor.type.categoryArchive": "Archivio categoria",
"menuEditor.empty": "Nessuna voce menu. Aggiungi una pagina o un sottomenu per iniziare.",
diff --git a/tests/engine/MenuEngine.test.ts b/tests/engine/MenuEngine.test.ts
index a4e880e..a34de7a 100644
--- a/tests/engine/MenuEngine.test.ts
+++ b/tests/engine/MenuEngine.test.ts
@@ -54,7 +54,7 @@ describe('MenuEngine', () => {
expect(result.items[0]).toMatchObject({
id: 'menu-home',
title: 'Home',
- kind: 'page',
+ kind: 'home',
pageSlug: 'home',
});
});
@@ -72,7 +72,7 @@ describe('MenuEngine', () => {
expect(result.items[0]).toMatchObject({
id: 'menu-home',
title: 'Home',
- kind: 'page',
+ kind: 'home',
pageSlug: 'home',
});
expect(result.items[1]).toMatchObject({
diff --git a/tests/renderer/components/MenuEditorView.test.tsx b/tests/renderer/components/MenuEditorView.test.tsx
index 70208e2..59004c6 100644
--- a/tests/renderer/components/MenuEditorView.test.tsx
+++ b/tests/renderer/components/MenuEditorView.test.tsx
@@ -16,7 +16,7 @@ describe('MenuEditorView entry editor', () => {
{
id: 'menu-home',
title: 'Home',
- kind: 'page',
+ kind: 'home',
pageSlug: 'home',
children: [],
},
@@ -217,4 +217,15 @@ describe('MenuEditorView entry editor', () => {
expect(deleteButton).toBeDisabled();
});
+ it('shows type as icon only (no visible type text label)', async () => {
+ const { container } = render();
+
+ await screen.findByText('Home');
+
+ const icon = container.querySelector('.menu-editor-row-kind-icon[data-kind="home"]');
+ expect(icon).not.toBeNull();
+ expect(screen.queryByText(/^page$/i)).not.toBeInTheDocument();
+ expect(screen.queryByText(/^submenu$/i)).not.toBeInTheDocument();
+ });
+
});