feat: replace lucide icons

This commit is contained in:
shadcn 2023-06-13 16:02:07 +04:00
parent 44f93d338e
commit 3c34307ab0
15 changed files with 457 additions and 204 deletions

View file

@ -1,10 +1,10 @@
'use client' 'use client'
import * as React from 'react' import * as React from 'react'
import { ArrowDown } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { Button, type ButtonProps } from '@/components/ui/button' import { Button, type ButtonProps } from '@/components/ui/button'
import { IconArrowDown } from '@/components/ui/icons'
export function ButtonScrollToBottom({ className, ...props }: ButtonProps) { export function ButtonScrollToBottom({ className, ...props }: ButtonProps) {
const [isAtBottom, setIsAtBottom] = React.useState(false) const [isAtBottom, setIsAtBottom] = React.useState(false)
@ -41,7 +41,7 @@ export function ButtonScrollToBottom({ className, ...props }: ButtonProps) {
} }
{...props} {...props}
> >
<ArrowDown className="h-4 w-4" /> <IconArrowDown />
<span className="sr-only">Scroll to bottom</span> <span className="sr-only">Scroll to bottom</span>
</Button> </Button>
) )

View file

@ -1,12 +1,11 @@
import { Message } from 'ai-connector' import { Message } from 'ai-connector'
import { User } from 'lucide-react'
import remarkGfm from 'remark-gfm' import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math' import remarkMath from 'remark-math'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { CodeBlock } from '@/components/ui/codeblock' import { CodeBlock } from '@/components/ui/codeblock'
import { OpenAI } from '@/components/icons'
import { MemoizedReactMarkdown } from '@/components/markdown' import { MemoizedReactMarkdown } from '@/components/markdown'
import { IconOpenAI, IconUser } from '@/components/ui/icons'
export interface ChatMessageProps { export interface ChatMessageProps {
message: Message message: Message
@ -23,11 +22,7 @@ export function ChatMessage({ message, ...props }: ChatMessageProps) {
: 'bg-primary text-primary-foreground' : 'bg-primary text-primary-foreground'
)} )}
> >
{message.role === 'user' ? ( {message.role === 'user' ? <IconUser /> : <IconOpenAI />}
<User className="h-4 w-4" />
) : (
<OpenAI className="h-4 w-4" />
)}
</div> </div>
<div className="ml-4 px-1"> <div className="ml-4 px-1">
<MemoizedReactMarkdown <MemoizedReactMarkdown

View file

