Header Test

This commit is contained in:
2026-04-24 14:57:06 +02:00
parent 2a989ee6f1
commit dadee4c78f
8 changed files with 273 additions and 39 deletions
+38 -38
View File
@@ -94,42 +94,7 @@ Statuses:
Complete the following: Complete the following:
- [-] 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 - [ ] Experiment with adding a neat new background. Pull it from @/home/vicky/Projects/nwnee-shadowsoverwestgate/media/ae02ec4a-88df-4a53-b780-00b7c3f482f4.png and try to overlay the header with it. Use your best judgment for what "looks good".
- [x] Widgets without the card containers should display plainly.
- [x] Widgets can be put inside of a card container to make a card.
- [x] Expand this from a single-widget bug into a theme-wide widget compatibility pass. The current issue appears broader: too many generic containers, especially plain `<div>` wrappers emitted by widgets or templates, are inheriting the glossy purple gradient card treatment even when they are only structural wrappers.
- [x] Define a compatibility model for widget rendering before implementation:
- [x] Structural wrappers should remain visually neutral by default. A wrapper existing only for layout, spacing, templating, or plugin/widget output should not automatically become a "Westgate card".
- [x] Card styling should be opt-in and intentional. The gradient/gloss/chrome treatment should apply only to known card surfaces, explicit card utility classes, or template regions that are semantically meant to read as panels.
- [x] Plain-text widgets and lightweight HTML widgets must render cleanly without needing custom markup just to avoid accidental card chrome.
- [x] Nested widget markup should not compound card styling. A widget inside a panel should not create boxes-within-boxes unless the nested card is intentional.
- [x] Footer widgets require special handling. Footer text such as "Powered by NodeBB" should behave like footer chrome, not like a content card or panel.
- [x] Build a proper investigation plan for global compatibility:
- [x] Inventory which selectors currently apply the purple gradient/card treatment too broadly. Pay particular attention to rules targeting generic `div`, broad widget wrappers, `.card`, `.panel`, Bootstrap containers, Harmony wrappers, and footer/sidebar/account-page blocks.
- [x] Trace the rendered wrapper stack for several widget types in the running forum, not just one route. Include at minimum: footer HTML widget, profile-page widget areas, sidebar widgets, category-page widgets, and any ACP-placed plain text/HTML widget.
- [x] Distinguish between three classes of surfaces:
- [x] structural wrappers
- [x] content cards/panels
- [x] utility text blocks / footer chrome / metadata strips
- [x] Decide whether the best long-term model is:
- [ ] tightening overly broad selectors so they only target real card components
- [ ] introducing a small explicit Westgate card utility class for opt-in chrome
- [ ] adding a small set of opt-out compatibility rules for widget regions that must stay plain
- [x] or a hybrid of the above
- 2026-04-24 implementation note: `scss/westgate/_widgets.scss` now limits chrome to known panel surfaces (`.card`, `.alert`, `.forum-stats`, `.search-widget`, `.category`, legacy `.panel`/`.well`/`.jumbotron`) plus explicit opt-in utility classes `.westgate-widget-card` and `.wg-widget-card`. Generic top-level wrappers in widget areas are neutral again, and footer wrappers are forced back to plain chrome.
- [x] Define expected compatibility outcomes before coding:
- [x] A plain HTML widget that outputs only text or a single `<div>` should render plainly.
- [x] A widget wrapped in an intentional card class should receive the full glossy Westgate card treatment.
- [x] Existing topic lists, category lists, and intentional content panels should keep their current Westgate identity.
- [x] Footer widget areas should not automatically gain panel framing unless explicitly requested.
- [x] Account/profile pages such as `/user/admin` should not pick up accidental panel chrome from generic wrappers.
- [x] Widget/plugin markup from outside this theme should degrade gracefully even if it uses simple Bootstrap or generic `<div>` containers.
- [-] Validation plan once implementation starts:
- [ ] Check desktop and mobile for footer widgets, sidebar widgets, profile widgets, and at least one plain HTML widget with no special classes.
- [ ] Confirm that intentionally carded widgets still look like Westgate cards.
- [ ] Confirm that nested wrappers no longer create accidental card-on-card stacking.
- [ ] Verify no regressions to topic cards, category panels, or other intentional glossy surfaces.
- [x] Local investigation covered the rendered wrapper stack on `http://localhost:4567/user/admin`, `http://localhost:4567/categories`, `http://localhost:4567/category/2/announcements`, and the sidebar footer widget HTML from the live local render.
## Future Tasks ## Future Tasks
@@ -192,9 +157,44 @@ Tasks to be considered in the future, not implemented immediately. Keep them in
- [ ] Decide whether uploaded category background images should be cleared for icon-driven categories after seeing the final ACP-configured visuals. - [ ] 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. - [ ] 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.
Next useful moves: - [-] 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
- [x] Widgets without the card containers should display plainly.
- [x] Widgets can be put inside of a card container to make a card.
- [x] Expand this from a single-widget bug into a theme-wide widget compatibility pass. The current issue appears broader: too many generic containers, especially plain `<div>` wrappers emitted by widgets or templates, are inheriting the glossy purple gradient card treatment even when they are only structural wrappers.
- [x] Define a compatibility model for widget rendering before implementation:
- [x] Structural wrappers should remain visually neutral by default. A wrapper existing only for layout, spacing, templating, or plugin/widget output should not automatically become a "Westgate card".
- [x] Card styling should be opt-in and intentional. The gradient/gloss/chrome treatment should apply only to known card surfaces, explicit card utility classes, or template regions that are semantically meant to read as panels.
- [x] Plain-text widgets and lightweight HTML widgets must render cleanly without needing custom markup just to avoid accidental card chrome.
- [x] Nested widget markup should not compound card styling. A widget inside a panel should not create boxes-within-boxes unless the nested card is intentional.
- [x] Footer widgets require special handling. Footer text such as "Powered by NodeBB" should behave like footer chrome, not like a content card or panel.
- [x] Build a proper investigation plan for global compatibility:
- [x] Inventory which selectors currently apply the purple gradient/card treatment too broadly. Pay particular attention to rules targeting generic `div`, broad widget wrappers, `.card`, `.panel`, Bootstrap containers, Harmony wrappers, and footer/sidebar/account-page blocks.
- [x] Trace the rendered wrapper stack for several widget types in the running forum, not just one route. Include at minimum: footer HTML widget, profile-page widget areas, sidebar widgets, category-page widgets, and any ACP-placed plain text/HTML widget.
- [x] Distinguish between three classes of surfaces:
- [x] structural wrappers
- [x] content cards/panels
- [x] utility text blocks / footer chrome / metadata strips
- [x] Decide whether the best long-term model is:
- [ ] tightening overly broad selectors so they only target real card components
- [ ] introducing a small explicit Westgate card utility class for opt-in chrome
- [ ] adding a small set of opt-out compatibility rules for widget regions that must stay plain
- [x] or a hybrid of the above
- 2026-04-24 implementation note: `scss/westgate/_widgets.scss` now limits chrome to known panel surfaces (`.card`, `.alert`, `.forum-stats`, `.search-widget`, `.category`, legacy `.panel`/`.well`/`.jumbotron`) plus explicit opt-in utility classes `.westgate-widget-card` and `.wg-widget-card`. Generic top-level wrappers in widget areas are neutral again, and footer wrappers are forced back to plain chrome.
- [x] Define expected compatibility outcomes before coding:
- [x] A plain HTML widget that outputs only text or a single `<div>` should render plainly.
- [x] A widget wrapped in an intentional card class should receive the full glossy Westgate card treatment.
- [x] Existing topic lists, category lists, and intentional content panels should keep their current Westgate identity.
- [x] Footer widget areas should not automatically gain panel framing unless explicitly requested.
- [x] Account/profile pages such as `/user/admin` should not pick up accidental panel chrome from generic wrappers.
- [x] Widget/plugin markup from outside this theme should degrade gracefully even if it uses simple Bootstrap or generic `<div>` containers.
- [-] Validation plan once implementation starts:
- [ ] Check desktop and mobile for footer widgets, sidebar widgets, profile widgets, and at least one plain HTML widget with no special classes.
- [ ] Confirm that intentionally carded widgets still look like Westgate cards.
- [ ] Confirm that nested wrappers no longer create accidental card-on-card stacking.
- [ ] Verify no regressions to topic cards, category panels, or other intentional glossy surfaces.
- [x] Local investigation covered the rendered wrapper stack on `http://localhost:4567/user/admin`, `http://localhost:4567/categories`, `http://localhost:4567/category/2/announcements`, and the sidebar footer widget HTML from the live local render.
Re-enter the preferred wg-icon-\* classes from GAME_ICONS.md into this local NodeBB instance, then rerun the rendered checks. Decide whether category background images should be cleared once the real ACP-configured icons are visible. Add the short operational note about rebuild/restart/cache behavior after ACP updates. Next useful moves:
### Context for categories ### Context for categories
+2 -1
View File
@@ -18,6 +18,7 @@
}, },
"staticDirs": { "staticDirs": {
"fonts": "public/fonts", "fonts": "public/fonts",
"game-icons": "public/game-icons" "game-icons": "public/game-icons",
"images": "public/images"
} }
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

