diff --git a/src/renderer/components/MenuEditorView/MenuEditorView.tsx b/src/renderer/components/MenuEditorView/MenuEditorView.tsx
index 0798b94..c19a6de 100644
--- a/src/renderer/components/MenuEditorView/MenuEditorView.tsx
+++ b/src/renderer/components/MenuEditorView/MenuEditorView.tsx
@@ -226,12 +226,29 @@ export const MenuEditorView: React.FC = () => {
]);
const metadataEntries = Object.entries(projectMetadata?.categoryMetadata ?? {});
- setCategoryTitlesByName(Object.fromEntries(
+ const categoryTitleMap = Object.fromEntries(
metadataEntries.map(([name, metadata]) => [name, metadata.title?.trim() || name]),
- ));
+ );
+ setCategoryTitlesByName(categoryTitleMap);
- setItems(menu.items);
- setSelectedId(menu.items[0]?.id ?? null);
+ const normalizedItems = mapItems(menu.items, (item) => {
+ if (item.kind !== 'category-archive' || !item.categoryName) {
+ return item;
+ }
+
+ const metadataTitle = categoryTitleMap[item.categoryName]?.trim();
+ if (!metadataTitle || metadataTitle === item.title) {
+ return item;
+ }
+
+ return {
+ ...item,
+ title: metadataTitle,
+ };
+ });
+
+ setItems(normalizedItems);
+ setSelectedId(normalizedItems[0]?.id ?? null);
} catch (error) {
console.error('Failed to load menu:', error);
showToast.error(tr('menuEditor.loadError'));
diff --git a/tests/renderer/components/MenuEditorView.test.tsx b/tests/renderer/components/MenuEditorView.test.tsx
index 88b904e..1999e6e 100644
--- a/tests/renderer/components/MenuEditorView.test.tsx
+++ b/tests/renderer/components/MenuEditorView.test.tsx
@@ -243,6 +243,42 @@ describe('MenuEditorView entry editor', () => {
expect(screen.queryByText(/^news$/i)).not.toBeInTheDocument();
});
+ it('saves existing category archive entries with metadata title while keeping category slug', async () => {
+ (window as any).electronAPI.menu.get = vi.fn().mockResolvedValue({
+ items: [
+ {
+ id: 'menu-home',
+ title: 'Home',
+ kind: 'home',
+ pageSlug: 'home',
+ children: [],
+ },
+ {
+ id: 'cat-news',
+ title: 'news',
+ kind: 'category-archive',
+ categoryName: 'news',
+ children: [],
+ },
+ ],
+ });
+
+ render();
+
+ await screen.findByText('Newsroom');
+ const saveButton = screen.getByRole('button', { name: /^save menu$/i });
+ fireEvent.click(saveButton);
+
+ const saveMock = (window as any).electronAPI.menu.save;
+ expect(saveMock).toHaveBeenCalled();
+ const payload = saveMock.mock.calls[0][0];
+
+ const categoryItem = payload.items.find((item: any) => item.id === 'cat-news');
+ expect(categoryItem).toBeDefined();
+ expect(categoryItem.title).toBe('Newsroom');
+ expect(categoryItem.categoryName).toBe('news');
+ });
+
it('disables delete action when Home entry is selected', async () => {
render();