feat: reorganize files and implement ui and sidebar
This commit is contained in:
parent
2e80864b84
commit
01dc4520d6
36 changed files with 1347 additions and 462 deletions
|
|
@ -1,7 +1,40 @@
|
||||||
'use server'
|
'use server'
|
||||||
|
|
||||||
import { kv } from '@vercel/kv'
|
|
||||||
import { revalidatePath } from 'next/cache'
|
import { revalidatePath } from 'next/cache'
|
||||||
|
import { kv } from '@vercel/kv'
|
||||||
|
|
||||||
|
import { type Chat } from '@/lib/types'
|
||||||
|
|
||||||
|
export async function getChats(userId: string) {
|
||||||
|
try {
|
||||||
|
const pipeline = kv.pipeline()
|
||||||
|
const chats: string[] = await kv.zrange(`user:chat:${userId}`, 0, -1)
|
||||||
|
|
||||||
|
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>(`chat:${id}`)
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
throw new Error('Not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userId && chat.userId !== userId) {
|
||||||
|
throw new Error('Unauthorized')
|
||||||
|
}
|
||||||
|
|
||||||
|
return chat
|
||||||
|
}
|
||||||
|
|
||||||
export async function removeChat({
|
export async function removeChat({
|
||||||
id,
|
id,
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
export { GET, POST } from '@/auth'
|
export { GET, POST } from '@/auth'
|
||||||
export const runtime = 'edge'
|
// export const runtime = 'edge'
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { nanoid } from '@/lib/utils'
|
||||||
import { OpenAIStream, StreamingTextResponse } from 'ai-connector'
|
import { OpenAIStream, StreamingTextResponse } from 'ai-connector'
|
||||||
import { Configuration, OpenAIApi } from 'openai-edge'
|
import { Configuration, OpenAIApi } from 'openai-edge'
|
||||||
|
|
||||||
export const runtime = 'edge'
|
// export const runtime = 'edge'
|
||||||
|
|
||||||
const configuration = new Configuration({
|
const configuration = new Configuration({
|
||||||
apiKey: process.env.OPENAI_API_KEY
|
apiKey: process.env.OPENAI_API_KEY
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
'use client'
|
|
||||||
|
|
||||||
import { type Message } from 'ai-connector'
|
|
||||||
|
|
||||||
import { ChatMessage } from './chat-message'
|
|
||||||
import { EmptyScreen } from './empty-screen'
|
|
||||||
|
|
||||||
export interface ChatList {
|
|
||||||
messages: Message[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ChatList({ messages }: ChatList) {
|
|
||||||
return (
|
|
||||||
<div className="relative max-w-2xl mx-auto">
|
|
||||||
{/* <div className="sticky top-0 border-b w-full bg-black md:hidden text-white font-semibold">
|
|
||||||
<div className="px-4 py-2 flex items-center justify-between">
|
|
||||||
<div className="flex flex-row gap-2 whitespace-nowrap items-center">
|
|
||||||
<NextChatLogo className="h-6 w-6" />
|
|
||||||
<span className="select-none">Next.js Chatbot</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button className="text-white p-2 rounded hover:bg-zinc-800 transition duration-100">
|
|
||||||
<Plus className="h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
{messages.length > 0 ? (
|
|
||||||
<div className="group">
|
|
||||||
{messages.map(message => (
|
|
||||||
<ChatMessage
|
|
||||||
key={message.id || message.content}
|
|
||||||
message={message}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="pt-10">
|
|
||||||
<EmptyScreen />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
57
app/chat.tsx
57
app/chat.tsx
|
|
@ -1,57 +0,0 @@
|
||||||
'use client'
|
|
||||||
|
|
||||||
import { useRouter } from 'next/navigation'
|
|
||||||
import { Prompt } from './prompt'
|
|
||||||
import { useChat, type Message } from 'ai-connector'
|
|
||||||
import { ChatList } from './chat-list'
|
|
||||||
import { ExternalLink } from '@/app/external-link'
|
|
||||||
|
|
||||||
export interface ChatProps {
|
|
||||||
// create?: (input: string) => Chat | undefined;
|
|
||||||
initialMessages?: Message[]
|
|
||||||
id?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Chat({
|
|
||||||
id,
|
|
||||||
// create,
|
|
||||||
initialMessages
|
|
||||||
}: ChatProps) {
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const { isLoading, messages, reload, append } = useChat({
|
|
||||||
initialMessages: initialMessages as any[],
|
|
||||||
id
|
|
||||||
// onCreate: (id: string) => {
|
|
||||||
// router.push(`/chat/${id}`);
|
|
||||||
// },
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="h-full w-full overflow-auto pb-[200px]">
|
|
||||||
<ChatList messages={messages} />
|
|
||||||
<div className="fixed bottom-0 left-1 right-3 p-6 bg-gradient-to-b from-background/10 via-background/50 to-background/80 backdrop-blur-lg">
|
|
||||||
<div className="max-w-2xl mx-auto pl-10">
|
|
||||||
<Prompt
|
|
||||||
onSubmit={value => {
|
|
||||||
append({
|
|
||||||
content: value,
|
|
||||||
role: 'user'
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
onRefresh={messages.length ? reload : undefined}
|
|
||||||
isLoading={isLoading}
|
|
||||||
/>
|
|
||||||
<p className="text-muted-foreground text-xs leading-normal text-center pt-2">
|
|
||||||
This is an open source AI chatbot app built with{' '}
|
|
||||||
<ExternalLink href="https://nextjs.org">Next.js</ExternalLink> and{' '}
|
|
||||||
<ExternalLink href="https://vercel.com/storage/kv">
|
|
||||||
Vercel KV
|
|
||||||
</ExternalLink>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
import { Sidebar } from '@/app/sidebar'
|
|
||||||
|
|
||||||
import { auth } from '@/auth'
|
|
||||||
import { type Metadata } from 'next'
|
import { type Metadata } from 'next'
|
||||||
|
|
||||||
import { Chat } from '@/app/chat'
|
import { auth } from '@/auth'
|
||||||
import { type Chat as ChatType } from '@/lib/types'
|
import { getChat } from '@/app/actions'
|
||||||
import { kv } from '@vercel/kv'
|
import { Chat } from '@/components/chat'
|
||||||
import { Message } from 'ai-connector'
|
|
||||||
|
|
||||||
export const runtime = 'edge'
|
// export const runtime = 'edge'
|
||||||
export const preferredRegion = 'home'
|
export const preferredRegion = 'home'
|
||||||
|
|
||||||
export interface ChatPageProps {
|
export interface ChatPageProps {
|
||||||
params: {
|
params: {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -30,28 +27,5 @@ export default async function ChatPage({ params }: ChatPageProps) {
|
||||||
const session = await auth()
|
const session = await auth()
|
||||||
const chat = await getChat(params.id, session?.user?.email ?? '')
|
const chat = await getChat(params.id, session?.user?.email ?? '')
|
||||||
|
|
||||||
return (
|
return <Chat id={chat.id} initialMessages={chat.messages} />
|
||||||
<div className="relative flex h-full w-full overflow-hidden">
|
|
||||||
{/* @ts-ignore */}
|
|
||||||
<Sidebar session={session} />
|
|
||||||
<div className="flex h-full min-w-0 flex-1 flex-col">
|
|
||||||
<Chat id={chat.id} initialMessages={chat.messages as Message[]} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatPage.displayName = 'ChatPage'
|
|
||||||
|
|
||||||
async function getChat(id: string, userId: string) {
|
|
||||||
const chat = await kv.hgetall<ChatType>(`chat:${id}`)
|
|
||||||
if (!chat) {
|
|
||||||
throw new Error('Not found')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userId && chat.userId !== userId) {
|
|
||||||
throw new Error('Unauthorized')
|
|
||||||
}
|
|
||||||
|
|
||||||
return chat
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
import { GitHub, Vercel } from '@/components/icons'
|
|
||||||
import './globals.css'
|
|
||||||
|
|
||||||
import { Sidebar } from '@/app/sidebar'
|
|
||||||
import { buttonVariants } from '@/components/ui/button'
|
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { Plus } from 'lucide-react'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { UserMenu } from '@/components/user-menu'
|
|
||||||
import { auth } from '@/auth'
|
|
||||||
|
|
||||||
export async function Header() {
|
|
||||||
const session = await auth()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<header className="h-16 shrink-0 z-50 bg-gradient-to-b from-background/30 to-background/50 backdrop-blur-lg px-4 flex sticky top-0 w-full items-center justify-between">
|
|
||||||
<div className="flex items-center">
|
|
||||||
{/* @ts-ignore */}
|
|
||||||
<Sidebar />
|
|
||||||
<UserMenu session={session} />
|
|
||||||
</div>
|
|
||||||
<div className="flex space-x-2 items-center">
|
|
||||||
<Link href="/" className={cn(buttonVariants({ size: 'sm' }))}>
|
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
|
||||||
New Chat
|
|
||||||
</Link>
|
|
||||||
<a
|
|
||||||
href="https://github.com/vercel/nextjs-ai-chatbot/"
|
|
||||||
target="_blank"
|
|
||||||
className={cn(
|
|
||||||
buttonVariants({ size: 'sm', variant: 'outline' }),
|
|
||||||
'space-x-2'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Vercel className="mr-2" />
|
|
||||||
Deploy
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
href="https://github.com/vercel/nextjs-ai-chatbot/"
|
|
||||||
className={cn(
|
|
||||||
buttonVariants({ size: 'sm', variant: 'ghost' }),
|
|
||||||
'h-9 w-9 p-0'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<GitHub className="w-5 h-5" />
|
|
||||||
<span className="sr-only">View on GitHub</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { Metadata } from 'next'
|
import { Metadata } from 'next'
|
||||||
import './globals.css'
|
|
||||||
|
|
||||||
import { TailwindIndicator } from '@/components/tailwind-indicator'
|
import '@/app/globals.css'
|
||||||
import { ThemeProvider } from '@/components/theme-provider'
|
|
||||||
import { fontMono, fontSans } from '@/lib/fonts'
|
import { fontMono, fontSans } from '@/lib/fonts'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { Header } from '@/app/header'
|
import { TailwindIndicator } from '@/components/tailwind-indicator'
|
||||||
|
import { ThemeProvider } from '@/components/theme-provider'
|
||||||
|
import { Header } from '@/components/header'
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
|
|
@ -43,7 +43,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
|
||||||
<div className="h-screen flex flex-col">
|
<div className="h-screen flex flex-col">
|
||||||
{/* @ts-ignore */}
|
{/* @ts-ignore */}
|
||||||
<Header />
|
<Header />
|
||||||
<main className="flex-1 overflow-hidden">{children}</main>
|
<main className="flex-1">{children}</main>
|
||||||
</div>
|
</div>
|
||||||
<TailwindIndicator />
|
<TailwindIndicator />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
|
|
||||||
11
app/page.tsx
11
app/page.tsx
|
|
@ -1,13 +1,8 @@
|
||||||
import { type Message } from 'ai-connector'
|
import { Chat } from '@/components/chat'
|
||||||
import { Chat } from './chat'
|
|
||||||
|
|
||||||
export const runtime = 'edge'
|
// export const runtime = 'edge'
|
||||||
export const preferredRegion = 'home'
|
export const preferredRegion = 'home'
|
||||||
|
|
||||||
export default async function IndexPage() {
|
export default async function IndexPage() {
|
||||||
return (
|
return <Chat />
|
||||||
<div className="h-full overflow-hidden">
|
|
||||||
<Chat />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
'use client'
|
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { usePathname, useRouter } from 'next/navigation'
|
|
||||||
import { MessageCircleIcon, Trash2Icon, Loader2Icon } from 'lucide-react'
|
|
||||||
import { removeChat } from './actions'
|
|
||||||
import { useTransition } from 'react'
|
|
||||||
|
|
||||||
export function SidebarItem({
|
|
||||||
title,
|
|
||||||
href,
|
|
||||||
id,
|
|
||||||
userId
|
|
||||||
}: {
|
|
||||||
title: string
|
|
||||||
href: string
|
|
||||||
id: string
|
|
||||||
userId: string
|
|
||||||
}) {
|
|
||||||
const pathname = usePathname()
|
|
||||||
const router = useRouter()
|
|
||||||
const active = pathname === href
|
|
||||||
const [isPending, startTransition] = useTransition()
|
|
||||||
|
|
||||||
if (!id) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
href={href}
|
|
||||||
className={cn(
|
|
||||||
'group flex shrink-0 cursor-pointer items-center gap-2 rounded p-2 text-sm font-medium transition-colors duration-100 hover:bg-zinc-500/10 hover:dark:bg-zinc-300/20',
|
|
||||||
isPending
|
|
||||||
? 'text-zinc-400 dark:text-zinc-500'
|
|
||||||
: 'text-zinc-800 dark:text-zinc-400',
|
|
||||||
active
|
|
||||||
? 'bg-zinc-500/20 text-zinc-900 font-semibold hover:bg-zinc-500/30 dark:text-white'
|
|
||||||
: 'bg-transparent'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<MessageCircleIcon className="h-4 w-4" />
|
|
||||||
<div
|
|
||||||
className="relative max-h-5 flex-1 overflow-hidden text-ellipsis break-all select-none"
|
|
||||||
title={title}
|
|
||||||
>
|
|
||||||
<span className="whitespace-nowrap">{title}</span>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className="opacity-0 -mr-6 transition-opacity duration-0 hover:bg-zinc-400/50 group-hover:mr-0 group-hover:opacity-80 p-1 -my-1 rounded group-hover:duration-600"
|
|
||||||
disabled={isPending}
|
|
||||||
onClick={e => {
|
|
||||||
e.preventDefault()
|
|
||||||
startTransition(() => {
|
|
||||||
removeChat({ id, userId, path: href }).then(() => {
|
|
||||||
router.push('/')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isPending ? (
|
|
||||||
<Loader2Icon className="animate-spin h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<Trash2Icon className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
import { Chat } from '@/lib/types'
|
|
||||||
import { type Session } from '@auth/nextjs/types'
|
|
||||||
import { kv } from '@vercel/kv'
|
|
||||||
import { Sidebar as SidebarIcon } from 'lucide-react'
|
|
||||||
import { SidebarItem } from './sidebar-item'
|
|
||||||
|
|
||||||
import { auth } from '@/auth'
|
|
||||||
import { NextChat } from '@/components/icons'
|
|
||||||
import { Button } from '@/components/ui/button'
|
|
||||||
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
|
|
||||||
|
|
||||||
export interface SidebarProps {}
|
|
||||||
|
|
||||||
export async function Sidebar({}: SidebarProps) {
|
|
||||||
const session = await auth()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Sheet>
|
|
||||||
<SheetTrigger asChild>
|
|
||||||
<Button variant="ghost" className="w-9 h-9 p-0">
|
|
||||||
<SidebarIcon className="w-6 h-6" />
|
|
||||||
<span className="sr-only">Toggle Sidebar</span>
|
|
||||||
</Button>
|
|
||||||
</SheetTrigger>
|
|
||||||
<SheetContent
|
|
||||||
position="left"
|
|
||||||
className="w-[300px] top-2 rounded-lg left-2 bottom-2 h-auto"
|
|
||||||
>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<NextChat className="mr-2 w-6 h-6 text-primary" inverted />
|
|
||||||
<span className="select-none font-bold">Chatbot</span>
|
|
||||||
</div>
|
|
||||||
{/* @ts-ignore */}
|
|
||||||
<SidebarList session={session} />
|
|
||||||
</SheetContent>
|
|
||||||
</Sheet>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function SidebarList({ session }: { session?: Session }) {
|
|
||||||
const results: Chat[] = await getChats(session?.user?.email ?? '')
|
|
||||||
|
|
||||||
return results.map(c => (
|
|
||||||
<SidebarItem
|
|
||||||
key={c.id}
|
|
||||||
title={c.title}
|
|
||||||
userId={session?.user?.email ?? ''}
|
|
||||||
href={`/chat/${c.id}`}
|
|
||||||
id={c.id}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getChats(userId: string) {
|
|
||||||
try {
|
|
||||||
const pipeline = kv.pipeline()
|
|
||||||
const chats: string[] = await kv.zrange(`user:chat:${userId}`, 0, -1)
|
|
||||||
|
|
||||||
for (const chat of chats) {
|
|
||||||
pipeline.hgetall(chat)
|
|
||||||
}
|
|
||||||
|
|
||||||
const results = await pipeline.exec()
|
|
||||||
|
|
||||||
return results as Chat[]
|
|
||||||
} catch (error) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
28
auth.ts
28
auth.ts
|
|
@ -1,27 +1,27 @@
|
||||||
import NextAuth from "@auth/nextjs";
|
import NextAuth from '@auth/nextjs'
|
||||||
import GitHub from "@auth/nextjs/providers/github";
|
import GitHub from '@auth/nextjs/providers/github'
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
handlers: { GET, POST },
|
handlers: { GET, POST },
|
||||||
auth,
|
auth,
|
||||||
CSRF_experimental,
|
CSRF_experimental
|
||||||
} = NextAuth({
|
} = NextAuth({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
providers: [GitHub],
|
providers: [GitHub],
|
||||||
session: { strategy: "jwt" },
|
session: { strategy: 'jwt' },
|
||||||
async authorized({ request, auth }: any) {
|
async authorized({ request, auth }: any) {
|
||||||
const url = request.nextUrl;
|
const url = request.nextUrl
|
||||||
|
|
||||||
if (request.method === "POST") {
|
if (request.method === 'POST') {
|
||||||
const { authToken } = (await request.json()) ?? {};
|
const { authToken } = (await request.json()) ?? {}
|
||||||
// If the request has a valid auth token, it is authorized
|
// If the request has a valid auth token, it is authorized
|
||||||
const valid = true;
|
const valid = true
|
||||||
if (valid) return true;
|
if (valid) return true
|
||||||
return NextResponse.json("Invalid auth token", { status: 401 });
|
return NextResponse.json('Invalid auth token', { status: 401 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logged in users are authenticated, otherwise redirect to login page
|
// Logged in users are authenticated, otherwise redirect to login page
|
||||||
return !!auth;
|
return !!auth
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
|
||||||
26
components/chat-list.tsx
Normal file
26
components/chat-list.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { type Message } from 'ai-connector'
|
||||||
|
|
||||||
|
import { ChatMessage } from '@/components/chat-message'
|
||||||
|
import { EmptyScreen } from '@/components/empty-screen'
|
||||||
|
|
||||||
|
export interface ChatList {
|
||||||
|
messages: Message[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChatList({ messages }: ChatList) {
|
||||||
|
return (
|
||||||
|
<div className="relative max-w-2xl mx-auto">
|
||||||
|
{messages.length > 0 ? (
|
||||||
|
messages.map(message => (
|
||||||
|
<ChatMessage key={message.id || message.content} message={message} />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="pt-10">
|
||||||
|
<EmptyScreen />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import CodeBlock from '@/components/ui/codeblock'
|
|
||||||
import { MemoizedReactMarkdown } from '@/components/markdown'
|
|
||||||
import remarkGfm from 'remark-gfm'
|
|
||||||
import remarkMath from 'remark-math'
|
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { fontMessage } from '@/lib/fonts'
|
|
||||||
import { Message } from 'ai-connector'
|
import { Message } from 'ai-connector'
|
||||||
import { User } from 'lucide-react'
|
import { User } from 'lucide-react'
|
||||||
|
import remarkGfm from 'remark-gfm'
|
||||||
|
import remarkMath from 'remark-math'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { fontMessage } from '@/lib/fonts'
|
||||||
|
import CodeBlock from '@/components/ui/codeblock'
|
||||||
|
import { MemoizedReactMarkdown } from '@/components/markdown'
|
||||||
import { OpenAI } from '@/components/icons'
|
import { OpenAI } from '@/components/icons'
|
||||||
|
|
||||||
export interface ChatMessageProps {
|
export interface ChatMessageProps {
|
||||||
|
|
@ -16,7 +17,7 @@ export function ChatMessage({ message, ...props }: ChatMessageProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-start space-x-4 mb-4',
|
'flex items-start space-x-4 mb-4 relative -ml-12',
|
||||||
fontMessage.className,
|
fontMessage.className,
|
||||||
message.role === 'user' && 'mt-12 first:mt-0'
|
message.role === 'user' && 'mt-12 first:mt-0'
|
||||||
)}
|
)}
|
||||||
|
|
@ -24,7 +25,7 @@ export function ChatMessage({ message, ...props }: ChatMessageProps) {
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-8 w-8 -ml-2 shrink-0 items-center justify-center rounded-full select-none border',
|
'flex h-8 w-8 shrink-0 items-center justify-center rounded-full select-none border',
|
||||||
message.role === 'assistant' && 'bg-primary text-primary-foreground'
|
message.role === 'assistant' && 'bg-primary text-primary-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
45
components/chat-panel.tsx
Normal file
45
components/chat-panel.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { ExternalLink } from '@/components/external-link'
|
||||||
|
import { UseChatHelpers } from 'ai-connector'
|
||||||
|
import { PromptForm } from './prompt-form'
|
||||||
|
|
||||||
|
export interface ChatPanelProps
|
||||||
|
extends Pick<UseChatHelpers, 'append' | 'isLoading' | 'reload' | 'messages'> {
|
||||||
|
id?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChatPanel({
|
||||||
|
id,
|
||||||
|
append,
|
||||||
|
isLoading,
|
||||||
|
reload,
|
||||||
|
messages
|
||||||
|
}: ChatPanelProps) {
|
||||||
|
return (
|
||||||
|
<div className="fixed bottom-0 left-0 right-0">
|
||||||
|
<div className="max-w-2xl mx-auto">
|
||||||
|
<div className="px-4 py-2 border space-y-4 shadow-lg bg-gradient-to-b from-background/10 via-background/50 to-background/80 backdrop-blur-lg rounded-t-xl">
|
||||||
|
<PromptForm
|
||||||
|
onSubmit={value => {
|
||||||
|
append({
|
||||||
|
content: value,
|
||||||
|
role: 'user'
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
onRefresh={messages.length ? reload : undefined}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
<p className="text-muted-foreground text-xs leading-normal text-center pb-1">
|
||||||
|
This is an open source AI chatbot app built with{' '}
|
||||||
|
<ExternalLink href="https://nextjs.org">Next.js</ExternalLink> and{' '}
|
||||||
|
<ExternalLink href="https://vercel.com/storage/kv">
|
||||||
|
Vercel KV
|
||||||
|
</ExternalLink>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
33
components/chat.tsx
Normal file
33
components/chat.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useChat, type Message } from 'ai-connector'
|
||||||
|
import { ChatList } from '@/components/chat-list'
|
||||||
|
import { ChatPanel } from '@/components/chat-panel'
|
||||||
|
|
||||||
|
export interface ChatProps {
|
||||||
|
// create?: (input: string) => Chat | undefined;
|
||||||
|
initialMessages?: Message[]
|
||||||
|
id?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Chat({ id, initialMessages }: ChatProps) {
|
||||||
|
const { messages, append, reload, isLoading } = useChat({
|
||||||
|
initialMessages,
|
||||||
|
id
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full overflow-hidden">
|
||||||
|
<div className="h-full w-full overflow-auto pb-[200px]">
|
||||||
|
<ChatList messages={messages} />
|
||||||
|
<ChatPanel
|
||||||
|
id={id}
|
||||||
|
append={append}
|
||||||
|
isLoading={isLoading}
|
||||||
|
reload={reload}
|
||||||
|
messages={messages}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { ExternalLink } from './external-link'
|
|
||||||
import { ArrowRight } from 'lucide-react'
|
import { ArrowRight } from 'lucide-react'
|
||||||
import { useChatStore } from '@/hooks/use-chat-store'
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { useChatStore } from '@/lib/hooks/use-chat-store'
|
||||||
|
import { ExternalLink } from '@/components/external-link'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { OpenAI } from '@/components/icons'
|
import { OpenAI } from '@/components/icons'
|
||||||
|
|
||||||
|
|
@ -24,10 +25,10 @@ export function EmptyScreen({ className }: React.ComponentProps<'div'>) {
|
||||||
const { setDefaultMessage } = useChatStore()
|
const { setDefaultMessage } = useChatStore()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-start space-x-4 mb-4">
|
<div className="flex items-start space-x-4 mb-4 -ml-12">
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-8 w-8 -ml-2 shrink-0 items-center justify-center rounded-full select-none border bg-primary text-primary-foreground'
|
'flex h-8 w-8 shrink-0 items-center justify-center rounded-full select-none border bg-primary text-primary-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<OpenAI className="w-4 h-4" />
|
<OpenAI className="w-4 h-4" />
|
||||||
42
components/header.tsx
Normal file
42
components/header.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { auth } from '@/auth'
|
||||||
|
import { getChats } from '@/app/actions'
|
||||||
|
import { buttonVariants } from '@/components/ui/button'
|
||||||
|
import { UserMenu } from '@/components/user-menu'
|
||||||
|
import { GitHub, Separator, Vercel } from '@/components/icons'
|
||||||
|
import { Sidebar } from '@/components/sidebar'
|
||||||
|
|
||||||
|
export async function Header() {
|
||||||
|
const session = await auth()
|
||||||
|
const chats = session?.user?.email ? await getChats(session.user.email) : []
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header className="h-16 shrink-0 z-50 bg-gradient-to-b from-background/10 via-background/50 to-background/80 backdrop-blur-lg px-4 flex sticky top-0 w-full items-center justify-between">
|
||||||
|
<div className="flex items-center w-2/5">
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<Sidebar chats={chats} session={session} />
|
||||||
|
<Separator className="h-6 w-6 text-muted-foreground/50" />
|
||||||
|
<UserMenu session={session} />
|
||||||
|
</div>
|
||||||
|
<div className="flex space-x-2 items-center justify-end w-2/5">
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
href="https://github.com/vercel/nextjs-ai-chatbot/"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className={cn(buttonVariants({ variant: 'outline' }))}
|
||||||
|
>
|
||||||
|
<GitHub className="w-4 h-4 mr-2" />
|
||||||
|
<span>GitHub</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vercel/nextjs-ai-chatbot/"
|
||||||
|
target="_blank"
|
||||||
|
className={cn(buttonVariants())}
|
||||||
|
>
|
||||||
|
<Vercel className="w-4 h-4 mr-2" />
|
||||||
|
Deploy to Vercel
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
|
@ -1,6 +1,7 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
export function NextChat({
|
export function NextChat({
|
||||||
|
|
@ -135,3 +136,25 @@ export function GitHub({ className, ...props }: React.ComponentProps<'svg'>) {
|
||||||
</svg>
|
</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('w-4 h-4', className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d="M16.88 3.549L7.12 20.451"></path>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { CornerDownLeft, RefreshCcw, StopCircle } from 'lucide-react'
|
import { CornerDownLeft, Plus, RefreshCcw, StopCircle } from 'lucide-react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Textarea from 'react-textarea-autosize'
|
import Textarea from 'react-textarea-autosize'
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button, buttonVariants } from '@/components/ui/button'
|
||||||
import { fontMessage } from '@/lib/fonts'
|
import { fontMessage } from '@/lib/fonts'
|
||||||
import { useCmdEnterSubmit } from '@/lib/hooks/use-command-enter-submit'
|
import { useEnterSubmit } from '@/lib/hooks/use-enter-submit'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useChatStore } from '@/hooks/use-chat-store'
|
import { useChatStore } from '@/lib/hooks/use-chat-store'
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger
|
TooltipTrigger
|
||||||
} from '@/components/ui/tooltip'
|
} from '@/components/ui/tooltip'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
export interface PromptProps {
|
export interface PromptProps {
|
||||||
onSubmit: (value: string) => void
|
onSubmit: (value: string) => void
|
||||||
|
|
@ -24,7 +25,7 @@ export interface PromptProps {
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Prompt({
|
export function PromptForm({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onAbort,
|
onAbort,
|
||||||
|
|
@ -32,7 +33,7 @@ export function Prompt({
|
||||||
}: PromptProps) {
|
}: PromptProps) {
|
||||||
const { defaultMessage } = useChatStore()
|
const { defaultMessage } = useChatStore()
|
||||||
const [input, setInput] = useState(defaultMessage)
|
const [input, setInput] = useState(defaultMessage)
|
||||||
const { formRef, onKeyDown } = useCmdEnterSubmit()
|
const { formRef, onKeyDown } = useEnterSubmit()
|
||||||
const inputRef = React.useRef<HTMLTextAreaElement>(null)
|
const inputRef = React.useRef<HTMLTextAreaElement>(null)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
@ -69,45 +70,40 @@ export function Prompt({
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
{/* <button
|
|
||||||
id="share-button"
|
|
||||||
className="btn btn-neutral flex justify-center gap-2"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
className="h-3 w-3"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M7.217 10.907a2.25 2.25 0 100 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186l9.566-5.314m-9.566 7.5l9.566 5.314m0 0a2.25 2.25 0 103.935 2.186 2.25 2.25 0 00-3.935-2.186zm0-12.814a2.25 2.25 0 103.933-2.185 2.25 2.25 0 00-3.933 2.185z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Share
|
|
||||||
</button> */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative flex w-full grow flex-col rounded-md border bg-background overflow-hidden pr-12">
|
<TooltipProvider>
|
||||||
<Textarea
|
<div className="relative flex w-full grow flex-col rounded-md border bg-background overflow-hidden px-12">
|
||||||
ref={inputRef}
|
<Tooltip>
|
||||||
tabIndex={0}
|
<TooltipTrigger asChild>
|
||||||
onKeyDown={onKeyDown}
|
<Link
|
||||||
rows={1}
|
href="/"
|
||||||
value={input}
|
className={cn(
|
||||||
onChange={e => setInput(e.target.value)}
|
buttonVariants({ size: 'sm', variant: 'outline' }),
|
||||||
placeholder="Send a message."
|
'w-8 h-8 p-0 rounded-full absolute top-4 left-4 bg-background'
|
||||||
spellCheck={false}
|
)}
|
||||||
className={cn(
|
>
|
||||||
'min-h-[60px] text-sm p-4 bg-transparent focus-within:outline-none w-full resize-none',
|
<Plus className="h-4 w-4" />
|
||||||
fontMessage.className
|
<span className="sr-only">New Chat</span>
|
||||||
)}
|
</Link>
|
||||||
/>
|
</TooltipTrigger>
|
||||||
<div className="absolute top-4 right-4">
|
<TooltipContent>New Chat</TooltipContent>
|
||||||
<TooltipProvider>
|
</Tooltip>
|
||||||
|
<Textarea
|
||||||
|
ref={inputRef}
|
||||||
|
tabIndex={0}
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
rows={1}
|
||||||
|
value={input}
|
||||||
|
onChange={e => setInput(e.target.value)}
|
||||||
|
placeholder="Send a message."
|
||||||
|
spellCheck={false}
|
||||||
|
className={cn(
|
||||||
|
'min-h-[60px] text-sm bg-transparent px-4 py-[1.4rem] focus-within:outline-none w-full resize-none',
|
||||||
|
fontMessage.className
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="absolute top-4 right-4">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
|
|
@ -125,20 +121,16 @@ export function Prompt({
|
||||||
) : (
|
) : (
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button type="submit" className="h-8 w-8 p-0">
|
||||||
variant="ghost"
|
|
||||||
type="submit"
|
|
||||||
className="h-8 w-8 p-0"
|
|
||||||
>
|
|
||||||
<CornerDownLeft className="h-4 w-4" />
|
<CornerDownLeft className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>Send message</TooltipContent>
|
<TooltipContent>Send message</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</TooltipProvider>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</TooltipProvider>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
104
components/sidebar-item.tsx
Normal file
104
components/sidebar-item.tsx
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Loader2Icon, MessageSquare, Trash2Icon } from 'lucide-react'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { usePathname, useRouter } from 'next/navigation'
|
||||||
|
import * as React from 'react'
|
||||||
|
import { useTransition } from 'react'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { removeChat } from '@/app/actions'
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle
|
||||||
|
} from '@/components/ui/alert-dialog'
|
||||||
|
import { Button, buttonVariants } from '@/components/ui/button'
|
||||||
|
|
||||||
|
export function SidebarItem({
|
||||||
|
title,
|
||||||
|
href,
|
||||||
|
id,
|
||||||
|
userId
|
||||||
|
}: {
|
||||||
|
title: string
|
||||||
|
href: string
|
||||||
|
id: string
|
||||||
|
userId: string
|
||||||
|
}) {
|
||||||
|
const [open, setIsOpen] = React.useState(false)
|
||||||
|
const pathname = usePathname()
|
||||||
|
const router = useRouter()
|
||||||
|
const isActive = pathname === href
|
||||||
|
const [isPending, startTransition] = useTransition()
|
||||||
|
|
||||||
|
if (!id) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Link
|
||||||
|
href={href}
|
||||||
|
className={cn(
|
||||||
|
buttonVariants({ variant: 'ghost' }),
|
||||||
|
'group w-full px-2',
|
||||||
|
isActive && 'bg-accent'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<MessageSquare className="h-4 w-4 mr-2" />
|
||||||
|
<div
|
||||||
|
className="relative max-h-5 flex-1 overflow-hidden text-ellipsis break-all select-none"
|
||||||
|
title={title}
|
||||||
|
>
|
||||||
|
<span className="whitespace-nowrap">{title}</span>
|
||||||
|
</div>
|
||||||
|
{isActive && (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="w-7 h-7"
|
||||||
|
disabled={isPending}
|
||||||
|
onClick={() => setIsOpen(true)}
|
||||||
|
>
|
||||||
|
<Trash2Icon className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Delete</span>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
<AlertDialog open={open} onOpenChange={setIsOpen}>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
This will permanently delete your chat message and remove your
|
||||||
|
data from our servers.
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel disabled={isPending}>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
disabled={isPending}
|
||||||
|
onClick={event => {
|
||||||
|
event.preventDefault()
|
||||||
|
startTransition(async () => {
|
||||||
|
await removeChat({ id, userId, path: href })
|
||||||
|
setIsOpen(false)
|
||||||
|
router.push('/')
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isPending && (
|
||||||
|
<Loader2Icon className="animate-spin h-4 w-4 mr-2" />
|
||||||
|
)}
|
||||||
|
Delete
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
77
components/sidebar.tsx
Normal file
77
components/sidebar.tsx
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as React from 'react'
|
||||||
|
import { Sidebar as SidebarIcon } from 'lucide-react'
|
||||||
|
import { type Session } from '@auth/nextjs/types'
|
||||||
|
import { signOut } from '@auth/nextjs/client'
|
||||||
|
|
||||||
|
import { type Chat } from '@/lib/types'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import {
|
||||||
|
Sheet,
|
||||||
|
SheetContent,
|
||||||
|
SheetHeader,
|
||||||
|
SheetTitle,
|
||||||
|
SheetTrigger
|
||||||
|
} from '@/components/ui/sheet'
|
||||||
|
import { SidebarItem } from '@/components/sidebar-item'
|
||||||
|
import { ThemeToggle } from '@/components/theme-toggle'
|
||||||
|
|
||||||
|
export interface SidebarProps {
|
||||||
|
session?: Session
|
||||||
|
chats: Chat[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function Sidebar({ session, chats }: SidebarProps) {
|
||||||
|
return (
|
||||||
|
<Sheet>
|
||||||
|
<SheetTrigger asChild>
|
||||||
|
<Button variant="ghost" className="w-9 h-9 p-0">
|
||||||
|
<SidebarIcon className="w-6 h-6" />
|
||||||
|
<span className="sr-only">Toggle Sidebar</span>
|
||||||
|
</Button>
|
||||||
|
</SheetTrigger>
|
||||||
|
<SheetContent
|
||||||
|
position="left"
|
||||||
|
className="w-[300px] gap-0 top-2 px-4 rounded-r-lg bottom-2 h-auto flex flex-col"
|
||||||
|
>
|
||||||
|
<SheetHeader>
|
||||||
|
<SheetTitle>Chat History</SheetTitle>
|
||||||
|
</SheetHeader>
|
||||||
|
<div className="flex-1">
|
||||||
|
{chats?.length ? (
|
||||||
|
<div className="space-y-2 -mx-2 py-4">
|
||||||
|
{chats.map(chat => (
|
||||||
|
<SidebarItem
|
||||||
|
key={chat.id}
|
||||||
|
title={chat.title}
|
||||||
|
userId={session?.user?.email ?? ''}
|
||||||
|
href={`/chat/${chat.id}`}
|
||||||
|
id={chat.id}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-center p-8">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{session?.user ? <>No chat history</> : <>Login for history</>}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<ThemeToggle />
|
||||||
|
{session?.user && (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => signOut()}
|
||||||
|
className="ml-auto"
|
||||||
|
>
|
||||||
|
Logout
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,33 +1,31 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import * as React from 'react'
|
||||||
import { useTheme } from 'next-themes'
|
import { useTheme } from 'next-themes'
|
||||||
|
import { Moon, Sun } from 'lucide-react'
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Moon, Sun } from 'lucide-react'
|
|
||||||
import { useTransition } from 'react'
|
|
||||||
|
|
||||||
export function ThemeToggle() {
|
export function ThemeToggle() {
|
||||||
const { setTheme, theme } = useTheme()
|
const { setTheme, theme } = useTheme()
|
||||||
const [_, startTransition] = useTransition()
|
const [_, startTransition] = React.useTransition()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="icon"
|
||||||
className="p-0 leading-4 h-4 font-normal w-full"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
setTheme(theme === 'light' ? 'dark' : 'light')
|
setTheme(theme === 'light' ? 'dark' : 'light')
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="flex flex-row justify-between text-xs text-zinc-900 dark:text-zinc-400 w-full">
|
{!theme ? null : theme === 'dark' ? (
|
||||||
<span className="">Toggle theme</span>
|
<Moon className="h-4 w-4 transition-all" />
|
||||||
{!theme ? null : theme === 'dark' ? (
|
) : (
|
||||||
<Moon className="h-4 transition-all" />
|
<Sun className="h-4 w-4 transition-all" />
|
||||||
) : (
|
)}
|
||||||
<Sun className="h-4 transition-all" />
|
<span className="sr-only">Toggle theme</span>
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
150
components/ui/alert-dialog.tsx
Normal file
150
components/ui/alert-dialog.tsx
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
"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 = ({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: AlertDialogPrimitive.AlertDialogPortalProps) => (
|
||||||
|
<AlertDialogPrimitive.Portal className={cn(className)} {...props}>
|
||||||
|
<div className="fixed inset-0 z-50 flex items-end justify-center sm:items-center">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</AlertDialogPrimitive.Portal>
|
||||||
|
)
|
||||||
|
AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName
|
||||||
|
|
||||||
|
const AlertDialogOverlay = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Overlay
|
||||||
|
className={cn(
|
||||||
|
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-opacity animate-in fade-in",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
||||||
|
|
||||||
|
const AlertDialogContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPortal>
|
||||||
|
<AlertDialogOverlay />
|
||||||
|
<AlertDialogPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed z-50 grid w-full max-w-lg scale-100 gap-4 border bg-background p-6 opacity-100 shadow-lg animate-in fade-in-90 slide-in-from-bottom-10 sm:rounded-lg sm:zoom-in-90 sm:slide-in-from-bottom-0 md:w-full",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</AlertDialogPortal>
|
||||||
|
))
|
||||||
|
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const AlertDialogHeader = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col space-y-2 text-center sm:text-left",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
AlertDialogHeader.displayName = "AlertDialogHeader"
|
||||||
|
|
||||||
|
const AlertDialogFooter = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
AlertDialogFooter.displayName = "AlertDialogFooter"
|
||||||
|
|
||||||
|
const AlertDialogTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-lg font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
||||||
|
|
||||||
|
const AlertDialogDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogDescription.displayName =
|
||||||
|
AlertDialogPrimitive.Description.displayName
|
||||||
|
|
||||||
|
const AlertDialogAction = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Action
|
||||||
|
ref={ref}
|
||||||
|
className={cn(buttonVariants(), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
||||||
|
|
||||||
|
const AlertDialogCancel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Cancel
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
buttonVariants({ variant: "outline" }),
|
||||||
|
"mt-2 sm:mt-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogTrigger,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogTitle,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background',
|
'inline-flex items-center justify-center shadow-sm rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
|
|
@ -16,13 +16,14 @@ const buttonVariants = cva(
|
||||||
'border border-input hover:bg-accent hover:text-accent-foreground',
|
'border border-input hover:bg-accent hover:text-accent-foreground',
|
||||||
secondary:
|
secondary:
|
||||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
ghost: 'hover:bg-accent shadow-none hover:text-accent-foreground',
|
||||||
link: 'underline-offset-4 hover:underline text-primary'
|
link: 'underline-offset-4 shadow-none hover:underline text-primary'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: 'h-10 py-2 px-4',
|
default: 'h-9 py-2 px-4',
|
||||||
sm: 'h-9 px-3 rounded-md',
|
sm: 'h-9 px-3 rounded-md',
|
||||||
lg: 'h-11 px-8 rounded-md'
|
lg: 'h-11 px-8 rounded-md',
|
||||||
|
icon: 'h-9 w-9 p-0'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
|
|
|
||||||
128
components/ui/dialog.tsx
Normal file
128
components/ui/dialog.tsx
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as React from 'react'
|
||||||
|
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
||||||
|
import { X } from 'lucide-react'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const Dialog = DialogPrimitive.Root
|
||||||
|
|
||||||
|
const DialogTrigger = DialogPrimitive.Trigger
|
||||||
|
|
||||||
|
const DialogPortal = ({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: DialogPrimitive.DialogPortalProps) => (
|
||||||
|
<DialogPrimitive.Portal className={cn(className)} {...props}>
|
||||||
|
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</DialogPrimitive.Portal>
|
||||||
|
)
|
||||||
|
DialogPortal.displayName = DialogPrimitive.Portal.displayName
|
||||||
|
|
||||||
|
const DialogOverlay = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Overlay
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||||
|
|
||||||
|
const DialogContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<DialogPortal>
|
||||||
|
<DialogOverlay />
|
||||||
|
<DialogPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'fixed z-50 grid w-full gap-4 rounded-b-lg border bg-background p-6 shadow-sm animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{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">
|
||||||
|
<X className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Close</span>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</DialogPortal>
|
||||||
|
))
|
||||||
|
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const DialogHeader = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex flex-col space-y-1.5 text-center sm:text-left',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
DialogHeader.displayName = 'DialogHeader'
|
||||||
|
|
||||||
|
const DialogFooter = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
DialogFooter.displayName = 'DialogFooter'
|
||||||
|
|
||||||
|
const DialogTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'text-lg font-semibold leading-none tracking-tight',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||||
|
|
||||||
|
const DialogDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={cn('text-sm text-muted-foreground', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
Dialog,
|
||||||
|
DialogTrigger,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogFooter,
|
||||||
|
DialogTitle,
|
||||||
|
DialogDescription
|
||||||
|
}
|
||||||
200
components/ui/dropdown-menu.tsx
Normal file
200
components/ui/dropdown-menu.tsx
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as React from 'react'
|
||||||
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
|
||||||
|
import { Check, ChevronRight, Circle } from 'lucide-react'
|
||||||
|
|
||||||
|
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 DropdownMenuSubTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||||
|
inset?: boolean
|
||||||
|
}
|
||||||
|
>(({ className, inset, children, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
|
||||||
|
inset && 'pl-8',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<ChevronRight className="ml-auto h-4 w-4" />
|
||||||
|
</DropdownMenuPrimitive.SubTrigger>
|
||||||
|
))
|
||||||
|
DropdownMenuSubTrigger.displayName =
|
||||||
|
DropdownMenuPrimitive.SubTrigger.displayName
|
||||||
|
|
||||||
|
const DropdownMenuSubContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.SubContent
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DropdownMenuSubContent.displayName =
|
||||||
|
DropdownMenuPrimitive.SubContent.displayName
|
||||||
|
|
||||||
|
const DropdownMenuContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||||
|
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.Portal>
|
||||||
|
<DropdownMenuPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
className={cn(
|
||||||
|
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-sm animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</DropdownMenuPrimitive.Portal>
|
||||||
|
))
|
||||||
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const DropdownMenuItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||||
|
inset?: boolean
|
||||||
|
}
|
||||||
|
>(({ className, inset, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
|
inset && 'pl-8',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||||
|
>(({ className, children, checked, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
checked={checked}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<DropdownMenuPrimitive.ItemIndicator>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</DropdownMenuPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
{children}
|
||||||
|
</DropdownMenuPrimitive.CheckboxItem>
|
||||||
|
))
|
||||||
|
DropdownMenuCheckboxItem.displayName =
|
||||||
|
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||||
|
|
||||||
|
const DropdownMenuRadioItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.RadioItem
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<DropdownMenuPrimitive.ItemIndicator>
|
||||||
|
<Circle className="h-2 w-2 fill-current" />
|
||||||
|
</DropdownMenuPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
{children}
|
||||||
|
</DropdownMenuPrimitive.RadioItem>
|
||||||
|
))
|
||||||
|
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||||
|
|
||||||
|
const DropdownMenuLabel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||||
|
inset?: boolean
|
||||||
|
}
|
||||||
|
>(({ className, inset, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.Label
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'px-2 py-1.5 text-sm font-semibold',
|
||||||
|
inset && 'pl-8',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||||
|
|
||||||
|
const DropdownMenuSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DropdownMenuPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
const DropdownMenuShortcut = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={cn('ml-auto text-xs tracking-widest opacity-60', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
|
||||||
|
|
||||||
|
export {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
|
DropdownMenuRadioItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuShortcut,
|
||||||
|
DropdownMenuGroup,
|
||||||
|
DropdownMenuPortal,
|
||||||
|
DropdownMenuSub,
|
||||||
|
DropdownMenuSubContent,
|
||||||
|
DropdownMenuSubTrigger,
|
||||||
|
DropdownMenuRadioGroup
|
||||||
|
}
|
||||||
25
components/ui/input.tsx
Normal file
25
components/ui/input.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
export interface InputProps
|
||||||
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
|
|
||||||
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, type, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
className={cn(
|
||||||
|
'flex h-9 w-full shadow-sm rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Input.displayName = 'Input'
|
||||||
|
|
||||||
|
export { Input }
|
||||||
|
|
@ -66,7 +66,6 @@ const SheetContent = React.forwardRef<
|
||||||
DialogContentProps
|
DialogContentProps
|
||||||
>(({ position, className, children, ...props }, ref) => (
|
>(({ position, className, children, ...props }, ref) => (
|
||||||
<SheetPortal>
|
<SheetPortal>
|
||||||
<SheetOverlay />
|
|
||||||
<SheetPrimitive.Content
|
<SheetPrimitive.Content
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(sheetVariants({ position }), className)}
|
className={cn(sheetVariants({ position }), className)}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,36 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button'
|
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'
|
||||||
|
|
||||||
export interface UserMenuProps {
|
export interface UserMenuProps {
|
||||||
session: Session
|
session?: Session
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UserMenu({ session }: UserMenuProps) {
|
export function UserMenu({ session }: UserMenuProps) {
|
||||||
if (!session) {
|
const [isLoading, setIsLoading] = React.useState(false)
|
||||||
|
|
||||||
|
if (!session?.user) {
|
||||||
return (
|
return (
|
||||||
<Button variant="ghost" size="sm" onClick={() => signIn('github')}>
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
setIsLoading(true)
|
||||||
|
signIn('github')
|
||||||
|
}}
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
|
{isLoading && <Loader2Icon className="animate-spin w-4 h-4 mr-2" />}
|
||||||
Login
|
Login
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <p className="text-sm font-medium">Logged in as {session.user.name}</p>
|
||||||
<div className="flex items-center justify-between text-sm">
|
|
||||||
{session?.user && (
|
|
||||||
<Button variant="link" size="sm">
|
|
||||||
{session.user?.name}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import type { RefObject } from 'react'
|
import type { RefObject } from 'react'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
|
||||||
export function useCmdEnterSubmit(): {
|
export function useEnterSubmit(): {
|
||||||
formRef: RefObject<HTMLFormElement>
|
formRef: RefObject<HTMLFormElement>
|
||||||
onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void
|
onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void
|
||||||
} {
|
} {
|
||||||
|
|
@ -10,8 +10,9 @@ export function useCmdEnterSubmit(): {
|
||||||
const handleKeyDown = (
|
const handleKeyDown = (
|
||||||
event: React.KeyboardEvent<HTMLTextAreaElement>
|
event: React.KeyboardEvent<HTMLTextAreaElement>
|
||||||
): void => {
|
): void => {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter' && !event.shiftKey) {
|
||||||
formRef.current?.requestSubmit()
|
formRef.current?.requestSubmit()
|
||||||
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/core": "0.0.0-manual.527fff6c",
|
"@auth/core": "0.0.0-manual.527fff6c",
|
||||||
"@auth/nextjs": "0.0.0-manual.030e8328",
|
"@auth/nextjs": "0.0.0-manual.030e8328",
|
||||||
|
"@radix-ui/react-alert-dialog": "^1.0.4",
|
||||||
"@radix-ui/react-dialog": "^1.0.4",
|
"@radix-ui/react-dialog": "^1.0.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
||||||
"@radix-ui/react-slot": "^1.0.2",
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
|
|
|
||||||
345
pnpm-lock.yaml
generated
345
pnpm-lock.yaml
generated
|
|
@ -14,6 +14,9 @@ dependencies:
|
||||||
'@auth/nextjs':
|
'@auth/nextjs':
|
||||||
specifier: 0.0.0-manual.030e8328
|
specifier: 0.0.0-manual.030e8328
|
||||||
version: 0.0.0-manual.030e8328(next@13.4.5-canary.3)(react@18.2.0)
|
version: 0.0.0-manual.030e8328(next@13.4.5-canary.3)(react@18.2.0)
|
||||||
|
'@radix-ui/react-alert-dialog':
|
||||||
|
specifier: ^1.0.4
|
||||||
|
version: 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-dialog':
|
'@radix-ui/react-dialog':
|
||||||
specifier: ^1.0.4
|
specifier: ^1.0.4
|
||||||
version: 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
|
@ -74,6 +77,9 @@ dependencies:
|
||||||
react-markdown:
|
react-markdown:
|
||||||
specifier: ^8.0.7
|
specifier: ^8.0.7
|
||||||
version: 8.0.7(@types/react@18.2.6)(react@18.2.0)
|
version: 8.0.7(@types/react@18.2.6)(react@18.2.0)
|
||||||
|
react-scroll-to-bottom:
|
||||||
|
specifier: ^4.2.0
|
||||||
|
version: 4.2.0(react@18.2.0)
|
||||||
react-syntax-highlighter:
|
react-syntax-highlighter:
|
||||||
specifier: ^15.5.0
|
specifier: ^15.5.0
|
||||||
version: 15.5.0(react@18.2.0)
|
version: 15.5.0(react@18.2.0)
|
||||||
|
|
@ -103,6 +109,9 @@ devDependencies:
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: ^18.0.7
|
specifier: ^18.0.7
|
||||||
version: 18.2.4
|
version: 18.2.4
|
||||||
|
'@types/react-scroll-to-bottom':
|
||||||
|
specifier: ^4.2.0
|
||||||
|
version: 4.2.0
|
||||||
'@types/react-syntax-highlighter':
|
'@types/react-syntax-highlighter':
|
||||||
specifier: ^15.5.6
|
specifier: ^15.5.6
|
||||||
version: 15.5.6
|
version: 15.5.6
|
||||||
|
|
@ -179,12 +188,137 @@ packages:
|
||||||
- nodemailer
|
- nodemailer
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@babel/code-frame@7.22.5:
|
||||||
|
resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/highlight': 7.22.5
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-module-imports@7.22.5:
|
||||||
|
resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.22.5
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-string-parser@7.22.5:
|
||||||
|
resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/helper-validator-identifier@7.22.5:
|
||||||
|
resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/highlight@7.22.5:
|
||||||
|
resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-validator-identifier': 7.22.5
|
||||||
|
chalk: 2.4.2
|
||||||
|
js-tokens: 4.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@babel/runtime-corejs3@7.22.5:
|
||||||
|
resolution: {integrity: sha512-TNPDN6aBFaUox2Lu+H/Y1dKKQgr4ucz/FGyCz67RVYLsBpVpUFf1dDngzg+Od8aqbrqwyztkaZjtWCZEUOT8zA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
core-js-pure: 3.30.2
|
||||||
|
regenerator-runtime: 0.13.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@babel/runtime@7.21.5:
|
/@babel/runtime@7.21.5:
|
||||||
resolution: {integrity: sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==}
|
resolution: {integrity: sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime: 0.13.11
|
regenerator-runtime: 0.13.11
|
||||||
|
|
||||||
|
/@babel/types@7.22.5:
|
||||||
|
resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-string-parser': 7.22.5
|
||||||
|
'@babel/helper-validator-identifier': 7.22.5
|
||||||
|
to-fast-properties: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/babel-plugin@11.11.0:
|
||||||
|
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-module-imports': 7.22.5
|
||||||
|
'@babel/runtime': 7.21.5
|
||||||
|
'@emotion/hash': 0.9.1
|
||||||
|
'@emotion/memoize': 0.8.1
|
||||||
|
'@emotion/serialize': 1.1.2
|
||||||
|
babel-plugin-macros: 3.1.0
|
||||||
|
convert-source-map: 1.9.0
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
find-root: 1.1.0
|
||||||
|
source-map: 0.5.7
|
||||||
|
stylis: 4.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/cache@11.11.0:
|
||||||
|
resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==}
|
||||||
|
dependencies:
|
||||||
|
'@emotion/memoize': 0.8.1
|
||||||
|
'@emotion/sheet': 1.2.2
|
||||||
|
'@emotion/utils': 1.2.1
|
||||||
|
'@emotion/weak-memoize': 0.3.1
|
||||||
|
stylis: 4.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/css@11.1.3:
|
||||||
|
resolution: {integrity: sha512-RSQP59qtCNTf5NWD6xM08xsQdCZmVYnX/panPYvB6LQAPKQB6GL49Njf0EMbS3CyDtrlWsBcmqBtysFvfWT3rA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@babel/core': ^7.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@babel/core':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@emotion/babel-plugin': 11.11.0
|
||||||
|
'@emotion/cache': 11.11.0
|
||||||
|
'@emotion/serialize': 1.1.2
|
||||||
|
'@emotion/sheet': 1.2.2
|
||||||
|
'@emotion/utils': 1.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/hash@0.9.1:
|
||||||
|
resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/memoize@0.8.1:
|
||||||
|
resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/serialize@1.1.2:
|
||||||
|
resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==}
|
||||||
|
dependencies:
|
||||||
|
'@emotion/hash': 0.9.1
|
||||||
|
'@emotion/memoize': 0.8.1
|
||||||
|
'@emotion/unitless': 0.8.1
|
||||||
|
'@emotion/utils': 1.2.1
|
||||||
|
csstype: 3.1.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/sheet@1.2.2:
|
||||||
|
resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/unitless@0.8.1:
|
||||||
|
resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/utils@1.2.1:
|
||||||
|
resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@emotion/weak-memoize@0.3.1:
|
||||||
|
resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@esbuild/android-arm@0.15.18:
|
/@esbuild/android-arm@0.15.18:
|
||||||
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
|
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
@ -479,6 +613,32 @@ packages:
|
||||||
'@babel/runtime': 7.21.5
|
'@babel/runtime': 7.21.5
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-alert-dialog@1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-jbfBCRlKYlhbitueOAv7z74PXYeIQmWpKwm3jllsdkw7fGWNkxqP3v0nY9WmOzcPqpQuoorNtvViBgL46n5gVg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.21.5
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dialog': 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.6)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.6
|
||||||
|
'@types/react-dom': 18.2.4
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-arrow@1.0.2(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-arrow@1.0.2(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==}
|
resolution: {integrity: sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -1259,6 +1419,10 @@ packages:
|
||||||
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
|
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/parse-json@4.0.0:
|
||||||
|
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/prop-types@15.7.5:
|
/@types/prop-types@15.7.5:
|
||||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||||
|
|
||||||
|
|
@ -1267,6 +1431,12 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 18.2.6
|
'@types/react': 18.2.6
|
||||||
|
|
||||||
|
/@types/react-scroll-to-bottom@4.2.0:
|
||||||
|
resolution: {integrity: sha512-CE8GnRIFl4CRYlnHikVwJcHj4WOFBbgclbs1LNlqooVGYSBfrRvig3C3aVKDUkiXQYpp0i2p8OPUMO1JvlrZ5Q==}
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.6
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/react-syntax-highlighter@15.5.6:
|
/@types/react-syntax-highlighter@15.5.6:
|
||||||
resolution: {integrity: sha512-i7wFuLbIAFlabTeD2I1cLjEOrG/xdMa/rpx2zwzAoGHuXJDhSqp9BSfDlMHSh9JSuNfxHk9eEmMX6D55GiyjGg==}
|
resolution: {integrity: sha512-i7wFuLbIAFlabTeD2I1cLjEOrG/xdMa/rpx2zwzAoGHuXJDhSqp9BSfDlMHSh9JSuNfxHk9eEmMX6D55GiyjGg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -1410,6 +1580,13 @@ packages:
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/ansi-styles@3.2.1:
|
||||||
|
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
color-convert: 1.9.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ansi-styles@4.3.0:
|
/ansi-styles@4.3.0:
|
||||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -1539,6 +1716,15 @@ packages:
|
||||||
deep-equal: 2.2.1
|
deep-equal: 2.2.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/babel-plugin-macros@3.1.0:
|
||||||
|
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
|
||||||
|
engines: {node: '>=10', npm: '>=6'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.21.5
|
||||||
|
cosmiconfig: 7.1.0
|
||||||
|
resolve: 1.22.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/bail@2.0.2:
|
/bail@2.0.2:
|
||||||
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
|
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
@ -1623,7 +1809,6 @@ packages:
|
||||||
/callsites@3.1.0:
|
/callsites@3.1.0:
|
||||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/camelcase-css@2.0.1:
|
/camelcase-css@2.0.1:
|
||||||
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
||||||
|
|
@ -1642,6 +1827,15 @@ packages:
|
||||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/chalk@2.4.2:
|
||||||
|
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 3.2.1
|
||||||
|
escape-string-regexp: 1.0.5
|
||||||
|
supports-color: 5.5.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/chalk@4.1.2:
|
/chalk@4.1.2:
|
||||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -1697,6 +1891,10 @@ packages:
|
||||||
typescript: 5.1.3
|
typescript: 5.1.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/classnames@2.3.1:
|
||||||
|
resolution: {integrity: sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/cli-color@2.0.3:
|
/cli-color@2.0.3:
|
||||||
resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==}
|
resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==}
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
|
|
@ -1717,6 +1915,12 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/color-convert@1.9.3:
|
||||||
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
|
dependencies:
|
||||||
|
color-name: 1.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/color-convert@2.0.1:
|
/color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
|
|
@ -1724,6 +1928,10 @@ packages:
|
||||||
color-name: 1.1.4
|
color-name: 1.1.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/color-name@1.1.3:
|
||||||
|
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/color-name@1.1.4:
|
/color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -1755,11 +1963,37 @@ packages:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/convert-source-map@1.9.0:
|
||||||
|
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/cookie@0.5.0:
|
/cookie@0.5.0:
|
||||||
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/core-js-pure@3.30.2:
|
||||||
|
resolution: {integrity: sha512-p/npFUJXXBkCCTIlEGBdghofn00jWG6ZOtdoIXSJmAu2QBvN0IqpZXWweOytcwE6cfx8ZvVUy1vw8zxhe4Y2vg==}
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/core-js@3.18.3:
|
||||||
|
resolution: {integrity: sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw==}
|
||||||
|
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/cosmiconfig@7.1.0:
|
||||||
|
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
'@types/parse-json': 4.0.0
|
||||||
|
import-fresh: 3.3.0
|
||||||
|
parse-json: 5.2.0
|
||||||
|
path-type: 4.0.0
|
||||||
|
yaml: 1.10.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/cross-spawn@7.0.3:
|
/cross-spawn@7.0.3:
|
||||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
@ -1970,6 +2204,12 @@ packages:
|
||||||
tapable: 2.2.1
|
tapable: 2.2.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/error-ex@1.3.2:
|
||||||
|
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||||
|
dependencies:
|
||||||
|
is-arrayish: 0.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/es-abstract@1.21.2:
|
/es-abstract@1.21.2:
|
||||||
resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==}
|
resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -2308,10 +2548,14 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/escape-string-regexp@1.0.5:
|
||||||
|
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
|
||||||
|
engines: {node: '>=0.8.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/escape-string-regexp@4.0.0:
|
/escape-string-regexp@4.0.0:
|
||||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/escape-string-regexp@5.0.0:
|
/escape-string-regexp@5.0.0:
|
||||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||||
|
|
@ -2703,6 +2947,10 @@ packages:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/find-root@1.1.0:
|
||||||
|
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/find-up@5.0.0:
|
/find-up@5.0.0:
|
||||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -2772,7 +3020,6 @@ packages:
|
||||||
|
|
||||||
/function-bind@1.1.1:
|
/function-bind@1.1.1:
|
||||||
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
|
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/function.prototype.name@1.1.5:
|
/function.prototype.name@1.1.5:
|
||||||
resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
|
resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
|
||||||
|
|
@ -2946,6 +3193,11 @@ packages:
|
||||||
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
|
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/has-flag@3.0.0:
|
||||||
|
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/has-flag@4.0.0:
|
/has-flag@4.0.0:
|
||||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -2979,7 +3231,6 @@ packages:
|
||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.1
|
function-bind: 1.1.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/hast-util-parse-selector@2.2.5:
|
/hast-util-parse-selector@2.2.5:
|
||||||
resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
|
resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
|
||||||
|
|
@ -3028,7 +3279,6 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
parent-module: 1.0.1
|
parent-module: 1.0.1
|
||||||
resolve-from: 4.0.0
|
resolve-from: 4.0.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/imurmurhash@0.1.4:
|
/imurmurhash@0.1.4:
|
||||||
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
||||||
|
|
@ -3092,6 +3342,10 @@ packages:
|
||||||
is-typed-array: 1.1.10
|
is-typed-array: 1.1.10
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/is-arrayish@0.2.1:
|
||||||
|
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-bigint@1.0.4:
|
/is-bigint@1.0.4:
|
||||||
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
|
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -3127,7 +3381,6 @@ packages:
|
||||||
resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==}
|
resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
has: 1.0.3
|
has: 1.0.3
|
||||||
dev: true
|
|
||||||
|
|
||||||
/is-date-object@1.0.5:
|
/is-date-object@1.0.5:
|
||||||
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
|
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
|
||||||
|
|
@ -3337,6 +3590,10 @@ packages:
|
||||||
dreamopt: 0.8.0
|
dreamopt: 0.8.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/json-parse-even-better-errors@2.3.1:
|
||||||
|
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/json-schema-traverse@0.4.1:
|
/json-schema-traverse@0.4.1:
|
||||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -3397,7 +3654,6 @@ packages:
|
||||||
|
|
||||||
/lines-and-columns@1.2.4:
|
/lines-and-columns@1.2.4:
|
||||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/locate-path@6.0.0:
|
/locate-path@6.0.0:
|
||||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
|
|
@ -3464,6 +3720,10 @@ packages:
|
||||||
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
|
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/math-random@2.0.1:
|
||||||
|
resolution: {integrity: sha512-oIEbWiVDxDpl5tIF4S6zYS9JExhh3bun3uLb3YAinHPTlRtW4g1S66LtJrJ4Npq8dgIa8CLK5iPVah5n4n0s2w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/mdast-util-definitions@5.1.2:
|
/mdast-util-definitions@5.1.2:
|
||||||
resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==}
|
resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -4200,7 +4460,6 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
callsites: 3.1.0
|
callsites: 3.1.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/parse-entities@2.0.0:
|
/parse-entities@2.0.0:
|
||||||
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
|
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
|
||||||
|
|
@ -4213,6 +4472,16 @@ packages:
|
||||||
is-hexadecimal: 1.0.4
|
is-hexadecimal: 1.0.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/parse-json@5.2.0:
|
||||||
|
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.22.5
|
||||||
|
error-ex: 1.3.2
|
||||||
|
json-parse-even-better-errors: 2.3.1
|
||||||
|
lines-and-columns: 1.2.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/path-exists@4.0.0:
|
/path-exists@4.0.0:
|
||||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -4235,12 +4504,10 @@ packages:
|
||||||
|
|
||||||
/path-parse@1.0.7:
|
/path-parse@1.0.7:
|
||||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/path-type@4.0.0:
|
/path-type@4.0.0:
|
||||||
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/picocolors@1.0.0:
|
/picocolors@1.0.0:
|
||||||
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
||||||
|
|
@ -4385,6 +4652,14 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/prop-types@15.7.2:
|
||||||
|
resolution: {integrity: sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
react-is: 16.13.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/prop-types@15.8.1:
|
/prop-types@15.8.1:
|
||||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -4504,6 +4779,23 @@ packages:
|
||||||
use-sidecar: 1.1.2(@types/react@18.2.6)(react@18.2.0)
|
use-sidecar: 1.1.2(@types/react@18.2.6)(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-scroll-to-bottom@4.2.0(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-1WweuumQc5JLzeAR81ykRdK/cEv9NlCPEm4vSwOGN1qS2qlpGVTyMgdI8Y7ZmaqRmzYBGV5/xPuJQtekYzQFGg==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>= 16.8.6'
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime-corejs3': 7.22.5
|
||||||
|
'@emotion/css': 11.1.3
|
||||||
|
classnames: 2.3.1
|
||||||
|
core-js: 3.18.3
|
||||||
|
math-random: 2.0.1
|
||||||
|
prop-types: 15.7.2
|
||||||
|
react: 18.2.0
|
||||||
|
simple-update-in: 2.2.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@babel/core'
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-style-singleton@2.2.1(@types/react@18.2.6)(react@18.2.0):
|
/react-style-singleton@2.2.1(@types/react@18.2.6)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -4630,7 +4922,6 @@ packages:
|
||||||
/resolve-from@4.0.0:
|
/resolve-from@4.0.0:
|
||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/resolve@1.22.2:
|
/resolve@1.22.2:
|
||||||
resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
|
resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
|
||||||
|
|
@ -4639,7 +4930,6 @@ packages:
|
||||||
is-core-module: 2.12.0
|
is-core-module: 2.12.0
|
||||||
path-parse: 1.0.7
|
path-parse: 1.0.7
|
||||||
supports-preserve-symlinks-flag: 1.0.0
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/resolve@2.0.0-next.4:
|
/resolve@2.0.0-next.4:
|
||||||
resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==}
|
resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==}
|
||||||
|
|
@ -4733,6 +5023,10 @@ packages:
|
||||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/simple-update-in@2.2.0:
|
||||||
|
resolution: {integrity: sha512-FrW41lLiOs82jKxwq39UrE1HDAHOvirKWk4Nv8tqnFFFknVbTxcHZzDS4vt02qqdU/5+KNsQHWzhKHznDBmrww==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/sisteransi@1.0.5:
|
/sisteransi@1.0.5:
|
||||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -4751,6 +5045,11 @@ packages:
|
||||||
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
|
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
/source-map@0.5.7:
|
||||||
|
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/space-separated-tokens@1.1.5:
|
/space-separated-tokens@1.1.5:
|
||||||
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
|
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
@ -4859,6 +5158,10 @@ packages:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/stylis@4.2.0:
|
||||||
|
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/sucrase@3.32.0:
|
/sucrase@3.32.0:
|
||||||
resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==}
|
resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -4873,6 +5176,13 @@ packages:
|
||||||
ts-interface-checker: 0.1.13
|
ts-interface-checker: 0.1.13
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/supports-color@5.5.0:
|
||||||
|
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
has-flag: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/supports-color@7.2.0:
|
/supports-color@7.2.0:
|
||||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -4883,7 +5193,6 @@ packages:
|
||||||
/supports-preserve-symlinks-flag@1.0.0:
|
/supports-preserve-symlinks-flag@1.0.0:
|
||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/swr@2.1.5(react@18.2.0):
|
/swr@2.1.5(react@18.2.0):
|
||||||
resolution: {integrity: sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw==}
|
resolution: {integrity: sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw==}
|
||||||
|
|
@ -4984,6 +5293,11 @@ packages:
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/to-fast-properties@2.0.0:
|
||||||
|
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/to-regex-range@5.0.1:
|
/to-regex-range@5.0.1:
|
||||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
engines: {node: '>=8.0'}
|
engines: {node: '>=8.0'}
|
||||||
|
|
@ -5327,6 +5641,11 @@ packages:
|
||||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/yaml@1.10.2:
|
||||||
|
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/yaml@2.2.2:
|
/yaml@2.2.2:
|
||||||
resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==}
|
resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue