diff --git a/.phpunit.cache/test-results b/.phpunit.cache/test-results deleted file mode 100644 index 9c6c18b..0000000 --- a/.phpunit.cache/test-results +++ /dev/null @@ -1 +0,0 @@ -{"version":2,"defects":[],"times":{"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testGetTokensReturnsNonEmptyArray":0.016,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testEveryTokenHasRequiredKeys":0.005,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testTokenNamesStartWithDoubleDash":0.002,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testTokenTypesAreValid":0.002,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testTokenTabsAreValid":0.002,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testGetTabLabelsCoversAllTabs":0.001,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testGetTokenNamesMatchesGetTokensKeys":0.002,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testIsEditableReturnsTrueForKnownToken":0.001,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testIsEditableReturnsFalseForUnknownToken":0.001,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testGetTokensByTabGroupsCorrectly":0.003,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testGetTokensByTabPreservesAllTokens":0,"OCA\\NLDesign\\Tests\\Unit\\Service\\TokenRegistryTest::testColorPrimaryIsInLoginTab":0.001}} \ No newline at end of file diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index fbf914c..08df751 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -17,7 +17,11 @@ const config = { i18n: { defaultLocale: 'en', - locales: ['en'], + locales: ['en', 'nl'], + localeConfigs: { + en: { label: 'English' }, + nl: { label: 'Nederlands' }, + }, }, presets: [ @@ -27,9 +31,10 @@ const config = { ({ docs: { path: './', + exclude: ['**/node_modules/**'], sidebarPath: require.resolve('./sidebars.js'), editUrl: - 'https://github.com/ConductionNL/nldesign/tree/main/docusaurus/', + 'https://github.com/ConductionNL/nldesign/tree/main/docs/', }, blog: false, theme: { @@ -60,6 +65,10 @@ const config = { label: 'GitHub', position: 'right', }, + { + type: 'localeDropdown', + position: 'right', + }, ], }, footer: { diff --git a/docs/features/README.md b/docs/features/README.md new file mode 100644 index 0000000..cdc4b18 --- /dev/null +++ b/docs/features/README.md @@ -0,0 +1,49 @@ +# NL Design — Features + +NL Design is a Nextcloud theming app that applies Dutch government design standards (Rijkshuisstijl and other NL Design System token sets) to every part of the Nextcloud interface. It functions as a Nextcloud Theme Editor: administrators select a pre-built organization token set or fine-tune individual CSS variables, and the result is propagated to both the NL Design CSS layer and Nextcloud's built-in theming system. + +NL Design has no direct GEMMA component mapping — it is a cross-cutting infrastructure concern that ensures WCAG AA accessibility and Dutch government branding across all Conduction apps. + +## Standards Compliance + +| Standard | Status | Description | +|----------|--------|-------------| +| NL Design System | Beschikbaar | `--nldesign-*` token namespace; 39+ organization token sets | +| Rijkshuisstijl | Beschikbaar | National government visual identity token set | +| WCAG 2.1 AA | Beschikbaar | Contrast, font size, and spacing tokens enforced per token set | +| Digitoegankelijk (EN 301 549) | Beschikbaar | Accessible colour and typography via design tokens | +| DCAT-AP NL | N.v.t. | Not applicable — theming layer only | + +## Features + +| Feature | Description | Docs | +|---------|-------------|------| +| [Token Sets](./token-sets.md) | 39+ organization-specific CSS token sets; searchable dropdown; auto-generated from upstream NL Design System | [token-sets.md](./token-sets.md) | +| [Token Editor UI](./token-editor.md) | Tabbed admin panel for editing all Nextcloud `--color-*` CSS variables with live preview and per-token reset | [token-editor.md](./token-editor.md) | +| [CSS Architecture](./css-architecture.md) | 7-layer CSS load order: design system → token set → custom overrides; `design-systems.json` controls bundles | [css-architecture.md](./css-architecture.md) | +| [Custom CSS Overrides](./css-architecture.md) | `custom-overrides.css` — single write target for all edits; loaded last; token set files are read-only | [css-architecture.md](./css-architecture.md) | +| [Token Set Apply Dialog](./apply-dialog.md) | Before applying a token set, shows old → new value diff per token; admin checks/unchecks individual changes | [apply-dialog.md](./apply-dialog.md) | +| [Theming Sync](./theming-sync.md) | After token set selection, syncs Nextcloud's primary color and background color via the theming API | [theming-sync.md](./theming-sync.md) | +| [Token Import/Export](./import-export.md) | Download `custom-overrides.css`; upload a saved file to restore or share a token configuration | [import-export.md](./import-export.md) | +| [Admin Settings](./admin-settings.md) | Admin panel under Theming: token set selector, toggles (hide slogan, show menu labels), token editor | [admin-settings.md](./admin-settings.md) | +| [Hide Slogan](./toggles.md) | Removes Nextcloud's default login-page slogan for a clean government-branded login | [toggles.md](./toggles.md) | +| [Show Menu Labels](./toggles.md) | Replaces header app icons with text labels; improves discoverability per Dutch government UX guidelines | [toggles.md](./toggles.md) | +| [Component Tokens](./token-sets.md) | `--nldesign-component-*` prefix bridging `--utrecht-*` component tokens to the nldesign namespace | [token-sets.md](./token-sets.md) | +| [App Compatibility](./app-compatibility.md) | Integration guide for other Nextcloud apps to ensure CSS-variable compatibility with nldesign | [app-compatibility.md](./app-compatibility.md) | +| [Prometheus Metrics](./css-architecture.md) | Active token set, custom override count, theming sync operations — in Prometheus text format | — | + +## Architecture + +NL Design operates as a pure CSS layer — no database tables. Configuration is stored in `IAppConfig`. The CSS stack loads in a defined order: + +1. Design system base CSS (`design-systems.json` bundle) +2. Organization token set (`css/tokens/{id}.css`) +3. Custom overrides (`custom-overrides.css`) — always loaded last + +The token sync workflow (nightly GitHub Actions) pulls updates from the upstream `nl-design-system/themes` repository and opens PRs when token changes are detected. + +## GEMMA Mapping + +| GEMMA Component | NL Design Role | +|-----------------|----------------| +| N.v.t. | Cross-cutting theming infrastructure for all Conduction Nextcloud apps | diff --git a/docs/i18n/nl/code.json b/docs/i18n/nl/code.json new file mode 100644 index 0000000..5aaed38 --- /dev/null +++ b/docs/i18n/nl/code.json @@ -0,0 +1,329 @@ +{ + "theme.ErrorPageContent.title": { + "message": "Deze pagina is gecrasht.", + "description": "The title of the fallback page when the page crashed" + }, + "theme.BackToTopButton.buttonAriaLabel": { + "message": "Scroll naar boven", + "description": "The ARIA label for the back to top button" + }, + "theme.blog.archive.title": { + "message": "Archief", + "description": "The page & hero title of the blog archive page" + }, + "theme.blog.archive.description": { + "message": "Archief", + "description": "The page & hero description of the blog archive page" + }, + "theme.blog.paginator.navAriaLabel": { + "message": "Paginanavigatie blog", + "description": "The ARIA label for the blog pagination" + }, + "theme.blog.paginator.newerEntries": { + "message": "Nieuwere items", + "description": "The label used to navigate to the newer blog posts page (previous page)" + }, + "theme.blog.paginator.olderEntries": { + "message": "Oudere items", + "description": "The label used to navigate to the older blog posts page (next page)" + }, + "theme.blog.post.paginator.navAriaLabel": { + "message": "Paginanavigatie blog", + "description": "The ARIA label for the blog posts pagination" + }, + "theme.blog.post.paginator.newerPost": { + "message": "Nieuwer bericht", + "description": "The blog post button label to navigate to the newer/previous post" + }, + "theme.blog.post.paginator.olderPost": { + "message": "Ouder bericht", + "description": "The blog post button label to navigate to the older/next post" + }, + "theme.tags.tagsPageLink": { + "message": "Laat alle tags zien", + "description": "The label of the link targeting the tag list page" + }, + "theme.colorToggle.ariaLabel.mode.system": { + "message": "system mode", + "description": "The name for the system color mode" + }, + "theme.colorToggle.ariaLabel.mode.light": { + "message": "lichte modus", + "description": "The name for the light color mode" + }, + "theme.colorToggle.ariaLabel.mode.dark": { + "message": "donkere modus", + "description": "The name for the dark color mode" + }, + "theme.colorToggle.ariaLabel": { + "message": "Schakel tussen donkere en lichte modus (momenteel {mode})", + "description": "The ARIA label for the color mode toggle" + }, + "theme.docs.breadcrumbs.navAriaLabel": { + "message": "Broodkruimels", + "description": "The ARIA label for the breadcrumbs" + }, + "theme.docs.DocCard.categoryDescription.plurals": { + "message": "1 artikel|{count} artikelen", + "description": "The default description for a category card in the generated index about how many items this category includes" + }, + "theme.docs.paginator.navAriaLabel": { + "message": "Documentatie pagina", + "description": "The ARIA label for the docs pagination" + }, + "theme.docs.paginator.previous": { + "message": "Vorige", + "description": "The label used to navigate to the previous doc" + }, + "theme.docs.paginator.next": { + "message": "Volgende", + "description": "The label used to navigate to the next doc" + }, + "theme.docs.tagDocListPageTitle.nDocsTagged": { + "message": "Een artikel getagd|{count} artikelen getagd", + "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.docs.tagDocListPageTitle": { + "message": "{nDocsTagged} met \"{tagName}\"", + "description": "The title of the page for a docs tag" + }, + "theme.docs.versionBadge.label": { + "message": "Versie: {versionLabel}" + }, + "theme.docs.versions.unreleasedVersionLabel": { + "message": "Dit is nog niet uitgegeven documentatie voor {siteTitle}, versie {versionLabel}", + "description": "The label used to tell the user that he's browsing an unreleased doc version" + }, + "theme.docs.versions.unmaintainedVersionLabel": { + "message": "Dit is de documentatie voor {siteTitle} {versionLabel}, welke niet langer actief wordt onderhouden.", + "description": "The label used to tell the user that he's browsing an unmaintained doc version" + }, + "theme.docs.versions.latestVersionSuggestionLabel": { + "message": "Voor de huidige documentatie, zie de {latestVersionLink} ({versionLabel}).", + "description": "The label used to tell the user to check the latest version" + }, + "theme.docs.versions.latestVersionLinkLabel": { + "message": "laatste versie", + "description": "The label used for the latest version suggestion link label" + }, + "theme.common.editThisPage": { + "message": "Bewerk deze pagina", + "description": "The link label to edit the current page" + }, + "theme.common.headingLinkTitle": { + "message": "Direct link naar {heading}", + "description": "Title for link to heading" + }, + "theme.lastUpdated.atDate": { + "message": " op {date}", + "description": "The words used to describe on which date a page has been last updated" + }, + "theme.lastUpdated.byUser": { + "message": " door {user}", + "description": "The words used to describe by who the page has been last updated" + }, + "theme.lastUpdated.lastUpdatedAtBy": { + "message": "Laatst bijgewerkt{atDate}{byUser}", + "description": "The sentence used to display when a page has been last updated, and by who" + }, + "theme.navbar.mobileVersionsDropdown.label": { + "message": "Versies", + "description": "The label for the navbar versions dropdown on mobile view" + }, + "theme.NotFound.title": { + "message": "Pagina niet gevonden", + "description": "The title of the 404 page" + }, + "theme.tags.tagsListLabel": { + "message": "Tags:", + "description": "The label alongside a tag list" + }, + "theme.admonition.caution": { + "message": "pas op", + "description": "The default label used for the Caution admonition (:::caution)" + }, + "theme.admonition.danger": { + "message": "gevaar", + "description": "The default label used for the Danger admonition (:::danger)" + }, + "theme.admonition.info": { + "message": "info", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.admonition.note": { + "message": "notitie", + "description": "The default label used for the Note admonition (:::note)" + }, + "theme.admonition.tip": { + "message": "tip", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.warning": { + "message": "waarschuwing", + "description": "The default label used for the Warning admonition (:::warning)" + }, + "theme.AnnouncementBar.closeButtonAriaLabel": { + "message": "Sluiten", + "description": "The ARIA label for close button of announcement bar" + }, + "theme.blog.sidebar.navAriaLabel": { + "message": "Navigatie recente blogitems", + "description": "The ARIA label for recent posts in the blog sidebar" + }, + "theme.DocSidebarItem.expandCategoryAriaLabel": { + "message": "Categorie zijbalk uitklappen '{label}'", + "description": "The ARIA label to expand the sidebar category" + }, + "theme.DocSidebarItem.collapseCategoryAriaLabel": { + "message": "Categorie zijbalk inklappen '{label}'", + "description": "The ARIA label to collapse the sidebar category" + }, + "theme.IconExternalLink.ariaLabel": { + "message": "(opens in new tab)", + "description": "The ARIA label for the external link icon" + }, + "theme.NavBar.navAriaLabel": { + "message": "Main", + "description": "The ARIA label for the main navigation" + }, + "theme.navbar.mobileLanguageDropdown.label": { + "message": "Talen", + "description": "The label for the mobile language switcher dropdown" + }, + "theme.NotFound.p1": { + "message": "We kunnen niet vinden waar je naar op zoek bent.", + "description": "The first paragraph of the 404 page" + }, + "theme.NotFound.p2": { + "message": "Neem contact op met de eigenaar van de website die naar de originele URL heeft geleid en laat weten dat de link niet meer werkt.", + "description": "The 2nd paragraph of the 404 page" + }, + "theme.TOCCollapsible.toggleButtonLabel": { + "message": "Op deze pagina", + "description": "The label used by the button on the collapsible TOC component" + }, + "theme.blog.post.readMore": { + "message": "Lees meer", + "description": "The label used in blog post item excerpts to link to full blog posts" + }, + "theme.blog.post.readMoreLabel": { + "message": "Lees meer over {title}", + "description": "The ARIA label for the link to full blog posts from excerpts" + }, + "theme.blog.post.readingTime.plurals": { + "message": "Een minuut leestijd|{readingTime} minuten leestijd", + "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.CodeBlock.copy": { + "message": "Kopieer", + "description": "The copy button label on code blocks" + }, + "theme.CodeBlock.copied": { + "message": "Gekopieerd", + "description": "The copied button label on code blocks" + }, + "theme.CodeBlock.copyButtonAriaLabel": { + "message": "Kopieer code naar klembord", + "description": "The ARIA label for copy code blocks button" + }, + "theme.CodeBlock.wordWrapToggle": { + "message": "Tekstterugloop in-/uitschakelen", + "description": "The title attribute for toggle word wrapping button of code block lines" + }, + "theme.docs.breadcrumbs.home": { + "message": "Homepagina", + "description": "The ARIA label for the home page in the breadcrumbs" + }, + "theme.docs.sidebar.collapseButtonTitle": { + "message": "Zijbalk inklappen", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.collapseButtonAriaLabel": { + "message": "Zijbalk inklappen", + "description": "The title attribute for collapse button of doc sidebar" + }, + "theme.docs.sidebar.navAriaLabel": { + "message": "Docs zijbalk", + "description": "The ARIA label for the sidebar navigation" + }, + "theme.docs.sidebar.closeSidebarButtonAriaLabel": { + "message": "Sluit navigatiebalk", + "description": "The ARIA label for close button of mobile sidebar" + }, + "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { + "message": "← Terug naar het hoofdmenu", + "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" + }, + "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { + "message": "Navigatiebalk schakelen", + "description": "The ARIA label for hamburger menu button of mobile navigation" + }, + "theme.navbar.mobileDropdown.collapseButton.expandAriaLabel": { + "message": "Expand the dropdown", + "description": "The ARIA label of the button to expand the mobile dropdown navbar item" + }, + "theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel": { + "message": "Collapse the dropdown", + "description": "The ARIA label of the button to collapse the mobile dropdown navbar item" + }, + "theme.docs.sidebar.expandButtonTitle": { + "message": "Zijbalk uitklappen", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.docs.sidebar.expandButtonAriaLabel": { + "message": "Zijbalk uitklappen", + "description": "The ARIA label and title attribute for expand button of doc sidebar" + }, + "theme.blog.post.plurals": { + "message": "Een bericht|{count} berichten", + "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" + }, + "theme.blog.tagTitle": { + "message": "{nPosts} getagd met \"{tagName}\"", + "description": "The title of the page for a blog tag" + }, + "theme.blog.author.pageTitle": { + "message": "{authorName} - {nPosts}", + "description": "The title of the page for a blog author" + }, + "theme.blog.authorsList.pageTitle": { + "message": "Auteurs", + "description": "The title of the authors page" + }, + "theme.blog.authorsList.viewAll": { + "message": "Bekijk alle auteurs", + "description": "The label of the link targeting the blog authors page" + }, + "theme.blog.author.noPosts": { + "message": "Deze auteur heeft nog geen berichten geschreven.", + "description": "The text for authors with 0 blog post" + }, + "theme.contentVisibility.unlistedBanner.title": { + "message": "Verborgen page", + "description": "The unlisted content banner title" + }, + "theme.contentVisibility.unlistedBanner.message": { + "message": "Deze pagina is verborgen. Zoekmachines indexeren deze niet en alleen gebruikers met een directe link kunnen deze openen.", + "description": "The unlisted content banner message" + }, + "theme.contentVisibility.draftBanner.title": { + "message": "Concept pagina", + "description": "The draft content banner title" + }, + "theme.contentVisibility.draftBanner.message": { + "message": "Deze pagina is een concept. Deze zal alleen zichtbaar zijn in de ontwikkelomgeving en uitgesloten worden van de productie build.", + "description": "The draft content banner message" + }, + "theme.ErrorPageContent.tryAgain": { + "message": "Probeer opnieuw", + "description": "The label of the button to try again rendering when the React error boundary captures an error" + }, + "theme.common.skipToMainContent": { + "message": "Ga naar hoofdinhoud", + "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" + }, + "theme.tags.tagsPageTitle": { + "message": "Tags", + "description": "The title of the tag list page" + } +} diff --git a/docs/i18n/nl/docusaurus-plugin-content-docs/current.json b/docs/i18n/nl/docusaurus-plugin-content-docs/current.json new file mode 100644 index 0000000..2533eba --- /dev/null +++ b/docs/i18n/nl/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,18 @@ +{ + "version.label": { + "message": "Volgende", + "description": "The label for version current" + }, + "sidebar.tutorialSidebar.category.Getting Started": { + "message": "Aan de slag", + "description": "The label for category 'Getting Started' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.Features": { + "message": "Functionaliteiten", + "description": "The label for category 'Features' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.Reference": { + "message": "Referentie", + "description": "The label for category 'Reference' in sidebar 'tutorialSidebar'" + } +} diff --git a/docs/i18n/nl/docusaurus-theme-classic/footer.json b/docs/i18n/nl/docusaurus-theme-classic/footer.json new file mode 100644 index 0000000..16db0a4 --- /dev/null +++ b/docs/i18n/nl/docusaurus-theme-classic/footer.json @@ -0,0 +1,22 @@ +{ + "link.title.Docs": { + "message": "Documentatie", + "description": "The title of the footer links column with title=Docs in the footer" + }, + "link.title.Community": { + "message": "Community", + "description": "The title of the footer links column with title=Community in the footer" + }, + "link.item.label.Documentation": { + "message": "Documentatie", + "description": "The label of footer link with label=Documentation linking to /docs" + }, + "link.item.label.GitHub": { + "message": "GitHub", + "description": "The label of footer link with label=GitHub linking to https://github.com/ConductionNL/nldesign" + }, + "copyright": { + "message": "Copyright © 2026 for Open Webconcept by Conduction B.V.", + "description": "The footer copyright" + } +} diff --git a/docs/i18n/nl/docusaurus-theme-classic/navbar.json b/docs/i18n/nl/docusaurus-theme-classic/navbar.json new file mode 100644 index 0000000..6f6de27 --- /dev/null +++ b/docs/i18n/nl/docusaurus-theme-classic/navbar.json @@ -0,0 +1,18 @@ +{ + "title": { + "message": "NL Design", + "description": "The title in the navbar" + }, + "logo.alt": { + "message": "NL Design Logo", + "description": "The alt text of navbar logo" + }, + "item.label.Documentation": { + "message": "Documentatie", + "description": "Navbar item with label Documentation" + }, + "item.label.GitHub": { + "message": "GitHub", + "description": "Navbar item with label GitHub" + } +} diff --git a/docs/screenshots/.gitkeep b/docs/screenshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/openspec/changes/archive/2026-02-15-add-vng-token-set/specs/vng-token-set/spec.md b/openspec/changes/archive/2026-02-15-add-vng-token-set/specs/vng-token-set/spec.md index 50c9ec7..23ef96a 100644 --- a/openspec/changes/archive/2026-02-15-add-vng-token-set/specs/vng-token-set/spec.md +++ b/openspec/changes/archive/2026-02-15-add-vng-token-set/specs/vng-token-set/spec.md @@ -3,7 +3,7 @@ ## Purpose Define requirements for adding VNG (Vereniging Nederlandse Gemeenten) as a selectable design token set in the nldesign Nextcloud app. VNG tokens are manually converted from the tilburg-woo-ui project since they are not available in the upstream nl-design-system/themes repository. -## ADDED Requirements +## Requirements ### Requirement: VNG Token CSS File The system MUST provide a `css/tokens/vng.css` file containing VNG design tokens in `:root` scope with `--nldesign-*` semantic tokens and `--vng-*` organization palette tokens. diff --git a/openspec/changes/archive/2026-03-02-enhance-docs-website/specs/docs-content/spec.md b/openspec/changes/archive/2026-03-02-enhance-docs-website/specs/docs-content/spec.md index 0df2c26..3eaf78f 100644 --- a/openspec/changes/archive/2026-03-02-enhance-docs-website/specs/docs-content/spec.md +++ b/openspec/changes/archive/2026-03-02-enhance-docs-website/specs/docs-content/spec.md @@ -1,4 +1,4 @@ -## ADDED Requirements +## Requirements ### Requirement: Documentation landing page The documentation site SHALL have an `intro.md` file at `docs/intro.md` that serves as the entry point for all documentation. It SHALL provide a high-level overview of what nldesign is, link to key sections (getting started, features, reference), and use the Docusaurus `slug: /` frontmatter to become the docs root. diff --git a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/custom-css-overrides/spec.md b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/custom-css-overrides/spec.md index 70a4ed9..64545ee 100644 --- a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/custom-css-overrides/spec.md +++ b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/custom-css-overrides/spec.md @@ -3,7 +3,7 @@ ## Purpose Defines the CSS file persistence layer for user-defined token customizations. `custom-overrides.css` is the single write target for all theme editor output. It is loaded last in the CSS stack so user intent always wins. NL Design token set CSS files are read-only presets and are never modified. -## ADDED Requirements +## Requirements ### Requirement: Custom Overrides File The system MUST maintain a `custom-overrides.css` file in the nldesign app's CSS directory. This file MUST be written exclusively by the theme editor backend — no other write path exists. diff --git a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/nl-design/spec.md b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/nl-design/spec.md index 20806cf..f4a9892 100644 --- a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/nl-design/spec.md +++ b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/nl-design/spec.md @@ -29,7 +29,7 @@ The nldesign app MUST support all organization token sets available in the confi - AND `custom-overrides.css` MUST remain unchanged - AND no visual change MUST persist -## ADDED Requirements +## Requirements ### Requirement: App Identity The app MUST be positioned as a **Nextcloud Theme Editor with NL Design System support** in its user-facing name, description, and admin settings heading. The scope is broader than NL Design loading: it encompasses editing any Nextcloud CSS custom property. diff --git a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-editor-ui/spec.md b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-editor-ui/spec.md index bb56262..a059d05 100644 --- a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-editor-ui/spec.md +++ b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-editor-ui/spec.md @@ -3,7 +3,7 @@ ## Purpose Provides a tabbed admin settings panel for browsing and editing all editable Nextcloud CSS custom properties (`--color-*`) with live preview and per-token reset controls. Changes are previewed in the browser before being committed to `custom-overrides.css`. -## ADDED Requirements +## Requirements ### Requirement: Token Editor Panel The admin settings page MUST include a token editor panel below the existing NL Design token-set selector. The panel MUST be rendered as a Vue component within the existing nldesign admin settings template. diff --git a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-import-export/spec.md b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-import-export/spec.md index 1069565..faf8b2f 100644 --- a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-import-export/spec.md +++ b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-import-export/spec.md @@ -3,7 +3,7 @@ ## Purpose Allows admins to download the current `custom-overrides.css` as a portable file and upload a previously saved file to restore or share a token configuration. Only known, editable Nextcloud `--color-*` tokens are accepted on import — unknown variables are silently rejected and their count is reported. -## ADDED Requirements +## Requirements ### Requirement: Export Current Overrides The admin settings panel MUST provide a **Download** button that exports the current `custom-overrides.css` as a file download. diff --git a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-set-apply-dialog/spec.md b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-set-apply-dialog/spec.md index 07998a6..b2daa33 100644 --- a/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-set-apply-dialog/spec.md +++ b/openspec/changes/archive/2026-03-03-nextcloud-theme-editor/specs/token-set-apply-dialog/spec.md @@ -3,7 +3,7 @@ ## Purpose Defines the modal dialog shown when an admin selects a new NL Design token set. The dialog shows which Nextcloud CSS variable values would change (resolved current value vs the value from the new token set), lets the admin check or uncheck individual changes, and writes only the checked values to `custom-overrides.css`. The NL Design token set CSS file itself is never applied directly. -## ADDED Requirements +## Requirements ### Requirement: Dialog Trigger Selecting a different NL Design token set from the selector MUST open the apply dialog instead of immediately switching themes. diff --git a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/component-tokens/spec.md b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/component-tokens/spec.md index d85648e..4841a49 100644 --- a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/component-tokens/spec.md +++ b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/component-tokens/spec.md @@ -3,7 +3,7 @@ ## Purpose Introduces component-level NL Design System tokens using the `--nldesign-component-*` prefix, with a temporary bridge file that maps the current `--utrecht-*` component tokens to the nldesign namespace. -## ADDED Requirements +## Requirements ### Requirement: NLDesign Component Token Prefix All component-level tokens MUST use the `--nldesign-component-*` prefix for consistency with the rest of the nldesign token system. diff --git a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/extended-token-sets/spec.md b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/extended-token-sets/spec.md index 724fe6f..a5f0606 100644 --- a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/extended-token-sets/spec.md +++ b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/extended-token-sets/spec.md @@ -3,7 +3,7 @@ ## Purpose Expands the nldesign app from 5 manually maintained token sets to all available NL Design System organization token sets (48+), using auto-generation from official upstream JSON token files. -## ADDED Requirements +## Requirements ### Requirement: Support All Available Token Sets The system MUST support all organization token sets available in the `nl-design-system/themes` repository. diff --git a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/nextcloud-variable-mapping/spec.md b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/nextcloud-variable-mapping/spec.md index 1e5c71c..0d7506b 100644 --- a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/nextcloud-variable-mapping/spec.md +++ b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/nextcloud-variable-mapping/spec.md @@ -3,7 +3,7 @@ ## Purpose Provides a complete, audited mapping between all Nextcloud CSS custom properties and `--nldesign-*` design tokens, with comprehensive documentation and a defaults layer that ensures all tokens always have a value. -## ADDED Requirements +## Requirements ### Requirement: Complete Nextcloud Variable Audit The system MUST include a mapping for every CSS custom property defined by Nextcloud's theming system (DefaultTheme.php, CommonThemeTrait.php, and core SCSS files). diff --git a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/token-sync-workflow/spec.md b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/token-sync-workflow/spec.md index ef90804..59c81d4 100644 --- a/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/token-sync-workflow/spec.md +++ b/openspec/changes/archive/2026-03-06-full-nextcloud-token-support-from-nldesign/specs/token-sync-workflow/spec.md @@ -3,7 +3,7 @@ ## Purpose Automates the synchronization of NL Design System token sets from the upstream `nl-design-system/themes` repository via a nightly GitHub Actions workflow that generates CSS token files and opens PRs when changes are detected. -## ADDED Requirements +## Requirements ### Requirement: Nightly Schedule The sync workflow MUST run automatically every night to check for upstream token changes. diff --git a/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/theming-sync-dialog/spec.md b/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/theming-sync-dialog/spec.md index f6e5eb6..dfd165a 100644 --- a/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/theming-sync-dialog/spec.md +++ b/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/theming-sync-dialog/spec.md @@ -3,7 +3,7 @@ ## Purpose After an admin selects a different token set in nldesign, offer to automatically update Nextcloud's built-in theming values (primary color, background color, logo, background image) to match the selected token set, preventing a split-brain theming state where CSS tokens and Nextcloud theming are out of sync. -## ADDED Requirements +## Requirements ### Requirement: Theming Metadata in Token Sets Each token set entry in `token-sets.json` MAY include a `theming` object with optional fields: `primary_color`, `background_color`, `logo`, and `background`. diff --git a/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/token-set-dropdown/spec.md b/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/token-set-dropdown/spec.md index 1c06634..b36cd99 100644 --- a/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/token-set-dropdown/spec.md +++ b/openspec/changes/archive/2026-03-06-sync-theming-on-token-change/specs/token-set-dropdown/spec.md @@ -3,7 +3,7 @@ ## Purpose Replace the radio button list for token set selection with a searchable dropdown (`` dropdown instead of radio buttons for token set selection. diff --git a/openspec/changes/archive/2026-03-21-admin-settings/.openspec.yaml b/openspec/changes/archive/2026-03-21-admin-settings/.openspec.yaml new file mode 100644 index 0000000..d8b0ed0 --- /dev/null +++ b/openspec/changes/archive/2026-03-21-admin-settings/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-20 diff --git a/openspec/changes/archive/2026-03-21-admin-settings/design.md b/openspec/changes/archive/2026-03-21-admin-settings/design.md new file mode 100644 index 0000000..5896e69 --- /dev/null +++ b/openspec/changes/archive/2026-03-21-admin-settings/design.md @@ -0,0 +1,20 @@ +# Design: admin-settings + +## Context +Admin settings panel in Nextcloud's Theming section. Vanilla PHP template + vanilla JS (no Vue/webpack). Provides token set dropdown, hide slogan toggle, menu labels toggle, live preview, token editor mount point, and theming sync trigger. + +## Goals / Non-Goals +**Goals:** Settings panel registration, template with all parameters, token set dropdown, feature toggles, live preview, XSS prevention +**Non-Goals:** Vue-based UI, per-user settings, real-time multi-admin sync + +## Decisions +1. Vanilla PHP template with script/style injection via Nextcloud helpers +2. All endpoints gated with `@AuthorizedAdminSetting` +3. Data attributes on root div for JS initialization +4. `p(json_encode(...))` for XSS prevention + +## File Changes +- `lib/Settings/Admin.php` — Panel registration and template response +- `templates/settings/admin.php` — PHP template with all controls +- `js/admin.js` — Vanilla JS event handlers +- `css/admin.css` — Admin panel styling diff --git a/openspec/changes/archive/2026-03-21-admin-settings/proposal.md b/openspec/changes/archive/2026-03-21-admin-settings/proposal.md new file mode 100644 index 0000000..3b1f66c --- /dev/null +++ b/openspec/changes/archive/2026-03-21-admin-settings/proposal.md @@ -0,0 +1,18 @@ +# Admin Settings Specification + +## Problem +Defines the admin settings panel for the NL Design app. The settings panel is located in Nextcloud's administration area under the Theming section. It provides controls for selecting the active token set, toggling the hide slogan feature, toggling show menu labels, and previewing the selected theme. The UI is built with vanilla PHP templates and vanilla JavaScript (no Vue or webpack). Additionally, the panel hosts the token editor for customizing individual Nextcloud CSS tokens, and triggers the theming sync dialog when a token set with theming metadata is selected. + +## Proposed Solution +Implement Admin Settings Specification following the detailed specification. Key requirements include: +- See full spec for detailed requirements + +## Scope +This change covers all requirements defined in the admin-settings specification. + +## Success Criteria +- Settings panel appears in admin area +- Settings panel position relative to Nextcloud theming +- Settings panel is absent when app is disabled +- Settings panel loads template with all parameters +- Token sets include design system metadata diff --git a/openspec/specs/admin-settings/design.md b/openspec/changes/archive/2026-03-21-admin-settings/specs/admin-settings/design.md similarity index 100% rename from openspec/specs/admin-settings/design.md rename to openspec/changes/archive/2026-03-21-admin-settings/specs/admin-settings/design.md diff --git a/openspec/changes/archive/2026-03-21-admin-settings/specs/admin-settings/spec.md b/openspec/changes/archive/2026-03-21-admin-settings/specs/admin-settings/spec.md new file mode 100644 index 0000000..a722233 --- /dev/null +++ b/openspec/changes/archive/2026-03-21-admin-settings/specs/admin-settings/spec.md @@ -0,0 +1,351 @@ +--- +status: implemented +reviewed_date: 2026-02-28 +enriched_date: 2026-03-20 +--- + +# Admin Settings Specification + +## Purpose +Defines the admin settings panel for the NL Design app. The settings panel is located in Nextcloud's administration area under the Theming section. It provides controls for selecting the active token set, toggling the hide slogan feature, toggling show menu labels, and previewing the selected theme. The UI is built with vanilla PHP templates and vanilla JavaScript (no Vue or webpack). Additionally, the panel hosts the token editor for customizing individual Nextcloud CSS tokens, and triggers the theming sync dialog when a token set with theming metadata is selected. + +## Requirements + +### REQ-ASET-001: Settings Panel Registration +The admin settings panel MUST be registered in the Nextcloud Theming section with a defined priority. + +#### Scenario: Settings panel appears in admin area +- GIVEN the nldesign app is enabled +- WHEN the admin navigates to Settings -> Administration -> Theming +- THEN an "NL Design System Theme" section MUST appear +- AND it MUST have priority 50 (via `Admin::getPriority()`) +- AND it MUST be in the `theming` section (via `Admin::getSection()`) + +#### Scenario: Settings panel position relative to Nextcloud theming +- GIVEN Nextcloud's built-in theming settings have default priority +- WHEN the admin views the Theming settings page +- THEN the NL Design section MUST appear below the default Nextcloud theming section +- AND both sections MUST be independently scrollable + +#### Scenario: Settings panel is absent when app is disabled +- GIVEN the nldesign app is not enabled +- WHEN the admin navigates to Settings -> Administration -> Theming +- THEN the "NL Design System Theme" section MUST NOT appear +- AND no nldesign CSS MUST be injected into the page + +### REQ-ASET-002: Template Response and Parameters +The settings form MUST return a `TemplateResponse` with all required parameters for the admin template. + +#### Scenario: Settings panel loads template with all parameters +- GIVEN the admin opens the NL Design settings panel +- WHEN `Admin::getForm()` is called +- THEN it MUST return a `TemplateResponse` for `settings/admin` +- AND the template parameters MUST include `tokenSets` (array of all available token sets from `TokenSetService::getAvailableTokenSets()`) +- AND the template parameters MUST include `currentTokenSet` (string, current active token set id, default `'nextcloud'`) +- AND the template parameters MUST include `hideSlogan` (boolean, from IConfig `hide_slogan` compared with `=== '1'`) +- AND the template parameters MUST include `showMenuLabels` (boolean, from IConfig `show_menu_labels` compared with `=== '1'`) + +#### Scenario: Token sets include design system metadata +- GIVEN `Admin::getForm()` retrieves token sets +- WHEN the `tokenSets` parameter is populated +- THEN each token set object MUST have `id`, `name`, `description`, and `design_system` fields +- AND token sets with theming metadata MUST include the `theming` object + +#### Scenario: Default values for fresh installation +- GIVEN nldesign is freshly installed with no configuration +- WHEN `Admin::getForm()` is called +- THEN `currentTokenSet` MUST be `'nextcloud'` +- AND `hideSlogan` MUST be `false` +- AND `showMenuLabels` MUST be `false` + +### REQ-ASET-003: Token Set Selector Dropdown +The settings panel MUST provide a searchable dropdown for selecting the active design token set from all available sets. + +#### Scenario: Dropdown populated with token sets +- GIVEN the settings panel is loaded +- AND there are multiple token sets available (discovered from `css/tokens/` directory) +- WHEN the dropdown renders +- THEN it MUST be a ` dropdown for token set selection, scaling to 400+ entries. + +## Decisions +1. Native HTML `) that scales to 400+ entries, improving usability as the number of available token sets grows. + +## Proposed Solution +Implement Token Set Dropdown Specification following the detailed specification. Key requirements include: +- Requirement: Dropdown Token Set Selector +- Requirement: Token Sets Sorted Alphabetically +- Requirement: Preview Updates on Selection + +## Scope +This change covers all requirements defined in the token-set-dropdown specification. + +## Success Criteria +- Dropdown renders with all token sets +- Dropdown is searchable via browser native behavior +- Token set selection triggers save +- Dropdown handles 400+ entries +- Token sets appear in alphabetical order diff --git a/openspec/changes/archive/2026-03-21-token-set-dropdown/specs/token-set-dropdown/spec.md b/openspec/changes/archive/2026-03-21-token-set-dropdown/specs/token-set-dropdown/spec.md new file mode 100644 index 0000000..fc1cb87 --- /dev/null +++ b/openspec/changes/archive/2026-03-21-token-set-dropdown/specs/token-set-dropdown/spec.md @@ -0,0 +1,55 @@ +--- +status: implemented +--- + +# Token Set Dropdown Specification + +## Purpose +Replace the radio button list for token set selection with a searchable dropdown (`` dropdown instead of radio buttons for token set selection. + +#### Scenario: Dropdown renders with all token sets +- GIVEN the admin opens nldesign settings +- WHEN the page loads +- THEN a `` element with id `nldesign-token-set-select` +- AND it MUST contain an `