This workspace hosts the shared v3.0 shell plus the current bubble (v2.0) and line (v2.4) chart applications for exploring UK government emissions data.
index.html→ parent shell that preloads shared data, swaps between the line and bubble chart iframes, and injects shared styles/assets.SharedResources/→ common Supabase client config, analytics helper, shared-data loader, color palette, fonts, and images consumed by both charts.bubblechart/→ self-contained bubble chart app with its own Supabase module (supabase.js), bridge loader, chart renderer, export helper, and main UI script.linechart/→ modular line chart app with its own Supabase module, chart logic, and export workflow.supabase/→ edge function and configuration scaffolding used by Supabase for scheduled aggregations and analytics capture.
- The shell loads
SharedResources/shared-data-loader.js, which fetches and caches pollutant, group, and timeseries tables from Supabase once per session. - Each iframe (bubble or line) reuses the shared cache through
SharedDataLoader, then renders via Google Charts with its respective UI scripts. - User actions (filters, exports) stay inside each iframe, while high-level tab changes and analytics events are handled by the parent shell.
- Exports rely on client-side XLSX/PNG generation; analytics events post to Supabase via
SharedResources/analytics.jswhen enabled.
- The helper
SharedResources/analytics.jsnow emits an automaticpage_drawnevent (once per load) plus any manualinteractionevents you send viaSiteAnalytics.trackInteraction(label, data). A recurringpage_seenheartbeat fires every 30 seconds after the user interacts (and only while the tab stays visible) so we approximate active dwell time instead of background tab time, and dashboard “Interactions” explicitly filters those heartbeats out so you only see deliberate actions. - Events insert into the lightweight
site_eventstable through the Supabase REST API, so no application-specific client wiring is required. - Country attribution continues to rely on the privacy-friendly timezone/locale guess (
GB,US, etc.); no IP addresses or fingerprints are stored. - To provision the storage, run
../CIC-test-data-explorer-analytics/scripts/site_analytics_setup.sqlinside your Supabase project once (the SQL now lives in the private analytics repo), then keep the existing Row Level Security policies for theanonrole (Supabase now maps this to the publishable key that replaces the legacy anon key). - Per-page slugs are inferred from
body[data-page-slug]; setwindow.__SITE_ANALYTICS_DISABLE_AUTO_PAGEVIEW__ = truebefore loading the script if a view should remain silent. - For a quick local view of the data, open
../CIC-test-data-explorer-analytics/site-analytics-dashboard.htmlfrom the private repo (serve it vianpx serveor similar). It now pulls fromsite_event_daily_summary,site_event_country_summary,site_event_session_summary, and the latestsite_eventsrows to render overview cards (including Avg Session Length), tables, and recent activity—no deployment needed.
For a concise summary of how the helper works (plus runtime flags like
?analytics=off), seeanalytics_overview.md.
- Serve the repository with any static file server (
python -m http.server,npx serve, etc.) so the Supabase client can resolve relative paths. - Configure Supabase credentials once via
.env+npm run supabase:env:- Copy
.env.exampleto.env.local(or.env) and drop in your test/live project values (SUPABASE_URL,SUPABASE_PUBLISHABLE_KEY, optionalSUPABASE_STORAGE_KEY_BASE). Backend/CLI scripts can also readSUPABASE_SECRET_KEYif you include it. - Run
npm run supabase:env(orSUPABASE_ENV_FILE=.env.live npm run supabase:env) to regenerateSharedResources/supabase-env.js. The generated file is gitignored on purpose—keep it locally (or recreate it in CI) so secrets never land in the repo. - Prefer automation, but if you need to hand-edit the values, copy
SharedResources/supabase-env.template.jstosupabase-env.jsand fill in the placeholders. - The runtime
SharedResources/supabase-config.jsnow auto-detectswindow.__NAEI_SUPABASE_CONFIG, so switching environments only requires rerunning the script with a different env file—no manual edits across multiple HTML files.
- Copy
- Supabase functions live under
supabase/functions/and can be deployed via the Supabase CLI when backend updates are needed.
- Supabase now issues publishable (
sb_publishable_…) keys for browser traffic and secret (sb_secret_…) keys for servers/automation. These replace the legacyanonandservice_roleJWTs, which Supabase will retire after November 2025. - Generate the new keys from Project Settings → API Keys → Try the new keys in the Supabase dashboard, then update your
.env/CI secrets withSUPABASE_PUBLISHABLE_KEYand (optionally)SUPABASE_SECRET_KEY. - Re-run
npm run supabase:envwhenever you rotate the publishable key soSharedResources/supabase-env.jsships the latest browser-safe credential. - CLI/Node scripts such as
scripts/export-default-data.jsautomatically pick up the secret key ifSUPABASE_SECRET_KEYor the historicSUPABASE_SERVICE_ROLE_KEYenv vars are defined, so no additional flags are required after rotation.
- The shell router inside
index.html(mirrored in404.html) makes/category-info,/user-guide, and/resourcesdeep links fall back to the SPA before the iframe content loads. - Each tab’s copy now lives in its own folder (
/category-info/,/user-guide/,/resources/) underembed.html, while the folderindex.htmlsimply redirects to the full shell (/?page=…) so direct visits keep the tab bar visible; the legacy*-embed.htmlfiles remain as tiny redirectors for older links and bookmarks. - The parent iframe wrapper is responsible for sizing; the embed documents only emit height messages, so keep any structural changes self-contained inside the embed file.
- Create
your-tab-embed.htmlnext to the existing embed files (reuse their boilerplate for messaging and styles). - Point the new tab’s iframe
srcinindex.htmlto the*-embed.htmlfile. - Copy
index.htmlto404.htmlso GitHub Pages continues to serve the SPA shell for direct requests to/your-tab. - Test the new path on GitHub Pages (or a local SPA preview) by loading
/your-tabdirectly to be sure the shell + iframe render together.
GitHub Pages hosts the test project at /CIC-test-uk-air-pollution-emissions-data-explorer/, so run a SPA-aware server from the parent directory to reproduce the same URL prefix locally:
cd /Users/mikehinford/Dropbox/Projects/CIC\ Data\ Explorer
npx http-server-spa ./CIC-test-uk-air-pollution-emissions-data-explorer index.html 4173 -c-1- Visit
http://localhost:4173/CIC-test-uk-air-pollution-emissions-data-explorer/for the default view, or append/category-info,/user-guide, or/resourcesto confirm deep links mount the SPA shell before loading the iframe content. - Any SPA-aware server (
vite preview,serve-spa, etc.) works as long as it rewrites unknown routes toindex.htmland preserves the/CIC-test-uk-air-pollution-emissions-data-explorer/prefix.
- Run
npm installonce to pull in the Tailwind/PostCSS toolchain. - Execute
npm run build:cssto regeneratedist/tailwind.cssfor production (GitHub Pages, Netlify, etc.). - Use
npm run watch:cssduring local development to keep the compiled stylesheet in sync.
-
dataexplorer-version.txt,linechart/linechart-version.txt, andbubblechart/bubblechart-version.txtare the single sources of truth for the displayed versions. -
A pre-commit hook (
.githooks/pre-commit) runsscripts/update-footer-versions.js, which refreshes theExplorer Version … • Build …line in any staged HTML file outsideCIC-test-Archive-Charts/. -
Enable the hook locally once:
git config core.hooksPath .githooks
-
After editing a version file (or any footer), stage your changes and the hook will restage affected HTML files with the correct version/build string before the commit completes.
- Logging is suppressed by default to keep the browser console quiet.
- Append
?debug=1(or?logs=1) to the URL to re-enable verbose logs across the shell and both iframes. - Remove the flag for production-style runs; critical warnings/errors always remain visible.