Skip to content

Commit 1971f5c

Browse files
committed
fix: sidebar active state matching
- Change isActive to exact path matching instead of startsWith - Add trailing slash removal to normalize function - Add comprehensive tests for route functions
1 parent 244db7b commit 1971f5c

File tree

2 files changed

+85
-8
lines changed

2 files changed

+85
-8
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { isActive, normalize } from '../route'
3+
4+
describe('normalize', () => {
5+
it('removes leading slash', () => {
6+
expect(normalize('/path/to/page')).toBe('path/to/page')
7+
})
8+
9+
it('removes trailing slash', () => {
10+
expect(normalize('path/to/page/')).toBe('path/to/page')
11+
})
12+
13+
it('removes .md extension', () => {
14+
expect(normalize('path/to/page.md')).toBe('path/to/page')
15+
})
16+
17+
it('removes .html extension', () => {
18+
expect(normalize('path/to/page.html')).toBe('path/to/page')
19+
})
20+
21+
it('removes index.md', () => {
22+
expect(normalize('path/to/index.md')).toBe('path/to')
23+
})
24+
25+
it('removes index.html', () => {
26+
expect(normalize('path/to/index.html')).toBe('path/to')
27+
})
28+
29+
it('removes leading index.md', () => {
30+
expect(normalize('index.md')).toBe('')
31+
})
32+
33+
it('removes hash fragments', () => {
34+
expect(normalize('path/to/page#section')).toBe('path/to/page')
35+
})
36+
37+
it('removes query parameters', () => {
38+
expect(normalize('path/to/page?param=value')).toBe('path/to/page')
39+
})
40+
41+
it('handles complex case', () => {
42+
expect(normalize('/path/to/index.md#section')).toBe('path/to')
43+
})
44+
})
45+
46+
describe('isActive', () => {
47+
it('returns false when matchPath is undefined', () => {
48+
expect(isActive('path/to/page', undefined)).toBe(false)
49+
})
50+
51+
it('returns true for exact path match', () => {
52+
expect(isActive('nimiq-icons/explorer.html', '/nimiq-icons/explorer')).toBe(true)
53+
})
54+
55+
it('returns false for non-matching paths', () => {
56+
expect(isActive('nimiq-icons/explorer.html', '/nimiq-icons')).toBe(false)
57+
})
58+
59+
it('returns true for index page matching module root', () => {
60+
expect(isActive('nimiq-icons/index.html', '/nimiq-icons')).toBe(true)
61+
})
62+
63+
it('returns true for exact match with extensions and slashes', () => {
64+
expect(isActive('/path/to/page.md', 'path/to/page')).toBe(true)
65+
})
66+
67+
it('returns false for partial matches that should not be active', () => {
68+
expect(isActive('nimiq-icons-extended/page.html', '/nimiq-icons')).toBe(false)
69+
})
70+
71+
it('handles hash fragments in match path', () => {
72+
expect(isActive('path/to/page.md', '/path/to/page#section')).toBe(false) // simplified without browser hash check
73+
})
74+
75+
it('normalizes paths before comparison', () => {
76+
expect(isActive('path/to/index.md', '/path/to/')).toBe(true)
77+
})
78+
})

packages/nimiq-vitepress-theme/src/lib/route.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ export function isActive(currentPath: string, matchPath?: string): boolean {
1111
const normalizedCurrent = normalize(currentPath)
1212
const normalizedMatch = normalize(matchPath)
1313

14-
// Check if current path starts with the match path
15-
if (!normalizedCurrent.startsWith(normalizedMatch))
16-
return false
17-
14+
// If there's a hash in the match path, check it specifically
1815
const hashMatch = matchPath.match(HASH_RE)
19-
if (hashMatch)
20-
return (inBrowser ? location.hash : '') === hashMatch[0]
16+
if (hashMatch) {
17+
return normalizedCurrent === normalizedMatch && (inBrowser ? location.hash : '') === hashMatch[0]
18+
}
2119

22-
return true
20+
// For exact path matching, return true only if they are exactly the same
21+
return normalizedCurrent === normalizedMatch
2322
}
2423

2524
export function normalize(path: string): string {
26-
return decodeURI(path).replace(HASH_OR_QUERY_RE, '').replace(INDEX_OR_EXT_RE, '$1')
25+
return decodeURI(path).replace(HASH_OR_QUERY_RE, '').replace(INDEX_OR_EXT_RE, '$1').replace(/^\//, '').replace(/\/$/, '')
2726
}

0 commit comments

Comments
 (0)