diff --git a/app/(chat)/chat/[id]/page.tsx b/app/(chat)/chat/[id]/page.tsx deleted file mode 100644 index 88b51462b6a8fe704d31f29457c016e1ed78a877..0000000000000000000000000000000000000000 --- a/app/(chat)/chat/[id]/page.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { type Metadata } from 'next'; -import { notFound, redirect } from 'next/navigation'; - -import { auth } from '@/auth'; -import { getChat } from '@/app/actions'; -import { Chat } from '@/components/chat'; - -export interface ChatPageProps { - params: { - id: string; - }; -} - -export async function generateMetadata({ - params, -}: ChatPageProps): Promise { - const session = await auth(); - - if (!session?.user) { - return {}; - } - - const chat = await getChat(params.id, session.user.id); - return { - title: chat?.title.toString().slice(0, 50) ?? 'Chat', - }; -} - -export default async function ChatPage({ params }: ChatPageProps) { - const session = await auth(); - - if (!session?.user) { - redirect(`/sign-in?next=/chat/${params.id}`); - } - - const chat = await getChat(params.id, session.user.id); - - if (!chat) { - notFound(); - } - - if (chat?.userId !== session?.user?.id) { - notFound(); - } - - return ; -} diff --git a/app/(chat)/layout.tsx b/app/(chat)/layout.tsx index bbdb1865316007e2192e8ba37403e0fedce7b398..72e21949c8dcc6c0e1c3deb7b835d18ed1b5ef6a 100644 --- a/app/(chat)/layout.tsx +++ b/app/(chat)/layout.tsx @@ -1,16 +1,14 @@ -import { SidebarDesktop } from '@/components/sidebar-desktop' - interface ChatLayoutProps { - children: React.ReactNode + children: React.ReactNode; } export default async function ChatLayout({ children }: ChatLayoutProps) { - return ( -
- -
- {children} -
-
- ) + return ( +
+ {/* */} +
+ {children} +
+
+ ); } diff --git a/app/(chat)/page.tsx b/app/(chat)/page.tsx index dce63c2636c370e7f786d6019951a2221a9e7f7f..ea33ac85a37e1119edd693127bad5f9db9fab3f2 100644 --- a/app/(chat)/page.tsx +++ b/app/(chat)/page.tsx @@ -2,10 +2,10 @@ import { nanoid } from '@/lib/utils'; import { Chat } from '@/components/chat'; -import { ThemeToggle } from '../../components/theme-toggle'; +import { ThemeToggle } from '../../components/ThemeToggle'; import { useAtomValue } from 'jotai'; import { datasetAtom } from '../../state'; -import { EmptyScreen } from '../../components/empty-screen'; +import { EmptyScreen } from '../../components/chat/EmptyScreen'; export default function IndexPage() { const id = nanoid(); diff --git a/app/actions.ts b/app/actions.ts deleted file mode 100644 index a2633519ec8788fd4367dc5b67ad242b64c0b858..0000000000000000000000000000000000000000 --- a/app/actions.ts +++ /dev/null @@ -1,129 +0,0 @@ -'use server' - -import { revalidatePath } from 'next/cache' -import { redirect } from 'next/navigation' -import { kv } from '@vercel/kv' - -import { auth } from '@/auth' -import { type Chat } from '@/lib/types' - -export async function getChats(userId?: string | null) { - if (!userId) { - return [] - } - - try { - const pipeline = kv.pipeline() - const chats: string[] = await kv.zrange(`user:chat:${userId}`, 0, -1, { - rev: true, - }) - - for (const chat of chats) { - pipeline.hgetall(chat) - } - - const results = await pipeline.exec() - - return results as Chat[] - } catch (error) { - return [] - } -} - -export async function getChat(id: string, userId: string) { - const chat = await kv.hgetall(`chat:${id}`) - - if (!chat || (userId && chat.userId !== userId)) { - return null - } - - return chat -} - -export async function removeChat({ id, path }: { id: string; path: string }) { - const session = await auth() - - if (!session) { - return { - error: 'Unauthorized', - } - } - - //Convert uid to string for consistent comparison with session.user.id - const uid = String(await kv.hget(`chat:${id}`, 'userId')) - - if (uid !== session?.user?.id) { - return { - error: 'Unauthorized', - } - } - - await kv.del(`chat:${id}`) - await kv.zrem(`user:chat:${session.user.id}`, `chat:${id}`) - - revalidatePath('/') - return revalidatePath(path) -} - -export async function clearChats() { - const session = await auth() - - if (!session?.user?.id) { - return { - error: 'Unauthorized', - } - } - - const chats: string[] = await kv.zrange(`user:chat:${session.user.id}`, 0, -1) - if (!chats.length) { - return redirect('/') - } - const pipeline = kv.pipeline() - - for (const chat of chats) { - pipeline.del(chat) - pipeline.zrem(`user:chat:${session.user.id}`, chat) - } - - await pipeline.exec() - - revalidatePath('/') - return redirect('/') -} - -export async function getSharedChat(id: string) { - const chat = await kv.hgetall(`chat:${id}`) - - if (!chat || !chat.sharePath) { - return null - } - - return chat -} - -export async function shareChat(id: string) { - const session = await auth() - - if (!session?.user?.id) { - return { - error: 'Unauthorized', - } - } - - const chat = await kv.hgetall(`chat:${id}`) - - if (!chat || chat.userId !== session.user.id) { - return { - error: 'Something went wrong', - } - } - - const payload = { - ...chat, - sharePath: `/share/${chat.id}`, - } - - await kv.hmset(`chat:${chat.id}`, payload) - - return payload -} diff --git a/app/layout.tsx b/app/layout.tsx index bff5e6975a640332769e7f04d4d0564d7bde9973..a81645870947ec0eedc431b73e69d6bac6e0ae62 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -4,9 +4,9 @@ import { GeistMono } from 'geist/font/mono'; import '@/app/globals.css'; import { cn } from '@/lib/utils'; -import { TailwindIndicator } from '@/components/tailwind-indicator'; -import { Providers } from '@/components/providers'; -import { Header } from '@/components/header'; +import { TailwindIndicator } from '@/components/TailwindIndicator'; +import { Providers } from '@/components/Providers'; +import { Header } from '@/components/Header'; export const metadata = { metadataBase: new URL(`https://${process.env.VERCEL_URL}`), diff --git a/app/opengraph-image.png b/app/opengraph-image.png deleted file mode 100644 index 278b197ef70a1aaf344b9f86061ec0cefe80fff7..0000000000000000000000000000000000000000 Binary files a/app/opengraph-image.png and /dev/null differ diff --git a/app/sign-in/page.tsx b/app/sign-in/page.tsx index f3fab823a05d767d21aa5b336e20ceb3db2b6fd0..af4f23c8c7270ac4628d8c3082f1abd841445a70 100644 --- a/app/sign-in/page.tsx +++ b/app/sign-in/page.tsx @@ -1,7 +1,7 @@ import { auth } from '@/auth'; -import { LoginButton } from '@/components/login-button'; +import { LoginButton } from '@/components/LoginButton'; import { redirect } from 'next/navigation'; -import { ThemeToggle } from '../../components/theme-toggle'; +import { ThemeToggle } from '../../components/ThemeToggle'; export default async function SignInPage() { const session = await auth(); diff --git a/app/twitter-image.png b/app/twitter-image.png deleted file mode 100644 index 278b197ef70a1aaf344b9f86061ec0cefe80fff7..0000000000000000000000000000000000000000 Binary files a/app/twitter-image.png and /dev/null differ diff --git a/components/login-button.tsx b/components/LoginButton.tsx similarity index 92% rename from components/login-button.tsx rename to components/LoginButton.tsx index 5fb73c7b9d6a4eb9265c75ed64bfc43bca48efce..a05028ef64c6057d8f7402e75bbb272795fd5d3e 100644 --- a/components/login-button.tsx +++ b/components/LoginButton.tsx @@ -4,8 +4,8 @@ import * as React from 'react'; import { signIn } from 'next-auth/react'; import { cn } from '@/lib/utils'; -import { Button, type ButtonProps } from '@/components/ui/button'; -import { IconGitHub, IconSpinner, IconGoogle } from '@/components/ui/icons'; +import { Button, type ButtonProps } from '@/components/ui/Button'; +import { IconGitHub, IconSpinner, IconGoogle } from '@/components/ui/Icons'; interface LoginButtonProps extends ButtonProps { oauth: 'github' | 'google'; diff --git a/components/TailwindIndicator.tsx b/components/TailwindIndicator.tsx new file mode 100644 index 0000000000000000000000000000000000000000..248a94e4ac3f4affe2783cd60d579c4c7d2af385 --- /dev/null +++ b/components/TailwindIndicator.tsx @@ -0,0 +1,14 @@ +export function TailwindIndicator() { + if (process.env.NODE_ENV === 'production') return null; + + return ( +
+
xs
+
sm
+
md
+
lg
+
xl
+
2xl
+
+ ); +} diff --git a/components/theme-toggle.tsx b/components/ThemeToggle.tsx similarity index 86% rename from components/theme-toggle.tsx rename to components/ThemeToggle.tsx index 675efb9671460fd5618668b67a970588ee6d69a2..664794f53351cca5e1b20badacb0f5502f60e8e7 100644 --- a/components/theme-toggle.tsx +++ b/components/ThemeToggle.tsx @@ -3,8 +3,8 @@ import * as React from 'react'; import { useTheme } from 'next-themes'; -import { Button } from '@/components/ui/button'; -import { IconMoon, IconSun } from '@/components/ui/icons'; +import { Button } from '@/components/ui/Button'; +import { IconMoon, IconSun } from '@/components/ui/Icons'; export function ThemeToggle() { const { setTheme, theme } = useTheme(); diff --git a/components/user-menu.tsx b/components/UserMenu.tsx similarity index 92% rename from components/user-menu.tsx rename to components/UserMenu.tsx index 1ac8bc9462a68ffcfe174a04057f98ac61a71b48..a0ba98d6e3474e36572c2f391cb5b69248c17c51 100644 --- a/components/user-menu.tsx +++ b/components/UserMenu.tsx @@ -4,15 +4,15 @@ import Image from 'next/image'; import { type Session } from 'next-auth'; import { signOut } from 'next-auth/react'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/ui/Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { IconExternalLink } from '@/components/ui/icons'; +} from '@/components/ui/DropdownMenu'; +import { IconExternalLink } from '@/components/ui/Icons'; export interface UserMenuProps { user: Session['user']; diff --git a/components/button-scroll-to-bottom.tsx b/components/button-scroll-to-bottom.tsx deleted file mode 100644 index 436a6c0a7f5fe4c51efbdc867fa916a1977ec24f..0000000000000000000000000000000000000000 --- a/components/button-scroll-to-bottom.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' - -import * as React from 'react' - -import { cn } from '@/lib/utils' -import { useAtBottom } from '@/lib/hooks/use-at-bottom' -import { Button, type ButtonProps } from '@/components/ui/button' -import { IconArrowDown } from '@/components/ui/icons' - -export function ButtonScrollToBottom({ className, ...props }: ButtonProps) { - const isAtBottom = useAtBottom() - - return ( - - ) -} diff --git a/components/chat-history.tsx b/components/chat-history.tsx deleted file mode 100644 index 7450fe8cb7a7747b1cb86ef4b3d581ceed840c7c..0000000000000000000000000000000000000000 --- a/components/chat-history.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import * as React from 'react' - -import Link from 'next/link' - -import { cn } from '@/lib/utils' -import { SidebarList } from '@/components/sidebar-list' -import { buttonVariants } from '@/components/ui/button' -import { IconPlus } from '@/components/ui/icons' - -interface ChatHistoryProps { - userId?: string -} - -export async function ChatHistory({ userId }: ChatHistoryProps) { - return ( -
-
- - - New Chat - -
- - {Array.from({ length: 10 }).map((_, i) => ( -
- ))} -
- } - > - {/* @ts-ignore */} - -
-
- ) -} diff --git a/components/chat-scroll-anchor.tsx b/components/chat-scroll-anchor.tsx deleted file mode 100644 index ac809f4486a48e134cb69314c3d0dae5e68d614e..0000000000000000000000000000000000000000 --- a/components/chat-scroll-anchor.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client' - -import * as React from 'react' -import { useInView } from 'react-intersection-observer' - -import { useAtBottom } from '@/lib/hooks/use-at-bottom' - -interface ChatScrollAnchorProps { - trackVisibility?: boolean -} - -export function ChatScrollAnchor({ trackVisibility }: ChatScrollAnchorProps) { - const isAtBottom = useAtBottom() - const { ref, entry, inView } = useInView({ - trackVisibility, - delay: 100, - rootMargin: '0px 0px -150px 0px' - }) - - React.useEffect(() => { - if (isAtBottom && trackVisibility && !inView) { - entry?.target.scrollIntoView({ - block: 'start' - }) - } - }, [inView, entry, isAtBottom, trackVisibility]) - - return
-} diff --git a/components/chat-share-dialog.tsx b/components/chat-share-dialog.tsx deleted file mode 100644 index caee773c7f55be14984ff247a28ef71fea200ba1..0000000000000000000000000000000000000000 --- a/components/chat-share-dialog.tsx +++ /dev/null @@ -1,106 +0,0 @@ -'use client'; - -import * as React from 'react'; -import { type DialogProps } from '@radix-ui/react-dialog'; -import { toast } from 'react-hot-toast'; - -import { ServerActionResult, type Chat } from '@/lib/types'; -import { Button } from '@/components/ui/button'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; -import { IconSpinner } from '@/components/ui/icons'; -import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'; - -interface ChatShareDialogProps extends DialogProps { - chat: Pick; - shareChat: (id: string) => ServerActionResult; - onCopy: () => void; -} - -export function ChatShareDialog({ - chat, - shareChat, - onCopy, - ...props -}: ChatShareDialogProps) { - const { copyToClipboard } = useCopyToClipboard({ timeout: 1000 }); - const [isSharePending, startShareTransition] = React.useTransition(); - - const copyShareLink = React.useCallback( - async (chat: Chat) => { - if (!chat.sharePath) { - return toast.error('Could not copy share link to clipboard'); - } - - const url = new URL(window.location.href); - url.pathname = chat.sharePath; - copyToClipboard(url.toString()); - onCopy(); - toast.success('Share link copied to clipboard', { - style: { - borderRadius: '10px', - background: '#333', - color: '#fff', - fontSize: '14px', - }, - iconTheme: { - primary: 'white', - secondary: 'black', - }, - }); - }, - [copyToClipboard, onCopy], - ); - - return ( - - - - Share link to chat - - Anyone with the URL will be able to view the shared chat. - - -
-
{chat.title}
-
- {chat.messages.length} messages -
-
- - - -
-
- ); -} diff --git a/components/chat/ButtonScrollToBottom.tsx b/components/chat/ButtonScrollToBottom.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8e17567c4e3b15a8536b38b4a654aa8a7f6423a0 --- /dev/null +++ b/components/chat/ButtonScrollToBottom.tsx @@ -0,0 +1,34 @@ +'use client'; + +import * as React from 'react'; + +import { cn } from '@/lib/utils'; +import { useAtBottom } from '@/lib/hooks/useAtBottom'; +import { Button, type ButtonProps } from '@/components/ui/Button'; +import { IconArrowDown } from '@/components/ui/Icons'; + +export function ButtonScrollToBottom({ className, ...props }: ButtonProps) { + const isAtBottom = useAtBottom(); + + return ( + + ); +} diff --git a/components/chat/ChatList.tsx b/components/chat/ChatList.tsx index 97da976f102155ee16b8e8cc9516b3f9c5972ca3..bda027422c88760fb424749359f4c541cf78af4f 100644 --- a/components/chat/ChatList.tsx +++ b/components/chat/ChatList.tsx @@ -1,7 +1,7 @@ 'use client'; -import { Separator } from '@/components/ui/separator'; -import { ChatMessage } from '@/components/chat-message'; +import { Separator } from '@/components/ui/Separator'; +import { ChatMessage } from '@/components/chat/ChatMessage'; import { MessageWithSelectedDataset } from '../../lib/types'; export interface ChatList { diff --git a/components/chat-message.tsx b/components/chat/ChatMessage.tsx similarity index 85% rename from components/chat-message.tsx rename to components/chat/ChatMessage.tsx index b773aafb3bd3cd6fb8c1b091b8b112a8f9064463..f9ec21110890b7aed7efc577659b768f7cd89080 100644 --- a/components/chat-message.tsx +++ b/components/chat/ChatMessage.tsx @@ -5,11 +5,11 @@ import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import { cn } from '@/lib/utils'; -import { CodeBlock } from '@/components/ui/codeblock'; -import { MemoizedReactMarkdown } from '@/components/markdown'; -import { IconOpenAI, IconUser } from '@/components/ui/icons'; -import { ChatMessageActions } from '@/components/chat-message-actions'; -import { MessageWithSelectedDataset } from '../lib/types'; +import { CodeBlock } from '@/components/ui/CodeBlock'; +import { MemoizedReactMarkdown } from '@/components/chat/MemoizedReactMarkdown'; +import { IconOpenAI, IconUser } from '@/components/ui/Icons'; +import { ChatMessageActions } from '@/components/chat/ChatMessageActions'; +import { MessageWithSelectedDataset } from '../../lib/types'; export interface ChatMessageProps { message: MessageWithSelectedDataset; diff --git a/components/chat-message-actions.tsx b/components/chat/ChatMessageActions.tsx similarity index 77% rename from components/chat-message-actions.tsx rename to components/chat/ChatMessageActions.tsx index 5043eaeac9af956e1290779cf10bc0811a010956..8fbb94182485de7fcb1d3a20174726edbf0caa3c 100644 --- a/components/chat-message-actions.tsx +++ b/components/chat/ChatMessageActions.tsx @@ -2,11 +2,11 @@ import { type Message } from 'ai'; -import { Button } from '@/components/ui/button'; -import { IconCheck, IconCopy } from '@/components/ui/icons'; -import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'; +import { Button } from '@/components/ui/Button'; +import { IconCheck, IconCopy } from '@/components/ui/Icons'; +import { useCopyToClipboard } from '@/lib/hooks/useCopyToClipboard'; import { cn } from '@/lib/utils'; -import { MessageWithSelectedDataset } from '../lib/types'; +import { MessageWithSelectedDataset } from '../../lib/types'; interface ChatMessageActionsProps extends React.ComponentProps<'div'> { message: MessageWithSelectedDataset; diff --git a/components/chat-panel.tsx b/components/chat/ChatPanel.tsx similarity index 65% rename from components/chat-panel.tsx rename to components/chat/ChatPanel.tsx index d650507073824fea3e423e9283288a170d81a83a..f7582a215ead48e9affae30fe09c549599ea4e41 100644 --- a/components/chat-panel.tsx +++ b/components/chat/ChatPanel.tsx @@ -1,13 +1,11 @@ import * as React from 'react'; import { type UseChatHelpers } from 'ai/react'; -import { shareChat } from '@/app/actions'; -import { Button } from '@/components/ui/button'; -import { PromptForm } from '@/components/prompt-form'; -import { ButtonScrollToBottom } from '@/components/button-scroll-to-bottom'; -import { IconRefresh, IconShare, IconStop } from '@/components/ui/icons'; -import { ChatShareDialog } from '@/components/chat-share-dialog'; -import { MessageWithSelectedDataset } from '../lib/types'; +import { Button } from '@/components/ui/Button'; +import { PromptForm } from '@/components/chat/PromptForm'; +import { ButtonScrollToBottom } from '@/components/chat/ButtonScrollToBottom'; +import { IconRefresh, IconShare, IconStop } from '@/components/ui/Icons'; +import { MessageWithSelectedDataset } from '../../lib/types'; export interface ChatPanelProps extends Pick< @@ -53,28 +51,6 @@ export function ChatPanel({ Regenerate response - {/* {id && title ? ( - <> - - setShareDialogOpen(false)} - shareChat={shareChat} - chat={{ - id, - title, - messages, - }} - /> - - ) : null} */}
) )} diff --git a/components/chat/ChatScrollAnchor.tsx b/components/chat/ChatScrollAnchor.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6f29fdf03b479b310622dd8f1b149bf63d85c740 --- /dev/null +++ b/components/chat/ChatScrollAnchor.tsx @@ -0,0 +1,29 @@ +'use client'; + +import * as React from 'react'; +import { useInView } from 'react-intersection-observer'; + +import { useAtBottom } from '@/lib/hooks/useAtBottom'; + +interface ChatScrollAnchorProps { + trackVisibility?: boolean; +} + +export function ChatScrollAnchor({ trackVisibility }: ChatScrollAnchorProps) { + const isAtBottom = useAtBottom(); + const { ref, entry, inView } = useInView({ + trackVisibility, + delay: 100, + rootMargin: '0px 0px -150px 0px', + }); + + React.useEffect(() => { + if (isAtBottom && trackVisibility && !inView) { + entry?.target.scrollIntoView({ + block: 'start', + }); + } + }, [inView, entry, isAtBottom, trackVisibility]); + + return
; +} diff --git a/components/empty-screen.tsx b/components/chat/EmptyScreen.tsx similarity index 94% rename from components/empty-screen.tsx rename to components/chat/EmptyScreen.tsx index 7718cdc60ab7d38e0f9e727f8c80b2c17e0c092e..cf0ec99f367271c1129f569162278a5e2ecc0552 100644 --- a/components/empty-screen.tsx +++ b/components/chat/EmptyScreen.tsx @@ -1,8 +1,8 @@ import { useAtom } from 'jotai'; import { useDropzone } from 'react-dropzone'; -import { datasetAtom } from '../state'; +import { datasetAtom } from '../../state'; import Image from 'next/image'; -import useImageUpload from '../lib/hooks/useImageUpload'; +import useImageUpload from '../../lib/hooks/useImageUpload'; const examples = [ 'https://landing-lens-support.s3.us-east-2.amazonaws.com/vision-agent-examples/cereal-example.jpg', diff --git a/components/chat/MemoizedReactMarkdown.tsx b/components/chat/MemoizedReactMarkdown.tsx new file mode 100644 index 0000000000000000000000000000000000000000..db8075ed10890324d7cf6fdd36ede7951599bcfe --- /dev/null +++ b/components/chat/MemoizedReactMarkdown.tsx @@ -0,0 +1,9 @@ +import { FC, memo } from 'react'; +import ReactMarkdown, { Options } from 'react-markdown'; + +export const MemoizedReactMarkdown: FC = memo( + ReactMarkdown, + (prevProps, nextProps) => + prevProps.children === nextProps.children && + prevProps.className === nextProps.className, +); diff --git a/components/prompt-form.tsx b/components/chat/PromptForm.tsx similarity index 91% rename from components/prompt-form.tsx rename to components/chat/PromptForm.tsx index 4024ef5a49e615f630d11a627fbb8d84d18fbd5c..41b1257fac7f4d488fd9b16df460b837d70ba8d9 100644 --- a/components/prompt-form.tsx +++ b/components/chat/PromptForm.tsx @@ -1,15 +1,15 @@ import * as React from 'react'; import Textarea from 'react-textarea-autosize'; import { UseChatHelpers } from 'ai/react'; -import { useEnterSubmit } from '@/lib/hooks/use-enter-submit'; +import { useEnterSubmit } from '@/lib/hooks/useEnterSubmit'; import { cn } from '@/lib/utils'; -import { Button, buttonVariants } from '@/components/ui/button'; +import { Button, buttonVariants } from '@/components/ui/Button'; import { Tooltip, TooltipContent, TooltipTrigger, -} from '@/components/ui/tooltip'; -import { IconArrowElbow, IconPlus } from '@/components/ui/icons'; +} from '@/components/ui/Tooltip'; +import { IconArrowElbow, IconPlus } from '@/components/ui/Icons'; import { useRouter } from 'next/navigation'; export interface PromptProps diff --git a/components/chat/index.tsx b/components/chat/index.tsx index 5c3a9de8931f8f3f54718103a43c13729b769730..9bb3ca06267970587e200e5b8a8f4f1d7331c18a 100644 --- a/components/chat/index.tsx +++ b/components/chat/index.tsx @@ -1,8 +1,8 @@ 'use client'; import { cn } from '@/lib/utils'; import { ChatList } from '@/components/chat/ChatList'; -import { ChatPanel } from '@/components/chat-panel'; -import { ChatScrollAnchor } from '@/components/chat-scroll-anchor'; +import { ChatPanel } from '@/components/chat/ChatPanel'; +import { ChatScrollAnchor } from '@/components/chat/ChatScrollAnchor'; import ImageList from './ImageList'; import useChatWithDataset from '../../lib/hooks/useChatWithDataset'; diff --git a/components/clear-history.tsx b/components/clear-history.tsx deleted file mode 100644 index 553d2db3c9b35235147d3e4a8d991e82d5dac730..0000000000000000000000000000000000000000 --- a/components/clear-history.tsx +++ /dev/null @@ -1,77 +0,0 @@ -'use client' - -import * as React from 'react' -import { useRouter } from 'next/navigation' -import { toast } from 'react-hot-toast' - -import { ServerActionResult } from '@/lib/types' -import { Button } from '@/components/ui/button' -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger -} from '@/components/ui/alert-dialog' -import { IconSpinner } from '@/components/ui/icons' - -interface ClearHistoryProps { - isEnabled: boolean - clearChats: () => ServerActionResult -} - -export function ClearHistory({ - isEnabled = false, - clearChats -}: ClearHistoryProps) { - const [open, setOpen] = React.useState(false) - const [isPending, startTransition] = React.useTransition() - const router = useRouter() - - return ( - - - - - - - Are you absolutely sure? - - This will permanently delete your chat history and remove your data - from our servers. - - - - Cancel - { - event.preventDefault() - startTransition(() => { - clearChats().then(result => { - if (result && 'error' in result) { - toast.error(result.error) - return - } - - setOpen(false) - router.push('/') - }) - }) - }} - > - {isPending && } - Delete - - - - - ) -} diff --git a/components/external-link.tsx b/components/external-link.tsx deleted file mode 100644 index ba6cc0161457e56c609c1a64ab458d573039d27d..0000000000000000000000000000000000000000 --- a/components/external-link.tsx +++ /dev/null @@ -1,29 +0,0 @@ -export function ExternalLink({ - href, - children -}: { - href: string - children: React.ReactNode -}) { - return ( - - {children} - - - ) -} diff --git a/components/header.tsx b/components/header.tsx index 72ea5c43719eff41f9ac4b1ce1eea9efa08c1b2b..58bc51c0cb27ad0c4fc0f3f1f85a0439e31c4754 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -1,73 +1,34 @@ -import * as React from 'react' -import Link from 'next/link' +import * as React from 'react'; +import Link from 'next/link'; -import { cn } from '@/lib/utils' -import { auth } from '@/auth' -import { Button, buttonVariants } from '@/components/ui/button' -import { - IconGitHub, - IconNextChat, - IconSeparator, - IconVercel -} from '@/components/ui/icons' -import { UserMenu } from '@/components/user-menu' -import { SidebarMobile } from './sidebar-mobile' -import { SidebarToggle } from './sidebar-toggle' -// import { ChatHistory } from './chat-history' +import { auth } from '@/auth'; +import { Button } from '@/components/ui/Button'; +import { UserMenu } from '@/components/UserMenu'; async function UserOrLogin() { - const session = await auth() - return ( - <> - {/* {session?.user ? ( - <> - - - - - - ) : ( */} - {/* - - - */} - {/* )} */} -
- {/* */} - {session?.user ? ( - - ) : ( - - )} -
- - ) + const session = await auth(); + return ( + <> +
+ {/* */} + {session?.user ? ( + + ) : ( + + )} +
+ + ); } export function Header() { - return ( -
-
- {/* }> - - */} -
-
- }> - - - {/* - - GitHub - */} -
-
- ) + return ( +
+ }> + + +
+ ); } diff --git a/components/markdown.tsx b/components/markdown.tsx deleted file mode 100644 index d4491467a1f14d1d72e535caac9c40636054e5df..0000000000000000000000000000000000000000 --- a/components/markdown.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { FC, memo } from 'react' -import ReactMarkdown, { Options } from 'react-markdown' - -export const MemoizedReactMarkdown: FC = memo( - ReactMarkdown, - (prevProps, nextProps) => - prevProps.children === nextProps.children && - prevProps.className === nextProps.className -) diff --git a/components/providers.tsx b/components/providers.tsx index 0a8de4a155aafa388dd8e2ac12dd1a5af36ed9c8..622125bfb4386c5b35d69339444a2b686b028573 100644 --- a/components/providers.tsx +++ b/components/providers.tsx @@ -1,17 +1,14 @@ -'use client' +'use client'; -import * as React from 'react' -import { ThemeProvider as NextThemesProvider } from 'next-themes' -import { ThemeProviderProps } from 'next-themes/dist/types' -import { SidebarProvider } from '@/lib/hooks/use-sidebar' -import { TooltipProvider } from '@/components/ui/tooltip' +import * as React from 'react'; +import { ThemeProvider as NextThemesProvider } from 'next-themes'; +import { ThemeProviderProps } from 'next-themes/dist/types'; +import { TooltipProvider } from '@/components/ui/Tooltip'; export function Providers({ children, ...props }: ThemeProviderProps) { - return ( - - - {children} - - - ) + return ( + + {children} + + ); } diff --git a/components/sidebar-actions.tsx b/components/sidebar-actions.tsx deleted file mode 100644 index bfcde3a6462bd84707bd3e54185e6bf19b8bf04d..0000000000000000000000000000000000000000 --- a/components/sidebar-actions.tsx +++ /dev/null @@ -1,125 +0,0 @@ -'use client' - -import { useRouter } from 'next/navigation' -import * as React from 'react' -import { toast } from 'react-hot-toast' - -import { ServerActionResult, type Chat } from '@/lib/types' -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle -} from '@/components/ui/alert-dialog' -import { Button } from '@/components/ui/button' -import { IconShare, IconSpinner, IconTrash } from '@/components/ui/icons' -import { ChatShareDialog } from '@/components/chat-share-dialog' -import { - Tooltip, - TooltipContent, - TooltipTrigger -} from '@/components/ui/tooltip' - -interface SidebarActionsProps { - chat: Chat - removeChat: (args: { id: string; path: string }) => ServerActionResult - shareChat: (id: string) => ServerActionResult -} - -export function SidebarActions({ - chat, - removeChat, - shareChat -}: SidebarActionsProps) { - const router = useRouter() - const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false) - const [shareDialogOpen, setShareDialogOpen] = React.useState(false) - const [isRemovePending, startRemoveTransition] = React.useTransition() - - return ( - <> -
- - - - - Share chat - - - - - - Delete chat - -
- setShareDialogOpen(false)} - /> - - - - Are you absolutely sure? - - This will permanently delete your chat message and remove your - data from our servers. - - - - - Cancel - - { - event.preventDefault() - // @ts-ignore - startRemoveTransition(async () => { - const result = await removeChat({ - id: chat.id, - path: chat.path - }) - - if (result && 'error' in result) { - toast.error(result.error) - return - } - - setDeleteDialogOpen(false) - router.refresh() - router.push('/') - toast.success('Chat deleted') - }) - }} - > - {isRemovePending && } - Delete - - - - - - ) -} diff --git a/components/sidebar-desktop.tsx b/components/sidebar-desktop.tsx deleted file mode 100644 index 82079d34a48c30ee3fc0e1ad1c9e6f4d6bc7be5b..0000000000000000000000000000000000000000 --- a/components/sidebar-desktop.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Sidebar } from '@/components/sidebar' - -import { auth } from '@/auth' -import { ChatHistory } from '@/components/chat-history' - -export async function SidebarDesktop() { - const session = await auth() - - if (!session?.user?.id) { - return null - } - - return null - - // return ( - // - // {/* @ts-ignore */} - // - // - // ) -} diff --git a/components/sidebar-footer.tsx b/components/sidebar-footer.tsx deleted file mode 100644 index a2e18ea6649fa6a505b77cda0e53b6e6e240f0a2..0000000000000000000000000000000000000000 --- a/components/sidebar-footer.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { cn } from '@/lib/utils' - -export function SidebarFooter({ - children, - className, - ...props -}: React.ComponentProps<'div'>) { - return ( -
- {children} -
- ) -} diff --git a/components/sidebar-item.tsx b/components/sidebar-item.tsx deleted file mode 100644 index d5d27a08883cfd21a35ec4e411eadd8a85cd808a..0000000000000000000000000000000000000000 --- a/components/sidebar-item.tsx +++ /dev/null @@ -1,124 +0,0 @@ -'use client' - -import * as React from 'react' - -import Link from 'next/link' -import { usePathname } from 'next/navigation' - -import { motion } from 'framer-motion' - -import { buttonVariants } from '@/components/ui/button' -import { IconMessage, IconUsers } from '@/components/ui/icons' -import { - Tooltip, - TooltipContent, - TooltipTrigger -} from '@/components/ui/tooltip' -import { useLocalStorage } from '@/lib/hooks/use-local-storage' -import { type Chat } from '@/lib/types' -import { cn } from '@/lib/utils' - -interface SidebarItemProps { - index: number - chat: Chat - children: React.ReactNode -} - -export function SidebarItem({ index, chat, children }: SidebarItemProps) { - const pathname = usePathname() - - const isActive = pathname === chat.path - const [newChatId, setNewChatId] = useLocalStorage('newChatId', null) - const shouldAnimate = index === 0 && isActive && newChatId - - if (!chat?.id) return null - - return ( - -
- {chat.sharePath ? ( - - - - - This is a shared chat. - - ) : ( - - )} -
- -
- - {shouldAnimate ? ( - chat.title.split('').map((character, index) => ( - { - if (index === chat.title.length - 1) { - setNewChatId(null) - } - }} - > - {character} - - )) - ) : ( - {chat.title} - )} - -
- - {isActive &&
{children}
} -
- ) -} diff --git a/components/sidebar-items.tsx b/components/sidebar-items.tsx deleted file mode 100644 index 11cc7fc47c201fa66f84043010b010352f8470c3..0000000000000000000000000000000000000000 --- a/components/sidebar-items.tsx +++ /dev/null @@ -1,42 +0,0 @@ -'use client' - -import { Chat } from '@/lib/types' -import { AnimatePresence, motion } from 'framer-motion' - -import { removeChat, shareChat } from '@/app/actions' - -import { SidebarActions } from '@/components/sidebar-actions' -import { SidebarItem } from '@/components/sidebar-item' - -interface SidebarItemsProps { - chats?: Chat[] -} - -export function SidebarItems({ chats }: SidebarItemsProps) { - if (!chats?.length) return null - - return ( - - {chats.map( - (chat, index) => - chat && ( - - - - - - ) - )} - - ) -} diff --git a/components/sidebar-list.tsx b/components/sidebar-list.tsx deleted file mode 100644 index 0a7fb1ade3d8d51e2deaaf597123fe4dd3cd6346..0000000000000000000000000000000000000000 --- a/components/sidebar-list.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { clearChats, getChats } from '@/app/actions' -import { ClearHistory } from '@/components/clear-history' -import { SidebarItems } from '@/components/sidebar-items' -import { ThemeToggle } from '@/components/theme-toggle' -import { cache } from 'react' - -interface SidebarListProps { - userId?: string - children?: React.ReactNode -} - -const loadChats = cache(async (userId?: string) => { - return await getChats(userId) -}) - -export async function SidebarList({ userId }: SidebarListProps) { - const chats = await loadChats(userId) - - return ( -
-
- {chats?.length ? ( -
- -
- ) : ( -
-

No chat history

-
- )} -
-
- - 0} /> -
-
- ) -} diff --git a/components/sidebar-mobile.tsx b/components/sidebar-mobile.tsx deleted file mode 100644 index 507f83ea54c4a37cb7f169f8ad9ab45e2081e424..0000000000000000000000000000000000000000 --- a/components/sidebar-mobile.tsx +++ /dev/null @@ -1,28 +0,0 @@ -'use client' - -import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet' - -import { Sidebar } from '@/components/sidebar' -import { Button } from '@/components/ui/button' - -import { IconSidebar } from '@/components/ui/icons' - -interface SidebarMobileProps { - children: React.ReactNode -} - -export function SidebarMobile({ children }: SidebarMobileProps) { - return ( - - - - - - {children} - - - ) -} diff --git a/components/sidebar-toggle.tsx b/components/sidebar-toggle.tsx deleted file mode 100644 index 6c750097405ff94e482b24fa9d8203f37cad2670..0000000000000000000000000000000000000000 --- a/components/sidebar-toggle.tsx +++ /dev/null @@ -1,24 +0,0 @@ -'use client' - -import * as React from 'react' - -import { useSidebar } from '@/lib/hooks/use-sidebar' -import { Button } from '@/components/ui/button' -import { IconSidebar } from '@/components/ui/icons' - -export function SidebarToggle() { - const { toggleSidebar } = useSidebar() - - return ( - - ) -} diff --git a/components/sidebar.tsx b/components/sidebar.tsx deleted file mode 100644 index 52dc5bd76217e3db8a2aecb9e6dd87ff85a217bd..0000000000000000000000000000000000000000 --- a/components/sidebar.tsx +++ /dev/null @@ -1,21 +0,0 @@ -'use client' - -import * as React from 'react' - -import { useSidebar } from '@/lib/hooks/use-sidebar' -import { cn } from '@/lib/utils' - -export interface SidebarProps extends React.ComponentProps<'div'> {} - -export function Sidebar({ className, children }: SidebarProps) { - const { isSidebarOpen, isLoading } = useSidebar() - - return ( -
- {children} -
- ) -} diff --git a/components/tailwind-indicator.tsx b/components/tailwind-indicator.tsx deleted file mode 100644 index 846faa96a23bb8300ff80ad2d534e5d9d8484dc8..0000000000000000000000000000000000000000 --- a/components/tailwind-indicator.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export function TailwindIndicator() { - if (process.env.NODE_ENV === 'production') return null - - return ( -
-
xs
-
sm
-
md
-
lg
-
xl
-
2xl
-
- ) -} diff --git a/components/ui/DropdownMenu.tsx b/components/ui/DropdownMenu.tsx new file mode 100644 index 0000000000000000000000000000000000000000..82e018e6950aa3085f42111114abf54fb563d2fb --- /dev/null +++ b/components/ui/DropdownMenu.tsx @@ -0,0 +1,128 @@ +'use client'; + +import * as React from 'react'; +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; + +import { cn } from '@/lib/utils'; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'; + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuRadioGroup, +}; diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx deleted file mode 100644 index 2302ff2d3ddc82e68e9a0eafc4ce3e17a11a6039..0000000000000000000000000000000000000000 --- a/components/ui/alert-dialog.tsx +++ /dev/null @@ -1,141 +0,0 @@ -'use client' - -import * as React from 'react' -import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog' - -import { cn } from '@/lib/utils' -import { buttonVariants } from '@/components/ui/button' - -const AlertDialog = AlertDialogPrimitive.Root - -const AlertDialogTrigger = AlertDialogPrimitive.Trigger - -const AlertDialogPortal = AlertDialogPrimitive.Portal - -const AlertDialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName - -const AlertDialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - -)) -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName - -const AlertDialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -AlertDialogHeader.displayName = 'AlertDialogHeader' - -const AlertDialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -AlertDialogFooter.displayName = 'AlertDialogFooter' - -const AlertDialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName - -const AlertDialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogDescription.displayName = - AlertDialogPrimitive.Description.displayName - -const AlertDialogAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName - -const AlertDialogCancel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName - -export { - AlertDialog, - AlertDialogPortal, - AlertDialogOverlay, - AlertDialogTrigger, - AlertDialogContent, - AlertDialogHeader, - AlertDialogFooter, - AlertDialogTitle, - AlertDialogDescription, - AlertDialogAction, - AlertDialogCancel -} diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx deleted file mode 100644 index d9a84b394090e5b4b3bd34f6135b9a2f2ead0aa2..0000000000000000000000000000000000000000 --- a/components/ui/badge.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import * as React from 'react' -import { cva, type VariantProps } from 'class-variance-authority' - -import { cn } from '@/lib/utils' - -const badgeVariants = cva( - 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', - { - variants: { - variant: { - default: - 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', - secondary: - 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', - destructive: - 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', - outline: 'text-foreground' - } - }, - defaultVariants: { - variant: 'default' - } - } -) - -export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} - -function Badge({ className, variant, ...props }: BadgeProps) { - return ( -
- ) -} - -export { Badge, badgeVariants } diff --git a/components/ui/button.tsx b/components/ui/button.tsx index 8d483e0c510988f53ea2e9c77374edb96a2b97a8..9a59b03c6dc9ce2390e617218c16cac5f1ada03d 100644 --- a/components/ui/button.tsx +++ b/components/ui/button.tsx @@ -1,57 +1,57 @@ -import * as React from 'react' -import { Slot } from '@radix-ui/react-slot' -import { cva, type VariantProps } from 'class-variance-authority' +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; -import { cn } from '@/lib/utils' +import { cn } from '@/lib/utils'; const buttonVariants = cva( - 'inline-flex items-center justify-center rounded-md text-sm font-medium shadow ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', - { - variants: { - variant: { - default: - 'bg-primary text-primary-foreground shadow-md hover:bg-primary/90', - destructive: - 'bg-destructive text-destructive-foreground hover:bg-destructive/90', - outline: - 'border border-input hover:bg-accent hover:text-accent-foreground', - secondary: - 'bg-secondary text-secondary-foreground hover:bg-secondary/80', - ghost: 'shadow-none hover:bg-accent hover:text-accent-foreground', - link: 'text-primary underline-offset-4 shadow-none hover:underline' - }, - size: { - default: 'h-8 px-4 py-2', - sm: 'h-8 rounded-md px-3', - lg: 'h-11 rounded-md px-8', - icon: 'size-8 p-0' - } - }, - defaultVariants: { - variant: 'default', - size: 'default' - } - } -) + 'inline-flex items-center justify-center rounded-md text-sm font-medium shadow ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: + 'bg-primary text-primary-foreground shadow-md hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: + 'border border-input hover:bg-accent hover:text-accent-foreground', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'shadow-none hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 shadow-none hover:underline', + }, + size: { + default: 'h-8 px-4 py-2', + sm: 'h-8 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'size-8 p-0', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +); export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; } const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : 'button' - return ( - - ) - } -) -Button.displayName = 'Button' + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + ); + }, +); +Button.displayName = 'Button'; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/components/ui/codeblock.tsx b/components/ui/codeblock.tsx index 3a61fd464bf930b9e78e02936515e9bb6d08c357..adb303554c75bf8f98ae27219a6ff9979f46f989 100644 --- a/components/ui/codeblock.tsx +++ b/components/ui/codeblock.tsx @@ -1,148 +1,148 @@ // Inspired by Chatbot-UI and modified to fit the needs of this project // @see https://github.com/mckaywrigley/chatbot-ui/blob/main/components/Markdown/CodeBlock.tsx -'use client' +'use client'; -import { FC, memo } from 'react' -import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' -import { coldarkDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' +import { FC, memo } from 'react'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { coldarkDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'; -import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard' -import { IconCheck, IconCopy, IconDownload } from '@/components/ui/icons' -import { Button } from '@/components/ui/button' +import { useCopyToClipboard } from '@/lib/hooks/useCopyToClipboard'; +import { IconCheck, IconCopy, IconDownload } from '@/components/ui/Icons'; +import { Button } from '@/components/ui/Button'; interface Props { - language: string - value: string + language: string; + value: string; } interface languageMap { - [key: string]: string | undefined + [key: string]: string | undefined; } export const programmingLanguages: languageMap = { - javascript: '.js', - python: '.py', - java: '.java', - c: '.c', - cpp: '.cpp', - 'c++': '.cpp', - 'c#': '.cs', - ruby: '.rb', - php: '.php', - swift: '.swift', - 'objective-c': '.m', - kotlin: '.kt', - typescript: '.ts', - go: '.go', - perl: '.pl', - rust: '.rs', - scala: '.scala', - haskell: '.hs', - lua: '.lua', - shell: '.sh', - sql: '.sql', - html: '.html', - css: '.css' - // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component -} + javascript: '.js', + python: '.py', + java: '.java', + c: '.c', + cpp: '.cpp', + 'c++': '.cpp', + 'c#': '.cs', + ruby: '.rb', + php: '.php', + swift: '.swift', + 'objective-c': '.m', + kotlin: '.kt', + typescript: '.ts', + go: '.go', + perl: '.pl', + rust: '.rs', + scala: '.scala', + haskell: '.hs', + lua: '.lua', + shell: '.sh', + sql: '.sql', + html: '.html', + css: '.css', + // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component +}; export const generateRandomString = (length: number, lowercase = false) => { - const chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789' // excluding similar looking characters like Z, 2, I, 1, O, 0 - let result = '' - for (let i = 0; i < length; i++) { - result += chars.charAt(Math.floor(Math.random() * chars.length)) - } - return lowercase ? result.toLowerCase() : result -} + const chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789'; // excluding similar looking characters like Z, 2, I, 1, O, 0 + let result = ''; + for (let i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return lowercase ? result.toLowerCase() : result; +}; const CodeBlock: FC = memo(({ language, value }) => { - const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 }) + const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 }); - const downloadAsFile = () => { - if (typeof window === 'undefined') { - return - } - const fileExtension = programmingLanguages[language] || '.file' - const suggestedFileName = `file-${generateRandomString( - 3, - true - )}${fileExtension}` - const fileName = window.prompt('Enter file name' || '', suggestedFileName) + const downloadAsFile = () => { + if (typeof window === 'undefined') { + return; + } + const fileExtension = programmingLanguages[language] || '.file'; + const suggestedFileName = `file-${generateRandomString( + 3, + true, + )}${fileExtension}`; + const fileName = window.prompt('Enter file name' || '', suggestedFileName); - if (!fileName) { - // User pressed cancel on prompt. - return - } + if (!fileName) { + // User pressed cancel on prompt. + return; + } - const blob = new Blob([value], { type: 'text/plain' }) - const url = URL.createObjectURL(blob) - const link = document.createElement('a') - link.download = fileName - link.href = url - link.style.display = 'none' - document.body.appendChild(link) - link.click() - document.body.removeChild(link) - URL.revokeObjectURL(url) - } + const blob = new Blob([value], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.download = fileName; + link.href = url; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + }; - const onCopy = () => { - if (isCopied) return - copyToClipboard(value) - } + const onCopy = () => { + if (isCopied) return; + copyToClipboard(value); + }; - return ( -
-
- {language} -
- - -
-
- - {value} - -
- ) -}) -CodeBlock.displayName = 'CodeBlock' + return ( +
+
+ {language} +
+ + +
+
+ + {value} + +
+ ); +}); +CodeBlock.displayName = 'CodeBlock'; -export { CodeBlock } +export { CodeBlock }; diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx deleted file mode 100644 index 7649a101a38bf0596756e94bcd9a50e75b39b6b0..0000000000000000000000000000000000000000 --- a/components/ui/dialog.tsx +++ /dev/null @@ -1,122 +0,0 @@ -'use client' - -import * as React from 'react' -import * as DialogPrimitive from '@radix-ui/react-dialog' - -import { cn } from '@/lib/utils' -import { IconClose } from '@/components/ui/icons' - -const Dialog = DialogPrimitive.Root - -const DialogTrigger = DialogPrimitive.Trigger - -const DialogPortal = DialogPrimitive.Portal - -const DialogClose = DialogPrimitive.Close - -const DialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName - -const DialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)) -DialogContent.displayName = DialogPrimitive.Content.displayName - -const DialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogHeader.displayName = 'DialogHeader' - -const DialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogFooter.displayName = 'DialogFooter' - -const DialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogTitle.displayName = DialogPrimitive.Title.displayName - -const DialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogDescription.displayName = DialogPrimitive.Description.displayName - -export { - Dialog, - DialogPortal, - DialogOverlay, - DialogClose, - DialogTrigger, - DialogContent, - DialogHeader, - DialogFooter, - DialogTitle, - DialogDescription -} diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx deleted file mode 100644 index 184d4e6007ef85187446362f69532ab077897fea..0000000000000000000000000000000000000000 --- a/components/ui/dropdown-menu.tsx +++ /dev/null @@ -1,128 +0,0 @@ -'use client' - -import * as React from 'react' -import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu' - -import { cn } from '@/lib/utils' - -const DropdownMenu = DropdownMenuPrimitive.Root - -const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger - -const DropdownMenuGroup = DropdownMenuPrimitive.Group - -const DropdownMenuPortal = DropdownMenuPrimitive.Portal - -const DropdownMenuSub = DropdownMenuPrimitive.Sub - -const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup - -const DropdownMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DropdownMenuSubContent.displayName = - DropdownMenuPrimitive.SubContent.displayName - -const DropdownMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - - - -)) -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName - -const DropdownMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } ->(({ className, inset, ...props }, ref) => ( - -)) -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName - -const DropdownMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } ->(({ className, inset, ...props }, ref) => ( - -)) -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName - -const DropdownMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName - -const DropdownMenuShortcut = ({ - className, - ...props -}: React.HTMLAttributes) => { - return ( - - ) -} -DropdownMenuShortcut.displayName = 'DropdownMenuShortcut' - -export { - DropdownMenu, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuGroup, - DropdownMenuPortal, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuRadioGroup -} diff --git a/components/ui/input.tsx b/components/ui/input.tsx index 684a857f3d769b78818fb13de1abaebfb09ca79c..5c93708bd106c9ea47792477e7bd3f1a658dd242 100644 --- a/components/ui/input.tsx +++ b/components/ui/input.tsx @@ -1,25 +1,25 @@ -import * as React from 'react' +import * as React from 'react'; -import { cn } from '@/lib/utils' +import { cn } from '@/lib/utils'; export interface InputProps - extends React.InputHTMLAttributes {} + extends React.InputHTMLAttributes {} const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { - return ( - - ) - } -) -Input.displayName = 'Input' + ({ className, type, ...props }, ref) => { + return ( + + ); + }, +); +Input.displayName = 'Input'; -export { Input } +export { Input }; diff --git a/components/ui/label.tsx b/components/ui/label.tsx deleted file mode 100644 index 534182176bf87f9308355514adc884d2b69750a5..0000000000000000000000000000000000000000 --- a/components/ui/label.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client" - -import * as React from "react" -import * as LabelPrimitive from "@radix-ui/react-label" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const labelVariants = cva( - "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" -) - -const Label = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps ->(({ className, ...props }, ref) => ( - -)) -Label.displayName = LabelPrimitive.Root.displayName - -export { Label } diff --git a/components/ui/select.tsx b/components/ui/select.tsx deleted file mode 100644 index c9986a66d3f225ef583c1c753bd57d317813eded..0000000000000000000000000000000000000000 --- a/components/ui/select.tsx +++ /dev/null @@ -1,123 +0,0 @@ -'use client' - -import * as React from 'react' -import * as SelectPrimitive from '@radix-ui/react-select' - -import { cn } from '@/lib/utils' -import { - IconArrowDown, - IconCheck, - IconChevronUpDown -} from '@/components/ui/icons' - -const Select = SelectPrimitive.Root - -const SelectGroup = SelectPrimitive.Group - -const SelectValue = SelectPrimitive.Value - -const SelectTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - {children} - - - - -)) -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName - -const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, position = 'popper', ...props }, ref) => ( - - - - {children} - - - -)) -SelectContent.displayName = SelectPrimitive.Content.displayName - -const SelectLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SelectLabel.displayName = SelectPrimitive.Label.displayName - -const SelectItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)) -SelectItem.displayName = SelectPrimitive.Item.displayName - -const SelectSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SelectSeparator.displayName = SelectPrimitive.Separator.displayName - -export { - Select, - SelectGroup, - SelectValue, - SelectTrigger, - SelectContent, - SelectLabel, - SelectItem, - SelectSeparator -} diff --git a/components/ui/separator.tsx b/components/ui/separator.tsx index 6c55e0b2ca8e2436658a06748aadbff7cd700db0..b985701b92e92353c252616568f37fd8ca2acadb 100644 --- a/components/ui/separator.tsx +++ b/components/ui/separator.tsx @@ -1,31 +1,31 @@ -'use client' +'use client'; -import * as React from 'react' -import * as SeparatorPrimitive from '@radix-ui/react-separator' +import * as React from 'react'; +import * as SeparatorPrimitive from '@radix-ui/react-separator'; -import { cn } from '@/lib/utils' +import { cn } from '@/lib/utils'; const Separator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >( - ( - { className, orientation = 'horizontal', decorative = true, ...props }, - ref - ) => ( - - ) -) -Separator.displayName = SeparatorPrimitive.Root.displayName + ( + { className, orientation = 'horizontal', decorative = true, ...props }, + ref, + ) => ( + + ), +); +Separator.displayName = SeparatorPrimitive.Root.displayName; -export { Separator } +export { Separator }; diff --git a/components/ui/sheet.tsx b/components/ui/sheet.tsx deleted file mode 100644 index 6dac033993643df35510fc45076a2a239c6a687d..0000000000000000000000000000000000000000 --- a/components/ui/sheet.tsx +++ /dev/null @@ -1,140 +0,0 @@ -'use client' - -import * as React from 'react' -import * as SheetPrimitive from '@radix-ui/react-dialog' -import { cva, type VariantProps } from 'class-variance-authority' -import { IconClose } from '@/components/ui/icons' - -import { cn } from '@/lib/utils' - -const Sheet = SheetPrimitive.Root - -const SheetTrigger = SheetPrimitive.Trigger - -const SheetClose = SheetPrimitive.Close - -const SheetPortal = SheetPrimitive.Portal - -const SheetOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SheetOverlay.displayName = SheetPrimitive.Overlay.displayName - -const sheetVariants = cva( - 'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500', - { - variants: { - side: { - top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top', - bottom: - 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom', - left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm', - right: - 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm' - } - }, - defaultVariants: { - side: 'right' - } - } -) - -interface SheetContentProps - extends React.ComponentPropsWithoutRef, - VariantProps {} - -const SheetContent = React.forwardRef< - React.ElementRef, - SheetContentProps ->(({ side = 'left', className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)) -SheetContent.displayName = SheetPrimitive.Content.displayName - -const SheetHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -SheetHeader.displayName = 'SheetHeader' - -const SheetFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -SheetFooter.displayName = 'SheetFooter' - -const SheetTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SheetTitle.displayName = SheetPrimitive.Title.displayName - -const SheetDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -SheetDescription.displayName = SheetPrimitive.Description.displayName - -export { - Sheet, - SheetPortal, - SheetOverlay, - SheetTrigger, - SheetClose, - SheetContent, - SheetHeader, - SheetFooter, - SheetTitle, - SheetDescription -} diff --git a/components/ui/switch.tsx b/components/ui/switch.tsx deleted file mode 100644 index 29b8c29d10215b786b19a613f3d022e76d77c742..0000000000000000000000000000000000000000 --- a/components/ui/switch.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client' - -import * as React from 'react' -import * as SwitchPrimitives from '@radix-ui/react-switch' - -import { cn } from '@/lib/utils' - -const Switch = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)) -Switch.displayName = SwitchPrimitives.Root.displayName - -export { Switch } diff --git a/components/ui/tooltip.tsx b/components/ui/tooltip.tsx index af1d48beb90dd5ae311796539843700871052cae..ca6f1bf712fb8c9ba47721d6acd20546850d9eac 100644 --- a/components/ui/tooltip.tsx +++ b/components/ui/tooltip.tsx @@ -1,30 +1,30 @@ -'use client' +'use client'; -import * as React from 'react' -import * as TooltipPrimitive from '@radix-ui/react-tooltip' +import * as React from 'react'; +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; -import { cn } from '@/lib/utils' +import { cn } from '@/lib/utils'; -const TooltipProvider = TooltipPrimitive.Provider +const TooltipProvider = TooltipPrimitive.Provider; -const Tooltip = TooltipPrimitive.Root +const Tooltip = TooltipPrimitive.Root; -const TooltipTrigger = TooltipPrimitive.Trigger +const TooltipTrigger = TooltipPrimitive.Trigger; const TooltipContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( - -)) -TooltipContent.displayName = TooltipPrimitive.Content.displayName + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/lib/hooks/use-at-bottom.tsx b/lib/hooks/use-at-bottom.tsx deleted file mode 100644 index d37c8cf4162adcb0064e08ecec24eb731416b045..0000000000000000000000000000000000000000 --- a/lib/hooks/use-at-bottom.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react' - -export function useAtBottom(offset = 0) { - const [isAtBottom, setIsAtBottom] = React.useState(false) - - React.useEffect(() => { - const handleScroll = () => { - setIsAtBottom( - window.innerHeight + window.scrollY >= - document.body.offsetHeight - offset - ) - } - - window.addEventListener('scroll', handleScroll, { passive: true }) - handleScroll() - - return () => { - window.removeEventListener('scroll', handleScroll) - } - }, [offset]) - - return isAtBottom -} diff --git a/lib/hooks/use-sidebar.tsx b/lib/hooks/use-sidebar.tsx deleted file mode 100644 index 4a52baf194d04dd2016ad8738c27d7c0b6774087..0000000000000000000000000000000000000000 --- a/lib/hooks/use-sidebar.tsx +++ /dev/null @@ -1,60 +0,0 @@ -'use client' - -import * as React from 'react' - -const LOCAL_STORAGE_KEY = 'sidebar' - -interface SidebarContext { - isSidebarOpen: boolean - toggleSidebar: () => void - isLoading: boolean -} - -const SidebarContext = React.createContext( - undefined -) - -export function useSidebar() { - const context = React.useContext(SidebarContext) - if (!context) { - throw new Error('useSidebarContext must be used within a SidebarProvider') - } - return context -} - -interface SidebarProviderProps { - children: React.ReactNode -} - -export function SidebarProvider({ children }: SidebarProviderProps) { - const [isSidebarOpen, setSidebarOpen] = React.useState(true) - const [isLoading, setLoading] = React.useState(true) - - React.useEffect(() => { - const value = localStorage.getItem(LOCAL_STORAGE_KEY) - if (value) { - setSidebarOpen(JSON.parse(value)) - } - setLoading(false) - }, []) - - const toggleSidebar = () => { - setSidebarOpen(value => { - const newState = !value - localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(newState)) - return newState - }) - } - - if (isLoading) { - return null - } - - return ( - - {children} - - ) -} diff --git a/lib/hooks/useAtBottom.tsx b/lib/hooks/useAtBottom.tsx new file mode 100644 index 0000000000000000000000000000000000000000..887d2d0e66db7b1654feb965b69cf777808b4dbd --- /dev/null +++ b/lib/hooks/useAtBottom.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; + +export function useAtBottom(offset = 0) { + const [isAtBottom, setIsAtBottom] = React.useState(false); + + React.useEffect(() => { + const handleScroll = () => { + setIsAtBottom( + window.innerHeight + window.scrollY >= + document.body.offsetHeight - offset, + ); + }; + + window.addEventListener('scroll', handleScroll, { passive: true }); + handleScroll(); + + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, [offset]); + + return isAtBottom; +} diff --git a/lib/hooks/use-copy-to-clipboard.tsx b/lib/hooks/useCopyToClipboard.tsx similarity index 100% rename from lib/hooks/use-copy-to-clipboard.tsx rename to lib/hooks/useCopyToClipboard.tsx diff --git a/lib/hooks/use-enter-submit.tsx b/lib/hooks/useEnterSubmit.tsx similarity index 100% rename from lib/hooks/use-enter-submit.tsx rename to lib/hooks/useEnterSubmit.tsx diff --git a/lib/hooks/use-local-storage.ts b/lib/hooks/useLocalStorage.ts similarity index 100% rename from lib/hooks/use-local-storage.ts rename to lib/hooks/useLocalStorage.ts diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index f70fd82a81529c08499ebd432b9052d9de3761ae..0000000000000000000000000000000000000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,5 +0,0 @@ -packages: - # include packages in subfolders (e.g. apps/ and packages/) - - 'app/**' - # if required, exclude some directories - - '!**/test/**'