diff --git a/.env.example b/.env.example index 3c45061..643a5cb 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ -## Get your OpenAI API Key +## You must first activate a Billing Account here: https://platform.openai.com/account/billing/overview +## Then get your OpenAI API Key here: https://platform.openai.com/account/api-keys OPENAI_API_KEY=XXXXXXXX ## Generate a random secret: https://generate-secret.vercel.app/32 diff --git a/README.md b/README.md index cb32307..1105e31 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ - [Next.js](https://nextjs.org) App Router - React Server Components (RSCs), Suspense, and Server Actions - [Vercel AI SDK](https://sdk.vercel.ai/docs) for streaming chat UI -- Support for OpenAI (default), Anthropic, HuggingFace, or custom AI chat models and/or LangChain +- Support for OpenAI (default), Anthropic, Hugging Face, or custom AI chat models and/or LangChain - Edge runtime-ready - [shadcn/ui](https://ui.shadcn.com) - Styling with [Tailwind CSS](https://tailwindcss.com) @@ -32,7 +32,7 @@ ## Model Providers -This template ships with OpenAI `gpt-3.5-turbo` as the default. However, thanks to the [Vercel AI SDK](https://sdk.vercel.ai/docs), you can switch LLM providers to [Anthropic](https://anthropic.com), [HuggingFace](https://huggingface.co), or using [LangChain](https://js.langchain.com) with just a few lines of code. +This template ships with OpenAI `gpt-3.5-turbo` as the default. However, thanks to the [Vercel AI SDK](https://sdk.vercel.ai/docs), you can switch LLM providers to [Anthropic](https://anthropic.com), [Hugging Face](https://huggingface.co), or using [LangChain](https://js.langchain.com) with just a few lines of code. ## Deploy Your Own diff --git a/app/actions.ts b/app/actions.ts index 90c6973..2c8a5dd 100644 --- a/app/actions.ts +++ b/app/actions.ts @@ -74,7 +74,9 @@ export async function clearChats() { } const chats: string[] = await kv.zrange(`user:chat:${session.user.id}`, 0, -1) - + if (!chats.length) { + return redirect('/') + } const pipeline = kv.pipeline() for (const chat of chats) { diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index 883210b..35e9719 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -1,2 +1 @@ export { GET, POST } from '@/auth' -export const runtime = 'edge' diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index 4f63d1e..b39b26c 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -7,22 +7,26 @@ import { nanoid } from '@/lib/utils' export const runtime = 'edge' +const configuration = new Configuration({ + apiKey: process.env.OPENAI_API_KEY +}) + +const openai = new OpenAIApi(configuration) + export async function POST(req: Request) { const json = await req.json() const { messages, previewToken } = json const session = await auth() - if (process.env.VERCEL_ENV !== 'preview') { + if (process.env.VERCEL_ENV === 'preview') { if (session == null) { return new Response('Unauthorized', { status: 401 }) } } - const configuration = new Configuration({ - apiKey: previewToken || process.env.OPENAI_API_KEY - }) - - const openai = new OpenAIApi(configuration) + if (previewToken) { + configuration.apiKey = previewToken + } const res = await openai.createChatCompletion({ model: 'gpt-3.5-turbo', @@ -34,7 +38,7 @@ export async function POST(req: Request) { const stream = OpenAIStream(res, { async onCompletion(completion) { const title = json.messages[0].content.substring(0, 100) - const userId = session?.user.id + const userId = session?.user?.id if (userId) { const id = json.id ?? nanoid() const createdAt = Date.now() diff --git a/app/chat/[id]/page.tsx b/app/chat/[id]/page.tsx index d7ad6d6..25d6c30 100644 --- a/app/chat/[id]/page.tsx +++ b/app/chat/[id]/page.tsx @@ -25,7 +25,7 @@ export async function generateMetadata({ const chat = await getChat(params.id, session.user.id) return { - title: chat?.title.slice(0, 50) ?? 'Chat' + title: chat?.title.toString().slice(0, 50) ?? 'Chat' } } diff --git a/app/share/[id]/page.tsx b/app/share/[id]/page.tsx index 3ec3f3e..4ee6620 100644 --- a/app/share/[id]/page.tsx +++ b/app/share/[id]/page.tsx @@ -35,9 +35,9 @@ export default async function SharePage({ params }: SharePageProps) { return ( <>
-
-
-
+
+
+

{chat.title}

