You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extract duplicated UI patterns from route-level Svelte files into shared components under web/admin/src/lib/components/, and convert hardcoded hex values into CSS custom properties in app.css. This eliminates copy-paste drift and gives upcoming features (#510–#514) a consistent component foundation.
Prerequisite: PR #624 (DESIGN.md) and PR #625 (ESLint/Prettier/Stylelint + Husky) should merge first. DESIGN.md defines the token palette; the linter enforces component size limits.
Depends on: PR #617 (Barak's org list + OAuth worker) — the extraction targets App.svelte and OrgList.svelte as they exist on that branch.
Estimated effort: 14–16 hours (~2 days)
Problem
The admin SPA has zero shared components. Every file re-implements buttons, spinners, and banners with slight inconsistencies:
OrgList.svelte is 1,155 lines. App.svelte is 473 lines. Both exceed the 150-line component limit from PR #625.
Phases
Phase 1: CSS custom properties token file
Expand app.css from 6 lines into the token foundation. Every color, spacing, typography, and radius value from DESIGN.md becomes a CSS custom property under :root. Includes .sr-only utility and prefers-reduced-motion media query.
~55 hardcoded hex values across App.svelte and OrgList.svelte map to tokens. GitHub sign-in button colors (#0d1117 etc.) stay local — they're GitHub brand colors, not part of the design system.
Phase 2: Shared component extraction
Create web/admin/src/lib/components/ with:
Component
Props
Replaces
Spinner.svelte
size: 'sm'|'md'|'lg'|'xl', label: string
6 spinner implementations (normalized to 4 sizes)
Button.svelte
variant: 'default'|'primary'|'accent'|'muted'|'link', children, leading (snippet slot for spinner)
link — text-styled inline action (replaces .link-btn)
Phase 3: Migration
Replace inline implementations in App.svelte and OrgList.svelte with shared component imports. Delete duplicate CSS. Each route file should drop well below the 150-line limit after extraction.
Migration example (spinner):
<!-- Before -->
<spanclass="spinner"aria-hidden="true"></span>
<!-- After -->
<Spinnersize="sm"label="Loading session" />
Summary
Extract duplicated UI patterns from route-level Svelte files into shared components under
web/admin/src/lib/components/, and convert hardcoded hex values into CSS custom properties inapp.css. This eliminates copy-paste drift and gives upcoming features (#510–#514) a consistent component foundation.Prerequisite: PR #624 (DESIGN.md) and PR #625 (ESLint/Prettier/Stylelint + Husky) should merge first. DESIGN.md defines the token palette; the linter enforces component size limits.
Depends on: PR #617 (Barak's org list + OAuth worker) — the extraction targets
App.svelteandOrgList.svelteas they exist on that branch.Estimated effort: 14–16 hours (~2 days)
Problem
The admin SPA has zero shared components. Every file re-implements buttons, spinners, and banners with slight inconsistencies:
.btnbase0.35remvs0.4rem; border#aaavs#888.btn.primary#24292f(emphasis) vs#0969da(accent)@keyframes spinspin), OrgList.svelte (org-spin).banner.sr-onlyOrgList.svelte is 1,155 lines. App.svelte is 473 lines. Both exceed the 150-line component limit from PR #625.
Phases
Phase 1: CSS custom properties token file
Expand
app.cssfrom 6 lines into the token foundation. Every color, spacing, typography, and radius value from DESIGN.md becomes a CSS custom property under:root. Includes.sr-onlyutility andprefers-reduced-motionmedia query.~55 hardcoded hex values across App.svelte and OrgList.svelte map to tokens. GitHub sign-in button colors (
#0d1117etc.) stay local — they're GitHub brand colors, not part of the design system.Phase 2: Shared component extraction
Create
web/admin/src/lib/components/with:Spinner.sveltesize: 'sm'|'md'|'lg'|'xl',label: stringButton.sveltevariant: 'default'|'primary'|'accent'|'muted'|'link',children,leading(snippet slot for spinner).btn/.link-btnduplicationButtonLink.sveltehref,variant,children<a class="btn">patterns in OrgListBanner.sveltevariant: 'error'|'warning'|'success'|'info',dismissible,children,actions(snippet slot).bannerduplicationCard.sveltechildren, heading snippetindex.tsAll components use Svelte 5 runes (
$props()) and follow DESIGN.md accessibility requirements (focus rings, ARIA attributes, reduced motion).Spinner sizes normalized:
smmdlgxlButton variants:
default— secondary actions (sign out, dismiss)primary— emphasis/dark bg (--bg-emphasis)accent— blue CTA for deploy/action (--fg-accent)muted— subtle, less prominentlink— text-styled inline action (replaces.link-btn)Phase 3: Migration
Replace inline implementations in App.svelte and OrgList.svelte with shared component imports. Delete duplicate CSS. Each route file should drop well below the 150-line limit after extraction.
Migration example (spinner):
Migration example (button with spinner):
Phase 4: Verification
npm run lint,npm run format:check,npm run stylelint)svelte-checkpasses with zero errorsRelationship to other issues