The sidebar was the project's actual nav (the design doc called it 'top nav' but the existing app is sidebar-driven). Five entries reflecting the doc-centric IA replace the seven analysis-centric ones. Sidebar - shared/ui/AppSidebar.vue: data-driven over a NavItem[] table instead of seven hard-coded RouterLinks. Inline SVG icon components keep the visual weight close to the previous version with no new dependency. - Five entries: Home / Docs (★ primary, bolder label) / Stores / Runs / Settings. - Active state via matchesActive(path, prefixes): exact match for Home, prefix match (with segment / query boundary) for the others. Pure helper in shared/ui/navActive.ts, unit tested. Removed from the sidebar (legacy pages still reachable by URL): Studio, Documents, Search, Reasoning, History. i18n - nav.docs / nav.stores / nav.runs added in fr + en, grouped under the 0.6.0 nav block. - Legacy nav labels (nav.studio / nav.documents / nav.history / nav.reasoning / nav.search) kept — the legacy pages still render headings using them. Duplicate nav.search entries removed (the key now lives once per locale, in the nav block). Tests - shared/ui/navActive.test.ts (5 cases): exact-match for Home, prefix boundary semantics, multi-prefix matching, empty list edge. Refs #209
33 lines
1.3 KiB
TypeScript
33 lines
1.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { matchesActive } from './navActive'
|
|
|
|
describe('matchesActive', () => {
|
|
it('matches Home only on the exact / path', () => {
|
|
expect(matchesActive('/', ['/'])).toBe(true)
|
|
expect(matchesActive('/docs', ['/'])).toBe(false)
|
|
expect(matchesActive('/anything', ['/'])).toBe(false)
|
|
})
|
|
|
|
it('matches a non-root prefix on exact, segment, and query boundaries', () => {
|
|
expect(matchesActive('/docs', ['/docs'])).toBe(true)
|
|
expect(matchesActive('/docs/abc', ['/docs'])).toBe(true)
|
|
expect(matchesActive('/docs/abc/123', ['/docs'])).toBe(true)
|
|
expect(matchesActive('/docs?foo=bar', ['/docs'])).toBe(true)
|
|
})
|
|
|
|
it('does not match prefixes that are part of a longer segment', () => {
|
|
expect(matchesActive('/documents', ['/docs'])).toBe(false)
|
|
expect(matchesActive('/docsy', ['/docs'])).toBe(false)
|
|
})
|
|
|
|
it('returns true if any prefix in the list matches', () => {
|
|
expect(matchesActive('/runs/abc', ['/index', '/runs'])).toBe(true)
|
|
expect(matchesActive('/index/foo/query', ['/index', '/runs'])).toBe(true)
|
|
expect(matchesActive('/somewhere-else', ['/index', '/runs'])).toBe(false)
|
|
})
|
|
|
|
it('returns false on empty prefix list', () => {
|
|
expect(matchesActive('/docs', [])).toBe(false)
|
|
})
|
|
})
|