diff --git a/.github/workflows/validate-build.yml b/.github/workflows/validate-build.yml index cf8c3729..6293337c 100644 --- a/.github/workflows/validate-build.yml +++ b/.github/workflows/validate-build.yml @@ -95,6 +95,8 @@ jobs: run: npm run test:hero-scroll - name: Test docs page weight (lazy images, trimmed Prism, on-demand highlighting, head) run: npm run test:docs-page-weight + - name: Test the introduced-in version badge + run: npm run test:introduced-in-badge - name: Test the Ask AI latest-version tool run: npm run test:latest-version-tool - name: Cache generated files diff --git a/package.json b/package.json index 6a907c5f..878a0336 100644 --- a/package.json +++ b/package.json @@ -97,11 +97,12 @@ "test:hero-scroll": "node --test tests/hero-scroll/*.test.js", "test:docs-page-weight": "node --test tests/docs-page-weight/*.test.js", "test:callout-preservation": "npx gulp generate:prism && node tests/callout-preservation/test-runner.js", - "test:all": "npm run test:playground && npm run test:interactive && npm run test:negative-cache && npm run test:head-meta && npm run test:latest-version-tool && npm run test:property-tooltips && npm run test:signin-nudge && npm run test:chat-panel-navigation && npm run test:toc-collapsible && npm run test:toc-active-anchor && npm run test:nav-scroll && npm run test:kapa-source-groups && npm run test:tooltip-touch && npm run test:tooltip-single-open && npm run test:lazy-askai && npm run test:nav-lazy-buckets && npm run test:has-code-blocks && npm run test:docs-page-weight && npm run test:anon-quota && npm run test:callout-preservation", + "test:all": "npm run test:playground && npm run test:interactive && npm run test:negative-cache && npm run test:head-meta && npm run test:latest-version-tool && npm run test:introduced-in-badge && npm run test:property-tooltips && npm run test:signin-nudge && npm run test:chat-panel-navigation && npm run test:toc-collapsible && npm run test:toc-active-anchor && npm run test:nav-scroll && npm run test:kapa-source-groups && npm run test:tooltip-touch && npm run test:tooltip-single-open && npm run test:lazy-askai && npm run test:nav-lazy-buckets && npm run test:has-code-blocks && npm run test:docs-page-weight && npm run test:anon-quota && npm run test:callout-preservation", "build:wasm": "cd blobl-editor/wasm && GOOS=js GOARCH=wasm go build -o ../../src/static/blobl.wasm .", "copy:wasm-exec": "cp \"$(go env GOROOT)/lib/wasm/wasm_exec.js\" src/js/vendor/", "serve:playground": "npx serve .", "test:toc-active-anchor": "node --test tests/toc-active-anchor/*.test.js", + "test:introduced-in-badge": "node --test tests/introduced-in-badge/*.test.js", "test:latest-version-tool": "node --test tests/latest-version-tool/*.test.js" }, "dependencies": { diff --git a/preview-src/introduced-in-cloud-test.adoc b/preview-src/introduced-in-cloud-test.adoc new file mode 100644 index 00000000..a8e9f455 --- /dev/null +++ b/preview-src/introduced-in-cloud-test.adoc @@ -0,0 +1,10 @@ += Introduced-In Badge on Cloud +:page-cloud: true +:page-introduced-in: 4.43.0 +:description: This page checks that the version badge never shows on Cloud pages. + +This page sets `:page-cloud: true` and `:page-introduced-in: 4.43.0`. + +== What to check + +* The sticky header shows no "Since" badge. A self-managed version doesn't apply to Cloud, so the badge is hidden on Cloud pages even when a single-sourced page carries the attribute. diff --git a/preview-src/introduced-in-combo-test.adoc b/preview-src/introduced-in-combo-test.adoc new file mode 100644 index 00000000..7f071c71 --- /dev/null +++ b/preview-src/introduced-in-combo-test.adoc @@ -0,0 +1,14 @@ += Introduced-In Badge With Other Badges +:page-beta: true +:page-limited-availability: true +:page-introduced-in: v4.43.0 +:page-introduced-in-product: Redpanda Connect +:description: This page tests the version badge next to the Beta and Limited Availability badges. + +This page sets `:page-beta:`, `:page-limited-availability:`, `:page-introduced-in: v4.43.0` and `:page-introduced-in-product: Redpanda Connect`. + +== What to check + +* The sticky header shows the Beta, Limited Availability and "Since 4.43.0" badges in that order, and wraps cleanly at narrow widths. +* The leading `v` is stripped: the badge reads "Since 4.43.0", not "Since v4.43.0". +* Hovering the version badge shows the tooltip "Introduced in Redpanda Connect 4.43.0." diff --git a/preview-src/introduced-in-test.adoc b/preview-src/introduced-in-test.adoc new file mode 100644 index 00000000..77da9098 --- /dev/null +++ b/preview-src/introduced-in-test.adoc @@ -0,0 +1,30 @@ += Introduced-In Badge Test Page +:page-introduced-in: 4.43.0 +:description: This page tests the version badge that shows the release a feature was introduced in. + +This page sets `:page-introduced-in: 4.43.0`, so the sticky header shows a gray "Since 4.43.0" badge. + +== What to check + +* The "Since 4.43.0" badge appears in the sticky header. +* Hovering the badge shows the tooltip "Introduced in version 4.43.0." +* The badge is readable in both light and dark themes. +* Pages that don't set `:page-introduced-in:`, such as the Limited Availability Test page, show no version badge. +* The Introduced-In Badge With Other Badges page shows the badge next to Beta and Limited Availability, with the product named in the tooltip. +* The Introduced-In Badge on Cloud page sets `:page-introduced-in:` but shows no version badge. + +== Page content + +Some content so you can scroll and check that the badge stays in the sticky header. + +=== Subsection 1 + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +=== Subsection 2 + +Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +=== Subsection 3 + +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. diff --git a/preview-src/ui-model.yml b/preview-src/ui-model.yml index 9e7f50bb..32adcbff 100644 --- a/preview-src/ui-model.yml +++ b/preview-src/ui-model.yml @@ -240,6 +240,15 @@ page: - content: Limited Availability Test url: /limited-availability-test.html urlType: internal + - content: Introduced-In Badge Test + url: /introduced-in-test.html + urlType: internal + - content: Introduced-In Badge With Other Badges + url: /introduced-in-combo-test.html + urlType: internal + - content: Introduced-In Badge on Cloud + url: /introduced-in-cloud-test.html + urlType: internal - content: Preview Status Test url: /preview-status-test.html urlType: internal diff --git a/src/css/doc.css b/src/css/doc.css index a648ae26..a9d616a5 100644 --- a/src/css/doc.css +++ b/src/css/doc.css @@ -439,7 +439,7 @@ html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill-caret { } } -/* Status badges (Beta, Limited Availability) in sticky header */ +/* Status badges (Beta, Preview, Limited Availability, Since) in sticky header */ .status-badge { display: inline-flex; align-items: center; @@ -485,7 +485,9 @@ html[data-theme="dark"] .status-badge--beta { border-color: rgba(251, 191, 36, 0.3); } -html[data-theme="dark"] .status-badge--preview { +/* Since shares the neutral dark palette with Preview */ +html[data-theme="dark"] .status-badge--preview, +html[data-theme="dark"] .status-badge--since { background: rgba(148, 163, 184, 0.15); color: #cbd5e1; border-color: rgba(148, 163, 184, 0.3); @@ -511,6 +513,26 @@ html[data-theme="dark"] .status-badge--cloud { border-color: rgba(14, 165, 233, 0.3); } +.status-badge--since { + background: #f3f4f6; + color: #374151; + border: 1px solid #d1d5db; + font-weight: 500; +} + +/* Full badge text for screen readers; the visible "Since X" is aria-hidden */ +.status-badge__sr-text { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + /* Availability badges: links to the other platform's version of this page */ a.status-badge--cloud-link, a.status-badge--self-managed-link { diff --git a/src/helpers/normalize-version.js b/src/helpers/normalize-version.js new file mode 100644 index 00000000..c9fb51f3 --- /dev/null +++ b/src/helpers/normalize-version.js @@ -0,0 +1,9 @@ +'use strict' + +// Normalizes a hand-set version string for display: trims whitespace, drops a +// leading "v" (v4.43.0 -> 4.43.0) and any trailing periods, so a value of +// "4.43.0." doesn't print "4.43.0.." in a sentence. Returns '' for no value. +module.exports = (val) => { + if (val == null || typeof val === 'object') return '' + return String(val).trim().replace(/^v(?=\d)/i, '').replace(/\.+$/, '') +} diff --git a/src/partials/article.hbs b/src/partials/article.hbs index 94bd7dc4..bd69162d 100644 --- a/src/partials/article.hbs +++ b/src/partials/article.hbs @@ -24,7 +24,7 @@ {{/with}} {{> version-selector}} - {{!-- Status badges: Beta, Preview, Limited Availability --}} + {{!-- Status badges: Beta, Preview, Limited Availability, Since (version) --}} {{#if page.attributes.beta}} beta {{/if}} @@ -39,6 +39,19 @@ Limited Availability {{/if}} + {{!-- Version badge: the release that introduced the page's feature. + :page-introduced-in: takes a bare X.Y.Z (a leading v or trailing period + is stripped). :page-introduced-in-product: names the product in the + tooltip, for example "Redpanda Connect"; without it the tooltip says + "version". Never shown on Cloud pages: a self-managed version doesn't + apply there, even if a single-sourced page carries the attribute. --}} + {{#if (and page.attributes.introduced-in (not page.attributes.cloud))}} + {{#with (normalize-version page.attributes.introduced-in)}} + {{!-- One source for the tooltip and the screen reader text, so they can't drift --}} + {{#*inline "introduced-in-text"}}Introduced in {{#if @root.page.attributes.introduced-in-product}}{{@root.page.attributes.introduced-in-product}}{{else}}version{{/if}} {{this}}.{{/inline}} + {{> introduced-in-text}} + {{/with}} + {{/if}} {{!-- ADP platform badges: only show when limited to one platform --}} {{#if page.attributes.adp}} {{#if page.attributes.byoc-only}} diff --git a/tests/introduced-in-badge/introduced-in-badge.test.js b/tests/introduced-in-badge/introduced-in-badge.test.js new file mode 100644 index 00000000..bbab7a68 --- /dev/null +++ b/tests/introduced-in-badge/introduced-in-badge.test.js @@ -0,0 +1,82 @@ +'use strict' + +// Verifies the "Since X" version badge in src/partials/article.hbs, rendered +// with the REAL helpers this repo ships (and.js, not.js, normalize-version.js). +// The badge block is sliced out of the partial, so a change to the template is +// what gets tested, not a copy of it. + +const test = require('node:test') +const assert = require('node:assert/strict') +const path = require('node:path') +const fs = require('node:fs') +const Handlebars = require('handlebars') + +const ROOT = path.join(__dirname, '..', '..') +const hbs = Handlebars.create() +hbs.registerHelper('and', require(path.join(ROOT, 'src/helpers/and.js'))) +hbs.registerHelper('not', require(path.join(ROOT, 'src/helpers/not.js'))) +hbs.registerHelper('normalize-version', require(path.join(ROOT, 'src/helpers/normalize-version.js'))) + +const ARTICLE_SRC = fs.readFileSync(path.join(ROOT, 'src/partials/article.hbs'), 'utf8') +const FROM = '{{!-- Status badges:' +const TO = '{{!-- ADP platform badges' +const start = ARTICLE_SRC.indexOf(FROM) +const end = ARTICLE_SRC.indexOf(TO) +assert.ok(start >= 0 && end > start, `article.hbs changed under this test: could not find ${FROM} .. ${TO}`) +const BADGES = hbs.compile(ARTICLE_SRC.slice(start, end)) + +const render = (attributes) => BADGES({ page: { attributes } }) +const sinceBadges = (html) => html.match(/status-badge--since/g) || [] +const tooltip = (html) => (html.match(/status-badge--since" data-tippy-content="([^"]*)"/) || [])[1] +const visible = (html) => (html.match(/