Files
web-app-launcher/src/lib/components/ui/ErrorState.svelte
T
alexei.dolgolyov 5dcadd1c20 feat(ui): migrate entire UI to "Cozy Home" design
Warm, friendly redesign replacing the generic cold-shadcn look. Built as a
swappable token bundle so other presets can be added later; dark mode and the
user-tunable accent hue are retained.

Foundation
- app.css: warm cream (light) + "dusk" (dark) token system; terracotta accent
  (default hue 16); pastel --room-* palette; vivid --status-* (dots/bars) plus
  AA-legible --status-*-ink (text); soft warm shadows; --radius 1rem; font tokens
- Fonts: Fraunces (display) + Figtree (body), self-hosted in static/fonts
  (no Google CDN) so offline/LAN installs work; system-ui fallbacks kept
- h1/h2/h3 render in Fraunces via base layer

Chrome and surfaces
- Sidebar, Header, home, AppCard/BoardCard, BoardHeader, sections, favorites
- 29 widgets + integration renderers: cozy card shells, room-palette charts
- Default background is a static warm "cozy" glow (mesh demoted, rAF gated on
  prefers-reduced-motion)

System-wide
- Status colors tokenized (no raw bg/text-*-500 or status hex); success/warning
  to status tokens, categorical to room palette, errors to destructive
- Inputs rounded-xl; buttons rounded-xl; cards/dialogs rounded-[1.4rem];
  soft-shadow vocabulary only; focus-visible:ring-primary/30
- Forms, admin tables (now cozy cards), dialogs, popovers, auth screens

a11y: reduced-motion guards; darker status "ink" text for AA on cream.
Known tradeoff: terracotta primary + white button text ~2.96:1 (signature color,
user-tunable).

Verified: svelte-check 0/0, build ok, 274 tests pass, eslint 0 errors.
Design refs + system sheet in design-mockups/.
2026-05-27 23:04:47 +03:00

61 lines
1.8 KiB
Svelte

<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
status: number;
title: string;
hint?: string;
/** Optional detail block (e.g. raw error message in a <details>). */
details?: Snippet;
/** Primary + secondary call-to-action snippets. */
actions?: Snippet;
/** When true, render the chrome (AmbientBackground, card surface). For
* boards/admin nested errors we want to inherit the parent layout. */
standalone?: boolean;
}
let { status, title, hint, details, actions, standalone = false }: Props = $props();
</script>
{#if standalone}
<main
class="relative z-10 flex min-h-screen items-center justify-center bg-background/80 p-4 text-foreground"
>
<div
class="w-full max-w-lg rounded-xl border border-border bg-card/90 p-8 text-center shadow-[var(--shadow-lift)] backdrop-blur-sm"
>
<div class="mb-2 text-xs uppercase tracking-widest text-muted-foreground">
{status}
</div>
<h1 class="mb-2 text-2xl font-semibold">{title}</h1>
{#if hint}
<p class="mb-6 text-sm text-muted-foreground">{hint}</p>
{/if}
{#if details}
<div class="mb-6 text-left">{@render details()}</div>
{/if}
{#if actions}
<div class="flex flex-wrap justify-center gap-2">{@render actions()}</div>
{/if}
</div>
</main>
{:else}
<main
class="mx-auto flex min-h-[60vh] max-w-lg flex-col items-center justify-center px-4 py-16 text-center"
>
<div class="mb-2 text-xs uppercase tracking-widest text-muted-foreground">
{status}
</div>
<h1 class="mb-2 text-2xl font-semibold">{title}</h1>
{#if hint}
<p class="mb-6 text-sm text-muted-foreground">{hint}</p>
{/if}
{#if details}
<div class="mb-6 w-full text-left">{@render details()}</div>
{/if}
{#if actions}
<div class="flex flex-wrap justify-center gap-2">{@render actions()}</div>
{/if}
</main>
{/if}