▓▓▒▒ FLOAT.BBS ▒▒▓▓
Document: imprints/sysops-daydream/2025-10-26-spa-vibes-without-spa-overhead
      
← Back to SYSOPS.DAYDREAM

SPA Vibes Without SPA Overhead

A meditation on localStorage, DOMParser, and the revolutionary power of boring technology

The Setup

You’re building a static site with Astro. You want a slide-out drawer showing today’s daily note. Users want to navigate between dates without page reloads. You could reach for React Router, Vue Router, SvelteKit navigation, Next.js App Router…

Or you could just use the browser.

The Pattern

// State persistence
localStorage.setItem('drawer-pinned', 'true');

// Navigation without routing
const response = await fetch('/evans-notes/2025-10-25');
const html = await response.text();
const doc = new DOMParser().parseFromString(html, 'text/html');
drawerContent.innerHTML = doc.querySelector('article').innerHTML;

// Event delegation for dynamic content
panel.addEventListener('click', (e) => {
  if (e.target.tagName === 'A' && e.target.href) {
    e.preventDefault();
    navigateToDate(extractDate(e.target.href));
  }
});

Three Web APIs. Zero frameworks. SPA-like navigation without the SPA.

Why This Works

Astro already renders everything. The server generates complete HTML pages. We’re not building an app that needs client-side routing—we’re enhancing documents that already exist.

DOMParser is magic. Fetch a page, parse it as HTML, extract what you need, inject it where you want. No virtual DOM, no hydration, no reconciliation. Just browser APIs from 2011 doing what they’ve always done.

localStorage is persistent state. Pin the drawer, navigate to another page, the drawer stays pinned. No Redux, no Zustand, no Jotai. Just localStorage.setItem() and localStorage.getItem(). Works on every browser since 2010.

Event delegation handles dynamic content. Attach one listener to the parent, check the event target. Content changes via innerHTML? Listener still works. No need to re-bind, no memory leaks, no framework lifecycle.

The Philosophy

Boring is revolutionary because it survives.

React will have breaking changes. Vue will ship new composition APIs. Svelte will rethink reactivity. The localStorage API from 2010 will work identically in 2030.

Progressive enhancement isn’t just accessibility—it’s maintenance strategy.

When JavaScript fails (and it will), the site still works. Links navigate. Content renders. Users can accomplish their goals. You’re not debugging why hydration failed in production.

Framework fatigue is solved by not having frameworks.

No build config. No plugin ecosystem. No “which state manager should we use.” Just HTML, CSS, JavaScript. The browser already knows how to run it.

The Economics

Framework overhead is cognitive debt.

Every abstraction is a concept to learn, maintain, debug, upgrade. localStorage has one API surface. DOMParser has one API surface. Your junior dev doesn’t need to understand component lifecycles or hook dependencies—they need to understand the browser.

Boring code ships faster.

No waiting for builds. No fighting with TypeScript about fetch types. No wondering if this pattern works with SSR. Astro handles SSR, the browser handles interactivity, you handle feature delivery.

Maintenance cost is proportional to abstraction layers.

Three APIs (localStorage, DOMParser, fetch) vs. an entire framework ecosystem (router, state manager, build tooling, plugin compatibility, version migrations). Which codebase will still work in 5 years without touching it?

The Tradeoffs

This doesn’t scale to complex SPAs.

If you’re building Gmail, use React. If you’re building a documentation viewer with some interactivity, maybe you don’t need to bring the entire React ecosystem along for the ride.

There’s no declarative reactivity.

You’re manually updating the DOM. For simple cases (swap this content, update this title), that’s fine. For complex UIs with many interdependent states, frameworks exist for a reason.

You’re responsible for the patterns.

No one’s written “React best practices for DOMParser navigation.” You’re in uncharted territory (even though the APIs are ancient). That’s either liberating or terrifying depending on your disposition.

The Lesson

The best framework is no framework when the browser already does what you need.

localStorage for state. DOMParser for navigation. Event delegation for interactivity. CSS custom properties for theming. These aren’t “old” technologies—they’re stable technologies.

Boring is revolutionary because it survives.


