import assert from 'node:assert/strict'; import test from 'node:test'; import { isXUrl, redundantNavPanes, type PaneBox } from '../src/shell/paneModel.ts'; import { buildPaneNavCss, withAlpha } from '../src/inject/paneNav.ts'; const pane = (id: string, x: number, y = 0, extra: Partial = {}): PaneBox => ({ id, url: 'https://x.com/home', profile: 'default', x, y, visible: true, ...extra }); test('only the leftmost X pane of an account keeps the navigation', () => { assert.deepEqual([...redundantNavPanes([pane('right', 800), pane('left', 0)])], ['right']); assert.deepEqual([...redundantNavPanes([pane('a', 0), pane('b', 600), pane('c', 1200)])].sort(), ['b', 'c']); }); test('stacked panes: the top one keeps it', () => { assert.deepEqual([...redundantNavPanes([pane('bottom', 0, 400), pane('top', 0, 40)])], ['bottom']); }); test('a single X pane, or one next to another site, keeps its navigation', () => { assert.equal(redundantNavPanes([pane('only', 400)]).size, 0); assert.equal(redundantNavPanes([pane('site', 0, 0, { url: 'https://github.com/' }), pane('x', 700)]).size, 0); }); test('panes of different accounts each keep their own navigation', () => { const panes = [pane('main', 0), pane('alt', 700, 0, { profile: 'p2' }), pane('main-2', 1400)]; assert.deepEqual([...redundantNavPanes(panes)], ['main-2']); }); test('hidden tabs are not judged and do not take the lead', () => { const panes = [pane('hidden-left', 0, 0, { visible: false }), pane('shown', 700)]; assert.equal(redundantNavPanes(panes).size, 0); }); test('isXUrl: x.com and twitter.com over https only', () => { for (const url of ['https://x.com/home', 'https://twitter.com/jack', 'https://mobile.x.com/i/chat']) assert.ok(isXUrl(url), url); for (const url of ['http://x.com/home', 'https://x.com.evil.test/', 'https://notx.com/', 'about:blank', 'nonsense']) assert.equal(isXUrl(url), false, url); }); const PAINT = { width: 88, background: 'rgb(0, 0, 0)', line: 'rgba(1, 2, 3, 0.16)', accent: 'rgb(29, 155, 240)', rtl: false }; test('pane CSS parks the rail only while the html attribute is set', () => { const css = buildPaneNavCss(PAINT); for (const rule of css.split('}').map(part => part.trim()).filter(Boolean)) { const selector = rule.split('{')[0]!; // Every rule is scoped: to the parked state, to our own edge element, or inside the motion query. assert.ok(/html\[data-bt-pane-nav|#bt-rail-edge|@media/.test(selector), selector); } assert.match(css, /width: 88px !important/); assert.match(css, /translateX\(-100%\)/); assert.match(css, /\[data-bt-pane-nav="peek"\]/); // Centering follows either kind of rail, not only X's classic header. assert.match(css, /\[data-bt-rail\]\) ~ main\[role="main"\]/); }); test('RTL: the rail parks and slides in on the right', () => { const css = buildPaneNavCss({ ...PAINT, rtl: true }); assert.match(css, /right: 0 !important; left: auto !important/); assert.match(css, /translateX\(100%\)/); assert.doesNotMatch(css, /translateX\(-100%\)/); assert.match(css, /#bt-rail-edge \{ position: fixed; right: 0/); }); test('withAlpha keeps the channels and swaps the alpha', () => { assert.equal(withAlpha('rgb(231, 233, 234)', 0.16), 'rgba(231, 233, 234, 0.16)'); assert.equal(withAlpha('rgba(15, 20, 25, 1)', 0.5), 'rgba(15, 20, 25, 0.5)'); assert.equal(withAlpha('', 0.2), 'rgba(128, 128, 128, 0.2)'); });