Improve chat navigation, model selection, and streaming

This commit is contained in:
Rami Bitar
2026-09-16 13:14:55 -04:00
parent 8790cfb1e2
commit dd04493e25
73 changed files with 1272 additions and 1367 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDownIcon } from "lucide-react"
import { RiArrowDownSLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -41,7 +41,7 @@ function AccordionTrigger({
{...props}
>
{children}
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
<RiArrowDownSLine className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
)
+3 -3
View File
@@ -1,6 +1,6 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { ChevronRight, MoreHorizontal } from "lucide-react"
import { RiArrowRightSLine, RiMoreLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -75,7 +75,7 @@ function BreadcrumbSeparator({
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRight />}
{children ?? <RiArrowRightSLine />}
</li>
)
}
@@ -92,7 +92,7 @@ function BreadcrumbEllipsis({
className={cn("flex size-9 items-center justify-center", className)}
{...props}
>
<MoreHorizontal className="size-4" />
<RiMoreLine className="size-4" />
<span className="sr-only">More</span>
</span>
)
+7 -7
View File
@@ -2,10 +2,10 @@
import * as React from "react"
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react"
RiArrowDownSLine,
RiArrowLeftSLine,
RiArrowRightSLine,
} from "@remixicon/react"
import {
DayPicker,
getDefaultClassNames,
@@ -145,13 +145,13 @@ function Calendar({
Chevron: ({ className, orientation, ...props }) => {
if (orientation === "left") {
return (
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
<RiArrowLeftSLine className={cn("size-4", className)} {...props} />
)
}
if (orientation === "right") {
return (
<ChevronRightIcon
<RiArrowRightSLine
className={cn("size-4", className)}
{...props}
/>
@@ -159,7 +159,7 @@ function Calendar({
}
return (
<ChevronDownIcon className={cn("size-4", className)} {...props} />
<RiArrowDownSLine className={cn("size-4", className)} {...props} />
)
},
DayButton: CalendarDayButton,
+5 -5
View File
@@ -4,7 +4,7 @@ import * as React from "react"
import useEmblaCarousel, {
type UseEmblaCarouselType,
} from "embla-carousel-react"
import { ArrowLeft, ArrowRight } from "lucide-react"
import { RiArrowLeftLine, RiArrowRightLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
@@ -77,10 +77,10 @@ function Carousel({
const handleKeyDown = React.useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "ArrowLeft") {
if (event.key === "RiArrowLeftLine") {
event.preventDefault()
scrollPrev()
} else if (event.key === "ArrowRight") {
} else if (event.key === "RiArrowRightLine") {
event.preventDefault()
scrollNext()
}
@@ -195,7 +195,7 @@ function CarouselPrevious({
onClick={scrollPrev}
{...props}
>
<ArrowLeft />
<RiArrowLeftLine />
<span className="sr-only">Previous slide</span>
</Button>
)
@@ -225,7 +225,7 @@ function CarouselNext({
onClick={scrollNext}
{...props}
>
<ArrowRight />
<RiArrowRightLine />
<span className="sr-only">Next slide</span>
</Button>
)
+2 -2
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { CheckIcon } from "lucide-react"
import { RiCheckLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -23,7 +23,7 @@ function Checkbox({
data-slot="checkbox-indicator"
className="grid place-content-center text-current transition-none"
>
<CheckIcon className="size-3.5" />
<RiCheckLine className="size-3.5" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
)
+5 -5
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import { Combobox as ComboboxPrimitive } from "@base-ui/react"
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react"
import { RiCheckLine, RiArrowDownSLine, RiCloseLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
@@ -31,7 +31,7 @@ function ComboboxTrigger({
{...props}
>
{children}
<ChevronDownIcon
<RiArrowDownSLine
data-slot="combobox-trigger-icon"
className="text-muted-foreground pointer-events-none size-4"
/>
@@ -47,7 +47,7 @@ function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
className={cn(className)}
{...props}
>
<XIcon className="pointer-events-none" />
<RiCloseLine className="pointer-events-none" />
</ComboboxPrimitive.Clear>
)
}
@@ -160,7 +160,7 @@ function ComboboxItem({
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
}
>
<CheckIcon className="pointer-events-none size-4 pointer-coarse:size-5" />
<RiCheckLine className="pointer-events-none size-4 pointer-coarse:size-5" />
</ComboboxPrimitive.ItemIndicator>
</ComboboxPrimitive.Item>
)
@@ -265,7 +265,7 @@ function ComboboxChip({
className="-ml-1 opacity-50 hover:opacity-100"
data-slot="combobox-chip-remove"
>
<XIcon className="pointer-events-none" />
<RiCloseLine className="pointer-events-none" />
</ComboboxPrimitive.ChipRemove>
)}
</ComboboxPrimitive.Chip>
+2 -2
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import { Command as CommandPrimitive } from "cmdk"
import { SearchIcon } from "lucide-react"
import { RiSearchLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
import {
@@ -69,7 +69,7 @@ function CommandInput({
data-slot="command-input-wrapper"
className="flex h-9 items-center gap-2 border-b px-3"
>
<SearchIcon className="size-4 shrink-0 opacity-50" />
<RiSearchLine className="size-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
data-slot="command-input"
className={cn(
+4 -4
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
import { RiCheckLine, RiArrowRightSLine, RiCircleLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -72,7 +72,7 @@ function ContextMenuSubTrigger({
{...props}
>
{children}
<ChevronRightIcon className="ml-auto" />
<RiArrowRightSLine className="ml-auto" />
</ContextMenuPrimitive.SubTrigger>
)
}
@@ -152,7 +152,7 @@ function ContextMenuCheckboxItem({
>
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<CheckIcon className="size-4" />
<RiCheckLine className="size-4" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
@@ -176,7 +176,7 @@ function ContextMenuRadioItem({
>
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<CircleIcon className="size-2 fill-current" />
<RiCircleLine className="size-2 fill-current" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
+1 -1
View File
@@ -45,7 +45,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
'relative z-50 grid w-full max-w-lg gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg',
'relative z-50 grid w-full max-w-lg gap-4 border border-border bg-background p-6 shadow-lg duration-200 rounded-lg',
'data-[state=open]:animate-in data-[state=closed]:animate-out',
'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
+4 -4
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
import { RiCheckLine, RiArrowRightSLine, RiCircleLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -100,7 +100,7 @@ function DropdownMenuCheckboxItem({
>
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon className="size-4" />
<RiCheckLine className="size-4" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
@@ -135,7 +135,7 @@ function DropdownMenuRadioItem({
>
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<CircleIcon className="size-2 fill-current" />
<RiCircleLine className="size-2 fill-current" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
@@ -217,7 +217,7 @@ function DropdownMenuSubTrigger({
{...props}
>
{children}
<ChevronRightIcon className="ml-auto size-4" />
<RiArrowRightSLine className="ml-auto size-4" />
</DropdownMenuPrimitive.SubTrigger>
)
}
+2 -2
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import { OTPInput, OTPInputContext } from "input-otp"
import { MinusIcon } from "lucide-react"
import { RiSubtractLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -69,7 +69,7 @@ function InputOTPSlot({
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
return (
<div data-slot="input-otp-separator" role="separator" {...props}>
<MinusIcon />
<RiSubtractLine />
</div>
)
}
+4 -4
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as MenubarPrimitive from "@radix-ui/react-menubar"
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
import { RiCheckLine, RiArrowRightSLine, RiCircleLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -129,7 +129,7 @@ function MenubarCheckboxItem({
>
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<CheckIcon className="size-4" />
<RiCheckLine className="size-4" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
@@ -153,7 +153,7 @@ function MenubarRadioItem({
>
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<CircleIcon className="size-2 fill-current" />
<RiCircleLine className="size-2 fill-current" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
@@ -235,7 +235,7 @@ function MenubarSubTrigger({
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
<RiArrowRightSLine className="ml-auto h-4 w-4" />
</MenubarPrimitive.SubTrigger>
)
}
+2 -2
View File
@@ -1,5 +1,5 @@
import * as React from "react"
import { ChevronDownIcon } from "lucide-react"
import { RiArrowDownSLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -24,7 +24,7 @@ function NativeSelect({
)}
{...props}
/>
<ChevronDownIcon
<RiArrowDownSLine
className="text-muted-foreground pointer-events-none absolute top-1/2 right-3.5 size-4 -translate-y-1/2 opacity-50 select-none"
aria-hidden="true"
data-slot="native-select-icon"
+2 -2
View File
@@ -1,7 +1,7 @@
import * as React from "react"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
import { ChevronDownIcon } from "lucide-react"
import { RiArrowDownSLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -74,7 +74,7 @@ function NavigationMenuTrigger({
{...props}
>
{children}{" "}
<ChevronDownIcon
<RiArrowDownSLine
className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
aria-hidden="true"
/>
+7 -7
View File
@@ -1,9 +1,9 @@
import * as React from "react"
import {
ChevronLeftIcon,
ChevronRightIcon,
MoreHorizontalIcon,
} from "lucide-react"
RiArrowLeftSLine,
RiArrowRightSLine,
RiMoreLine,
} from "@remixicon/react"
import { cn } from "@/lib/utils"
import { buttonVariants, type Button } from "@/components/ui/button"
@@ -76,7 +76,7 @@ function PaginationPrevious({
className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
{...props}
>
<ChevronLeftIcon />
<RiArrowLeftSLine />
<span className="hidden sm:block">Previous</span>
</PaginationLink>
)
@@ -94,7 +94,7 @@ function PaginationNext({
{...props}
>
<span className="hidden sm:block">Next</span>
<ChevronRightIcon />
<RiArrowRightSLine />
</PaginationLink>
)
}
@@ -110,7 +110,7 @@ function PaginationEllipsis({
className={cn("flex size-9 items-center justify-center", className)}
{...props}
>
<MoreHorizontalIcon className="size-4" />
<RiMoreLine className="size-4" />
<span className="sr-only">More pages</span>
</span>
)
+2 -2
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
import { CircleIcon } from "lucide-react"
import { RiCircleFill } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -36,7 +36,7 @@ function RadioGroupItem({
data-slot="radio-group-indicator"
className="relative flex items-center justify-center"
>
<CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
<RiCircleFill className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
)
+2 -2
View File
@@ -1,7 +1,7 @@
"use client"
import * as React from "react"
import { GripVerticalIcon } from "lucide-react"
import { RiDraggable } from "@remixicon/react"
import * as ResizablePrimitive from "react-resizable-panels"
import { cn } from "@/lib/utils"
@@ -46,7 +46,7 @@ function ResizableHandle({
>
{withHandle && (
<div className="bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border">
<GripVerticalIcon className="size-2.5" />
<RiDraggable className="size-2.5" />
</div>
)}
</ResizablePrimitive.Separator>
+5 -5
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
import { RiCheckLine, RiArrowDownSLine, RiArrowUpSLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -44,7 +44,7 @@ function SelectTrigger({
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDownIcon className="size-4 opacity-50" />
<RiArrowDownSLine className="size-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
)
@@ -119,7 +119,7 @@ function SelectItem({
className="absolute right-2 flex size-3.5 items-center justify-center"
>
<SelectPrimitive.ItemIndicator>
<CheckIcon className="size-4" />
<RiCheckLine className="size-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
@@ -153,7 +153,7 @@ function SelectScrollUpButton({
)}
{...props}
>
<ChevronUpIcon className="size-4" />
<RiArrowUpSLine className="size-4" />
</SelectPrimitive.ScrollUpButton>
)
}
@@ -171,7 +171,7 @@ function SelectScrollDownButton({
)}
{...props}
>
<ChevronDownIcon className="size-4" />
<RiArrowDownSLine className="size-4" />
</SelectPrimitive.ScrollDownButton>
)
}
+2 -2
View File
@@ -2,7 +2,7 @@
import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { XIcon } from "lucide-react"
import { RiCloseLine } from "@remixicon/react"
import { cn } from "@/lib/utils"
@@ -76,7 +76,7 @@ function SheetContent({
{children}
{showCloseButton && (
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
<XIcon className="size-4" />
<RiCloseLine className="size-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
)}
+2 -2
View File
@@ -3,7 +3,7 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { PanelLeftIcon } from "lucide-react"
import { RiLayoutLeftLine } from "@remixicon/react"
import { useIsMobile } from "@/hooks/use-mobile"
import { cn } from "@/lib/utils"
@@ -273,7 +273,7 @@ function SidebarTrigger({
}}
{...props}
>
<PanelLeftIcon />
<RiLayoutLeftLine className="size-5" aria-hidden="true" />
<span className="sr-only">Toggle Sidebar</span>
</Button>
)
+11 -11
View File
@@ -1,12 +1,12 @@
"use client"
import {
CircleCheckIcon,
InfoIcon,
Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from "lucide-react"
RiCheckboxCircleLine,
RiInformationLine,
RiLoader4Line,
RiCloseCircleLine,
RiErrorWarningLine,
} from "@remixicon/react"
import { useTheme } from "next-themes"
import { Toaster as Sonner, type ToasterProps } from "sonner"
@@ -18,11 +18,11 @@ const Toaster = ({ ...props }: ToasterProps) => {
theme={theme as ToasterProps["theme"]}
className="toaster group"
icons={{
success: <CircleCheckIcon className="size-4" />,
info: <InfoIcon className="size-4" />,
warning: <TriangleAlertIcon className="size-4" />,
error: <OctagonXIcon className="size-4" />,
loading: <Loader2Icon className="size-4 animate-spin" />,
success: <RiCheckboxCircleLine className="size-4" />,
info: <RiInformationLine className="size-4" />,
warning: <RiErrorWarningLine className="size-4" />,
error: <RiCloseCircleLine className="size-4" />,
loading: <RiLoader4Line className="size-4 animate-spin" />,
}}
style={
{
+3 -3
View File
@@ -1,10 +1,10 @@
import { Loader2Icon } from "lucide-react"
import { RiLoader4Line } from "@remixicon/react"
import { cn } from "@/lib/utils"
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
function Spinner({ className, ...props }: React.ComponentProps<typeof RiLoader4Line>) {
return (
<Loader2Icon
<RiLoader4Line
role="status"
aria-label="Loading"
className={cn("size-4 animate-spin", className)}