{formatDate(chat.createdAt)} ยท {chat.messages.length} messages diff --git a/auth.ts b/auth.ts index e422771..5c7c1dd 100644 --- a/auth.ts +++ b/auth.ts @@ -1,25 +1,18 @@ import NextAuth from 'next-auth' import GitHub from 'next-auth/providers/github' -declare module 'next-auth' { - interface Session { - user: { - /** The user's id. */ - id: string - } - } -} - export const { handlers: { GET, POST }, auth, CSRF_experimental + // @ts-ignore } = NextAuth({ - // @ts-expect-error + // @ts-ignore providers: [GitHub], callbacks: { + // @ts-ignore jwt: async ({ token, profile }) => { - if (profile) { + if (profile?.id) { token.id = profile.id token.image = profile.picture } diff --git a/components/chat-message-actions.tsx b/components/chat-message-actions.tsx index 2905f8a..d4e4b40 100644 --- a/components/chat-message-actions.tsx +++ b/components/chat-message-actions.tsx @@ -18,6 +18,11 @@ export function ChatMessageActions({ }: ChatMessageActionsProps) { const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 }) + const onCopy = () => { + if (isCopied) return + copyToClipboard(message.content) + } + return (
- diff --git a/components/header.tsx b/components/header.tsx index b08bd46..3ff0dd6 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -4,7 +4,7 @@ import Link from 'next/link' import { cn } from '@/lib/utils' import { auth } from '@/auth' import { clearChats } from '@/app/actions' -import { buttonVariants } from '@/components/ui/button' +import { Button, buttonVariants } from '@/components/ui/button' import { Sidebar } from '@/components/sidebar' import { SidebarList } from '@/components/sidebar-list' import { @@ -22,7 +22,7 @@ import { LoginButton } from '@/components/login-button' export async function Header() { const session = await auth() return ( -
+
{session?.user ? ( @@ -37,21 +37,18 @@ export async function Header() { ) : ( - - + + )}
- + {session?.user ? ( ) : ( - + )}
@@ -63,7 +60,7 @@ export async function Header() { className={cn(buttonVariants({ variant: 'outline' }))} > - GitHub + GitHub { setIsLoading(true) + // next-auth signIn() function doesn't work yet at Edge Runtime due to usage of BroadcastChannel signIn('github', { callbackUrl: `/` }) }} disabled={isLoading} diff --git a/components/prompt-form.tsx b/components/prompt-form.tsx index 75258c8..d053842 100644 --- a/components/prompt-form.tsx +++ b/components/prompt-form.tsx @@ -15,7 +15,7 @@ import { IconArrowElbow, IconPlus } from '@/components/ui/icons' export interface PromptProps extends Pick { - onSubmit: (value: string) => void + onSubmit: (value: string) => Promise isLoading: boolean } @@ -38,7 +38,7 @@ export function PromptForm({
{ e.preventDefault() - if (input === '') { + if (!input?.trim()) { return } setInput('') @@ -46,7 +46,7 @@ export function PromptForm({ }} ref={formRef} > -
+
= memo(({ language, value }) => { URL.revokeObjectURL(url) } + const onCopy = () => { + if (isCopied) return + copyToClipboard(value) + } + return (
@@ -102,7 +107,7 @@ const CodeBlock: FC = memo(({ language, value }) => { variant="ghost" size="icon" className="text-xs hover:bg-zinc-800 focus-visible:ring-1 focus-visible:ring-slate-700 focus-visible:ring-offset-0" - onClick={() => copyToClipboard(value)} + onClick={onCopy} > {isCopied ? : } Copy code diff --git a/lib/hooks/use-copy-to-clipboard.tsx b/lib/hooks/use-copy-to-clipboard.tsx index 9f9b8e3..62f7156 100644 --- a/lib/hooks/use-copy-to-clipboard.tsx +++ b/lib/hooks/use-copy-to-clipboard.tsx @@ -12,11 +12,11 @@ export function useCopyToClipboard({ const [isCopied, setIsCopied] = React.useState(false) const copyToClipboard = (value: string) => { - if ( - typeof window === 'undefined' || - !navigator.clipboard || - !navigator.clipboard.writeText - ) { + if (typeof window === 'undefined' || !navigator.clipboard?.writeText) { + return + } + + if (!value) { return } diff --git a/lib/hooks/use-enter-submit.tsx b/lib/hooks/use-enter-submit.tsx index 5091ddf..d66b2d3 100644 --- a/lib/hooks/use-enter-submit.tsx +++ b/lib/hooks/use-enter-submit.tsx @@ -9,7 +9,11 @@ export function useEnterSubmit(): { const handleKeyDown = ( event: React.KeyboardEvent ): void => { - if (event.key === 'Enter' && !event.shiftKey) { + if ( + event.key === 'Enter' && + !event.shiftKey && + !event.nativeEvent.isComposing + ) { formRef.current?.requestSubmit() event.preventDefault() } diff --git a/next-auth.d.ts b/next-auth.d.ts new file mode 100644 index 0000000..918e14d --- /dev/null +++ b/next-auth.d.ts @@ -0,0 +1,13 @@ +import NextAuth, { DefaultSession } from 'next-auth' + +declare module 'next-auth' { + /** + * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context + */ + interface Session { + user: { + /** The user's postal address. */ + id: string + } & DefaultSession['user'] + } +} diff --git a/package.json b/package.json index 32fda5a..353f59f 100644 --- a/package.json +++ b/package.json @@ -26,14 +26,14 @@ "@vercel/analytics": "^1.0.0", "@vercel/kv": "^0.2.1", "@vercel/og": "^0.5.7", - "ai": "^2.1.2", + "ai": "^2.1.6", "body-scroll-lock": "4.0.0-beta.0", "class-variance-authority": "^0.4.0", "clsx": "^1.2.1", "focus-trap-react": "^10.1.1", "nanoid": "^4.0.2", "next": "13.4.7-canary.1", - "next-auth": "0.0.0-manual.f414f2f5", + "next-auth": "0.0.0-manual.4cd21ea5", "next-themes": "^0.2.1", "openai-edge": "^0.5.1", "react": "^18.2.0", @@ -67,5 +67,10 @@ "tailwindcss-animate": "^1.0.5", "typescript": "^5.1.3" }, + "pnpm": { + "overrides": { + "@auth/nextjs": "0.0.0-manual.223c6467" + } + }, "packageManager": "pnpm@8.6.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 065cfca..c044890 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,9 +1,12 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: - autoInstallPeers: false + autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + '@auth/nextjs': 0.0.0-manual.223c6467 + dependencies: '@radix-ui/react-alert-dialog': specifier: ^1.0.4 @@ -42,8 +45,8 @@ dependencies: specifier: ^0.5.7 version: 0.5.7 ai: - specifier: ^2.1.2 - version: 2.1.2(react@18.2.0) + specifier: ^2.1.6 + version: 2.1.6(react@18.2.0)(svelte@3.59.2)(vue@3.3.4) body-scroll-lock: specifier: 4.0.0-beta.0 version: 4.0.0-beta.0 @@ -55,7 +58,7 @@ dependencies: version: 1.2.1 focus-trap-react: specifier: ^10.1.1 - version: 10.1.1(react-dom@18.2.0)(react@18.2.0) + version: 10.1.1(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0) nanoid: specifier: ^4.0.2 version: 4.0.2 @@ -63,8 +66,8 @@ dependencies: specifier: 13.4.7-canary.1 version: 13.4.7-canary.1(react-dom@18.2.0)(react@18.2.0) next-auth: - specifier: 0.0.0-manual.f414f2f5 - version: 0.0.0-manual.f414f2f5(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0) + specifier: 0.0.0-manual.4cd21ea5 + version: 0.0.0-manual.4cd21ea5(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0) next-themes: specifier: ^0.2.1 version: 0.2.1(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0) @@ -79,7 +82,7 @@ dependencies: version: 18.2.0(react@18.2.0) react-hot-toast: specifier: ^2.4.1 - version: 2.4.1(react-dom@18.2.0)(react@18.2.0) + version: 2.4.1(csstype@3.1.2)(react-dom@18.2.0)(react@18.2.0) react-intersection-observer: specifier: ^9.4.4 version: 9.4.4(react@18.2.0) @@ -184,7 +187,7 @@ packages: /@auth/nextjs@0.0.0-manual.179c08d4(next@13.4.7-canary.1)(react@18.2.0): resolution: {integrity: sha512-HVuDgb6xlYLV5mHTGc0Pycg8BlwtcvjvS+54QXEbOBpA5tulzKxAH8QlCoKj5R9XHW9hP9DiCnvXyVV9x2N+jA==} peerDependencies: - next: ^13.4.6 + next: ^13.4.2 react: ^18.2.0 dependencies: '@auth/core': 0.0.0-manual.8fcd46b0 @@ -194,12 +197,39 @@ packages: - nodemailer 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/parser@7.22.5: + resolution: {integrity: sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.22.5 + dev: false + /@babel/runtime@7.21.5: resolution: {integrity: sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==} engines: {node: '>=6.9.0'} dependencies: 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 + /@esbuild/android-arm@0.15.18: resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} engines: {node: '>=12'} @@ -321,7 +351,6 @@ packages: /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true /@jridgewell/trace-mapping@0.3.18: resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} @@ -1358,6 +1387,89 @@ packages: yoga-wasm-web: 0.3.3 dev: false + /@vue/compiler-core@3.3.4: + resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} + dependencies: + '@babel/parser': 7.22.5 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + dev: false + + /@vue/compiler-dom@3.3.4: + resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==} + dependencies: + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + dev: false + + /@vue/compiler-sfc@3.3.4: + resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} + dependencies: + '@babel/parser': 7.22.5 + '@vue/compiler-core': 3.3.4 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-ssr': 3.3.4 + '@vue/reactivity-transform': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.0 + postcss: 8.4.23 + source-map-js: 1.0.2 + dev: false + + /@vue/compiler-ssr@3.3.4: + resolution: {integrity: sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/shared': 3.3.4 + dev: false + + /@vue/reactivity-transform@3.3.4: + resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} + dependencies: + '@babel/parser': 7.22.5 + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.0 + dev: false + + /@vue/reactivity@3.3.4: + resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} + dependencies: + '@vue/shared': 3.3.4 + dev: false + + /@vue/runtime-core@3.3.4: + resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==} + dependencies: + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 + dev: false + + /@vue/runtime-dom@3.3.4: + resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==} + dependencies: + '@vue/runtime-core': 3.3.4 + '@vue/shared': 3.3.4 + csstype: 3.1.2 + dev: false + + /@vue/server-renderer@3.3.4(vue@3.3.4): + resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==} + peerDependencies: + vue: 3.3.4 + dependencies: + '@vue/compiler-ssr': 3.3.4 + '@vue/shared': 3.3.4 + vue: 3.3.4 + dev: false + + /@vue/shared@3.3.4: + resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} + dev: false + /acorn-jsx@5.3.2(acorn@8.8.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1372,8 +1484,8 @@ packages: hasBin: true dev: true - /ai@2.1.2(react@18.2.0): - resolution: {integrity: sha512-WhyGH95Pv/gpgVMQT5eCyKXJh7irozr+bmpJ94somfRYBcAN2U270ii/OOHzGLrPM3liTbBilGQL2Ds7/5sz9Q==} + /ai@2.1.6(react@18.2.0)(svelte@3.59.2)(vue@3.3.4): + resolution: {integrity: sha512-YFCy7KEUDvuNGNuD8Bz7BynXB/eW2jJRAxAIM8Hb5/gpppZJs6/nTSdpocROxoGESJchtkFgYdygieG/wciEEQ==} engines: {node: '>=14.6'} peerDependencies: react: ^18.0.0 @@ -1390,9 +1502,11 @@ packages: eventsource-parser: 1.0.0 nanoid: 3.3.6 react: 18.2.0 - sswr: 1.10.0 + sswr: 1.10.0(svelte@3.59.2) + svelte: 3.59.2 swr: 2.1.5(react@18.2.0) - swrv: 1.0.3 + swrv: 1.0.3(vue@3.3.4) + vue: 3.3.4 dev: false /ajv@6.12.6: @@ -2644,6 +2758,10 @@ packages: engines: {node: '>=4.0'} dev: true + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: false + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -2774,7 +2892,7 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /focus-trap-react@10.1.1(react-dom@18.2.0)(react@18.2.0): + /focus-trap-react@10.1.1(prop-types@15.8.1)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-OtLeSIQPKFzMzbLHkGtfZYwGLMhTRHd3CDhfyd0DDx8tvXzlgpseClDiuiKoiIHZtdjsbXTfTmUuuLKaxrwSyQ==} peerDependencies: prop-types: ^15.8.1 @@ -2782,6 +2900,7 @@ packages: react-dom: '>=16.3.0' dependencies: focus-trap: 7.4.0 + prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) tabbable: 6.1.2 @@ -2967,10 +3086,12 @@ packages: slash: 4.0.0 dev: true - /goober@2.1.13: + /goober@2.1.13(csstype@3.1.2): resolution: {integrity: sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==} peerDependencies: csstype: ^3.0.10 + dependencies: + csstype: 3.1.2 dev: false /gopd@1.0.1: @@ -3515,6 +3636,13 @@ packages: es5-ext: 0.10.62 dev: true + /magic-string@0.30.0: + resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + /markdown-table@3.0.3: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} dev: false @@ -4017,8 +4145,8 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /next-auth@0.0.0-manual.f414f2f5(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-qJmSX4QUV8V2JOQavl0fQyJymt0fte7eDQsMGTpx8ZRU2Qvx8uh+xrvXlHt3dXf603OB3QkWaj77ipIEt62Hfg==} + /next-auth@0.0.0-manual.4cd21ea5(next@13.4.7-canary.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-qzsrs2xeopmIYUz1C+FbudBIoNI7xSTd1xWeECr/Qa4NFzbCt8Dr9tb2Yocpa5jnRpk0xN96HwsJqimOYVjtRg==} peerDependencies: next: ^13.4.5 nodemailer: ^6.6.5 @@ -4429,7 +4557,6 @@ packages: nanoid: 3.3.6 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true /preact-render-to-string@5.2.3(preact@10.11.3): resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} @@ -4505,14 +4632,14 @@ packages: scheduler: 0.23.0 dev: false - /react-hot-toast@2.4.1(react-dom@18.2.0)(react@18.2.0): + /react-hot-toast@2.4.1(csstype@3.1.2)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==} engines: {node: '>=10'} peerDependencies: react: '>=16' react-dom: '>=16' dependencies: - goober: 2.1.13 + goober: 2.1.13(csstype@3.1.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: @@ -4867,11 +4994,12 @@ packages: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} dev: false - /sswr@1.10.0: + /sswr@1.10.0(svelte@3.59.2): resolution: {integrity: sha512-nLWAJSQy3h8t7rrbTXanRyVHuQPj4PwKIVGe4IMlxJFdhyaxnN/JGACnvQKGDeWiTGYIZIx/jRuUsPEF0867Pg==} peerDependencies: svelte: ^3.29.0 dependencies: + svelte: 3.59.2 swrev: 3.0.0 dev: false @@ -5005,6 +5133,11 @@ packages: engines: {node: '>= 0.4'} dev: true + /svelte@3.59.2: + resolution: {integrity: sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==} + engines: {node: '>= 8'} + dev: false + /swr@2.1.5(react@18.2.0): resolution: {integrity: sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw==} peerDependencies: @@ -5018,10 +5151,12 @@ packages: resolution: {integrity: sha512-QJuZiptdOmbDY45pECBRVEgnoBlOKjeT2MWVz04wKHpWX15hM3P7EjcIbHDg5yLoPCMQ7to3349MEE+l9QF5HA==} dev: false - /swrv@1.0.3: + /swrv@1.0.3(vue@3.3.4): resolution: {integrity: sha512-sl+eLEE+aPPjhP1E8gQ75q3RPRyw5Gd/kROnrTFo3+LkCeLskv7F+uAl5W97wgJkzitobL6FLsRPVm0DgIgN8A==} peerDependencies: vue: '>=3.2.26 < 4' + dependencies: + vue: 3.3.4 dev: false /synckit@0.8.5: @@ -5118,6 +5253,11 @@ packages: engines: {node: '>=12'} 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: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -5392,6 +5532,16 @@ packages: vfile-message: 3.1.4 dev: false + /vue@3.3.4: + resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-sfc': 3.3.4 + '@vue/runtime-dom': 3.3.4 + '@vue/server-renderer': 3.3.4(vue@3.3.4) + '@vue/shared': 3.3.4 + dev: false + /watchpack@2.4.0: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} engines: {node: '>=10.13.0'} diff --git a/tailwind.config.js b/tailwind.config.js index 93289bd..e16dd0f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -56,9 +56,6 @@ module.exports = { md: `calc(var(--radius) - 2px)`, sm: 'calc(var(--radius) - 4px)' }, - fontFamily: { - sans: ['var(--font-sans)', ...fontFamily.sans] - }, keyframes: { 'accordion-down': { from: { height: 0 }, diff --git a/tsconfig.json b/tsconfig.json index 9be1cf1..9f91b9b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,6 +26,7 @@ }, "include": [ "next-env.d.ts", + "next-auth.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"