Skip to content

feat(design-system): introduce DesignSystem module and port primitive components#10

Closed
RealDyllon wants to merge 3 commits into
mainfrom
feat/apple-design-award-ui
Closed

feat(design-system): introduce DesignSystem module and port primitive components#10
RealDyllon wants to merge 3 commits into
mainfrom
feat/apple-design-award-ui

Conversation

@RealDyllon

Copy link
Copy Markdown
Owner

Summary

Implements task group 1 (Design System Foundation, 19/19 tasks) of the
apple-design-award-ui change
proposal. This lays the foundation for the larger UI overhaul that targets
Apple Design Award credibility. Every subsequent screen-level task in the
change will consume tokens through this module.

What's in this PR

Tokens (new module ColimaStack/DesignSystem/Tokens/)

  • TextStyledisplay, title1, title2, title3, body,
    caption, code, mono backed by Font.
  • ColorRoletext/{primary,secondary,tertiary},
    surface/{canvas,raised,sunken,inverse}, border/{subtle,strong},
    accent/primary, status/{success,warning,critical,info,neutral}
    with light/dark resolution and an environment-injected resolver.
  • Spacing — four-point grid (xs 4 → xxl 48).
  • Radiuscontrol 6, card 12, pill 999.
  • Elevation — canvas/raised/sunken.
  • Motion — fast/default/slow × standard/emphasized/spring with a
    reduce-motion observer that collapses non-essential animation.

Primitives (new module ColimaStack/DesignSystem/Primitives/)

  • SectionCard, MetricTile, StatusBanner, KeyValueGrid
  • EmptyStateView (renamed from SurfaceStateView; new
    EmptyStateKind: noResults, noData, loading, error, unavailable,
    disabled)
  • StateDot, IconBadge
  • ToolbarActionButton, PrimaryButton, DestructiveButton
  • WorkspaceTone (moved out of WorkspaceComponents.swift so it
    is shared with the design system)

Icon namespace (ColimaStack/DesignSystem/Icon.swift)

  • Icon.brand, Icon.runtime.*, Icon.profile.*
    (incl. Icon.Profile.forState(_:)), Icon.kubernetes.*,
    Icon.action.*, Icon.section.*, Icon.empty.*
  • Sized via .iconControl (16pt), .iconRow (20pt), .iconHero
    (48pt)
  • Resolves the cube confusion: brand, runtime, profile, and
    Kubernetes each get a distinct symbol; one symbol per concept.

Other

  • BrandMark imageset added to Assets.xcassets (placeholder;
    Icon.brand falls back to the shippingbox.fill SF Symbol until
    the asset is finalized).
  • CI guardrail at scripts/lint-no-raw-tokens.sh fails the build
    if a new Image(systemName:), Color(...), or .font(.system(size:))
    literal is introduced outside ColimaStack/DesignSystem/. A baseline
    of 22 pre-existing violations is captured for incremental cleanup.
  • Contrast test at ColimaStackTests/DesignSystemContrastTests.swift
    asserts every (text role, surface role) pair passes WCAG 2.1 AA in
    both light and dark mode. The contrast helper is also exposed so
    future tokens can self-audit.
  • ContentView now injects the color-role resolver and the
    reduce-motion observer via .designSystemColorResolution() and
    .observeReducedMotion().
  • OverviewScreen migrated to EmptyStateView(kind: ...) and
    DesignSystem.Spacing tokens as the reference implementation.

Backwards compatibility

  • SurfaceStateView and StatusDot are typealiased to the new
    types; the legacy (title:message:symbol:tone:) initializer on
    EmptyStateView infers the kind from the tone so existing call
    sites continue to compile while subsequent PRs migrate them.

Build status

  • xcodebuild build (Debug, macOS) — green
  • xcodebuild build-for-testing — green
  • scripts/lint-no-raw-tokens.sh — clean (22 baseline violations,
    no new ones)
  • UI test runner intentionally not exercised in this PR.

Out of scope (subsequent PRs)

The remaining 113 tasks of the apple-design-award-ui change are
grouped into 11 follow-up workstreams:

  • Group 2: workspace chrome (toolbar, sidebar, title bar, search)
  • Group 3: Table-based data tables
  • Group 4: profile editor rewrite
  • Group 5: settings window rewrite
  • Group 6: terminal log
  • Group 7: container lifecycle (start/stop/restart/delete/inspect/logs)
  • Group 8: onboarding
  • Group 9: empty-states pass (replace every bare Text("No …"))
  • Group 10: motion and feedback (toasts, focus rings, lifecycle flashes)
  • Group 11: accessibility audit and shortcuts menu
  • Group 12: final polish and quality gates

Each group will be a separate PR with a narrow scope so the diff is
reviewable.

Refs

RealDyllon and others added 3 commits June 20, 2026 21:35
Introduces a RuntimeEventBus that fans in events from long-lived
sources and drives AppState as a delta-applying reducer, replacing
the runAutoRefreshLoop that spawned ~20 subprocesses every 2-10s.

