diff --git a/AGENTS.md b/AGENTS.md index 16fbaa5..fd29b0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## Project -This repository is `nodebb-theme-westgate`, a NodeBB theme for the Shadows Over Westgate forum. +This repository is `nodebb-theme-westgate`, a NodeBB theme for the Shadows Over Westgate forum and website. It is forked from `nodebb-theme-quickstart` and should remain a small, focused NodeBB child theme rather than a full replacement for NodeBB or Harmony. diff --git a/docs/superpowers/specs/2026-06-26-website-pages-design.md b/docs/superpowers/specs/2026-06-26-website-pages-design.md index de317fa..d7d9647 100644 --- a/docs/superpowers/specs/2026-06-26-website-pages-design.md +++ b/docs/superpowers/specs/2026-06-26-website-pages-design.md @@ -39,10 +39,9 @@ drafts, and authentication entry points. - `theme.json` declares `baseTheme: "nodebb-theme-harmony"`. - `theme.scss` imports Harmony first, then focused Westgate partials under `scss/westgate/`. -- `templates/header.tpl` currently matches the Harmony layout pattern: a - `layout-container`, `partials/sidebar-left.tpl`, `#panel`, and - `partials/header/brand.tpl`. -- Harmony's `footer.tpl` imports `partials/sidebar-right.tpl`. +- `templates/header.tpl` currently mounts the Westgate topbar inside the + `layout-container` before `#panel`. +- `templates/footer.tpl` no longer imports Harmony's right sidebar. - Harmony's sidebar partials under `/home/vicky/Repositories/nodebb-theme-harmony/templates/partials/sidebar/` own the live controls for navigation, user menu, search, notifications, chat, diff --git a/lib/theme.js b/lib/theme.js index ecac492..c7a2cd0 100644 --- a/lib/theme.js +++ b/lib/theme.js @@ -115,11 +115,6 @@ library.defineWidgetAreas = async function (areas) { template: 'global', location: 'sidebar-footer', }, - { - name: 'Brand Header', - template: 'global', - location: 'brand-header', - }, { name: 'About me (before)', template: 'account/profile.tpl', @@ -182,4 +177,3 @@ library.filterMiddlewareRenderHeader = async function (hookData) { hookData.templateData.bootswatchSkinOptions = await meta.css.getSkinSwitcherOptions(hookData.req.uid); return hookData; }; - diff --git a/public/images/plum-header-bg.png b/public/images/plum-header-bg.png deleted file mode 100644 index 21d96d5..0000000 Binary files a/public/images/plum-header-bg.png and /dev/null differ diff --git a/scss/westgate/_header.scss b/scss/westgate/_header.scss deleted file mode 100644 index d148f5c..0000000 --- a/scss/westgate/_header.scss +++ /dev/null @@ -1,187 +0,0 @@ -.westgate-brand-hero { - position: relative; - overflow: hidden; - margin-top: 0.25rem; - border: 1px solid rgba(194, 163, 90, 0.22); - border-radius: 10px; - padding: 1.2rem 1.05rem; - filter: saturate(1) contrast(1) brightness(1); - background-color: #16121b; - background: - linear-gradient(90deg, rgba(5, 4, 7, 0.82) 0%, rgba(7, 6, 9, 0.72) 22%, rgba(9, 7, 11, 0.48) 34%, rgba(10, 8, 12, 0.18) 43%, rgba(10, 8, 12, 0) 52%), - url("./plugins/nodebb-theme-westgate/images/plum-header-bg.png") center 50% / cover no-repeat; - box-shadow: - inset 0 1px 0 rgba(255, 242, 204, 0.08), - inset 0 0 0 1px rgba(33, 21, 28, 0.5), - 0 18px 42px rgba(0, 0, 0, 0.3); - - &::before { - content: ""; - position: absolute; - inset: 0; - background: - radial-gradient(circle at 62% 100%, rgba(88, 38, 86, 0.26), rgba(88, 38, 86, 0.13) 20%, transparent 44%), - linear-gradient(155deg, transparent 58%, rgba(55, 24, 53, 0.08) 78%, rgba(78, 33, 75, 0.14) 100%); - pointer-events: none; - } -} - -.westgate-brand-hero__veil, -.westgate-brand-hero__inner { - position: relative; - z-index: 1; -} - -.westgate-brand-hero__veil { - display: none; -} - -.westgate-brand-hero__inner { - align-items: center; - justify-content: flex-start; - gap: 0; - min-height: 142px; - width: 100%; - z-index: 2; -} - -.westgate-brand-hero__brand { - width: 100%; - flex-wrap: wrap; - min-height: inherit; - padding: 0 0 0 clamp(1rem, 4vw, 3rem); - justify-content: flex-start; - text-align: left; - - &:hover, - &:focus-within { - background: transparent; - } -} - -.westgate-brand-hero__brand :where([component="brand/anchor"], [component="siteTitle"]) { - color: inherit; - text-decoration: none; - - &:hover, - &:focus { - color: inherit; - text-decoration: none; - background: transparent; - box-shadow: none; - outline: none; - } -} - -.westgate-brand-hero__title-shell { - width: 100%; - padding: 0; - min-height: inherit; - justify-content: flex-start; - text-align: left; - color: inherit; - position: relative; - z-index: 3; - text-decoration: none; - - &:hover, - &:focus { - color: inherit; - text-decoration: none; - background: transparent; - box-shadow: none; - outline: none; - } -} - -.westgate-brand-hero__title-block { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 0.35rem; - text-align: left; -} - -.westgate-brand-hero__brand [component="siteTitle"] :where(h1, .fs-6) { - font-family: var(--wg-font-display); - font-size: clamp(1.25rem, 2.1vw, 1.9rem) !important; - line-height: 0.92; - font-weight: 600; - letter-spacing: 0.1em; - text-transform: uppercase; - text-shadow: - 0 1px 0 rgba(255, 222, 142, 0.05), - 0 2px 0 rgba(52, 37, 15, 0.92), - 0 4px 0 rgba(16, 11, 6, 0.96), - 0 8px 14px rgba(0, 0, 0, 0.72), - 0 14px 26px rgba(0, 0, 0, 0.46), - 0 0 16px rgba(48, 10, 26, 0.24); - opacity: 0.82; - mix-blend-mode: screen; -} - -.westgate-brand-hero__subtitle { - color: #c2a35a; - font-family: var(--wg-font-display); - font-size: 0.64rem; - font-weight: 600; - letter-spacing: 0.22em; - line-height: 1; - text-transform: uppercase; - text-shadow: - 0 1px 0 rgba(0, 0, 0, 0.92), - 0 3px 8px rgba(0, 0, 0, 0.34); -} - -.westgate-brand-hero__widgets { - position: relative; - z-index: 4; - color: var(--wg-text); - text-shadow: 0 1px 0 rgba(0, 0, 0, 0.74); - width: 100%; - padding-left: 0; - border-left: 0; - text-align: center; - margin-top: 0.5rem; - - > :last-child { - margin-bottom: 0; - } -} - -@media (max-width: 991.98px) { - .westgate-brand-hero { - margin-top: 0; - padding: 1.05rem 0.9rem; - background-position: center 46%; - } - - .westgate-brand-hero__inner { - min-height: 118px; - flex-wrap: wrap; - } - - .westgate-brand-hero__brand { - min-height: 0; - padding: 0 0 0 0.65rem; - } - - .westgate-brand-hero__title-block { - gap: 0.28rem; - } - - .westgate-brand-hero__brand [component="siteTitle"] :where(h1, .fs-6) { - font-size: clamp(1rem, 3.9vw, 1.35rem) !important; - letter-spacing: 0.07em; - } - - .westgate-brand-hero__subtitle { - font-size: 0.56rem; - letter-spacing: 0.18em; - } - - .westgate-brand-hero__widgets { - border-top: 1px solid rgba(216, 194, 138, 0.12); - padding-top: 0.85rem; - } -} diff --git a/templates/partials/header/brand.tpl b/templates/partials/header/brand.tpl deleted file mode 100644 index f7f0b69..0000000 --- a/templates/partials/header/brand.tpl +++ /dev/null @@ -1,26 +0,0 @@ -{{{ if (brand:logo || (config.showSiteTitle || widgets.brand-header.length)) }}} -
-
-
-
- {{{ if config.showSiteTitle }}} - - {{{ end }}} - {{{ if widgets.brand-header.length }}} -
- {{{each widgets.brand-header}}} - {{./html}} - {{{end}}} -
- {{{ end }}} -
-
-
-{{{ end }}} diff --git a/tests/global-topbar-contract.test.js b/tests/global-topbar-contract.test.js index efe2fb4..98807b1 100644 --- a/tests/global-topbar-contract.test.js +++ b/tests/global-topbar-contract.test.js @@ -10,6 +10,11 @@ function read(relativePath) { return fs.readFileSync(filePath, 'utf8'); } +function assertMissing(relativePath, message) { + const filePath = path.join(__dirname, '..', relativePath); + assert(!fs.existsSync(filePath), message || `${relativePath} should not exist`); +} + function assertIncludes(haystack, needle, message) { assert( haystack.includes(needle), @@ -30,6 +35,7 @@ const topbar = read('templates/partials/header/topbar.tpl'); const theme = read('theme.scss'); const stylesheet = read('scss/westgate/_topbar.scss'); const client = read('public/client.js'); +const themeHooks = read('lib/theme.js'); assertIncludes( header, @@ -51,6 +57,11 @@ assertIncludes( '@import "./scss/westgate/topbar";', 'theme.scss should import the focused topbar partial' ); +assertExcludes( + theme, + '@import "./scss/westgate/header";', + 'theme.scss should not import the removed brand banner stylesheet' +); assertIncludes( stylesheet, '.wg-topbar', @@ -94,3 +105,21 @@ assertIncludes(topbar, '{{{ if config.loggedIn }}}', 'Topbar should branch on th assertIncludes(topbar, '{{{ if canChat }}}', 'Chat controls should remain permission-gated'); assertIncludes(topbar, '{{{ if allowRegistration }}}', 'Registration should remain server-gated'); assertIncludes(topbar, '{{{ each navigation }}}', 'Topbar should render ACP Navigation items'); + +assertMissing( + 'templates/partials/header/brand.tpl', + 'Theme should inherit Harmony brand markup instead of shipping the removed Westgate brand banner override' +); +assertMissing( + 'scss/westgate/_header.scss', + 'Removed brand banner styles should not remain in the theme' +); +assertMissing( + 'public/images/plum-header-bg.png', + 'Removed brand banner background should not remain in static assets' +); +assertExcludes( + themeHooks, + 'brand-header', + 'Removed brand banner widget area should not remain registered' +); diff --git a/theme.scss b/theme.scss index 748907a..a4a066c 100644 --- a/theme.scss +++ b/theme.scss @@ -1,7 +1,6 @@ @import "../nodebb-theme-harmony/theme"; @import "./scss/westgate/tokens"; @import "./scss/westgate/wiki-prose"; -@import "./scss/westgate/header"; @import "./scss/westgate/topbar"; @import "./scss/westgate/surfaces"; @import "./scss/westgate/categories";