experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: theme cascade system, peek as default, tag wrong-page fix

- Theme cascade: peek's variables.css prepended as base layer for all
non-peek themes, so themes only need to override colors
- Default theme changed from basic to peek
- Theme list sorted with peek first
- Shichijuni: brighten dark mode text (base03/base04) for readability,
remove font definitions (inherited from peek)
- Tags/entities: use getFocusedVisibleWindowId() instead of windows[0]
to tag the actually-focused page, not the oldest window

+63 -11
+7
backend/electron/ipc.ts
··· 1708 1708 } 1709 1709 }).filter(Boolean); 1710 1710 1711 + // Sort: 'peek' first (default theme), then alphabetically 1712 + themes.sort((a: any, b: any) => { 1713 + if (a.id === 'peek') return -1; 1714 + if (b.id === 'peek') return 1; 1715 + return a.name.localeCompare(b.name); 1716 + }); 1717 + 1711 1718 return { themes }; 1712 1719 }); 1713 1720
+37 -2
backend/electron/protocol.ts
··· 25 25 // Theme path cache: themeId -> filesystem path 26 26 const themePaths = new Map<string, string>(); 27 27 28 - // Active theme ID (defaults to basic) 29 - let activeThemeId = 'basic'; 28 + // Active theme ID (defaults to peek) 29 + let activeThemeId = 'peek'; 30 30 31 31 // Root directory (set during init) 32 32 let rootDir: string; ··· 329 329 console.error(`[protocol] FILE NOT FOUND: ${absolutePath} (requested: ${req.url})`); 330 330 return new Response('Not Found', { status: 404 }); 331 331 } 332 + 333 + // For variables.css: prepend peek theme as base layer so other themes 334 + // only need to override what they change (colors, etc.). Peek's fonts, 335 + // typography, and other defaults cascade automatically. 336 + if (themePath === 'variables.css' && themeId !== 'peek') { 337 + const peekBasePath = getThemePath('peek'); 338 + const peekCssPath = peekBasePath ? path.resolve(peekBasePath, 'variables.css') : null; 339 + 340 + if (peekCssPath && fs.existsSync(peekCssPath)) { 341 + let baseCss = fs.readFileSync(peekCssPath, 'utf-8'); 342 + // Rewrite relative font URLs to point to peek's theme path 343 + baseCss = baseCss.replace( 344 + /url\(["']?\.\//g, 345 + 'url("peek://theme/peek/' 346 + ); 347 + // Fix closing quotes for rewritten URLs 348 + baseCss = baseCss.replace( 349 + /peek:\/\/theme\/peek\/([^"')]+)["']?\)/g, 350 + 'peek://theme/peek/$1")' 351 + ); 352 + const themeCss = fs.readFileSync(absolutePath, 'utf-8'); 353 + const combined = `/* Base: peek theme defaults */\n${baseCss}\n\n/* Active theme: ${themeId} */\n${themeCss}\n`; 354 + 355 + return new Response(combined, { 356 + status: 200, 357 + headers: { 358 + 'Content-Type': 'text/css', 359 + 'Cache-Control': 'no-store, no-cache, must-revalidate', 360 + 'Pragma': 'no-cache', 361 + 'Expires': '0' 362 + } 363 + }); 364 + } 365 + } 366 + 332 367 const fileURL = pathToFileURL(absolutePath).toString(); 333 368 const response = await net.fetch(fileURL); 334 369 const body = await response.arrayBuffer();
+7 -1
extensions/entities/background.js
··· 266 266 return; 267 267 } 268 268 269 - const activeWindow = windowList.windows[0]; 269 + // Use the last focused visible window (not just first in list) 270 + let activeWindow = windowList.windows[0]; 271 + const focusedId = await api.window.getFocusedVisibleWindowId(); 272 + if (focusedId) { 273 + const focused = windowList.windows.find(w => w.id === focusedId); 274 + if (focused) activeWindow = focused; 275 + } 270 276 const url = activeWindow.url; 271 277 272 278 if (!url || !url.startsWith('http')) {
+7 -1
extensions/tags/background.js
··· 70 70 if (!result.success || !result.windows.length) { 71 71 return null; 72 72 } 73 - // Return the first non-internal window 73 + // Use the last focused visible window (survives cmd palette focus changes) 74 + const focusedId = await api.window.getFocusedVisibleWindowId(); 75 + if (focusedId) { 76 + const focused = result.windows.find(w => w.id === focusedId); 77 + if (focused) return focused; 78 + } 79 + // Fall back to first window if no focused window found 74 80 return result.windows[0]; 75 81 }; 76 82
+5 -7
extensions/theme-shichijuni/variables.css
··· 60 60 --theme-surface-border: 1px solid rgba(0, 0, 0, 0.10); 61 61 --theme-surface-ring: 0 0 0 1px rgba(0, 0, 0, 0.06); 62 62 63 - /* Typography — system fonts, colors-only theme */ 64 - --theme-font-sans: system-ui, sans-serif; 65 - --theme-font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Monaco, monospace; 63 + /* Typography: inherited from peek base layer — colors-only theme */ 66 64 } 67 65 68 66 /* =================================================================== ··· 294 292 --base00: #1a1918; 295 293 --base01: #2a2825; 296 294 --base02: #3a3835; 297 - --base03: #5a5752; 298 - --base04: #8a8680; 295 + --base03: #7a7770; /* Muted text — warm grey, readable on dark bg */ 296 + --base04: #a5a098; /* Secondary text — warm grey, good contrast */ 299 297 --base05: #f0ede8; 300 298 --base06: #faf8f4; 301 299 --base07: #ffffff; ··· 345 343 --base00: #1a1918; 346 344 --base01: #2a2825; 347 345 --base02: #3a3835; 348 - --base03: #5a5752; 349 - --base04: #8a8680; 346 + --base03: #7a7770; /* Muted text — warm grey, readable on dark bg */ 347 + --base04: #a5a098; /* Secondary text — warm grey, good contrast */ 350 348 --base05: #f0ede8; 351 349 --base06: #faf8f4; 352 350 --base07: #ffffff;