From 93a3f9fc0d147bcda548253405a129515077d813 Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Fri, 26 Jun 2026 11:16:12 +0200 Subject: [PATCH 1/3] docs: capture topbar refinements --- .../2026-06-26-global-topbar-refinements.md | 74 +++++++++++++++++++ .../specs/2026-06-26-global-topbar-design.md | 30 ++++++++ 2 files changed, 104 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-26-global-topbar-refinements.md diff --git a/docs/superpowers/plans/2026-06-26-global-topbar-refinements.md b/docs/superpowers/plans/2026-06-26-global-topbar-refinements.md new file mode 100644 index 0000000..41d2032 --- /dev/null +++ b/docs/superpowers/plans/2026-06-26-global-topbar-refinements.md @@ -0,0 +1,74 @@ +# Global Topbar Refinements Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Apply the post-review global topbar refinements from `docs/superpowers/specs/2026-06-26-global-topbar-design.md`. + +**Architecture:** Keep the implementation inside the existing NodeBB child theme topbar partial, topbar SCSS partial, and theme client bundle. Extend the existing static topbar contract test so the refinements are pinned without adding a new test harness. + +**Tech Stack:** Node.js built-in test runner, NodeBB templates, SCSS. + +## Global Constraints + +- Keep this as a child theme over `nodebb-theme-harmony`. +- Keep `theme.scss` imports-only. +- Put substantive Westgate-specific topbar CSS under `scss/westgate/`. +- Preserve real NodeBB/Harmony live partials and component hooks for search, notifications, chat, drafts, user menu, and ACP navigation. +- Do not commit secrets or token material. + +--- + +### Task 1: Topbar Contract Refinements + +**Files:** +- Modify: `tests/global-topbar-contract.test.js` +- Modify: `templates/partials/header/topbar.tpl` +- Modify: `scss/westgate/_topbar.scss` +- Modify: `public/client.js` + +**Interfaces:** +- Consumes: Existing `topbar.tpl` markup, `_topbar.scss` selectors, and `initWestgateTopbar`. +- Produces: A single desktop navigation model, a one-line brand lockup, and opaque topbar menu surfaces. + +- [ ] **Step 1: Write the failing test** + +Add static contract assertions to `tests/global-topbar-contract.test.js`: + +```js +assertIncludes(topbar, 'SHADOWS OVER WESTGATE', 'Topbar brand should use the single required identity line'); +assertExcludes(topbar, 'wg-topbar__brand-subtitle', 'Topbar should not repeat the site name as a subtitle'); +assertExcludes(topbar, 'wg-topbar__forums', 'Topbar should not ship a separate desktop Forums dropdown'); +assertExcludes(topbar, 'data-wg-menu="forums"', 'Forums should not use a custom topbar menu trigger'); +assertIncludes(stylesheet, '$wg-topbar-panel-bg', 'Topbar menu surfaces should use an opaque local panel base'); +assertExcludes(stylesheet, 'var(--wg-velvet-panel) !important;', 'Topbar menu surfaces should not inherit the translucent velvet panel token'); +assertExcludes(stylesheet, 'text-overflow: ellipsis;', 'Topbar brand should not truncate in normal desktop layouts'); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `node --test tests/global-topbar-contract.test.js` + +Expected: FAIL because the current topbar still has the brand subtitle, custom Forums dropdown, translucent panel token, and brand truncation. + +- [ ] **Step 3: Write minimal implementation** + +Change the template so the brand is only the mark plus `SHADOWS OVER WESTGATE`, remove the custom desktop Forums dropdown block, and keep mobile drawer forum entry links. Change `_topbar.scss` so dropdown/drawer surfaces use an opaque local panel gradient, remove custom Forums panel rules, and remove desktop brand ellipsis. Remove now-unused custom topbar panel toggle handling from `public/client.js`. + +- [ ] **Step 4: Run test to verify it passes** + +Run: `node --test tests/global-topbar-contract.test.js` + +Expected: PASS. + +- [ ] **Step 5: Run the full available test set** + +Run: `node --test tests/*.test.js` + +Expected: PASS. + +- [ ] **Step 6: Commit** + +```bash +git add docs/superpowers/plans/2026-06-26-global-topbar-refinements.md tests/global-topbar-contract.test.js templates/partials/header/topbar.tpl scss/westgate/_topbar.scss public/client.js +git commit -m "fix: refine global topbar integration" +``` diff --git a/docs/superpowers/specs/2026-06-26-global-topbar-design.md b/docs/superpowers/specs/2026-06-26-global-topbar-design.md index 893b557..76d327c 100644 --- a/docs/superpowers/specs/2026-06-26-global-topbar-design.md +++ b/docs/superpowers/specs/2026-06-26-global-topbar-design.md @@ -79,6 +79,30 @@ Harmony sidebar buttons should be restyled as topbar controls. They should feel native to the topbar, not like sidebar markup awkwardly placed in a horizontal row. +## Post-Review Refinements + +Screenshots captured on 2026-06-26 show the topbar working visually, but with +three refinements needed before the topbar feels fully integrated. + +Drawer and dropdown menus must be opaque. The current translucent treatment lets +page content show through account, forum, and drawer surfaces, which weakens +readability and makes the controls feel less deliberate. Keep the near-black and +plum surface direction, but use an opaque panel base; decorative highlights, +borders, and shadows may remain subtle. + +The brand lockup should be simplified to one identity line: the circular mark +followed by `SHADOWS OVER WESTGATE`. Do not repeat `Shadows Over Westgate` as a +subtitle in the topbar, and do not allow the primary brand name to truncate in +normal desktop layouts. Longer project context such as `An NWN:EE Roleplaying +Experience` belongs on larger page surfaces, not in the dense global chrome. + +The custom right-side `Forums` dropdown is redundant when ACP Navigation already +contains a Forums entry. Prefer one seamless navigation model: remove the +separate desktop Forums dropdown and let forum entry points live in ACP +Navigation or in the mobile drawer as direct links. If ACP-managed navigation +needs to drop text bubbles or helper labels to make this feel clean, that is +acceptable. + ## Implementation Direction The production implementation should be theme-first: @@ -142,6 +166,12 @@ mobile bars should not duplicate those controls. - Search uses NodeBB search behavior rather than a visual-only input. - The topbar appears consistently on Custom Pages, wiki routes, and normal forum routes. +- Drawer, dropdown, account, and notification surfaces are opaque enough that + underlying page content does not show through. +- The brand appears once as the mark plus `SHADOWS OVER WESTGATE`; no duplicate + topbar subtitle repeats the site name. +- Desktop navigation has one Forums entry model, not both ACP Navigation Forums + and a separate right-side Forums dropdown. - The topbar styling follows Westgate theme tokens and lives under `scss/westgate/`. - The implementation remains a child theme over `nodebb-theme-harmony`. -- 2.54.0 From 40d431023a042b3ce8b5191fa02d4fca91c97095 Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Fri, 26 Jun 2026 11:16:17 +0200 Subject: [PATCH 2/3] fix: refine global topbar integration --- public/client.js | 41 ------------- scss/westgate/_topbar.scss | 89 +++++----------------------- templates/partials/header/topbar.tpl | 21 +------ tests/global-topbar-contract.test.js | 7 +++ 4 files changed, 23 insertions(+), 135 deletions(-) diff --git a/public/client.js b/public/client.js index 22ba7f3..6b44da1 100644 --- a/public/client.js +++ b/public/client.js @@ -153,23 +153,6 @@ return document.querySelector('[data-wg-topbar]'); } - function closeWestgateTopbarPanels(topbar, exceptKey) { - if (!topbar || typeof topbar.querySelectorAll !== 'function') { - return; - } - - toArray(topbar.querySelectorAll('[data-wg-panel]')).forEach((panel) => { - if (panel.getAttribute('data-wg-panel') !== exceptKey) { - panel.classList.remove('is-open'); - } - }); - toArray(topbar.querySelectorAll('[data-wg-menu]')).forEach((trigger) => { - if (trigger.getAttribute('data-wg-menu') !== exceptKey) { - trigger.setAttribute('aria-expanded', 'false'); - } - }); - } - function closeWestgateTopbarDrawer(topbar) { if (!topbar) { return; @@ -195,22 +178,6 @@ return; } - const trigger = event.target.closest && event.target.closest('[data-wg-menu]'); - if (trigger && currentTopbar.contains(trigger)) { - event.preventDefault(); - event.stopPropagation(); - - const key = trigger.getAttribute('data-wg-menu'); - const panel = currentTopbar.querySelector(`[data-wg-panel="${key}"]`); - const shouldOpen = !!panel && !panel.classList.contains('is-open'); - closeWestgateTopbarPanels(currentTopbar, shouldOpen ? key : null); - if (panel) { - panel.classList.toggle('is-open', shouldOpen); - } - trigger.setAttribute('aria-expanded', String(shouldOpen)); - return; - } - const burger = event.target.closest && event.target.closest('[data-wg-burger]'); if (burger && currentTopbar.contains(burger)) { event.preventDefault(); @@ -219,15 +186,9 @@ const isOpen = !currentTopbar.classList.contains('is-drawer-open'); currentTopbar.classList.toggle('is-drawer-open', isOpen); burger.setAttribute('aria-expanded', String(isOpen)); - closeWestgateTopbarPanels(currentTopbar, null); return; } - if (event.target.closest && event.target.closest('[data-wg-panel]')) { - return; - } - - closeWestgateTopbarPanels(currentTopbar, null); if (!currentTopbar.contains(event.target)) { closeWestgateTopbarDrawer(currentTopbar); } @@ -239,7 +200,6 @@ } const currentTopbar = getWestgateTopbar(); - closeWestgateTopbarPanels(currentTopbar, null); closeWestgateTopbarDrawer(currentTopbar); }); @@ -263,7 +223,6 @@ $(window).on('action:ajaxify.end', function () { wrapWestgateWikiTables(document); initWestgateTopbar(); - closeWestgateTopbarPanels(getWestgateTopbar(), null); closeWestgateTopbarDrawer(getWestgateTopbar()); }); diff --git a/scss/westgate/_topbar.scss b/scss/westgate/_topbar.scss index 7ecec9e..5698289 100644 --- a/scss/westgate/_topbar.scss +++ b/scss/westgate/_topbar.scss @@ -1,3 +1,11 @@ +$wg-topbar-panel-bg: linear-gradient( + 100deg, + #2a1222 0%, + #19161f 23%, + #121017 62%, + #0d0c11 100% +); + .wg-layout-container { min-height: 100vh; } @@ -17,7 +25,7 @@ .wg-topbar__inner { display: grid; - grid-template-columns: auto minmax(0, 1fr) auto auto; + grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 0.9rem; width: min(100%, 1420px); @@ -60,35 +68,16 @@ font-weight: 700; } -.wg-topbar__brand-text { - display: flex; - flex-direction: column; - min-width: 0; - line-height: 1; -} - .wg-topbar__brand-name { - max-width: 22ch; - overflow: hidden; color: var(--wg-text); font-family: var(--wg-font-display); font-size: 0.96rem; font-weight: 600; letter-spacing: 0.08em; - text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; } -.wg-topbar__brand-subtitle { - margin-top: 0.28rem; - color: var(--wg-gold-soft); - font-family: var(--wg-font-code); - font-size: 0.62rem; - letter-spacing: 0.08em; - text-transform: uppercase; -} - .wg-topbar__nav { min-width: 0; } @@ -104,8 +93,7 @@ } .wg-topbar .nav-link, -.wg-topbar__nav-link, -.wg-topbar__forums-toggle { +.wg-topbar__nav-link { min-height: 2.35rem; border: 1px solid transparent; border-radius: 6px; @@ -122,8 +110,6 @@ .wg-topbar .nav-link:focus, .wg-topbar__nav-link:hover, .wg-topbar__nav-link:focus, -.wg-topbar__forums-toggle:hover, -.wg-topbar__forums-toggle:focus, .wg-topbar .nav-item.active > .nav-link, .wg-topbar .nav-item.active > .navigation-link { color: #f3ede4; @@ -132,16 +118,6 @@ box-shadow: inset 0 1px 0 rgba(255, 244, 221, 0.035); } -.wg-topbar__forums { - position: relative; -} - -.wg-topbar__forums-toggle { - display: inline-flex; - align-items: center; - gap: 0.35rem; -} - .wg-topbar__utilities { justify-self: end; } @@ -187,8 +163,7 @@ .wg-topbar .notifications-dropdown, .wg-topbar .chats-dropdown, .wg-topbar .drafts-dropdown, -.wg-topbar .user-dropdown, -.wg-topbar__panel { +.wg-topbar .user-dropdown { min-width: min(22rem, calc(100vw - 1.5rem)); max-width: calc(100vw - 1.5rem); border: 1px solid rgba(194, 163, 90, 0.22) !important; @@ -196,7 +171,7 @@ color: var(--wg-text-soft) !important; background: linear-gradient(180deg, rgba(255, 244, 221, 0.028), transparent 36%), - var(--wg-velvet-panel) !important; + $wg-topbar-panel-bg !important; box-shadow: inset 0 1px 0 rgba(255, 244, 221, 0.035), 0 18px 42px rgba(0, 0, 0, 0.42) !important; @@ -258,36 +233,6 @@ background: rgba(194, 163, 90, 0.1); } -.wg-topbar__panel { - position: absolute; - top: calc(100% + 0.45rem); - right: 0; - display: none; - padding: 0.42rem; -} - -.wg-topbar__panel.is-open { - display: grid; - gap: 0.2rem; -} - -.wg-topbar__panel--forums a { - display: flex; - align-items: center; - min-height: 2.25rem; - border-radius: 6px; - padding: 0.35rem 0.55rem; - color: var(--wg-text-soft); - font-size: 0.9rem; - text-decoration: none; -} - -.wg-topbar__panel--forums a:hover, -.wg-topbar__panel--forums a:focus { - color: var(--wg-text); - background: rgba(194, 163, 90, 0.08); -} - .wg-topbar__burger { display: none; align-items: center; @@ -310,7 +255,8 @@ display: none; border-top: 1px solid rgba(194, 163, 90, 0.12); background: - linear-gradient(180deg, rgba(42, 18, 34, 0.98), rgba(12, 10, 15, 0.99)); + linear-gradient(180deg, rgba(255, 244, 221, 0.025), transparent 38%), + $wg-topbar-panel-bg; } .wg-topbar.is-drawer-open .wg-topbar__drawer { @@ -389,12 +335,6 @@ grid-template-columns: minmax(0, 1fr) auto; } - .wg-topbar__brand-name { - max-width: 16ch; - } - - .wg-topbar__brand-subtitle, - .wg-topbar__forums, .wg-topbar__utilities { display: none; } @@ -411,7 +351,6 @@ } .wg-topbar__brand-name { - max-width: 13ch; font-size: 0.82rem; letter-spacing: 0.05em; } diff --git a/templates/partials/header/topbar.tpl b/templates/partials/header/topbar.tpl index 93f9623..9adb962 100644 --- a/templates/partials/header/topbar.tpl +++ b/templates/partials/header/topbar.tpl @@ -1,11 +1,8 @@
- + - - {config.siteTitle} - Shadows Over Westgate - + SHADOWS OVER WESTGATE - -
{{{ if config.loggedIn }}}