@ -1,12 +1,12 @@
'use client' 'use client'
import { UseChatHelpers } from 'ai-connector' import { UseChatHelpers } from 'ai-connector'
import { RefreshCcw, StopCircle } from 'lucide-react'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { ExternalLink } from '@/components/external-link' import { ExternalLink } from '@/components/external-link'
import { PromptForm } from '@/components/prompt-form' import { PromptForm } from '@/components/prompt-form'
import { ButtonScrollToBottom } from '@/components/button-scroll-to-bottom' import { ButtonScrollToBottom } from '@/components/button-scroll-to-bottom'
import { IconRefresh, IconStop } from '@/components/ui/icons'
export interface ChatPanelProps export interface ChatPanelProps
extends Pick< extends Pick<
@ -34,7 +34,7 @@ export function ChatPanel({
onClick={() => stop()} onClick={() => stop()}
className="bg-background" className="bg-background"
> >
<StopCircle className="mr-2 h-4 w-4" /> <IconStop className="mr-2" />
Stop generating Stop generating
</Button> </Button>
) : ( ) : (
@ -44,7 +44,7 @@ export function ChatPanel({
onClick={() => reload()} onClick={() => reload()}
className="bg-background" className="bg-background"
> >
<RefreshCcw className="mr-2 h-4 w-4" /> <IconRefresh className="mr-2" />
Regenerate response Regenerate response
</Button> </Button>
) )

View file

@ -1,9 +1,8 @@
import { ArrowRight } from 'lucide-react'
import { useChatStore } from '@/lib/hooks/use-chat-store' import { useChatStore } from '@/lib/hooks/use-chat-store'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { ExternalLink } from '@/components/external-link' import { ExternalLink } from '@/components/external-link'
import { IconArrowRight } from '@/components/ui/icons'
const exampleMessages = [ const exampleMessages = [
{ {
@ -47,7 +46,7 @@ export function EmptyScreen({ className }: React.ComponentProps<'div'>) {
className="h-auto p-0 text-base" className="h-auto p-0 text-base"
onClick={() => setDefaultMessage(message.message)} onClick={() => setDefaultMessage(message.message)}
> >
<ArrowRight className="mr-2 h-4 w-4 text-muted-foreground" /> <IconArrowRight className="mr-2 text-muted-foreground" />
{message.heading} {message.heading}
</Button> </Button>
))} ))}

View file

@ -1,11 +1,12 @@
import { Suspense } from 'react'
import { auth } from '@/auth' import { auth } from '@/auth'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { buttonVariants } from '@/components/ui/button' import { buttonVariants } from '@/components/ui/button'
import { GitHub, Separator, Vercel } from '@/components/icons'
import { Sidebar } from '@/components/sidebar' import { Sidebar } from '@/components/sidebar'
import { UserMenu } from '@/components/user-menu' import { UserMenu } from '@/components/user-menu'
import { SidebarList } from './sidebar-list' import { SidebarList } from '@/components/sidebar-list'
import { Suspense } from 'react' import { IconGitHub, IconSeparator, IconVercel } from '@/components/ui/icons'
export async function Header() { export async function Header() {
const session = await auth() const session = await auth()
@ -21,7 +22,7 @@ export async function Header() {
</Suspense> </Suspense>
</Sidebar> </Sidebar>
<div className="hidden items-center md:flex"> <div className="hidden items-center md:flex">
<Separator className="h-6 w-6 text-muted-foreground/50" /> <IconSeparator className="h-6 w-6 text-muted-foreground/50" />
<UserMenu session={session} /> <UserMenu session={session} />
</div> </div>
</div> </div>
@ -32,7 +33,7 @@ export async function Header() {
rel="noopener noreferrer" rel="noopener noreferrer"
className={cn(buttonVariants({ variant: 'outline' }))} className={cn(buttonVariants({ variant: 'outline' }))}
> >
<GitHub className="mr-2 h-4 w-4" /> <IconGitHub className="mr-2 h-4 w-4" />
<span>GitHub</span> <span>GitHub</span>
</a> </a>
<a <a
@ -40,7 +41,7 @@ export async function Header() {
target="_blank" target="_blank"
className={cn(buttonVariants())} className={cn(buttonVariants())}
> >
<Vercel className="mr-2 h-4 w-4" /> <IconVercel className="mr-2 h-4 w-4" />
<span className="hidden sm:block">Deploy to Vercel</span> <span className="hidden sm:block">Deploy to Vercel</span>
<span className="sm:hidden">Deploy</span> <span className="sm:hidden">Deploy</span>
</a> </a>

View file

@ -1,160 +0,0 @@
'use client'
import * as React from 'react'
import { cn } from '@/lib/utils'
export function NextChat({
className,
inverted,
...props
}: React.ComponentProps<'svg'> & { inverted?: boolean }) {
const id = React.useId()
return (
<svg
viewBox="0 0 17 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={cn('h-4 w-4', className)}
{...props}
>
<defs>
<linearGradient
id={`gradient-${id}-1`}
x1="10.6889"
y1="10.3556"
x2="13.8445"
y2="14.2667"
gradientUnits="userSpaceOnUse"
>
<stop stopColor={inverted ? 'white' : 'black'} />
<stop
offset={1}
stopColor={inverted ? 'white' : 'black'}
stopOpacity={0}
/>
</linearGradient>
<linearGradient
id={`gradient-${id}-2`}
x1="11.7555"
y1="4.8"
x2="11.7376"
y2="9.50002"
gradientUnits="userSpaceOnUse"
>
<stop stopColor={inverted ? 'white' : 'black'} />
<stop
offset={1}
stopColor={inverted ? 'white' : 'black'}
stopOpacity={0}
/>
</linearGradient>
</defs>
<path
d="M1 16L2.58314 11.2506C1.83084 9.74642 1.63835 8.02363 2.04013 6.39052C2.4419 4.75741 3.41171 3.32057 4.776 2.33712C6.1403 1.35367 7.81003 0.887808 9.4864 1.02289C11.1628 1.15798 12.7364 1.8852 13.9256 3.07442C15.1148 4.26363 15.842 5.83723 15.9771 7.5136C16.1122 9.18997 15.6463 10.8597 14.6629 12.224C13.6794 13.5883 12.2426 14.5581 10.6095 14.9599C8.97637 15.3616 7.25358 15.1692 5.74942 14.4169L1 16Z"
fill={inverted ? 'black' : 'white'}
stroke={inverted ? 'black' : 'white'}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
<mask
id="mask0_91_2047"
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x={1}
y={0}
width={16}
height={16}
>
<circle cx={9} cy={8} r={8} fill={inverted ? 'black' : 'white'} />
</mask>
<g mask="url(#mask0_91_2047)">
<circle cx={9} cy={8} r={8} fill={inverted ? 'black' : 'white'} />
<path
d="M14.2896 14.0018L7.146 4.8H5.80005V11.1973H6.87681V6.16743L13.4444 14.6529C13.7407 14.4545 14.0231 14.2369 14.2896 14.0018Z"
fill={`url(#gradient-${id}-1)`}
/>
<rect
x="11.2222"
y="4.8"
width="1.06667"
height="6.4"
fill={`url(#gradient-${id}-2)`}
/>
</g>
</svg>
)
}
export function OpenAI({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
fill="currentColor"
viewBox="0 0 24 24"
role="img"
xmlns="http://www.w3.org/2000/svg"
className={cn('h-4 w-4', className)}
{...props}
>
<title>OpenAI icon</title>
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" />
</svg>
)
}
export function Vercel({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
aria-label="Vercel logomark"
role="img"
viewBox="0 0 74 64"
className={cn('h-4 w-4', className)}
{...props}
>
<path
d="M37.5896 0.25L74.5396 64.25H0.639648L37.5896 0.25Z"
fill="currentColor"
></path>
</svg>
)
}
export function GitHub({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
)
}
export function Separator({
className,
...props
}: React.ComponentProps<'svg'>) {
return (
<svg
fill="none"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1"
viewBox="0 0 24 24"
aria-hidden="true"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
)
}

View file

@ -2,7 +2,6 @@
import * as React from 'react' import * as React from 'react'
import Link from 'next/link' import Link from 'next/link'
import { CornerDownLeft, Plus } from 'lucide-react'
import Textarea from 'react-textarea-autosize' import Textarea from 'react-textarea-autosize'
import { useChatStore } from '@/lib/hooks/use-chat-store' import { useChatStore } from '@/lib/hooks/use-chat-store'
@ -15,6 +14,7 @@ import {
TooltipProvider, TooltipProvider,
TooltipTrigger TooltipTrigger
} from '@/components/ui/tooltip' } from '@/components/ui/tooltip'
import { IconArrowElbow, IconPlus } from '@/components/ui/icons'
export interface PromptProps { export interface PromptProps {
onSubmit: (value: string) => void onSubmit: (value: string) => void
@ -60,7 +60,7 @@ export function PromptForm({ onSubmit, isLoading }: PromptProps) {
'absolute left-0 top-4 h-8 w-8 rounded-full bg-background p-0 sm:left-4' 'absolute left-0 top-4 h-8 w-8 rounded-full bg-background p-0 sm:left-4'
)} )}
> >
<Plus className="h-4 w-4" /> <IconPlus />
<span className="sr-only">New Chat</span> <span className="sr-only">New Chat</span>
</Link> </Link>
</TooltipTrigger> </TooltipTrigger>
@ -85,7 +85,7 @@ export function PromptForm({ onSubmit, isLoading }: PromptProps) {
size="icon" size="icon"
disabled={isLoading || input === ''} disabled={isLoading || input === ''}
> >
<CornerDownLeft className="h-4 w-4" /> <IconArrowElbow />
<span className="sr-only">Send message</span> <span className="sr-only">Send message</span>
</Button> </Button>
</TooltipTrigger> </TooltipTrigger>

View file

@ -4,7 +4,6 @@ import * as React from 'react'
import { useTransition } from 'react' import { useTransition } from 'react'
import Link from 'next/link' import Link from 'next/link'
import { usePathname, useRouter } from 'next/navigation' import { usePathname, useRouter } from 'next/navigation'
import { Loader2Icon, MessageSquare, Trash2Icon } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { import {
@ -19,6 +18,7 @@ import {
} from '@/components/ui/alert-dialog' } from '@/components/ui/alert-dialog'
import { Button, buttonVariants } from '@/components/ui/button' import { Button, buttonVariants } from '@/components/ui/button'
import { removeChat } from '@/app/actions' import { removeChat } from '@/app/actions'
import { IconMessage, IconSpinner, IconTrash } from '@/components/ui/icons'
export function SidebarItem({ export function SidebarItem({
title, title,
@ -49,7 +49,7 @@ export function SidebarItem({
isActive && 'bg-accent' isActive && 'bg-accent'
)} )}
> >
<MessageSquare className="mr-2 h-4 w-4" /> <IconMessage className="mr-2" />
<div <div
className="relative max-h-5 flex-1 select-none overflow-hidden text-ellipsis break-all" className="relative max-h-5 flex-1 select-none overflow-hidden text-ellipsis break-all"
title={title} title={title}
@ -64,7 +64,7 @@ export function SidebarItem({
disabled={isPending} disabled={isPending}
onClick={() => setIsOpen(true)} onClick={() => setIsOpen(true)}
> >
<Trash2Icon className="h-4 w-4" /> <IconTrash />
<span className="sr-only">Delete</span> <span className="sr-only">Delete</span>
</Button> </Button>
)} )}
@ -91,9 +91,7 @@ export function SidebarItem({
}) })
}} }}
> >
{isPending && ( {isPending && <IconSpinner className="mr-2 animate-spin" />}
<Loader2Icon className="mr-2 h-4 w-4 animate-spin" />
)}
Delete Delete
</AlertDialogAction> </AlertDialogAction>
</AlertDialogFooter> </AlertDialogFooter>