New infrastructure:
- RuntimeEventBus: AsyncStream<RuntimeEvent> fan-in with bounded buffer
- RuntimeEventEngine: @StateObject at app scope that observes
  selectedProfileID and starts/stops per-profile sources on change;
  survives main window close so the menu bar stays live
- StreamingProcessRunner: yields stdout/stderr chunks before process
  exit, with cooperative cancellation and timeout escalation
- AppState.reduce(_:): applies typed deltas to the minimal affected
  @published slice (containers, pods, logs, monitor samples, etc.)

New event sources (all behind the useEventBus flag, default on):
- DockerEventSource: docker events --format json stream with bootstrap
  snapshot and exponential backoff reconnect
- KubernetesWatchSource: kubectl get pods -A -w -o json with bootstrap
  and backoff
- ColimaFileWatcherSource: DispatchSource vnode watchers on
  colima.yaml, daemon.log, and lima state; triggers on-demand
  colima status probes and tails the daemon log live

Phase 1 streaming command output:
- Lifecycle commands (start/stop/restart/delete/kubernetes/update)
  now route through StreamingProcessRunner when
  useStreamingCommandOutput is on; commandLog entries update
  incrementally as chunks arrive
- Cancel button in the toolbar cancels the running command via
  ProcessCancellation
- Live ProgressView in CommandEntryRow while a command runs

Connection state:
- Each source tracks ConnectionState (disconnected/connecting/connected/
  reconnecting/failed) exposed via AppState.connectionStatus
- Menu bar and Overview show degraded/reconnecting status

Removed:
- runAutoRefreshLoop (fixed-interval polling)
- runAutoRefreshLoop branch in ColimaStackApp
- Dead appState.searchText published property

Updated docs/architecture.md to describe the event-driven control
plane (Docker events, kubectl watch, DispatchSource file watchers,
streaming process runner, tool presence timer) replacing polling.
Adds the proposal, 13 capability specs, design, and tasks for a
comprehensive UI overhaul targeting Apple Design Award credibility:
design system tokens, native chrome, SwiftUI Table migration, custom
profile editor and settings, terminal log, empty states, iconography,
motion, accessibility, menubar polish, onboarding, and container
lifecycle actions.

Refs: openspec/changes/apple-design-award-ui/
… components

Lays the foundation for the apple-design-award-ui change. Every view
in the app will consume design tokens through this module; raw
Color/Font/Image(systemName:) literals in screen code are now
forbidden by a CI guardrail.

Tokens:
* TextStyle — display, title1, title2, title3, body, caption, code, mono
* ColorRole — text/surface/border/accent/status roles with light/dark
  resolution and an environment-injected resolver
* Spacing — four-point grid (xs 4 → xxl 48)
* Radius — control 6, card 12, pill 999
* Elevation — canvas/raised/sunken
* Motion — fast/default/slow × standard/emphasized/spring, with a
  reduce-motion observer that collapses non-essential animation

Primitives (port from WorkspaceComponents.swift to token-driven):
* SectionCard, MetricTile, StatusBanner, KeyValueGrid
* EmptyStateView (renamed from SurfaceStateView; new
  EmptyStateKind: noResults/noData/loading/error/unavailable/disabled)
* StateDot, IconBadge
* ToolbarActionButton, PrimaryButton, DestructiveButton

Icon namespace — one symbol per concept:
* Icon.brand, Icon.runtime.*, Icon.profile.* (incl. forState(_:)),
  Icon.kubernetes.*, Icon.action.*, Icon.section.*, Icon.empty.*
* Sized via .iconControl (16pt), .iconRow (20pt), .iconHero (48pt)

Other:
* BrandMark imageset added (placeholder; Icon.brand falls back to
  shippingbox.fill SF Symbol until the asset is finalized)
* scripts/lint-no-raw-tokens.sh — CI guardrail that fails on new
  raw-token usages outside ColimaStack/DesignSystem/ (baseline of 22
  pre-existing violations captured for incremental cleanup)
* ColimaStackTests/DesignSystemContrastTests — asserts every
  (text, surface) pair passes WCAG 2.1 AA in both color schemes
* ContentView root now injects the colorRole resolver and the
  reduce-motion observer via .designSystemColorResolution() and
  .observeReducedMotion()
* OverviewScreen migrated to EmptyStateView(kind: ...) and
  DesignSystem.Spacing tokens as the reference implementation

Backwards compatibility:
* SurfaceStateView and StatusDot are typealiased to the new types
* EmptyStateView retains the legacy (title:message:symbol:tone:)
  initializer that infers the kind from the tone, so existing call
  sites continue to compile while subsequent PRs migrate them

Build status: xcodebuild build (Debug, macOS) is green; build-for-testing
is green; UI test runner is intentionally not exercised in this PR.

Refs: openspec/changes/apple-design-award-ui/{proposal,design}.md,
openspec/changes/apple-design-award-ui/specs/design-system/spec.md,
openspec/changes/apple-design-award-ui/tasks.md (group 1: 19/19 done)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant