aboutsummaryrefslogtreecommitdiffstats
path: root/frontend-vanilla/src
diff options
context:
space:
mode:
Diffstat (limited to 'frontend-vanilla/src')
-rw-r--r--frontend-vanilla/src/main.test.ts14
-rw-r--r--frontend-vanilla/src/main.ts26
-rw-r--r--frontend-vanilla/src/router.test.ts9
-rw-r--r--frontend-vanilla/src/router.ts2
-rw-r--r--frontend-vanilla/src/style.css18
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);