Skip to content

feat(ui): PWA polish, smart service worker caching, and DuckDB splash screen#48

Merged
sushruth merged 4 commits intomainfrom
feature/improve-pwa-icons
Mar 11, 2026
Merged

feat(ui): PWA polish, smart service worker caching, and DuckDB splash screen#48
sushruth merged 4 commits intomainfrom
feature/improve-pwa-icons

Conversation

@sushruth
Copy link
Copy Markdown
Contributor

Summary

Bundles three related UI improvements for a better first-load and install experience.


1. PWA icons & CSS modules refactor

  • Adds full SVG icon set (192, 512, 1024, maskable variants) and updates manifest.json
  • Extracts all component inline styles into CSS modules (Header, Icon, Layout, ResultsTable, Sidebar)
  • Cleans up theme.css, adds base.css / codemirror.css / utilities.css

2. Service worker: targeted caching strategy

Replaces the old stale-while-revalidate-everything approach with two explicit strategies:

  • cache-first — DuckDB WASM + worker, Vite content-hashed assets (/assets/*.js, *.css)
  • network-first — everything else (index.html, manifest.json, icons)

Users now see app updates immediately on next load instead of one visit later.

3. DuckDB loading splash screen

First load of DuckDB WASM can take several seconds. This adds a full-screen splash that looks like a desktop app launcher:

  • Pre-fetches duckdb-eh.wasm via ReadableStream for real byte-level progress tracking
  • The service worker caches the WASM from that fetch, so DuckDB's own instantiate call hits the cache
  • Animated progress bar (5% → download → 75% → init → 92% → connect → 100%)
  • Status text + percentage readout
  • Pulsing logo with glow, brand dark-blue gradient background
  • Smooth fade-out with 700ms linger at 100% so it doesn't flash away
  • On repeat visits: WASM is cached → splash is sub-100ms

4. TypeScript fix: vite-env.d.ts

Triple-slash directives must appear before any statements. import "solid-js" was on line 1, silently discarding the /// <reference types="vite/client" /> directive and causing all *.module.css imports to emit TS2307 errors. Fixed by reordering.


This PR was created by an AI agent on behalf of @sushruth.

sushruth and others added 4 commits March 11, 2026 01:19
- Add SVG icon variants (favicon, 192, 512, 1024, maskable)
- Update manifest.json to reference new icons
- Extract component styles into CSS modules (Header, Icon, Layout,
  ResultsTable, Sidebar, SidebarTables)
- Clean up theme.css and add base/codemirror/utilities style files
- Refactor vite.config.ts and update index.html

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace aggressive stale-while-revalidate-everything approach with two
explicit strategies:
- cache-first: DuckDB WASM + worker, Vite content-hashed assets (/assets/*.js, *.css)
- network-first: everything else (index.html, manifest, icons)

This ensures app updates are seen immediately on next load while keeping
DuckDB's large binaries fully cached for offline/repeat use.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Pre-fetch duckdb-eh.wasm with ReadableStream to track download bytes
  (service worker caches it so duckdb's subsequent fetch is instant)
- Expose loadProgress (0-100) and loadStatus signals from SchemaContext
- New SplashScreen component: full-screen overlay with logo, animated
  progress bar, status text, and fade-out on ready
- Progress phases: download (5-75%), init (80%), connect (92%),
  restore files (97%), ready (100%)
- On repeat visits WASM is cached so splash is sub-100ms

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d.ts

Triple-slash directives must appear before any statements. With
'import "solid-js"' on line 1, TypeScript was silently ignoring the
'/// <reference types="vite/client" />' directive, causing all
*.module.css imports to report TS2307 errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 11, 2026 08:20
@sushruth sushruth merged commit 8d65830 into main Mar 11, 2026
5 of 6 checks passed
@sushruth sushruth deleted the feature/improve-pwa-icons branch March 11, 2026 08:20
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the UI’s first-load/install experience by polishing PWA assets/styles, updating the service worker caching strategy, and adding a DuckDB loading splash screen with progress reporting.

Changes:

  • Refactors global styles into base.css / codemirror.css / utilities.css and multiple component CSS modules.
  • Reworks the service worker to use cache-first for DuckDB + hashed assets and network-first for everything else, with an update-triggered reload flow.
  • Adds DuckDB initialization progress tracking and a full-screen splash screen.

Reviewed changes

Copilot reviewed 24 out of 30 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/ui/vite.config.ts Adds a build hook to inject a version token into the service worker output.
packages/ui/src/vite-env.d.ts Fixes triple-slash directive ordering; adds typings for *.module.css.
packages/ui/src/styles/utilities.css Introduces reusable layout utility classes.
packages/ui/src/styles/theme.css Reduces this file to theme variables only.
packages/ui/src/styles/codemirror.css Extracts CodeMirror styling into a dedicated stylesheet.
packages/ui/src/styles/base.css Extracts base element/layout styles (reset, typography, buttons).
packages/ui/src/contexts/SchemaContext.tsx Adds DuckDB load progress/status signals and WASM prefetch progress tracking.
packages/ui/src/components/SplashScreen.tsx New splash screen UI driven by schema load progress/status.
packages/ui/src/components/SidebarTables.module.css Adds table-list CSS module (currently not wired into the component).
packages/ui/src/components/Sidebar.tsx Migrates sidebar styling to CSS modules (but currently mismatched with the module content).
packages/ui/src/components/Sidebar.module.css Adds sidebar CSS module (missing classes referenced by Sidebar.tsx).
packages/ui/src/components/ResultsTable.tsx Migrates results table styling from inline styles to a CSS module.
packages/ui/src/components/ResultsTable.module.css New CSS module backing ResultsTable styling.
packages/ui/src/components/Layout.tsx Migrates layout styling to a CSS module.
packages/ui/src/components/Layout.module.css New CSS module backing Layout styling.
packages/ui/src/components/Icon.tsx Applies CSS-module styling for icons.
packages/ui/src/components/Icon.module.css New CSS module for base icon styling.
packages/ui/src/components/Header.tsx Migrates header styling to a CSS module.
packages/ui/src/components/Header.module.css New CSS module backing Header styling.
packages/ui/src/App.tsx Imports the new CSS layers; mounts the splash screen.
packages/ui/src/App.module.css New CSS module for editor/results pane styling.
packages/ui/public/sw.js Implements explicit cache-first/network-first strategies plus SKIP_WAITING handling.
packages/ui/public/manifest.json Updates theme color to match the new branding.
packages/ui/public/icon-maskable.svg Adds a maskable PWA icon.
packages/ui/public/icon-512.svg Adds a 512px SVG icon.
packages/ui/public/icon-192.svg Adds a 192px SVG icon.
packages/ui/public/icon-1024.svg Adds a 1024px SVG icon.
packages/ui/public/favicon.svg Adds an SVG favicon.
packages/ui/index.html Updates theme-color meta and adds SW update/reload wiring.
.serena/project.yml Adds/updates Serena project configuration metadata.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +1 to +6
.tablesList {
display: flex;
flex-direction: column;
gap: 0.25rem;
margin-top: 0.5rem;
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SidebarTables.module.css does not appear to be imported/used anywhere in the UI (no references found), so these styles will never be applied and the file becomes dead code. Either import it from Sidebar.tsx (and wire up its collapsed selectors) or remove it and move the needed class definitions into the module that is actually used.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +30
const cacheNames = await caches.keys();
await Promise.all(
cacheNames.map((name) => {
if (name !== CACHE_NAME) {
console.log(`[SW] Deleting old cache: ${name}`);
return caches.delete(name);
}
return Promise.resolve();
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On activation, the SW deletes every cache except the current CACHE_NAME. Because CACHE_NAME is versioned per build, this guarantees that large immutable assets (DuckDB WASM/worker and Vite hashed assets) will be purged and re-downloaded on every deployment, negating the “cache forever” intent and potentially hurting repeat-load performance. Consider using separate caches (e.g., a stable static cache for DuckDB + hashed assets, and a versioned runtime cache for network-first resources), and only clear the versioned/runtime cache on update.

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +35
createEffect(() => {
if (!loading()) {
// Brief pause so user sees 100% before fade
setTimeout(() => setGone(true), 700);
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createEffect schedules a setTimeout when loading() becomes false, but the timeout isn’t cleared on cleanup. During HMR/unmounts this can trigger setGone(true) after the component is gone. Store the timeout id and clear it via onCleanup, and consider guarding against multiple timers if the effect re-runs.

Copilot uses AI. Check for mistakes.
class="sidebar"
classList={{ collapsed: props.collapsed }}
class={styles.sidebar}
classList={{ [styles.collapsed]: props.collapsed }}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

classList={{ [styles.collapsed]: props.collapsed }} relies on styles.collapsed, but Sidebar.module.css only defines the compound selector .sidebar.collapsed and does not define/export a standalone .collapsed class. This makes styles.collapsed undefined at runtime, so the collapsed class won’t be applied. Define a .collapsed class in the module (and update selectors accordingly) or adjust the CSS/module usage so the exported class name exists.

Suggested change
classList={{ [styles.collapsed]: props.collapsed }}

Copilot uses AI. Check for mistakes.
Comment on lines +110 to 114
<div class={styles.tablesList}>
<Show when={tables().length === 0}>
<div class="empty-state">
<div class={styles.emptyState}>
<p>No data loaded</p>
<small>Click "Add Data" to load a CSV file</small>
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file references table-related CSS module keys like styles.tablesList / styles.emptyState / styles.tableItem etc., but Sidebar.module.css does not define these classes (they currently exist in SidebarTables.module.css, which isn’t imported). As-is, those class={...} bindings will evaluate to undefined and the sidebar table list will lose styling. Import/use the correct CSS module or consolidate the styles into Sidebar.module.css.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants