feat: reworked the category editing

This commit is contained in:
2026-07-24 09:00:12 +02:00
parent d9085cf681
commit 7a3c5683e7
23 changed files with 471 additions and 193 deletions

View File

@@ -14,7 +14,6 @@ value SettingsView {
active_sections: List<String> -- visible sections after search filter
project_section: SettingsProjectSection?
editor_section: SettingsEditorSection?
categories: List<SettingsCategoryRow>
ai_section: SettingsAISection?
technology_section: SettingsTechnologySection?
publishing_section: SettingsPublishingSection?
@@ -42,16 +41,6 @@ value SettingsEditorSection {
hide_unchanged_regions: Boolean -- checkbox
}
value SettingsCategoryRow {
name: String -- read-only for protected categories
title: String -- editable
render_in_lists: Boolean -- checkbox
show_titles: Boolean -- checkbox
post_template_slug: String? -- select
list_template_slug: String? -- select
is_protected: Boolean -- true for: article, aside, page, picture
}
value SettingsAISection {
online: SettingsAIEndpoint
airplane: SettingsAIEndpoint
@@ -97,11 +86,6 @@ value SettingsDataSection {
rebuild_targets: List<String> -- posts | media | scripts | templates | links | thumbnails | embedding
}
invariant SettingsProtectedCategories {
-- Protected categories (article, aside, page, picture) cannot be deleted.
-- Their Remove button is disabled.
}
invariant SettingsMCPAgents {
-- MCP section has exactly 7 agent rows in this order:
-- Claude Code, Claude Desktop, GitHub Copilot, Gemini CLI,

View File

@@ -314,6 +314,8 @@ value CategoryMetaJson {
value CategorySettings {
renderInLists: Boolean
showTitle: Boolean
title: String?
titles: Map<String, String>
postTemplateSlug: String?
listTemplateSlug: String?
}

View File

@@ -29,6 +29,7 @@ surface PublishingPreferencesSurface {
value CategoryRenderSettings {
title: String?
titles: Map<String, String> -- translated titles keyed by language
render_in_lists: Boolean
show_title: Boolean
post_template_slug: String?
@@ -78,7 +79,9 @@ invariant MetadataPersistedAsFiles {
-- sshMode, sshRemotePath, sshUser (nil keys absent; sshMode defaults to scp).
-- Category names and per-category keys are byte-order sorted; per-category
-- keys are listTemplateSlug, postTemplateSlug, renderInLists, showTitle,
-- title. categories.json uses case-sensitive byte-order sorting. tags.json
-- title, titles. The title is for the main language; titles contains
-- configured translations keyed by language. categories.json uses
-- case-sensitive byte-order sorting. tags.json
-- remains case-insensitively name-sorted; entry keys are color, name,
-- postTemplateSlug and blank optional values are absent.
}

View File

@@ -222,6 +222,13 @@ rule BuildListAssigns {
ensures: ListRenderAssigns
}
invariant CategoryArchiveTitleLanguage {
-- A category archive uses the title configured for its render language.
-- The main-language archive uses title; translated archives use the entry
-- in titles keyed by their language; a missing title falls back to the
-- category name.
}
invariant SharedRenderPathForPreviewAndGeneration {
-- Preview and generation produce identical HTML for the same input because
-- both build assigns through this subsystem and render via the same Liquid

View File

@@ -447,16 +447,15 @@ value SettingsNavEntry {
}
invariant SettingsNavSections {
-- Settings navigation has exactly 9 entries in this fixed order:
-- Settings navigation has exactly 8 entries in this fixed order:
-- 1. section="project", icon="folder", label_key="settings.nav.project"
-- 2. section="editor", icon="notepad", label_key="settings.nav.editor"
-- 3. section="content", icon="clipboard", label_key="settings.nav.content"
-- 4. section="ai", icon="robot", label_key="settings.nav.ai"
-- 5. section="technology", icon="gear", label_key="settings.nav.technology"
-- 6. section="publishing", icon="rocket", label_key="settings.nav.publishing"
-- 7. section="data", icon="database", label_key="settings.nav.data"
-- 8. section="mcp", icon="plug", label_key="settings.nav.mcp"
-- 9. section="style", icon="palette", label_key="settings.nav.style"
-- 3. section="ai", icon="robot", label_key="settings.nav.ai"
-- 4. section="technology", icon="gear", label_key="settings.nav.technology"
-- 5. section="publishing", icon="rocket", label_key="settings.nav.publishing"
-- 6. section="data", icon="database", label_key="settings.nav.data"
-- 7. section="mcp", icon="plug", label_key="settings.nav.mcp"
-- 8. section="style", icon="palette", label_key="settings.nav.style"
-- Labels are localised via their label_key through i18n.
}
@@ -513,10 +512,11 @@ value TagsNavEntry {
}
invariant TagsNavSections {
-- Tags navigation has exactly 3 entries in this fixed order:
-- Tags navigation has exactly 4 entries in this fixed order:
-- 1. section="cloud", icon="cloud", label_key="tags.nav.cloud" -- tag cloud visualisation
-- 2. section="manage", icon="pencil", label_key="tags.nav.manage" -- create/edit tags
-- 3. section="merge", icon="merge", label_key="tags.nav.merge" -- merge duplicate tags
-- 4. section="categories", icon="list", label_key="tags.nav.categories" -- edit categories
-- Labels are localised via their label_key through i18n.
}
@@ -559,6 +559,39 @@ rule TagsNavClick {
-- Active section is persisted across sidebar switches
}
value CategoryEditor {
main_language: String
translation_languages: List<String>
rows: List<CategoryEditorRow>
}
value CategoryEditorRow {
name: String
titles: Map<String, String>
render_in_lists: Boolean
show_title: Boolean
post_template_slug: String?
list_template_slug: String?
is_protected: Boolean
}
surface CategoryEditorSurface {
context editor: CategoryEditor
exposes:
editor.main_language
editor.translation_languages
editor.rows.count
@guarantee TableLayout
-- Category settings render as one table. Its first title column is the
-- main language and every configured translation language adds one
-- further title column.
@guarantee ProtectedCategories
-- article, aside, page, and picture cannot be removed.
}
-- ─── 8. Chat view ─────────────────────────────────────────────
-- Follows SidebarEntityListPattern.