diff options
Diffstat (limited to 'frontend-vanilla/src')
| -rw-r--r-- | frontend-vanilla/src/main.test.ts | 14 | ||||
| -rw-r--r-- | frontend-vanilla/src/main.ts | 26 | ||||
| -rw-r--r-- | frontend-vanilla/src/router.test.ts | 9 | ||||
| -rw-r--r-- | frontend-vanilla/src/router.ts | 2 | ||||
| -rw-r--r-- | frontend-vanilla/src/style.css | 18 |
5 files changed, 44 insertions, 25 deletions
diff --git a/frontend-vanilla/src/main.test.ts b/frontend-vanilla/src/main.test.ts index be5a076..aa0568b 100644 --- a/frontend-vanilla/src/main.test.ts +++ b/frontend-vanilla/src/main.test.ts @@ -21,13 +21,13 @@ vi.mock('./api', () => ({ apiFetch: vi.fn() })); -// Mock IntersectionObserver -const mockObserver = vi.fn(() => ({ - observe: vi.fn(), - unobserve: vi.fn(), - disconnect: vi.fn(), -})); -vi.stubGlobal('IntersectionObserver', mockObserver); +// Mock IntersectionObserver as a constructor +class MockIntersectionObserver { + observe = vi.fn(); + unobserve = vi.fn(); + disconnect = vi.fn(); +} +vi.stubGlobal('IntersectionObserver', MockIntersectionObserver); describe('main application logic', () => { beforeEach(() => { diff --git a/frontend-vanilla/src/main.ts b/frontend-vanilla/src/main.ts index 5e14266..c0a4e66 100644 --- a/frontend-vanilla/src/main.ts +++ b/frontend-vanilla/src/main.ts @@ -95,6 +95,8 @@ export function attachLayoutListeners() { if (!link) return; const navType = link.getAttribute('data-nav'); + const currentQuery = Object.fromEntries(router.getCurrentRoute().query.entries()); + if (navType === 'filter') { e.preventDefault(); const filter = link.getAttribute('data-value') as FilterType; @@ -102,11 +104,11 @@ export function attachLayoutListeners() { } else if (navType === 'tag') { e.preventDefault(); const tag = link.getAttribute('data-value')!; - router.navigate(`/tag/${encodeURIComponent(tag)}`); + router.navigate(`/tag/${encodeURIComponent(tag)}`, currentQuery); } else if (navType === 'feed') { e.preventDefault(); const feedId = link.getAttribute('data-value')!; - router.navigate(`/feed/${feedId}`); + router.navigate(`/feed/${feedId}`, currentQuery); } }); @@ -239,8 +241,9 @@ export function renderSettings() { <section class="settings-section"> <h3>Font</h3> <select id="font-selector"> - <option value="default" ${store.fontTheme === 'default' ? 'selected' : ''}>Default (Serif)</option> + <option value="default" ${store.fontTheme === 'default' ? 'selected' : ''}>Default (Palatino)</option> <option value="serif" ${store.fontTheme === 'serif' ? 'selected' : ''}>Serif (Georgia)</option> + <option value="sans" ${store.fontTheme === 'sans' ? 'selected' : ''}>Sans-Serif (Helvetica)</option> <option value="mono" ${store.fontTheme === 'mono' ? 'selected' : ''}>Monospace</option> </select> </section> @@ -348,8 +351,12 @@ export async function fetchItems(feedId?: string, tagName?: string, append: bool if (feedId) params.append('feed_id', feedId); if (tagName) params.append('tag', tagName); if (store.searchQuery) params.append('q', store.searchQuery); - if (store.filter === 'unread') params.append('read', 'false'); - if (store.filter === 'starred') params.append('starred', 'true'); + if (store.filter === 'starred' || store.filter === 'all') { + params.append('read_filter', 'all'); + } + if (store.filter === 'starred') { + params.append('starred', 'true'); + } if (append && store.items.length > 0) { params.append('max_id', String(store.items[store.items.length - 1]._id)); @@ -382,9 +389,7 @@ function handleRoute() { const route = router.getCurrentRoute(); const filterFromQuery = route.query.get('filter') as FilterType; - if (filterFromQuery && ['unread', 'all', 'starred'].includes(filterFromQuery)) { - store.setFilter(filterFromQuery); - } + store.setFilter(filterFromQuery || 'unread'); const qFromQuery = route.query.get('q'); if (qFromQuery !== null) { @@ -463,10 +468,7 @@ store.on('feeds-updated', renderFeeds); store.on('tags-updated', renderTags); store.on('active-feed-updated', renderFeeds); store.on('active-tag-updated', renderTags); -store.on('filter-updated', () => { - renderFilters(); - handleRoute(); -}); +store.on('filter-updated', renderFilters); store.on('search-updated', () => { const searchInput = document.getElementById('search-input') as HTMLInputElement; if (searchInput && searchInput.value !== store.searchQuery) { diff --git a/frontend-vanilla/src/router.test.ts b/frontend-vanilla/src/router.test.ts index c206d9c..d1a5d7f 100644 --- a/frontend-vanilla/src/router.test.ts +++ b/frontend-vanilla/src/router.test.ts @@ -38,6 +38,15 @@ describe('Router', () => { expect(route.path).toBe('/tag'); expect(route.params.tagName).toBe('Tech News'); }); + it('should parse settings path', () => { + vi.stubGlobal('location', { + href: 'http://localhost/v3/settings', + pathname: '/v3/settings', + search: '' + }); + const route = router.getCurrentRoute(); + expect(route.path).toBe('/settings'); + }); it('should parse query parameters', () => { vi.stubGlobal('location', { diff --git a/frontend-vanilla/src/router.ts b/frontend-vanilla/src/router.ts index 46fbe06..a0ac55a 100644 --- a/frontend-vanilla/src/router.ts +++ b/frontend-vanilla/src/router.ts @@ -28,6 +28,8 @@ export class Router extends EventTarget { } else if (segments[0] === 'tag' && segments[1]) { routePath = '/tag'; params.tagName = decodeURIComponent(segments[1]); + } else if (segments[0] === 'settings') { + routePath = '/settings'; } return { path: routePath, params, query: url.searchParams }; diff --git a/frontend-vanilla/src/style.css b/frontend-vanilla/src/style.css index 575be9d..8ec3db3 100644 --- a/frontend-vanilla/src/style.css +++ b/frontend-vanilla/src/style.css @@ -10,9 +10,9 @@ /* Light Mode Defaults */ --bg-color: #ffffff; --text-color: rgba(0, 0, 0, 0.87); - --sidebar-bg: #ccc; + --sidebar-bg: #f5f5f5; --link-color: #0000ee; - --border-color: #999; + --border-color: #e5e5e5; --accent-color: #007bff; color-scheme: light dark; @@ -37,9 +37,9 @@ body { width: 100%; } -/* Sidebar - glassmorphism by default */ +/* Sidebar - matching v2 glass variant */ .sidebar { - width: 14rem; + width: 11rem; background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); @@ -87,7 +87,7 @@ body { } .sidebar-section h3 { - font-family: var(--font-heading); + font-family: var(--font-sans); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; @@ -116,6 +116,7 @@ body { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + font-family: var(--font-sans); } .sidebar-section li a:hover { @@ -148,7 +149,7 @@ body { text-decoration: none; color: var(--text-color); font-size: 0.9rem; - font-family: var(--font-heading); + font-family: var(--font-sans); } .sidebar-footer a:hover { @@ -280,6 +281,11 @@ body { font-family: var(--font-body); } +.font-sans { + --font-body: var(--font-heading); + font-family: var(--font-body); +} + .font-mono { --font-body: Menlo, Monaco, Consolas, 'Courier New', monospace; font-family: var(--font-body); |
