diff --git a/docs/VUE-MIGRATION.md b/docs/VUE-MIGRATION.md index 9db7fcbfc..f88ade519 100644 --- a/docs/VUE-MIGRATION.md +++ b/docs/VUE-MIGRATION.md @@ -42,6 +42,16 @@ one-panel rule too. Share links continue to record which panels are open. this repository and styled by its existing stylesheet and custom properties. They contain no application state. +Controls share one skin, so every panel reads the same. Every scrolling +surface carries the kit's `.ui-scroll` (ui-vue's name), which draws the thin +themed scrollbar from `--scroll-thumb` and `--scroll-track`; the Cyber theme +sets those two tokens, and Cockpit's HUD windows keep their accent tint. A +surface without it would draw the platform's light scrollbar, because the +page declares no dark `color-scheme`. Selects and number fields are +`.gev-field`, which draws its own chevron in place of the platform's arrow +and keeps native spinners dark; ranges are `.gev-quantitative-slider`, with +a feature supplying only its accent. + ## Phases 1. **Foundation.** Vue, Pinia and the Vite Vue plugin join the browser build diff --git a/src/contextTabKeyboard.test.mjs b/src/contextTabKeyboard.test.mjs index 05e013e96..adc176196 100644 --- a/src/contextTabKeyboard.test.mjs +++ b/src/contextTabKeyboard.test.mjs @@ -95,9 +95,9 @@ test('Context async action buttons remain focused while busy', () => { }); test('Context header holds only its title and collapse control', () => { - const panel = html.match(/
([\s\S]*?)<\/div>\s*
([\s\S]*?)<\/div>\s*
`${tag}.${cls}`); assert.deepEqual(tags, ['span.panel-title', 'span.panel-divider', 'button.panel-collapse-btn']); diff --git a/src/data/bhoteKoshiEmbeddedMedia.js b/src/data/bhoteKoshiEmbeddedMedia.js index 1ea0ccec9..53e21f8f4 100644 --- a/src/data/bhoteKoshiEmbeddedMedia.js +++ b/src/data/bhoteKoshiEmbeddedMedia.js @@ -1054,7 +1054,7 @@ export function createBhoteKoshiEmbeddedMedia({ leader.innerHTML = ''; const player = documentRef.createElement('div'); - player.className = 'bhote-embedded-callout-player'; + player.className = 'bhote-embedded-callout-player ui-scroll'; const footer = documentRef.createElement('footer'); const title = documentRef.createElement('strong'); title.textContent = bhoteEventText( diff --git a/src/data/bhoteKoshiEmbeddedMedia.test.mjs b/src/data/bhoteKoshiEmbeddedMedia.test.mjs index 6829adca5..af6afc1e8 100644 --- a/src/data/bhoteKoshiEmbeddedMedia.test.mjs +++ b/src/data/bhoteKoshiEmbeddedMedia.test.mjs @@ -348,7 +348,7 @@ test('camera updates retain a preload until the visible player loads', () => { assert.equal(frame.parent, root, 'keep the preload while the visible player starts'); const card = root.children.find(node => node.tag === 'section'); const body = card.children.find(node => node.className === 'bhote-embedded-callout-body'); - const player = body.children.find(node => node.className === 'bhote-embedded-callout-player'); + const player = body.children.find(node => node.className.split(' ').includes('bhote-embedded-callout-player')); player.children.find(node => node.tag === 'iframe').dispatchEvent(new Event('load')); assert.equal(frame.parent, null, 'visible player readiness releases the preload'); media.destroy(); diff --git a/src/streetLevelMarkup.test.mjs b/src/streetLevelMarkup.test.mjs index bc1716f14..18a61de42 100644 --- a/src/streetLevelMarkup.test.mjs +++ b/src/streetLevelMarkup.test.mjs @@ -32,7 +32,7 @@ test('Street Level is a collapsible right-rail panel that starts collapsed', () assert.doesNotMatch(html, /sl-mark|mly-mark/); assert.match( html, - /
/, + /
/, ); assert.doesNotMatch( html, diff --git a/src/ui/cyberTheme.test.mjs b/src/ui/cyberTheme.test.mjs index c31eeba8c..1433da97a 100644 --- a/src/ui/cyberTheme.test.mjs +++ b/src/ui/cyberTheme.test.mjs @@ -22,10 +22,14 @@ test('CCTV and Context keep their headers outside Cyber-only scroll bodies', () new URL(`./views/${file}`, import.meta.url), 'utf8', ); - assert.match(markup, /class="cyber-panel-body" data-rail-scroller/); + // The body wears the shared scrollbar skin where Cyber makes it scroll. + assert.match( + markup, + /class="cyber-panel-body ui-scroll" data-rail-scroller/, + ); assert.ok( markup.indexOf('class="panel-header"') < - markup.indexOf('class="cyber-panel-body"'), + markup.indexOf('class="cyber-panel-body ui-scroll"'), ); } const shared = readFileSync( diff --git a/src/ui/localePicker.js b/src/ui/localePicker.js index 41875042d..f21559e1d 100644 --- a/src/ui/localePicker.js +++ b/src/ui/localePicker.js @@ -431,7 +431,7 @@ export function mountLocalePicker({ heading.textContent = t('Interface language'); popup.append(heading); - const listbox = element(documentRef, 'ul', 'locale-picker-list'); + const listbox = element(documentRef, 'ul', 'locale-picker-list ui-scroll'); listbox.id = ids.listbox; listbox.setAttribute('role', 'listbox'); listbox.setAttribute('aria-labelledby', ids.heading); diff --git a/src/ui/rail/RailRowList.vue b/src/ui/rail/RailRowList.vue index 059244207..8778b059c 100644 --- a/src/ui/rail/RailRowList.vue +++ b/src/ui/rail/RailRowList.vue @@ -35,7 +35,7 @@ onUpdated(followCurrent);