From e31e096dd4fefa901c166e35bfaa7adf95b54c97 Mon Sep 17 00:00:00 2001 From: Quickbeard Date: Mon, 10 Aug 2026 14:37:40 +0700 Subject: [PATCH] feat(ui): draw the codev C in Splash and Mark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The icon/wordmark rebrand only reached `Logo`, so upstream's square "o" still shipped in the last two glyphs that render it: the desktop boot splash, the app loading overlay, the connection-error screen, the two session side-panel watermarks and the v1 new-session view. Both glyphs now draw the codev C — the block art `█▀▀▀ / █ / ▀▀▀▀` on a 4x5 grid with a one-unit stroke, the same geometry the app icon and the `codev --mini` badge use — as one full-bleed path each. Upstream's second path, which shaded the lower half of the "o"'s enclosed counter, is dropped: the C is open on the right so there is no counter to shade, and the TUI badge is a flat outline for the same reason. The two split on color. `Splash` is brand-locked through a new `--logo-splash: #ee0033`, declared once with no dark-mode swap — red clears 4:1 against both the light and dark `background-base`, unlike the wordmark's navy half. `Mark` keeps `var(--icon-strong-base)` because two of its three call sites are `opacity-10` watermarks, where brand red reads as a pink wash rather than a neutral texture. The static `opacity-50` on the two splash call sites is left as is: this fork's `animate-pulse` is `pulse-opacity` (0.4 -> 1 -> 0.4), which overrides the declared opacity for the whole animation, so removing it would be a no-op in two upstream files. Co-Authored-By: Claude Opus 5 (1M context) --- DIVERGENCES.md | 2 +- packages/ui/src/components/logo.css | 11 +++++++++++ packages/ui/src/components/logo.tsx | 19 +++++++++++++++---- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/DIVERGENCES.md b/DIVERGENCES.md index 9594066b33..2ee0e4a0cb 100644 --- a/DIVERGENCES.md +++ b/DIVERGENCES.md @@ -92,7 +92,7 @@ from the squash message first, or use a plain merge. | `packages/opencode/script/postinstall.mjs` | `base` prefix `opencode-` → `codev-code-`; source/target binary names `opencode`/`opencode.exe` → `codev`/`codev.exe` (matches build.ts's `bin/codev` and publish.ts's `bin/codev.exe` stub); temp-dir prefix and failure message rebranded | Install-time platform-binary fetch must match the published package and binary names. | Keep our prefix and binary names. | | `packages/tui/src/logo.ts` | Pixel glyphs "open"+"code" → "co"+"dev"; added a `brand` export (`navy` `#19224c` / `red` `#ee0033`, the landing page's `--color-brand-navy`/`--color-brand-red`), a `wordmarkHalves` export (each row's "co" and "dev" halves with the shadow marks substituted to glyphs, so each half can take its own brand color), the composed `wordmark` (plain lines, built from `wordmarkHalves`) and `ansiWordmark` (bold, no shadow: "co" in the terminal's default foreground, "dev" in brand red truecolor) exports for CLI banners; added a `badge` export (the "c" of the wordmark — `logo.left` rows 1-3 sliced to the first glyph, with the `_` shadow-fill marks stripped to spaces so it renders as a flat outline) for the `--mini` splashes | Branded wordmark art; `ansiWordmark` feeds the CLI help banner and session epilogue. | Keep our glyphs + exports; take upstream's surrounding changes. | | `packages/tui/src/component/logo.tsx` | Renders the lowercase codev wordmark from `wordmarkHalves` — one bold `` per half, no per-char shadow cells — with "co" in `brand.navy` on light / `theme.text` on dark and "dev" in `brand.red`, instead of upstream's two-tone "open"+"code" | Banner is pixel-identical to the landing page wordmark (`codev-landing-page` `app/components/PixelWordmark.tsx`: `text-brand-navy dark:text-foreground` + `text-brand-red`), so the marketing site and the TUI read as one brand. Deliberately fixed brand colors rather than the theme's `secondary`, and no drop shadow — the landing wordmark has neither. | Keep our version wholesale. If upstream restructures the component, re-apply the two-half brand coloring rather than reverting to a theme color. | -| `packages/ui/src/components/logo.tsx`, `packages/ui/src/components/logo.css` | `Logo` renders the lowercase "codev" wordmark instead of upstream's "opencode": the `wordmarkHalves` pixel glyphs of `packages/tui/src/logo.ts` resolved to a 24x6 grid at one unit per pixel (viewBox `0 0 24 6`, was `0 0 234 42`), as two ``s — `data-slot="logo-wordmark-co"` and `…-dev` — with no drop-shadow paths. Colors come from two custom properties defined in logo.css on `[data-component="logo-wordmark"]`: `--logo-wordmark-dev` is always brand red `#ee0033`, `--logo-wordmark-co` is brand navy `#19224c` on light and `var(--icon-strong-base)` on dark. The dark swap is declared three times — under `prefers-color-scheme: dark` for surfaces that never stamp a theme, then under both `[data-color-scheme="light"]` and `[data-color-scheme="dark"]` so the app's explicit choice (`packages/ui/src/theme/context.tsx` sets it on ``) beats the OS preference in both directions. Brand hexes are literals, not theme tokens — same reasoning as the TUI component row. `Mark` and `Splash` (the square "o") are untouched. | The web/desktop banner is the same art the TUI home banner and the landing page wordmark draw, so every surface reads as one brand. | Keep our version wholesale. If upstream restructures the component, re-apply the two-half brand coloring rather than reverting to `--icon-*` tokens. | +| `packages/ui/src/components/logo.tsx`, `packages/ui/src/components/logo.css` | `Logo` renders the lowercase "codev" wordmark instead of upstream's "opencode": the `wordmarkHalves` pixel glyphs of `packages/tui/src/logo.ts` resolved to a 24x6 grid at one unit per pixel (viewBox `0 0 24 6`, was `0 0 234 42`), as two ``s — `data-slot="logo-wordmark-co"` and `…-dev` — with no drop-shadow paths. Colors come from two custom properties defined in logo.css on `[data-component="logo-wordmark"]`: `--logo-wordmark-dev` is always brand red `#ee0033`, `--logo-wordmark-co` is brand navy `#19224c` on light and `var(--icon-strong-base)` on dark. The dark swap is declared three times — under `prefers-color-scheme: dark` for surfaces that never stamp a theme, then under both `[data-color-scheme="light"]` and `[data-color-scheme="dark"]` so the app's explicit choice (`packages/ui/src/theme/context.tsx` sets it on ``) beats the OS preference in both directions. Brand hexes are literals, not theme tokens — same reasoning as the TUI component row. `Mark` and `Splash` likewise drop upstream's square "o" for the codev "C": the block art `█▀▀▀ / █ / ▀▀▀▀` on a 4x5 grid with a one-unit stroke — the same geometry `packages/desktop/icons/icon.svg` and the `codev --mini` badge (`badge` in `packages/tui/src/logo.ts`) draw — as one full-bleed `` each, `data-slot="logo-mark-c"` at viewBox `0 0 16 20` and `logo-splash-c` at `0 0 80 100`. Upstream's second path on each glyph, which shaded the lower half of the "o"'s enclosed counter in `--icon-weak-base` / `--icon-base`, is dropped: the C is open on the right so there is no counter to shade, and the TUI badge is a flat outline for the same reason. The two split on color. `Splash` is brand-locked through `--logo-splash: #ee0033`, declared once on `[data-component="logo-splash"]` with no dark-mode swap — red clears 4:1 against both the light and dark `background-base`, unlike the wordmark's navy half. `Mark` keeps `var(--icon-strong-base)` because two of its three call sites are `opacity-10` watermarks in the session side panel, where brand red reads as a pink wash instead of a neutral texture. | The web/desktop banner is the same art the TUI home banner and the landing page wordmark draw, so every surface reads as one brand. Same for the marks: the desktop boot splash, the app icon, the landing page icon and the `--mini` badge are one glyph in one red, so the splash should not be the only surface still drawing upstream's "o" in theme grey. | Keep our version wholesale. If upstream restructures the component, re-apply the two-half brand coloring rather than reverting to `--icon-*` tokens, and re-apply the C rather than taking back the "o". Keep `Splash` brand-locked and `Mark` tokenized — do not "unify" them, the split is load-bearing for the `opacity-10` watermarks. | | `packages/ui/src/v2/components/wordmark-v2.tsx` (+ fork-only `wordmark-v2.css`) | `WordmarkV2` — the watermark behind the v2 new-session composer (`packages/app/src/components/session/session-new-design-view.tsx`) — draws the codev wordmark from the same 24x6 pixel grid as `Logo` instead of upstream's 720x129 "opencode", as two ``s (`data-slot="wordmark-v2-co"` / `…-dev`). Upstream's watermark treatment is kept verbatim: the `0.6` outer opacity and the alpha mask whose gradient fades the mark out over its bottom half (converted to the new viewBox: gradient `y1` 68/129 → 3.163/6). "co" keeps `fill="currentColor"` so it still follows the caller's `text-*` class; "dev" takes brand red `#ee0033`. Per-half opacities live in the new `wordmark-v2.css`, following the one-CSS-file-per-v2-component convention: `co` is `0.112` (upstream's own `0.16 × 0.7` nesting, flattened), `dev` is boosted to `0.224` on light and `0.336` on dark via `--wordmark-v2-dev-opacity`, declared under `prefers-color-scheme` and both `[data-color-scheme]` values like components/logo.css. The boost is deliberate and measured: at upstream's weight a saturated red composites to within a few levels of the grey "co" half against the dark background and the two-tone disappears entirely, while the same value already reads pink against the light one. | The component is currently **not rendered** — the new-session view drops it (see the row below) — but it stays rebranded and exported so reinstating the watermark does not bring the upstream mark back with it. | Keep our version wholesale, including the per-theme `dev` opacity. If upstream retunes the watermark opacities, re-derive the `dev` boost from the new base rather than adopting a single flat value. | | `packages/app/src/components/session/session-new-design-view.tsx`, `packages/app/src/pages/new-session.tsx` | Drops the `WordmarkV2` watermark from the v2 new-session screen and centres the composer. Upstream absolutely positions the content block at `top-[25.375%]` to leave room for the wordmark above it; with the mark gone that offset just parks the composer high in an empty pane, so the outer element becomes `flex items-center justify-center` over `size-full` (carrying the `px-6` inset across) and the `mt-8` spacer under the wordmark goes away. The pane also takes the same raised card every session sits on: `bg-v2-background-bg-deep` → `bg-v2-background-bg-base` in the view, and `new-session.tsx`'s `rounded-[10px]` wrapper gains `bg-v2-background-bg-base shadow-[var(--v2-elevation-raised)]` — the exact pair `SessionPanelFrame` (`pages/session.tsx`) applies with `newLayout raised`. Verified equal at runtime: same background, same eight-layer shadow, same 10px radius. | The wordmark reads as clutter on the desktop new-session screen; without it the pane should be balanced, not top-weighted. And with the sidebar always on screen, upstream's `bg-deep` made the draft screen read as an extension of the window chrome while every session floated on a card — the two screens have to match. | Keep our centred layout and the card. If upstream restyles this view, re-apply the drop + centring rather than restoring `top-[25.375%]`, and re-check the background against whatever `SessionPanelFrame` then uses rather than hardcoding `bg-base`. Reinstating the watermark means restoring the offset too, or it will sit centred with the composer. | | `packages/app/src/pages/home.tsx`, `packages/app/src/pages/error.tsx`, `packages/enterprise/src/routes/share/[shareID].tsx` | `Logo` width utilities retuned for the codev wordmark's 4:1 box (upstream's is 5.57:1): home `md:w-xl` → `md:w-104`, error `w-58.5` → `w-42`, share (both call sites) `w-58.5` → `w-42` | Each value is the width at which the new wordmark renders at exactly the height the upstream one did, so no surrounding layout shifts. | Keep our widths; take upstream's surrounding changes. Recompute rather than restore if upstream changes the size. | diff --git a/packages/ui/src/components/logo.css b/packages/ui/src/components/logo.css index d948f34e25..d1ce78e480 100644 --- a/packages/ui/src/components/logo.css +++ b/packages/ui/src/components/logo.css @@ -3,6 +3,17 @@ aspect-ratio: 4/5; } +/* Fork: the splash "C" is brand-locked, matching the `codev --mini` badge + (BRAND_MARK in packages/opencode/src/cli/cmd/run/theme.ts), the landing page + icon and the desktop app icon — the same glyph in the same red on every + surface. Unlike the wordmark's navy half this needs no dark-mode swap: red + clears 4:1 against both the light and dark background-base, so one + unconditional declaration covers every theme. `Mark` deliberately stays on + --icon-strong-base; see the note on the component. */ +[data-component="logo-splash"] { + --logo-splash: #ee0033; +} + /* Fork: the codev wordmark's two halves. Literal hex rather than theme tokens — these are the landing page's brand colors (codev-landing-page app/globals.css --color-brand-navy / --color-brand-red, mirrored in packages/tui/src/logo.ts diff --git a/packages/ui/src/components/logo.tsx b/packages/ui/src/components/logo.tsx index 0fe06f6f97..e5135e7afd 100644 --- a/packages/ui/src/components/logo.tsx +++ b/packages/ui/src/components/logo.tsx @@ -1,5 +1,16 @@ import { type ComponentProps } from "solid-js" +// Fork: the codev "C" instead of upstream's square "o" — the block art +// `█▀▀▀ / █ / ▀▀▀▀` on a 4x5 grid with a one-unit stroke, the same geometry the +// app icon (packages/desktop/icons/icon.svg) and the `codev --mini` badge draw. +// The C has no enclosed counter, so upstream's second path — which shaded the +// lower half of the "o"'s hole — has nowhere to live and is dropped, matching +// the TUI badge's flat outline (packages/tui/src/logo.ts `badge`). +// +// Stays on --icon-strong-base rather than the brand red `Splash` uses: two of +// this component's three call sites are opacity-10 watermarks in the session +// side panel, where brand red renders as a pink wash instead of a neutral +// texture. export const Mark = (props: { class?: string }) => { return ( { fill="none" xmlns="http://www.w3.org/2000/svg" > - - + ) } +// Fork: the same codev "C" as `Mark`, at 80x100 (unit 20), brand-locked rather +// than tokenized — see --logo-splash in logo.css. export const Splash = (props: Pick, "ref" | "class">) => { return ( , "ref" | "class">) => { fill="none" xmlns="http://www.w3.org/2000/svg" > - - + ) }