ComponentShowcase.tsx 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437
  1. import {
  2. Accordion,
  3. AccordionContent,
  4. AccordionItem,
  5. AccordionTrigger,
  6. } from "@/components/ui/accordion";
  7. import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
  8. import { AspectRatio } from "@/components/ui/aspect-ratio";
  9. import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
  10. import { Badge } from "@/components/ui/badge";
  11. import {
  12. Breadcrumb,
  13. BreadcrumbItem,
  14. BreadcrumbLink,
  15. BreadcrumbList,
  16. BreadcrumbPage,
  17. BreadcrumbSeparator,
  18. } from "@/components/ui/breadcrumb";
  19. import { Button } from "@/components/ui/button";
  20. import { Calendar } from "@/components/ui/calendar";
  21. import {
  22. Card,
  23. CardContent,
  24. CardDescription,
  25. CardFooter,
  26. CardHeader,
  27. CardTitle,
  28. } from "@/components/ui/card";
  29. import {
  30. Carousel,
  31. CarouselContent,
  32. CarouselItem,
  33. CarouselNext,
  34. CarouselPrevious,
  35. } from "@/components/ui/carousel";
  36. import { Checkbox } from "@/components/ui/checkbox";
  37. import {
  38. Collapsible,
  39. CollapsibleContent,
  40. CollapsibleTrigger,
  41. } from "@/components/ui/collapsible";
  42. import {
  43. Command,
  44. CommandEmpty,
  45. CommandGroup,
  46. CommandInput,
  47. CommandItem,
  48. CommandList,
  49. } from "@/components/ui/command";
  50. import {
  51. ContextMenu,
  52. ContextMenuContent,
  53. ContextMenuItem,
  54. ContextMenuTrigger,
  55. } from "@/components/ui/context-menu";
  56. import {
  57. Dialog,
  58. DialogContent,
  59. DialogDescription,
  60. DialogHeader,
  61. DialogTitle,
  62. DialogTrigger,
  63. } from "@/components/ui/dialog";
  64. import {
  65. Drawer,
  66. DrawerClose,
  67. DrawerContent,
  68. DrawerDescription,
  69. DrawerFooter,
  70. DrawerHeader,
  71. DrawerTitle,
  72. DrawerTrigger,
  73. } from "@/components/ui/drawer";
  74. import {
  75. DropdownMenu,
  76. DropdownMenuContent,
  77. DropdownMenuItem,
  78. DropdownMenuLabel,
  79. DropdownMenuSeparator,
  80. DropdownMenuTrigger,
  81. } from "@/components/ui/dropdown-menu";
  82. import {
  83. HoverCard,
  84. HoverCardContent,
  85. HoverCardTrigger,
  86. } from "@/components/ui/hover-card";
  87. import { Input } from "@/components/ui/input";
  88. import {
  89. InputOTP,
  90. InputOTPGroup,
  91. InputOTPSlot,
  92. } from "@/components/ui/input-otp";
  93. import { Label } from "@/components/ui/label";
  94. import {
  95. Menubar,
  96. MenubarContent,
  97. MenubarItem,
  98. MenubarMenu,
  99. MenubarSeparator,
  100. MenubarTrigger,
  101. } from "@/components/ui/menubar";
  102. import {
  103. Pagination,
  104. PaginationContent,
  105. PaginationItem,
  106. PaginationLink,
  107. PaginationNext,
  108. PaginationPrevious,
  109. } from "@/components/ui/pagination";
  110. import {
  111. Popover,
  112. PopoverContent,
  113. PopoverTrigger,
  114. } from "@/components/ui/popover";
  115. import { Progress } from "@/components/ui/progress";
  116. import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
  117. import {
  118. ResizableHandle,
  119. ResizablePanel,
  120. ResizablePanelGroup,
  121. } from "@/components/ui/resizable";
  122. import { ScrollArea } from "@/components/ui/scroll-area";
  123. import {
  124. Select,
  125. SelectContent,
  126. SelectItem,
  127. SelectTrigger,
  128. SelectValue,
  129. } from "@/components/ui/select";
  130. import { Separator } from "@/components/ui/separator";
  131. import {
  132. Sheet,
  133. SheetContent,
  134. SheetDescription,
  135. SheetHeader,
  136. SheetTitle,
  137. SheetTrigger,
  138. } from "@/components/ui/sheet";
  139. import { Skeleton } from "@/components/ui/skeleton";
  140. import { Slider } from "@/components/ui/slider";
  141. import { Switch } from "@/components/ui/switch";
  142. import {
  143. Table,
  144. TableBody,
  145. TableCaption,
  146. TableCell,
  147. TableHead,
  148. TableHeader,
  149. TableRow,
  150. } from "@/components/ui/table";
  151. import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
  152. import { Textarea } from "@/components/ui/textarea";
  153. import { Toggle } from "@/components/ui/toggle";
  154. import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
  155. import {
  156. Tooltip,
  157. TooltipContent,
  158. TooltipTrigger,
  159. } from "@/components/ui/tooltip";
  160. import { useTheme } from "@/contexts/ThemeContext";
  161. import { format } from "date-fns";
  162. import { zhCN } from "date-fns/locale";
  163. import {
  164. AlertCircle,
  165. CalendarIcon,
  166. Check,
  167. Clock,
  168. Moon,
  169. Sun,
  170. X,
  171. } from "lucide-react";
  172. import { useState } from "react";
  173. import { toast as sonnerToast } from "sonner";
  174. import { AIChatBox, type Message } from "@/components/AIChatBox";
  175. export default function ComponentsShowcase() {
  176. const { theme, toggleTheme } = useTheme();
  177. const [date, setDate] = useState<Date | undefined>(new Date());
  178. const [datePickerDate, setDatePickerDate] = useState<Date>();
  179. const [selectedFruits, setSelectedFruits] = useState<string[]>([]);
  180. const [progress, setProgress] = useState(33);
  181. const [currentPage, setCurrentPage] = useState(2);
  182. const [openCombobox, setOpenCombobox] = useState(false);
  183. const [selectedFramework, setSelectedFramework] = useState("");
  184. const [selectedMonth, setSelectedMonth] = useState("");
  185. const [selectedYear, setSelectedYear] = useState("");
  186. const [dialogInput, setDialogInput] = useState("");
  187. const [dialogOpen, setDialogOpen] = useState(false);
  188. // AI ChatBox demo state
  189. const [chatMessages, setChatMessages] = useState<Message[]>([
  190. { role: "system", content: "You are a helpful assistant." },
  191. ]);
  192. const [isChatLoading, setIsChatLoading] = useState(false);
  193. const handleDialogSubmit = () => {
  194. console.log("Dialog submitted with value:", dialogInput);
  195. sonnerToast.success("Submitted successfully", {
  196. description: `Input: ${dialogInput}`,
  197. });
  198. setDialogInput("");
  199. setDialogOpen(false);
  200. };
  201. const handleDialogKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
  202. if (e.key === "Enter" && !e.nativeEvent.isComposing) {
  203. e.preventDefault();
  204. handleDialogSubmit();
  205. }
  206. };
  207. const handleChatSend = (content: string) => {
  208. // Add user message
  209. const newMessages: Message[] = [...chatMessages, { role: "user", content }];
  210. setChatMessages(newMessages);
  211. // Simulate AI response with delay
  212. setIsChatLoading(true);
  213. setTimeout(() => {
  214. const aiResponse: Message = {
  215. role: "assistant",
  216. content: `This is a **demo response**. In a real app, you would call a tRPC mutation here:\n\n\`\`\`typescript\nconst chatMutation = trpc.ai.chat.useMutation({\n onSuccess: (response) => {\n setChatMessages(prev => [...prev, {\n role: "assistant",\n content: response.choices[0].message.content\n }]);\n }\n});\n\nchatMutation.mutate({ messages: newMessages });\n\`\`\`\n\nYour message was: "${content}"`,
  217. };
  218. setChatMessages([...newMessages, aiResponse]);
  219. setIsChatLoading(false);
  220. }, 1500);
  221. };
  222. return (
  223. <div className="min-h-screen bg-background text-foreground">
  224. <main className="container max-w-6xl mx-auto">
  225. <div className="space-y-2 justify-between flex">
  226. <h2 className="text-3xl font-bold tracking-tight mb-6">
  227. Shadcn/ui Component Library
  228. </h2>
  229. <Button variant="outline" size="icon" onClick={toggleTheme}>
  230. {theme === "light" ? (
  231. <Moon className="h-5 w-5" />
  232. ) : (
  233. <Sun className="h-5 w-5" />
  234. )}
  235. </Button>
  236. </div>
  237. <div className="space-y-12">
  238. {/* Text Colors Section */}
  239. <section className="space-y-4">
  240. <h3 className="text-2xl font-semibold">Text Colors</h3>
  241. <Card>
  242. <CardContent className="pt-6">
  243. <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
  244. <div className="space-y-3">
  245. <div>
  246. <p className="text-sm text-muted-foreground mb-1">
  247. Foreground (Default)
  248. </p>
  249. <p className="text-foreground text-lg">
  250. Default text color for main content
  251. </p>
  252. </div>
  253. <div>
  254. <p className="text-sm text-muted-foreground mb-1">
  255. Muted Foreground
  256. </p>
  257. <p className="text-muted-foreground text-lg">
  258. Muted text for secondary information
  259. </p>
  260. </div>
  261. <div>
  262. <p className="text-sm text-muted-foreground mb-1">
  263. Primary
  264. </p>
  265. <p className="text-primary text-lg font-medium">
  266. Primary brand color text
  267. </p>
  268. </div>
  269. <div>
  270. <p className="text-sm text-muted-foreground mb-1">
  271. Secondary Foreground
  272. </p>
  273. <p className="text-secondary-foreground text-lg">
  274. Secondary action text color
  275. </p>
  276. </div>
  277. </div>
  278. <div className="space-y-3">
  279. <div>
  280. <p className="text-sm text-muted-foreground mb-1">
  281. Accent Foreground
  282. </p>
  283. <p className="text-accent-foreground text-lg">
  284. Accent text for emphasis
  285. </p>
  286. </div>
  287. <div>
  288. <p className="text-sm text-muted-foreground mb-1">
  289. Destructive
  290. </p>
  291. <p className="text-destructive text-lg font-medium">
  292. Error or destructive action text
  293. </p>
  294. </div>
  295. <div>
  296. <p className="text-sm text-muted-foreground mb-1">
  297. Card Foreground
  298. </p>
  299. <p className="text-card-foreground text-lg">
  300. Text color on card backgrounds
  301. </p>
  302. </div>
  303. <div>
  304. <p className="text-sm text-muted-foreground mb-1">
  305. Popover Foreground
  306. </p>
  307. <p className="text-popover-foreground text-lg">
  308. Text color in popovers
  309. </p>
  310. </div>
  311. </div>
  312. </div>
  313. </CardContent>
  314. </Card>
  315. </section>
  316. {/* Color Combinations Section */}
  317. <section className="space-y-4">
  318. <h3 className="text-2xl font-semibold">Color Combinations</h3>
  319. <Card>
  320. <CardContent className="pt-6">
  321. <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  322. <div className="bg-primary text-primary-foreground rounded-lg p-4">
  323. <p className="font-medium mb-1">Primary</p>
  324. <p className="text-sm opacity-90">
  325. Primary background with foreground text
  326. </p>
  327. </div>
  328. <div className="bg-secondary text-secondary-foreground rounded-lg p-4">
  329. <p className="font-medium mb-1">Secondary</p>
  330. <p className="text-sm opacity-90">
  331. Secondary background with foreground text
  332. </p>
  333. </div>
  334. <div className="bg-muted text-muted-foreground rounded-lg p-4">
  335. <p className="font-medium mb-1">Muted</p>
  336. <p className="text-sm opacity-90">
  337. Muted background with foreground text
  338. </p>
  339. </div>
  340. <div className="bg-accent text-accent-foreground rounded-lg p-4">
  341. <p className="font-medium mb-1">Accent</p>
  342. <p className="text-sm opacity-90">
  343. Accent background with foreground text
  344. </p>
  345. </div>
  346. <div className="bg-destructive text-destructive-foreground rounded-lg p-4">
  347. <p className="font-medium mb-1">Destructive</p>
  348. <p className="text-sm opacity-90">
  349. Destructive background with foreground text
  350. </p>
  351. </div>
  352. <div className="bg-card text-card-foreground rounded-lg p-4 border">
  353. <p className="font-medium mb-1">Card</p>
  354. <p className="text-sm opacity-90">
  355. Card background with foreground text
  356. </p>
  357. </div>
  358. <div className="bg-popover text-popover-foreground rounded-lg p-4 border">
  359. <p className="font-medium mb-1">Popover</p>
  360. <p className="text-sm opacity-90">
  361. Popover background with foreground text
  362. </p>
  363. </div>
  364. <div className="bg-background text-foreground rounded-lg p-4 border">
  365. <p className="font-medium mb-1">Background</p>
  366. <p className="text-sm opacity-90">
  367. Default background with foreground text
  368. </p>
  369. </div>
  370. </div>
  371. </CardContent>
  372. </Card>
  373. </section>
  374. {/* Buttons Section */}
  375. <section className="space-y-4">
  376. <h3 className="text-2xl font-semibold">Buttons</h3>
  377. <Card>
  378. <CardContent className="pt-6">
  379. <div className="flex flex-wrap gap-4">
  380. <Button>Default</Button>
  381. <Button variant="secondary">Secondary</Button>
  382. <Button variant="destructive">Destructive</Button>
  383. <Button variant="outline">Outline</Button>
  384. <Button variant="ghost">Ghost</Button>
  385. <Button variant="link">Link</Button>
  386. <Button size="sm">Small</Button>
  387. <Button size="lg">Large</Button>
  388. <Button size="icon">
  389. <Check className="h-4 w-4" />
  390. </Button>
  391. </div>
  392. </CardContent>
  393. </Card>
  394. </section>
  395. {/* Form Inputs Section */}
  396. <section className="space-y-4">
  397. <h3 className="text-2xl font-semibold">Form Inputs</h3>
  398. <Card>
  399. <CardContent className="pt-6 space-y-6">
  400. <div className="space-y-2">
  401. <Label htmlFor="email">Email</Label>
  402. <Input id="email" type="email" placeholder="Email" />
  403. </div>
  404. <div className="space-y-2">
  405. <Label htmlFor="message">Message</Label>
  406. <Textarea
  407. id="message"
  408. placeholder="Type your message here."
  409. />
  410. </div>
  411. <div className="space-y-2">
  412. <Label>Select</Label>
  413. <Select>
  414. <SelectTrigger>
  415. <SelectValue placeholder="Select a fruit" />
  416. </SelectTrigger>
  417. <SelectContent>
  418. <SelectItem value="apple">Apple</SelectItem>
  419. <SelectItem value="banana">Banana</SelectItem>
  420. <SelectItem value="orange">Orange</SelectItem>
  421. </SelectContent>
  422. </Select>
  423. </div>
  424. <div className="flex items-center space-x-2">
  425. <Checkbox id="terms" />
  426. <Label htmlFor="terms">Accept terms and conditions</Label>
  427. </div>
  428. <div className="flex items-center space-x-2">
  429. <Switch id="airplane-mode" />
  430. <Label htmlFor="airplane-mode">Airplane Mode</Label>
  431. </div>
  432. <div className="space-y-2">
  433. <Label>Radio Group</Label>
  434. <RadioGroup defaultValue="option-one">
  435. <div className="flex items-center space-x-2">
  436. <RadioGroupItem value="option-one" id="option-one" />
  437. <Label htmlFor="option-one">Option One</Label>
  438. </div>
  439. <div className="flex items-center space-x-2">
  440. <RadioGroupItem value="option-two" id="option-two" />
  441. <Label htmlFor="option-two">Option Two</Label>
  442. </div>
  443. </RadioGroup>
  444. </div>
  445. <div className="space-y-2">
  446. <Label>Slider</Label>
  447. <Slider defaultValue={[50]} max={100} step={1} />
  448. </div>
  449. <div className="space-y-2">
  450. <Label>Input OTP</Label>
  451. <InputOTP maxLength={6}>
  452. <InputOTPGroup>
  453. <InputOTPSlot index={0} />
  454. <InputOTPSlot index={1} />
  455. <InputOTPSlot index={2} />
  456. <InputOTPSlot index={3} />
  457. <InputOTPSlot index={4} />
  458. <InputOTPSlot index={5} />
  459. </InputOTPGroup>
  460. </InputOTP>
  461. </div>
  462. <div className="space-y-2">
  463. <Label>Date Time Picker</Label>
  464. <Popover>
  465. <PopoverTrigger asChild>
  466. <Button
  467. variant="outline"
  468. className={`w-full justify-start text-left font-normal ${
  469. !datePickerDate && "text-muted-foreground"
  470. }`}
  471. >
  472. <CalendarIcon className="mr-2 h-4 w-4" />
  473. {datePickerDate ? (
  474. format(datePickerDate, "PPP HH:mm", { locale: zhCN })
  475. ) : (
  476. <span>Select date and time</span>
  477. )}
  478. </Button>
  479. </PopoverTrigger>
  480. <PopoverContent className="w-auto p-0" align="start">
  481. <div className="p-3 space-y-3">
  482. <Calendar
  483. mode="single"
  484. selected={datePickerDate}
  485. onSelect={setDatePickerDate}
  486. />
  487. <div className="border-t pt-3 space-y-2">
  488. <Label className="flex items-center gap-2">
  489. <Clock className="h-4 w-4" />
  490. Time
  491. </Label>
  492. <div className="flex gap-2">
  493. <Input
  494. type="time"
  495. value={
  496. datePickerDate
  497. ? format(datePickerDate, "HH:mm")
  498. : "00:00"
  499. }
  500. onChange={e => {
  501. const [hours, minutes] =
  502. e.target.value.split(":");
  503. const newDate = datePickerDate
  504. ? new Date(datePickerDate)
  505. : new Date();
  506. newDate.setHours(parseInt(hours));
  507. newDate.setMinutes(parseInt(minutes));
  508. setDatePickerDate(newDate);
  509. }}
  510. />
  511. </div>
  512. </div>
  513. </div>
  514. </PopoverContent>
  515. </Popover>
  516. {datePickerDate && (
  517. <p className="text-sm text-muted-foreground">
  518. Selected:{" "}
  519. {format(datePickerDate, "yyyy/MM/dd HH:mm", {
  520. locale: zhCN,
  521. })}
  522. </p>
  523. )}
  524. </div>
  525. <div className="space-y-2">
  526. <Label>Searchable Dropdown</Label>
  527. <Popover open={openCombobox} onOpenChange={setOpenCombobox}>
  528. <PopoverTrigger asChild>
  529. <Button
  530. variant="outline"
  531. role="combobox"
  532. aria-expanded={openCombobox}
  533. className="w-full justify-between"
  534. >
  535. {selectedFramework
  536. ? [
  537. { value: "react", label: "React" },
  538. { value: "vue", label: "Vue" },
  539. { value: "angular", label: "Angular" },
  540. { value: "svelte", label: "Svelte" },
  541. { value: "nextjs", label: "Next.js" },
  542. { value: "nuxt", label: "Nuxt" },
  543. { value: "remix", label: "Remix" },
  544. ].find(fw => fw.value === selectedFramework)?.label
  545. : "Select framework..."}
  546. <CalendarIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
  547. </Button>
  548. </PopoverTrigger>
  549. <PopoverContent className="w-full p-0">
  550. <Command>
  551. <CommandInput placeholder="Search frameworks..." />
  552. <CommandList>
  553. <CommandEmpty>No framework found</CommandEmpty>
  554. <CommandGroup>
  555. {[
  556. { value: "react", label: "React" },
  557. { value: "vue", label: "Vue" },
  558. { value: "angular", label: "Angular" },
  559. { value: "svelte", label: "Svelte" },
  560. { value: "nextjs", label: "Next.js" },
  561. { value: "nuxt", label: "Nuxt" },
  562. { value: "remix", label: "Remix" },
  563. ].map(framework => (
  564. <CommandItem
  565. key={framework.value}
  566. value={framework.value}
  567. onSelect={currentValue => {
  568. setSelectedFramework(
  569. currentValue === selectedFramework
  570. ? ""
  571. : currentValue
  572. );
  573. setOpenCombobox(false);
  574. }}
  575. >
  576. <Check
  577. className={`mr-2 h-4 w-4 ${
  578. selectedFramework === framework.value
  579. ? "opacity-100"
  580. : "opacity-0"
  581. }`}
  582. />
  583. {framework.label}
  584. </CommandItem>
  585. ))}
  586. </CommandGroup>
  587. </CommandList>
  588. </Command>
  589. </PopoverContent>
  590. </Popover>
  591. {selectedFramework && (
  592. <p className="text-sm text-muted-foreground">
  593. Selected:{" "}
  594. {
  595. [
  596. { value: "react", label: "React" },
  597. { value: "vue", label: "Vue" },
  598. { value: "angular", label: "Angular" },
  599. { value: "svelte", label: "Svelte" },
  600. { value: "nextjs", label: "Next.js" },
  601. { value: "nuxt", label: "Nuxt" },
  602. { value: "remix", label: "Remix" },
  603. ].find(fw => fw.value === selectedFramework)?.label
  604. }
  605. </p>
  606. )}
  607. </div>
  608. <div className="space-y-2">
  609. <div className="grid grid-cols-2 gap-4">
  610. <div className="space-y-2">
  611. <Label htmlFor="month" className="text-sm font-medium">
  612. Month
  613. </Label>
  614. <Select
  615. value={selectedMonth}
  616. onValueChange={setSelectedMonth}
  617. >
  618. <SelectTrigger id="month">
  619. <SelectValue placeholder="MM" />
  620. </SelectTrigger>
  621. <SelectContent>
  622. {Array.from({ length: 12 }, (_, i) => i + 1).map(
  623. month => (
  624. <SelectItem
  625. key={month}
  626. value={month.toString().padStart(2, "0")}
  627. >
  628. {month.toString().padStart(2, "0")}
  629. </SelectItem>
  630. )
  631. )}
  632. </SelectContent>
  633. </Select>
  634. </div>
  635. <div className="space-y-2">
  636. <Label htmlFor="year" className="text-sm font-medium">
  637. Year
  638. </Label>
  639. <Select
  640. value={selectedYear}
  641. onValueChange={setSelectedYear}
  642. >
  643. <SelectTrigger id="year">
  644. <SelectValue placeholder="YYYY" />
  645. </SelectTrigger>
  646. <SelectContent>
  647. {Array.from(
  648. { length: 10 },
  649. (_, i) => new Date().getFullYear() - 5 + i
  650. ).map(year => (
  651. <SelectItem key={year} value={year.toString()}>
  652. {year}
  653. </SelectItem>
  654. ))}
  655. </SelectContent>
  656. </Select>
  657. </div>
  658. </div>
  659. {selectedMonth && selectedYear && (
  660. <p className="text-sm text-muted-foreground">
  661. Selected: {selectedYear}/{selectedMonth}/
  662. </p>
  663. )}
  664. </div>
  665. </CardContent>
  666. </Card>
  667. </section>
  668. {/* Data Display Section */}
  669. <section className="space-y-4">
  670. <h3 className="text-2xl font-semibold">Data Display</h3>
  671. <Card>
  672. <CardContent className="pt-6 space-y-6">
  673. <div className="space-y-2">
  674. <Label>Badges</Label>
  675. <div className="flex flex-wrap gap-2">
  676. <Badge>Default</Badge>
  677. <Badge variant="secondary">Secondary</Badge>
  678. <Badge variant="destructive">Destructive</Badge>
  679. <Badge variant="outline">Outline</Badge>
  680. </div>
  681. </div>
  682. <Separator />
  683. <div className="space-y-2">
  684. <Label>Avatar</Label>
  685. <div className="flex gap-4">
  686. <Avatar>
  687. <AvatarImage src="https://github.com/shadcn.png" />
  688. <AvatarFallback>CN</AvatarFallback>
  689. </Avatar>
  690. <Avatar>
  691. <AvatarFallback>AB</AvatarFallback>
  692. </Avatar>
  693. </div>
  694. </div>
  695. <Separator />
  696. <div className="space-y-2">
  697. <Label>Progress</Label>
  698. <Progress value={progress} />
  699. <div className="flex gap-2">
  700. <Button
  701. size="sm"
  702. onClick={() => setProgress(Math.max(0, progress - 10))}
  703. >
  704. -10
  705. </Button>
  706. <Button
  707. size="sm"
  708. onClick={() => setProgress(Math.min(100, progress + 10))}
  709. >
  710. +10
  711. </Button>
  712. </div>
  713. </div>
  714. <Separator />
  715. <div className="space-y-2">
  716. <Label>Skeleton</Label>
  717. <div className="space-y-2">
  718. <Skeleton className="h-4 w-full" />
  719. <Skeleton className="h-4 w-3/4" />
  720. <Skeleton className="h-4 w-1/2" />
  721. </div>
  722. </div>
  723. <Separator />
  724. <div className="space-y-2">
  725. <Label>Pagination</Label>
  726. <Pagination>
  727. <PaginationContent>
  728. <PaginationItem>
  729. <PaginationPrevious
  730. href="#"
  731. onClick={e => {
  732. e.preventDefault();
  733. setCurrentPage(Math.max(1, currentPage - 1));
  734. }}
  735. />
  736. </PaginationItem>
  737. {[1, 2, 3, 4, 5].map(page => (
  738. <PaginationItem key={page}>
  739. <PaginationLink
  740. href="#"
  741. isActive={currentPage === page}
  742. onClick={e => {
  743. e.preventDefault();
  744. setCurrentPage(page);
  745. }}
  746. >
  747. {page}
  748. </PaginationLink>
  749. </PaginationItem>
  750. ))}
  751. <PaginationItem>
  752. <PaginationNext
  753. href="#"
  754. onClick={e => {
  755. e.preventDefault();
  756. setCurrentPage(Math.min(5, currentPage + 1));
  757. }}
  758. />
  759. </PaginationItem>
  760. </PaginationContent>
  761. </Pagination>
  762. <p className="text-sm text-muted-foreground text-center">
  763. Current page: {currentPage}
  764. </p>
  765. </div>
  766. <Separator />
  767. <div className="space-y-2">
  768. <Label>Table</Label>
  769. <Table>
  770. <TableCaption>A list of your recent invoices.</TableCaption>
  771. <TableHeader>
  772. <TableRow>
  773. <TableHead className="w-[100px]">Invoice</TableHead>
  774. <TableHead>Status</TableHead>
  775. <TableHead>Method</TableHead>
  776. <TableHead className="text-right">Amount</TableHead>
  777. </TableRow>
  778. </TableHeader>
  779. <TableBody>
  780. <TableRow>
  781. <TableCell className="font-medium">INV001</TableCell>
  782. <TableCell>Paid</TableCell>
  783. <TableCell>Credit Card</TableCell>
  784. <TableCell className="text-right">$250.00</TableCell>
  785. </TableRow>
  786. <TableRow>
  787. <TableCell className="font-medium">INV002</TableCell>
  788. <TableCell>Pending</TableCell>
  789. <TableCell>PayPal</TableCell>
  790. <TableCell className="text-right">$150.00</TableCell>
  791. </TableRow>
  792. <TableRow>
  793. <TableCell className="font-medium">INV003</TableCell>
  794. <TableCell>Unpaid</TableCell>
  795. <TableCell>Bank Transfer</TableCell>
  796. <TableCell className="text-right">$350.00</TableCell>
  797. </TableRow>
  798. </TableBody>
  799. </Table>
  800. </div>
  801. <Separator />
  802. <div className="space-y-2">
  803. <Label>Menubar</Label>
  804. <Menubar>
  805. <MenubarMenu>
  806. <MenubarTrigger>File</MenubarTrigger>
  807. <MenubarContent>
  808. <MenubarItem>New Tab</MenubarItem>
  809. <MenubarItem>New Window</MenubarItem>
  810. <MenubarSeparator />
  811. <MenubarItem>Share</MenubarItem>
  812. <MenubarSeparator />
  813. <MenubarItem>Print</MenubarItem>
  814. </MenubarContent>
  815. </MenubarMenu>
  816. <MenubarMenu>
  817. <MenubarTrigger>Edit</MenubarTrigger>
  818. <MenubarContent>
  819. <MenubarItem>Undo</MenubarItem>
  820. <MenubarItem>Redo</MenubarItem>
  821. </MenubarContent>
  822. </MenubarMenu>
  823. <MenubarMenu>
  824. <MenubarTrigger>View</MenubarTrigger>
  825. <MenubarContent>
  826. <MenubarItem>Reload</MenubarItem>
  827. <MenubarItem>Force Reload</MenubarItem>
  828. </MenubarContent>
  829. </MenubarMenu>
  830. </Menubar>
  831. </div>
  832. <Separator />
  833. <div className="space-y-2">
  834. <Label>Breadcrumb</Label>
  835. <Breadcrumb>
  836. <BreadcrumbList>
  837. <BreadcrumbItem>
  838. <BreadcrumbLink href="/">Home</BreadcrumbLink>
  839. </BreadcrumbItem>
  840. <BreadcrumbSeparator />
  841. <BreadcrumbItem>
  842. <BreadcrumbLink href="/components">
  843. Components
  844. </BreadcrumbLink>
  845. </BreadcrumbItem>
  846. <BreadcrumbSeparator />
  847. <BreadcrumbItem>
  848. <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
  849. </BreadcrumbItem>
  850. </BreadcrumbList>
  851. </Breadcrumb>
  852. </div>
  853. </CardContent>
  854. </Card>
  855. </section>
  856. {/* Alerts Section */}
  857. <section className="space-y-4">
  858. <h3 className="text-2xl font-semibold">Alerts</h3>
  859. <div className="space-y-4">
  860. <Alert>
  861. <AlertCircle className="h-4 w-4" />
  862. <AlertTitle>Heads up!</AlertTitle>
  863. <AlertDescription>
  864. You can add components to your app using the cli.
  865. </AlertDescription>
  866. </Alert>
  867. <Alert variant="destructive">
  868. <X className="h-4 w-4" />
  869. <AlertTitle>Error</AlertTitle>
  870. <AlertDescription>
  871. Your session has expired. Please log in again.
  872. </AlertDescription>
  873. </Alert>
  874. </div>
  875. </section>
  876. {/* Tabs Section */}
  877. <section className="space-y-4">
  878. <h3 className="text-2xl font-semibold">Tabs</h3>
  879. <Tabs defaultValue="account" className="w-full">
  880. <TabsList className="grid w-full grid-cols-3">
  881. <TabsTrigger value="account">Account</TabsTrigger>
  882. <TabsTrigger value="password">Password</TabsTrigger>
  883. <TabsTrigger value="settings">Settings</TabsTrigger>
  884. </TabsList>
  885. <TabsContent value="account">
  886. <Card>
  887. <CardHeader>
  888. <CardTitle>Account</CardTitle>
  889. <CardDescription>
  890. Make changes to your account here.
  891. </CardDescription>
  892. </CardHeader>
  893. <CardContent className="space-y-2">
  894. <div className="space-y-1">
  895. <Label htmlFor="name">Name</Label>
  896. <Input id="name" defaultValue="Pedro Duarte" />
  897. </div>
  898. </CardContent>
  899. <CardFooter>
  900. <Button>Save changes</Button>
  901. </CardFooter>
  902. </Card>
  903. </TabsContent>
  904. <TabsContent value="password">
  905. <Card>
  906. <CardHeader>
  907. <CardTitle>Password</CardTitle>
  908. <CardDescription>
  909. Change your password here.
  910. </CardDescription>
  911. </CardHeader>
  912. <CardContent className="space-y-2">
  913. <div className="space-y-1">
  914. <Label htmlFor="current">Current password</Label>
  915. <Input id="current" type="password" />
  916. </div>
  917. <div className="space-y-1">
  918. <Label htmlFor="new">New password</Label>
  919. <Input id="new" type="password" />
  920. </div>
  921. </CardContent>
  922. <CardFooter>
  923. <Button>Save password</Button>
  924. </CardFooter>
  925. </Card>
  926. </TabsContent>
  927. <TabsContent value="settings">
  928. <Card>
  929. <CardHeader>
  930. <CardTitle>Settings</CardTitle>
  931. <CardDescription>
  932. Manage your settings here.
  933. </CardDescription>
  934. </CardHeader>
  935. <CardContent>
  936. <p className="text-sm text-muted-foreground">
  937. Settings content goes here.
  938. </p>
  939. </CardContent>
  940. </Card>
  941. </TabsContent>
  942. </Tabs>
  943. </section>
  944. {/* Accordion Section */}
  945. <section className="space-y-4">
  946. <h3 className="text-2xl font-semibold">Accordion</h3>
  947. <Accordion type="single" collapsible className="w-full">
  948. <AccordionItem value="item-1">
  949. <AccordionTrigger>Is it accessible?</AccordionTrigger>
  950. <AccordionContent>
  951. Yes. It adheres to the WAI-ARIA design pattern.
  952. </AccordionContent>
  953. </AccordionItem>
  954. <AccordionItem value="item-2">
  955. <AccordionTrigger>Is it styled?</AccordionTrigger>
  956. <AccordionContent>
  957. Yes. It comes with default styles that matches the other
  958. components' aesthetic.
  959. </AccordionContent>
  960. </AccordionItem>
  961. <AccordionItem value="item-3">
  962. <AccordionTrigger>Is it animated?</AccordionTrigger>
  963. <AccordionContent>
  964. Yes. It's animated by default, but you can disable it if you
  965. prefer.
  966. </AccordionContent>
  967. </AccordionItem>
  968. </Accordion>
  969. </section>
  970. {/* Collapsible Section */}
  971. <section className="space-y-4">
  972. <h3 className="text-2xl font-semibold">Collapsible</h3>
  973. <Collapsible>
  974. <Card>
  975. <CardHeader>
  976. <CollapsibleTrigger asChild>
  977. <Button variant="ghost" className="w-full justify-between">
  978. <CardTitle>@peduarte starred 3 repositories</CardTitle>
  979. </Button>
  980. </CollapsibleTrigger>
  981. </CardHeader>
  982. <CollapsibleContent>
  983. <CardContent>
  984. <div className="space-y-2">
  985. <div className="rounded-md border px-4 py-3 font-mono text-sm">
  986. @radix-ui/primitives
  987. </div>
  988. <div className="rounded-md border px-4 py-3 font-mono text-sm">
  989. @radix-ui/colors
  990. </div>
  991. <div className="rounded-md border px-4 py-3 font-mono text-sm">
  992. @stitches/react
  993. </div>
  994. </div>
  995. </CardContent>
  996. </CollapsibleContent>
  997. </Card>
  998. </Collapsible>
  999. </section>
  1000. {/* Dialog, Sheet, Drawer Section */}
  1001. <section className="space-y-4">
  1002. <h3 className="text-2xl font-semibold">Overlays</h3>
  1003. <Card>
  1004. <CardContent className="pt-6">
  1005. <div className="flex flex-wrap gap-4">
  1006. <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
  1007. <DialogTrigger asChild>
  1008. <Button variant="outline">Open Dialog</Button>
  1009. </DialogTrigger>
  1010. <DialogContent>
  1011. <DialogHeader>
  1012. <DialogTitle>Test Input</DialogTitle>
  1013. <DialogDescription>
  1014. Enter some text below. Press Enter to submit (IME composition supported).
  1015. </DialogDescription>
  1016. </DialogHeader>
  1017. <div className="space-y-4 py-4">
  1018. <div className="space-y-2">
  1019. <Label htmlFor="dialog-input">Input</Label>
  1020. <Input
  1021. id="dialog-input"
  1022. placeholder="Type something..."
  1023. value={dialogInput}
  1024. onChange={(e) => setDialogInput(e.target.value)}
  1025. onKeyDown={handleDialogKeyDown}
  1026. autoFocus
  1027. />
  1028. </div>
  1029. </div>
  1030. <div className="flex justify-end gap-2">
  1031. <Button
  1032. variant="outline"
  1033. onClick={() => setDialogOpen(false)}
  1034. >
  1035. Cancel
  1036. </Button>
  1037. <Button onClick={handleDialogSubmit}>Submit</Button>
  1038. </div>
  1039. </DialogContent>
  1040. </Dialog>
  1041. <Sheet>
  1042. <SheetTrigger asChild>
  1043. <Button variant="outline">Open Sheet</Button>
  1044. </SheetTrigger>
  1045. <SheetContent>
  1046. <SheetHeader>
  1047. <SheetTitle>Edit profile</SheetTitle>
  1048. <SheetDescription>
  1049. Make changes to your profile here. Click save when
  1050. you're done.
  1051. </SheetDescription>
  1052. </SheetHeader>
  1053. </SheetContent>
  1054. </Sheet>
  1055. <Drawer>
  1056. <DrawerTrigger asChild>
  1057. <Button variant="outline">Open Drawer</Button>
  1058. </DrawerTrigger>
  1059. <DrawerContent>
  1060. <DrawerHeader>
  1061. <DrawerTitle>Are you absolutely sure?</DrawerTitle>
  1062. <DrawerDescription>
  1063. This action cannot be undone.
  1064. </DrawerDescription>
  1065. </DrawerHeader>
  1066. <DrawerFooter>
  1067. <Button>Submit</Button>
  1068. <DrawerClose asChild>
  1069. <Button variant="outline">Cancel</Button>
  1070. </DrawerClose>
  1071. </DrawerFooter>
  1072. </DrawerContent>
  1073. </Drawer>
  1074. <Popover>
  1075. <PopoverTrigger asChild>
  1076. <Button variant="outline">Open Popover</Button>
  1077. </PopoverTrigger>
  1078. <PopoverContent>
  1079. <div className="space-y-2">
  1080. <h4 className="font-medium leading-none">Dimensions</h4>
  1081. <p className="text-sm text-muted-foreground">
  1082. Set the dimensions for the layer.
  1083. </p>
  1084. </div>
  1085. </PopoverContent>
  1086. </Popover>
  1087. <Tooltip>
  1088. <TooltipTrigger asChild>
  1089. <Button variant="outline">Hover me</Button>
  1090. </TooltipTrigger>
  1091. <TooltipContent>
  1092. <p>Add to library</p>
  1093. </TooltipContent>
  1094. </Tooltip>
  1095. </div>
  1096. </CardContent>
  1097. </Card>
  1098. </section>
  1099. {/* Menus Section */}
  1100. <section className="space-y-4">
  1101. <h3 className="text-2xl font-semibold">Menus</h3>
  1102. <Card>
  1103. <CardContent className="pt-6">
  1104. <div className="flex flex-wrap gap-4">
  1105. <DropdownMenu>
  1106. <DropdownMenuTrigger asChild>
  1107. <Button variant="outline">Dropdown Menu</Button>
  1108. </DropdownMenuTrigger>
  1109. <DropdownMenuContent>
  1110. <DropdownMenuLabel>My Account</DropdownMenuLabel>
  1111. <DropdownMenuSeparator />
  1112. <DropdownMenuItem>Profile</DropdownMenuItem>
  1113. <DropdownMenuItem>Billing</DropdownMenuItem>
  1114. <DropdownMenuItem>Team</DropdownMenuItem>
  1115. <DropdownMenuItem>Subscription</DropdownMenuItem>
  1116. </DropdownMenuContent>
  1117. </DropdownMenu>
  1118. <ContextMenu>
  1119. <ContextMenuTrigger asChild>
  1120. <Button variant="outline">Right Click Me</Button>
  1121. </ContextMenuTrigger>
  1122. <ContextMenuContent>
  1123. <ContextMenuItem>Profile</ContextMenuItem>
  1124. <ContextMenuItem>Billing</ContextMenuItem>
  1125. <ContextMenuItem>Team</ContextMenuItem>
  1126. <ContextMenuItem>Subscription</ContextMenuItem>
  1127. </ContextMenuContent>
  1128. </ContextMenu>
  1129. <HoverCard>
  1130. <HoverCardTrigger asChild>
  1131. <Button variant="outline">Hover Card</Button>
  1132. </HoverCardTrigger>
  1133. <HoverCardContent>
  1134. <div className="space-y-2">
  1135. <h4 className="text-sm font-semibold">@nextjs</h4>
  1136. <p className="text-sm">
  1137. The React Framework – created and maintained by
  1138. @vercel.
  1139. </p>
  1140. </div>
  1141. </HoverCardContent>
  1142. </HoverCard>
  1143. </div>
  1144. </CardContent>
  1145. </Card>
  1146. </section>
  1147. {/* Calendar Section */}
  1148. <section className="space-y-4">
  1149. <h3 className="text-2xl font-semibold">Calendar</h3>
  1150. <Card>
  1151. <CardContent className="pt-6 flex justify-center">
  1152. <Calendar
  1153. mode="single"
  1154. selected={date}
  1155. onSelect={setDate}
  1156. className="rounded-md border"
  1157. />
  1158. </CardContent>
  1159. </Card>
  1160. </section>
  1161. {/* Carousel Section */}
  1162. <section className="space-y-4">
  1163. <h3 className="text-2xl font-semibold">Carousel</h3>
  1164. <Card>
  1165. <CardContent className="pt-6">
  1166. <Carousel className="w-full max-w-xs mx-auto">
  1167. <CarouselContent>
  1168. {Array.from({ length: 5 }).map((_, index) => (
  1169. <CarouselItem key={index}>
  1170. <div className="p-1">
  1171. <Card>
  1172. <CardContent className="flex aspect-square items-center justify-center p-6">
  1173. <span className="text-4xl font-semibold">
  1174. {index + 1}
  1175. </span>
  1176. </CardContent>
  1177. </Card>
  1178. </div>
  1179. </CarouselItem>
  1180. ))}
  1181. </CarouselContent>
  1182. <CarouselPrevious />
  1183. <CarouselNext />
  1184. </Carousel>
  1185. </CardContent>
  1186. </Card>
  1187. </section>
  1188. {/* Toggle Section */}
  1189. <section className="space-y-4">
  1190. <h3 className="text-2xl font-semibold">Toggle</h3>
  1191. <Card>
  1192. <CardContent className="pt-6 space-y-4">
  1193. <div className="space-y-2">
  1194. <Label>Toggle</Label>
  1195. <div className="flex gap-2">
  1196. <Toggle aria-label="Toggle italic">
  1197. <span className="font-bold">B</span>
  1198. </Toggle>
  1199. <Toggle aria-label="Toggle italic">
  1200. <span className="italic">I</span>
  1201. </Toggle>
  1202. <Toggle aria-label="Toggle underline">
  1203. <span className="underline">U</span>
  1204. </Toggle>
  1205. </div>
  1206. </div>
  1207. <Separator />
  1208. <div className="space-y-2">
  1209. <Label>Toggle Group</Label>
  1210. <ToggleGroup type="multiple">
  1211. <ToggleGroupItem value="bold" aria-label="Toggle bold">
  1212. <span className="font-bold">B</span>
  1213. </ToggleGroupItem>
  1214. <ToggleGroupItem value="italic" aria-label="Toggle italic">
  1215. <span className="italic">I</span>
  1216. </ToggleGroupItem>
  1217. <ToggleGroupItem
  1218. value="underline"
  1219. aria-label="Toggle underline"
  1220. >
  1221. <span className="underline">U</span>
  1222. </ToggleGroupItem>
  1223. </ToggleGroup>
  1224. </div>
  1225. </CardContent>
  1226. </Card>
  1227. </section>
  1228. {/* Aspect Ratio & Scroll Area Section */}
  1229. <section className="space-y-4">
  1230. <h3 className="text-2xl font-semibold">Layout Components</h3>
  1231. <Card>
  1232. <CardContent className="pt-6 space-y-6">
  1233. <div className="space-y-2">
  1234. <Label>Aspect Ratio (16/9)</Label>
  1235. <AspectRatio ratio={16 / 9} className="bg-muted">
  1236. <div className="flex h-full items-center justify-center">
  1237. <p className="text-muted-foreground">16:9 Aspect Ratio</p>
  1238. </div>
  1239. </AspectRatio>
  1240. </div>
  1241. <Separator />
  1242. <div className="space-y-2">
  1243. <Label>Scroll Area</Label>
  1244. <ScrollArea className="h-[200px] w-full rounded-md border overflow-hidden">
  1245. <div className="p-4">
  1246. <div className="space-y-4">
  1247. {Array.from({ length: 20 }).map((_, i) => (
  1248. <div key={i} className="text-sm">
  1249. Item {i + 1}: This is a scrollable content area
  1250. </div>
  1251. ))}
  1252. </div>
  1253. </div>
  1254. </ScrollArea>
  1255. </div>
  1256. </CardContent>
  1257. </Card>
  1258. </section>
  1259. {/* Resizable Section */}
  1260. <section className="space-y-4">
  1261. <h3 className="text-2xl font-semibold">Resizable Panels</h3>
  1262. <Card>
  1263. <CardContent className="pt-6">
  1264. <ResizablePanelGroup
  1265. direction="horizontal"
  1266. className="min-h-[200px] rounded-lg border"
  1267. >
  1268. <ResizablePanel defaultSize={50}>
  1269. <div className="flex h-full items-center justify-center p-6">
  1270. <span className="font-semibold">Panel One</span>
  1271. </div>
  1272. </ResizablePanel>
  1273. <ResizableHandle />
  1274. <ResizablePanel defaultSize={50}>
  1275. <div className="flex h-full items-center justify-center p-6">
  1276. <span className="font-semibold">Panel Two</span>
  1277. </div>
  1278. </ResizablePanel>
  1279. </ResizablePanelGroup>
  1280. </CardContent>
  1281. </Card>
  1282. </section>
  1283. {/* Toast Section */}
  1284. <section className="space-y-4">
  1285. <h3 className="text-2xl font-semibold">Toast</h3>
  1286. <Card>
  1287. <CardContent className="pt-6 space-y-4">
  1288. <div className="space-y-2">
  1289. <Label>Sonner Toast</Label>
  1290. <div className="flex flex-wrap gap-2">
  1291. <Button
  1292. variant="outline"
  1293. onClick={() => {
  1294. sonnerToast.success("Operation successful", {
  1295. description: "Your changes have been saved",
  1296. });
  1297. }}
  1298. >
  1299. Success
  1300. </Button>
  1301. <Button
  1302. variant="outline"
  1303. onClick={() => {
  1304. sonnerToast.error("Operation failed", {
  1305. description:
  1306. "Cannot complete operation, please try again",
  1307. });
  1308. }}
  1309. >
  1310. Error
  1311. </Button>
  1312. <Button
  1313. variant="outline"
  1314. onClick={() => {
  1315. sonnerToast.info("Information", {
  1316. description: "This is an information message",
  1317. });
  1318. }}
  1319. >
  1320. Info
  1321. </Button>
  1322. <Button
  1323. variant="outline"
  1324. onClick={() => {
  1325. sonnerToast.warning("Warning", {
  1326. description:
  1327. "Please note the impact of this operation",
  1328. });
  1329. }}
  1330. >
  1331. Warning
  1332. </Button>
  1333. <Button
  1334. variant="outline"
  1335. onClick={() => {
  1336. sonnerToast.loading("Loading", {
  1337. description: "Please wait",
  1338. });
  1339. }}
  1340. >
  1341. Loading
  1342. </Button>
  1343. <Button
  1344. variant="outline"
  1345. onClick={() => {
  1346. const promise = new Promise(resolve =>
  1347. setTimeout(resolve, 2000)
  1348. );
  1349. sonnerToast.promise(promise, {
  1350. loading: "Processing...",
  1351. success: "Processing complete!",
  1352. error: "Processing failed",
  1353. });
  1354. }}
  1355. >
  1356. Promise
  1357. </Button>
  1358. </div>
  1359. </div>
  1360. </CardContent>
  1361. </Card>
  1362. </section>
  1363. {/* AI ChatBox Section */}
  1364. <section className="space-y-4">
  1365. <h3 className="text-2xl font-semibold">AI ChatBox</h3>
  1366. <Card>
  1367. <CardContent className="pt-6">
  1368. <div className="space-y-4">
  1369. <div className="text-sm text-muted-foreground">
  1370. <p>
  1371. A ready-to-use chat interface component that integrates with the LLM system.
  1372. Features markdown rendering, auto-scrolling, and loading states.
  1373. </p>
  1374. <p className="mt-2">
  1375. This is a demo with simulated responses. In a real app, you'd connect it to a tRPC mutation.
  1376. </p>
  1377. </div>
  1378. <AIChatBox
  1379. messages={chatMessages}
  1380. onSendMessage={handleChatSend}
  1381. isLoading={isChatLoading}
  1382. placeholder="Try sending a message..."
  1383. height="500px"
  1384. emptyStateMessage="How can I help you today?"
  1385. suggestedPrompts={[
  1386. "What is React?",
  1387. "Explain TypeScript",
  1388. "How to use tRPC?",
  1389. "Best practices for web development",
  1390. ]}
  1391. />
  1392. </div>
  1393. </CardContent>
  1394. </Card>
  1395. </section>
  1396. </div>
  1397. </main>
  1398. <footer className="border-t py-6 mt-12">
  1399. <div className="container text-center text-sm text-muted-foreground">
  1400. <p>Shadcn/ui Component Showcase</p>
  1401. </div>
  1402. </footer>
  1403. </div>
  1404. );
  1405. }