- Token sweep: exact-value gold literals now use --wg-border / --wg-border-soft / --wg-focus - Topbar: drop invalid role="menuitem" (no parent role="menu") - topics_list: topic-select icons get role="checkbox", tabindex, aria-label; client.js makes them keyboard-operable and syncs aria-checked - category.tpl: copy-handle link gets an accessible name, "View Original" moved to i18n, external-link icon aria-hidden, stretched link inside aria-hidden alert removed from tab order - Footer: all copy moved to [[westgate:footer.*]] keys; year injected via filter:middleware.renderFooter instead of hard-coded 2026 - client.js: batch table measurements before writes (no interleaved reflow), .catch on the category class map so search results never hang, category selector match uses fw-bold class instead of inline style - Forced-colors focus fallback: transparent outline alongside the box-shadow focus ring - DESIGN.md: real radius scale (3/4/6/8px), code-block palette, motion & modes section, placeholder alpha Verified against the sow-nodebb dev container: themed code blocks render in posts, footer i18n + year, checkbox roles in served HTML. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
101 lines
4.0 KiB
Smarty
101 lines
4.0 KiB
Smarty
<!-- IMPORT partials/breadcrumbs-json-ld.tpl -->
|
|
{{{ if config.theme.enableBreadcrumbs }}}
|
|
<!-- IMPORT partials/breadcrumbs.tpl -->
|
|
{{{ end }}}
|
|
|
|
<div class="category-header d-flex flex-column gap-2">
|
|
<div class="d-flex gap-3 align-items-center mb-1 {{{ if config.theme.centerHeaderElements }}}justify-content-center flex-column{{{ end }}}">
|
|
<div class="westgate-category-header-icon flex-shrink-0 {./class}">
|
|
{{buildCategoryIcon(@value, "60px", "rounded-1")}}
|
|
</div>
|
|
<div class="d-flex flex-column gap-1">
|
|
<h1 class="tracking-tight fs-3 fw-semibold mb-0">{{tx(./name)}}</h1>
|
|
<div class="d-flex flex-wrap gap-2 align-items-center {{{ if config.theme.centerHeaderElements }}}justify-content-center{{{ end }}}">
|
|
<span class="badge text-body border border-gray-300 stats text-xs">
|
|
<span title="{formattedNumber(totalTopicCount)}" class="fw-bold">{humanReadableNumber(totalTopicCount)}</span>
|
|
<span class="text-lowercase fw-normal">[[global:topics]]</span>
|
|
</span>
|
|
<span class="badge text-body border border-gray-300 stats text-xs">
|
|
<span title="{formattedNumber(totalPostCount)}" class="fw-bold">{humanReadableNumber(totalPostCount)}</span>
|
|
<span class="text-lowercase fw-normal">[[global:posts]]</span>
|
|
</span>
|
|
{{{ if !isNumber(cid) }}}
|
|
<a href="{./url}" class="badge text-body border border-gray-300 text-xs" data-ajaxify="false">
|
|
<span class="fw-normal">[[westgate:view-original]]</span>
|
|
<i class="fa fa-external-link" aria-hidden="true"></i>
|
|
</a>
|
|
{{{ end }}}
|
|
{{{ if (!feeds:disableRSS && rssFeedUrl) }}}
|
|
<a class="badge text-body text-decoration-none border border-gray-300 d-flex align-items-center align-self-stretch" target="_blank" href="{rssFeedUrl}" itemprop="item" title="[[global:rss-feed]]"><i class="fa fa-rss fa-sm text-muted lh-1"></i></a>
|
|
{{{ end }}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{{ if ./descriptionParsed }}}
|
|
<div class="description text-secondary text-sm lh-sm w-100 {{{ if config.theme.centerHeaderElements }}}text-center{{{ end }}} line-clamp-4 clamp-fade-sm-4">
|
|
{{./descriptionParsed}}
|
|
</div>
|
|
{{{ end }}}
|
|
{{{ if ./handleFull }}}
|
|
<p class="text-secondary text-sm fst-italic mb-0 {{{ if config.theme.centerHeaderElements }}}text-center{{{ end }}}">
|
|
[[category:handle.description, {handleFull}]]
|
|
<a href="#" class="link-secondary" data-action="copy" data-clipboard-text="{handleFull}" aria-label="[[westgate:copy-handle]]"><i class="fa fa-fw fa-copy" aria-hidden="true"></i></a>
|
|
</p>
|
|
{{{ end }}}
|
|
|
|
</div>
|
|
|
|
{{{ if widgets.header.length }}}
|
|
<div data-widget-area="header">
|
|
{{{ each widgets.header }}}
|
|
{{widgets.header.html}}
|
|
{{{ end }}}
|
|
</div>
|
|
{{{ end }}}
|
|
|
|
|
|
<div class="row flex-fill mt-3">
|
|
<div class="category d-flex flex-column {{{if widgets.sidebar.length }}}col-lg-9 col-sm-12{{{ else }}}col-lg-12{{{ end }}}">
|
|
<!-- IMPORT partials/category/subcategory.tpl -->
|
|
{{{ if (topics.length || privileges.topics:create) }}}
|
|
<!-- IMPORT partials/topic-list-bar.tpl -->
|
|
{{{ end }}}
|
|
|
|
{{{ if (./inbox && (./hasFollowers == false)) }}}
|
|
<div class="alert alert-warning mb-4" id="category-no-followers" data-bs-toggle="dropdown" data-bs-target='[component="topic/watch"] button' aria-hidden="true">
|
|
<i class="fa fa-triangle-exclamation pe-2"></i>
|
|
[[category:no-followers]]
|
|
<a href="#" class="stretched-link" tabindex="-1"></a>
|
|
</div>
|
|
{{{ end }}}
|
|
|
|
{{{ if (!topics.length && privileges.topics:create) }}}
|
|
<div class="alert alert-info" id="category-no-topics">
|
|
[[category:no-topics]]
|
|
</div>
|
|
{{{ end }}}
|
|
|
|
<!-- IMPORT partials/topics_list.tpl -->
|
|
|
|
{{{ if config.usePagination }}}
|
|
<!-- IMPORT partials/paginator.tpl -->
|
|
{{{ end }}}
|
|
</div>
|
|
<div data-widget-area="sidebar" class="col-lg-3 col-sm-12 {{{ if !widgets.sidebar.length }}}hidden{{{ end }}}">
|
|
{{{ each widgets.sidebar }}}
|
|
{{widgets.sidebar.html}}
|
|
{{{ end }}}
|
|
</div>
|
|
</div>
|
|
<div data-widget-area="footer">
|
|
{{{each widgets.footer}}}
|
|
{{widgets.footer.html}}
|
|
{{{end}}}
|
|
</div>
|
|
|
|
{{{ if !config.usePagination }}}
|
|
<noscript>
|
|
<!-- IMPORT partials/paginator.tpl -->
|
|
</noscript>
|
|
{{{ end }}}
|