mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-03-18 11:23:08 +00:00
feat(ui): comprehensive design system improvements
This PR addresses 53 design issues identified in the UI codebase, implementing a more consistent and polished neobrutalism design system. Typography: - Improved font stacks with proper fallbacks - Added font smoothing for crisp text rendering Color/Theme: - Added neutral scale (50-900) for consistent grays - Added semantic log level colors with dark mode variants - Added category colors for feature cards - Added GLM badge color variable - Full dark mode support for all new variables Design Tokens: - Spacing scale (xs to 2xl) - Z-index scale (dropdown to toast) - Border radius tokens - Inset shadow variants Animations: - New transition timing variables - New easing curves (bounce, smooth, out-back) - Slide-in animations (top/bottom/left) - Bounce, shake, scale-pop animations - Stagger delay utilities - Enhanced YOLO fire effect with parallax layers Components: - Button size variants (sm/lg/icon) and loading state - Input variants (error/disabled/textarea) - Badge color and size variants - Card elevation variants (elevated/flat/sunken) - Progress bar shimmer animation - Stronger modal backdrop with blur - Neobrutalist tooltips - Enhanced empty state with striped pattern Component Fixes: - Replaced hardcoded colors with CSS variables - Fixed ProgressDashboard percentage alignment - Improved ChatMessage role-specific styling - Consistent category badge colors in FeatureModal - Improved step input styling in forms Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -87,13 +87,13 @@ export function AddFeatureForm({ projectName, onClose }: AddFeatureFormProps) {
|
||||
<form onSubmit={handleSubmit} className="p-6 space-y-4">
|
||||
{/* Error Message */}
|
||||
{error && (
|
||||
<div className="flex items-center gap-3 p-4 bg-[var(--color-neo-danger)] text-white border-3 border-[var(--color-neo-border)]">
|
||||
<div className="flex items-center gap-3 p-4 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] border-3 border-[var(--color-neo-error-border)]">
|
||||
<AlertCircle size={20} />
|
||||
<span>{error}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setError(null)}
|
||||
className="ml-auto"
|
||||
className="ml-auto hover:opacity-70 transition-opacity"
|
||||
>
|
||||
<X size={16} />
|
||||
</button>
|
||||
@@ -166,8 +166,11 @@ export function AddFeatureForm({ projectName, onClose }: AddFeatureFormProps) {
|
||||
</label>
|
||||
<div className="space-y-2">
|
||||
{steps.map((step, index) => (
|
||||
<div key={step.id} className="flex gap-2">
|
||||
<span className="neo-input w-12 text-center flex-shrink-0 flex items-center justify-center">
|
||||
<div key={step.id} className="flex gap-2 items-center">
|
||||
<span
|
||||
className="w-10 h-10 flex-shrink-0 flex items-center justify-center font-mono font-bold text-sm border-3 border-[var(--color-neo-border)] bg-[var(--color-neo-bg)] text-[var(--color-neo-text-secondary)]"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
{index + 1}
|
||||
</span>
|
||||
<input
|
||||
|
||||
@@ -131,7 +131,7 @@ export function AssistantChat({ projectName }: AssistantChatProps) {
|
||||
)}
|
||||
|
||||
{/* Input area */}
|
||||
<div className="border-t-3 border-[var(--color-neo-border)] p-4 bg-white">
|
||||
<div className="border-t-3 border-[var(--color-neo-border)] p-4 bg-[var(--color-neo-card)]">
|
||||
<div className="flex gap-2">
|
||||
<textarea
|
||||
ref={inputRef}
|
||||
|
||||
@@ -17,9 +17,8 @@ export function AssistantFAB({ onClick, isOpen }: AssistantFABProps) {
|
||||
fixed bottom-6 right-6 z-50
|
||||
w-14 h-14
|
||||
flex items-center justify-center
|
||||
bg-[var(--color-neo-progress)] text-white
|
||||
bg-[var(--color-neo-progress)] text-[var(--color-neo-text-on-bright)]
|
||||
border-3 border-[var(--color-neo-border)]
|
||||
rounded-full
|
||||
shadow-neo-md
|
||||
transition-all duration-200
|
||||
hover:shadow-neo-lg hover:-translate-y-0.5
|
||||
|
||||
@@ -31,26 +31,29 @@ export function AssistantPanel({ projectName, isOpen, onClose }: AssistantPanelP
|
||||
className={`
|
||||
fixed right-0 top-0 bottom-0 z-50
|
||||
w-[400px] max-w-[90vw]
|
||||
bg-white
|
||||
bg-neo-card
|
||||
border-l-4 border-[var(--color-neo-border)]
|
||||
shadow-[-8px_0_0px_rgba(0,0,0,1)]
|
||||
transform transition-transform duration-300 ease-out
|
||||
flex flex-col
|
||||
${isOpen ? 'translate-x-0' : 'translate-x-full'}
|
||||
`}
|
||||
style={{ boxShadow: 'var(--shadow-neo-left-lg)' }}
|
||||
role="dialog"
|
||||
aria-label="Project Assistant"
|
||||
aria-hidden={!isOpen}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-4 py-3 border-b-3 border-[var(--color-neo-border)] bg-[var(--color-neo-progress)]">
|
||||
<div className="flex items-center justify-between px-4 py-3 border-b-3 border-neo-border bg-neo-progress">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="bg-white border-2 border-[var(--color-neo-border)] p-1.5 shadow-[2px_2px_0px_rgba(0,0,0,1)]">
|
||||
<div
|
||||
className="bg-neo-card border-2 border-neo-border p-1.5"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<Bot size={18} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="font-display font-bold text-white">Project Assistant</h2>
|
||||
<p className="text-xs text-white/80 font-mono">{projectName}</p>
|
||||
<h2 className="font-display font-bold text-neo-text-on-bright">Project Assistant</h2>
|
||||
<p className="text-xs text-neo-text-on-bright opacity-80 font-mono">{projectName}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
@@ -58,9 +61,9 @@ export function AssistantPanel({ projectName, isOpen, onClose }: AssistantPanelP
|
||||
className="
|
||||
neo-btn neo-btn-ghost
|
||||
p-2
|
||||
bg-white/20 border-white/40
|
||||
hover:bg-white/30
|
||||
text-white
|
||||
bg-[var(--color-neo-card)] border-[var(--color-neo-border)]
|
||||
hover:bg-[var(--color-neo-bg)]
|
||||
text-[var(--color-neo-text)]
|
||||
"
|
||||
title="Close Assistant (Press A)"
|
||||
aria-label="Close Assistant"
|
||||
|
||||
@@ -21,31 +21,37 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
minute: '2-digit',
|
||||
})
|
||||
|
||||
// Role-specific styling
|
||||
// Role-specific styling using CSS variables for theme consistency
|
||||
const roleConfig = {
|
||||
user: {
|
||||
icon: User,
|
||||
bgColor: 'bg-[var(--color-neo-pending)]',
|
||||
textColor: 'text-[var(--color-neo-text-on-bright)]',
|
||||
borderColor: 'border-[var(--color-neo-border)]',
|
||||
align: 'justify-end',
|
||||
bubbleAlign: 'items-end',
|
||||
iconBg: 'bg-[var(--color-neo-pending)]',
|
||||
shadow: 'var(--shadow-neo-md)',
|
||||
},
|
||||
assistant: {
|
||||
icon: Bot,
|
||||
bgColor: 'bg-white',
|
||||
bgColor: 'bg-[var(--color-neo-card)]',
|
||||
textColor: 'text-[var(--color-neo-text)]',
|
||||
borderColor: 'border-[var(--color-neo-border)]',
|
||||
align: 'justify-start',
|
||||
bubbleAlign: 'items-start',
|
||||
iconBg: 'bg-[var(--color-neo-progress)]',
|
||||
shadow: 'var(--shadow-neo-md)',
|
||||
},
|
||||
system: {
|
||||
icon: Info,
|
||||
bgColor: 'bg-[var(--color-neo-done)]',
|
||||
textColor: 'text-[var(--color-neo-text-on-bright)]',
|
||||
borderColor: 'border-[var(--color-neo-border)]',
|
||||
align: 'justify-center',
|
||||
bubbleAlign: 'items-center',
|
||||
iconBg: 'bg-[var(--color-neo-done)]',
|
||||
shadow: 'var(--shadow-neo-sm)',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -61,9 +67,9 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
${config.bgColor}
|
||||
border-2 ${config.borderColor}
|
||||
px-4 py-2
|
||||
text-sm font-mono
|
||||
shadow-[2px_2px_0px_rgba(0,0,0,1)]
|
||||
text-sm font-mono text-[var(--color-neo-text-on-bright)]
|
||||
`}
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<Icon size={14} />
|
||||
@@ -85,11 +91,11 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
${config.iconBg}
|
||||
border-2 border-[var(--color-neo-border)]
|
||||
p-1.5
|
||||
shadow-[2px_2px_0px_rgba(0,0,0,1)]
|
||||
flex-shrink-0
|
||||
`}
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<Icon size={16} className="text-white" />
|
||||
<Icon size={16} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -98,13 +104,13 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
${config.bgColor}
|
||||
border-3 ${config.borderColor}
|
||||
px-4 py-3
|
||||
shadow-[4px_4px_0px_rgba(0,0,0,1)]
|
||||
${isStreaming ? 'animate-pulse-neo' : ''}
|
||||
`}
|
||||
style={{ boxShadow: config.shadow }}
|
||||
>
|
||||
{/* Parse content for basic markdown-like formatting */}
|
||||
{content && (
|
||||
<div className="whitespace-pre-wrap text-sm leading-relaxed text-[#1a1a1a]">
|
||||
<div className={`whitespace-pre-wrap text-sm leading-relaxed ${config.textColor}`}>
|
||||
{content.split('\n').map((line, i) => {
|
||||
// Bold text
|
||||
const boldRegex = /\*\*(.*?)\*\*/g
|
||||
@@ -144,7 +150,8 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
{attachments.map((attachment) => (
|
||||
<div
|
||||
key={attachment.id}
|
||||
className="border-2 border-[var(--color-neo-border)] p-1 bg-white shadow-[2px_2px_0px_rgba(0,0,0,1)]"
|
||||
className="border-2 border-[var(--color-neo-border)] p-1 bg-[var(--color-neo-card)]"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<img
|
||||
src={attachment.previewUrl}
|
||||
@@ -153,7 +160,7 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
onClick={() => window.open(attachment.previewUrl, '_blank')}
|
||||
title={`${attachment.filename} (click to enlarge)`}
|
||||
/>
|
||||
<span className="text-xs text-[var(--color-neo-text-secondary)] block mt-1 text-center">
|
||||
<span className="text-xs text-neo-text-secondary block mt-1 text-center">
|
||||
{attachment.filename}
|
||||
</span>
|
||||
</div>
|
||||
@@ -163,7 +170,7 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
|
||||
{/* Streaming indicator */}
|
||||
{isStreaming && (
|
||||
<span className="inline-block w-2 h-4 bg-[var(--color-neo-accent)] ml-1 animate-pulse" />
|
||||
<span className="inline-block w-2 h-4 bg-neo-accent ml-1 animate-pulse" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -173,11 +180,11 @@ export function ChatMessage({ message }: ChatMessageProps) {
|
||||
${config.iconBg}
|
||||
border-2 border-[var(--color-neo-border)]
|
||||
p-1.5
|
||||
shadow-[2px_2px_0px_rgba(0,0,0,1)]
|
||||
flex-shrink-0
|
||||
`}
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<Icon size={16} />
|
||||
<Icon size={16} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -55,12 +55,12 @@ export function ConfirmDialog({
|
||||
<div className="flex items-center justify-between p-4 border-b-3 border-[var(--color-neo-border)]">
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
className="p-2 border-2 border-[var(--color-neo-border)] shadow-[2px_2px_0px_rgba(0,0,0,1)]"
|
||||
style={{ backgroundColor: colors.icon }}
|
||||
className="p-2 border-2 border-[var(--color-neo-border)]"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)', backgroundColor: colors.icon }}
|
||||
>
|
||||
<AlertTriangle size={20} className="text-white" />
|
||||
<AlertTriangle size={20} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
</div>
|
||||
<h2 className="font-display font-bold text-lg text-[#1a1a1a]">
|
||||
<h2 className="font-display font-bold text-lg text-[var(--color-neo-text)]">
|
||||
{title}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -273,18 +273,18 @@ export function DebugLogViewer({
|
||||
return 'info'
|
||||
}
|
||||
|
||||
// Get color class for log level
|
||||
// Get color class for log level using theme CSS variables
|
||||
const getLogColor = (level: LogLevel): string => {
|
||||
switch (level) {
|
||||
case 'error':
|
||||
return 'text-red-400'
|
||||
return 'text-[var(--color-neo-log-error)]'
|
||||
case 'warn':
|
||||
return 'text-yellow-400'
|
||||
return 'text-[var(--color-neo-log-warning)]'
|
||||
case 'debug':
|
||||
return 'text-gray-400'
|
||||
return 'text-[var(--color-neo-log-debug)]'
|
||||
case 'info':
|
||||
default:
|
||||
return 'text-green-400'
|
||||
return 'text-[var(--color-neo-log-success)]'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,27 +316,27 @@ export function DebugLogViewer({
|
||||
className="absolute top-0 left-0 right-0 h-2 cursor-ns-resize group flex items-center justify-center -translate-y-1/2 z-50"
|
||||
onMouseDown={handleResizeStart}
|
||||
>
|
||||
<div className="w-16 h-1.5 bg-[#333] rounded-full group-hover:bg-[#555] transition-colors flex items-center justify-center">
|
||||
<GripHorizontal size={12} className="text-gray-500 group-hover:text-gray-400" />
|
||||
<div className="w-16 h-1.5 bg-[var(--color-neo-border)] rounded-full group-hover:bg-[var(--color-neo-text-secondary)] transition-colors flex items-center justify-center">
|
||||
<GripHorizontal size={12} className="text-[var(--color-neo-text-muted)] group-hover:text-[var(--color-neo-text-secondary)]" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Header bar */}
|
||||
<div
|
||||
className="flex items-center justify-between h-10 px-4 bg-[#1a1a1a] border-t-3 border-black"
|
||||
className="flex items-center justify-between h-10 px-4 bg-[var(--color-neo-border)] border-t-3 border-[var(--color-neo-text)]"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Collapse/expand toggle */}
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="flex items-center gap-2 hover:bg-[#333] px-2 py-1 rounded transition-colors cursor-pointer"
|
||||
className="flex items-center gap-2 hover:bg-[var(--color-neo-hover-subtle)] px-2 py-1 rounded transition-colors cursor-pointer"
|
||||
>
|
||||
<TerminalIcon size={16} className="text-green-400" />
|
||||
<span className="font-mono text-sm text-white font-bold">
|
||||
<TerminalIcon size={16} className="text-[var(--color-neo-done)]" />
|
||||
<span className="font-mono text-sm text-[var(--color-neo-bg)] font-bold">
|
||||
Debug
|
||||
</span>
|
||||
<span className="px-1.5 py-0.5 text-xs font-mono bg-[#333] text-gray-500 rounded" title="Toggle debug panel">
|
||||
<span className="px-1.5 py-0.5 text-xs font-mono bg-[var(--color-neo-card)] text-[var(--color-neo-text-muted)] rounded" title="Toggle debug panel">
|
||||
D
|
||||
</span>
|
||||
</button>
|
||||
@@ -351,14 +351,14 @@ export function DebugLogViewer({
|
||||
}}
|
||||
className={`flex items-center gap-1.5 px-3 py-1 text-xs font-mono rounded transition-colors ${
|
||||
activeTab === 'agent'
|
||||
? 'bg-[#333] text-white'
|
||||
: 'text-gray-400 hover:text-white hover:bg-[#2a2a2a]'
|
||||
? 'bg-[var(--color-neo-card)] text-[var(--color-neo-text)]'
|
||||
: 'text-[var(--color-neo-text-muted)] hover:text-[var(--color-neo-text)] hover:bg-[var(--color-neo-hover-subtle)]'
|
||||
}`}
|
||||
>
|
||||
<Cpu size={12} />
|
||||
Agent
|
||||
{logs.length > 0 && (
|
||||
<span className="px-1.5 py-0.5 text-[10px] bg-[#444] rounded">
|
||||
<span className="px-1.5 py-0.5 text-[10px] bg-[var(--color-neo-text-secondary)] text-[var(--color-neo-bg)] rounded">
|
||||
{logs.length}
|
||||
</span>
|
||||
)}
|
||||
@@ -370,14 +370,14 @@ export function DebugLogViewer({
|
||||
}}
|
||||
className={`flex items-center gap-1.5 px-3 py-1 text-xs font-mono rounded transition-colors ${
|
||||
activeTab === 'devserver'
|
||||
? 'bg-[#333] text-white'
|
||||
: 'text-gray-400 hover:text-white hover:bg-[#2a2a2a]'
|
||||
? 'bg-[var(--color-neo-card)] text-[var(--color-neo-text)]'
|
||||
: 'text-[var(--color-neo-text-muted)] hover:text-[var(--color-neo-text)] hover:bg-[var(--color-neo-hover-subtle)]'
|
||||
}`}
|
||||
>
|
||||
<Server size={12} />
|
||||
Dev Server
|
||||
{devLogs.length > 0 && (
|
||||
<span className="px-1.5 py-0.5 text-[10px] bg-[#444] rounded">
|
||||
<span className="px-1.5 py-0.5 text-[10px] bg-[var(--color-neo-text-secondary)] text-[var(--color-neo-bg)] rounded">
|
||||
{devLogs.length}
|
||||
</span>
|
||||
)}
|
||||
@@ -389,13 +389,13 @@ export function DebugLogViewer({
|
||||
}}
|
||||
className={`flex items-center gap-1.5 px-3 py-1 text-xs font-mono rounded transition-colors ${
|
||||
activeTab === 'terminal'
|
||||
? 'bg-[#333] text-white'
|
||||
: 'text-gray-400 hover:text-white hover:bg-[#2a2a2a]'
|
||||
? 'bg-[var(--color-neo-card)] text-[var(--color-neo-text)]'
|
||||
: 'text-[var(--color-neo-text-muted)] hover:text-[var(--color-neo-text)] hover:bg-[var(--color-neo-hover-subtle)]'
|
||||
}`}
|
||||
>
|
||||
<TerminalIcon size={12} />
|
||||
Terminal
|
||||
<span className="px-1.5 py-0.5 text-[10px] bg-[#444] text-gray-500 rounded" title="Toggle terminal">
|
||||
<span className="px-1.5 py-0.5 text-[10px] bg-[var(--color-neo-text-secondary)] text-[var(--color-neo-text-muted)] rounded" title="Toggle terminal">
|
||||
T
|
||||
</span>
|
||||
</button>
|
||||
@@ -406,12 +406,12 @@ export function DebugLogViewer({
|
||||
{isOpen && activeTab !== 'terminal' && (
|
||||
<>
|
||||
{getCurrentLogCount() > 0 && (
|
||||
<span className="px-2 py-0.5 text-xs font-mono bg-[#333] text-gray-300 rounded ml-2">
|
||||
<span className="px-2 py-0.5 text-xs font-mono bg-[var(--color-neo-card)] text-[var(--color-neo-text-secondary)] rounded ml-2">
|
||||
{getCurrentLogCount()}
|
||||
</span>
|
||||
)}
|
||||
{isAutoScrollPaused() && (
|
||||
<span className="px-2 py-0.5 text-xs font-mono bg-yellow-600 text-white rounded">
|
||||
<span className="px-2 py-0.5 text-xs font-mono bg-[var(--color-neo-pending)] text-[var(--color-neo-text-on-bright)] rounded">
|
||||
Paused
|
||||
</span>
|
||||
)}
|
||||
@@ -427,17 +427,17 @@ export function DebugLogViewer({
|
||||
e.stopPropagation()
|
||||
handleClear()
|
||||
}}
|
||||
className="p-1.5 hover:bg-[#333] rounded transition-colors"
|
||||
className="p-1.5 hover:bg-[var(--color-neo-hover-subtle)] rounded transition-colors"
|
||||
title="Clear logs"
|
||||
>
|
||||
<Trash2 size={14} className="text-gray-400" />
|
||||
<Trash2 size={14} className="text-[var(--color-neo-text-muted)]" />
|
||||
</button>
|
||||
)}
|
||||
<div className="p-1">
|
||||
{isOpen ? (
|
||||
<ChevronDown size={16} className="text-gray-400" />
|
||||
<ChevronDown size={16} className="text-[var(--color-neo-text-muted)]" />
|
||||
) : (
|
||||
<ChevronUp size={16} className="text-gray-400" />
|
||||
<ChevronUp size={16} className="text-[var(--color-neo-text-muted)]" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -445,7 +445,7 @@ export function DebugLogViewer({
|
||||
|
||||
{/* Content area */}
|
||||
{isOpen && (
|
||||
<div className="h-[calc(100%-2.5rem)] bg-[#1a1a1a]">
|
||||
<div className="h-[calc(100%-2.5rem)] bg-[var(--color-neo-border)]">
|
||||
{/* Agent Logs Tab */}
|
||||
{activeTab === 'agent' && (
|
||||
<div
|
||||
@@ -454,7 +454,7 @@ export function DebugLogViewer({
|
||||
className="h-full overflow-y-auto p-2 font-mono text-sm"
|
||||
>
|
||||
{logs.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-full text-gray-500">
|
||||
<div className="flex items-center justify-center h-full text-[var(--color-neo-text-muted)]">
|
||||
No logs yet. Start the agent to see output.
|
||||
</div>
|
||||
) : (
|
||||
@@ -467,9 +467,9 @@ export function DebugLogViewer({
|
||||
return (
|
||||
<div
|
||||
key={`${log.timestamp}-${index}`}
|
||||
className="flex gap-2 hover:bg-[#2a2a2a] px-1 py-0.5 rounded"
|
||||
className="flex gap-2 hover:bg-[var(--color-neo-hover-subtle)] px-1 py-0.5 rounded"
|
||||
>
|
||||
<span className="text-gray-500 select-none shrink-0">
|
||||
<span className="text-[var(--color-neo-text-muted)] select-none shrink-0">
|
||||
{timestamp}
|
||||
</span>
|
||||
<span className={`${colorClass} whitespace-pre-wrap break-all`}>
|
||||
@@ -491,7 +491,7 @@ export function DebugLogViewer({
|
||||
className="h-full overflow-y-auto p-2 font-mono text-sm"
|
||||
>
|
||||
{devLogs.length === 0 ? (
|
||||
<div className="flex items-center justify-center h-full text-gray-500">
|
||||
<div className="flex items-center justify-center h-full text-[var(--color-neo-text-muted)]">
|
||||
No dev server logs yet.
|
||||
</div>
|
||||
) : (
|
||||
@@ -504,9 +504,9 @@ export function DebugLogViewer({
|
||||
return (
|
||||
<div
|
||||
key={`${log.timestamp}-${index}`}
|
||||
className="flex gap-2 hover:bg-[#2a2a2a] px-1 py-0.5 rounded"
|
||||
className="flex gap-2 hover:bg-[var(--color-neo-hover-subtle)] px-1 py-0.5 rounded"
|
||||
>
|
||||
<span className="text-gray-500 select-none shrink-0">
|
||||
<span className="text-[var(--color-neo-text-muted)] select-none shrink-0">
|
||||
{timestamp}
|
||||
</span>
|
||||
<span className={`${colorClass} whitespace-pre-wrap break-all`}>
|
||||
@@ -538,11 +538,11 @@ export function DebugLogViewer({
|
||||
{/* Terminal content - render all terminals and show/hide to preserve buffers */}
|
||||
<div className="flex-1 min-h-0 relative">
|
||||
{isLoadingTerminals ? (
|
||||
<div className="h-full flex items-center justify-center text-gray-500 font-mono text-sm">
|
||||
<div className="h-full flex items-center justify-center text-[var(--color-neo-text-muted)] font-mono text-sm">
|
||||
Loading terminals...
|
||||
</div>
|
||||
) : terminals.length === 0 ? (
|
||||
<div className="h-full flex items-center justify-center text-gray-500 font-mono text-sm">
|
||||
<div className="h-full flex items-center justify-center text-[var(--color-neo-text-muted)] font-mono text-sm">
|
||||
No terminal available
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -92,7 +92,7 @@ export function DevServerControl({ projectName, status, url }: DevServerControlP
|
||||
className="neo-btn text-sm py-2 px-3"
|
||||
style={isCrashed ? {
|
||||
backgroundColor: 'var(--color-neo-danger)',
|
||||
color: '#ffffff',
|
||||
color: 'var(--color-neo-text-on-bright)',
|
||||
} : undefined}
|
||||
title={isCrashed ? "Dev Server Crashed - Click to Restart" : "Start Dev Server"}
|
||||
aria-label={isCrashed ? "Restart Dev Server (crashed)" : "Start Dev Server"}
|
||||
@@ -112,7 +112,7 @@ export function DevServerControl({ projectName, status, url }: DevServerControlP
|
||||
className="neo-btn text-sm py-2 px-3"
|
||||
style={{
|
||||
backgroundColor: 'var(--color-neo-progress)',
|
||||
color: '#ffffff',
|
||||
color: 'var(--color-neo-text-on-bright)',
|
||||
}}
|
||||
title="Stop Dev Server"
|
||||
aria-label="Stop Dev Server"
|
||||
@@ -134,7 +134,7 @@ export function DevServerControl({ projectName, status, url }: DevServerControlP
|
||||
className="neo-btn text-sm py-2 px-3 gap-1"
|
||||
style={{
|
||||
backgroundColor: 'var(--color-neo-progress)',
|
||||
color: '#ffffff',
|
||||
color: 'var(--color-neo-text-on-bright)',
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
title={`Open ${url} in new tab`}
|
||||
|
||||
@@ -105,13 +105,13 @@ export function EditFeatureForm({ feature, projectName, onClose, onSaved }: Edit
|
||||
<form onSubmit={handleSubmit} className="p-6 space-y-4">
|
||||
{/* Error Message */}
|
||||
{error && (
|
||||
<div className="flex items-center gap-3 p-4 bg-[var(--color-neo-danger)] text-white border-3 border-[var(--color-neo-border)]">
|
||||
<div className="flex items-center gap-3 p-4 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] border-3 border-[var(--color-neo-error-border)]">
|
||||
<AlertCircle size={20} />
|
||||
<span>{error}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setError(null)}
|
||||
className="ml-auto"
|
||||
className="ml-auto hover:opacity-70 transition-opacity"
|
||||
>
|
||||
<X size={16} />
|
||||
</button>
|
||||
@@ -184,8 +184,11 @@ export function EditFeatureForm({ feature, projectName, onClose, onSaved }: Edit
|
||||
</label>
|
||||
<div className="space-y-2">
|
||||
{steps.map((step, index) => (
|
||||
<div key={step.id} className="flex gap-2">
|
||||
<span className="neo-input w-12 text-center flex-shrink-0 flex items-center justify-center">
|
||||
<div key={step.id} className="flex gap-2 items-center">
|
||||
<span
|
||||
className="w-10 h-10 flex-shrink-0 flex items-center justify-center font-mono font-bold text-sm border-3 border-[var(--color-neo-border)] bg-[var(--color-neo-bg)] text-[var(--color-neo-text-secondary)]"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
{index + 1}
|
||||
</span>
|
||||
<input
|
||||
|
||||
@@ -152,28 +152,28 @@ export function ExpandProjectChat({
|
||||
switch (connectionStatus) {
|
||||
case 'connected':
|
||||
return (
|
||||
<span className="flex items-center gap-1 text-xs text-[var(--color-neo-done)]">
|
||||
<span className="flex items-center gap-1 text-xs text-neo-done">
|
||||
<Wifi size={12} />
|
||||
Connected
|
||||
</span>
|
||||
)
|
||||
case 'connecting':
|
||||
return (
|
||||
<span className="flex items-center gap-1 text-xs text-[var(--color-neo-pending)]">
|
||||
<span className="flex items-center gap-1 text-xs text-neo-pending">
|
||||
<Wifi size={12} className="animate-pulse" />
|
||||
Connecting...
|
||||
</span>
|
||||
)
|
||||
case 'error':
|
||||
return (
|
||||
<span className="flex items-center gap-1 text-xs text-[var(--color-neo-danger)]">
|
||||
<span className="flex items-center gap-1 text-xs text-neo-danger">
|
||||
<WifiOff size={12} />
|
||||
Error
|
||||
</span>
|
||||
)
|
||||
default:
|
||||
return (
|
||||
<span className="flex items-center gap-1 text-xs text-[var(--color-neo-text-secondary)]">
|
||||
<span className="flex items-center gap-1 text-xs text-neo-text-secondary">
|
||||
<WifiOff size={12} />
|
||||
Disconnected
|
||||
</span>
|
||||
@@ -182,16 +182,16 @@ export function ExpandProjectChat({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full bg-[var(--color-neo-bg)]">
|
||||
<div className="flex flex-col h-full bg-neo-bg">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b-3 border-[var(--color-neo-border)] bg-white">
|
||||
<div className="flex items-center justify-between p-4 border-b-3 border-neo-border bg-neo-card">
|
||||
<div className="flex items-center gap-3">
|
||||
<h2 className="font-display font-bold text-lg text-[#1a1a1a]">
|
||||
<h2 className="font-display font-bold text-lg text-neo-text">
|
||||
Expand Project: {projectName}
|
||||
</h2>
|
||||
<ConnectionIndicator />
|
||||
{featuresCreated > 0 && (
|
||||
<span className="flex items-center gap-1 text-sm text-[var(--color-neo-done)] font-bold">
|
||||
<span className="flex items-center gap-1 text-sm text-neo-done font-bold">
|
||||
<Plus size={14} />
|
||||
{featuresCreated} added
|
||||
</span>
|
||||
@@ -200,7 +200,7 @@ export function ExpandProjectChat({
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{isComplete && (
|
||||
<span className="flex items-center gap-1 text-sm text-[var(--color-neo-done)] font-bold">
|
||||
<span className="flex items-center gap-1 text-sm text-neo-done font-bold">
|
||||
<CheckCircle2 size={16} />
|
||||
Complete
|
||||
</span>
|
||||
@@ -218,12 +218,12 @@ export function ExpandProjectChat({
|
||||
|
||||
{/* Error banner */}
|
||||
{error && (
|
||||
<div className="flex items-center gap-2 p-3 bg-[var(--color-neo-danger)] text-white border-b-3 border-[var(--color-neo-border)]">
|
||||
<div className="flex items-center gap-2 p-3 bg-neo-error-bg text-neo-error-text border-b-3 border-neo-error-border">
|
||||
<AlertCircle size={16} />
|
||||
<span className="flex-1 text-sm">{error}</span>
|
||||
<button
|
||||
onClick={() => setError(null)}
|
||||
className="p-1 hover:bg-white/20 rounded"
|
||||
className="p-1 hover:opacity-70 transition-opacity rounded"
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
@@ -238,7 +238,7 @@ export function ExpandProjectChat({
|
||||
<h3 className="font-display font-bold text-lg mb-2">
|
||||
Starting Project Expansion
|
||||
</h3>
|
||||
<p className="text-sm text-[var(--color-neo-text-secondary)]">
|
||||
<p className="text-sm text-neo-text-secondary">
|
||||
Connecting to Claude to help you add new features to your project...
|
||||
</p>
|
||||
{connectionStatus === 'error' && (
|
||||
@@ -268,7 +268,7 @@ export function ExpandProjectChat({
|
||||
{/* Input area */}
|
||||
{!isComplete && (
|
||||
<div
|
||||
className="p-4 border-t-3 border-[var(--color-neo-border)] bg-white"
|
||||
className="p-4 border-t-3 border-neo-border bg-neo-card"
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
>
|
||||
@@ -278,7 +278,8 @@ export function ExpandProjectChat({
|
||||
{pendingAttachments.map((attachment) => (
|
||||
<div
|
||||
key={attachment.id}
|
||||
className="relative group border-2 border-[var(--color-neo-border)] p-1 bg-white shadow-[2px_2px_0px_rgba(0,0,0,1)]"
|
||||
className="relative group border-2 border-neo-border p-1 bg-neo-card"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<img
|
||||
src={attachment.previewUrl}
|
||||
@@ -287,7 +288,7 @@ export function ExpandProjectChat({
|
||||
/>
|
||||
<button
|
||||
onClick={() => handleRemoveAttachment(attachment.id)}
|
||||
className="absolute -top-2 -right-2 bg-[var(--color-neo-danger)] text-white rounded-full p-0.5 border-2 border-[var(--color-neo-border)] hover:scale-110 transition-transform"
|
||||
className="absolute -top-2 -right-2 bg-neo-danger text-neo-text-on-bright rounded-full p-0.5 border-2 border-neo-border hover:scale-110 transition-transform"
|
||||
title="Remove attachment"
|
||||
>
|
||||
<X size={12} />
|
||||
@@ -351,7 +352,7 @@ export function ExpandProjectChat({
|
||||
</div>
|
||||
|
||||
{/* Help text */}
|
||||
<p className="text-xs text-[var(--color-neo-text-secondary)] mt-2">
|
||||
<p className="text-xs text-neo-text-secondary mt-2">
|
||||
Press Enter to send. Drag & drop or click <Paperclip size={12} className="inline" /> to attach images.
|
||||
</p>
|
||||
</div>
|
||||
@@ -359,7 +360,7 @@ export function ExpandProjectChat({
|
||||
|
||||
{/* Completion footer */}
|
||||
{isComplete && (
|
||||
<div className="p-4 border-t-3 border-[var(--color-neo-border)] bg-[var(--color-neo-done)]">
|
||||
<div className="p-4 border-t-3 border-neo-border bg-neo-done text-neo-text-on-bright">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle2 size={20} />
|
||||
@@ -369,7 +370,7 @@ export function ExpandProjectChat({
|
||||
</div>
|
||||
<button
|
||||
onClick={() => onComplete(featuresCreated)}
|
||||
className="neo-btn bg-white"
|
||||
className="neo-btn bg-neo-card"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
||||
@@ -7,16 +7,17 @@ interface FeatureCardProps {
|
||||
isInProgress?: boolean
|
||||
}
|
||||
|
||||
// Generate consistent color for category
|
||||
// Generate consistent color for category using CSS variable references
|
||||
// These map to the --color-neo-category-* variables defined in globals.css
|
||||
function getCategoryColor(category: string): string {
|
||||
const colors = [
|
||||
'#ff006e', // pink
|
||||
'#00b4d8', // cyan
|
||||
'#70e000', // green
|
||||
'#ffd60a', // yellow
|
||||
'#ff5400', // orange
|
||||
'#8338ec', // purple
|
||||
'#3a86ff', // blue
|
||||
'var(--color-neo-category-pink)',
|
||||
'var(--color-neo-category-cyan)',
|
||||
'var(--color-neo-category-green)',
|
||||
'var(--color-neo-category-yellow)',
|
||||
'var(--color-neo-category-orange)',
|
||||
'var(--color-neo-category-purple)',
|
||||
'var(--color-neo-category-blue)',
|
||||
]
|
||||
|
||||
let hash = 0
|
||||
@@ -36,18 +37,18 @@ export function FeatureCard({ feature, onClick, isInProgress }: FeatureCardProps
|
||||
className={`
|
||||
w-full text-left neo-card p-4 cursor-pointer
|
||||
${isInProgress ? 'animate-pulse-neo' : ''}
|
||||
${feature.passes ? 'border-[var(--color-neo-done)]' : ''}
|
||||
${feature.passes ? 'border-neo-done' : ''}
|
||||
`}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between gap-2 mb-2">
|
||||
<span
|
||||
className="neo-badge"
|
||||
style={{ backgroundColor: categoryColor, color: 'white' }}
|
||||
style={{ backgroundColor: categoryColor, color: 'var(--color-neo-text-on-bright)' }}
|
||||
>
|
||||
{feature.category}
|
||||
</span>
|
||||
<span className="font-mono text-sm text-[var(--color-neo-text-secondary)]">
|
||||
<span className="font-mono text-sm text-neo-text-secondary">
|
||||
#{feature.priority}
|
||||
</span>
|
||||
</div>
|
||||
@@ -58,7 +59,7 @@ export function FeatureCard({ feature, onClick, isInProgress }: FeatureCardProps
|
||||
</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-sm text-[var(--color-neo-text-secondary)] line-clamp-2 mb-3">
|
||||
<p className="text-sm text-neo-text-secondary line-clamp-2 mb-3">
|
||||
{feature.description}
|
||||
</p>
|
||||
|
||||
@@ -66,18 +67,18 @@ export function FeatureCard({ feature, onClick, isInProgress }: FeatureCardProps
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
{isInProgress ? (
|
||||
<>
|
||||
<Loader2 size={16} className="animate-spin text-[var(--color-neo-progress)]" />
|
||||
<span className="text-[var(--color-neo-progress)] font-bold">Processing...</span>
|
||||
<Loader2 size={16} className="animate-spin text-neo-progress" />
|
||||
<span className="text-neo-progress font-bold">Processing...</span>
|
||||
</>
|
||||
) : feature.passes ? (
|
||||
<>
|
||||
<CheckCircle2 size={16} className="text-[var(--color-neo-done)]" />
|
||||
<span className="text-[var(--color-neo-done)] font-bold">Complete</span>
|
||||
<CheckCircle2 size={16} className="text-neo-done" />
|
||||
<span className="text-neo-done font-bold">Complete</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Circle size={16} className="text-[var(--color-neo-text-secondary)]" />
|
||||
<span className="text-[var(--color-neo-text-secondary)]">Pending</span>
|
||||
<Circle size={16} className="text-neo-text-secondary" />
|
||||
<span className="text-neo-text-secondary">Pending</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,26 @@ import { useSkipFeature, useDeleteFeature } from '../hooks/useProjects'
|
||||
import { EditFeatureForm } from './EditFeatureForm'
|
||||
import type { Feature } from '../lib/types'
|
||||
|
||||
// Generate consistent color for category (matches FeatureCard pattern)
|
||||
function getCategoryColor(category: string): string {
|
||||
const colors = [
|
||||
'#ff006e', // pink (accent)
|
||||
'#00b4d8', // cyan (progress)
|
||||
'#70e000', // green (done)
|
||||
'#ffd60a', // yellow (pending)
|
||||
'#ff5400', // orange (danger)
|
||||
'#8338ec', // purple
|
||||
'#3a86ff', // blue
|
||||
]
|
||||
|
||||
let hash = 0
|
||||
for (let i = 0; i < category.length; i++) {
|
||||
hash = category.charCodeAt(i) + ((hash << 5) - hash)
|
||||
}
|
||||
|
||||
return colors[Math.abs(hash) % colors.length]
|
||||
}
|
||||
|
||||
interface FeatureModalProps {
|
||||
feature: Feature
|
||||
projectName: string
|
||||
@@ -59,7 +79,10 @@ export function FeatureModal({ feature, projectName, onClose }: FeatureModalProp
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between p-6 border-b-3 border-[var(--color-neo-border)]">
|
||||
<div>
|
||||
<span className="neo-badge bg-[var(--color-neo-accent)] text-white mb-2">
|
||||
<span
|
||||
className="neo-badge mb-2"
|
||||
style={{ backgroundColor: getCategoryColor(feature.category), color: 'var(--color-neo-text-on-bright)' }}
|
||||
>
|
||||
{feature.category}
|
||||
</span>
|
||||
<h2 className="font-display text-2xl font-bold">
|
||||
@@ -78,12 +101,12 @@ export function FeatureModal({ feature, projectName, onClose }: FeatureModalProp
|
||||
<div className="p-6 space-y-6">
|
||||
{/* Error Message */}
|
||||
{error && (
|
||||
<div className="flex items-center gap-3 p-4 bg-[var(--color-neo-danger)] text-white border-3 border-[var(--color-neo-border)]">
|
||||
<div className="flex items-center gap-3 p-4 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] border-3 border-[var(--color-neo-error-border)]">
|
||||
<AlertCircle size={20} />
|
||||
<span>{error}</span>
|
||||
<button
|
||||
onClick={() => setError(null)}
|
||||
className="ml-auto"
|
||||
className="ml-auto hover:opacity-70 transition-opacity"
|
||||
>
|
||||
<X size={16} />
|
||||
</button>
|
||||
|
||||
@@ -139,10 +139,10 @@ export function FolderBrowser({ onSelect, onCancel, initialPath }: FolderBrowser
|
||||
return (
|
||||
<div className="flex flex-col h-full max-h-[70vh]">
|
||||
{/* Header with breadcrumb navigation */}
|
||||
<div className="flex-shrink-0 p-4 border-b-3 border-[var(--color-neo-border)] bg-white">
|
||||
<div className="flex-shrink-0 p-4 border-b-3 border-[var(--color-neo-border)] bg-[var(--color-neo-card)]">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Folder size={20} className="text-[var(--color-neo-progress)]" />
|
||||
<span className="font-bold text-[#1a1a1a]">Select Project Folder</span>
|
||||
<span className="font-bold text-[var(--color-neo-text)]">Select Project Folder</span>
|
||||
</div>
|
||||
|
||||
{/* Breadcrumb navigation */}
|
||||
@@ -159,11 +159,11 @@ export function FolderBrowser({ onSelect, onCancel, initialPath }: FolderBrowser
|
||||
|
||||
{breadcrumbs.map((crumb, index) => (
|
||||
<div key={crumb.path} className="flex items-center">
|
||||
{index > 0 && <ChevronRight size={14} className="text-gray-400 mx-1" />}
|
||||
{index > 0 && <ChevronRight size={14} className="text-[var(--color-neo-text-muted)] mx-1" />}
|
||||
<button
|
||||
onClick={() => handleNavigate(crumb.path)}
|
||||
className={`
|
||||
px-2 py-1 rounded text-[#1a1a1a]
|
||||
px-2 py-1 rounded text-[var(--color-neo-text)]
|
||||
hover:bg-[var(--color-neo-bg)]
|
||||
${index === breadcrumbs.length - 1 ? 'font-bold' : ''}
|
||||
`}
|
||||
@@ -187,7 +187,7 @@ export function FolderBrowser({ onSelect, onCancel, initialPath }: FolderBrowser
|
||||
className={`
|
||||
neo-btn neo-btn-ghost py-1 px-2 text-sm
|
||||
flex items-center gap-1
|
||||
${currentPath?.startsWith(drive.letter) ? 'bg-[var(--color-neo-progress)] text-white' : ''}
|
||||
${currentPath?.startsWith(drive.letter) ? 'bg-[var(--color-neo-progress)] text-[var(--color-neo-text-on-bright)]' : ''}
|
||||
`}
|
||||
>
|
||||
<HardDrive size={14} />
|
||||
@@ -199,7 +199,7 @@ export function FolderBrowser({ onSelect, onCancel, initialPath }: FolderBrowser
|
||||
)}
|
||||
|
||||
{/* Directory listing */}
|
||||
<div className="flex-1 overflow-y-auto p-2 bg-white">
|
||||
<div className="flex-1 overflow-y-auto p-2 bg-[var(--color-neo-card)]">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<Loader2 size={24} className="animate-spin text-[var(--color-neo-progress)]" />
|
||||
@@ -238,9 +238,9 @@ export function FolderBrowser({ onSelect, onCancel, initialPath }: FolderBrowser
|
||||
) : (
|
||||
<Folder size={18} className="text-[var(--color-neo-pending)] flex-shrink-0" />
|
||||
)}
|
||||
<span className="truncate flex-1 text-[#1a1a1a]">{entry.name}</span>
|
||||
<span className="truncate flex-1 text-[var(--color-neo-text)]">{entry.name}</span>
|
||||
{entry.has_children && (
|
||||
<ChevronRight size={14} className="ml-auto text-gray-400 flex-shrink-0" />
|
||||
<ChevronRight size={14} className="ml-auto text-[var(--color-neo-text-muted)] flex-shrink-0" />
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
@@ -299,11 +299,11 @@ export function FolderBrowser({ onSelect, onCancel, initialPath }: FolderBrowser
|
||||
</div>
|
||||
|
||||
{/* Footer with selected path and actions */}
|
||||
<div className="flex-shrink-0 p-4 border-t-3 border-[var(--color-neo-border)] bg-white">
|
||||
<div className="flex-shrink-0 p-4 border-t-3 border-[var(--color-neo-border)] bg-[var(--color-neo-card)]">
|
||||
{/* Selected path display */}
|
||||
<div className="mb-3 p-2 bg-[var(--color-neo-bg)] rounded border-2 border-[var(--color-neo-border)]">
|
||||
<div className="text-xs text-[#4a4a4a] mb-1">Selected path:</div>
|
||||
<div className="font-mono text-sm truncate text-[#1a1a1a]">{selectedPath || 'No folder selected'}</div>
|
||||
<div className="text-xs text-[var(--color-neo-text-secondary)] mb-1">Selected path:</div>
|
||||
<div className="font-mono text-sm truncate text-[var(--color-neo-text)]">{selectedPath || 'No folder selected'}</div>
|
||||
{selectedPath && (
|
||||
<div className="text-xs text-[var(--color-neo-text-secondary)] mt-2 italic">
|
||||
This folder will contain all project files
|
||||
|
||||
@@ -40,9 +40,9 @@ export function KanbanColumn({
|
||||
style={{ backgroundColor: colorMap[color] }}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="font-display text-lg font-bold uppercase flex items-center gap-2 text-[var(--color-neo-text)]">
|
||||
<h2 className="font-display text-lg font-bold uppercase flex items-center gap-2 text-[var(--color-neo-text-on-bright)]">
|
||||
{title}
|
||||
<span className="neo-badge bg-white text-[var(--color-neo-text)]">{count}</span>
|
||||
<span className="neo-badge bg-[var(--color-neo-card)] text-[var(--color-neo-text)]">{count}</span>
|
||||
</h2>
|
||||
{(onAddFeature || onExpandProject) && (
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -58,7 +58,7 @@ export function KanbanColumn({
|
||||
{onExpandProject && showExpandButton && (
|
||||
<button
|
||||
onClick={onExpandProject}
|
||||
className="neo-btn bg-[var(--color-neo-progress)] text-black text-sm py-1.5 px-2"
|
||||
className="neo-btn bg-[var(--color-neo-progress)] text-[var(--color-neo-text-on-bright)] text-sm py-1.5 px-2"
|
||||
title="Expand project with AI (E)"
|
||||
>
|
||||
<Sparkles size={16} />
|
||||
|
||||
@@ -212,10 +212,10 @@ export function NewProjectModal({
|
||||
<div className="flex items-center gap-3">
|
||||
<Folder size={24} className="text-[var(--color-neo-progress)]" />
|
||||
<div>
|
||||
<h2 className="font-display font-bold text-xl text-[#1a1a1a]">
|
||||
<h2 className="font-display font-bold text-xl text-[var(--color-neo-text)]">
|
||||
Select Project Location
|
||||
</h2>
|
||||
<p className="text-sm text-[#4a4a4a]">
|
||||
<p className="text-sm text-[var(--color-neo-text-secondary)]">
|
||||
Select the folder to use for project <span className="font-bold font-mono">{projectName}</span>. Create a new folder or choose an existing one.
|
||||
</p>
|
||||
</div>
|
||||
@@ -248,7 +248,7 @@ export function NewProjectModal({
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b-3 border-[var(--color-neo-border)]">
|
||||
<h2 className="font-display font-bold text-xl text-[#1a1a1a]">
|
||||
<h2 className="font-display font-bold text-xl text-[var(--color-neo-text)]">
|
||||
{step === 'name' && 'Create New Project'}
|
||||
{step === 'method' && 'Choose Setup Method'}
|
||||
{step === 'complete' && 'Project Created!'}
|
||||
@@ -267,7 +267,7 @@ export function NewProjectModal({
|
||||
{step === 'name' && (
|
||||
<form onSubmit={handleNameSubmit}>
|
||||
<div className="mb-6">
|
||||
<label className="block font-bold mb-2 text-[#1a1a1a]">
|
||||
<label className="block font-bold mb-2 text-[var(--color-neo-text)]">
|
||||
Project Name
|
||||
</label>
|
||||
<input
|
||||
@@ -285,7 +285,7 @@ export function NewProjectModal({
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="mb-4 p-3 bg-[var(--color-neo-danger)] text-white text-sm border-2 border-[var(--color-neo-border)]">
|
||||
<div className="mb-4 p-3 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] text-sm border-3 border-[var(--color-neo-error-border)]">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -315,25 +315,27 @@ export function NewProjectModal({
|
||||
<button
|
||||
onClick={() => handleMethodSelect('claude')}
|
||||
disabled={createProject.isPending}
|
||||
className={`
|
||||
className="
|
||||
w-full text-left p-4
|
||||
border-3 border-[var(--color-neo-border)]
|
||||
bg-white
|
||||
shadow-[4px_4px_0px_rgba(0,0,0,1)]
|
||||
bg-[var(--color-neo-card)]
|
||||
hover:translate-x-[-2px] hover:translate-y-[-2px]
|
||||
hover:shadow-[6px_6px_0px_rgba(0,0,0,1)]
|
||||
transition-all duration-150
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
`}
|
||||
neo-card
|
||||
"
|
||||
>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="p-2 bg-[var(--color-neo-progress)] border-2 border-[var(--color-neo-border)] shadow-[2px_2px_0px_rgba(0,0,0,1)]">
|
||||
<Bot size={24} className="text-white" />
|
||||
<div
|
||||
className="p-2 bg-[var(--color-neo-progress)] border-2 border-[var(--color-neo-border)]"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<Bot size={24} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-bold text-lg text-[#1a1a1a]">Create with Claude</span>
|
||||
<span className="neo-badge bg-[var(--color-neo-done)] text-xs">
|
||||
<span className="font-bold text-lg text-[var(--color-neo-text)]">Create with Claude</span>
|
||||
<span className="neo-badge bg-[var(--color-neo-done)] text-[var(--color-neo-text-on-bright)] text-xs">
|
||||
Recommended
|
||||
</span>
|
||||
</div>
|
||||
@@ -348,23 +350,25 @@ export function NewProjectModal({
|
||||
<button
|
||||
onClick={() => handleMethodSelect('manual')}
|
||||
disabled={createProject.isPending}
|
||||
className={`
|
||||
className="
|
||||
w-full text-left p-4
|
||||
border-3 border-[var(--color-neo-border)]
|
||||
bg-white
|
||||
shadow-[4px_4px_0px_rgba(0,0,0,1)]
|
||||
bg-[var(--color-neo-card)]
|
||||
hover:translate-x-[-2px] hover:translate-y-[-2px]
|
||||
hover:shadow-[6px_6px_0px_rgba(0,0,0,1)]
|
||||
transition-all duration-150
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
`}
|
||||
neo-card
|
||||
"
|
||||
>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="p-2 bg-[var(--color-neo-pending)] border-2 border-[var(--color-neo-border)] shadow-[2px_2px_0px_rgba(0,0,0,1)]">
|
||||
<FileEdit size={24} />
|
||||
<div
|
||||
className="p-2 bg-[var(--color-neo-pending)] border-2 border-[var(--color-neo-border)]"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<FileEdit size={24} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<span className="font-bold text-lg text-[#1a1a1a]">Edit Templates Manually</span>
|
||||
<span className="font-bold text-lg text-[var(--color-neo-text)]">Edit Templates Manually</span>
|
||||
<p className="text-sm text-[var(--color-neo-text-secondary)] mt-1">
|
||||
Edit the template files directly. Best for developers who want full control.
|
||||
</p>
|
||||
@@ -374,7 +378,7 @@ export function NewProjectModal({
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="mt-4 p-3 bg-[var(--color-neo-danger)] text-white text-sm border-2 border-[var(--color-neo-border)]">
|
||||
<div className="mt-4 p-3 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] text-sm border-3 border-[var(--color-neo-error-border)]">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -402,8 +406,11 @@ export function NewProjectModal({
|
||||
{/* Step 3: Complete */}
|
||||
{step === 'complete' && (
|
||||
<div className="text-center py-8">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 bg-[var(--color-neo-done)] border-3 border-[var(--color-neo-border)] shadow-[4px_4px_0px_rgba(0,0,0,1)] mb-4">
|
||||
<CheckCircle2 size={32} />
|
||||
<div
|
||||
className="inline-flex items-center justify-center w-16 h-16 bg-[var(--color-neo-done)] border-3 border-[var(--color-neo-border)] mb-4"
|
||||
style={{ boxShadow: 'var(--shadow-neo-md)' }}
|
||||
>
|
||||
<CheckCircle2 size={32} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
</div>
|
||||
<h3 className="font-display font-bold text-xl mb-2">
|
||||
{projectName}
|
||||
|
||||
@@ -36,11 +36,13 @@ export function ProgressDashboard({
|
||||
|
||||
{/* Large Percentage */}
|
||||
<div className="text-center mb-6">
|
||||
<span className="font-display text-6xl font-bold">
|
||||
{percentage.toFixed(1)}
|
||||
</span>
|
||||
<span className="font-display text-3xl font-bold text-[var(--color-neo-text-secondary)]">
|
||||
%
|
||||
<span className="inline-flex items-baseline">
|
||||
<span className="font-display text-6xl font-bold">
|
||||
{percentage.toFixed(1)}
|
||||
</span>
|
||||
<span className="font-display text-3xl font-bold text-[var(--color-neo-text-secondary)]">
|
||||
%
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ export function ProjectSelector({
|
||||
{/* Dropdown Trigger */}
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="neo-btn bg-white text-[var(--color-neo-text)] min-w-[200px] justify-between"
|
||||
className="neo-btn bg-[var(--color-neo-card)] text-[var(--color-neo-text)] min-w-[200px] justify-between"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
@@ -108,7 +108,7 @@ export function ProjectSelector({
|
||||
key={project.name}
|
||||
className={`flex items-center ${
|
||||
project.name === selectedProject
|
||||
? 'bg-[var(--color-neo-pending)]'
|
||||
? 'bg-[var(--color-neo-pending)] text-[var(--color-neo-text-on-bright)]'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -93,11 +93,11 @@ export function QuestionOptions({
|
||||
{questions.map((q, questionIdx) => (
|
||||
<div
|
||||
key={questionIdx}
|
||||
className="neo-card p-4 bg-white"
|
||||
className="neo-card p-4 bg-[var(--color-neo-card)]"
|
||||
>
|
||||
{/* Question header */}
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<span className="neo-badge bg-[var(--color-neo-accent)] text-white">
|
||||
<span className="neo-badge bg-[var(--color-neo-accent)] text-[var(--color-neo-text-on-bright)]">
|
||||
{q.header}
|
||||
</span>
|
||||
<span className="font-bold text-[var(--color-neo-text)]">
|
||||
@@ -126,11 +126,24 @@ export function QuestionOptions({
|
||||
transition-all duration-150
|
||||
${
|
||||
isSelected
|
||||
? 'bg-[var(--color-neo-pending)] shadow-[2px_2px_0px_rgba(0,0,0,1)] translate-x-[1px] translate-y-[1px]'
|
||||
: 'bg-white shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:translate-x-[-1px] hover:translate-y-[-1px] hover:shadow-[5px_5px_0px_rgba(0,0,0,1)]'
|
||||
? 'bg-[var(--color-neo-pending)] translate-x-[1px] translate-y-[1px]'
|
||||
: 'bg-[var(--color-neo-card)] hover:translate-x-[-1px] hover:translate-y-[-1px]'
|
||||
}
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
`}
|
||||
style={{
|
||||
boxShadow: isSelected ? 'var(--shadow-neo-sm)' : 'var(--shadow-neo-md)',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (!isSelected && !disabled) {
|
||||
e.currentTarget.style.boxShadow = 'var(--shadow-neo-lg)'
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (!isSelected && !disabled) {
|
||||
e.currentTarget.style.boxShadow = 'var(--shadow-neo-md)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start gap-2">
|
||||
{/* Checkbox/Radio indicator */}
|
||||
@@ -140,7 +153,7 @@ export function QuestionOptions({
|
||||
border-2 border-[var(--color-neo-border)]
|
||||
flex items-center justify-center
|
||||
${q.multiSelect ? '' : 'rounded-full'}
|
||||
${isSelected ? 'bg-[var(--color-neo-done)]' : 'bg-white'}
|
||||
${isSelected ? 'bg-[var(--color-neo-done)]' : 'bg-[var(--color-neo-card)]'}
|
||||
`}
|
||||
>
|
||||
{isSelected && <Check size={12} strokeWidth={3} />}
|
||||
@@ -169,11 +182,24 @@ export function QuestionOptions({
|
||||
transition-all duration-150
|
||||
${
|
||||
showCustomInput[String(questionIdx)]
|
||||
? 'bg-[var(--color-neo-pending)] shadow-[2px_2px_0px_rgba(0,0,0,1)] translate-x-[1px] translate-y-[1px]'
|
||||
: 'bg-white shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:translate-x-[-1px] hover:translate-y-[-1px] hover:shadow-[5px_5px_0px_rgba(0,0,0,1)]'
|
||||
? 'bg-[var(--color-neo-pending)] translate-x-[1px] translate-y-[1px]'
|
||||
: 'bg-[var(--color-neo-card)] hover:translate-x-[-1px] hover:translate-y-[-1px]'
|
||||
}
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
`}
|
||||
style={{
|
||||
boxShadow: showCustomInput[String(questionIdx)] ? 'var(--shadow-neo-sm)' : 'var(--shadow-neo-md)',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (!showCustomInput[String(questionIdx)] && !disabled) {
|
||||
e.currentTarget.style.boxShadow = 'var(--shadow-neo-lg)'
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (!showCustomInput[String(questionIdx)] && !disabled) {
|
||||
e.currentTarget.style.boxShadow = 'var(--shadow-neo-md)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start gap-2">
|
||||
<div
|
||||
@@ -182,7 +208,7 @@ export function QuestionOptions({
|
||||
border-2 border-[var(--color-neo-border)]
|
||||
flex items-center justify-center
|
||||
${q.multiSelect ? '' : 'rounded-full'}
|
||||
${showCustomInput[String(questionIdx)] ? 'bg-[var(--color-neo-done)]' : 'bg-white'}
|
||||
${showCustomInput[String(questionIdx)] ? 'bg-[var(--color-neo-done)]' : 'bg-[var(--color-neo-card)]'}
|
||||
`}
|
||||
>
|
||||
{showCustomInput[String(questionIdx)] && <Check size={12} strokeWidth={3} />}
|
||||
|
||||
@@ -115,14 +115,14 @@ export function SettingsModal({ onClose }: SettingsModalProps) {
|
||||
|
||||
{/* Error State */}
|
||||
{isError && (
|
||||
<div className="p-4 bg-[var(--color-neo-danger)] text-white border-3 border-[var(--color-neo-border)] mb-4">
|
||||
<div className="p-4 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] border-3 border-[var(--color-neo-error-border)] mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertCircle size={18} />
|
||||
<span>Failed to load settings</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => refetch()}
|
||||
className="mt-2 underline text-sm"
|
||||
className="mt-2 underline text-sm hover:opacity-70 transition-opacity"
|
||||
>
|
||||
Retry
|
||||
</button>
|
||||
@@ -152,7 +152,7 @@ export function SettingsModal({ onClose }: SettingsModalProps) {
|
||||
className={`relative w-14 h-8 rounded-none border-3 border-[var(--color-neo-border)] transition-colors ${
|
||||
settings.yolo_mode
|
||||
? 'bg-[var(--color-neo-pending)]'
|
||||
: 'bg-white'
|
||||
: 'bg-[var(--color-neo-card)]'
|
||||
} ${isSaving ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
role="switch"
|
||||
aria-checked={settings.yolo_mode}
|
||||
@@ -189,8 +189,8 @@ export function SettingsModal({ onClose }: SettingsModalProps) {
|
||||
aria-checked={settings.model === model.id}
|
||||
className={`flex-1 py-3 px-4 font-display font-bold text-sm transition-colors ${
|
||||
settings.model === model.id
|
||||
? 'bg-[var(--color-neo-accent)] text-white'
|
||||
: 'bg-white text-[var(--color-neo-text)] hover:bg-gray-100'
|
||||
? 'bg-[var(--color-neo-accent)] text-[var(--color-neo-text-on-bright)]'
|
||||
: 'bg-[var(--color-neo-card)] text-[var(--color-neo-text)] hover:bg-[var(--color-neo-hover-subtle)]'
|
||||
} ${isSaving ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
>
|
||||
{model.name}
|
||||
@@ -201,7 +201,7 @@ export function SettingsModal({ onClose }: SettingsModalProps) {
|
||||
|
||||
{/* Update Error */}
|
||||
{updateSettings.isError && (
|
||||
<div className="p-3 bg-red-50 border-3 border-red-200 text-red-700 text-sm">
|
||||
<div className="p-3 bg-[var(--color-neo-error-bg)] border-3 border-[var(--color-neo-error-border)] text-[var(--color-neo-error-text)] text-sm">
|
||||
Failed to save settings. Please try again.
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -108,7 +108,7 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
||||
|
||||
{/* Error Message */}
|
||||
{(healthError || setupError) && (
|
||||
<div className="mt-6 p-4 bg-[var(--color-neo-danger)] text-white border-3 border-[var(--color-neo-border)]">
|
||||
<div className="mt-6 p-4 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] border-3 border-[var(--color-neo-error-border)]">
|
||||
<p className="font-bold mb-2">Setup Error</p>
|
||||
<p className="text-sm">
|
||||
{healthError
|
||||
|
||||
@@ -207,9 +207,9 @@ export function SpecCreationChat({
|
||||
return (
|
||||
<div className="flex flex-col h-full bg-[var(--color-neo-bg)]">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b-3 border-[var(--color-neo-border)] bg-white">
|
||||
<div className="flex items-center justify-between p-4 border-b-3 border-[var(--color-neo-border)] bg-[var(--color-neo-card)]">
|
||||
<div className="flex items-center gap-3">
|
||||
<h2 className="font-display font-bold text-lg text-[#1a1a1a]">
|
||||
<h2 className="font-display font-bold text-lg text-[var(--color-neo-text)]">
|
||||
Create Spec: {projectName}
|
||||
</h2>
|
||||
<ConnectionIndicator />
|
||||
@@ -245,12 +245,12 @@ export function SpecCreationChat({
|
||||
|
||||
{/* Error banner */}
|
||||
{error && (
|
||||
<div className="flex items-center gap-2 p-3 bg-[var(--color-neo-danger)] text-white border-b-3 border-[var(--color-neo-border)]">
|
||||
<div className="flex items-center gap-2 p-3 bg-[var(--color-neo-error-bg)] text-[var(--color-neo-error-text)] border-b-3 border-[var(--color-neo-error-border)]">
|
||||
<AlertCircle size={16} />
|
||||
<span className="flex-1 text-sm">{error}</span>
|
||||
<button
|
||||
onClick={() => setError(null)}
|
||||
className="p-1 hover:bg-white/20 rounded"
|
||||
className="p-1 hover:opacity-70 transition-opacity rounded"
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
@@ -304,7 +304,7 @@ export function SpecCreationChat({
|
||||
{/* Input area */}
|
||||
{!isComplete && (
|
||||
<div
|
||||
className="p-4 border-t-3 border-[var(--color-neo-border)] bg-white"
|
||||
className="p-4 border-t-3 border-[var(--color-neo-border)] bg-[var(--color-neo-card)]"
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
>
|
||||
@@ -314,7 +314,8 @@ export function SpecCreationChat({
|
||||
{pendingAttachments.map((attachment) => (
|
||||
<div
|
||||
key={attachment.id}
|
||||
className="relative group border-2 border-[var(--color-neo-border)] p-1 bg-white shadow-[2px_2px_0px_rgba(0,0,0,1)]"
|
||||
className="relative group border-2 border-[var(--color-neo-border)] p-1 bg-[var(--color-neo-card)]"
|
||||
style={{ boxShadow: 'var(--shadow-neo-sm)' }}
|
||||
>
|
||||
<img
|
||||
src={attachment.previewUrl}
|
||||
@@ -323,7 +324,7 @@ export function SpecCreationChat({
|
||||
/>
|
||||
<button
|
||||
onClick={() => handleRemoveAttachment(attachment.id)}
|
||||
className="absolute -top-2 -right-2 bg-[var(--color-neo-danger)] text-white rounded-full p-0.5 border-2 border-[var(--color-neo-border)] hover:scale-110 transition-transform"
|
||||
className="absolute -top-2 -right-2 bg-[var(--color-neo-danger)] text-[var(--color-neo-text-on-bright)] rounded-full p-0.5 border-2 border-[var(--color-neo-border)] hover:scale-110 transition-transform"
|
||||
title="Remove attachment"
|
||||
>
|
||||
<X size={12} />
|
||||
@@ -409,22 +410,22 @@ export function SpecCreationChat({
|
||||
<div className="flex items-center gap-2">
|
||||
{initializerStatus === 'starting' ? (
|
||||
<>
|
||||
<Loader2 size={20} className="animate-spin" />
|
||||
<span className="font-bold">
|
||||
<Loader2 size={20} className="animate-spin text-[var(--color-neo-text-on-bright)]" />
|
||||
<span className="font-bold text-[var(--color-neo-text-on-bright)]">
|
||||
Starting agent{yoloEnabled ? ' (YOLO mode)' : ''}...
|
||||
</span>
|
||||
</>
|
||||
) : initializerStatus === 'error' ? (
|
||||
<>
|
||||
<AlertCircle size={20} className="text-white" />
|
||||
<span className="font-bold text-white">
|
||||
<AlertCircle size={20} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
<span className="font-bold text-[var(--color-neo-text-on-bright)]">
|
||||
{initializerError || 'Failed to start agent'}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<CheckCircle2 size={20} />
|
||||
<span className="font-bold">Specification created successfully!</span>
|
||||
<CheckCircle2 size={20} className="text-[var(--color-neo-text-on-bright)]" />
|
||||
<span className="font-bold text-[var(--color-neo-text-on-bright)]">Specification created successfully!</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -432,7 +433,7 @@ export function SpecCreationChat({
|
||||
{initializerStatus === 'error' && onRetryInitializer && (
|
||||
<button
|
||||
onClick={onRetryInitializer}
|
||||
className="neo-btn bg-white"
|
||||
className="neo-btn bg-[var(--color-neo-card)]"
|
||||
>
|
||||
<RotateCcw size={14} />
|
||||
Retry
|
||||
@@ -444,7 +445,7 @@ export function SpecCreationChat({
|
||||
<button
|
||||
onClick={() => setYoloEnabled(!yoloEnabled)}
|
||||
className={`neo-btn text-sm py-2 px-3 ${
|
||||
yoloEnabled ? 'neo-btn-warning' : 'bg-white'
|
||||
yoloEnabled ? 'neo-btn-warning' : 'bg-[var(--color-neo-card)]'
|
||||
}`}
|
||||
title="YOLO Mode: Skip testing for rapid prototyping"
|
||||
>
|
||||
|
||||
@@ -165,7 +165,7 @@ export function TerminalTabs({
|
||||
${
|
||||
activeTerminalId === terminal.id
|
||||
? 'bg-neo-progress text-black'
|
||||
: 'bg-[#3a3a3a] text-white hover:bg-[#4a4a4a]'
|
||||
: 'bg-[#3a3a3a] text-white hover:bg-neo-text-secondary'
|
||||
}
|
||||
`}
|
||||
onClick={() => onSelect(terminal.id)}
|
||||
@@ -180,7 +180,7 @@ export function TerminalTabs({
|
||||
onChange={(e) => setEditValue(e.target.value)}
|
||||
onBlur={submitEdit}
|
||||
onKeyDown={handleKeyDown}
|
||||
className="bg-white text-black px-1 py-0 text-sm font-mono border-2 border-black w-24 outline-none"
|
||||
className="bg-neo-card text-neo-text px-1 py-0 text-sm font-mono border-2 border-black w-24 outline-none"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
) : (
|
||||
@@ -212,7 +212,7 @@ export function TerminalTabs({
|
||||
{/* Add new terminal button */}
|
||||
<button
|
||||
onClick={onCreate}
|
||||
className="flex items-center justify-center w-8 h-8 border-2 border-black bg-[#3a3a3a] text-white hover:bg-[#4a4a4a] transition-colors"
|
||||
className="flex items-center justify-center w-8 h-8 border-2 border-black bg-[#3a3a3a] text-white hover:bg-neo-text-secondary transition-colors"
|
||||
title="New terminal"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
@@ -222,8 +222,8 @@ export function TerminalTabs({
|
||||
{contextMenu.visible && (
|
||||
<div
|
||||
ref={contextMenuRef}
|
||||
className="fixed z-50 bg-white border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] py-1 min-w-[120px]"
|
||||
style={{ left: contextMenu.x, top: contextMenu.y }}
|
||||
className="fixed z-50 bg-neo-card border-2 border-[var(--color-neo-border)] py-1 min-w-[120px]"
|
||||
style={{ left: contextMenu.x, top: contextMenu.y, boxShadow: 'var(--shadow-neo-md)' }}
|
||||
>
|
||||
<button
|
||||
onClick={handleContextMenuRename}
|
||||
|
||||
Reference in New Issue
Block a user