- Move new chat button to left side, bookmark button stays on right - Add max-width constraint (75%) to user messages with proper text wrapping - Remove right-align text from user message frames (keep bubbles on right) - Add overflow handling for code blocks in messages - Change scrollbar color from orange to gray in light and dark modes - Fix pill loading animation flicker by initializing pinnedAgents from localStorage - Add 0.2s base delay to pill animations for staggered reveal - Improve Create new button animation: longer duration (0.6s), bouncy scale sequence, easeInOut easing
448 lines
27 KiB
JSON
448 lines
27 KiB
JSON
{
|
||
"meta": {
|
||
"title": "Inspiration Repo Multi-Agent Chat Design DNA",
|
||
"generated": "2025-11-15T01:05:52-07:00",
|
||
"sourceScreens": [
|
||
"public/ui/desktop.png",
|
||
"public/ui/mobile.png",
|
||
"public/ui/chat.png",
|
||
"public/ui/chatinput.png"
|
||
],
|
||
"sourceCode": [
|
||
"src/app/globals.css",
|
||
"src/app/layout.tsx",
|
||
"src/app/page.tsx",
|
||
"src/components/chat-interface.tsx",
|
||
"src/components/agent-selector.tsx",
|
||
"src/components/header.tsx",
|
||
"src/components/markdown-renderer.tsx",
|
||
"src/components/diff-display.tsx",
|
||
"src/components/ui/button.tsx",
|
||
"src/components/ui/dropdown-menu.tsx",
|
||
"src/components/ui/dialog.tsx",
|
||
"src/components/ui/input.tsx"
|
||
],
|
||
"summary": "High-level creative direction that bridges the cinematic mockups with the Tailwind/Radix/Framer code so every contributor can recreate the soft, glassy correspondence room consistently."
|
||
},
|
||
"foundations": {
|
||
"structure": {
|
||
"pageShell": {
|
||
"description": "A full-bleed, gradient washed canvas with radial glows that feel like dawn light spilling into a studio. Implemented with .gallery-shell and body background layers (globals.css:126-205).",
|
||
"layout": "Stage everything inside a centered column capped at max-w-5xl with generous vertical breathing room. Use px-3/py-4 gutters on mobile and sm:px-6/py-6 on desktop (src/app/page.tsx:57-87).",
|
||
"responsive": "At <=639px the shell locks to 100dvh, pads for safe areas, hides scroll bounce, and increases background opacity (globals.css:267-320)."
|
||
},
|
||
"centerPanel": {
|
||
"description": "The glass manuscript that houses both the empty-state hero and the running conversation. It is a rounded-[2.5rem] surface with layered inset shadows (chat-interface.tsx:285-303).",
|
||
"layout": "Use padding px-4 py-8 on phones, sm:px-8 sm:py-10 on desktop. Keep internal content at max-w-[52rem] for text legibility.",
|
||
"responsive": "Mobile overrides tighten the radius to 1.75rem, add warm gradients, and enforce overflow hidden (globals.css:304-333)."
|
||
},
|
||
"heroStage": {
|
||
"description": "The \"hello, user\" marquee introduces the correspondence ritual with oversized type, uppercase prompts, and chip selectors (chat-interface.tsx:382-452).",
|
||
"layout": "Stack hero heading, eyebrow copy, agent chips, and two-column prompt cards with gap-6. Keep hero text centered; chips wrap flexibly.",
|
||
"responsive": "On mobile the hero collapses into vertical cards styled via .mobile-hero-* helpers (globals.css:332-420)."
|
||
},
|
||
"messageFeed": {
|
||
"description": "Scrollable column of chat messages with AnimatePresence transitions and max width of 52rem (chat-interface.tsx:306-381).",
|
||
"layout": "Use space-y-10 between exchanges, align user bubbles to the right, assistant bubbles to the left, and reserve 10rem bottom padding to clear the composer.",
|
||
"responsive": "Mobile feed removes lateral padding and increases bubble radius while maintaining vertical rhythm (globals.css:314-333)."
|
||
},
|
||
"composerDock": {
|
||
"description": "Floated manuscript panel for input, agent selection, and actions (chat-interface.tsx:460-615).",
|
||
"layout": "Width is clamped to 85%/max-w-2xl with p-5 padding. The textarea autosizes up to 224px, and the toolbar flexes between dropdown and actions.",
|
||
"responsive": "max-sm:mobile-composer swaps to a dark, pill-shaped dock with white text and saturated send button (globals.css:498-548)."
|
||
},
|
||
"dialogCanvas": {
|
||
"description": "Palette-shell surfaces establish a museum-like agent picker with swatch cards, blur, and radial tint (agent-selector.tsx:93-165, globals.css:642-782).",
|
||
"layout": "Cards live in a responsive 2-column grid inside a rounded 1.5rem container. Each card includes eyebrow, heading, description, and CTA microcopy.",
|
||
"responsive": "Intersection observer animates cards in sequence; on narrow screens the grid collapses to a single column with intact spacing."
|
||
}
|
||
},
|
||
"spacing": {
|
||
"baseUnit": "4px (Tailwind default) with compositional emphasis on 12px and 16px steps.",
|
||
"scale": {
|
||
"xxs": "4px / 0.25rem – icon padding, divider offsets.",
|
||
"xs": "8px / 0.5rem – tight gaps between labels and icons.",
|
||
"sm": "12px / 0.75rem – message stack gaps, chip gutters.",
|
||
"md": "16px / 1rem – standard padding for cards and prompt buttons.",
|
||
"lg": "24px / 1.5rem – hero spacing, composer internal gutters.",
|
||
"xl": "32px / 2rem – panel padding, hero breathing room.",
|
||
"2xl": "40px / 2.5rem – chat-panel outer padding, manuscript radius curvature.",
|
||
"3xl": "64px / 4rem – stage-level margins around the primary canvas."
|
||
},
|
||
"rules": [
|
||
"Pairs of components should sit on 12px multiples to align with AnimatePresence translate values (15-18px).",
|
||
"Use at least 24px vertical gap between stacked sections (hero -> chips -> prompts) to preserve the airy tone.",
|
||
"Maintain 16px minimum inset around text within pills or cards to keep glyphs from touching the rounded walls.",
|
||
"Composer height changes should never exceed 224px; overflow is hidden to keep the panel silhouette intact."
|
||
]
|
||
},
|
||
"typography": {
|
||
"fonts": {
|
||
"heading": "Playfair Display (var --font-heading, layout.tsx:8-27) – used for hero lines, agent names, dropdown selections.",
|
||
"body": "Space Grotesk (var --font-body) – default for conversational text, chips, and descriptive copy.",
|
||
"mono": "Geist Mono – reserved for Markdown code, diff displays, and subtle tech cues."
|
||
},
|
||
"styles": {
|
||
"hero": "Lowercase Playfair at 3.5rem on mobile up to 7rem on desktop, tracking-tight with drop shadow and animation delay per letter.",
|
||
"eyebrow": "0.6-0.7rem uppercase, 0.35em letter spacing, muted charcoal (#2d2d2d) at 60% opacity.",
|
||
"body": "1rem Space Grotesk at 1.5 line-height inside bubbles, 0.95rem for supportive copy.",
|
||
"bubbleTone": "Assistant replies appear in charcoal/dark foreground; user bubbles lean lighter with slight italic for emphasis when needed.",
|
||
"buttonCaps": "Chips and CTA buttons use 0.55-0.65rem uppercase text with 0.3em tracking to mimic typewritten labels.",
|
||
"monoBlocks": "Markdown code runs at 0.9rem Geist Mono with translucent background capsules."
|
||
},
|
||
"usage": [
|
||
"Always mix serif (guiding voice) and grotesk (utility voice) within the same panel to reinforce the sense of correspondence between eras.",
|
||
"Limit hero headings to sentence case or lowercase to keep the entrance calm; shouty all caps are reserved for micro labels.",
|
||
"Paragraphs should never exceed 75 characters per line; max-w-[52rem] handles this automatically in code."
|
||
]
|
||
},
|
||
"colors": {
|
||
"palette": {
|
||
"burntOrange": "#e67e50 (var --burnt-orange) – glow accents, send button core.",
|
||
"terracotta": "#d87850 (var --terracotta) – secondary CTA backgrounds.",
|
||
"sageConcrete": "#7a8b8b (var --sage-concrete) – assistant bubbles and neutral glass.",
|
||
"charcoalInk": "#2d2d2d (var --charcoal-ink) – primary text, icon strokes.",
|
||
"sandstone": "#f3e8d1 (var --sandstone) – accent highlight and prompt cards.",
|
||
"inkVeil": "#fdf9f4 – used for popovers and base glass fill.",
|
||
"mutedMist": "#cbd2d2 (var --muted) – dividers, placeholders.",
|
||
"destructive": "#b3473b (light) / #ff8f7f (dark) – warning feedback (globals.css:28,66)."
|
||
},
|
||
"semanticUsage": {
|
||
"background": "Dual radial gradients plus a linear haze (globals.css:132-143) to create depth.",
|
||
"foreground": "charcoalInk in light mode, #f6ede0 in dark (globals.css:14-68).",
|
||
"primary": "burntOrange for CTAs, focus rings, and breathing indicator on agent dropdown (agent-picker-prompt).",
|
||
"accent": "Sandstone, used for scroll-reveal cards and hint callouts.",
|
||
"border": "Transparent whites or muted sage at 10-20% opacity to keep edges soft.",
|
||
"popover": "InkVeil with 10-30% opacity for menus and dialogs."
|
||
},
|
||
"gradients": [
|
||
"Background: radial gradient at 20%/80% plus 135° + 180° layers (globals.css:132-140).",
|
||
"Chat panel: from white/0 to white/45 for a frosted look (chat-interface.tsx:285-291).",
|
||
"Agent picker prompt: animated gradient between burnt orange and sage (globals.css:850-874).",
|
||
"Send button (mobile): linear-gradient(135deg, var(--burnt-orange), lighter mix) (globals.css:498-533)."
|
||
],
|
||
"opacityGuidelines": "Typical glass overlays sit between 5% and 45% white/black tint. Buttons lean on 15-30% backgrounds with inset 1px white strokes to read as acrylic."
|
||
},
|
||
"effects": {
|
||
"styleKeywords": [
|
||
"Glassmorphism with inset rim lights.",
|
||
"Soft, shallow depth-of-field shadows (0 15px 35px rgba(45,45,45,0.1)).",
|
||
"Rounded geometry between 1.25rem and 2.75rem.",
|
||
"Backdrops with 12px-18px blur.",
|
||
"Subtle motion (fade-slide 18px, shimmer loaders, Framer spring)."
|
||
],
|
||
"radii": {
|
||
"base": "var(--radius)=0.75rem for inputs.",
|
||
"large": "1.5rem+ for cards, message bubbles, composer.",
|
||
"pill": "999px for chips and icon buttons.",
|
||
"panel": "2.5rem for the chat manuscript."
|
||
},
|
||
"shadows": {
|
||
"surface": "0 15px 35px rgba(45,45,45,0.1) + inset white strokes for light mode (chat-interface.tsx:285).",
|
||
"floatingCTA": "0 10px 25px rgba(0,0,0,0.2) on icon buttons and send button.",
|
||
"dialog": "0 25px 45px rgba(45,45,45,0.25) for palette-shell (globals.css:642-690)."
|
||
},
|
||
"motion": {
|
||
"framerDefaults": "easeOut durations between 0.35s–0.9s; hero letters cascade by 0.05s increments (chat-interface.tsx:390-404).",
|
||
"css": "fade-slide keyframe for scroll-reveal, shimmer for loading indicators, agent-picker-breathe for dropdown prompt."
|
||
},
|
||
"borders": "Use 1px translucent strokes (border-white/15, border-border/30). In dark mode, switch to rgba(255,255,255,0.12). Corners never go sharp."
|
||
},
|
||
"principles": [
|
||
"Treat every interaction like a letter-writing ritual: slow entrances, generous whitespace, serif headings guiding the story.",
|
||
"Never expose raw UI rails—cover them with frosted layers or soft gradients to maintain the dreamy atelier mood.",
|
||
"Accessibility: uphold 4.5:1 contrast for text on glass; dark mode palette already in globals.css:51-84 handles this.",
|
||
"Responsiveness is holistic: rather than shrinking everything, reshape components (mobile-composer, mobile agent chips) to keep the experience bespoke.",
|
||
"Consistency: chip shapes, letter spacing, and radius scale must match across dropdowns, hero chips, and composer controls."
|
||
]
|
||
},
|
||
"components": {
|
||
"AppShell": {
|
||
"role": "Scene-setting background that frames the entire conversation.",
|
||
"structure": "Full viewport div with class gallery-shell, radial gradient layers, ::after glow veil, and isolation to keep blur effects independent.",
|
||
"visuals": {
|
||
"background": "Gradient stack defined in globals.css:132-143.",
|
||
"overlay": "Pseudo-element adds radial highlight at 15%/85% (globals.css:342-352)."
|
||
},
|
||
"states": ["default", "mobile-safe-area", "dark-mode (html.dark)"],
|
||
"responsive": "Switch to fixed-height 100dvh, hide scrollbars, and scale down padding (globals.css:267-333).",
|
||
"codeRefs": [
|
||
"src/app/page.tsx:57-90",
|
||
"src/app/globals.css:255-333"
|
||
]
|
||
},
|
||
"HeroEmptyState": {
|
||
"role": "Welcomes the user before any conversation exists.",
|
||
"structure": "Motion block comprising heroGreeting letters, guidance copy, chip selector, and suggestion grid.",
|
||
"visuals": {
|
||
"text": "Playfair Display 3.5-7rem, text-white/85 + drop shadow.",
|
||
"chips": "Rounded-full borders with two visual states (active vs hover).",
|
||
"suggestions": "Scroll-reveal cards with white/80 backgrounds."
|
||
},
|
||
"states": [
|
||
"default (no messages): show hero, chips, prompts.",
|
||
"agents-loading: display placeholder copy.",
|
||
"agent-selected: highlight active chip with white fill."
|
||
],
|
||
"interactions": "Motion spans animate via Framer, prompt buttons set the composer input, chips trigger handleComposerAgentSelect.",
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:382-452"
|
||
]
|
||
},
|
||
"AgentChip": {
|
||
"role": "Represents each correspondent option both in hero chips and dropdown menu.",
|
||
"structure": "Rounded-full button with uppercase label, 0.35em tracking, px-4 py-2 padding.",
|
||
"visuals": {
|
||
"default": "border-white/10 bg-white/5 text-white/70.",
|
||
"active": "border-white/25 bg-white/25 text-white with shadow.",
|
||
"mobile": "full-width pill (.mobile-agent-chip) with warm white fill (globals.css:399-419)."
|
||
},
|
||
"states": ["default", "hover", "active", "disabled (when agents loading)"],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:406-428",
|
||
"src/app/globals.css:399-419"
|
||
]
|
||
},
|
||
"PromptCard": {
|
||
"role": "One-tap inspiration snippet inside the hero state.",
|
||
"structure": "Rounded-2xl card with border-border/30, white/80 background, p-4 text-left body copy.",
|
||
"states": ["rest", "hover (border-ring/60 + bright background)"],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:435-450"
|
||
]
|
||
},
|
||
"ChatPanel": {
|
||
"role": "Primary conversation container providing the glass manuscript look.",
|
||
"structure": "motion.div with gradient background, px-4/py-8 padding, shadow stack, and rounded-[2.5rem].",
|
||
"visuals": {
|
||
"light": "From white/0 to white/45 fill, inset highlights.",
|
||
"dark": "Transparent to white/20 gradient with deeper drop shadow (chat-interface.tsx:285-291)."
|
||
},
|
||
"states": ["empty (shows hero)", "active conversation (shows feed + toolbar)"],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:285-304"
|
||
]
|
||
},
|
||
"MessageBubble": {
|
||
"role": "Displays user and assistant messages with distinct glass treatments.",
|
||
"structure": "div with class message-bubble plus .user or .assistant modifiers.",
|
||
"visuals": {
|
||
"assistant": "rgba(255,255,255,0.56) background, 1px charcoal mix border, 1.5rem radius (globals.css:809-828).",
|
||
"user": "Lighter background, inset white strokes, tighter padding (globals.css:818-824).",
|
||
"darkMode": "Switch to darker glass with 0.15 opacity borders (globals.css:831-848)."
|
||
},
|
||
"states": ["user", "assistant", "error (plain text in destructive color)", "loading shimmer placeholder"],
|
||
"interactions": "Assistant bubbles contain Markdown-rendered content with copy + diff actions.",
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:324-369",
|
||
"src/app/globals.css:784-848"
|
||
]
|
||
},
|
||
"MessageToolbar": {
|
||
"role": "Inline actions beneath assistant replies (copy button, hints).",
|
||
"structure": "Flex row with copy icon button, border-t accent, opacity transition.",
|
||
"visuals": "Buttons use 7x7 px icon pill with border-white/20 and hover scale. Hints appear as rounded accent cards (chat-interface.tsx:347-369).",
|
||
"states": ["rest", "hover (opacity 100%)", "copied (scale-90 + white background)", "hint present (accent panel)"],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:347-369"
|
||
]
|
||
},
|
||
"HintCallout": {
|
||
"role": "Optional assistant side-note or remediation tip.",
|
||
"structure": "Rounded-lg border border-accent/60 background accent/40, px-3 py-2 text-xs.",
|
||
"visuals": "Sandstone hue with charcoal text keeps hints friendly.",
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:363-369"
|
||
]
|
||
},
|
||
"MarkdownBlock": {
|
||
"role": "Renders formatted assistant content with diff tool support.",
|
||
"structure": "ReactMarkdown with remark-gfm + rehype-highlight, wrapped by markdown-glass class (markdown-renderer.tsx:1-205).",
|
||
"visuals": {
|
||
"text": "Space Grotesk 0.95rem, base tone text-charcoal/dark:foreground.",
|
||
"code": "Rounded capsules with white/60 backgrounds; block code uses PreWithCopy with inline copy button.",
|
||
"tables": "Translucent backgrounds with subtle borders (markdown-renderer.tsx:84-152)."
|
||
},
|
||
"states": ["default", "diff-tool placeholder (replaced at runtime)", "copy success (button scales)."],
|
||
"codeRefs": [
|
||
"src/components/markdown-renderer.tsx:1-205"
|
||
]
|
||
},
|
||
"Composer": {
|
||
"role": "Input system for crafting the next note, including textarea, agent dropdown, send and attachment controls.",
|
||
"structure": "motion.div (composer-affix) containing form, optional image preview grid, and manuscript-panel with flex column.",
|
||
"visuals": {
|
||
"panel": "Frosted acrylic with inset highlights (globals.css:876-888).",
|
||
"textarea": "Borderless, hide-scrollbar, 1rem-1.125rem text.",
|
||
"toolbar": "Dropdown pill + action buttons aligned end."
|
||
},
|
||
"states": [
|
||
"idle (prompt highlight pulses if no agent chosen).",
|
||
"typing (textarea animates height).",
|
||
"sending (send button shows Loader2).",
|
||
"disabled (buttons opacity 50%).",
|
||
"image-selected (thumb grid appears)."
|
||
],
|
||
"responsive": "Mobile variant (mobile-composer) flips to dark background, white text, saturated send button, and full-width layout (globals.css:498-548).",
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:460-615",
|
||
"src/app/globals.css:498-633"
|
||
]
|
||
},
|
||
"AgentDropdown": {
|
||
"role": "Radix-powered list to pick which agent the composer routes to.",
|
||
"structure": "DropdownMenuTrigger -> DropdownMenuContent with DropdownMenuItem entries.",
|
||
"visuals": {
|
||
"trigger": "Rounded-2xl pill, border-white/20, bg-white/30, uppercase microcopy (chat-interface.tsx:528-535).",
|
||
"menu": "Glass sheet with border-white/15, white/10 fill, and text-white icons (chat-interface.tsx:536-569, dropdown-menu.tsx:1-200)."
|
||
},
|
||
"states": ["prompt highlight (agent-picker-breathe), default, disabled (no agents), active item showing \"Active\" badge."],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:528-569",
|
||
"src/components/ui/dropdown-menu.tsx:1-200",
|
||
"src/app/globals.css:626-656"
|
||
]
|
||
},
|
||
"Button": {
|
||
"role": "Primary interactive primitive from shadcn/ui.",
|
||
"structure": "cva-powered variants (default, destructive, outline, secondary, ghost, link) plus size scale (button.tsx:1-60).",
|
||
"visuals": "Rounded-md base with focus rings using var(--ring); icon variants are perfect squares (size-8/9/10).",
|
||
"states": ["hover (color lighten/darken), focus-visible ring, disabled pointer-events-none."],
|
||
"codeRefs": [
|
||
"src/components/ui/button.tsx:1-60"
|
||
]
|
||
},
|
||
"InputField": {
|
||
"role": "Text + file inputs share the same translucent style (input.tsx:1-23).",
|
||
"structure": "h-9, px-3, border border-input, placeholder muted, selection colors follow primary palette.",
|
||
"states": ["focus-visible ring", "disabled (opacity 50%)", "aria-invalid (destructive ring)."],
|
||
"codeRefs": [
|
||
"src/components/ui/input.tsx:1-23"
|
||
]
|
||
},
|
||
"IconButton": {
|
||
"role": "Circular or rounded-square button for single glyph actions (new chat, copy, send, attach).",
|
||
"structure": "Button component with size=\"icon\" or custom classes (h-11 w-11) plus backdrop blur.",
|
||
"visuals": "Use 10-20% white fill, 20% border, slight drop shadow. Send button uses 12x12 icon at center with group hover transitions.",
|
||
"states": ["default", "hover lighten", "disabled (opacity)", "copied state scale-90"],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:292-303",
|
||
"src/components/chat-interface.tsx:573-608"
|
||
]
|
||
},
|
||
"ImageAttachmentThumb": {
|
||
"role": "Preview of uploaded images prior to sending.",
|
||
"structure": "3.4rem square, rounded-lg, border-border/40, object-cover image plus remove FAB at -right-2 -top-2.",
|
||
"visuals": "Shadow-md drop, charcoal-ink close button with white icon (chat-interface.tsx:467-485, globals.css:575-616).",
|
||
"states": ["default", "hover remove button (opacity 80%)."],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:467-485",
|
||
"src/app/globals.css:575-616"
|
||
]
|
||
},
|
||
"DiffPanel": {
|
||
"role": "Expandable timeline of code/text changes for responses requesting diff visualization.",
|
||
"structure": "Collapsible card with header (title, language, expand button, copy button) and optional diff body (diff-display.tsx:1-200).",
|
||
"visuals": {
|
||
"header": "Neutral-900/50 background, border-neutral-800, text-white/neutral.",
|
||
"diffLines": "Green for additions, red for removals, neutral for unchanged; column shows old|new numbers."
|
||
},
|
||
"states": ["collapsed", "expanded", "copied (Check icon)."],
|
||
"codeRefs": [
|
||
"src/components/diff-display.tsx:1-200"
|
||
]
|
||
},
|
||
"AgentSelectorDialog": {
|
||
"role": "Modal palette for browsing configured agents.",
|
||
"structure": "Radix Dialog overlay + palette-shell container with scroll-reveal card grid (agent-selector.tsx:93-165).",
|
||
"visuals": {
|
||
"shell": "Linear-gradient background, border color-mix charcoal, 25px drop shadow (globals.css:642-690).",
|
||
"cards": "Swatch cards with tinted overlays, uppercase eyebrow, Playfair name, avatar coin (globals.css:699-782)."
|
||
},
|
||
"states": ["loading (Loader2 + caption)", "error (destructive block)", "ready (card grid)."],
|
||
"interactions": "Click card selects agent, stores to localStorage, closes dialog.",
|
||
"codeRefs": [
|
||
"src/components/agent-selector.tsx:1-165"
|
||
]
|
||
},
|
||
"HeaderBar": {
|
||
"role": "Optional sticky heading (header.tsx) for contexts outside the main chat manuscript.",
|
||
"structure": "Stacked serif heading + dropdown button when no agent is selected.",
|
||
"visuals": "Text-white hero, dropdown uses same glass pill treatment as composer but full width (header.tsx:10-63).",
|
||
"states": ["agent-selected (shows name only)", "no-agent (shows dropdown)."],
|
||
"codeRefs": [
|
||
"src/components/header.tsx:1-74"
|
||
]
|
||
}
|
||
},
|
||
"patterns": {
|
||
"conversationFlow": {
|
||
"description": "Hero stage invites selection, conversation feed takes over once a message exists, and composer remains anchored at the bottom.",
|
||
"steps": [
|
||
"No messages -> show HeroEmptyState with chips and prompts.",
|
||
"User selects agent or prompt -> composer label updates and highlight stops pulsing.",
|
||
"Message send triggers user bubble append, then assistant bubble, plus copy toolbar.",
|
||
"New chat resets state and animates hero back in."
|
||
],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:278-369"
|
||
]
|
||
},
|
||
"agentPersistence": {
|
||
"description": "Selected agents and chat sessions persist in localStorage so the UI can reload context silently.",
|
||
"details": "ChatInterface stores chat-session-{agentId} and chat-messages-{agentId}; AgentSelector/Header store selected-agent JSON (chat-interface.tsx:68-154, agent-selector.tsx:83-90, page.tsx:10-70).",
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:58-155",
|
||
"src/app/page.tsx:10-70",
|
||
"src/components/agent-selector.tsx:83-90"
|
||
]
|
||
},
|
||
"imageUpload": {
|
||
"description": "Optional image attachments convert to base64, preview in a thumb reel, and can be removed via floating X.",
|
||
"states": ["images empty", "images present -> preview grid + remove buttons."],
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:127-200",
|
||
"src/components/chat-interface.tsx:467-485"
|
||
]
|
||
},
|
||
"diffInspection": {
|
||
"description": "Assistant replies can embed ```diff-tool``` blocks that render a collapsible diff viewer with copy-to-clipboard.",
|
||
"codeRefs": [
|
||
"src/components/markdown-renderer.tsx:15-91",
|
||
"src/components/diff-display.tsx:1-200"
|
||
]
|
||
},
|
||
"emptyStateToActive": {
|
||
"description": "AnimatePresence swaps hero for conversation with slide/fade transitions while preserving chat-panel height to avoid layout jump.",
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:314-381",
|
||
"src/components/chat-interface.tsx:382-452"
|
||
]
|
||
},
|
||
"responsiveStrategy": {
|
||
"description": "Custom CSS classes override Tailwind tokens for small screens: body overflow hidden, safe-area paddings, composer redesign, chip restyling.",
|
||
"codeRefs": [
|
||
"src/app/globals.css:267-563"
|
||
]
|
||
},
|
||
"interactionShortcuts": {
|
||
"description": "Enter submits, Shift+Enter inserts newline; copy buttons provide quick clipboard access; new chat button resets session; dropdown disabled state communicates loading.",
|
||
"codeRefs": [
|
||
"src/components/chat-interface.tsx:252-275",
|
||
"src/components/chat-interface.tsx:292-305",
|
||
"src/components/chat-interface.tsx:324-369"
|
||
]
|
||
}
|
||
},
|
||
"codeIntegration": {
|
||
"stylingApproach": "Tailwind CSS v4 via @import plus bespoke component classes live in src/app/globals.css (lines 1-940). Utility helper cn() merges classes (src/lib/utils.ts:1-7).",
|
||
"componentArchitecture": "UI primitives from shadcn (Button, Input, DropdownMenu, Dialog) live in src/components/ui, while experience-level pieces (ChatInterface, AgentSelector, Header, MarkdownRenderer, DiffDisplay) compose those primitives. Naming stays PascalCase with descriptive file names.",
|
||
"designTokens": "CSS variables defined in :root/.dark (globals.css:6-84) provide color + radius tokens; @theme inline exports them for Tailwind usage. Maintain palette references when adding new surfaces.",
|
||
"stateManagement": "React hooks manage UI: ChatInterface tracks messages, inputs, loading states, composer agent, textarea height, and copiedMessageId; useEffect wires localStorage persistence and scroll behavior; useFlags (src/lib/use-flags.ts:1-50) gates optional features (image uploads, diff tool).",
|
||
"compositionPatterns": "Framer Motion powers fades/slides (chat-interface.tsx:285-463). Radix primitives supply semantics for dropdowns and dialogs. MarkdownRenderer pipelines remark/rehype for formatting and diff embedding.",
|
||
"responsiveImplementation": "Globals define mobile overrides using @media (max-width:639px) plus helper classes like mobile-feed and mobile-composer (globals.css:267-563). Components toggle those classes with Tailwind responsive modifiers (e.g., max-sm:mobile-composer).",
|
||
"accessibility": "Focus-visible rings built into Button/Input, aria-invalid states, sr-only spans on dialog close, and uppercase microcopy with adequate color contrast. Enter handling prevents multi-line send mistakes, but shift+enter is respected.",
|
||
"dataFlow": "API calls hit /api/agents and /api/chat; responses feed MarkdownRenderer or set error states that bubble into message list. Feature parity between design + code requires storing new metadata (hints, images) on Message records (src/lib/types.ts:20-55)."
|
||
}
|
||
}
|