This document is an onboarding note for the next maintainer.

The focus of this pass is to move the announcement system’s real source of truth out of config params and into theme data, so rendering, styling, and multilingual content all point to one consistent path.

Key changes in this pass

1) The real source of truth moved to themes/(0000-0000-0000-0001)/data/40-communication/announcement/_index.toml

Files:

  • themes/(0000-0000-0000-0001)/data/40-communication/announcement/_index.toml

Changes:

  • Centralized operational values for announcements in theme data.
  • enabled, strategy, defaultMode, defaultVariant, placement, and maxItems are now managed in one place.
  • Each announcement item now owns its own content block, while language-specific overrides live in data/40-communication/announcement/<lang>.toml.
  • Image, alt text, links, and CTA values are managed per announcement item through the same key structure.
  • Multiple samples remain in the file, but visibility is controlled by enabled and scope.

Why this matters:

  • The renderer now reads a layout-adjacent source, instead of depending on a config-only mental model.
  • Commit-level changes to copy, media, CTA, and visibility rules become much easier to review.
  • Maintainers can open the actual source immediately instead of searching through config fragments.

2) Settings calculation moved into theme/announcement-config.html

Files:

  • themes/(0000-0000-0000-0001)/layouts/partials/theme/announcement-config.html
  • themes/(0000-0000-0000-0001)/layouts/partials/theme/settings.html

Changes:

  • Theme data is read first; legacy params remain as a fallback layer.
  • Announcement normalization moved into its own partial so settings.html stays smaller and easier to maintain.
  • The rendering partial now receives normalized state instead of re-implementing the same logic.

Why this matters:

  • Rendering and configuration should stay separate to avoid spaghetti code.
  • New announcement rules can now be added in one dedicated place.
  • The same pattern can be reused for future centralized modules.

3) Renderer now supports images and linkable media

Files:

  • themes/(0000-0000-0000-0001)/layouts/partials/theme/announcement.html
  • themes/(0000-0000-0000-0001)/assets/css/common/announcement.css

Changes:

  • The renderer now supports image-based cards, linked media, and captions.
  • Media can render in either top or aside placement.
  • The close button remains intact while the card layout stays stable.

Why this matters:

  • Announcements often need more than plain copy.
  • Release notes, operational notices, and guidance cards are easier to understand when image and CTA live together.
  • Keeping everything in one renderer reduces maintenance cost.

4) Nested section and path matching was strengthened

Files:

  • themes/(0000-0000-0000-0001)/layouts/partials/theme/announcement.html
  • themes/(0000-0000-0000-0001)/data/40-communication/announcement/_index.toml

Changes:

  • Nested paths like sections = ["blog/theme-upgrade-lab"] are now matched using path-aware checks.
  • pathPrefixes and paths are compared with language prefixes in mind.
  • Matching is derived from page path information instead of hardcoding a specific locale or page.

Why this matters:

  • .Section alone is not enough for nested content trees.
  • In many cases, the section path is more important than the top-level content section.
  • Maintainers can read the scope rule and understand the intent immediately.

5) config/_default/params/_index.toml was reduced to a path guide

Files:

  • config/_default/params/_index.toml

Changes:

  • The real copy was removed from this config file.
  • The file now points to the actual source, renderer, and style paths.
  • It acts as a navigation note for maintainers instead of a second source of truth.

Why this matters:

  • Config and theme data should not fight over the same responsibility.
  • Root config is better kept for site-wide policy and compatibility hints.
  • Design and announcements now each have their own centralized control path.

Updated tree

config/
└── _default/
    ├── hugo.toml
    ├── params.toml
    ├── params/
    │   ├── _index.toml   # path guide / compatibility file
    │   └── cta.toml
    └── languages/
        ├── languages.ko.toml
        ├── languages.en.toml
        ├── languages.jp.toml
        └── languages.cn.toml

themes/
└── (0000-0000-0000-0001)/
    ├── assets/
    │   └── css/
    │       ├── common/
    │       │   └── announcement.css
    │       └── core/
    │           └── theme-vars/
    │               └── 80-announcement.css
    ├── data/
    │   └── _index.toml   # actual source of truth
    └── layouts/
        └── partials/
            └── theme/
                ├── announcement-config.html
                ├── announcement.html
                └── settings.html

Notes

  • Do not move language files back to the root.
  • Keep hugo.toml and params.toml under config/_default/.
  • The announcement source of truth now lives in theme data.
  • Keep design values inside the theme-vars layer.
  • Keep UI strings inside theme i18n.
  • Re-check nested section matching before shipping new samples.

Announcement structure addendum

This pass no longer treats announcements as a single items.<id>.content / data/40-communication/announcement/<lang>.toml blob.
The source is now split between one base file and language override files so structure and copy can evolve independently.

Current tree

themes/
└── (0000-0000-0000-0001)/
    └── data/
        └── _index.toml
        └── announcement/
            ├── ko.toml
            ├── en.toml
            ├── jp.toml
            └── cn.toml

Dismiss rules

  • session: hide for the current session
  • persistent: store in localStorage and hide until cleared
  • hours: hide for a fixed number of hours

Pages to inspect

The showcase page uses announcementProfile = "showcase" in front matter. That keeps the modal and inline examples reusable without hardcoding a single path.

Additional pass: global activation and scope normalization

This pass makes the announcement system easier to inspect by turning all banners on globally and standardizing the structure for every banner item.

What changed

  • Added scopeDefaults in themes/(0000-0000-0000-0001)/data/40-communication/announcement/_index.toml so every item follows the same shape.
  • languages / kinds / sections / pathPrefixes / taxonomies / terms now treat ["*"] as a wildcard.
  • storageKey is optional; leaving it blank now falls back to an auto-generated key.
  • priority is now treated as an ordering hint where larger numbers appear first.
  • dismissMode controls the close button persistence policy, with session as the default.
  • snoozeHours is reserved for the time-based hide action only.

Close button review

  • Click handling now listens in the capture phase, so the close action is less likely to be blocked by ancestor listeners.
  • Close behavior is split across session / persistent / hours policies.
  • Storage failures do not block the visual hide action.

Layout review

  • CTA and dismiss buttons stay content-sized on desktop and expand to full width on mobile only.
  • Footer and dismiss alignment are controlled through theme-vars tokens rather than page-level hardcoding.

File tree to check

config/_default/params/_index.toml

themes/(0000-0000-0000-0001)/
├─ data/
│  ├─ _index.toml
│  └─ announcement/
│     ├─ ko.toml
│     ├─ en.toml
│     ├─ jp.toml
│     └─ cn.toml
├─ layouts/partials/theme/
│  ├─ announcement-config.html
│  └─ announcement.html
├─ assets/css/common/
│  └─ announcement.css
├─ assets/css/core/theme-vars/
│  └─ 80-announcement.css
└─ assets/js/04-composition-layer/cross-cutting-composition/
   └─ announcement.js

Operational note

  • To show every banner globally, keep enabled = true and the item scopes wide open.
  • Narrow the scope only when a banner truly belongs to a specific section or page class.
  • storageKey should be set only when a banner needs a long-lived dismissal identity.