View file

@ -3,7 +3,6 @@
import * as React from 'react' import * as React from 'react'
import { signOut } from '@auth/nextjs/client' import { signOut } from '@auth/nextjs/client'
import { type Session } from '@auth/nextjs/types' import { type Session } from '@auth/nextjs/types'
import { Sidebar as SidebarIcon } from 'lucide-react'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { import {
@ -14,6 +13,7 @@ import {
SheetTrigger SheetTrigger
} from '@/components/ui/sheet' } from '@/components/ui/sheet'
import { ThemeToggle } from '@/components/theme-toggle' import { ThemeToggle } from '@/components/theme-toggle'
import { IconSidebar } from '@/components/ui/icons'
export interface SidebarProps { export interface SidebarProps {
session?: Session session?: Session
@ -25,7 +25,7 @@ export function Sidebar({ session, children }: SidebarProps) {
<Sheet> <Sheet>
<SheetTrigger asChild> <SheetTrigger asChild>
<Button variant="ghost" className="-ml-2 h-9 w-9 p-0"> <Button variant="ghost" className="-ml-2 h-9 w-9 p-0">
<SidebarIcon className="h-6 w-6" /> <IconSidebar className="h-6 w-6" />
<span className="sr-only">Toggle Sidebar</span> <span className="sr-only">Toggle Sidebar</span>
</Button> </Button>
</SheetTrigger> </SheetTrigger>

View file

@ -1,10 +1,10 @@
'use client' 'use client'
import * as React from 'react' import * as React from 'react'
import { Moon, Sun } from 'lucide-react'
import { useTheme } from 'next-themes' import { useTheme } from 'next-themes'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { IconMoon, IconSun } from '@/components/ui/icons'
export function ThemeToggle() { export function ThemeToggle() {
const { setTheme, theme } = useTheme() const { setTheme, theme } = useTheme()
@ -21,9 +21,9 @@ export function ThemeToggle() {
}} }}
> >
{!theme ? null : theme === 'dark' ? ( {!theme ? null : theme === 'dark' ? (
<Moon className="h-4 w-4 transition-all" /> <IconMoon className="transition-all" />
) : ( ) : (
<Sun className="h-4 w-4 transition-all" /> <IconSun className="transition-all" />
)} )}
<span className="sr-only">Toggle theme</span> <span className="sr-only">Toggle theme</span>
</Button> </Button>

View file

@ -1,11 +1,11 @@
'use client' 'use client'
import { FC, memo } from 'react' import { FC, memo } from 'react'
import { Check, Clipboard, Download } from 'lucide-react'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { coldarkDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' import { coldarkDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'
import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-cliipboard' import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-cliipboard'
import { IconCheck, IconCopy, IconDownload } from '@/components/ui/icons'
interface Props { interface Props {
language: string language: string
@ -91,7 +91,7 @@ const CodeBlock: FC<Props> = memo(({ language, value }) => {
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-white" className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-white"
onClick={() => copyToClipboard(value)} onClick={() => copyToClipboard(value)}
> >
{isCopied ? <Check size={18} /> : <Clipboard size={18} />} {isCopied ? <IconCheck /> : <IconCopy />}
{isCopied ? 'Copied!' : 'Copy code'} {isCopied ? 'Copied!' : 'Copy code'}
</button> </button>
<button <button
@ -99,7 +99,7 @@ const CodeBlock: FC<Props> = memo(({ language, value }) => {
className="flex items-center rounded bg-none p-1 text-xs text-white" className="flex items-center rounded bg-none p-1 text-xs text-white"
onClick={downloadAsFile} onClick={downloadAsFile}
> >
<Download size={18} /> <IconDownload />
</button> </button>
</div> </div>
</div> </div>

View file

@ -2,9 +2,9 @@
import * as React from 'react' import * as React from 'react'
import * as DialogPrimitive from '@radix-ui/react-dialog' import * as DialogPrimitive from '@radix-ui/react-dialog'
import { X } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { IconClose } from '@/components/ui/icons'
const Dialog = DialogPrimitive.Root const Dialog = DialogPrimitive.Root
@ -54,7 +54,7 @@ const DialogContent = React.forwardRef<
> >
{children} {children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" /> <IconClose />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</DialogPrimitive.Close> </DialogPrimitive.Close>
</DialogPrimitive.Content> </DialogPrimitive.Content>

420
components/ui/icons.tsx Normal file
View file

@ -0,0 +1,420 @@
'use client'
import * as React from 'react'
import { cn } from '@/lib/utils'
function IconNextChat({
className,
inverted,
...props
}: React.ComponentProps<'svg'> & { inverted?: boolean }) {
const id = React.useId()
return (
<svg
viewBox="0 0 17 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={cn('h-4 w-4', className)}
{...props}
>
<defs>
<linearGradient
id={`gradient-${id}-1`}
x1="10.6889"
y1="10.3556"
x2="13.8445"
y2="14.2667"
gradientUnits="userSpaceOnUse"
>
<stop stopColor={inverted ? 'white' : 'black'} />
<stop
offset={1}
stopColor={inverted ? 'white' : 'black'}
stopOpacity={0}
/>
</linearGradient>
<linearGradient
id={`gradient-${id}-2`}
x1="11.7555"
y1="4.8"
x2="11.7376"
y2="9.50002"
gradientUnits="userSpaceOnUse"
>
<stop stopColor={inverted ? 'white' : 'black'} />
<stop
offset={1}
stopColor={inverted ? 'white' : 'black'}
stopOpacity={0}
/>
</linearGradient>
</defs>
<path
d="M1 16L2.58314 11.2506C1.83084 9.74642 1.63835 8.02363 2.04013 6.39052C2.4419 4.75741 3.41171 3.32057 4.776 2.33712C6.1403 1.35367 7.81003 0.887808 9.4864 1.02289C11.1628 1.15798 12.7364 1.8852 13.9256 3.07442C15.1148 4.26363 15.842 5.83723 15.9771 7.5136C16.1122 9.18997 15.6463 10.8597 14.6629 12.224C13.6794 13.5883 12.2426 14.5581 10.6095 14.9599C8.97637 15.3616 7.25358 15.1692 5.74942 14.4169L1 16Z"
fill={inverted ? 'black' : 'white'}
stroke={inverted ? 'black' : 'white'}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
<mask
id="mask0_91_2047"
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x={1}
y={0}
width={16}
height={16}
>
<circle cx={9} cy={8} r={8} fill={inverted ? 'black' : 'white'} />
</mask>
<g mask="url(#mask0_91_2047)">
<circle cx={9} cy={8} r={8} fill={inverted ? 'black' : 'white'} />
<path
d="M14.2896 14.0018L7.146 4.8H5.80005V11.1973H6.87681V6.16743L13.4444 14.6529C13.7407 14.4545 14.0231 14.2369 14.2896 14.0018Z"
fill={`url(#gradient-${id}-1)`}
/>
<rect
x="11.2222"
y="4.8"
width="1.06667"
height="6.4"
fill={`url(#gradient-${id}-2)`}
/>
</g>
</svg>
)
}
function IconOpenAI({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
fill="currentColor"
viewBox="0 0 24 24"
role="img"
xmlns="http://www.w3.org/2000/svg"
className={cn('h-4 w-4', className)}
{...props}
>
<title>OpenAI icon</title>
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" />
</svg>
)
}
function IconVercel({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
aria-label="Vercel logomark"
role="img"
viewBox="0 0 74 64"
className={cn('h-4 w-4', className)}
{...props}
>
<path
d="M37.5896 0.25L74.5396 64.25H0.639648L37.5896 0.25Z"
fill="currentColor"
></path>
</svg>
)
}
function IconGitHub({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
)
}
function IconSeparator({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
fill="none"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1"
viewBox="0 0 24 24"
aria-hidden="true"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M16.88 3.549L7.12 20.451"></path>
</svg>
)
}
function IconArrowDown({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="m205.66 149.66-72 72a8 8 0 0 1-11.32 0l-72-72a8 8 0 0 1 11.32-11.32L120 196.69V40a8 8 0 0 1 16 0v156.69l58.34-58.35a8 8 0 0 1 11.32 11.32Z" />
</svg>
)
}
function IconArrowRight({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="m221.66 133.66-72 72a8 8 0 0 1-11.32-11.32L196.69 136H40a8 8 0 0 1 0-16h156.69l-58.35-58.34a8 8 0 0 1 11.32-11.32l72 72a8 8 0 0 1 0 11.32Z" />
</svg>
)
}
function IconUser({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M230.92 212c-15.23-26.33-38.7-45.21-66.09-54.16a72 72 0 1 0-73.66 0c-27.39 8.94-50.86 27.82-66.09 54.16a8 8 0 1 0 13.85 8c18.84-32.56 52.14-52 89.07-52s70.23 19.44 89.07 52a8 8 0 1 0 13.85-8ZM72 96a56 56 0 1 1 56 56 56.06 56.06 0 0 1-56-56Z" />
</svg>
)
}
function IconPlus({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M224 128a8 8 0 0 1-8 8h-80v80a8 8 0 0 1-16 0v-80H40a8 8 0 0 1 0-16h80V40a8 8 0 0 1 16 0v80h80a8 8 0 0 1 8 8Z" />
</svg>
)
}
function IconArrowElbow({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M200 32v144a8 8 0 0 1-8 8H67.31l34.35 34.34a8 8 0 0 1-11.32 11.32l-48-48a8 8 0 0 1 0-11.32l48-48a8 8 0 0 1 11.32 11.32L67.31 168H184V32a8 8 0 0 1 16 0Z" />
</svg>
)
}
function IconSpinner({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M232 128a104 104 0 0 1-208 0c0-41 23.81-78.36 60.66-95.27a8 8 0 0 1 6.68 14.54C60.15 61.59 40 93.27 40 128a88 88 0 0 0 176 0c0-34.73-20.15-66.41-51.34-80.73a8 8 0 0 1 6.68-14.54C208.19 49.64 232 87 232 128Z" />
</svg>
)
}
function IconMessage({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M216 48H40a16 16 0 0 0-16 16v160a15.84 15.84 0 0 0 9.25 14.5A16.05 16.05 0 0 0 40 240a15.89 15.89 0 0 0 10.25-3.78.69.69 0 0 0 .13-.11L82.5 208H216a16 16 0 0 0 16-16V64a16 16 0 0 0-16-16ZM40 224Zm176-32H82.5a16 16 0 0 0-10.3 3.75l-.12.11L40 224V64h176Z" />
</svg>
)
}
function IconTrash({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M216 48h-40v-8a24 24 0 0 0-24-24h-48a24 24 0 0 0-24 24v8H40a8 8 0 0 0 0 16h8v144a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16V64h8a8 8 0 0 0 0-16ZM96 40a8 8 0 0 1 8-8h48a8 8 0 0 1 8 8v8H96Zm96 168H64V64h128Zm-80-104v64a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Zm48 0v64a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Z" />
</svg>
)
}
function IconRefresh({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M197.67 186.37a8 8 0 0 1 0 11.29C196.58 198.73 170.82 224 128 224c-37.39 0-64.53-22.4-80-39.85V208a8 8 0 0 1-16 0v-48a8 8 0 0 1 8-8h48a8 8 0 0 1 0 16H55.44C67.76 183.35 93 208 128 208c36 0 58.14-21.46 58.36-21.68a8 8 0 0 1 11.31.05ZM216 40a8 8 0 0 0-8 8v23.85C192.53 54.4 165.39 32 128 32c-42.82 0-68.58 25.27-69.66 26.34a8 8 0 0 0 11.3 11.34C69.86 69.46 92 48 128 48c35 0 60.24 24.65 72.56 40H168a8 8 0 0 0 0 16h48a8 8 0 0 0 8-8V48a8 8 0 0 0-8-8Z" />
</svg>
)
}
function IconStop({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24Zm0 192a88 88 0 1 1 88-88 88.1 88.1 0 0 1-88 88Zm24-120h-48a8 8 0 0 0-8 8v48a8 8 0 0 0 8 8h48a8 8 0 0 0 8-8v-48a8 8 0 0 0-8-8Zm-8 48h-32v-32h32Z" />
</svg>
)
}
function IconSidebar({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M216 40H40a16 16 0 0 0-16 16v144a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16ZM40 56h40v144H40Zm176 144H96V56h120v144Z" />
</svg>
)
}
function IconMoon({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M233.54 142.23a8 8 0 0 0-8-2 88.08 88.08 0 0 1-109.8-109.8 8 8 0 0 0-10-10 104.84 104.84 0 0 0-52.91 37A104 104 0 0 0 136 224a103.09 103.09 0 0 0 62.52-20.88 104.84 104.84 0 0 0 37-52.91 8 8 0 0 0-1.98-7.98Zm-44.64 48.11A88 88 0 0 1 65.66 67.11a89 89 0 0 1 31.4-26A106 106 0 0 0 96 56a104.11 104.11 0 0 0 104 104 106 106 0 0 0 14.92-1.06 89 89 0 0 1-26.02 31.4Z" />
</svg>
)
}
function IconSun({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M120 40V16a8 8 0 0 1 16 0v24a8 8 0 0 1-16 0Zm72 88a64 64 0 1 1-64-64 64.07 64.07 0 0 1 64 64Zm-16 0a48 48 0 1 0-48 48 48.05 48.05 0 0 0 48-48ZM58.34 69.66a8 8 0 0 0 11.32-11.32l-16-16a8 8 0 0 0-11.32 11.32Zm0 116.68-16 16a8 8 0 0 0 11.32 11.32l16-16a8 8 0 0 0-11.32-11.32ZM192 72a8 8 0 0 0 5.66-2.34l16-16a8 8 0 0 0-11.32-11.32l-16 16A8 8 0 0 0 192 72Zm5.66 114.34a8 8 0 0 0-11.32 11.32l16 16a8 8 0 0 0 11.32-11.32ZM48 128a8 8 0 0 0-8-8H16a8 8 0 0 0 0 16h24a8 8 0 0 0 8-8Zm80 80a8 8 0 0 0-8 8v24a8 8 0 0 0 16 0v-24a8 8 0 0 0-8-8Zm112-88h-24a8 8 0 0 0 0 16h24a8 8 0 0 0 0-16Z" />
</svg>
)
}
function IconCopy({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M216 32H88a8 8 0 0 0-8 8v40H40a8 8 0 0 0-8 8v128a8 8 0 0 0 8 8h128a8 8 0 0 0 8-8v-40h40a8 8 0 0 0 8-8V40a8 8 0 0 0-8-8Zm-56 176H48V96h112Zm48-48h-32V88a8 8 0 0 0-8-8H96V48h112Z" />
</svg>
)
}
function IconCheck({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="m229.66 77.66-128 128a8 8 0 0 1-11.32 0l-56-56a8 8 0 0 1 11.32-11.32L96 188.69 218.34 66.34a8 8 0 0 1 11.32 11.32Z" />
</svg>
)
}
function IconDownload({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M224 152v56a16 16 0 0 1-16 16H48a16 16 0 0 1-16-16v-56a8 8 0 0 1 16 0v56h160v-56a8 8 0 0 1 16 0Zm-101.66 5.66a8 8 0 0 0 11.32 0l40-40a8 8 0 0 0-11.32-11.32L136 132.69V40a8 8 0 0 0-16 0v92.69l-26.34-26.35a8 8 0 0 0-11.32 11.32Z" />
</svg>
)
}
function IconClose({ className, ...props }: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256"
fill="currentColor"
className={cn('h-4 w-4', className)}
{...props}
>
<path d="M205.66 194.34a8 8 0 0 1-11.32 11.32L128 139.31l-66.34 66.35a8 8 0 0 1-11.32-11.32L116.69 128 50.34 61.66a8 8 0 0 1 11.32-11.32L128 116.69l66.34-66.35a8 8 0 0 1 11.32 11.32L139.31 128Z" />
</svg>
)
}
export {
IconNextChat,
IconOpenAI,
IconVercel,
IconGitHub,
IconSeparator,
IconArrowDown,
IconArrowRight,
IconUser,
IconPlus,
IconArrowElbow,
IconSpinner,
IconMessage,
IconTrash,
IconRefresh,
IconStop,
IconSidebar,
IconMoon,
IconSun,
IconCopy,
IconCheck,
IconDownload,
IconClose
}

View file

@ -3,9 +3,9 @@
import * as React from 'react' import * as React from 'react'
import * as SheetPrimitive from '@radix-ui/react-dialog' import * as SheetPrimitive from '@radix-ui/react-dialog'
import { cva, type VariantProps } from 'class-variance-authority' import { cva, type VariantProps } from 'class-variance-authority'
import { X } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { IconClose } from '@/components/ui/icons'
const Sheet = SheetPrimitive.Root const Sheet = SheetPrimitive.Root
@ -73,7 +73,7 @@ const SheetContent = React.forwardRef<
> >
{children} {children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"> <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" /> <IconClose />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</SheetPrimitive.Close> </SheetPrimitive.Close>
</SheetPrimitive.Content> </SheetPrimitive.Content>

View file

@ -3,9 +3,9 @@
import * as React from 'react' import * as React from 'react'
import { signIn } from '@auth/nextjs/client' import { signIn } from '@auth/nextjs/client'
import { type Session } from '@auth/nextjs/types' import { type Session } from '@auth/nextjs/types'
import { Loader2Icon } from 'lucide-react'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { IconSpinner } from '@/components/ui/icons'
export interface UserMenuProps { export interface UserMenuProps {
session?: Session session?: Session
@ -25,7 +25,7 @@ export function UserMenu({ session }: UserMenuProps) {
}} }}
disabled={isLoading} disabled={isLoading}
> >
{isLoading && <Loader2Icon className="mr-2 h-4 w-4 animate-spin" />} {isLoading && <IconSpinner className="mr-2 animate-spin" />}
Login Login
</Button> </Button>
) )