From 3dcc9553c44bf13da64348f0c5b8a85382d9b092 Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Thu, 23 Apr 2026 14:27:29 +0200 Subject: [PATCH] ACP Icons --- AGENTS.md | 28 +++--- GAME_ICONS.md | 66 +++++++------- scss/westgate/_categories.scss | 74 +++++++++++++++ templates/category.tpl | 100 +++++++++++++++++++++ templates/partials/categories/children.tpl | 2 +- templates/partials/categories/item.tpl | 15 +--- 6 files changed, 230 insertions(+), 55 deletions(-) create mode 100644 templates/category.tpl diff --git a/AGENTS.md b/AGENTS.md index 12ee108..09903b7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -99,17 +99,20 @@ Complete the following: - [x] Recommend icons from the game-icons pack for forum categories and their subcategories. See `GAME_ICONS.md`. - [x] Include the `.svg`/`.png` files in the theme if possible. SVG assets are in `public/game-icons/`. - [x] Author any necessary credits in a `.md` file at the root of the `nodebb-theme-westgate` repository. See `GAME_ICONS.md`. - - [ ] Phase 2: Implementation. - - [ ] Confirm category `class` data is present on all required render paths: `/categories`, category-page subcategory rows, category-page header, and AJAX-loaded "more subcategories" rows. Initial assessment: NodeBB stores and escapes `category.class`, and `getCategoryData`/`getCategoriesData` include it, but local templates currently do not emit it. - - [ ] Add ACP custom class output to local category templates. At minimum, add `{./class}` to root category rows and child/subcategory row wrappers so classes like `wg-icon-scroll-quill` can control icons without hardcoding category IDs. - - [ ] Add a minimal local `templates/category.tpl` override, copied from Harmony only as needed, so the category page header can expose `{./class}` around its `buildCategoryIcon(...)` output. - - [ ] Decide whether `templates/partials/categories/children.tpl` should remain a separate source of truth or whether the duplicated child markup inside `templates/partials/categories/item.tpl` should be collapsed back to the imported partial before adding icon classes. - - [ ] Implement the `wg-icon-*` CSS mask classes in a focused SCSS file or the existing category SCSS layer. Use `public/game-icons/*.svg` through the theme static path, hide/neutralize the Font Awesome `` only for `wg-icon-*` classes, and render the game-icon mask via `::before` using `currentColor`. - - [ ] Preserve the existing ornate icon frame treatment: category ACP `bgColor`/`color` should still tint the icon frame/glyph where possible, with fallback faded-gold/dark-steel styling if ACP colors are too bright. - - [ ] Define the exact ACP custom classes to enter for each category/subcategory, based on `GAME_ICONS.md`, so setup can happen without theme code knowing category IDs. - - [ ] Document setup steps for admins: where to enter the custom class, which class names map to which icons, and when to rebuild/restart NodeBB after theme changes. - - [ ] Validate on the live website because it has all sections: desktop and mobile `/categories`, one category page with subcategories, "load more subcategories" if present, and at least one category with no game-icon class to confirm Font Awesome fallback still works. - - [ ] Explain any additional steps needed after implementation, especially ACP class entry, asset rebuild, restart/cache behavior, and whether uploaded category background images should be cleared for icon-driven categories. + - [-] Phase 2: Implementation. + - [x] Confirm category `class` data is present on all required render paths: `/categories`, category-page subcategory rows, category-page header, and AJAX-loaded "more subcategories" rows. NodeBB stores and escapes `category.class`; `getCategoryData`/`getCategoriesData` include it; the category template's `children` block is used for AJAX-loaded subcategories. + - [x] Add ACP custom class output to local category templates. Root category rows and child/subcategory row wrappers now emit `{./class}` so classes like `wg-icon-scroll-quill` can control icons without hardcoding category IDs. + - [x] Add a minimal local `templates/category.tpl` override, copied from Harmony only as needed, so the category page header can expose `{./class}` around its `buildCategoryIcon(...)` output. + - [x] Keep `templates/partials/categories/children.tpl` as the single source of truth for nested child markup and collapse the duplicate child markup in `templates/partials/categories/item.tpl` back to the imported partial before adding icon classes. + - [x] Implement the `wg-icon-*` CSS mask classes in the existing category SCSS layer. Use `public/game-icons/*.svg` through the theme static path, hide/neutralize the Font Awesome `` only for `wg-icon-*` classes, and render the game-icon mask via `::before` using `currentColor`. + - [x] Preserve the existing ornate icon frame treatment: category ACP `bgColor`/`color` still drives the frame and glyph color because the mask uses the icon element's current color; fallback styling remains faded-gold/dark-steel. + - [x] Define the exact ACP custom classes to enter for each category/subcategory, based on `GAME_ICONS.md`, so setup can happen without theme code knowing category IDs. + - [x] Document setup steps for admins: where to enter the custom class, which class names map to which icons, and when to rebuild/restart NodeBB after theme changes. + - [x] Validate implementation scaffolding: `./nodebb build` succeeds, compiled templates emit `{./class}`, compiled CSS contains the `wg-icon-*` mask rules, and `/assets/plugins/nodebb-theme-westgate/game-icons/drama-masks.svg` returns HTTP 200. + - [ ] Enter the `wg-icon-*` values from `GAME_ICONS.md` into the live ACP category custom class fields. The current live data still contains legacy layout classes like `col-md-3 col-6`; keep them only if they are still intentionally used for layout, and append the `wg-icon-*` class alongside them. + - [ ] Validate actual game-icon visuals on the live website after ACP class entry: desktop and mobile `/categories`, one category page with subcategories, "load more subcategories" if present, and at least one category with no game-icon class to confirm Font Awesome fallback still works. + - [ ] Decide whether uploaded category background images should be cleared for icon-driven categories after seeing the final ACP-configured visuals. + - [ ] Explain any operational follow-up after ACP setup, especially asset rebuild, restart/cache behavior, and whether legacy Bootstrap layout classes should remain in category custom class fields. ### Context for categories @@ -159,3 +162,6 @@ Tasks to be considered in the future, not implemented immediately. Keep them in - [ ] Un-bold "topics" and "posts" and make the color lines replace the black line drived from category background color to either use the foreground color of the icon, or an ornate gilding like the icons (image 2) - [ ] Consider making the category names a bit smoother; it looks like it's not anti-aliased. (image 3) - [ ] Mobile website doesn't use the correct fonts. +- [ ] In the process of testing widgets, I noticed that some are being given the "card" treatment (the glossy purple background element) even if there is no card container. Example here: http://localhost:4567/user/admin + - [ ] Widgets without the card containers should display plainly. + - [ ] Widgets can be put inside of a card container to make a card. diff --git a/GAME_ICONS.md b/GAME_ICONS.md index 5451ebd..0a85ebe 100644 --- a/GAME_ICONS.md +++ b/GAME_ICONS.md @@ -6,38 +6,45 @@ Source: https://game-icons.net and https://github.com/game-icons/icons License: Creative Commons Attribution 3.0 Unported, https://creativecommons.org/licenses/by/3.0/ -The SVGs in `public/game-icons/` were sanitized for theme use by removing the default black square background and changing the foreground fill to `currentColor`. They should be used as monochrome/tintable assets, preferably in an engraved faded-gold or dark-steel treatment. Category-specific colors can still come from the NodeBB ACP category color fields or future `wg-icon-*` classes. +The SVGs in `public/game-icons/` were sanitized for theme use by removing the default black square background and changing the foreground fill to `currentColor`. They are used as monochrome/tintable assets, preferably in an engraved faded-gold or dark-steel treatment. Category-specific colors still come from the NodeBB ACP category color fields. ## Recommended Mapping -| Category | Recommended icon | Asset | -| --- | --- | --- | -| INFORMATION | Scroll and quill | `public/game-icons/scroll-quill.svg` | -| Player Guide | Rule book | `public/game-icons/rule-book.svg` | -| Announcements | Ringing bell | `public/game-icons/ringing-bell.svg` | -| Patch Notes | Spinning wheel | `public/game-icons/spinning-wheel.svg` | -| COMMUNITY | Tavern sign | `public/game-icons/tavern-sign.svg` | -| General Discussion | Saloon | `public/game-icons/saloon.svg` | -| Introductions | Shaking hands | `public/game-icons/shaking-hands.svg` | -| Screenshots | Large paint brush | `public/game-icons/large-paint-brush.svg` | -| Creations | Flute | `public/game-icons/flute.svg` | -| ROLEPLAY | Drama masks | `public/game-icons/drama-masks.svg` | -| Notices | Target poster | `public/game-icons/target-poster.svg` | -| Rumors & Gossip | Chat bubble | `public/game-icons/chat-bubble.svg` | -| Journals & Biographies | Notebook | `public/game-icons/notebook.svg` | -| Factions & Guilds | Wax seal | `public/game-icons/wax-seal.svg` | -| SUPPORT | Glowing hands | `public/game-icons/glowing-hands.svg` | -| Common Issues & Questions | Question badge | `public/game-icons/question.svg` | -| Technical Help | Monkey wrench | `public/game-icons/monkey-wrench.svg` | -| Bug Reports | Long antennae bug | `public/game-icons/long-antennae-bug.svg` | -| Feedback | Idea | `public/game-icons/idea.svg` | -| DEVELOPMENT | Gears | `public/game-icons/gears.svg` | -| Tools & References | Toolbox | `public/game-icons/toolbox.svg` | -| General | Compass | `public/game-icons/compass.svg` | -| Lore | Open book | `public/game-icons/open-book.svg` | -| Designs | Pencil ruler | `public/game-icons/pencil-ruler.svg` | -| Programming | Processor | `public/game-icons/processor.svg` | -| Area Building | Castle ruins | `public/game-icons/castle-ruins.svg` | +| Category | Recommended icon | ACP custom class | Asset | +| --- | --- | --- | --- | +| INFORMATION | Scroll and quill | `wg-icon-scroll-quill` | `public/game-icons/scroll-quill.svg` | +| Player Guide | Rule book | `wg-icon-rule-book` | `public/game-icons/rule-book.svg` | +| Announcements | Ringing bell | `wg-icon-ringing-bell` | `public/game-icons/ringing-bell.svg` | +| Patch Notes | Spinning wheel | `wg-icon-spinning-wheel` | `public/game-icons/spinning-wheel.svg` | +| COMMUNITY | Tavern sign | `wg-icon-tavern-sign` | `public/game-icons/tavern-sign.svg` | +| General Discussion | Saloon | `wg-icon-saloon` | `public/game-icons/saloon.svg` | +| Introductions | Shaking hands | `wg-icon-shaking-hands` | `public/game-icons/shaking-hands.svg` | +| Screenshots | Large paint brush | `wg-icon-large-paint-brush` | `public/game-icons/large-paint-brush.svg` | +| Creations | Flute | `wg-icon-flute` | `public/game-icons/flute.svg` | +| ROLEPLAY | Drama masks | `wg-icon-drama-masks` | `public/game-icons/drama-masks.svg` | +| Notices | Target poster | `wg-icon-target-poster` | `public/game-icons/target-poster.svg` | +| Rumors & Gossip | Chat bubble | `wg-icon-chat-bubble` | `public/game-icons/chat-bubble.svg` | +| Journals & Biographies | Notebook | `wg-icon-notebook` | `public/game-icons/notebook.svg` | +| Factions & Guilds | Wax seal | `wg-icon-wax-seal` | `public/game-icons/wax-seal.svg` | +| SUPPORT | Glowing hands | `wg-icon-glowing-hands` | `public/game-icons/glowing-hands.svg` | +| Common Issues & Questions | Question badge | `wg-icon-question` | `public/game-icons/question.svg` | +| Technical Help | Monkey wrench | `wg-icon-monkey-wrench` | `public/game-icons/monkey-wrench.svg` | +| Bug Reports | Long antennae bug | `wg-icon-long-antennae-bug` | `public/game-icons/long-antennae-bug.svg` | +| Feedback | Idea | `wg-icon-idea` | `public/game-icons/idea.svg` | +| DEVELOPMENT | Gears | `wg-icon-gears` | `public/game-icons/gears.svg` | +| Tools & References | Toolbox | `wg-icon-toolbox` | `public/game-icons/toolbox.svg` | +| General | Compass | `wg-icon-compass` | `public/game-icons/compass.svg` | +| Lore | Open book | `wg-icon-open-book` | `public/game-icons/open-book.svg` | +| Designs | Pencil ruler | `wg-icon-pencil-ruler` | `public/game-icons/pencil-ruler.svg` | +| Programming | Processor | `wg-icon-processor` | `public/game-icons/processor.svg` | +| Area Building | Castle ruins | `wg-icon-castle-ruins` | `public/game-icons/castle-ruins.svg` | + +## Setup + +1. In the NodeBB ACP, open `Manage > Categories`, choose a category, and put the matching `wg-icon-*` value in the category's custom class field. If that field already has layout classes such as `col-md-3 col-6`, append the icon class instead of replacing them until the layout classes are confirmed unnecessary. +2. Keep the regular ACP icon configured as a Font Awesome fallback. The theme hides it only when a matching `wg-icon-*` class is present. +3. Use the ACP text/icon color for category-specific glyph tinting. Prefer muted gold, green, blue, red, or violet accents over bright saturated colors. +4. After theme file changes, rebuild NodeBB assets and restart if the running process does not pick up `plugin.json` static directory changes. ## Attribution @@ -47,4 +54,3 @@ The following Game Icons authors are represented in this curated set: - Caro Asercion: `spinning-wheel.svg` - Delapouite: `castle-ruins.svg`, `chat-bubble.svg`, `flute.svg`, `idea.svg`, `large-paint-brush.svg`, `monkey-wrench.svg`, `notebook.svg`, `pencil-ruler.svg`, `rule-book.svg`, `saloon.svg`, `scroll-quill.svg`, `shaking-hands.svg`, `target-poster.svg`, `tavern-sign.svg`, `toolbox.svg` - Lorc: `compass.svg`, `drama-masks.svg`, `gears.svg`, `glowing-hands.svg`, `long-antennae-bug.svg`, `open-book.svg`, `processor.svg`, `ringing-bell.svg`, `wax-seal.svg` - diff --git a/scss/westgate/_categories.scss b/scss/westgate/_categories.scss index db5daa4..4800079 100644 --- a/scss/westgate/_categories.scss +++ b/scss/westgate/_categories.scss @@ -41,6 +41,80 @@ li[component="categories/category"] .icon { 0 0 8px rgba(0, 0, 0, 0.22); } +$wg-game-icon-path: "./plugins/nodebb-theme-westgate/game-icons/"; +$wg-game-icons: ( + scroll-quill: "scroll-quill.svg", + rule-book: "rule-book.svg", + ringing-bell: "ringing-bell.svg", + spinning-wheel: "spinning-wheel.svg", + tavern-sign: "tavern-sign.svg", + saloon: "saloon.svg", + shaking-hands: "shaking-hands.svg", + large-paint-brush: "large-paint-brush.svg", + flute: "flute.svg", + drama-masks: "drama-masks.svg", + target-poster: "target-poster.svg", + chat-bubble: "chat-bubble.svg", + notebook: "notebook.svg", + wax-seal: "wax-seal.svg", + glowing-hands: "glowing-hands.svg", + question: "question.svg", + monkey-wrench: "monkey-wrench.svg", + long-antennae-bug: "long-antennae-bug.svg", + idea: "idea.svg", + gears: "gears.svg", + toolbox: "toolbox.svg", + compass: "compass.svg", + open-book: "open-book.svg", + pencil-ruler: "pencil-ruler.svg", + processor: "processor.svg", + castle-ruins: "castle-ruins.svg" +); + +.westgate-category-header-icon { + flex-basis: auto; + width: auto; + max-width: none; +} + +.westgate-category-header-icon[class*="wg-icon-"] > .icon, +li[component="categories/category"][class*="wg-icon-"] > .d-flex > .flex-shrink-0 > .icon, +.category-children-item[class*="wg-icon-"] > .westgate-category-child > .icon { + position: relative; + color: var(--wg-ledger-ink); +} + +.westgate-category-header-icon[class*="wg-icon-"] > .icon > i, +li[component="categories/category"][class*="wg-icon-"] > .d-flex > .flex-shrink-0 > .icon > i, +.category-children-item[class*="wg-icon-"] > .westgate-category-child > .icon > i { + opacity: 0; +} + +.westgate-category-header-icon[class*="wg-icon-"] > .icon::before, +li[component="categories/category"][class*="wg-icon-"] > .d-flex > .flex-shrink-0 > .icon::before, +.category-children-item[class*="wg-icon-"] > .westgate-category-child > .icon::before { + content: ""; + position: absolute; + inset: 22%; + background: currentColor; + filter: + drop-shadow(0 1px 0 rgba(0, 0, 0, 0.72)) + drop-shadow(0 -1px 0 rgba(255, 238, 190, 0.16)); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + pointer-events: none; +} + +@each $name, $file in $wg-game-icons { + .westgate-category-header-icon.wg-icon-#{$name} > .icon::before, + li[component="categories/category"].wg-icon-#{$name} > .d-flex > .flex-shrink-0 > .icon::before, + .category-children-item.wg-icon-#{$name} > .westgate-category-child > .icon::before { + -webkit-mask-image: url("#{$wg-game-icon-path}#{$file}"); + mask-image: url("#{$wg-game-icon-path}#{$file}"); + } +} + li[component="categories/category"] h2.title { position: relative; padding-bottom: 0.18rem; diff --git a/templates/category.tpl b/templates/category.tpl new file mode 100644 index 0000000..10c27fa --- /dev/null +++ b/templates/category.tpl @@ -0,0 +1,100 @@ + +{{{ if config.theme.enableBreadcrumbs }}} + +{{{ end }}} + +
+
+
+ {buildCategoryIcon(@value, "60px", "rounded-1")} +
+
+

