From f8b4c3cf4fecf66b8097fc5ac92f38b28af80ab2 Mon Sep 17 00:00:00 2001 From: David Kaya Date: Sun, 29 Mar 2026 17:10:00 +0200 Subject: [PATCH] feat: Luminous Depth UI redesign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complete visual overhaul of the Aryx application with the Luminous Depth design language — blue-tinted dark surfaces, brand gradient accents, glass-morphism effects, and refined typography. Design Foundation: - New color system with CSS custom properties for all surfaces, borders, text, accents, and status colors - Typography: Outfit (display), DM Sans (body), JetBrains Mono (code) - Animations: accent-flow, thinking-wave, ambient-glow - Utility classes: glass-surface, glow-border, brand-gradient-bg/text - Light theme with cool-tinted whites and blue-tinted shadows Components Updated: - UI primitives (TextInput, SelectInput, ToggleSwitch, FormField, etc.) - AppShell with ambient glow background - Sidebar with brand gradient selection and accent-flow running bars - ChatPane with semantic phase tinting and gradient user avatars - WelcomePane with nebula background and motion entrance animations - All chat banners (Approval, UserInput, PlanReview, MCP Auth, etc.) - ActivityPanel and RunTimeline with glass-surface cards - Settings panels, modals, and editor shells - TerminalPanel with harmonized ANSI palette - PatternGraph nodes with glass-surface styling - MarkdownComposer toolbar Zero hardcoded zinc/indigo color classes remain in renderer components. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- bun.lock | 20 + package.json | 4 + src/renderer/components/ActivityPanel.tsx | 116 ++--- src/renderer/components/AgentConfigFields.tsx | 38 +- src/renderer/components/AppShell.tsx | 19 +- src/renderer/components/ChatPane.tsx | 120 +++--- src/renderer/components/CopilotStatusCard.tsx | 128 +++--- .../components/DiscoveredToolingModal.tsx | 44 +- src/renderer/components/MarkdownComposer.tsx | 8 +- src/renderer/components/NewSessionModal.tsx | 36 +- src/renderer/components/PatternEditor.tsx | 101 +++-- .../components/ProjectSettingsPanel.tsx | 148 +++---- src/renderer/components/ProviderIcons.tsx | 6 +- src/renderer/components/RunTimeline.tsx | 88 ++-- src/renderer/components/SettingsPanel.tsx | 118 ++--- src/renderer/components/Sidebar.tsx | 124 +++--- src/renderer/components/TerminalPanel.tsx | 62 +-- src/renderer/components/WelcomePane.tsx | 123 ++++-- .../components/chat/ApprovalBanner.tsx | 58 +-- src/renderer/components/chat/InlinePills.tsx | 110 ++--- .../components/chat/InlinePromptPill.tsx | 34 +- .../components/chat/McpAuthBanner.tsx | 22 +- .../components/chat/PermissionDetailView.tsx | 60 +-- .../components/chat/PlanReviewBanner.tsx | 24 +- .../components/chat/SubagentActivityCard.tsx | 26 +- src/renderer/components/chat/ThinkingDots.tsx | 6 +- .../components/chat/UserInputBanner.tsx | 20 +- .../components/pattern-graph/GraphNodes.tsx | 18 +- .../pattern-graph/PatternGraphCanvas.tsx | 12 +- .../pattern-graph/PatternGraphInspector.tsx | 28 +- .../components/settings/LspProfileEditor.tsx | 6 +- .../components/settings/McpServerEditor.tsx | 6 +- .../settings/ToolingEditorShell.tsx | 12 +- src/renderer/components/ui/FormField.tsx | 4 +- src/renderer/components/ui/InfoCallout.tsx | 4 +- .../components/ui/PopoverToggleRow.tsx | 6 +- src/renderer/components/ui/SelectInput.tsx | 2 +- src/renderer/components/ui/TextInput.tsx | 2 +- src/renderer/components/ui/TextareaInput.tsx | 2 +- src/renderer/components/ui/ToggleSwitch.tsx | 4 +- src/renderer/index.html | 2 +- src/renderer/main.tsx | 4 + src/renderer/styles.css | 408 ++++++++++++------ 43 files changed, 1214 insertions(+), 969 deletions(-) diff --git a/bun.lock b/bun.lock index 132fd4b..425be42 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,11 @@ "": { "name": "kopaya", "dependencies": { + "@fontsource-variable/dm-sans": "^5.2.8", + "@fontsource-variable/jetbrains-mono": "^5.2.8", + "@fontsource-variable/outfit": "^5.2.8", "keytar": "^7.9.0", + "motion": "^12.38.0", "node-pty": "^1.1.0", }, "devDependencies": { @@ -157,6 +161,12 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + "@fontsource-variable/dm-sans": ["@fontsource-variable/dm-sans@5.2.8", "", {}, "sha512-AxkvMTvNWgfrmlyjiV05vlHYJa+nRQCf1EfvIrQAPBpFJW0O9VTz7oAFr9S3lvbWdmnFoBk7yFqQL86u64nl2g=="], + + "@fontsource-variable/jetbrains-mono": ["@fontsource-variable/jetbrains-mono@5.2.8", "", {}, "sha512-WBA9elru6Jdp5df2mES55wuOO0WIrn3kpXnI4+W2ek5u3ZgLS9XS4gmIlcQhiZOWEKl95meYdvK7xI+ETLCq/Q=="], + + "@fontsource-variable/outfit": ["@fontsource-variable/outfit@5.2.8", "", {}, "sha512-4oUDCZx/Tcz6HZP423w/niqEH31Gks5IsqHV2ZZz1qKHaVIZdj2f0/S1IK2n8jl6Xo0o3N+3RjNHlV9R73ozQA=="], + "@hono/node-server": ["@hono/node-server@1.19.11", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -569,6 +579,8 @@ "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], @@ -831,6 +843,12 @@ "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + "motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], + + "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], + + "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], @@ -1011,6 +1029,8 @@ "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], "type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], diff --git a/package.json b/package.json index 8ef0489..9a6a4db 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,11 @@ "yaml": "^2.8.3" }, "dependencies": { + "@fontsource-variable/dm-sans": "^5.2.8", + "@fontsource-variable/jetbrains-mono": "^5.2.8", + "@fontsource-variable/outfit": "^5.2.8", "keytar": "^7.9.0", + "motion": "^12.38.0", "node-pty": "^1.1.0" } } diff --git a/src/renderer/components/ActivityPanel.tsx b/src/renderer/components/ActivityPanel.tsx index 677f482..39ec1cf 100644 --- a/src/renderer/components/ActivityPanel.tsx +++ b/src/renderer/components/ActivityPanel.tsx @@ -24,12 +24,12 @@ import { ProviderIcon } from './ProviderIcons'; /* ── Mode accent colours ───────────────────────────────────── */ const modeAccent: Record = { - single: { dot: 'bg-indigo-400', bar: 'bg-indigo-500/60', label: 'text-indigo-400' }, - sequential: { dot: 'bg-amber-400', bar: 'bg-amber-500/60', label: 'text-amber-400' }, - concurrent: { dot: 'bg-emerald-400', bar: 'bg-emerald-500/60', label: 'text-emerald-400' }, - handoff: { dot: 'bg-sky-400', bar: 'bg-sky-500/60', label: 'text-sky-400' }, - 'group-chat': { dot: 'bg-violet-400', bar: 'bg-violet-500/60', label: 'text-violet-400' }, - magentic: { dot: 'bg-zinc-500', bar: 'bg-zinc-600/60', label: 'text-zinc-500' }, + single: { dot: 'bg-[#245CF9]', bar: 'bg-[#245CF9] opacity-60', label: 'text-[#245CF9]' }, + sequential: { dot: 'bg-[var(--color-status-warning)]', bar: 'bg-[var(--color-status-warning)] opacity-60', label: 'text-[var(--color-status-warning)]' }, + concurrent: { dot: 'bg-[var(--color-status-success)]', bar: 'bg-[var(--color-status-success)] opacity-60', label: 'text-[var(--color-status-success)]' }, + handoff: { dot: 'bg-[var(--color-accent-sky)]', bar: 'bg-[var(--color-accent-sky)] opacity-60', label: 'text-[var(--color-accent-sky)]' }, + 'group-chat': { dot: 'bg-[var(--color-accent-purple)]', bar: 'bg-[var(--color-accent-purple)] opacity-60', label: 'text-[var(--color-accent-purple)]' }, + magentic: { dot: 'bg-[var(--color-text-muted)]', bar: 'bg-[var(--color-text-muted)] opacity-60', label: 'text-[var(--color-text-muted)]' }, }; /* ── Helpers ───────────────────────────────────────────────── */ @@ -62,7 +62,7 @@ const modeLabels: Record = { function SectionHeader({ children }: { children: ReactNode }) { return ( -

+

{children}

); @@ -87,7 +87,7 @@ function AgentRow({ const isCompleted = isAgentActivityCompleted(row.activity); return ( -
+
{/* Left accent bar — visible only when this agent is actively working */} {isActive && (
@@ -96,12 +96,12 @@ function AgentRow({ {/* Status dot */}
@@ -109,13 +109,13 @@ function AgentRow({ {/* Content */}
- {row.agentName} + {row.agentName}
{/* Model + effort inline */} {agent && (
- + {(() => { const prov = inferProvider(agent.model); return prov ? : null; @@ -124,8 +124,8 @@ function AgentRow({ {agent.reasoningEffort && ( <> - · - + · + {formatEffort(agent.reasoningEffort)} @@ -141,8 +141,8 @@ function AgentRow({ isActive ? accent.label : isCompleted - ? 'text-emerald-400' - : 'text-zinc-600' + ? 'text-[var(--color-status-success)]' + : 'text-[var(--color-text-muted)]' }`} > {formatAgentActivityLabel(row.activity)} @@ -151,20 +151,20 @@ function AgentRow({ {/* Per-agent usage summary */} {agentUsage && agentUsage.requestCount > 0 && ( -
- {formatTokenCount(agentUsage.inputTokens)} in - · - {formatTokenCount(agentUsage.outputTokens)} out +
+ {formatTokenCount(agentUsage.inputTokens)} in + · + {formatTokenCount(agentUsage.outputTokens)} out {agentUsage.cost > 0 && ( <> - · - {agentUsage.cost.toFixed(2)} cost + · + {agentUsage.cost.toFixed(2)} cost )} {agentUsage.durationMs > 0 && ( <> - · - {formatDuration(agentUsage.durationMs)} + · + {formatDuration(agentUsage.durationMs)} )}
@@ -182,15 +182,15 @@ function TurnEventIcon({ kind, phase, success }: { kind: SessionEventKind; phase const base = 'size-3'; switch (kind) { case 'subagent': - return ; + return ; case 'hook-lifecycle': - return ; + return ; case 'skill-invoked': - return ; + return ; case 'session-compaction': - return ; + return ; default: - return ; + return ; } } @@ -238,19 +238,19 @@ export function ActivityPanel({ {/* Header — top padding clears the title bar overlay zone */}
- - + + Activity {hasPendingApproval ? ( - - + + Approval{totalApprovalCount > 1 ? `s (${totalApprovalCount})` : ''} ) : isBusy ? ( - + ) : null}
@@ -261,7 +261,7 @@ export function ActivityPanel({ Agents - + {activityRows.length} @@ -270,7 +270,7 @@ export function ActivityPanel({ {activityRows.length > 0 ? ( -
+
{activityRows.map((row, index) => { const agentKey = row.activity?.agentId ?? row.key; const agentUsage = sessionRequestUsage?.perAgent[agentKey] @@ -288,7 +288,7 @@ export function ActivityPanel({ })}
) : ( -

No agents configured

+

No agents configured

)}
@@ -300,32 +300,32 @@ export function ActivityPanel({ Session Usage -
-
- +
+
+ {sessionRequestUsage.requestCount} premium request{sessionRequestUsage.requestCount === 1 ? '' : 's'} {sessionRequestUsage.totalNanoAiu > 0 && ( <> - · - {formatNanoAiu(sessionRequestUsage.totalNanoAiu)} AIU + · + {formatNanoAiu(sessionRequestUsage.totalNanoAiu)} AIU )}
-
- {formatTokenCount(sessionRequestUsage.totalInputTokens)} in - · - {formatTokenCount(sessionRequestUsage.totalOutputTokens)} out +
+ {formatTokenCount(sessionRequestUsage.totalInputTokens)} in + · + {formatTokenCount(sessionRequestUsage.totalOutputTokens)} out {sessionRequestUsage.totalCost > 0 && ( <> - · - {sessionRequestUsage.totalCost.toFixed(2)} cost + · + {sessionRequestUsage.totalCost.toFixed(2)} cost )} {sessionRequestUsage.totalDurationMs > 0 && ( <> - · - {formatDuration(sessionRequestUsage.totalDurationMs)} total + · + {formatDuration(sessionRequestUsage.totalDurationMs)} total )}
@@ -339,7 +339,7 @@ export function ActivityPanel({ Timeline {session.runs.length > 0 && ( - + {session.runs.length} )} @@ -354,12 +354,12 @@ export function ActivityPanel({ Events - + {turnEvents.length} -
+
{turnEvents.slice().reverse().map((entry, index) => (
@@ -367,13 +367,13 @@ export function ActivityPanel({
- {entry.label} - + {entry.label} + {formatTurnEventTimestamp(entry.occurredAt)}
{entry.detail && ( -

{entry.detail}

+

{entry.detail}

)}
diff --git a/src/renderer/components/AgentConfigFields.tsx b/src/renderer/components/AgentConfigFields.tsx index c7bfd36..ba4f5f9 100644 --- a/src/renderer/components/AgentConfigFields.tsx +++ b/src/renderer/components/AgentConfigFields.tsx @@ -18,9 +18,9 @@ function TierBadge({ tier }: { tier: ModelDefinition['tier'] }) { } const styles = { - premium: 'bg-amber-500/10 text-amber-400', - standard: 'bg-zinc-700/50 text-zinc-500', - fast: 'bg-emerald-500/10 text-emerald-400', + premium: 'bg-[var(--color-status-warning)]/10 text-[var(--color-status-warning)]', + standard: 'bg-[var(--color-surface-3)]/50 text-[var(--color-text-muted)]', + fast: 'bg-[var(--color-status-success)]/10 text-[var(--color-status-success)]', }; return ( @@ -75,10 +75,10 @@ export function ModelSelect({ return (