From d8b1935c4e7875ea1e414ae94a6ab3a9c761c3b9 Mon Sep 17 00:00:00 2001 From: pallaoro Date: Wed, 9 Sep 2026 11:58:07 +0200 Subject: [PATCH 1/7] Apply the apps design system across the whole editor The token layer had drifted from the current design system: a slate-gray palette where the neutrals are meant to be warm, coral as the primary button where the primary is ink, 6/8/12px corners where the scale is 8/12/16/24, and no accent, info or category families at all. Everything downstream inherited that, so this replaces the tokens with the generated values and then follows them through both routes. - Tokens: the full generated palette (neutrals, accent, four statuses, four track categories) in light and dark, the type scale as `--text-*` so a component names a step instead of a pixel size, and the three elevation recipes as utilities. The edge is an inset ring everywhere, never a painted border; in dark mode the drops disappear and the ring is the whole treatment. - One ink action per screen. Coral goes back to being the accent, which now appears only on the app icon and the focus ring. Auto-cut, Clean up clip and New edit become secondary; Export and New video keep the solid. - Both timelines share one category palette, so a video clip is the same hue in the composition timeline and the footage timeline. Clips are a tint fill with a solid bar at the left edge rather than a solid block: a timeline is mostly one kind of clip, and a wall of the solid role reads as a paint chart. - window.confirm and alert are gone. Deleting a composition or a library asset opens a dialog that names the object and says what is lost; a failed render reports in place. An agent driving the browser could not answer a native dialog at all. - Uppercase tracked labels are gone from the inspectors. That style is the micro label above a KPI number; section titles and field labels are sentence case in `label`. - Empty states say what the thing is and offer the way forward, and sit on the pane rather than inside a card. Loading renders the shape of the answer. - Phones and tablets get one pane at a time. Below lg the footage editor shows Library, Edit or Options, chosen from a second toolbar row; the four-region grid stays a desktop layout. Inputs hold 16px so iOS does not zoom. - The starter composition moves to its own module: those colours are pixels inside the user's video, not app chrome, so the design tokens do not apply and the lint exempts that one file. - Inter is actually loaded now, and the app icon carries the accent hue. scripts/apps-design-lint.py goes from 33 findings to clean. Typecheck and build pass, and both routes plus the delete dialog were driven in a browser at 390, 1024 and 1920. --- .design-lint-ignore | 5 + icon.svg | 11 +- index.html | 13 +- src/client/app.tsx | 373 +++++++++++++++++++++++------------------ src/client/edit.tsx | 376 +++++++++++++++++++++++++++++------------- src/client/starter.ts | 34 ++++ src/client/styles.css | 320 +++++++++++++++++++++++++++++------ src/client/ui.tsx | 182 ++++++++++++++++++++ 8 files changed, 975 insertions(+), 339 deletions(-) create mode 100644 .design-lint-ignore create mode 100644 src/client/starter.ts create mode 100644 src/client/ui.tsx diff --git a/.design-lint-ignore b/.design-lint-ignore new file mode 100644 index 0000000..0615455 --- /dev/null +++ b/.design-lint-ignore @@ -0,0 +1,5 @@ +# Video DOCUMENT content, not app chrome. The colours and sizes in here are +# pixels inside the user's composition, so they are literal by definition and +# the app's design tokens do not apply — the same exemption DESIGN.md gives a +# faithful rendering of someone else's UI. +src/client/starter.ts diff --git a/icon.svg b/icon.svg index 769f447..0133d0b 100644 --- a/icon.svg +++ b/icon.svg @@ -1,7 +1,10 @@ + - + - - - + + + diff --git a/index.html b/index.html index 962f8ba..ad9df3c 100644 --- a/index.html +++ b/index.html @@ -2,10 +2,19 @@ - + + OpenVideo + + + + + - +
diff --git a/src/client/app.tsx b/src/client/app.tsx index 2a37a52..34315b3 100644 --- a/src/client/app.tsx +++ b/src/client/app.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { EditProjectsSection, EditRoute } from "./edit"; +import { STARTER_HTML } from "./starter"; import { Group, Panel, Separator, useDefaultLayout } from "react-resizable-panels"; import { ArrowLeft, @@ -19,6 +20,19 @@ import { AlertCircle, X, } from "lucide-react"; +import { + Badge, + ConfirmDialog, + EmptyState, + btnDanger, + btnGhost, + btnIcon, + btnPrimary, + btnSecondary, + card, + chip, + stretch, +} from "./ui"; // ── types ──────────────────────────────────────────────────────────── @@ -74,35 +88,6 @@ const api = { // ── app ────────────────────────────────────────────────────────────── -// Starter composition for "New" — three clips on three separate tracks with a -// staggered GSAP timeline, so the timeline view shows real track registration. -// Lives here as a string (not a DB seed) so it goes in via the normal -// parameterized insert. -const STARTER_HTML = `
-
- Product Launch -
-
- Your Title Here -
-
- A subtitle that fades in -
- - -
`; - type Tab = "compose" | "timeline" | "media" | "renders"; // Minimal history-based router: `/` = gallery, `/` = editor for that id. @@ -128,20 +113,20 @@ export function App() { const editId = id.startsWith("edits/") ? id.slice(6) : id === "edits" ? "" : null; return ( -
+
+ {/* Brand row: the app icon is the identity object, and the accent hue + lives here (plus count badges and the focus ring) and nowhere else. */}
- {id ? ( - - ) : ( - )} - OpenVideo - edit & render video + + + + OpenVideo + edit & render video
{editId ? ( @@ -189,32 +174,51 @@ function Gallery({ navigate }: { navigate: (to: string) => void }) { return (
-
-

Your videos

-
{comps === null ? ( -
Loading…
- ) : comps.length === 0 ? ( -
-