Replace hardcoded Tailwind color utilities with semantic CSS variable tokens across 31 files in the FlowPilot, Assistant Chat, and Script Builder feature communities — the areas graphify identified as design-system-free. - text-blue-400 → text-accent, bg-blue-500/10 → bg-accent-dim, border-blue-500/20 → border-accent/20 - text-amber-400 → text-warning, bg-amber-400/10 → bg-warning-dim, border-l-amber-500 → border-l-warning - text-rose-400/500 → text-danger, bg-rose-500/10 → bg-danger-dim - text-emerald-400 → text-success, bg-emerald-500/10 → bg-success-dim, border-l-emerald-500 → border-l-success - bg-white/[0.08] → bg-elevated (opacity hack → semantic surface token) - bg-gradient-to-r from-blue-500 to-blue-400 → bg-accent (no gradient surfaces) - bg-[#60a5fa] → bg-accent (hard-coded hex removed) Also adds graphify-out/ to .gitignore. Theme resilience: accent color has changed twice in 5 weeks. Semantic tokens mean the next change is a 1-line edit in index.css, not 110 grep-and-replace. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
115 lines
3.9 KiB
TypeScript
115 lines
3.9 KiB
TypeScript
import { useEffect, useRef } from 'react'
|
|
import { Bot, User, Loader2 } from 'lucide-react'
|
|
import { cn } from '@/lib/utils'
|
|
import { MarkdownContent } from '@/components/ui/MarkdownContent'
|
|
import { ScriptCodeBlock } from './ScriptCodeBlock'
|
|
import type { ScriptBuilderMessage } from '@/types'
|
|
|
|
interface ScriptBuilderChatProps {
|
|
messages: ScriptBuilderMessage[]
|
|
language: string
|
|
onViewScript: (script: string, filename: string | null) => void
|
|
onSaveScript: () => void
|
|
isLoading: boolean
|
|
}
|
|
|
|
export function ScriptBuilderChat({
|
|
messages,
|
|
language,
|
|
onViewScript,
|
|
onSaveScript,
|
|
isLoading,
|
|
}: ScriptBuilderChatProps) {
|
|
const bottomRef = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
|
|
}, [messages.length, isLoading])
|
|
|
|
if (messages.length === 0 && !isLoading) {
|
|
return (
|
|
<div className="flex-1 flex items-center justify-center p-8">
|
|
<div className="text-center max-w-md">
|
|
<div className="w-14 h-14 rounded-2xl bg-primary flex items-center justify-center mx-auto mb-4">
|
|
<Bot size={28} className="text-white" />
|
|
</div>
|
|
<h2 className="text-lg font-heading font-bold text-foreground mb-2">
|
|
Script Builder
|
|
</h2>
|
|
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
Describe the script you need and AI will generate it for you. You can iterate on the script,
|
|
preview it, and save it to your library.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="flex-1 overflow-y-auto p-4 space-y-4">
|
|
{messages.map((msg, idx) => (
|
|
<div
|
|
key={idx}
|
|
className={cn(
|
|
"flex gap-3",
|
|
msg.role === 'user' ? "justify-end" : "justify-start"
|
|
)}
|
|
>
|
|
{msg.role === 'assistant' && (
|
|
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(96,165,250,0.1)] flex items-center justify-center mt-0.5">
|
|
<Bot size={16} className="text-accent" />
|
|
</div>
|
|
)}
|
|
|
|
<div
|
|
className={cn(
|
|
"max-w-[85%] rounded-xl px-4 py-3 text-sm",
|
|
msg.role === 'user'
|
|
? "bg-[rgba(96,165,250,0.08)] border border-[rgba(96,165,250,0.15)] text-foreground"
|
|
: "card-flat"
|
|
)}
|
|
>
|
|
{msg.role === 'assistant' ? (
|
|
<>
|
|
<MarkdownContent content={msg.content} />
|
|
{msg.script && (
|
|
<ScriptCodeBlock
|
|
script={msg.script}
|
|
filename={msg.script_filename ?? null}
|
|
lineCount={msg.line_count ?? null}
|
|
language={language}
|
|
onViewFull={() => onViewScript(msg.script!, msg.script_filename ?? null)}
|
|
onSave={onSaveScript}
|
|
/>
|
|
)}
|
|
</>
|
|
) : (
|
|
<p className="whitespace-pre-wrap">{msg.content}</p>
|
|
)}
|
|
</div>
|
|
|
|
{msg.role === 'user' && (
|
|
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(255,255,255,0.06)] flex items-center justify-center mt-0.5">
|
|
<User size={16} className="text-muted-foreground" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
|
|
{isLoading && (
|
|
<div className="flex gap-3 justify-start">
|
|
<div className="shrink-0 w-8 h-8 rounded-lg bg-[rgba(96,165,250,0.1)] flex items-center justify-center">
|
|
<Bot size={16} className="text-accent" />
|
|
</div>
|
|
<div className="card-flat rounded-xl px-4 py-3 text-sm flex items-center gap-2">
|
|
<Loader2 size={14} className="animate-spin text-accent" />
|
|
<span className="text-muted-foreground">Generating script...</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div ref={bottomRef} />
|
|
</div>
|
|
)
|
|
}
|