Case Study: float.bbs TodayDrawer component Implementation: 150 lines of JavaScript, zero dependencies Techniques: localStorage persistence, fetch-based navigation, event delegation Result: SPA-like UX without SPA maintenance burden Maintenance projection: Will work unchanged for 10+ years

Infrastructure monk approved.

═══════════════════════════════════════════════════════════════
 sysop::boring.core - float.bbs viewer v0.1
═══════════════════════════════════════════════════════════════
    
▓▓▒▒ TODAY: 2025-10-27 ▒▒▓▓

<< 2025-10-26 | 2025-10-28 >>

🎯 What Evan Needs This Morning

Pending PRs (Awaiting Review/Merge)

  • PR #604: GP node assessment + basket automation

    • Status: In approval backlog, merge conflicts being resolved
    • Demos: Successfully demo’d on 2025-10-24 sprint demo (Daniel happy with feedback)
    • Next: Check if conflicts resolved, ready for merge to staging
  • PR #606: [Description needed - check GitHub]

    • Status: Demo’d successfully, awaiting review
    • Next: Check GitHub status
  • PR #607: [Description needed - check GitHub]

    • Status: Demo’d successfully, awaiting review
    • Next: Check GitHub status

Active Issues Ready for Dev

  • Issue #122: Assessment workflow

    • Location: /Users/evan/float-hub/rangle/issues/active/122-assessment-workflow.md
    • Status: Fully documented with acceptance criteria
    • Priority: Assessment UX experience (per Scott sync 2025-10-24)
    • Key consideration: Guest→account response transfer (piggybacking basket logic)
  • Issue #442: HEIC upload support

    • Location: /Users/evan/float-hub/rangle/issues/active/442-heic-upload-support.md
    • Status: Fully documented with acceptance criteria
    • Priority: Lower than #122 (per Scott sync realignment)

Follow-ups from Weekend

  • Check GitHub PR statuses (#604, #606, #607) - are they merged? ready for staging?
  • Scott mentioned creating UI/UX ticket (priority 3) and multi-product assessment response logging ticket
  • Wins tracking system now operational - remember to capture wins as they happen

First Tasks

  • Check pharmacy-online PR status (merged? staging? conflicts?)
  • Review Issue #122 (assessment workflow) - priority work
  • Check if Scott’s new tickets created (UI/UX, multi-product logging)
  • Capture wins as work happens (two-home system: quick log + weekly review)

Context from Yesterday

Weekend mode: Shack building + infrastructure work

  • float.bbs viewer operational
  • TodayDrawer component shipped
  • Documentation preserved
  • Monday prep notes ready

Repo: https://github.com/pharmonline/pharmacy-online Local: ~/projects/pharmacy-online


timelog

  • 11:45pm - 12:03am - [project::float-bbs-viewer] hermit crab blueprints → forge patterns extracted (102KB doc)
  • 11:40pm - 11:45pm - [project::float-infrastructure] domain migration → sysop-beta.floatbbs.net live
  • 12:03am - 12:05am - [project::float-hub] CLAUDE.md evna integration → explicit tool names + capture triggers

Late Night: Infrastructure & Blueprinting

float-bbs-viewer Architecture Extraction (11:45pm - 12:03am)

  • Extracted patterns from float-dispatch-manifesto-forge (React/Vite/ShadCN)
  • Created hermit crab reference: 2025-10-26-dispatch-blueprints-for-bbs-viewer-hermit-crab-patterns.md
  • Key patterns: color-coded imprint system, grid layouts, Tailwind HSL tokens, editorial philosophy sections
  • Translation map: React hooks → Astro content collections, SPA routing → SSG file-based
  • Breadcrumb: /Users/evan/projects/float-bbs-viewer/2025-10-26-dispatch-blueprints-for-bbs-viewer-hermit-crab-patterns.md

CLAUDE.md evna Integration (12:03am - 12:05am)

  • Replaced vague “evna-context-concierge” references with explicit tool names
  • Added mandatory capture triggers (7-item checklist: after features, docs, infrastructure, archaeology, context switches, obstacles, chunks)
  • Context capture pattern template (ctx::, project::, format)
  • Breadcrumb: /Users/evan/float-hub/CLAUDE.md:308-315, 374-403, 422

Morning: Brain Booting

(Space for morning thoughts)

Press ESC or Ctrl+D to close