From 07d804588e4a01fd7bb0e0ae1b5c86a391ae1779 Mon Sep 17 00:00:00 2001 From: Andrew <43323844+snowdamiz@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:17:03 -0400 Subject: [PATCH] =?UTF-8?q?feat(web):=20Dark=20mode=20contrast=20=E2=80=94?= =?UTF-8?q?=20raise=20token=20floor=20and=20flatten=20opacity=20tier=20sys?= =?UTF-8?q?tem=20(#2734)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Raised four dark-mode tokens, converted five hardcoded oklch valu… - "web/app/globals.css" - "web/components/gsd/code-editor.tsx" GSD-Task: S01/T01 * feat: Applied border-border 2-tier sweep across 21 component files: /20… - "web/components/gsd/command-surface.tsx" - "web/components/gsd/remaining-command-panels.tsx" - "web/components/gsd/chat-mode.tsx" - "web/components/gsd/settings-panels.tsx" - "web/components/gsd/diagnostics-panels.tsx" - "web/components/gsd/onboarding/step-authenticate.tsx" - "web/components/gsd/knowledge-captures-panel.tsx" - "web/components/gsd/projects-view.tsx" GSD-Task: S02/T01 * feat: Swept text-foreground/muted-foreground/sidebar-foreground opacity… - "web/components/gsd/command-surface.tsx" - "web/components/gsd/remaining-command-panels.tsx" - "web/components/gsd/chat-mode.tsx" - "web/components/gsd/settings-panels.tsx" - "web/components/gsd/diagnostics-panels.tsx" - "web/components/gsd/knowledge-captures-panel.tsx" - "web/components/gsd/projects-view.tsx" - "web/components/gsd/visualizer-view.tsx" GSD-Task: S02/T02 * feat: Applied background opacity mapping tables across all component fi… - "web/components/gsd/remaining-command-panels.tsx" - "web/components/gsd/command-surface.tsx" - "web/components/gsd/visualizer-view.tsx" - "web/components/gsd/chat-mode.tsx" - "web/components/gsd/settings-panels.tsx" - "web/components/gsd/diagnostics-panels.tsx" - "web/components/gsd/onboarding/step-authenticate.tsx" - "web/components/gsd/knowledge-captures-panel.tsx" GSD-Task: S02/T03 --- web/app/globals.css | 20 +-- web/components/gsd/app-shell.tsx | 4 +- web/components/gsd/chat-mode.tsx | 98 ++++++------- web/components/gsd/code-editor.tsx | 2 +- web/components/gsd/command-surface.tsx | 100 +++++++------- web/components/gsd/dashboard.tsx | 8 +- web/components/gsd/diagnostics-panels.tsx | 46 +++---- web/components/gsd/file-content-viewer.tsx | 10 +- web/components/gsd/focused-panel.tsx | 6 +- .../gsd/knowledge-captures-panel.tsx | 30 ++-- web/components/gsd/main-session-terminal.tsx | 2 +- web/components/gsd/onboarding-gate.tsx | 2 +- .../gsd/onboarding/step-authenticate.tsx | 28 ++-- .../gsd/onboarding/step-dev-root.tsx | 12 +- web/components/gsd/onboarding/step-mode.tsx | 6 +- .../gsd/onboarding/step-optional.tsx | 10 +- .../gsd/onboarding/step-project.tsx | 24 ++-- .../gsd/onboarding/step-provider.tsx | 10 +- web/components/gsd/onboarding/step-ready.tsx | 4 +- web/components/gsd/onboarding/step-remote.tsx | 14 +- .../gsd/onboarding/step-welcome.tsx | 2 +- .../gsd/onboarding/wizard-stepper.tsx | 4 +- web/components/gsd/project-welcome.tsx | 2 +- web/components/gsd/projects-view.tsx | 44 +++--- .../gsd/remaining-command-panels.tsx | 130 +++++++++--------- web/components/gsd/roadmap.tsx | 4 +- web/components/gsd/settings-panels.tsx | 68 ++++----- web/components/gsd/shell-terminal.tsx | 6 +- web/components/gsd/sidebar.tsx | 8 +- web/components/gsd/terminal.tsx | 16 +-- web/components/gsd/visualizer-view.tsx | 58 ++++---- web/components/ui/kbd.tsx | 2 +- web/components/ui/sidebar.tsx | 2 +- web/components/ui/toast.tsx | 2 +- 34 files changed, 392 insertions(+), 392 deletions(-) diff --git a/web/app/globals.css b/web/app/globals.css index 085e0fa3e..48dac9159 100644 --- a/web/app/globals.css +++ b/web/app/globals.css @@ -60,12 +60,12 @@ --secondary: oklch(0.18 0 0); --secondary-foreground: oklch(0.85 0 0); --muted: oklch(0.15 0 0); - --muted-foreground: oklch(0.55 0 0); + --muted-foreground: oklch(0.60 0 0); --accent: oklch(0.2 0 0); --accent-foreground: oklch(0.9 0 0); --destructive: oklch(0.5 0.15 25); --destructive-foreground: oklch(0.95 0 0); - --border: oklch(0.22 0 0); + --border: oklch(0.28 0 0); --input: oklch(0.15 0 0); --ring: oklch(0.4 0 0); --chart-1: oklch(0.7 0 0); @@ -79,7 +79,7 @@ --sidebar-primary-foreground: oklch(0.09 0 0); --sidebar-accent: oklch(0.15 0 0); --sidebar-accent-foreground: oklch(0.9 0 0); - --sidebar-border: oklch(0.18 0 0); + --sidebar-border: oklch(0.24 0 0); --sidebar-ring: oklch(0.35 0 0); /* Custom tokens */ @@ -88,7 +88,7 @@ --info: oklch(0.6 0.1 250); --terminal: oklch(0.06 0 0); --terminal-foreground: oklch(0.75 0 0); - --code-line-number: oklch(0.35 0 0); + --code-line-number: oklch(0.42 0 0); } @theme inline { @@ -210,7 +210,7 @@ width: 3.5ch; margin-right: 1.5ch; text-align: right; - color: oklch(0.35 0 0); + color: var(--code-line-number); user-select: none; } @@ -228,7 +228,7 @@ margin-top: 0; margin-bottom: 1rem; padding-bottom: 0.5rem; - border-bottom: 1px solid oklch(0.22 0 0); + border-bottom: 1px solid var(--border); } .markdown-body h2 { @@ -237,7 +237,7 @@ margin-top: 1.75rem; margin-bottom: 0.75rem; padding-bottom: 0.35rem; - border-bottom: 1px solid oklch(0.22 0 0); + border-bottom: 1px solid var(--border); } .markdown-body h3 { @@ -289,14 +289,14 @@ .markdown-body blockquote { margin: 0.75rem 0; padding: 0.25rem 1rem; - border-left: 3px solid oklch(0.3 0 0); + border-left: 3px solid oklch(0.38 0 0); color: oklch(0.6 0 0); } .markdown-body hr { margin: 1.5rem 0; border: none; - border-top: 1px solid oklch(0.22 0 0); + border-top: 1px solid var(--border); } .markdown-body strong { @@ -310,7 +310,7 @@ .markdown-body del { text-decoration: line-through; - color: oklch(0.5 0 0); + color: oklch(0.55 0 0); } /* Task list checkboxes */ diff --git a/web/components/gsd/app-shell.tsx b/web/components/gsd/app-shell.tsx index cfe8440d9..3b0da7b49 100644 --- a/web/components/gsd/app-shell.tsx +++ b/web/components/gsd/app-shell.tsx @@ -267,7 +267,7 @@ function WorkspaceChrome() { beta - / + / {isConnecting ? ( @@ -427,7 +427,7 @@ function WorkspaceChrome() { >
Terminal - + {isTerminalExpanded ? "▼" : "▲"}
diff --git a/web/components/gsd/chat-mode.tsx b/web/components/gsd/chat-mode.tsx index 53c729f6b..a715be651 100644 --- a/web/components/gsd/chat-mode.tsx +++ b/web/components/gsd/chat-mode.tsx @@ -337,7 +337,7 @@ function MarkdownContent({ content }: { content: string }) { }) return (
) @@ -348,7 +348,7 @@ function MarkdownContent({ content }: { content: string }) { if (isInline) { return ( {children} @@ -357,7 +357,7 @@ function MarkdownContent({ content }: { content: string }) { } return ( -
+              
                 {children}
               
) @@ -374,7 +374,7 @@ function MarkdownContent({ content }: { content: string }) { }, th({ children }: { children?: React.ReactNode }) { return ( - + {children} ) @@ -424,7 +424,7 @@ function MarkdownContent({ content }: { content: string }) { }, img({ alt, src }: { alt?: string; src?: string }) { return ( - + 🖼 {alt || src || "image"} ) @@ -559,7 +559,7 @@ function TuiSelectPrompt({ data-testid="tui-select-prompt" tabIndex={0} onKeyDown={handleKeyDown} - className="mt-2 rounded-xl border border-border/60 bg-background/60 p-1.5 shadow-sm outline-none focus-visible:ring-1 focus-visible:ring-border" + className="mt-2 rounded-xl border border-border bg-background p-1.5 shadow-sm outline-none focus-visible:ring-1 focus-visible:ring-border" aria-label={`Select: ${prompt.label}`} role="listbox" aria-activedescendant={`tui-select-option-${localIndex}`} @@ -584,7 +584,7 @@ function TuiSelectPrompt({ "flex w-full items-start gap-2 rounded-lg px-3 py-1.5 text-left text-sm transition-colors", isSelected ? "bg-primary/15 text-primary font-medium" - : "text-foreground hover:bg-muted/60", + : "text-foreground hover:bg-muted", )} > @@ -671,7 +671,7 @@ function TuiTextPrompt({ return (
{prompt.label && (

@@ -695,7 +695,7 @@ function TuiTextPrompt({ "flex h-8 items-center justify-center rounded-lg px-3 text-xs font-medium transition-all", value.trim() ? "bg-primary text-primary-foreground hover:bg-primary/90 active:scale-95 shadow-sm" - : "bg-muted text-muted-foreground/40 cursor-not-allowed", + : "bg-muted text-muted-foreground cursor-not-allowed", )} > Submit @@ -771,7 +771,7 @@ function TuiPasswordPrompt({ return (

{prompt.label && (

@@ -796,7 +796,7 @@ function TuiPasswordPrompt({ onClick={() => setShowPassword((s) => !s)} tabIndex={-1} aria-label={showPassword ? "Hide input" : "Show input"} - className="absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground/50 hover:text-muted-foreground transition-colors" + className="absolute right-2.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-muted-foreground transition-colors" > {showPassword ? ( @@ -812,13 +812,13 @@ function TuiPasswordPrompt({ "flex h-8 items-center justify-center rounded-lg px-3 text-xs font-medium transition-all", value ? "bg-primary text-primary-foreground hover:bg-primary/90 active:scale-95 shadow-sm" - : "bg-muted text-muted-foreground/40 cursor-not-allowed", + : "bg-muted text-muted-foreground cursor-not-allowed", )} > Submit

-

+

Value is transmitted securely and not stored in chat history.

@@ -910,7 +910,7 @@ function InlineThinking({ content, isStreaming }: { content: string; isStreaming onClick={() => setExpanded((e) => !e)} className={cn( "group w-full rounded-xl border px-3.5 py-2.5 text-left transition-all", - "border-border/40 bg-muted/20 hover:bg-muted/30", + "border-border/50 bg-muted/50 hover:bg-muted/50", )} > {/* Header row */} @@ -922,21 +922,21 @@ function InlineThinking({ content, isStreaming }: { content: string; isStreaming
) : ( - 💭 + 💭 )} - + {isStreaming ? "Thinking…" : "Thought process"} {hasMore && !expanded && ( - + {lines.length} lines )} {expanded - ? - : + ? + : }
@@ -945,7 +945,7 @@ function InlineThinking({ content, isStreaming }: { content: string; isStreaming {!expanded && (
{previewLines.map((line, i) => ( -

+

{line}

))} @@ -957,7 +957,7 @@ function InlineThinking({ content, isStreaming }: { content: string; isStreaming {expanded && (
{content} {isStreaming && } @@ -991,7 +991,7 @@ function ChatBubble({ if (message.role === "system") { return (
- + {message.content}
@@ -1047,7 +1047,7 @@ function ChatBubble({
-
+
{/* Minimal waiting indicator — shown when streaming starts but no content yet */} {isThinking && !message.content && (
@@ -1055,7 +1055,7 @@ function ChatBubble({ - + Thinking…
@@ -1326,7 +1326,7 @@ function ChatInputBar({ const overflowGroups = useMemo(() => groupByCategory(OVERFLOW_ACTIONS), []) return ( -
+
@@ -1367,7 +1367,7 @@ function ChatInputBar({
))} {imageNotice && ( - {imageNotice} + {imageNotice} )}
)} @@ -1386,12 +1386,12 @@ function ChatInputBar({ ? "Message…" : "Connecting…" } - className="min-h-[40px] flex-1 resize-none bg-transparent px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground/50 focus:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground" + className="min-h-[40px] flex-1 resize-none bg-transparent px-3 py-2.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground" style={{ height: "40px", maxHeight: "160px", overflowY: "auto" }} />
{!connected && ( - + Disconnected )} @@ -1403,7 +1403,7 @@ function ChatInputBar({ "flex h-7 w-7 items-center justify-center rounded-lg transition-all", hasContent && connected ? "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 active:scale-95" - : "bg-muted text-muted-foreground/40 cursor-not-allowed", + : "bg-muted text-muted-foreground cursor-not-allowed", )} > @@ -1476,7 +1476,7 @@ function ChatInputBar({ {overflowGroups.map((group, gi) => (
{gi > 0 &&
} -

+

{group.label}

{group.items.map((action) => { @@ -1542,9 +1542,9 @@ function PlaceholderState({
{showSpinner ? ( - + ) : ( - + )}
@@ -1608,7 +1608,7 @@ function InlineUiRequest({ request }: { request: PendingUiRequest }) {
-
+
{request.title && (

{request.title}

)} @@ -1675,7 +1675,7 @@ function InlineSelect({ disabled={disabled} className={cn( "flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-left text-sm transition-colors", - checked ? "bg-primary/15 text-primary font-medium" : "text-foreground hover:bg-muted/60", + checked ? "bg-primary/15 text-primary font-medium" : "text-foreground hover:bg-muted", )} > @@ -1693,7 +1693,7 @@ function InlineSelect({ disabled={disabled} className={cn( "flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-left text-sm transition-colors", - selected ? "bg-primary/15 text-primary font-medium" : "text-foreground hover:bg-muted/60", + selected ? "bg-primary/15 text-primary font-medium" : "text-foreground hover:bg-muted", )} > @@ -1714,7 +1714,7 @@ function InlineSelect({ "mt-2 flex w-full items-center justify-center rounded-lg px-3 py-2 text-xs font-medium transition-all", canSubmit && !disabled ? "bg-primary text-primary-foreground hover:bg-primary/90 active:scale-[0.98] shadow-sm" - : "bg-muted text-muted-foreground/40 cursor-not-allowed", + : "bg-muted text-muted-foreground cursor-not-allowed", )} > {isMulti ? `Submit (${multiValues.size})` : "Submit"} @@ -1816,7 +1816,7 @@ function InlineInput({ "flex h-8 items-center justify-center rounded-lg px-3 text-xs font-medium transition-all", value.trim() && !disabled ? "bg-primary text-primary-foreground hover:bg-primary/90 active:scale-95 shadow-sm" - : "bg-muted text-muted-foreground/40 cursor-not-allowed", + : "bg-muted text-muted-foreground cursor-not-allowed", )} > Submit @@ -1927,12 +1927,12 @@ function ToolExecutionBlock({ tool }: { tool: CompletedToolExecution }) { "w-full rounded-lg border px-3 py-2 text-left text-xs transition-colors", isError ? "border-destructive/30 bg-destructive/5 hover:bg-destructive/10" - : "border-border/40 bg-muted/20 hover:bg-muted/30", + : "border-border/50 bg-muted/50 hover:bg-muted/50", )} > {/* Header */}
- + {icon} @@ -1942,16 +1942,16 @@ function ToolExecutionBlock({ tool }: { tool: CompletedToolExecution }) { {shortPath} )} {bashCommand && !shortPath && ( - {bashCommand.length > 60 ? bashCommand.slice(0, 60) + "…" : bashCommand} + {bashCommand.length > 60 ? bashCommand.slice(0, 60) + "…" : bashCommand} )} - + {expanded ? : }
{/* Expanded content */} {expanded && diff && ( -
+
{diff.split("\n").map((line, i) => { const isAdd = line.startsWith("+") const isRemove = line.startsWith("-") @@ -1963,8 +1963,8 @@ function ToolExecutionBlock({ tool }: { tool: CompletedToolExecution }) { "whitespace-pre", isAdd && "bg-success/10 text-success", isRemove && "bg-destructive/10 text-destructive", - isContext && "text-muted-foreground/60", - !isAdd && !isRemove && !isContext && "text-muted-foreground/40", + isContext && "text-muted-foreground", + !isAdd && !isRemove && !isContext && "text-muted-foreground", )} > {line} @@ -1976,7 +1976,7 @@ function ToolExecutionBlock({ tool }: { tool: CompletedToolExecution }) { {/* Expanded: bash output or other result */} {expanded && !diff && resultText && ( -
+
{resultText.length > 2000 ? resultText.slice(0, 2000) + "\n…" : resultText}
)} @@ -2291,8 +2291,8 @@ export function ChatPane({ className, onOpenAction }: ChatPaneProps) {
-
- +
+ {item.tool.name} diff --git a/web/components/gsd/code-editor.tsx b/web/components/gsd/code-editor.tsx index 2243fb8f1..164b1ce0c 100644 --- a/web/components/gsd/code-editor.tsx +++ b/web/components/gsd/code-editor.tsx @@ -78,7 +78,7 @@ const darkTheme = createTheme({ selection: "oklch(0.2 0 0)", lineHighlight: "oklch(0.12 0 0)", gutterBackground: "oklch(0.09 0 0)", - gutterForeground: "oklch(0.35 0 0)", + gutterForeground: "oklch(0.42 0 0)", gutterBorder: "transparent", }, styles: darkStyles, diff --git a/web/components/gsd/command-surface.tsx b/web/components/gsd/command-surface.tsx index 90a8baa0d..29e434f3a 100644 --- a/web/components/gsd/command-surface.tsx +++ b/web/components/gsd/command-surface.tsx @@ -224,7 +224,7 @@ function SectionHeader({ return (
-

{title}

+

{title}

{status}
{action} @@ -290,7 +290,7 @@ function SegmentedControl({ disabled?: boolean }) { return ( -
+
{options.map((opt) => ( @@ -738,7 +738,7 @@ export function CommandSurface() { )} {/* Apply */} -
+

{diag.summary.detail}

-
+

{issue.message}

- {issue.suggestion &&

→ {issue.suggestion}

} + {issue.suggestion &&

→ {issue.suggestion}

}
))}
@@ -1156,7 +1156,7 @@ export function CommandSurface() { )} {/* Actions */} -
+
{diag.actions.browser.length > 0 ? ( diag.actions.browser.map((action) => ( @@ -1574,7 +1574,7 @@ export function CommandSurface() {

No fork points available yet.

)} -
+
) @@ -1788,7 +1788,7 @@ export function CommandSurface() { {/* Selected provider details */} {selectedAuthProvider && ( -
+
{selectedAuthProvider.label}
@@ -1899,7 +1899,7 @@ export function CommandSurface() { {activeFlow.progress.length > 0 && (
{activeFlow.progress.map((message, index) => ( -
+
{message}
))} @@ -1987,7 +1987,7 @@ export function CommandSurface() { {/* Individual overrides — only visible when master is on */} {devOverrides.enabled && ( -
+
Override shortcuts
@@ -1999,7 +1999,7 @@ export function CommandSurface() {
{entry.label} - + {entry.shortcutLabel}
@@ -2016,7 +2016,7 @@ export function CommandSurface() { )} {/* Onboarding — one-click launch */} -
+
Onboarding
@@ -2046,7 +2046,7 @@ export function CommandSurface() {
-
+
This tab is only visible when running via{" "} npm run gsd:web. Overrides reset on page refresh. @@ -2061,7 +2061,7 @@ export function CommandSurface() { case "model": return (
{renderModelSection()} -
+
{renderThinkingSection()}
@@ -2069,7 +2069,7 @@ export function CommandSurface() { case "thinking": return (
{renderModelSection()} -
+
{renderThinkingSection()}
@@ -2077,10 +2077,10 @@ export function CommandSurface() { case "session-behavior": return (
{renderQueueSection()} -
+
{renderCompactionSection()}
-
+
{renderRetrySection()}
@@ -2089,10 +2089,10 @@ export function CommandSurface() { case "queue": return (
{renderQueueSection()} -
+
{renderCompactionSection()}
-
+
{renderRetrySection()}
@@ -2100,10 +2100,10 @@ export function CommandSurface() { case "compaction": return (
{renderQueueSection()} -
+
{renderCompactionSection()}
-
+
{renderRetrySection()}
@@ -2111,10 +2111,10 @@ export function CommandSurface() { case "retry": return (
{renderQueueSection()} -
+
{renderCompactionSection()}
-
+
{renderRetrySection()}
@@ -2188,7 +2188,7 @@ export function CommandSurface() { const isClean = gitResult?.kind === "repo" && !hasChanges return ( -
+
{branchName && mainBranch && branchName !== mainBranch && ( - from {mainBranch} + from {mainBranch} )}
{gitResult?.kind === "repo" && ( @@ -2248,7 +2248,7 @@ export function CommandSurface() { } const renderDefaultHeader = () => ( -
+
Command surface
@@ -2285,7 +2285,7 @@ export function CommandSurface() {
{/* ─── Left nav rail (hidden for single-section surfaces) ─── */} {!isSingleSection && ( -