From be4df01302975ba7268bd9b8256011a5b07c9d59 Mon Sep 17 00:00:00 2001 From: Hibryda Date: Sun, 8 Mar 2026 02:54:31 +0100 Subject: [PATCH] feat(v3): VSCode-style prompt redesign + theme-aware CSS migration --- .claude/CLAUDE.md | 1 + .claude/rules/51-theme-integration.md | 17 + v2/src/lib/components/Agent/AgentPane.svelte | 660 ++++++++++-------- .../lib/components/Context/ContextPane.svelte | 100 ++- .../components/Workspace/ClaudeSession.svelte | 9 + .../components/Workspace/ProjectBox.svelte | 29 +- 6 files changed, 489 insertions(+), 327 deletions(-) create mode 100644 .claude/rules/51-theme-integration.md diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 5fffb27..988bb54 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -102,3 +102,4 @@ All operational rules live in `.claude/rules/`. Every `.md` file in that directo | 16 | `sub-agents.md` | When to use sub-agents and team agents | | 17 | `document-imports.md` | Resolve @ imports in CLAUDE.md before acting | | 18 | `relative-units.md` | Use rem/em for layout, px only for icons/borders | +| 51 | `theme-integration.md` | All colors via --ctp-* CSS vars, never hardcode | diff --git a/.claude/rules/51-theme-integration.md b/.claude/rules/51-theme-integration.md new file mode 100644 index 0000000..1869e5d --- /dev/null +++ b/.claude/rules/51-theme-integration.md @@ -0,0 +1,17 @@ +# Theme Integration (CSS) + +All UI components MUST use the project's CSS custom properties for colors. Never hardcode color values. + +## Rules + +- **Backgrounds**: Use `var(--ctp-base)`, `var(--ctp-mantle)`, `var(--ctp-crust)`, `var(--ctp-surface0)`, `var(--ctp-surface1)`, `var(--ctp-surface2)`. +- **Text**: Use `var(--ctp-text)`, `var(--ctp-subtext0)`, `var(--ctp-subtext1)`. +- **Muted/overlay text**: Use `var(--ctp-overlay0)`, `var(--ctp-overlay1)`, `var(--ctp-overlay2)`. +- **Accents**: Use `var(--ctp-blue)`, `var(--ctp-green)`, `var(--ctp-mauve)`, `var(--ctp-peach)`, `var(--ctp-pink)`, `var(--ctp-red)`, `var(--ctp-yellow)`, `var(--ctp-teal)`, `var(--ctp-sapphire)`, `var(--ctp-lavender)`, `var(--ctp-flamingo)`, `var(--ctp-rosewater)`, `var(--ctp-maroon)`, `var(--ctp-sky)`. +- **Per-project accent**: Use `var(--accent)` which is set per ProjectBox slot. +- **Borders**: Use `var(--ctp-surface0)` or `var(--ctp-surface1)`. +- Never use raw hex/rgb/hsl color values in component CSS. All colors must go through `--ctp-*` variables. +- Hover states: typically lighten by stepping up one surface level (e.g., surface0 -> surface1) or change text from subtext0 to text. +- Active/selected states: use `var(--accent)` or a specific accent color with `var(--ctp-base)` background distinction. +- Disabled states: reduce opacity (0.4-0.5) rather than introducing gray colors. +- Use `color-mix()` for semi-transparent overlays: `color-mix(in srgb, var(--ctp-blue) 10%, transparent)`. diff --git a/v2/src/lib/components/Agent/AgentPane.svelte b/v2/src/lib/components/Agent/AgentPane.svelte index 4f1c0f3..0bb8356 100644 --- a/v2/src/lib/components/Agent/AgentPane.svelte +++ b/v2/src/lib/components/Agent/AgentPane.svelte @@ -5,10 +5,8 @@ import { getAgentSession, createAgentSession, - removeAgentSession, getChildSessions, getTotalCost, - type AgentSession, } from '../../stores/agents.svelte'; import { focusPane } from '../../stores/layout.svelte'; import { isSidecarAlive, setSidecarAlive } from '../../agent-dispatcher'; @@ -16,7 +14,6 @@ import AgentTree from './AgentTree.svelte'; import { getHighlighter, highlightCode, escapeHtml } from '../../utils/highlight'; import type { - AgentMessage, TextContent, ThinkingContent, ToolCallContent, @@ -93,7 +90,8 @@ // NOTE: Do NOT stop agents in onDestroy — it fires on layout changes/remounts, // not just explicit close. Stop-on-close is handled by workspace teardown. - let followUpPrompt = $state(''); + let promptRef = $state(); + let isRunning = $derived(session?.status === 'running' || session?.status === 'starting'); async function startQuery(text: string, resume = false) { if (!text.trim()) return; @@ -126,7 +124,9 @@ claude_config_dir: profile?.config_dir, }); inputPrompt = ''; - followUpPrompt = ''; + if (promptRef) { + promptRef.style.height = 'auto'; + } } async function expandSkillPrompt(text: string): Promise { @@ -143,11 +143,22 @@ } } - async function handleSubmit(e: Event) { - e.preventDefault(); + async function handleUnifiedSubmit() { + if (!inputPrompt.trim() || isRunning) return; const expanded = await expandSkillPrompt(inputPrompt); showSkillMenu = false; - startQuery(expanded); + // If session exists with sdkSessionId, this is a follow-up (resume) + const isResume = !!(session?.sdkSessionId && session.messages.length > 0); + startQuery(expanded, isResume); + } + + function handleNewSession() { + onExit?.(); + } + + function autoResizeTextarea(el: HTMLTextAreaElement) { + el.style.height = 'auto'; + el.style.height = Math.min(el.scrollHeight, 150) + 'px'; } function handleSkillSelect(skill: ClaudeSkill) { @@ -218,97 +229,47 @@
- {#if !session || session.messages.length === 0} -
-
-
- - {#if showSkillMenu && filteredSkills.length > 0} -
- {#each filteredSkills as skill, i (skill.name)} - - {/each} -
- {/if} -
- -
+ {#if parentSession} + - {:else} - {#if parentSession} - + {/each} +
+ {/if} + {#if hasToolCalls} +
+ +
+ {#if showTree && session} + {/if} - {#if childSessions.length > 0} -
- {childSessions.length} subagent{childSessions.length > 1 ? 's' : ''} - {#each childSessions as child (child.id)} - - {/each} + {/if} + +
+ {#if !session || session.messages.length === 0} +
+
+ + + +
+ Ask Claude anything + Type / for skills • Shift+Enter for newline
- {/if} - {#if hasToolCalls} -
- -
- {#if showTree && session} - - {/if} - {/if} -
+ {:else} {#each session.messages as msg (msg.id)}
{#if msg.type === 'init'} @@ -353,15 +314,18 @@ {/if}
{/each} -
+ {/if} +
- {/if} + + + {#if session && (session.status === 'done' || session.status === 'error') && session.sdkSessionId} +
+ + +
+ {/if} + + +
+
+ {#if showSkillMenu && filteredSkills.length > 0} +
+ {#each filteredSkills as skill, i (skill.name)} + + {/each} +
+ {/if} + + +
+