Conversation List
spectrumui/conversation-listFreeBlock
A date-grouped conversation sidebar with pinning.
Install it
npx shadcn@latest add https://ui.spectrumhq.in/r/conversation-list.jsonSource
1'use client';23import { useState } from 'react';4import { MessageSquare, Pin } from 'lucide-react';5import { cn } from '@/lib/utils';67export interface ConversationEntry {8 id: string;9 title: string;10 group: string;11 pinned?: boolean;12}1314export type ConversationListVariant = 'Default' | 'Compact';1516export interface ConversationListProps {17 conversations: ConversationEntry[];18 activeId?: string;19 onSelect?: (id: string) => void;20 onTogglePin?: (id: string) => void;21 variant?: ConversationListVariant;22 className?: string;23}2425export function ConversationList({26 conversations,27 activeId: activeProp,28 onSelect,29 onTogglePin,30 variant = 'Default',31 className,32}: ConversationListProps) {33 const [activeState, setActiveState] = useState(conversations[0]?.id);34 const [pins, setPins] = useState<Set<string>>(35 new Set(conversations.filter((c) => c.pinned).map((c) => c.id)),36 );37 const active = activeProp !== undefined ? activeProp : activeState;38 const compact = variant === 'Compact';3940 function select(id: string) {41 setActiveState(id);42 onSelect?.(id);43 }4445 function togglePin(id: string) {46 setPins((previous) => {47 const next = new Set(previous);48 if (next.has(id)) next.delete(id);49 else next.add(id);50 return next;51 });52 onTogglePin?.(id);53 }5455 const groups: string[] = [];56 for (const conversation of conversations) {57 if (!groups.includes(conversation.group)) groups.push(conversation.group);58 }5960 return (61 <nav62 aria-label="Conversations"63 className={cn(64 'w-full max-w-[300px] rounded-2xl border border-black/[0.08] bg-white p-2 shadow-xs dark:border-white/[0.09] dark:bg-[#0B0B0D]',65 className,66 )}67 >68 {groups.map((group) => (69 <div key={group} className="[&:not(:first-child)]:mt-3">70 <p className="px-2 pb-1 font-mono text-[9.5px] font-medium uppercase tracking-[0.08em] text-neutral-400 dark:text-neutral-600">71 {group}72 </p>73 <ul>74 {conversations75 .filter((conversation) => conversation.group === group)76 .map((conversation) => {77 const isActive = conversation.id === active;78 const pinned = pins.has(conversation.id);79 return (80 <li key={conversation.id} className="group/item relative">81 <button82 type="button"83 aria-current={isActive ? 'true' : undefined}84// … truncated
What it pulls in
npm packages
Files it writes
More from spectrumui
All 182 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Agent Planagent-plan | spectrumui | Blocks | Free | 1 dep | |
| Agent Stepsagent-steps | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Approval Cardapproval-card | spectrumui | Blocks | Free | 1 dep | |
| Chat Empty Statechat-empty-state | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Citation Sourcescitation-sources | spectrumui | Blocks | Free | no deps · 2 files | |
| Code Blockcode-block | spectrumui | Blocks | Free | 1 dep | |
| Diff Viewdiff-view | spectrumui | Blocks | Free | 1 dep | |
| Error Stateerror-state | spectrumui | Blocks | Free | 1 dep |
