Skip to content

Commit e08fc3b

Browse files
committed
feat: enhance agent panel, terminal, and chat input components with improved functionality and styling
- Updated the AgentPanel to utilize a skills catalog for dynamic skill management, improving the user experience. - Enhanced the TerminalPane with dark and light mode support for terminal background and foreground colors, ensuring better visibility. - Refined the ChatInputBar layout and styling, including adjustments for mobile responsiveness and improved button interactions.
1 parent bc065ef commit e08fc3b

5 files changed

Lines changed: 89 additions & 111 deletions

File tree

components/agent-panel.tsx

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,77 +2110,31 @@ export function AgentPanel({ onClose }: { onClose?: () => void } = {}) {
21102110

21112111
// ─── Picker data sources ──────────────────────────────────────
21122112
const skillPickerItems = useMemo<PickerItem[]>(() => {
2113+
const enabledMap = new Map<string, boolean>()
21132114
const stored =
21142115
typeof window !== 'undefined' ? localStorage.getItem('knot-code:skills:runtime') : null
2116+
21152117
if (stored) {
21162118
try {
21172119
const skills = JSON.parse(stored) as Array<{
21182120
id: string
2119-
name: string
2120-
description?: string
21212121
enabled?: boolean
21222122
}>
2123-
return skills.map((s) => ({
2124-
id: s.id,
2125-
name: s.name,
2126-
description: s.description || 'No description',
2127-
icon: 'lucide:sparkles',
2128-
enabled: s.enabled ?? true,
2129-
}))
2123+
for (const skill of skills) {
2124+
enabledMap.set(skill.id, skill.enabled ?? true)
2125+
}
21302126
} catch {
2131-
// Ignore parse errors, fall through to defaults
2127+
// Ignore parse errors and fall back to the bundled catalog.
21322128
}
21332129
}
2134-
return [
2135-
{
2136-
id: 'code-review',
2137-
name: 'Code Review',
2138-
description: 'Review code for bugs and improvements',
2139-
icon: 'lucide:scan-eye',
2140-
},
2141-
{
2142-
id: 'refactor',
2143-
name: 'Refactor',
2144-
description: 'Improve code structure and readability',
2145-
icon: 'lucide:refresh-cw',
2146-
},
2147-
{
2148-
id: 'test-gen',
2149-
name: 'Test Generator',
2150-
description: 'Generate unit tests for code',
2151-
icon: 'lucide:flask-conical',
2152-
},
2153-
{
2154-
id: 'doc-gen',
2155-
name: 'Documentation',
2156-
description: 'Generate documentation for code',
2157-
icon: 'lucide:file-text',
2158-
},
2159-
{
2160-
id: 'explain',
2161-
name: 'Explain Code',
2162-
description: 'Get a detailed explanation of code',
2163-
icon: 'lucide:book-open',
2164-
},
2165-
{
2166-
id: 'optimize',
2167-
name: 'Optimize',
2168-
description: 'Optimize code for performance',
2169-
icon: 'lucide:zap',
2170-
},
2171-
{
2172-
id: 'security',
2173-
name: 'Security Audit',
2174-
description: 'Check code for security vulnerabilities',
2175-
icon: 'lucide:shield',
2176-
},
2177-
{
2178-
id: 'debug',
2179-
name: 'Debug Helper',
2180-
description: 'Help identify and fix bugs',
2181-
icon: 'lucide:bug',
2182-
},
2183-
]
2130+
2131+
return SKILLS_CATALOG.map((skill) => ({
2132+
id: skill.slug,
2133+
name: skill.title,
2134+
description: skill.shortDescription || 'No description',
2135+
icon: skill.icon || 'lucide:sparkles',
2136+
enabled: enabledMap.get(skill.id) ?? enabledMap.get(skill.slug) ?? true,
2137+
}))
21842138
}, [])
21852139

21862140
const promptPickerItems = useMemo<PickerItem[]>(() => {

components/chat/chat-input-bar.tsx

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -584,37 +584,31 @@ export function ChatInputBar({
584584
/>
585585

586586
{/* Bottom toolbar row */}
587-
<div className="flex items-center justify-between px-2.5 pb-1.5 pt-0.5">
588-
<div className="flex items-center gap-0.5">
587+
<div className="flex items-center justify-between px-2.5 pb-2 pt-0.5">
588+
<div className="flex items-center gap-1.5">
589589
<button
590590
onClick={onFileAttach}
591-
className="p-2 sm:p-1.5 rounded-md text-[var(--text-disabled)] hover:text-[var(--text-secondary)] hover:bg-[var(--bg-subtle)] transition-colors cursor-pointer"
591+
className="flex h-7 w-7 items-center justify-center rounded-lg border border-[var(--border)] bg-[var(--bg)] text-[var(--text-disabled)] hover:text-[var(--text-secondary)] hover:border-[var(--border-hover)] transition-colors cursor-pointer"
592592
title="Attach file"
593593
>
594-
<Icon
595-
icon="lucide:paperclip"
596-
width={16}
597-
height={16}
598-
className="sm:w-[14px] sm:h-[14px]"
599-
/>
594+
<Icon icon="lucide:paperclip" width={14} height={14} />
600595
</button>
601596
<button
602597
onClick={onImageAttach}
603-
className="p-2 sm:p-1.5 rounded-md text-[var(--text-disabled)] hover:text-[var(--text-secondary)] hover:bg-[var(--bg-subtle)] transition-colors cursor-pointer"
598+
className="flex h-7 w-7 items-center justify-center rounded-lg border border-[var(--border)] bg-[var(--bg)] text-[var(--text-disabled)] hover:text-[var(--text-secondary)] hover:border-[var(--border-hover)] transition-colors cursor-pointer"
604599
title="Attach image"
605600
>
606-
<Icon
607-
icon="lucide:image-plus"
608-
width={16}
609-
height={16}
610-
className="sm:w-[14px] sm:h-[14px]"
611-
/>
601+
<Icon icon="lucide:image-plus" width={14} height={14} />
612602
</button>
613-
<span className="ml-1 text-[11.5px] text-[var(--text-disabled)]">
603+
<span className="text-[11.5px] text-[var(--text-disabled)]">
614604
<kbd className="rounded border border-[var(--border)] px-1 py-px text-[10px] font-mono">
615605
@
616606
</kbd>
617607
</span>
608+
<div className="hidden sm:flex items-center gap-1.5 ml-0.5">
609+
<ModeSelector mode={agentMode} onChange={setAgentMode} />
610+
<span className="text-[9px] text-[var(--text-disabled)]">⇧Tab</span>
611+
</div>
618612
</div>
619613
<div className="flex items-center gap-1">
620614
{contextTokens > 0 && (
@@ -640,14 +634,10 @@ export function ChatInputBar({
640634
</button>
641635
</div>
642636
</div>
643-
</div>
644-
</div>
645-
646-
{/* Bottom bar — mode selector */}
647-
<div className="flex items-center mt-1">
648-
<div className="flex items-center gap-1.5">
649-
<ModeSelector mode={agentMode} onChange={setAgentMode} />
650-
<span className="hidden sm:inline text-[9px] text-[var(--text-disabled)]">⇧Tab</span>
637+
{/* Mobile mode selector — below toolbar on small screens */}
638+
<div className="flex sm:hidden items-center gap-1.5 px-2.5 pb-2">
639+
<ModeSelector mode={agentMode} onChange={setAgentMode} />
640+
</div>
651641
</div>
652642
</div>
653643
</div>

components/terminal-panel.tsx

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ const FILE_PATH_REGEX = new RegExp(
3737
'g',
3838
)
3939

40-
const SOLID_TERMINAL_BG = '#000000'
41-
const SOLID_TERMINAL_FG = '#e5e7eb'
40+
const SOLID_TERMINAL_BG_DARK = '#000000'
41+
const SOLID_TERMINAL_BG_LIGHT = '#ffffff'
42+
const SOLID_TERMINAL_FG_DARK = '#e5e7eb'
43+
const SOLID_TERMINAL_FG_LIGHT = '#1a1a1a'
4244

4345
function findFileLinksInLine(
4446
lineText: string,
@@ -82,12 +84,11 @@ function buildXtermTheme(hasBgImage?: boolean, bgColor?: string | null) {
8284
const s = getComputedStyle(document.documentElement)
8385
const v = (name: string) => s.getPropertyValue(name).trim()
8486
const dark = document.documentElement.classList.contains('dark')
85-
const solidBg = bgColor || SOLID_TERMINAL_BG
87+
const solidBg = bgColor || (dark ? SOLID_TERMINAL_BG_DARK : SOLID_TERMINAL_BG_LIGHT)
88+
const solidFg = dark ? SOLID_TERMINAL_FG_DARK : SOLID_TERMINAL_FG_LIGHT
8689
return {
8790
background: hasBgImage ? 'transparent' : solidBg,
88-
foreground: hasBgImage
89-
? v('--text-primary') || (dark ? '#e5e5e5' : '#171717')
90-
: SOLID_TERMINAL_FG,
91+
foreground: hasBgImage ? v('--text-primary') || (dark ? '#e5e5e5' : '#171717') : solidFg,
9192
cursor: v('--brand') || '#a855f7',
9293
cursorAccent: hasBgImage ? 'transparent' : solidBg,
9394
selectionBackground: (v('--brand') || '#a855f7') + '40',
@@ -267,6 +268,7 @@ function TerminalPane({
267268
onChangeBgColor,
268269
}: TerminalPaneProps) {
269270
const hasBgImage = !!terminalBg
271+
const [isDark, setIsDark] = useState(true)
270272
const [showBgPicker, setShowBgPicker] = useState(false)
271273
const [activeId, setActiveId] = useState<number | null>(session.terminalId)
272274
const [terminalError, setTerminalError] = useState<string | null>(null)
@@ -275,6 +277,10 @@ function TerminalPane({
275277
const wasVisibleRef = useRef(false)
276278
const refreshTokenRef = useRef<string | undefined>(undefined)
277279

280+
useEffect(() => {
281+
setIsDark(document.documentElement.classList.contains('dark'))
282+
}, [themeVersion])
283+
278284
useEffect(() => {
279285
onFileOpenRef.current = onFileOpen
280286
}, [onFileOpen])
@@ -630,20 +636,36 @@ function TerminalPane({
630636
Background tint
631637
</p>
632638
<div className="grid grid-cols-6 gap-1.5 mb-2">
633-
{[
634-
'#000000',
635-
'#0a0a0a',
636-
'#1a1a2e',
637-
'#0d1117',
638-
'#1e1e2e',
639-
'#2d1b2e',
640-
'#0b132b',
641-
'#1b2a1b',
642-
'#2a1a0b',
643-
'#1a0a0a',
644-
'#0a1a2a',
645-
'#2a2a1a',
646-
].map((c) => (
639+
{(isDark
640+
? [
641+
'#000000',
642+
'#0a0a0a',
643+
'#1a1a2e',
644+
'#0d1117',
645+
'#1e1e2e',
646+
'#2d1b2e',
647+
'#0b132b',
648+
'#1b2a1b',
649+
'#2a1a0b',
650+
'#1a0a0a',
651+
'#0a1a2a',
652+
'#2a2a1a',
653+
]
654+
: [
655+
'#ffffff',
656+
'#fafafa',
657+
'#f5f5f5',
658+
'#f0f0f5',
659+
'#f5f0e8',
660+
'#f0f5f0',
661+
'#e8f0f5',
662+
'#f5e8f0',
663+
'#f0f0e0',
664+
'#e8e8f0',
665+
'#f0e8e0',
666+
'#e0f0f0',
667+
]
668+
).map((c) => (
647669
<button
648670
key={c}
649671
onClick={() => {
@@ -659,13 +681,17 @@ function TerminalPane({
659681
<div className="flex items-center gap-2">
660682
<input
661683
type="color"
662-
value={terminalBgColor || '#000000'}
684+
value={
685+
terminalBgColor ||
686+
(isDark ? SOLID_TERMINAL_BG_DARK : SOLID_TERMINAL_BG_LIGHT)
687+
}
663688
onChange={(e) => onChangeBgColor(e.target.value)}
664689
className="w-6 h-6 rounded cursor-pointer border border-[var(--border)] bg-transparent p-0"
665690
title="Custom color"
666691
/>
667692
<span className="text-[10px] text-[var(--text-disabled)] font-mono flex-1">
668-
{terminalBgColor || '#000000'}
693+
{terminalBgColor ||
694+
(isDark ? SOLID_TERMINAL_BG_DARK : SOLID_TERMINAL_BG_LIGHT)}
669695
</span>
670696
{terminalBgColor && (
671697
<button
@@ -725,7 +751,11 @@ function TerminalPane({
725751
{/* Terminal viewport */}
726752
<div
727753
className="flex-1 overflow-hidden relative"
728-
style={{ backgroundColor: hasBgImage ? undefined : terminalBgColor || '#000000' }}
754+
style={{
755+
backgroundColor: hasBgImage
756+
? undefined
757+
: terminalBgColor || (isDark ? SOLID_TERMINAL_BG_DARK : SOLID_TERMINAL_BG_LIGHT),
758+
}}
729759
>
730760
{hasBgImage && (
731761
<>

context/app-mode-context.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,17 @@ export function AppModeProvider({ children }: { children: ReactNode }) {
6666
}
6767

6868
// Ensure active view is valid in this mode.
69-
// Chat mode is always chat-first, so force the chat view.
7069
if (mode === 'chat') {
7170
if (activeViewRef.current !== 'chat') {
7271
setView('chat')
7372
}
74-
// Force collapse (bypass editor-view guard in setEditorCollapsed).
7573
dispatch({ type: 'SET_EDITOR_COLLAPSED', collapsed: true })
74+
} else if (mode === 'tui') {
75+
// TUI needs activeView === 'editor' so useCenteredTerminal activates
76+
if (activeViewRef.current !== spec.defaultView) {
77+
setView(spec.defaultView)
78+
}
79+
dispatch({ type: 'SET_EDITOR_COLLAPSED', collapsed: false })
7680
} else {
7781
if (!spec.visibleViews.includes(activeViewRef.current)) {
7882
setView(spec.defaultView)

src-tauri/gen/apple/project.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ targets:
8484
- sdk: UIKit.framework
8585
- sdk: WebKit.framework
8686
preBuildScripts:
87-
- script: /opt/homebrew/bin/pnpm --dir "$SRCROOT/../../.." exec tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths "${FRAMEWORK_SEARCH_PATHS:?}" --header-search-paths "${HEADER_SEARCH_PATHS:?}" --gcc-preprocessor-definitions "${GCC_PREPROCESSOR_DEFINITIONS:-}" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}
87+
- script: /opt/homebrew/bin/pnpm --dir "$SRCROOT/../../.." exec tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths "${FRAMEWORK_SEARCH_PATHS:?}" --header-search-paths "${HEADER_SEARCH_PATHS:?}" --gcc-preprocessor-definitions "${GCC_PREPROCESSOR_DEFINITIONS:-}" --configuration ${CONFIGURATION:?} ${ARCHS:?}
8888
name: Build Rust Code
8989
basedOnDependencyAnalysis: false
9090
outputFiles:

0 commit comments

Comments
 (0)