{./name}

+
+ + {humanReadableNumber(totalTopicCount)} + [[global:topics]] + + + {humanReadableNumber(totalPostCount)} + [[global:posts]] + + {{{ if !isNumber(cid) }}} + + View Original + + + {{{ end }}} + {{{ if (!feeds:disableRSS && rssFeedUrl) }}} + + {{{ end }}} +
+
+
+ {{{ if ./descriptionParsed }}} +
+ {./descriptionParsed} +
+ {{{ end }}} + {{{ if ./handleFull }}} +

+ [[category:handle.description, {handleFull}]] + +

+ {{{ end }}} + +
+ +{{{ if widgets.header.length }}} +
+ {{{ each widgets.header }}} + {{widgets.header.html}} + {{{ end }}} +
+{{{ end }}} + + +
+
+ + {{{ if (topics.length || privileges.topics:create) }}} + + {{{ end }}} + + {{{ if (./inbox && (./hasFollowers == false)) }}} + + {{{ end }}} + + {{{ if (!topics.length && privileges.topics:create) }}} +
+ [[category:no-topics]] +
+ {{{ end }}} + + + + {{{ if config.usePagination }}} + + {{{ end }}} +
+
+ {{{ each widgets.sidebar }}} + {{widgets.sidebar.html}} + {{{ end }}} +
+
+
+ {{{each widgets.footer}}} + {{widgets.footer.html}} + {{{end}}} +
+ +{{{ if !config.usePagination }}} + +{{{ end }}} diff --git a/templates/partials/categories/children.tpl b/templates/partials/categories/children.tpl index bb8abca..22b9e37 100644 --- a/templates/partials/categories/children.tpl +++ b/templates/partials/categories/children.tpl @@ -1,7 +1,7 @@
    {{{ each ./children }}} {{{ if !./isSection }}} -
  • +
  • {buildCategoryIcon(@value, "18px", "westgate-child-icon rounded-1")} {./name} diff --git a/templates/partials/categories/item.tpl b/templates/partials/categories/item.tpl index bbe649c..5179807 100644 --- a/templates/partials/categories/item.tpl +++ b/templates/partials/categories/item.tpl @@ -1,4 +1,4 @@ -
  • +
  • @@ -31,18 +31,7 @@ {{{ end }}} {{{ if !config.hideSubCategories }}} {{{ if ./children.length }}} -
      - {{{ each ./children }}} - {{{ if !./isSection }}} -
    • -
      - {buildCategoryIcon(@value, "18px", "westgate-child-icon rounded-1")} - {./name} -
      -
    • - {{{ end }}} - {{{ end }}} -
    + {{{ end }}} {{{ end }}}