+169
View File
@@ -0,0 +1,169 @@
.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.05rem 1.05rem;
filter: saturate(1) contrast(1) brightness(1);
background: 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 22% 46%, rgba(120, 46, 94, 0.15), transparent 26%),
linear-gradient(90deg, rgba(14, 11, 18, 0.54) 0%, rgba(37, 19, 36, 0.24) 24%, rgba(37, 19, 36, 0.18) 76%, rgba(14, 11, 18, 0.58) 100%);
opacity: 0.82;
pointer-events: none;
}
}
.westgate-brand-hero__veil,
.westgate-brand-hero__inner {
position: relative;
z-index: 1;
}
.westgate-brand-hero__veil {
position: absolute;
inset: auto 0 0 0;
height: 54%;
background: linear-gradient(180deg, rgba(11, 8, 15, 0), rgba(34, 15, 30, 0.62));
z-index: 0;
pointer-events: none;
}
.westgate-brand-hero__inner {
align-items: center;
justify-content: center;
gap: 0;
min-height: 128px;
}
.westgate-brand-hero__brand {
width: 100%;
flex-wrap: wrap;
min-height: inherit;
padding: 0 0 0 clamp(1rem, 4vw, 3rem);
&: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__brand [component="siteTitle"] {
width: 100%;
padding: 0;
justify-content: flex-start;
}
.westgate-brand-hero__title-block {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.35rem;
}
.westgate-brand-hero__brand [component="siteTitle"] :where(h1, .fs-6) {
font-family: var(--wg-font-display);
font-size: clamp(1.65rem, 2.8vw, 2.5rem) !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.86rem;
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;
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: 0.95rem 0.9rem;
background-position: center 46%;
}
.westgate-brand-hero__inner {
min-height: 108px;
flex-wrap: wrap;
}
.westgate-brand-hero__brand {
min-height: 0;
padding: 0 0 0 0.4rem;
}
.westgate-brand-hero__title-block {
gap: 0.28rem;
}
.westgate-brand-hero__brand [component="siteTitle"] :where(h1, .fs-6) {
font-size: clamp(1.3rem, 5.2vw, 1.8rem) !important;
letter-spacing: 0.07em;
}
.westgate-brand-hero__subtitle {
font-size: 0.74rem;
letter-spacing: 0.18em;
}
.westgate-brand-hero__widgets {
border-top: 1px solid rgba(216, 194, 138, 0.12);
padding-top: 0.85rem;
}
}
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="{function.localeToHTML, userLang, defaultLang}" {{{if languageDirection}}}data-dir="{languageDirection}" style="direction: {languageDirection};"{{{end}}}>
<head>
<title>{browserTitle}</title>
{{{each metaTags}}}{function.buildMetaTag}{{{end}}}
<link rel="stylesheet" type="text/css" href="{relative_path}/assets/client{{{if bootswatchSkin}}}-{bootswatchSkin}{{{end}}}{{{ if (languageDirection=="rtl") }}}-rtl{{{ end }}}.css?{config.cache-buster}" />
{{{each linkTags}}}{function.buildLinkTag}{{{end}}}
<script>
var config = JSON.parse('{{configJSON}}');
var app = {
user: JSON.parse('{{userJSON}}')
};
document.documentElement.style.setProperty('--panel-offset', `0px`);
</script>
{{{if useCustomHTML}}}
{{customHTML}}
{{{end}}}
{{{if useCustomCSS}}}
<style>{{customCSS}}</style>
{{{end}}}
</head>
<body class="{bodyClass} skin-{{{if bootswatchSkin}}}{bootswatchSkin}{{{else}}}noskin{{{end}}}">
<a class="visually-hidden-focusable position-absolute top-0 start-0 p-3 m-3 bg-body" style="z-index: 1021;" href="#content">[[global:skip-to-content]]</a>
{{{ if config.theme.topMobilebar }}}
<!-- IMPORT partials/mobile-header.tpl -->
{{{ end }}}
<div class="layout-container d-flex justify-content-between pb-4 pb-md-0">
<!-- IMPORT partials/sidebar-left.tpl -->
<main id="panel" class="d-flex flex-column gap-3 flex-grow-1 mt-3" style="min-width: 0;">
<div class="container-lg px-md-4 d-flex flex-column gap-3 h-100 mb-5 mb-lg-0" id="content">
<!-- IMPORT partials/header/brand.tpl -->
<!-- IMPORT partials/noscript/warning.tpl -->
<!-- IMPORT partials/noscript/message.tpl -->
+24
View File
@@ -0,0 +1,24 @@
{{{ if (brand:logo || (config.showSiteTitle || widgets.brand-header.length)) }}}
<div class="container-lg px-md-4 brand-container westgate-brand-hero">
<div class="westgate-brand-hero__veil"></div>
<div class="d-flex westgate-brand-hero__inner {{{ if config.theme.centerHeaderElements }}}justify-content-left{{{ end }}}">
{{{ if config.showSiteTitle }}}
<div component="brand/wrapper" class="d-flex align-items-center justify-content-left align-content-stretch westgate-brand-hero__brand">
<a component="siteTitle" class="text-truncate align-self-stretch align-items-center d-flex justify-content-left" href="{{{ if title:url }}}{title:url}{{{ else }}}{relative_path}/{{{ end }}}">
<span class="westgate-brand-hero__title-block">
<h1 class="fs-6 fw-bold text-body mb-0">{config.siteTitle}</h1>
<span class="westgate-brand-hero__subtitle">Forums</span>
</span>
</a>
</div>
{{{ end }}}
{{{ if widgets.brand-header.length }}}
<div data-widget-area="brand-header" class="flex-fill gap-3 align-self-center westgate-brand-hero__widgets">
{{{each widgets.brand-header}}}
{{./html}}
{{{end}}}
</div>
{{{ end }}}
</div>
</div>
{{{ end }}}
+1
View File
@@ -1,5 +1,6 @@
@import "../nodebb-theme-harmony/theme"; @import "../nodebb-theme-harmony/theme";
@import "./scss/westgate/tokens"; @import "./scss/westgate/tokens";
@import "./scss/westgate/header";
@import "./scss/westgate/surfaces"; @import "./scss/westgate/surfaces";
@import "./scss/westgate/categories"; @import "./scss/westgate/categories";
@import "./scss/westgate/topics"; @import "./scss/westgate/topics";