From aa81ab9a11ee3e18ea7a679e639697d4ddc0733d Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Thu, 2 Jul 2026 10:16:05 +0200 Subject: [PATCH 1/2] docs: spec for wiki badge in global search results Theme-only slice: render wiki-tagged search results with a wiki badge and link to /wiki, in the quick-search dropdown and /search page. Depends on the wiki plugin tagging results with isWikiArticle + wikiPath. Co-Authored-By: Claude Opus 4.8 --- ...6-07-02-wiki-search-result-badge-design.md | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md diff --git a/docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md b/docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md new file mode 100644 index 0000000..44489ea --- /dev/null +++ b/docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md @@ -0,0 +1,88 @@ +# Wiki Badge in Global Search Results — Theme Design + +Date: 2026-07-02 +Status: Approved for planning +Scope: theme-only slice of the cross-repo "wiki in global search" work. + +Companion spec (drives this): `sow-nodebb-plugin-wiki` → +`docs/superpowers/specs/2026-07-02-wiki-global-search-design.md`. The wiki +plugin makes wiki articles searchable and tags each wiki result with +`isWikiArticle: true` and `wikiPath` (`/wiki/...`). **This spec covers only the +rendering of those tagged results in the theme.** + +## Problem + +The theme currently ships no search-result overrides — global search +(quick-search dropdown + `/search` page) renders with stock NodeBB templates. +Once the wiki plugin surfaces wiki articles in search, those results need to be +visually marked as wiki and to link to `/wiki/...` instead of `/topic/...`. + +## Input contract (from the wiki plugin) + +Each search result object may carry: + +- `isWikiArticle` — `true` for wiki article hits. +- `wikiPath` — the `/wiki/...` URL for the article. + +Forum results do not carry these; they render unchanged. + +## Design + +Mark wiki result rows and point them at the wiki URL, in **both** surfaces: + +1. **`/search` page** — the full results list. +2. **Quick-search dropdown** — the navbar type-ahead results. + +For each row where `isWikiArticle` is set: + +- show a wiki icon/badge (e.g. a book/wiki icon plus a small "Wiki" label), + consistent with existing theme iconography (see `GAME_ICONS.md`); +- set the result's link `href` to `wikiPath`. + +Rows stay in the single relevance-ranked list returned by search; no grouping or +reordering. + +### Approach — decide during planning + +Two ways to inject this; pick the smaller one that works against the pinned +NodeBB version: + +- **Template override (preferred if a small partial isolates the row):** add a + theme override of the NodeBB search result partial(s) — the quick-search + results partial and the `/search` results partial — with a conditional badge + and `wikiPath` link. Keeps logic declarative and server-rendered. +- **Client-side decoration (fallback):** in `public/client.js`, after results + render, decorate rows flagged `isWikiArticle` (badge + rewrite href). Smaller + surface if the stock partials are awkward to override cleanly, but relies on + the data being present in the client payload. + +Planning resolves which, based on the actual stock partials in the pinned +NodeBB/theme base. + +## Styling + +Add badge styles in the theme SCSS (`scss/`, wired via `theme.scss`), matching +existing badge/pill conventions. No new dependencies. + +## Non-goals + +- No search *behavior* changes — indexing, matching, ranking, and result tagging + all live in the wiki plugin. +- No grouping/separate section — inline badge only. +- No changes to non-search surfaces. + +## Testing / verification + +- Visual: run the dev stack (`docker-compose.dev.yml` in `sow-nodebb`), search a + term matching a wiki article, confirm the result shows the wiki badge and its + link goes to `/wiki/...`; confirm forum results are unchanged. Check both the + dropdown and the `/search` page. +- Snapshot/DOM assertions only if the theme's existing test setup (`tests/`) + makes them cheap; otherwise rely on the visual check (badge/link is not + complex logic). + +## Dependencies / sequencing + +Depends on the wiki plugin emitting `isWikiArticle` + `wikiPath` on results. +Theme work can be built against a stubbed result but is only end-to-end +verifiable once the plugin side lands. -- 2.54.0 From 32716f8ff1fd9b45edd0c408786bc52ee10752a2 Mon Sep 17 00:00:00 2001 From: vickydotbat Date: Fri, 3 Jul 2026 08:59:24 +0200 Subject: [PATCH 2/2] feat: wiki badge and /wiki links in global search results Override Harmony's search partials so results tagged by the wiki plugin (isWikiArticle + wikiPath) show a gold Wiki badge and link to /wiki/... instead of /post/..., in the quick-search dropdown and both /search views. Forum results render unchanged; posts_list_item is shared with account and group pages, where the flags are never set and the conditional no-ops. Co-Authored-By: Claude Fable 5 --- ...6-07-02-wiki-search-result-badge-design.md | 7 +++ languages/en-GB/westgate.json | 3 + scss/westgate/_search.scss | 17 ++++++ templates/partials/posts_list_item.tpl | 28 ++++++++++ templates/partials/quick-search-results.tpl | 50 +++++++++++++++++ templates/partials/search-results.tpl | 55 +++++++++++++++++++ tests/wiki-search-badge-contract.test.js | 42 ++++++++++++++ theme.scss | 1 + 8 files changed, 203 insertions(+) create mode 100644 languages/en-GB/westgate.json create mode 100644 scss/westgate/_search.scss create mode 100644 templates/partials/posts_list_item.tpl create mode 100644 templates/partials/quick-search-results.tpl create mode 100644 templates/partials/search-results.tpl create mode 100644 tests/wiki-search-badge-contract.test.js diff --git a/docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md b/docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md index 44489ea..fb6c75c 100644 --- a/docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md +++ b/docs/superpowers/specs/2026-07-02-wiki-search-result-badge-design.md @@ -59,6 +59,13 @@ NodeBB version: Planning resolves which, based on the actual stock partials in the pinned NodeBB/theme base. +**Resolved (2026-07-03): template override.** Harmony's row markup is small and +self-contained, so the theme overrides `partials/posts_list_item.tpl` (`/search` +posts view — shared with account/groups pages, where the wiki flags are never +set and the conditional no-ops), `partials/search-results.tpl` (`/search` topics +view), and `partials/quick-search-results.tpl` (dropdown). No client-side +decoration needed. + ## Styling Add badge styles in the theme SCSS (`scss/`, wired via `theme.scss`), matching diff --git a/languages/en-GB/westgate.json b/languages/en-GB/westgate.json new file mode 100644 index 0000000..6b3e767 --- /dev/null +++ b/languages/en-GB/westgate.json @@ -0,0 +1,3 @@ +{ + "wiki-badge": "Wiki" +} diff --git a/scss/westgate/_search.scss b/scss/westgate/_search.scss new file mode 100644 index 0000000..ba19512 --- /dev/null +++ b/scss/westgate/_search.scss @@ -0,0 +1,17 @@ +/* Wiki badge on global search results (quick-search dropdown + /search page). + Marks results tagged by nodebb-plugin-westgate-wiki (isWikiArticle/wikiPath). */ +.westgate-wiki-badge { + font-family: var(--wg-font-ui); + font-size: 0.62em; + font-weight: 600; + letter-spacing: 0.09em; + text-transform: uppercase; + color: var(--wg-gold); + background: rgba(194, 163, 90, 0.1); + border: 1px solid var(--wg-ledger-border); + vertical-align: middle; +} + +.quick-search-results .westgate-wiki-badge { + font-size: 0.7rem; +} diff --git a/templates/partials/posts_list_item.tpl b/templates/partials/posts_list_item.tpl new file mode 100644 index 0000000..9637d78 --- /dev/null +++ b/templates/partials/posts_list_item.tpl @@ -0,0 +1,28 @@ +
  • +
    + + {{{ if ./isWikiArticle }}} [[westgate:wiki-badge]] {{{ else }}}{{{ if ./isMainPost }}} {{{ end }}}{{{ end }}}{./topic.title} + + +
    + + +
    + {./content} +
    +
    +
    + {buildCategoryLabel(./category, "a", "border")} + + {{{ each ./topic.tags }}} + {./valueEscaped} + {{{ end }}} + +
    +
  • \ No newline at end of file diff --git a/templates/partials/quick-search-results.tpl b/templates/partials/quick-search-results.tpl new file mode 100644 index 0000000..3e60396 --- /dev/null +++ b/templates/partials/quick-search-results.tpl @@ -0,0 +1,50 @@ +{{{ if (multiplePages && !config.theme.topMobilebar) }}} + +{{{ end }}} + + + +{{{ if multiplePages }}} + +{{{ end }}} +{{{ if (multiplePages && config.theme.topMobilebar) }}} + +{{{ end }}} + +{{{if !posts.length}}} +
    [[search:no-matches]] + +{{{end}}} \ No newline at end of file diff --git a/templates/partials/search-results.tpl b/templates/partials/search-results.tpl new file mode 100644 index 0000000..fd5327b --- /dev/null +++ b/templates/partials/search-results.tpl @@ -0,0 +1,55 @@ +{{{ if matchCount }}} +
    [[search:results-matching, {matchCount}, {search_query}, {time}]]
    +{{{ else }}} +{{{ if search_query }}} +
    [[search:no-matches]]
    +{{{ end }}} +{{{ end }}} + +
    + {{{ if showAsPosts }}} + {{{ if posts.length }}} + + {{{ end }}} + {{{ end }}} + + {{{ if showAsTopics }}} + {{{ each posts }}} +
    + + {{{ end }}} + {{{ end }}} + + {{{ if users.length }}} + + {{{ end }}} + + {{{ if tags.length }}} +
    + +
    + {{{ end }}} + + {{{ if categories.length }}} +
      + {{{each categories}}} + + {{{end}}} +
    + {{{ end }}} + + +
    \ No newline at end of file diff --git a/tests/wiki-search-badge-contract.test.js b/tests/wiki-search-badge-contract.test.js new file mode 100644 index 0000000..c998292 --- /dev/null +++ b/tests/wiki-search-badge-contract.test.js @@ -0,0 +1,42 @@ +'use strict'; + +// Contract: search results tagged by nodebb-plugin-westgate-wiki +// (isWikiArticle + wikiPath) render with a wiki badge and link to /wiki/..., +// while untagged forum results keep the stock /post/... link. + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +function read(relativePath) { + const filePath = path.join(__dirname, '..', relativePath); + assert(fs.existsSync(filePath), `${relativePath} should exist`); + return fs.readFileSync(filePath, 'utf8'); +} + +function assertIncludes(haystack, needle, message) { + assert( + haystack.includes(needle), + message || `Expected file to include ${needle}` + ); +} + +[ + ['templates/partials/posts_list_item.tpl', './isWikiArticle', '{./wikiPath}', '/post/{encodeURIComponent(./pid)}'], + ['templates/partials/search-results.tpl', './isWikiArticle', '{./wikiPath}', '/post/{encodeURIComponent(./pid)}'], + ['templates/partials/quick-search-results.tpl', 'posts.isWikiArticle', '{posts.wikiPath}', '/post/{encodeURIComponent(posts.pid)}'], +].forEach(([templatePath, flag, wikiHref, forumHref]) => { + const template = read(templatePath); + assertIncludes(template, flag, `${templatePath} should branch on the wiki result flag`); + assertIncludes(template, wikiHref, `${templatePath} should link wiki results to their wikiPath`); + assertIncludes(template, forumHref, `${templatePath} should keep the stock post link for forum results`); + assertIncludes(template, 'westgate-wiki-badge', `${templatePath} should render the wiki badge`); +}); + +assertIncludes(read('theme.scss'), 'westgate/search', 'theme.scss should import the search styles'); +assertIncludes(read('scss/westgate/_search.scss'), '.westgate-wiki-badge', 'search styles should define the wiki badge'); + +const languageKeys = JSON.parse(read('languages/en-GB/westgate.json')); +assert(languageKeys['wiki-badge'], 'westgate language file should define the wiki-badge label'); + +console.log('wiki search badge contract tests passed'); diff --git a/theme.scss b/theme.scss index ed6fbfc..39ae4b7 100644 --- a/theme.scss +++ b/theme.scss @@ -7,6 +7,7 @@ @import "./scss/westgate/categories"; @import "./scss/westgate/topics"; @import "./scss/westgate/posts"; +@import "./scss/westgate/search"; @import "./scss/westgate/controls"; @import "./scss/westgate/widgets"; @import "./scss/westgate/responsive"; -- 2.54.0