Files
ResumeSite/docs/spec/COMPONENT_ARCHITECTURE.md
2026-07-03 21:07:25 +02:00

4.4 KiB

COMPONENT_ARCHITECTURE.md

1. Principles

  1. Server components by default (Astro components, zero client JS). Client behaviour only via the five behaviour modules bound by data-* attributes.
  2. Components receive typed props from content + locale; they never fetch or read files. Layouts do the data plumbing.
  3. One component, both themes, both locales — no HeroNo.astro, no CardDark.astro. Locale comes in as a prop bundle; theme is pure CSS.
  4. Naming and states follow the Phase 1 component inventory (DESIGN_SYSTEM §5) 1:1 — design system and component tree share vocabulary.

2. Component tree

layouts/
  Base            html/head/meta, Seo, ThemeScript(inline), fonts preload, SkipLink,
                  Header, <slot/>, Footer, behaviour-module script tags (deferred)
  Page            Base + page-title block + prose container (about/contact/cv/colophon)
  Home            Base + section scaffolding with reveal data-attributes
  CaseStudy       Base + case-study scaffold (header block, MiniToc, section renderer)

components/core/
  Header          nav links (slug-map-driven), LangSwitch, ThemeToggle, SplitCvButton;
                  states: default/scrolled via data-scrolled (observer module)
  MobileNav       overlay panel (template in DOM, hidden; nav.ts toggles, traps focus)
  Footer          channels, CV links, language repeat, colophon link
  Seo             per-page meta, hreflang pairs (slug map), OG, JSON-LD builders
  ThemeScript     inline no-flash theme init (the one permitted inline script, CSP-hashed)
  SkipLink        first focusable element

components/ui/    (design-system atoms — dumb, prop-driven)
  Chip(kind: fact|status|stack, status?)     Button(variant: primary|secondary|ghost)
  SplitCvButton(locale, cvMeta)              LangSwitch(currentPageId, locale)
  ThemeToggle                                Card(interactive?)
  SectionLabel(number, text)                 TraceMotif(animated?)
  FramedImage(media, loading)                Tooltip(delay 600ms)

components/home/
  Hero(profile)                    ProofStrip(4 tiles from profile/skills data)
  SkillsGrid(skillGroups)          ProjectCards(featured projects, homelab slim card)
  ExperienceTimeline(entries)      AboutTeaser(profile)         ContactBand(profile)

components/case-study/
  CsHeader(project)                TldrBox(project.tldr)
  MiniToc(sections, sticky ≥1200)  SectionRenderer(section) — markdown → prose
  DecisionList(decisions)          ArchDiagram(diagram, locale labels)
  Gallery(media) + Lightbox host   NextPrev(project order)

3. Behaviour modules (the entire client JS surface)

Module Binds to Responsibility Budget
theme.ts ThemeToggle + inline init read/persist preference, data-theme swap, icon morph class ~1 kB
nav.ts Header/MobileNav overlay open/close, focus trap, scroll lock, Esc; header data-scrolled flag ~2 kB
observer.ts [data-reveal], [data-spy] shared IntersectionObserver: reveal-once classes, scroll-spy for nav/MiniToc, timeline draw trigger ~2 kB
lightbox.ts Gallery open/close/navigate, focus trap, key handling, swipe ~3 kB
form.ts Contact form client validation, honeypot timing, POST to relay, A9 success/error panels, copy-to-clipboard buttons ~3 kB

Rules: modules are independent (no shared state beyond localStorage keys), fail-silent (feature simply absent if errored), loaded defer, total ≤ 15 kB gzip — well under the 40 kB budget with margin for the language-hint logic (~1 kB, lives in nav.ts).

4. Contracts between design tokens and components

  • Components use Tailwind utilities mapped to tokens; no raw hex/px in component code (lint-guarded where feasible).
  • State styling via data-attributes (data-scrolled, data-open, data-revealed, data-status="active") so behaviour modules never touch inline styles — CSS owns all appearance.
  • Motion classes come exclusively from motion.css (token durations + reduced-motion layer) — a component never declares its own transition values.

5. Reuse & variant policy

  • Case-study template is one component set; JobTrack vs InboxIntel differ only in content. Homelab's capability template reuses CsHeader/SectionRenderer, omits TldrBox/MiniToc/DecisionList.
  • The 404, hint bar, and colophon reuse existing atoms only — no bespoke components for one-offs unless an atom can't express it (guard against component sprawl in a one-person codebase).