diff --git a/.fork/customizations.yaml b/.fork/customizations.yaml index 2bf7078900c..2f3d927f9e0 100644 --- a/.fork/customizations.yaml +++ b/.fork/customizations.yaml @@ -615,7 +615,12 @@ the latch survive thread switches, and "only an empty prompt turns it off" is a rule about one composing session, not the component's lifetime. Which controls sit where is the whole point. Inside the box: the model - pill, the effort pill, and the send/stop button. Everything else is on the + pill, the effort pill, and the send/stop button. In dark mode a send + button without stage-channel art — any stage label that is not Dev/Nightly + — is flat pure white with a black icon + (data-fork-composer-send-tone="flat"); Dev and Nightly keep the + stage-channel fill, and light builds keep upstream's fill. Everything else + is on the control row below it — runtime mode ("Auto"), interaction mode ("Build"), the plan-sidebar toggle, the context meter, the preparing-worktree line, the no-provider badge, and, at the row's right end, the worktree/branch @@ -711,7 +716,9 @@ # sibling of the composer. - apps/web/src/components/ChatView.tsx # data-fork-composer-action on the send and stop buttons; the whole 24px - # square restyle hangs off it. + # square restyle hangs off it. Send also carries + # data-fork-composer-send-tone ("channel" with stage art, "flat" + # otherwise) for the dark-mode white/black fill. - apps/web/src/components/chat/ComposerPrimaryActions.tsx # The glass-shell pseudo-elements and .chat-composer-context-strip this # customization switches off. An upstream rework of that paint would leave diff --git a/apps/web/src/__fork_guards__/forkComposerShell.test.ts b/apps/web/src/__fork_guards__/forkComposerShell.test.ts index 540593c7396..5a73ce20bda 100644 --- a/apps/web/src/__fork_guards__/forkComposerShell.test.ts +++ b/apps/web/src/__fork_guards__/forkComposerShell.test.ts @@ -182,8 +182,21 @@ describe("fork guard: fork-composer-shell", () => { expect(theme).toMatch(/\[data-testid="composer-editor"\][\s\S]{0,160}min-height:\s*0/u); }); - it("squares the send and stop buttons and reddens stop", () => { + it("squares the send and stop buttons, flattens release send, and reddens stop", () => { expect(theme).toMatch(/\[data-fork-composer-action\]\s*\{[\s\S]{0,200}border-radius:\s*6px/u); + // Flat (no stage art) is pure white / black icon in dark mode only; light + // and unmarked builds keep upstream's fill, so the rule must stay anchored + // on the dark-scoped marker prefix. Dev/Nightly keep tone=channel and the + // stage art; do not collapse them. + expect(primaryActions).toMatch( + /data-fork-composer-send-tone=\{\s*stageBackdropVariant\s*\?\s*"channel"\s*:\s*"flat"\s*\}/u, + ); + expect(theme).toMatch( + /:root\[data-fork="noahhendrickson-t3code"\]\.dark\s+\[data-fork-composer-action="send"\]\[data-fork-composer-send-tone="flat"\][\s\S]{0,200}background:\s*#ffffff/u, + ); + expect(theme).toMatch( + /:root\[data-fork="noahhendrickson-t3code"\]\.dark\s+\[data-fork-composer-action="send"\]\[data-fork-composer-send-tone="flat"\][\s\S]{0,200}color:\s*#000000/u, + ); expect(theme).toMatch( /\[data-fork-composer-action="stop"\][\s\S]{0,120}background:\s*#ea3150/u, ); diff --git a/apps/web/src/components/chat/ComposerPrimaryActions.tsx b/apps/web/src/components/chat/ComposerPrimaryActions.tsx index afeab513f60..c08098ba0a2 100644 --- a/apps/web/src/components/chat/ComposerPrimaryActions.tsx +++ b/apps/web/src/components/chat/ComposerPrimaryActions.tsx @@ -203,6 +203,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({ type="submit" /* fork:begin fork-composer-shell — see .fork/customizations.yaml#fork-composer-shell */ data-fork-composer-action="send" + data-fork-composer-send-tone={stageBackdropVariant ? "channel" : "flat"} /* fork:end fork-composer-shell */ className={cn( "relative isolate flex h-9 w-9 items-center justify-center overflow-hidden rounded-full text-primary-foreground shadow-xs transition-all duration-150 enabled:cursor-pointer enabled:inset-shadow-[0_1px_--theme(--color-white/16%)] hover:scale-105 active:inset-shadow-[0_1px_--theme(--color-black/8%)] active:shadow-none disabled:pointer-events-none disabled:opacity-30 disabled:shadow-none disabled:hover:scale-100 sm:h-8 sm:w-8", diff --git a/apps/web/src/theme.custom.css b/apps/web/src/theme.custom.css index 56f52cb4f6a..17e266087ff 100644 --- a/apps/web/src/theme.custom.css +++ b/apps/web/src/theme.custom.css @@ -434,6 +434,19 @@ border-radius: 6px; } +/* Flat send (tone="flat"): in dark mode, a send button without stage-channel + art — any stage label that is not Dev/Nightly — is flat pure white with a + black icon. Dev/Nightly keep the stage-channel fill (tone="channel"). + Unlayered, so this beats upstream's Tailwind fill; the fenced attribute + survives upstream className rewrites. Unmarked or light builds never match + and fall through to upstream's primary fill. */ +:root[data-fork="noahhendrickson-t3code"].dark + [data-fork-composer-action="send"][data-fork-composer-send-tone="flat"] { + background: #ffffff; + color: #000000; + box-shadow: none; +} + :root[data-fork="noahhendrickson-t3code"].dark [data-fork-composer-action="stop"] { background: #ea3150; }