From bbc5db473a6c4b95902b1861a888537ef538d193 Mon Sep 17 00:00:00 2001 From: Admin <1+admin@noreply.git.dcntrlized.org> Date: Mon, 3 Aug 2026 14:22:50 +0100 Subject: [PATCH] feat(frontend): redesign console UI with new component tree and design system --- src/frontend/DESIGN.md | 211 ++++++++++ src/frontend/PRODUCT.md | 59 +++ src/frontend/bun.lock | 27 +- src/frontend/index.html | 7 +- src/frontend/package.json | 7 +- src/frontend/src/app.css | 0 src/frontend/src/app.tsx | 395 +++--------------- src/frontend/src/assets/hero.png | Bin 13057 -> 0 bytes src/frontend/src/assets/preact.svg | 1 - src/frontend/src/assets/vite.svg | 1 - src/frontend/src/components/brand-mark.tsx | 26 ++ .../connection/connection-badge.tsx | 46 ++ .../src/components/container/status.ts | 81 ++++ src/frontend/src/components/layout/header.tsx | 53 +++ .../src/components/layout/status-states.tsx | 70 ++++ .../src/components/layout/toolbar.tsx | 92 ++++ .../src/components/service/service-card.tsx | 265 ++++++++++++ .../src/components/service/service-grid.tsx | 16 + src/frontend/src/components/ui/badge.tsx | 54 +++ .../{lib/shadcn => }/components/ui/button.tsx | 14 +- src/frontend/src/components/ui/card.tsx | 89 ++++ src/frontend/src/components/ui/input.tsx | 29 ++ src/frontend/src/components/ui/sonner.tsx | 49 +++ src/frontend/src/components/ui/spinner.tsx | 16 + src/frontend/src/index.css | 391 +++++++++-------- .../src/lib/components/connectionBadge.tsx | 48 --- .../src/lib/components/installButton.tsx | 52 --- .../src/lib/components/startButton.tsx | 44 -- .../src/lib/components/stopButton.tsx | 45 -- .../src/lib/components/uninstallButton.tsx | 45 -- src/frontend/src/lib/maestro/containers.tsx | 56 --- .../src/lib/shadcn/components/ui/badge.tsx | 58 --- .../src/lib/shadcn/components/ui/card.tsx | 100 ----- .../src/lib/shadcn/components/ui/input.tsx | 29 -- .../src/lib/shadcn/components/ui/spinner.tsx | 10 - .../src/lib/shadcn/components/ui/tabs.tsx | 91 ---- src/frontend/src/lib/shadcn/lib/utils.ts | 6 - src/frontend/src/main.tsx | 2 +- src/frontend/tsconfig.app.json | 2 +- src/frontend/vite.config.ts | 2 +- 40 files changed, 1469 insertions(+), 1120 deletions(-) create mode 100644 src/frontend/DESIGN.md create mode 100644 src/frontend/PRODUCT.md delete mode 100644 src/frontend/src/app.css delete mode 100644 src/frontend/src/assets/hero.png delete mode 100644 src/frontend/src/assets/preact.svg delete mode 100644 src/frontend/src/assets/vite.svg create mode 100644 src/frontend/src/components/brand-mark.tsx create mode 100644 src/frontend/src/components/connection/connection-badge.tsx create mode 100644 src/frontend/src/components/container/status.ts create mode 100644 src/frontend/src/components/layout/header.tsx create mode 100644 src/frontend/src/components/layout/status-states.tsx create mode 100644 src/frontend/src/components/layout/toolbar.tsx create mode 100644 src/frontend/src/components/service/service-card.tsx create mode 100644 src/frontend/src/components/service/service-grid.tsx create mode 100644 src/frontend/src/components/ui/badge.tsx rename src/frontend/src/{lib/shadcn => }/components/ui/button.tsx (65%) create mode 100644 src/frontend/src/components/ui/card.tsx create mode 100644 src/frontend/src/components/ui/input.tsx create mode 100644 src/frontend/src/components/ui/sonner.tsx create mode 100644 src/frontend/src/components/ui/spinner.tsx delete mode 100644 src/frontend/src/lib/components/connectionBadge.tsx delete mode 100644 src/frontend/src/lib/components/installButton.tsx delete mode 100644 src/frontend/src/lib/components/startButton.tsx delete mode 100644 src/frontend/src/lib/components/stopButton.tsx delete mode 100644 src/frontend/src/lib/components/uninstallButton.tsx delete mode 100644 src/frontend/src/lib/maestro/containers.tsx delete mode 100644 src/frontend/src/lib/shadcn/components/ui/badge.tsx delete mode 100644 src/frontend/src/lib/shadcn/components/ui/card.tsx delete mode 100644 src/frontend/src/lib/shadcn/components/ui/input.tsx delete mode 100644 src/frontend/src/lib/shadcn/components/ui/spinner.tsx delete mode 100644 src/frontend/src/lib/shadcn/components/ui/tabs.tsx delete mode 100644 src/frontend/src/lib/shadcn/lib/utils.ts diff --git a/src/frontend/DESIGN.md b/src/frontend/DESIGN.md new file mode 100644 index 0000000..a6559e3 --- /dev/null +++ b/src/frontend/DESIGN.md @@ -0,0 +1,211 @@ +--- +name: Maestro · dcntrlized console +description: Dark ops console for running a self-hosted node — precise, calm, alive at night. +colors: + primary: "oklch(0.4981 0.1996 354.66)" + primary-foreground: "oklch(0.97 0.012 354)" + secondary: "oklch(0.63 0.15 354.66)" + tertiary: "oklch(0.39 0.14 354.66)" + signal: "oklch(0.74 0.13 160)" + ember: "oklch(0.78 0.15 55)" + alert: "oklch(0.66 0.2 24)" + night-ink: "oklch(0.14 0.015 265)" + panel: "oklch(0.173 0.017 265)" + raised: "oklch(0.19 0.018 265)" + slate: "oklch(0.218 0.026 354)" + muted-fill: "oklch(0.205 0.018 265)" + frost: "oklch(0.955 0.004 265)" + ash: "oklch(0.7 0.02 265)" + edge: "oklch(100% 0 0 / 8%)" +typography: + title: + fontFamily: "IBM Plex Sans Variable, system-ui, sans-serif" + fontSize: "15px" + fontWeight: 600 + body: + fontFamily: "IBM Plex Sans Variable, system-ui, sans-serif" + fontSize: "13px" + fontWeight: 400 + lineHeight: 1.55 + label: + fontFamily: "JetBrains Mono Variable, ui-monospace, monospace" + fontSize: "11px" + fontWeight: 500 +rounded: + sm: "7px" + md: "9px" + lg: "11px" + xl: "15px" + pill: "9999px" +spacing: + xs: "4px" + sm: "8px" + md: "12px" + lg: "16px" + xl: "24px" +components: + button-primary: + backgroundColor: "{colors.primary}" + textColor: "{colors.primary-foreground}" + rounded: "{rounded.lg}" + padding: "12px 16px" + button-primary-hover: + backgroundColor: "color-mix(in oklab, {colors.primary} 80%, transparent)" + button-ghost: + backgroundColor: "transparent" + textColor: "{colors.ash}" + rounded: "{rounded.lg}" + chip-running: + backgroundColor: "color-mix(in oklab, {colors.signal} 10%, transparent)" + textColor: "{colors.signal}" + rounded: "{rounded.pill}" + card-service: + backgroundColor: "{colors.panel}" + rounded: "{rounded.xl}" + input-search: + backgroundColor: "color-mix(in oklab, {colors.muted-fill} 40%, transparent)" + rounded: "{rounded.lg}" +--- + +# Design System: Maestro · dcntrlized console + +## Overview + +**Creative North Star: "The Night Conductor"** + +Maestro is the dark booth at the edge of the night. A single operator runs every service on the rack from a near-black console — a raspberry glow overhead, warm ember and signal lights breathing along the rails below. Nothing on screen shouts; everything is readable at a glance, like instrument faces in a dim cockpit. The interface is calm, precise, and quietly alive: status lights pulse only when something is actually happening, surfaces sit in hairline-defined layers, and every action reads as a deliberate act of control rather than a marketing flourish. + +Density is operator-dense but never crowded. One service equals one card; the card compresses identity (monogram tile), state (status light), provenance (vendor, image, source), and the single correct next action into a tight unit. The header is a glance-line: brand, installed count, update flag, and connection state in one row. The visual system is built on tonal layering over flat ink — near-black blue-zinc surfaces stacked by elevation, separated by 8% white hairlines — with soft black drop shadows used only as ambient grounding, never as decoration. + +**Key Characteristics:** +- Nocturnal and utilitarian — near-black blue-zinc ink, never pure black, never white-page light. +- Raspberry is the only accent and it is rare; it marks brand, the primary action, and focus. +- Warm status lights (signal / ember) carry operational truth; blue is banned from status semantics. +- Hairline borders over tonal surfaces convey structure; shadows are ambient, not structural. +- Mono type does the technical talking; the sans voice is quiet, structured, legible. +- Motion is a response to state — pings, toasts, hovers — gated behind `prefers-reduced-motion`. + +## Colors + +The palette is one raspberry accent against a cool blue-zinc ink scene. Status colors are warm lights (green, orange, red) tuned to sit inside the scene and read at a glance without clashing with the accent. + +### Primary +- **Raspberry** (oklch(0.4981 0.1996 354.66) · #b00b69): The single accent. Used for the brand mark, the primary action button, the active search/filter treatment, and the focus ring. Its rarity is the point — it should never paint a whole screen. +- **Primary Frost** (oklch(0.97 0.012 354)): Frost-white text *on* raspberry. The dark accent needs light ink — holds AA at 6.2:1 while staying inside the night scene. + +### Secondary +- **Rose** (oklch(0.63 0.15 354.66)): The brand family's lighter voice — supporting accents, chart fills, hover tints. Derived from the raspberry hue, never picked ad hoc. +- **Ember** (oklch(0.78 0.15 55)): Warm orange. Warns — stopping, restarting, transitions, "update available", registry unreachable. +- **Signal** (oklch(0.74 0.13 160)): Warm emerald. Running / connected / success — the "all clear" light. + +### Tertiary +- **Wine** (oklch(0.39 0.14 354.66)): The deep bookend of the raspberry family — pressed states and depth accents. Too dark for text on the scene; surfaces only. +- **Alert** (oklch(0.66 0.2 24)): Crimson red. Destructive intent and hard failures — uninstall, errors, lost connection. Deepened to read as danger beside the raspberry accent. + +### Neutral +- **Night Ink** (oklch(0.14 0.015 265)): Page background. The scene's floor. +- **Frost** (oklch(0.955 0.004 265)): Primary text — headings, names, labels. +- **Ash** (oklch(0.7 0.02 265)): Secondary text and metadata. Set bright enough to hold AA at 11px (4.5:1 on secondary). +- **Panel** (oklch(0.173 0.017 265)): Card surface — one step up from the page. +- **Raised** (oklch(0.19 0.018 265)): Popover / toast surface — the top layer. +- **Blush** (oklch(0.218 0.026 354)): Secondary and selected fills — quiet chips, monogram tiles. Near-black ink with a faint raspberry cast. +- **Muted Fill** (oklch(0.205 0.018 265)): Quiet fills — inputs, version chips. +- **Edge** (oklch(100% 0 0 / 8%)): Hairline borders and dividers. Structure without weight. + +### Named Rules +**The One Voice Rule.** Raspberry appears on ≤10% of any given screen. Its rarity is the signal — when raspberry appears, it means "act here" or "this is Maestro itself." +**The Derived Family Rule.** Rose and wine are the raspberry family's lightness bookends, derived in OKLCH from the primary hue — never chosen ad hoc. Rose carries support (accents, tints, charts); wine carries depth (press, shadows of brand surfaces). +**The No Blue Light Rule.** Blue is banned from status semantics. Operational states are warm (signal / ember / alert) only; a blue accent reads as the old stock dashboard and breaks the scene. +**The Warm-Second Rule.** Warm accents are derived to sit *inside* the dark scene: on-card chips use a 10–25% tint of the accent over the surface, never a full-strength saturated wash. + +## Typography + +**Display Font:** IBM Plex Sans Variable (fallback system-ui, sans-serif) +**Body Font:** IBM Plex Sans Variable (fallback system-ui, sans-serif) +**Label/Mono Font:** JetBrains Mono Variable (fallback ui-monospace, Menlo, monospace) + +**Character:** A structured, technical-but-human pairing. IBM Plex Sans is quietly engineered — clear, slightly industrial, no flourish — while JetBrains Mono carries the machine voice: names, images, versions, and counts. Mono is used for anything the operator might copy or compare; sans for anything meant to be read. + +### Hierarchy +Type sizes are authored at 100% density in the DESIGN tokens and rendered 1.5× by the root `font-size: 150%` on `` (rem-based utilities scale, px and viewport units don't). The relative steps below are the design intent; on screen they read 18 / 21 / 24 / 27px. +- **Title** (600, 15px, 1.2): Brand wordmark, card names. The only semibold in the system. +- **Body** (400, 13px, 1.55): Descriptions and secondary reading. Capped at 2 lines in cards. +- **Label** (500, 11px, mono): Versions, image refs, counts, vendor, service names, timestamps. Tabular-nums where numeric (`tabular-nums`). + +### Named Rules +**The Mono Voice Rule.** Anything technical is mono: image references, versions, service names, counts. If a user could copy it, set it in JetBrains Mono. +**The One-Weight Rule.** Sans weight stays at 400 (body) and 600 (title). No 500 intermediates; hierarchy comes from size and mono, not weight gradations. + +## Layout + +**Density baseline: desktop-first at 150%, a single root rule.** The console targets desktop operators on 1080p displays at 100% zoom. Density is achieved with one line in `src/index.css` — `html { font-size: 150% }` — so every rem-based utility (`text-sm`, `text-lg`, `max-w-xl`, `h-8`, `gap-4`, `rounded-lg`) scales 1.5× while keeping its standard Tailwind name. No theme values are rewritten; the only density token is `--radius` (0.6875rem), the design's 11px corner base, which scales with the root font-size. `zoom` was ruled out because it scales viewport units and px too, breaking `min-h-screen`/`dvh` filling and the hairline px focus ring. Px values (focus ring `ring-[3px]`, shadows, borders) stay hairline. Breakpoints are pinned to fixed CSS px (`--breakpoint-*: 640/768/1024/1280px`) rather than rem, so the responsive grid stays tied to the real viewport and keeps 3 columns on desktop instead of collapsing. + +The console is a single centered column capped at 1800px (`max-w-console` = `--container-console: 75rem`, scaled 1.5× by the root font-size) with horizontal padding 24px / 36px desktop. The header is a fixed glance-line: 96px tall (`h-16`), sticky, hairline bottom border, frosted (`bg-background/85` + `backdrop-blur-md`) so cards scroll under it. Below it, the page stacks with 36px rhythm: toolbar → result count → grid. + +Services render in a 3-column grid at desktop (`xl:grid-cols-3`); narrower viewports drop to 2 columns at `sm` and 1 below, but mobile is not a design target — the desktop layout is the committed truth. Cards are equal-height units; each card is a self-contained column with footer actions pinned to the bottom. The toolbar keeps its single-row search + segmented filters on desktop. + +Spacing follows the tailwind half-step rhythm (6 / 12 / 18 / 24 / 36px at the 150% root). Inside cards: content padding 24–30px, gaps 18px between identity row, description, and metadata; footer separated by a hairline with 18px top padding. + +## Elevation & Depth + +**Hairline precision** — depth is carried by tonal layering and hairline borders first, ambient shadow second. Every surface is flat at rest; elevation reads as a lighter fill (Night Ink → Panel → Raised) plus an 8% white hairline. Shadows are soft black ambient pools used only to lift interactive/critical layers off the page. + +### Shadow Vocabulary +- **Card** (`0 1px 0 rgba(0,0,0,0.4), 0 10px 28px -14px rgba(0,0,0,0.6)`): The resting card pool. Ambient, non-structural. +- **Card Hover** (`0 1px 0 rgba(0,0,0,0.4), 0 16px 36px -16px rgba(0,0,0,0.75)`): A card under the cursor — a slightly deeper pool, nothing dramatic. +- **Toast** (`0 8px 30px -8px rgba(0,0,0,0.7)`): The floating layer — toasts hover above everything. + +### Named Rules +**The Flat-At-Rest Rule.** Surfaces are flat at rest. Shadows appear only as a state response (hover, floating layers) or as ambient grounding. No shadows on chips, badges, or buttons — borders do that work. + +## Shapes + +The form language is **precision with a softened edge**: corners are rounded but never pill-soft on structural surfaces. Cards use 15px (`rounded-xl`), buttons and inputs 11px (`rounded-lg`), the brand mark 10px. Only status/state *chips* and the connection badge break into full pills (`rounded-full`) — the pill shape is reserved for state, never structure. Monogram tiles are 36px squares at `rounded-lg` with a hairline border and a tinted fill matching their status tone. The overall silhouette reads as a rack of neat, softly-cornered instruments. + +## Components + +### Buttons +- **Shape:** 11px radius, tight 1–3px gutters, 28px resting height (24/32/36 by size step). +- **Primary (Raspberry):** raspberry fill with frost-white text (6.2:1). Hover dims to 80% (`hover:bg-primary/80`); press nudges down 1px. +- **Status actions (Start / Update):** transparent fills with a tinted 30% border and tinted text — signal for Start, ember for Update. These read as "operational" rather than "branded". +- **Ghost:** transparent, ash text; hover warms to a muted fill. Used for uninstall (hover flips to alert) and the connection badge. +- **Focus:** raspberry ring at 30% (`ring-3 ring-primary/30`) + border shift; always visible for keyboard. +- **Disabled:** 50% opacity, pointer-events off. + +### Chips +- **Status chip:** full pill, 11px mono-adjacent sans, 1.5px gutter with a 2px status light. Tint follows the tone: signal/ember/alert at 10% fill over the surface with a 25% border. +- **Filter pill:** segmented control in a hairline tray (`bg-muted/60`); active pill lifts to `bg-card` with a hairline ring, inactive stays ash on hover. + +### Cards / Containers +- **Corner Style:** 15px (`rounded-xl`). +- **Background:** Panel (oklch(0.173 0.017 265)) + hairline Edge border. +- **Shadow Strategy:** ambient Card pool; hover deepens to Card Hover (see Elevation). +- **Internal Padding:** 20px horizontal, 16px top, content gap 12px; footer hairline-separated, 12px top. +- **Behavior:** hover deepens border to `border-border/90` and the shadow pool. The update badge is an ember chip with an up-arrow; version → latest is a mono "vX → vY" pair. + +### Inputs / Fields +- **Style:** 11px radius, 36px tall, muted-fill at 40% opacity over the surface, hairline `--input` border, ash placeholder. +- **Focus:** raspberry ring at 30% + border shift to `--ring`. No shadow. + +### Navigation +- **Style:** the sticky header is a hairline bar: brand block (mark + wordmark + mono subtitle) left; right side holds the installed count chip, the ember "updates" pill, and the connection badge. On desktop (the design target) all elements show in the glance-line. + +### Service Card (signature) +The rack unit. Left: 36px status-tinted monogram tile. Middle: title (sans 600) + vendor (mono), the image ref as a compact mono copy chip (host-stripped, truncating, click-to-copy with a toast), 2-line description clamp. Bottom metadata strip: current version chip, ember update chip when stale, container-ID copy chip when running, and a right-aligned mono "Source" link. Footer: uninstall ghost icon left; right side the correct action — Install (raspberry), Start (signal), Stop (outline), Update (ember) — one primary action per state, disabled while busy with a spinner. + +## Do's and Don'ts + +### Do: +- **Do** keep raspberry rare and purposeful — brand mark, one primary action, focus ring. +- **Do** use signal for running/connected and ember for warning/updates; these warm lights are the operator's truth. +- **Do** set every technical value (versions, images, names, counts) in JetBrains Mono. +- **Do** separate surfaces with hairlines and tonal steps, and keep shadows ambient-only. +- **Do** show exactly one primary action per card state, and disable it with a spinner while pending. +- **Do** gate all motion (status pings, toast entrance) behind `prefers-reduced-motion`. + +### Don't: +- **Don't** use blue for any status or accent role — the scene is raspberry + warm status lights only. +- **Don't** paint surfaces with full-strength saturated washes; status tints sit at 10–25% over the surface. +- **Don't** put shadows on chips, badges, or buttons — borders carry that weight. +- **Don't** add sans weights beyond 400/600, or introduce a second sans family. +- **Don't** pill-round structural elements (cards, buttons, inputs); pills are reserved for state chips and the connection badge. diff --git a/src/frontend/PRODUCT.md b/src/frontend/PRODUCT.md new file mode 100644 index 0000000..f0f8705 --- /dev/null +++ b/src/frontend/PRODUCT.md @@ -0,0 +1,59 @@ +# Product + + + +## Platform + +web + +## Users + +- Primary: dcntrlized node operators and self-hosters who run their own infrastructure and deploy services from the dcntrlized registry onto a Docker host. [Inferred from README positioning and docker-compose evidence; confirm.] +- Adjacent: developers and tinkerers evaluating Maestro and the dcntrlized ecosystem. + +## Product Purpose + +Maestro is the coordination layer of the dcntrlized ecosystem: a single web console that runs on a Docker host, lists the services installed on that node, lets the operator install new services from the dcntrlized container registry, and start, stop, update, and uninstall them. Success is a node operator managing the whole service stack from one console without dropping to the shell. + +## Positioning + +The mechanism is a Git-backed, decentralized service registry: services are published as OCI images with rich metadata in a Gitea registry, discovered through `/api/registry`, and installed by reference onto the node. The dashboard merges that remote catalog with the live local Docker state so installed services, available updates, and registry-only (not-yet-installed) services live in one view. Plainly: a decentralized app store that runs on your own hardware. + +## Operating Context + +- Web dashboard served from the Go backend on `:8080`, which talks to the local Docker socket. +- Live state flows over WebSocket (`ws://127.0.0.1:8080/api/ws`); the catalog is fetched once from `/api/registry`. +- Real-time statuses come from Docker (running, exited, stopped, created, restarting) plus UI states (installed, uninstalled). +- Service metadata (title, vendor, author, description, source, licenses, revision) comes from OCI annotations published with each image. +- Upstream registry is git.dcntrlized.org (Gitea), org `Dcntrlized`. +- Maestro itself runs as a container (image `maestro`); its own container is hidden from the list. +- Update detection compares the installed version against the registry latest via semver; versions are normalized to `X.Y.Z`. + +## Capabilities and Constraints + +- Capabilities: list installed + registry services; filter (all / running / updates / registry-only); search by name, image, or source; install, update (reinstall), start, stop, uninstall; live connection indicator; repository link per registry service. +- Constraints: browser talks to the backend on `127.0.0.1:8080` (dev proxy in Vite); no auth in the current UI; the data model merges local containers with remote registry items and must keep both sources distinct. +- Terminology: containers/services, registry, installed, running, "update available". + +## Brand Commitments + +- Name: Maestro. Organization: dcntrlized (lowercase, `.org`). Docker image name `maestro`. +- Open source (LICENSE present); dcntrlized ethos is decentralized, self-hosted, own-your-infrastructure. + +## Evidence on Hand + +- Backend Go source in `../src/` (handlers, lib) is the API and data-model truth. +- `services.json` at repo root lists registry examples: KeepNote (dcntrlized.org:8081), SafeGuard (dcntrlized.org:8082). +- README, docker-compose.yaml (mounts docker.sock, Gitea tokens), LICENSE. +- No DESIGN.md. Incumbent UI is a stock shadcn template — evidence of what it looked like, not authority over what it becomes. + +## Product Principles + +- Own your stack: the console runs on the node, beside the services it manages. +- One surface, live state: local Docker reality and the remote catalog appear in a single merged view. +- Act without the shell: install, start, stop, update, uninstall all happen from the UI. +- Honest status: every service shows a truthful current state and the action that fits it. + +## Accessibility & Inclusion + +- No product-specific requirement established yet; standard WCAG 2.x AA contrast and full keyboard support expected. diff --git a/src/frontend/bun.lock b/src/frontend/bun.lock index 8ad6d4e..5ac0086 100644 --- a/src/frontend/bun.lock +++ b/src/frontend/bun.lock @@ -5,17 +5,16 @@ "": { "name": "frontend", "dependencies": { - "@fontsource-variable/inter": "^5.3.0", + "@fontsource-variable/ibm-plex-sans": "^5.3.0", + "@fontsource-variable/jetbrains-mono": "^5.3.0", "@tailwindcss/vite": "^4.3.3", - "@types/semver": "^7.7.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.27.0", "preact": "^10.29.3", "react-aria-components": "^1.19.0", - "react-icons": "^5.7.0", - "semver": "^7.8.5", "shadcn": "^4.15.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.4.0", @@ -101,7 +100,9 @@ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], - "@fontsource-variable/inter": ["@fontsource-variable/inter@5.3.0", "", {}, "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA=="], + "@fontsource-variable/ibm-plex-sans": ["@fontsource-variable/ibm-plex-sans@5.3.0", "", {}, "sha512-agG8tXFEo0hD9+J7npa4vbbWult52eMLVaQ6WQRlhs/iCAojrMAoejru85W9HTVXHfyUj96KM7gp/KGAS87XaQ=="], + + "@fontsource-variable/jetbrains-mono": ["@fontsource-variable/jetbrains-mono@5.3.0", "", {}, "sha512-F32xpS2NsGYoQi2ADSkKTgpJj7ozajsGgDJ8woTnqjmIB+dxDIqImjl4pXZVEExu8UFZ2ndhmX18EBS/hdz3Lw=="], "@hono/node-server": ["@hono/node-server@1.19.15", "", { "peerDependencies": { "hono": "^4" } }, "sha512-Za2ai6TLdKjUvnur+eenO6nuYYipVAEhyCAdaV8IRvmU9kK8crOZUSYvIXn72E4f8fJqyAbpcJuTsYYmZp9Deg=="], @@ -227,8 +228,6 @@ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], - "@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="], - "@types/validate-npm-package-name": ["@types/validate-npm-package-name@4.0.2", "", {}, "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw=="], "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], @@ -675,8 +674,6 @@ "react-dom": ["react-dom@19.2.8", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.8" } }, "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ=="], - "react-icons": ["react-icons@5.7.0", "", { "peerDependencies": { "react": "*" } }, "sha512-LBLy340Rzqy6+/yVhZKT3B/QpP1BZaesGqasf09HPOBzRarcDIFH0WwXlXQfE7q7ipxK4MSiC5DIBWURCny6fw=="], - "react-stately": ["react-stately@3.48.0", "", { "dependencies": { "@internationalized/date": "^3.12.2", "@internationalized/number": "^3.6.7", "@internationalized/string": "^3.2.9", "@react-types/shared": "^3.36.0", "@swc/helpers": "^0.5.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-ImicSAG+lTotAe5izcs1fz49Zk48w7pDusqYg04WaPhCoej8BJ24soMu3iLXIrsi273s4P1gZrYGrqReMfgEEA=="], "recast": ["recast@0.23.12", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-dEWRjcINDu/F4l2dYx57ugBtD7HV9KXESyxhzw/MqWLeglJrsjJKqACPyUPg+6AF8mIgm+Zi0dZ3ACoIg+QtpA=="], @@ -701,7 +698,7 @@ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], @@ -729,6 +726,8 @@ "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -819,12 +818,6 @@ "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@dotenvx/dotenvx/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "@dotenvx/dotenvx/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], @@ -853,6 +846,8 @@ "conf/json-schema-typed": ["json-schema-typed@7.0.3", "", {}, "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A=="], + "conf/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "dot-prop/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], diff --git a/src/frontend/index.html b/src/frontend/index.html index 7f3c7b9..f640ea2 100644 --- a/src/frontend/index.html +++ b/src/frontend/index.html @@ -4,9 +4,12 @@ -