Scope Chat
atroui/scope-chatFreeBlock
AI scoping chat UI. Wire CONTENT.endpoint (Host API).
Install it
npx shadcn@latest add https://atroui.com/r/scope-chat.jsonSource
1"use client"23import { Bot, Loader2, Send, User } from "lucide-react"4import { useState, type FormEvent } from "react"56import { cn } from "@/lib/utils"78/**9 * Scope chat UI shell. Wire CONTENT.endpoint to your AI host API.10 */11const CONTENT = {12 endpoint: "/api/scope",13 placeholder: "Describe the product you want to ship…",14 emptyHint: "Ask for a fixed-scope plan. Host API required for replies.",15 maxMessages: 40,16}1718type Msg = { role: "user" | "assistant"; content: string }1920export function ScopeChat() {21 const [messages, setMessages] = useState<Msg[]>([])22 const [input, setInput] = useState("")23 const [loading, setLoading] = useState(false)24 const [error, setError] = useState<string | null>(null)2526 async function onSubmit(e: FormEvent) {27 e.preventDefault()28 const text = input.trim()29 if (!text || loading) return30 setInput("")31 setError(null)32 const next: Msg[] = [...messages, { role: "user", content: text }].slice(33 -CONTENT.maxMessages34 )35 setMessages(next)36 setLoading(true)37 try {38 const res = await fetch(CONTENT.endpoint, {39 method: "POST",40 headers: { "Content-Type": "application/json" },41 body: JSON.stringify({ messages: next }),42 })43 if (!res.ok) throw new Error(`Request failed (${res.status})`)44 const data = (await res.json()) as { reply?: string }45 setMessages((m) =>46 [47 ...m,48 {49 role: "assistant" as const,50 content: data.reply ?? "No reply from host API.",51 },52 ].slice(-CONTENT.maxMessages)53 )54 } catch (err) {55 setError(err instanceof Error ? err.message : "Request failed")56 } finally {57 setLoading(false)58 }59 }6061 return (62 <div className="flex min-h-[420px] flex-col overflow-hidden rounded-2xl border border-border-subtle bg-card/40">63 <div className="border-b border-border-subtle px-4 py-3">64 <p className="ms-stamp">Scope chat</p>65 <p className="mt-1 text-xs text-muted-foreground">{CONTENT.emptyHint}</p>66 </div>67 <div className="flex-1 space-y-3 overflow-y-auto p-4">68 {messages.length === 0 ? (69 <p className="text-sm text-muted-foreground">{CONTENT.placeholder}</p>70 ) : (71 messages.map((m, i) => (72 <div73 key={`${m.role}-${i}`}74 className={cn(75 "flex gap-2 text-sm",76 m.role === "user" ? "justify-end" : "justify-start"77 )}78// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from atroui
All 81 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analytics Provideranalytics-provider | atroui | Blocks | Free | 1 dep | |
| AR Portfolioar-portfolio | atroui | Blocks | Free | 1 dep | |
| Before / Afterbefore-after-slider | atroui | Blocks | Free | no deps | |
| Calendly Embedcalendly-embed | atroui | Blocks | Free | 1 dep | |
| Changelogchangelog | atroui | Blocks | Free | no deps | |
| Command Menucommand-menu | atroui | Blocks | Free | 4 deps | |
| Contact Formcontact-form | atroui | Blocks | Free | 2 deps | |
| Contextual CTAcontextual-cta | atroui | Blocks | Free | 2 deps |
