nicholai-work-2026/dev/continuity.md
Nicholai 7a24dcc387 Add ClientRouter and clean up legacy prefetch in BaseLayout
- Updated .gitignore to include GEMINI.md.
- Documented client router implementation and decisions in dev/continuity.md.
- Added ClientRouter component and theme persistence logic to BaseLayout.astro.
- Removed legacy intent‑based prefetch script.

Hubert The Eunuch
Trapped in this commit, I endure
2026-01-02 02:05:32 -07:00

3.6 KiB

Continuity Log

Template for New Entries

## YYYY-MM-DD - <Milestone>

### Changes Made
- Created X, Y, Z files
- Implemented feature A using pattern B

### Decisions
- Chose X over Y because...
- Pattern for Z is...

### How to Test
1. Navigate to...
2. Click...
3. Verify...

### Next Steps
- [ ] Item 1
- [ ] Item 2

Example: postMessage Pattern (Reference)

Parent sends to iframe:

// lib/communication/iframe-controller.ts
export function selectElement(iframe: HTMLIFrameElement, nodeId: string) {
  iframe.contentWindow?.postMessage(
    { type: 'SELECT_ELEMENT', payload: { nodeId } },
    'http://localhost:4321' // Always explicit origin
  )
}

Iframe sends to parent:

// Injected script in iframe
window.parent.postMessage(
  { type: 'ELEMENT_SELECTED', payload: { nodeId, rect, astroSource } },
  'http://localhost:3000'
)

Parent receives:

// lib/communication/message-handler.ts
window.addEventListener('message', (event) => {
  if (event.origin !== 'http://localhost:4321') return
  
  switch (event.data.type) {
    case 'ELEMENT_SELECTED':
      handleElementSelected(event.data.payload)
      break
    // ... other handlers
  }
})

Example: Zustand Store Pattern (Reference)

// lib/store/editor-store.ts
import { create } from 'zustand'

interface EditorStore {
  selectedElement: SelectedElement | null
  setSelectedElement: (el: SelectedElement | null) => void
}

export const useEditorStore = create<EditorStore>((set) => ({
  selectedElement: null,
  setSelectedElement: (el) => set({ selectedElement: el }),
}))

Usage:

const selectedElement = useEditorStore((state) => state.selectedElement)
const setSelectedElement = useEditorStore((state) => state.setSelectedElement)

Example: File Update Pattern (Reference)

// lib/astro/class-updater.ts
import { parse, walk } from '@astrojs/compiler'

export async function updateClasses(
  filePath: string,
  line: number,
  col: number,
  newClasses: string
): Promise<string> {
  const source = await fs.readFile(filePath, 'utf-8')
  const ast = await parse(source)
  
  // Walk AST to find element at line:col
  let targetNode = null
  walk(ast, (node) => {
    if (node.position?.start.line === line && 
        node.position?.start.column === col) {
      targetNode = node
    }
  })
  
  // Update class attribute in source string
  // ... implementation
  
  return updatedSource
}

2026-01-02 - Client Router Implementation

Changes Made

  • Updated src/layouts/BaseLayout.astro to use <ClientRouter /> from astro:transitions.
  • Modified theme initialization script to handle astro:after-swap events for persistent theming during navigation.
  • Removed legacy "Intent-Based Prefetch" script as it is superseded by Astro's built-in router capabilities.

Decisions

  • Adopted Astro's ClientRouter to provide a smoother, SPA-like user experience with view transitions.
  • Consolidated theme logic into a function applyTheme() that runs on both initial load and after view transitions to prevent theme flickering or resetting.

How to Test

  1. Open the site in a browser.
  2. Toggle the theme to a non-default state (e.g., Light mode if default is Dark).
  3. Click a navigation link (e.g., "Blog").
  4. Verify the new page loads without a full refresh (no white flash).
  5. Verify the selected theme persists on the new page.

Next Steps

  • Monitor for any script re-execution issues common with View Transitions.
  • Consider adding custom transition animations for specific elements if needed.