diff --git a/__tests__/__snapshots__/index.test.tsx.snap b/__tests__/__snapshots__/index.test.tsx.snap index e76a1fd..41d1f31 100644 --- a/__tests__/__snapshots__/index.test.tsx.snap +++ b/__tests__/__snapshots__/index.test.tsx.snap @@ -14,7 +14,7 @@ exports[`Home renders homepage unchanged 1`] = ` No 1 task management app </div> <h1 - class="mb-6 text-center text-neutral-800 ~/md:~text-3xl/6xl" + class="mb-6 text-center text-neutral-800 ~/md:~text-3xl/6xl dark:text-neutral-100" > Tasko helps teams move </h1> diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts new file mode 100644 index 0000000..11bc331 --- /dev/null +++ b/__tests__/utils.test.ts @@ -0,0 +1,40 @@ +import { cn, absoluteUrl } from '@/lib/utils'; + +describe('absoluteUrl', () => { + const originalEnv = process.env; + + beforeEach(() => { + process.env = { + ...originalEnv, + NEXT_PUBLIC_APP_URL: 'https://example.com', + }; + }); + + afterEach(() => { + process.env = originalEnv; + }); + + it('should return the correct absolute URL', () => { + const pathname = '/test'; + expect(absoluteUrl(pathname)).toBe('https://example.com/test'); + }); + + it('should handle empty pathname', () => { + const pathname = ''; + expect(absoluteUrl(pathname)).toBe('https://example.com'); + }); +}); + +describe('cn', () => { + it('should merge multiple class names', () => { + expect(cn('class1', 'class2')).toBe('class1 class2'); + }); + + it('should handle conditional class names', () => { + const isActive = true; + expect(cn('base', isActive && 'active')).toBe('base active'); + + const isDisabled = false; + expect(cn('base', isDisabled && 'disabled')).toBe('base'); + }); +}); diff --git a/app/(main)/_components/footer.tsx b/app/(main)/_components/footer.tsx index bf6da7a..bea046b 100644 --- a/app/(main)/_components/footer.tsx +++ b/app/(main)/_components/footer.tsx @@ -3,7 +3,7 @@ import { Button } from '@/components/ui/button'; export const Footer = () => { return ( - <div className='fixed bottom-0 w-full border-t bg-slate-100 p-4'> + <div className='fixed bottom-0 w-full border-t bg-slate-100 p-4 dark:bg-slate-800'> <div className='mx-auto flex w-full items-center justify-between md:max-w-screen-2xl'> <Logo /> <div className='flex w-full items-center justify-between space-x-4 md:block md:w-auto'> diff --git a/app/(main)/_components/navbar.tsx b/app/(main)/_components/navbar.tsx index b8374e0..335e7a1 100644 --- a/app/(main)/_components/navbar.tsx +++ b/app/(main)/_components/navbar.tsx @@ -3,6 +3,7 @@ import { auth } from '@clerk/nextjs/server'; import { Logo } from '@/components/logo'; import { Button } from '@/components/ui/button'; +import { ModeToggle } from '@/components/ui/mode-toggle'; export const Navbar = async () => { const { userId } = await auth(); @@ -10,7 +11,7 @@ export const Navbar = async () => { let isSignedIn = !!userId; return ( - <div className='fixed top-0 flex h-14 w-full items-center border-b bg-white px-4 shadow-sm'> + <nav className='fixed top-0 z-50 flex h-14 w-full items-center border-b bg-white px-4 shadow-sm dark:bg-black'> <div className='mx-auto flex w-full items-center justify-between md:max-w-screen-2xl'> <Logo /> <div className='ml-0 flex w-full flex-auto items-center space-x-1 md:ml-6 md:block md:w-auto md:space-x-4'> @@ -30,16 +31,18 @@ export const Navbar = async () => { <Button size='sm' asChild> <Link href='/sign-up'>Get Tasko for Free</Link> </Button> + <ModeToggle /> </div> ) : ( - <div> + <div className='flex w-full justify-between space-x-4 md:block md:w-auto'> <Button size='sm' variant='outline' asChild> <Link href='/select-org'>Dashboard</Link> </Button> + <ModeToggle /> </div> )} </div> </div> - </div> + </nav> ); }; diff --git a/app/(main)/blog/page.tsx b/app/(main)/blog/page.tsx index 4e956f5..6951af9 100644 --- a/app/(main)/blog/page.tsx +++ b/app/(main)/blog/page.tsx @@ -5,7 +5,9 @@ import Link from 'next/link'; const BlogPage = () => { return ( <div className='ml-4 mr-4 flex flex-col items-center space-y-10'> - <h1 className='text-4xl font-semibold text-neutral-700'>Blog</h1> + <h1 className='text-4xl font-semibold text-neutral-800 dark:text-neutral-100'> + Blog + </h1> <div className='grid grid-cols-2 gap-20 md:grid-cols-3 lg:grid-cols-4'> {allBlogPosts.map((post) => ( <div className='space-y-4 text-center' key={post._meta.path}> @@ -17,10 +19,12 @@ const BlogPage = () => { alt='post cover image' className='aspect-video w-full rounded-md object-cover' /> - <h2 className='text-lg font-semibold text-neutral-700'> + <h2 className='text-lg font-semibold text-neutral-800 dark:text-neutral-100'> {post.title} </h2> - <p className='text-sm text-neutral-500'>{post.summary}</p> + <p className='text-sm text-neutral-700 dark:text-neutral-200'> + {post.summary} + </p> </Link> </div> ))} diff --git a/app/(main)/layout.tsx b/app/(main)/layout.tsx index 9cdd5d6..2a2dc51 100644 --- a/app/(main)/layout.tsx +++ b/app/(main)/layout.tsx @@ -3,9 +3,11 @@ import { Navbar } from './_components/navbar'; const MarketingLayout = ({ children }: { children: React.ReactNode }) => { return ( - <div className='h-full bg-slate-100'> + <div className='h-full bg-slate-100 dark:bg-slate-800'> <Navbar /> - <main className='bg-slate-100 pb-20 pt-20'>{children}</main> + <main className='bg-slate-100 pb-20 pt-20 dark:bg-slate-800'> + {children} + </main> <Footer /> </div> ); diff --git a/app/(main)/page.tsx b/app/(main)/page.tsx index ab5657e..d525869 100644 --- a/app/(main)/page.tsx +++ b/app/(main)/page.tsx @@ -26,7 +26,7 @@ const MarketingPage = () => { <Medal className='mr-2 h-6 w-6' /> No 1 task management app </div> - <h1 className='mb-6 text-center text-neutral-800 ~/md:~text-3xl/6xl'> + <h1 className='mb-6 text-center text-neutral-800 ~/md:~text-3xl/6xl dark:text-neutral-100'> Tasko helps teams move </h1> <div className='w-fit rounded-md bg-gradient-to-r from-fuchsia-600 to-pink-600 p-2 px-4 pb-4 text-white ~/md:~text-3xl/6xl'> diff --git a/app/(platform)/(dashboard)/_components/Navbar.tsx b/app/(platform)/(dashboard)/_components/Navbar.tsx index d05701a..60a131c 100644 --- a/app/(platform)/(dashboard)/_components/Navbar.tsx +++ b/app/(platform)/(dashboard)/_components/Navbar.tsx @@ -6,10 +6,11 @@ import { Button } from '@/components/ui/button'; import { FormPopover } from '@/components/form/form-popover'; import { MobileSidebar } from './mobile-sidebar'; +import { ModeToggle } from '@/components/ui/mode-toggle'; export const Navbar = () => { return ( - <nav className='fixed top-0 z-50 flex h-14 w-full items-center border-b bg-white px-4 shadow-sm'> + <nav className='fixed top-0 z-50 flex h-14 w-full items-center border-b bg-white px-4 shadow-sm dark:bg-black'> <MobileSidebar /> <div className='flex items-center gap-x-4'> <div className='hidden md:flex'> @@ -60,6 +61,7 @@ export const Navbar = () => { }, }} /> + <ModeToggle /> </div> </nav> ); diff --git a/app/(platform)/(dashboard)/_components/nav-item.tsx b/app/(platform)/(dashboard)/_components/nav-item.tsx index 1bd2025..ac10fbf 100644 --- a/app/(platform)/(dashboard)/_components/nav-item.tsx +++ b/app/(platform)/(dashboard)/_components/nav-item.tsx @@ -68,8 +68,10 @@ export const NavItem = ({ <AccordionTrigger onClick={() => onExpand(organization.id)} className={cn( - 'flex items-center gap-x-2 rounded-md p-1.5 text-start text-neutral-700 no-underline transition hover:bg-neutral-500/10 hover:no-underline', - isActive && !isExpanded && 'bg-sky-500/10 text-sky-700' + 'flex items-center gap-x-2 rounded-md p-1.5 text-start text-neutral-700 no-underline transition hover:bg-neutral-500/10 hover:no-underline dark:text-neutral-200 dark:hover:bg-neutral-200/10', + isActive && + !isExpanded && + 'bg-sky-500/10 text-sky-700 dark:bg-sky-300/10 dark:text-sky-600' )} > <div className='flex items-center gap-x-2'> @@ -84,7 +86,7 @@ export const NavItem = ({ <span className='text-sm font-medium'>{organization.name}</span> </div> </AccordionTrigger> - <AccordionContent className='pt-1 text-neutral-700'> + <AccordionContent className='pt-1 text-neutral-700 dark:text-neutral-200'> {routes.map((route) => ( <Button key={route.href} @@ -92,7 +94,8 @@ export const NavItem = ({ onClick={() => onClick(route.href)} className={cn( 'mb-1 w-full justify-start pl-10 font-normal', - pathname === route.href && 'bg-sky-500/10 text-sky-700' + pathname === route.href && + 'bg-sky-500/10 text-sky-700 dark:bg-sky-300/10 dark:text-sky-600' )} variant='ghost' > diff --git a/app/(platform)/(dashboard)/board/[boardId]/_components/board-navbar.tsx b/app/(platform)/(dashboard)/board/[boardId]/_components/board-navbar.tsx index 807c642..12b13bf 100644 --- a/app/(platform)/(dashboard)/board/[boardId]/_components/board-navbar.tsx +++ b/app/(platform)/(dashboard)/board/[boardId]/_components/board-navbar.tsx @@ -9,7 +9,7 @@ interface BoardNavbarProps { export const BoardNavbar = ({ data }: BoardNavbarProps) => { return ( - <div className='fixed top-14 z-[40] flex h-14 w-full items-center gap-x-4 bg-black/50 px-6 text-white'> + <div className='fixed top-14 z-[40] flex h-14 w-full items-center gap-x-4 bg-black/50 px-6 text-white dark:text-neutral-200'> <BoardTitleForm data={data} /> <div className='ml-auto'> <BoardOptions id={data.id} /> diff --git a/app/(platform)/(dashboard)/board/[boardId]/_components/board-options.tsx b/app/(platform)/(dashboard)/board/[boardId]/_components/board-options.tsx index b5cd490..683c908 100644 --- a/app/(platform)/(dashboard)/board/[boardId]/_components/board-options.tsx +++ b/app/(platform)/(dashboard)/board/[boardId]/_components/board-options.tsx @@ -54,12 +54,12 @@ export const BoardOptions = ({ id }: BoardOptionsProps) => { </Button> </PopoverTrigger> <PopoverContent className='px-0 pb-3 pt-3' side='bottom' align='start'> - <div className='pb-4 text-center text-sm font-medium text-neutral-600'> + <div className='pb-4 text-center text-sm font-medium text-neutral-600 dark:text-neutral-200'> Board Actions </div> <PopoverClose asChild> <Button - className='absolute right-2 top-2 h-auto w-auto p-2 text-neutral-600' + className='absolute right-2 top-2 h-auto w-auto p-2 text-neutral-600 dark:text-neutral-200' variant='ghost' > <X className='h-4 w-4' /> @@ -69,7 +69,7 @@ export const BoardOptions = ({ id }: BoardOptionsProps) => { variant='ghost' onClick={onCopy} disabled={isLoadingCopy} - className='h-auto w-full justify-start rounded-none p-2 px-5 text-sm font-normal text-neutral-600' + className='h-auto w-full justify-start rounded-none p-2 px-5 text-sm font-normal text-neutral-600 dark:text-neutral-200' > Copy this Board </Button> @@ -78,7 +78,7 @@ export const BoardOptions = ({ id }: BoardOptionsProps) => { variant='ghost' onClick={onDelete} disabled={isLoadingDelete} - className='h-auto w-full justify-start rounded-none p-2 px-5 text-sm font-normal text-destructive hover:text-destructive' + className='h-auto w-full justify-start rounded-none p-2 px-5 text-sm font-normal text-destructive hover:text-destructive dark:text-red-500 dark:hover:text-red-500' > Delete this Board </Button> diff --git a/app/(platform)/(dashboard)/board/[boardId]/_components/board-update-image.tsx b/app/(platform)/(dashboard)/board/[boardId]/_components/board-update-image.tsx index 6c092d1..052163d 100644 --- a/app/(platform)/(dashboard)/board/[boardId]/_components/board-update-image.tsx +++ b/app/(platform)/(dashboard)/board/[boardId]/_components/board-update-image.tsx @@ -43,7 +43,7 @@ export const BoardUpdateImage = ({ boardId }: BoardUpdateImageProps) => { <PopoverTrigger asChild> <Button variant='ghost' - className='h-auto w-full justify-start p-2 px-5 text-sm font-normal text-neutral-600' + className='h-auto w-full justify-start p-2 px-5 text-sm font-normal text-neutral-600 dark:text-neutral-200' > Change Background Image </Button> @@ -51,7 +51,7 @@ export const BoardUpdateImage = ({ boardId }: BoardUpdateImageProps) => { <PopoverContent className='w-80 pt-3' side='left' align='start'> <PopoverClose asChild> <Button - className='absolute right-2 top-2 h-auto w-auto p-2 text-neutral-600' + className='absolute right-2 top-2 h-auto w-auto p-2 text-neutral-600 dark:text-neutral-200' variant='ghost' > <X className='h-4 w-4' /> @@ -59,10 +59,10 @@ export const BoardUpdateImage = ({ boardId }: BoardUpdateImageProps) => { </PopoverClose> <form action={onSubmit} className='space-y-4'> <div className='space-y-4'> - <p className='text-center text-xs font-medium italic text-neutral-700'> + <p className='text-center text-xs font-medium italic text-neutral-700 dark:text-neutral-100'> Images Provided by{' '} <Link - className='text-sky-900 underline' + className='text-sky-900 underline dark:text-sky-600' href='https://unsplash.com/' > Unsplash diff --git a/app/(platform)/(dashboard)/board/[boardId]/_components/card-item.tsx b/app/(platform)/(dashboard)/board/[boardId]/_components/card-item.tsx index fc789d6..db6a04a 100644 --- a/app/(platform)/(dashboard)/board/[boardId]/_components/card-item.tsx +++ b/app/(platform)/(dashboard)/board/[boardId]/_components/card-item.tsx @@ -24,17 +24,17 @@ export const CardItem = ({ index, data }: CardItemProps) => { ref={provided.innerRef} role='button' onClick={() => cardModal.onOpen(data.id)} - className='space-y-2 truncate rounded-md border-2 border-transparent bg-white px-3 py-2 text-sm shadow-sm hover:border-black' + className='space-y-2 truncate rounded-md border-2 border-transparent bg-white px-3 py-2 text-sm shadow-sm hover:border-black dark:bg-black dark:hover:border-white/50' > {data.title} {data?.dueDate && ( - <div className='flex w-fit rounded-md border-2 border-transparent bg-slate-100 px-0.5 pb-0.5 pt-0.5 text-sm'> + <div className='flex w-fit rounded-md border-2 border-transparent bg-slate-100 px-0.5 pb-0.5 pt-0.5 text-sm dark:bg-slate-800'> <Calendar className='ml-0.5 mr-0.5 h-4 w-4' /> Due: {format(data.dueDate, 'PP')} </div> )} {data?.startedAt && ( - <div className='flex w-fit rounded-md border-2 border-transparent bg-slate-100 px-0.5 pb-0.5 pt-0.5 text-sm'> + <div className='flex w-fit rounded-md border-2 border-transparent bg-slate-100 px-0.5 pb-0.5 pt-0.5 text-sm dark:bg-slate-800'> <Calendar className='ml-0.5 mr-0.5 h-4 w-4' /> Started: {format(data.startedAt, 'PP')} </div> diff --git a/app/(platform)/(dashboard)/board/[boardId]/_components/list-form.tsx b/app/(platform)/(dashboard)/board/[boardId]/_components/list-form.tsx index c645e31..8db1612 100644 --- a/app/(platform)/(dashboard)/board/[boardId]/_components/list-form.tsx +++ b/app/(platform)/(dashboard)/board/[boardId]/_components/list-form.tsx @@ -67,7 +67,7 @@ export const ListForm = () => { <form action={onSubmit} ref={formRef} - className='w-full space-y-4 rounded-md bg-white p-3 shadow-md' + className='w-full space-y-4 rounded-md bg-white p-3 shadow-md dark:bg-black' > <FormInput ref={inputRef} @@ -92,7 +92,7 @@ export const ListForm = () => { <ListWrapper> <button onClick={enableEditing} - className='flex w-full items-center rounded-md bg-white/80 p-3 text-sm font-medium transition hover:bg-white/50' + className='flex w-full items-center rounded-md bg-white/80 p-3 text-sm font-medium transition hover:bg-white/50 dark:bg-white/10 dark:hover:bg-white/5' > <Plus className='mr-2 h-4 w-4' /> Add a list diff --git a/app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx b/app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx index c65dc72..2ae17b8 100644 --- a/app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx +++ b/app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx @@ -41,7 +41,7 @@ export const ListItem = ({ index, data }: ListItemProps) => { > <div {...provided.dragHandleProps} - className='w-full rounded-md bg-[#f1f2f4] pb-2 shadow-md' + className='w-full rounded-md bg-[#f1f2f4] pb-2 shadow-md dark:bg-[#1f1f1f]' > <ListHeader onAddCard={enableEditing} data={data} /> <Droppable droppableId={data.id} type='card'> diff --git a/app/(platform)/(dashboard)/board/[boardId]/layout.tsx b/app/(platform)/(dashboard)/board/[boardId]/layout.tsx index 0c5d647..96d6c20 100644 --- a/app/(platform)/(dashboard)/board/[boardId]/layout.tsx +++ b/app/(platform)/(dashboard)/board/[boardId]/layout.tsx @@ -1,14 +1,8 @@ import { auth } from '@clerk/nextjs/server'; import { notFound, redirect } from 'next/navigation'; -import { - LiveblocksProvider, - RoomProvider, - ClientSideSuspense, -} from '@liveblocks/react/suspense'; import { db } from '@/lib/db'; import { BoardNavbar } from './_components/board-navbar'; -import { Skeleton } from '@/components/ui/skeleton'; import { BoardLiveblocks } from './_components/board-liveblocks'; export async function generateMetadata(props: { diff --git a/app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx b/app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx index 01fbb71..860b650 100644 --- a/app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx +++ b/app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx @@ -32,7 +32,7 @@ export const BoardList = async () => { return ( <div className='space-y-4'> - <div className='flex items-center text-lg font-semibold text-neutral-700'> + <div className='flex items-center text-lg font-semibold text-neutral-700 dark:text-neutral-200'> <User2 className='mr-2 h-6 w-6' /> Your boards </div> diff --git a/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx b/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx index 42415fd..d7a0bc7 100644 --- a/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx +++ b/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx @@ -64,14 +64,14 @@ const ActivityPage = async ({ export default ActivityPage; -const ActivityListSkeleton = () => { +function ActivityListSkeleton() { return ( - <ol className='mt-4 space-y-4'> + <div className='mt-4 space-y-4'> <Skeleton className='h-14 w-[80%]' /> <Skeleton className='h-14 w-[50%]' /> <Skeleton className='h-14 w-[70%]' /> <Skeleton className='h-14 w-[80%]' /> <Skeleton className='h-14 w-[75%]' /> - </ol> + </div> ); -}; +} diff --git a/app/(platform)/layout.tsx b/app/(platform)/layout.tsx index 4f37db4..c655a66 100644 --- a/app/(platform)/layout.tsx +++ b/app/(platform)/layout.tsx @@ -1,14 +1,25 @@ +'use client'; + import { Toaster } from 'sonner'; import { ClerkProvider } from '@clerk/nextjs'; +import { dark } from '@clerk/themes'; +import { useTheme } from 'next-themes'; import { ModalProvider } from '@/components/providers/modal-provider'; import { QueryProvider } from '@/components/providers/query-provider'; const PlatformLayout = ({ children }: { children: React.ReactNode }) => { + const { theme } = useTheme(); + return ( - <ClerkProvider afterSignOutUrl='/'> + <ClerkProvider + afterSignOutUrl='/' + appearance={{ + baseTheme: theme === 'dark' ? dark : undefined, + }} + > <QueryProvider> - <Toaster /> + <Toaster theme='system' /> <ModalProvider /> {children} </QueryProvider> diff --git a/app/layout.tsx b/app/layout.tsx index ec5725c..8555621 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -5,6 +5,7 @@ import type { Metadata } from 'next'; import './globals.css'; import { siteConfig } from '@/config/site'; +import { ThemeProvider } from '@/components/theme-provider'; const inter = Inter({ subsets: ['latin'] }); @@ -28,10 +29,17 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - <html lang='en'> + <html lang='en' suppressHydrationWarning> <body className={inter.className}> <SpeedInsights /> - {children} + <ThemeProvider + attribute='class' + defaultTheme='system' + enableSystem + disableTransitionOnChange + > + {children} + </ThemeProvider> <Analytics /> </body> </html> diff --git a/components/activity-item.tsx b/components/activity-item.tsx index ad6692f..7897072 100644 --- a/components/activity-item.tsx +++ b/components/activity-item.tsx @@ -16,7 +16,7 @@ export const ActivityItem = ({ data }: ActivityItemProps) => { </Avatar> <div className='flex flex-col space-y-0.5'> <p className='text-sm text-muted-foreground'> - <span className='font-semibold lowercase text-neutral-700'> + <span className='font-semibold lowercase text-neutral-700 dark:text-neutral-200'> {data.userName} </span>{' '} {generateLogMessage(data)} diff --git a/components/form/form-input.tsx b/components/form/form-input.tsx index 3210365..07f4777 100644 --- a/components/form/form-input.tsx +++ b/components/form/form-input.tsx @@ -45,7 +45,7 @@ export const FormInput = forwardRef<HTMLInputElement, FormInputProps>( {label ? ( <Label htmlFor={id} - className='text-xs font-semibold text-neutral-700' + className='text-xs font-semibold text-neutral-700 dark:text-neutral-200' > {label} </Label> diff --git a/components/form/form-picker.tsx b/components/form/form-picker.tsx index 1130977..8215085 100644 --- a/components/form/form-picker.tsx +++ b/components/form/form-picker.tsx @@ -74,7 +74,7 @@ export const FormPicker = ({ id, errors }: FormPickerProps) => { id={id} name={id} className='hidden' - checked={selectedImageId === image.id} + defaultChecked={selectedImageId === image.id} disabled={pending} value={`${image.id}|${image.urls.thumb}|${image.urls.full}|${image.links.html}|${image.user.name}|${image.links.download_location}`} /> diff --git a/components/form/form-popover.tsx b/components/form/form-popover.tsx index 102ba7f..1ccbcca 100644 --- a/components/form/form-popover.tsx +++ b/components/form/form-popover.tsx @@ -66,12 +66,12 @@ export const FormPopover = ({ side={side} sideOffset={sideOffset} > - <div className='pb-4 text-center text-sm font-medium text-neutral-600'> + <div className='pb-4 text-center text-sm font-medium text-neutral-600 dark:text-neutral-300'> Create board </div> <PopoverClose ref={closeRef} asChild> <Button - className='absolute right-2 top-2 h-auto w-auto p-2 text-neutral-600' + className='absolute right-2 top-2 h-auto w-auto p-2 text-neutral-600 dark:text-neutral-300' variant='ghost' > <X className='h-4 w-4' /> @@ -79,10 +79,10 @@ export const FormPopover = ({ </PopoverClose> <form action={onSubmit} className='space-y-4'> <div className='space-y-4'> - <p className='text-center text-xs font-medium italic text-neutral-700'> + <p className='text-center text-xs font-medium italic text-neutral-700 dark:text-neutral-200'> Images Provided by{' '} <Link - className='text-sky-900 underline' + className='text-sky-900 underline dark:text-sky-600' href='https://unsplash.com/' > Unsplash diff --git a/components/logo.tsx b/components/logo.tsx index cf230cb..3e6477f 100644 --- a/components/logo.tsx +++ b/components/logo.tsx @@ -1,13 +1,21 @@ +'use client'; + import Image from 'next/image'; import Link from 'next/link'; +import { useTheme } from 'next-themes'; export const Logo = () => { + const { theme } = useTheme(); + return ( // TODO: Make this go back to the organization page if you are logged in <Link href='/'> - <div className='hidden items-center gap-x-2 transition hover:opacity-75 md:flex'> + <div + className='hidden items-center gap-x-2 transition hover:opacity-75 md:flex' + suppressHydrationWarning + > <Image - src='/logo-transparent.svg' + src={`/logo-${theme === 'light' ? 'light' : 'dark'}.svg`} alt='logo' height={100} width={100} diff --git a/components/modals/card-modal/actions.tsx b/components/modals/card-modal/actions.tsx index 1384b41..61c8442 100644 --- a/components/modals/card-modal/actions.tsx +++ b/components/modals/card-modal/actions.tsx @@ -82,7 +82,7 @@ export const Actions = ({ data }: ActionsProps) => { <DatePicker type='dueDate' variant='gray' - className='w-full justify-start text-black' + className='w-full justify-start text-black dark:text-white' size='inline' placeholder='Add Due Date' afterSelectText='Due ' @@ -92,7 +92,7 @@ export const Actions = ({ data }: ActionsProps) => { <DatePicker type='startedAtDate' variant='gray' - className='w-full justify-start text-black' + className='w-full justify-start text-black dark:text-white' size='inline' placeholder='Add Started Date' afterSelectText='Started ' @@ -103,7 +103,7 @@ export const Actions = ({ data }: ActionsProps) => { onClick={onDelete} disabled={isLoadingDelete} variant='gray' - className='w-full justify-start text-destructive' + className='w-full justify-start text-destructive dark:text-red-500' size='inline' > <Trash className='mr-2 h-4 w-4' /> diff --git a/components/modals/card-modal/activity.tsx b/components/modals/card-modal/activity.tsx index afafda5..a2d9968 100644 --- a/components/modals/card-modal/activity.tsx +++ b/components/modals/card-modal/activity.tsx @@ -13,9 +13,11 @@ interface ActivityProps { export const Activity = ({ items }: ActivityProps) => { return ( <div className='flex w-full items-start gap-x-3'> - <ActivityIcon className='mt-0.5 h-5 w-5 text-neutral-700' /> + <ActivityIcon className='mt-0.5 h-5 w-5 text-neutral-700 dark:text-neutral-100' /> <div className='w-full'> - <p className='mb-2 font-semibold text-neutral-700'>Activity</p> + <p className='mb-2 font-semibold text-neutral-700 dark:text-neutral-100'> + Activity + </p> <ol className='mt-2 space-y-4'> {items.map((item) => ( <ActivityItem key={item.id} data={item} /> diff --git a/components/modals/card-modal/description.tsx b/components/modals/card-modal/description.tsx index a72fd6a..3d8f694 100644 --- a/components/modals/card-modal/description.tsx +++ b/components/modals/card-modal/description.tsx @@ -74,9 +74,11 @@ export const Description = ({ data }: DescriptionProps) => { return ( <div className='flex w-full items-start gap-x-3'> - <AlignLeft className='mt-0.5 h-5 w-5 text-neutral-700' /> + <AlignLeft className='mt-0.5 h-5 w-5 text-neutral-700 dark:text-neutral-100' /> <div className='w-full'> - <p className='mb-2 font-semibold text-neutral-700'>Description</p> + <p className='mb-2 font-semibold text-neutral-700 dark:text-neutral-100'> + Description + </p> {isEditing ? ( <form ref={formRef} className='space-y-2' action={onSubmit}> <FormTextarea @@ -103,7 +105,7 @@ export const Description = ({ data }: DescriptionProps) => { <div onClick={enaleEditing} role='button' - className='min-h-[78px] rounded-md bg-neutral-200 px-3.5 py-3 text-sm font-medium' + className='min-h-[78px] rounded-md bg-neutral-200 px-3.5 py-3 text-sm font-medium dark:bg-neutral-800' > {data.description ?? 'Add a more detailed description...'} </div> diff --git a/components/modals/card-modal/header.tsx b/components/modals/card-modal/header.tsx index fc10a4a..b70f9e9 100644 --- a/components/modals/card-modal/header.tsx +++ b/components/modals/card-modal/header.tsx @@ -61,7 +61,7 @@ export const Header = ({ data }: HeaderProps) => { return ( <div className='mb-6 flex w-full items-start gap-x-3'> - <Layout className='mt-1 h-5 w-5 text-neutral-700' /> + <Layout className='mt-1 h-5 w-5 text-neutral-700 dark:text-neutral-100' /> <div className='w-full'> <form action={onSubmit}> <FormInput @@ -69,7 +69,7 @@ export const Header = ({ data }: HeaderProps) => { ref={inputRef} onBlur={onBlur} defaultValue={title} - className='font-semi-bold relative -left-1 mb-0.5 w-[95%] truncate border-transparent bg-transparent px-1 text-xl text-neutral-700 focus-visible:border-input focus-visible:bg-white' + className='font-semi-bold relative -left-1 mb-0.5 w-[95%] truncate border-transparent bg-transparent px-1 text-xl text-neutral-700 focus-visible:border-input focus-visible:bg-white dark:text-neutral-100 dark:focus-visible:bg-black' /> </form> <p className='text-sm text-muted-foreground'> diff --git a/components/modals/pro-modal.tsx b/components/modals/pro-modal.tsx index 8715ce5..cc69719 100644 --- a/components/modals/pro-modal.tsx +++ b/components/modals/pro-modal.tsx @@ -37,9 +37,9 @@ export const ProModal = () => { <div className='relative flex aspect-video items-center justify-center'> <Image src='/hero.svg' alt='hero' className='object-cover' fill /> </div> - <div className='mx-auto space-y-6 p-6 text-neutral-700'> + <div className='mx-auto space-y-6 p-6 text-neutral-700 dark:text-neutral-200'> <h1 className='text-xl font-semibold'>Upgrade to Tasko Pro Today!</h1> - <p className='text-xs font-semibold text-neutral-600'> + <p className='text-xs font-semibold text-neutral-600 dark:text-neutral-300'> Explore the best of Tasko </p> <div className='pl-3'> diff --git a/components/theme-provider.tsx b/components/theme-provider.tsx new file mode 100644 index 0000000..9bf53d8 --- /dev/null +++ b/components/theme-provider.tsx @@ -0,0 +1,11 @@ +'use client'; + +import * as React from 'react'; +import { ThemeProvider as NextThemesProvider } from 'next-themes'; + +export function ThemeProvider({ + children, + ...props +}: React.ComponentProps<typeof NextThemesProvider>) { + return <NextThemesProvider {...props}>{children}</NextThemesProvider>; +} diff --git a/components/ui/button.tsx b/components/ui/button.tsx index 64c21c7..c096f77 100644 --- a/components/ui/button.tsx +++ b/components/ui/button.tsx @@ -18,9 +18,10 @@ const buttonVariants = cva( 'bg-secondary text-secondary-foreground hover:bg-secondary/80', ghost: 'hover:bg-accent hover:text-accent-foreground', link: 'text-primary underline-offset-4 hover:underline', - primary: 'bg-sky-700 text-primary-foreground hover:bg-sky-700/90', + primary: + 'bg-sky-700 text-primary-foreground hover:bg-sky-700/90 dark:text-neutral-200', transparent: 'bg-transparent text-white hover:bg-white/20', - gray: 'bg-neutral-200 text-secondary-foreground hover:bg-neutral-300', + gray: 'bg-neutral-200 text-secondary-foreground hover:bg-neutral-300 dark:bg-neutral-700 dark:text-neutral-200 dark:hover:bg-neutral-600', }, size: { default: 'h-10 px-4 py-2', diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..b9c0f93 --- /dev/null +++ b/components/ui/dropdown-menu.tsx @@ -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 gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + inset && 'pl-8', + className + )} + {...props} + > + {children} + <ChevronRight className='ml-auto' /> + </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-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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} + /> +)); +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-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 gap-2 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 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + 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, +}; diff --git a/components/ui/mode-toggle.tsx b/components/ui/mode-toggle.tsx new file mode 100644 index 0000000..f97cfb2 --- /dev/null +++ b/components/ui/mode-toggle.tsx @@ -0,0 +1,39 @@ +'use client'; + +import { Moon, Sun } from 'lucide-react'; +import { useTheme } from 'next-themes'; + +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; + +export function ModeToggle() { + const { setTheme } = useTheme(); + + return ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant='outline' size='icon'> + <Sun className='h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0' /> + <Moon className='absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100' /> + <span className='sr-only'>Toggle theme</span> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align='end'> + <DropdownMenuItem onClick={() => setTheme('light')}> + Light + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme('dark')}> + Dark + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme('system')}> + System + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + ); +} diff --git a/docs/mint.json b/docs/mint.json index ef58382..2539199 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -2,8 +2,9 @@ "$schema": "https://mintlify.com/schema.json", "name": "Tasko", "logo": { - "dark": "/public/logo-transparent.svg", - "light": "/public/logo-transparent.svg" + "dark": "/public/logo-light.svg", + "light": "/public/logo-dark.svg", + "href": "https://tasko.ahmadk953.org/" }, "favicon": "/public/favicon.svg", "colors": { diff --git a/docs/public/logo-dark.svg b/docs/public/logo-dark.svg new file mode 100644 index 0000000..78ccea0 --- /dev/null +++ b/docs/public/logo-dark.svg @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no" ?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="376" height="120" viewBox="0 0 376 120" xml:space="preserve"> +<desc>Created with Fabric.js 5.3.0</desc> +<defs> +</defs> +<g transform="matrix(0.9994324631 0 0 1 188 60)" id="w_mP2bJK3j5Lw_jckhinB" > +<g style="" > + <g transform="matrix(1 0 0 1 -137.003535513 1.0016495644)" id="rwm5Fx6mCPDDyYZTLS83i" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-112.996464487, -251.0016495644)" d="M 66.028732 267 C 66.028961 249.509247 66.01149 232.518478 66.036255 215.527771 C 66.0504 205.827576 70.768333 201.018372 80.370125 201.001831 C 102.024933 200.964493 123.679916 200.959305 145.334702 201.004562 C 154.820145 201.024384 159.838303 205.900436 159.885071 215.513 C 160.000168 239.166199 159.998932 262.820709 159.886169 286.473938 C 159.840332 296.090576 154.840363 300.970642 145.350357 300.993103 C 123.69561 301.044342 102.040581 301.042847 80.385818 300.993988 C 70.731483 300.972198 66.070244 296.19516 66.033859 286.489716 C 66.010132 280.159882 66.028961 273.829926 66.028732 267 M 128.499634 207.14389 C 112.839783 207.144135 97.179916 207.128754 81.520096 207.151459 C 74.172005 207.162109 72.286903 209.000824 72.278992 216.249481 C 72.253708 239.406006 72.25415 262.562622 72.278648 285.719147 C 72.286339 292.987457 74.161774 294.844055 81.497017 294.852966 C 102.321236 294.878265 123.145523 294.876984 143.969742 294.853027 C 151.64856 294.844177 153.66243 292.825531 153.725449 284.992981 C 153.793823 276.497223 153.743866 268.000519 153.743713 259.504211 C 153.743469 245.343719 153.78624 231.183044 153.723221 217.022827 C 153.688324 209.182495 151.64473 207.182358 143.992966 207.14859 C 139.161835 207.127274 134.330521 207.144196 128.499634 207.14389 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 101.4329052016 -2.347225608)" id="LgzQG6S4IgJ5LSB-1MGhT" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-351.4329052016, -247.652774392)" d="M 348.781433 267.992584 C 344.020813 267.000305 346.399017 270.55365 346.284027 271.849976 C 345.774017 277.598938 344.230011 279.230469 338.542694 278.983704 C 333.55484 278.767334 332.031006 277.164459 332.015045 271.672943 C 331.96817 255.538239 331.96524 239.403183 332.016418 223.268494 C 332.034485 217.576462 333.653381 216.004379 339.04306 216.004074 C 344.500305 216.003769 346.080872 217.523224 346.129791 223.174164 C 346.199646 231.24498 346.147552 239.316864 346.147552 248.754532 C 350.008942 245.327988 352.672485 242.690506 355.61618 240.415619 C 360.169617 236.896713 362.418396 237.205536 365.734344 241.332031 C 369.10437 245.525848 368.863678 247.488007 364.49295 251.364548 C 362.278625 253.328522 360.056854 255.284119 357.481232 257.55899 C 361.356812 260.842712 364.820129 263.914734 368.432709 266.799927 C 372.158295 269.775299 371.127533 272.722321 368.741302 275.841095 C 366.316284 279.01059 363.44339 280.708008 359.869202 277.819855 C 356.12793 274.796722 352.659149 271.43631 348.781433 267.992584 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 13.9953092113 7.5797863158)" id="LsBsxmXg-vbvnhXy1RkUo" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-263.9953092113, -257.5797863158)" d="M 284.771912 276.59201 C 279.486603 279.963928 275.77652 279.62796 271.166351 275.736328 C 262.517487 280.80835 254.822266 279.518646 248.069412 271.865326 C 241.064392 263.926208 240.673157 252.51239 247.125427 244.326935 C 253.786194 235.876999 261.510315 234.299423 269.477875 238.476303 C 274.214264 237.511551 277.465973 236.19725 280.581451 236.465408 C 282.376556 236.619919 285.37149 239.30867 285.398773 240.898392 C 285.600891 252.671097 285.192871 264.454285 284.771912 276.59201 M 267.214417 251.240356 C 265.927124 250.987366 264.599274 250.395447 263.360016 250.543747 C 259.346893 251.024033 257.036652 253.464294 256.970032 257.504822 C 256.90625 261.372101 259.187103 263.757019 262.889221 264.367645 C 266.977844 265.042023 270.082123 262.900208 270.534576 259.063232 C 270.809723 256.729675 268.814606 254.128464 267.214417 251.240356 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 146.7050068684 7.5269668305)" id="gQjcX6p2dhO5R11vo0WDq" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-396.7050068684, -257.5269668305)" d="M 374.355896 259.589935 C 374.229004 247.238068 380.640686 238.509155 391.428986 235.859436 C 401.295013 233.436249 411.709747 238.038864 416.491638 246.93544 C 421.321075 255.920609 419.171021 267.401581 411.372498 274.270447 C 398.060089 285.99588 378.095123 278.294647 374.355896 259.589935 M 399.775146 250.163162 C 393.726257 249.211777 390.029816 250.988312 389.023773 255.330338 C 388.045654 259.552124 389.874298 263.284882 393.626801 264.726227 C 397.247803 266.117065 401.839813 264.533173 403.629944 261.275879 C 405.654175 257.592621 404.526611 253.704361 399.775146 250.163162 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -39.3286224803 -0.8900576382)" id="Ga9r6lxzZi1HcY-6a_Kmx" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-210.6713775197, -249.1099423618)" d="M 217.79866 273.382568 C 216.923828 279.496368 212.680267 279.19397 208.608749 278.87265 C 204.457565 278.545013 203.723129 275.567871 203.729706 272.073151 C 203.752319 260.075867 203.595383 248.076477 203.783997 236.082245 C 203.84642 232.113571 202.446686 230.712036 198.564392 231.015686 C 195.25238 231.274704 191.899368 230.956589 188.571884 231.084991 C 184.529022 231.240997 182.248962 229.717987 182.147507 225.40152 C 182.040085 220.832214 184.449203 219.183365 188.663696 219.211792 C 194.995285 219.254501 201.327438 219.206177 207.659363 219.206024 C 215.990875 219.205826 224.32251 219.244675 232.653824 219.207184 C 236.7966 219.188538 239.219223 220.566879 239.198563 225.293152 C 239.177353 230.154022 236.543015 231.181366 232.467041 231.084061 C 227.84584 230.97374 223.219971 231.058594 217.828979 231.058594 C 217.828979 245.409164 217.828979 259.176727 217.79866 273.382568 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 58.9901139341 7.5030230049)" id="wRbxYkwgpURFOPOX-2bBy" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-308.9901139341, -257.5030230049)" d="M 316.296387 252.674011 C 324.396332 255.646759 327.28714 259.645386 326.749725 266.743164 C 326.196747 274.046631 322.445099 277.641724 314.168854 279.185272 C 307.365387 280.454132 300.962585 279.581757 294.782471 276.479156 C 291.320648 274.741241 290.179199 272.477844 292.087158 268.839752 C 293.926208 265.333069 296.127899 263.05777 300.356659 265.206757 C 304.301849 267.211639 308.189362 269.611237 313.136902 265.755859 C 311.162476 265.138214 309.222015 264.362549 307.207855 263.929626 C 297.112366 261.759583 292.329346 256.612518 292.528229 247.980499 C 292.661041 242.215485 295.200562 238.528305 300.651978 236.718475 C 307.751343 234.361542 314.749878 234.922546 321.568787 237.94635 C 324.222382 239.123093 325.655518 240.896454 324.182709 243.843811 C 322.776489 246.65799 321.683014 249.716644 317.248688 248.460068 C 313.674347 247.447174 309.895508 247.155945 306.01709 247.382187 C 307.940002 252.539169 312.596619 251.089508 316.296387 252.674011 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -111.9882042178 1.0006770411)" id="kuUaRTkI7TiYKQKgLhgH1" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-138.0117957822, -251.0006770411)" d="M 128.754608 259.999939 C 128.755646 246.860184 128.725449 234.220322 128.771347 221.580719 C 128.793991 215.347488 130.520416 213.708328 136.863113 213.589539 C 144.91658 213.438705 147.143906 214.965347 147.185333 221.54248 C 147.308914 241.166443 147.307388 260.792145 147.187988 280.416138 C 147.147873 287.011322 144.90448 288.569672 136.904938 288.411011 C 130.379074 288.281586 128.797287 286.666046 128.763519 279.958496 C 128.730881 273.472443 128.755341 266.986145 128.754608 259.999939 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -161.9853889369 -8.4289790636)" id="8Hekvf9O-OHjgZhJ8rMo2" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-88.0146110631, -241.5710209364)" d="M 90.470505 269.769745 C 88.223045 269.76535 86.368317 269.92099 84.566414 269.680664 C 80.978569 269.202087 78.794708 267.214905 78.789551 263.392487 C 78.769997 248.903625 78.758598 234.414719 78.787582 219.925903 C 78.79512 216.155106 80.837402 214.149902 84.53833 213.660339 C 94.495842 212.34314 97.243431 214.705841 97.25354 224.729874 C 97.2658 236.887299 97.219048 249.04483 97.259071 261.202118 C 97.273911 265.708801 95.936394 269.0802 90.470505 269.769745 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -136.9919327036 -20.8348662725)" id="aZ-DbO6E3jqPfEiZIEpjX" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-113.0080672964, -229.1651337275)" d="M 117.90834 244.256958 C 115.70591 244.538742 113.887573 244.803146 112.071442 244.788712 C 105.681915 244.737976 103.807259 242.837769 103.760071 236.413605 C 103.720932 231.084427 103.665596 225.752548 103.789619 220.425873 C 103.903732 215.52475 105.81395 213.825058 111.026039 213.59137 C 118.825111 213.241699 121.722244 214.651627 122.01783 219.730377 C 122.375107 225.869095 122.440315 232.068161 121.958641 238.188126 C 121.796677 240.246063 119.574173 242.1418 117.90834 244.256958 z" stroke-linecap="round" /> +</g> +</g> +</g> +</svg> \ No newline at end of file diff --git a/docs/public/logo-transparent.svg b/docs/public/logo-light.svg similarity index 100% rename from docs/public/logo-transparent.svg rename to docs/public/logo-light.svg diff --git a/package.json b/package.json index f26a696..b0b364f 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "dependencies": { "@arcjet/next": "^1.0.0-alpha.34", "@clerk/nextjs": "^6.9.9", + "@clerk/themes": "^2.2.5", "@hello-pangea/dnd": "^17.0.0", "@liveblocks/client": "^2.15.1", "@liveblocks/node": "^2.15.1", @@ -30,6 +31,7 @@ "@radix-ui/react-accordion": "^1.2.2", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-dialog": "^1.1.3", + "@radix-ui/react-dropdown-menu": "^2.1.4", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-popover": "^1.1.3", "@radix-ui/react-separator": "^1.0.3", @@ -47,6 +49,7 @@ "lodash": "^4.17.21", "lucide-react": "^0.471.0", "next": "^15.1.4", + "next-themes": "^0.4.4", "react": "^19.0.0", "react-day-picker": "^9.5.0", "react-dom": "^19.0.0", diff --git a/public/logo-dark.svg b/public/logo-dark.svg new file mode 100644 index 0000000..78ccea0 --- /dev/null +++ b/public/logo-dark.svg @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no" ?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="376" height="120" viewBox="0 0 376 120" xml:space="preserve"> +<desc>Created with Fabric.js 5.3.0</desc> +<defs> +</defs> +<g transform="matrix(0.9994324631 0 0 1 188 60)" id="w_mP2bJK3j5Lw_jckhinB" > +<g style="" > + <g transform="matrix(1 0 0 1 -137.003535513 1.0016495644)" id="rwm5Fx6mCPDDyYZTLS83i" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-112.996464487, -251.0016495644)" d="M 66.028732 267 C 66.028961 249.509247 66.01149 232.518478 66.036255 215.527771 C 66.0504 205.827576 70.768333 201.018372 80.370125 201.001831 C 102.024933 200.964493 123.679916 200.959305 145.334702 201.004562 C 154.820145 201.024384 159.838303 205.900436 159.885071 215.513 C 160.000168 239.166199 159.998932 262.820709 159.886169 286.473938 C 159.840332 296.090576 154.840363 300.970642 145.350357 300.993103 C 123.69561 301.044342 102.040581 301.042847 80.385818 300.993988 C 70.731483 300.972198 66.070244 296.19516 66.033859 286.489716 C 66.010132 280.159882 66.028961 273.829926 66.028732 267 M 128.499634 207.14389 C 112.839783 207.144135 97.179916 207.128754 81.520096 207.151459 C 74.172005 207.162109 72.286903 209.000824 72.278992 216.249481 C 72.253708 239.406006 72.25415 262.562622 72.278648 285.719147 C 72.286339 292.987457 74.161774 294.844055 81.497017 294.852966 C 102.321236 294.878265 123.145523 294.876984 143.969742 294.853027 C 151.64856 294.844177 153.66243 292.825531 153.725449 284.992981 C 153.793823 276.497223 153.743866 268.000519 153.743713 259.504211 C 153.743469 245.343719 153.78624 231.183044 153.723221 217.022827 C 153.688324 209.182495 151.64473 207.182358 143.992966 207.14859 C 139.161835 207.127274 134.330521 207.144196 128.499634 207.14389 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 101.4329052016 -2.347225608)" id="LgzQG6S4IgJ5LSB-1MGhT" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-351.4329052016, -247.652774392)" d="M 348.781433 267.992584 C 344.020813 267.000305 346.399017 270.55365 346.284027 271.849976 C 345.774017 277.598938 344.230011 279.230469 338.542694 278.983704 C 333.55484 278.767334 332.031006 277.164459 332.015045 271.672943 C 331.96817 255.538239 331.96524 239.403183 332.016418 223.268494 C 332.034485 217.576462 333.653381 216.004379 339.04306 216.004074 C 344.500305 216.003769 346.080872 217.523224 346.129791 223.174164 C 346.199646 231.24498 346.147552 239.316864 346.147552 248.754532 C 350.008942 245.327988 352.672485 242.690506 355.61618 240.415619 C 360.169617 236.896713 362.418396 237.205536 365.734344 241.332031 C 369.10437 245.525848 368.863678 247.488007 364.49295 251.364548 C 362.278625 253.328522 360.056854 255.284119 357.481232 257.55899 C 361.356812 260.842712 364.820129 263.914734 368.432709 266.799927 C 372.158295 269.775299 371.127533 272.722321 368.741302 275.841095 C 366.316284 279.01059 363.44339 280.708008 359.869202 277.819855 C 356.12793 274.796722 352.659149 271.43631 348.781433 267.992584 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 13.9953092113 7.5797863158)" id="LsBsxmXg-vbvnhXy1RkUo" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-263.9953092113, -257.5797863158)" d="M 284.771912 276.59201 C 279.486603 279.963928 275.77652 279.62796 271.166351 275.736328 C 262.517487 280.80835 254.822266 279.518646 248.069412 271.865326 C 241.064392 263.926208 240.673157 252.51239 247.125427 244.326935 C 253.786194 235.876999 261.510315 234.299423 269.477875 238.476303 C 274.214264 237.511551 277.465973 236.19725 280.581451 236.465408 C 282.376556 236.619919 285.37149 239.30867 285.398773 240.898392 C 285.600891 252.671097 285.192871 264.454285 284.771912 276.59201 M 267.214417 251.240356 C 265.927124 250.987366 264.599274 250.395447 263.360016 250.543747 C 259.346893 251.024033 257.036652 253.464294 256.970032 257.504822 C 256.90625 261.372101 259.187103 263.757019 262.889221 264.367645 C 266.977844 265.042023 270.082123 262.900208 270.534576 259.063232 C 270.809723 256.729675 268.814606 254.128464 267.214417 251.240356 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 146.7050068684 7.5269668305)" id="gQjcX6p2dhO5R11vo0WDq" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-396.7050068684, -257.5269668305)" d="M 374.355896 259.589935 C 374.229004 247.238068 380.640686 238.509155 391.428986 235.859436 C 401.295013 233.436249 411.709747 238.038864 416.491638 246.93544 C 421.321075 255.920609 419.171021 267.401581 411.372498 274.270447 C 398.060089 285.99588 378.095123 278.294647 374.355896 259.589935 M 399.775146 250.163162 C 393.726257 249.211777 390.029816 250.988312 389.023773 255.330338 C 388.045654 259.552124 389.874298 263.284882 393.626801 264.726227 C 397.247803 266.117065 401.839813 264.533173 403.629944 261.275879 C 405.654175 257.592621 404.526611 253.704361 399.775146 250.163162 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -39.3286224803 -0.8900576382)" id="Ga9r6lxzZi1HcY-6a_Kmx" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-210.6713775197, -249.1099423618)" d="M 217.79866 273.382568 C 216.923828 279.496368 212.680267 279.19397 208.608749 278.87265 C 204.457565 278.545013 203.723129 275.567871 203.729706 272.073151 C 203.752319 260.075867 203.595383 248.076477 203.783997 236.082245 C 203.84642 232.113571 202.446686 230.712036 198.564392 231.015686 C 195.25238 231.274704 191.899368 230.956589 188.571884 231.084991 C 184.529022 231.240997 182.248962 229.717987 182.147507 225.40152 C 182.040085 220.832214 184.449203 219.183365 188.663696 219.211792 C 194.995285 219.254501 201.327438 219.206177 207.659363 219.206024 C 215.990875 219.205826 224.32251 219.244675 232.653824 219.207184 C 236.7966 219.188538 239.219223 220.566879 239.198563 225.293152 C 239.177353 230.154022 236.543015 231.181366 232.467041 231.084061 C 227.84584 230.97374 223.219971 231.058594 217.828979 231.058594 C 217.828979 245.409164 217.828979 259.176727 217.79866 273.382568 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 58.9901139341 7.5030230049)" id="wRbxYkwgpURFOPOX-2bBy" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-308.9901139341, -257.5030230049)" d="M 316.296387 252.674011 C 324.396332 255.646759 327.28714 259.645386 326.749725 266.743164 C 326.196747 274.046631 322.445099 277.641724 314.168854 279.185272 C 307.365387 280.454132 300.962585 279.581757 294.782471 276.479156 C 291.320648 274.741241 290.179199 272.477844 292.087158 268.839752 C 293.926208 265.333069 296.127899 263.05777 300.356659 265.206757 C 304.301849 267.211639 308.189362 269.611237 313.136902 265.755859 C 311.162476 265.138214 309.222015 264.362549 307.207855 263.929626 C 297.112366 261.759583 292.329346 256.612518 292.528229 247.980499 C 292.661041 242.215485 295.200562 238.528305 300.651978 236.718475 C 307.751343 234.361542 314.749878 234.922546 321.568787 237.94635 C 324.222382 239.123093 325.655518 240.896454 324.182709 243.843811 C 322.776489 246.65799 321.683014 249.716644 317.248688 248.460068 C 313.674347 247.447174 309.895508 247.155945 306.01709 247.382187 C 307.940002 252.539169 312.596619 251.089508 316.296387 252.674011 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -111.9882042178 1.0006770411)" id="kuUaRTkI7TiYKQKgLhgH1" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-138.0117957822, -251.0006770411)" d="M 128.754608 259.999939 C 128.755646 246.860184 128.725449 234.220322 128.771347 221.580719 C 128.793991 215.347488 130.520416 213.708328 136.863113 213.589539 C 144.91658 213.438705 147.143906 214.965347 147.185333 221.54248 C 147.308914 241.166443 147.307388 260.792145 147.187988 280.416138 C 147.147873 287.011322 144.90448 288.569672 136.904938 288.411011 C 130.379074 288.281586 128.797287 286.666046 128.763519 279.958496 C 128.730881 273.472443 128.755341 266.986145 128.754608 259.999939 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -161.9853889369 -8.4289790636)" id="8Hekvf9O-OHjgZhJ8rMo2" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-88.0146110631, -241.5710209364)" d="M 90.470505 269.769745 C 88.223045 269.76535 86.368317 269.92099 84.566414 269.680664 C 80.978569 269.202087 78.794708 267.214905 78.789551 263.392487 C 78.769997 248.903625 78.758598 234.414719 78.787582 219.925903 C 78.79512 216.155106 80.837402 214.149902 84.53833 213.660339 C 94.495842 212.34314 97.243431 214.705841 97.25354 224.729874 C 97.2658 236.887299 97.219048 249.04483 97.259071 261.202118 C 97.273911 265.708801 95.936394 269.0802 90.470505 269.769745 z" stroke-linecap="round" /> +</g> + <g transform="matrix(1 0 0 1 -136.9919327036 -20.8348662725)" id="aZ-DbO6E3jqPfEiZIEpjX" > +<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #DBD5CB; fill-rule: nonzero; opacity: 1;" transform=" translate(-113.0080672964, -229.1651337275)" d="M 117.90834 244.256958 C 115.70591 244.538742 113.887573 244.803146 112.071442 244.788712 C 105.681915 244.737976 103.807259 242.837769 103.760071 236.413605 C 103.720932 231.084427 103.665596 225.752548 103.789619 220.425873 C 103.903732 215.52475 105.81395 213.825058 111.026039 213.59137 C 118.825111 213.241699 121.722244 214.651627 122.01783 219.730377 C 122.375107 225.869095 122.440315 232.068161 121.958641 238.188126 C 121.796677 240.246063 119.574173 242.1418 117.90834 244.256958 z" stroke-linecap="round" /> +</g> +</g> +</g> +</svg> \ No newline at end of file diff --git a/public/logo-transparent.svg b/public/logo-light.svg similarity index 100% rename from public/logo-transparent.svg rename to public/logo-light.svg diff --git a/tailwind.config.ts b/tailwind.config.ts index cc08e2f..8d38c45 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -2,7 +2,7 @@ import fluid, { extract, screens, fontSize } from 'fluid-tailwind'; import type { Config } from 'tailwindcss'; const config = { - darkMode: ['class'], + darkMode: ['selector'], content: { files: [ './pages/**/*.{ts,tsx,md,mdx}', diff --git a/yarn.lock b/yarn.lock index 5867860..118de20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -708,6 +708,16 @@ __metadata: languageName: node linkType: hard +"@clerk/themes@npm:^2.2.5": + version: 2.2.5 + resolution: "@clerk/themes@npm:2.2.5" + dependencies: + "@clerk/types": "npm:^4.40.2" + tslib: "npm:2.4.1" + checksum: 10c0/39172cf42fc04ca9f8a5c46619abcb9b22f01d39140e1e2b30c8906b19248ab3ca104ae56b9c6cc79b97dee74bb629be273582bd6cce5e2d37d90b633dbc77aa + languageName: node + linkType: hard + "@clerk/types@npm:^4.40.2": version: 4.40.2 resolution: "@clerk/types@npm:4.40.2" @@ -3060,6 +3070,31 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-dropdown-menu@npm:^2.1.4": + version: 2.1.4 + resolution: "@radix-ui/react-dropdown-menu@npm:2.1.4" + dependencies: + "@radix-ui/primitive": "npm:1.1.1" + "@radix-ui/react-compose-refs": "npm:1.1.1" + "@radix-ui/react-context": "npm:1.1.1" + "@radix-ui/react-id": "npm:1.1.0" + "@radix-ui/react-menu": "npm:2.1.4" + "@radix-ui/react-primitive": "npm:2.0.1" + "@radix-ui/react-use-controllable-state": "npm:1.1.0" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/90ff1f27288b73d000be904773705bbbe4c31204380d4bee55fcd24d82da7638fe29f9577e4cd5d962607927eba4aad6e5600a9bd5e0ee7924a5a1b5e542b437 + languageName: node + linkType: hard + "@radix-ui/react-focus-guards@npm:1.1.1": version: 1.1.1 resolution: "@radix-ui/react-focus-guards@npm:1.1.1" @@ -3128,6 +3163,42 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-menu@npm:2.1.4": + version: 2.1.4 + resolution: "@radix-ui/react-menu@npm:2.1.4" + dependencies: + "@radix-ui/primitive": "npm:1.1.1" + "@radix-ui/react-collection": "npm:1.1.1" + "@radix-ui/react-compose-refs": "npm:1.1.1" + "@radix-ui/react-context": "npm:1.1.1" + "@radix-ui/react-direction": "npm:1.1.0" + "@radix-ui/react-dismissable-layer": "npm:1.1.3" + "@radix-ui/react-focus-guards": "npm:1.1.1" + "@radix-ui/react-focus-scope": "npm:1.1.1" + "@radix-ui/react-id": "npm:1.1.0" + "@radix-ui/react-popper": "npm:1.2.1" + "@radix-ui/react-portal": "npm:1.1.3" + "@radix-ui/react-presence": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.0.1" + "@radix-ui/react-roving-focus": "npm:1.1.1" + "@radix-ui/react-slot": "npm:1.1.1" + "@radix-ui/react-use-callback-ref": "npm:1.1.0" + aria-hidden: "npm:^1.1.1" + react-remove-scroll: "npm:^2.6.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/617b167d110a6866184a562cecd052eef9de3e6f9bfa0780d954629f6a1d09c9dd43cb3f803e3987214f79031a67410fd4d6036c4a4581909edd4bb224ec0f7f + languageName: node + linkType: hard + "@radix-ui/react-popover@npm:^1.1.3": version: 1.1.4 resolution: "@radix-ui/react-popover@npm:1.1.4" @@ -3248,6 +3319,33 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-roving-focus@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-roving-focus@npm:1.1.1" + dependencies: + "@radix-ui/primitive": "npm:1.1.1" + "@radix-ui/react-collection": "npm:1.1.1" + "@radix-ui/react-compose-refs": "npm:1.1.1" + "@radix-ui/react-context": "npm:1.1.1" + "@radix-ui/react-direction": "npm:1.1.0" + "@radix-ui/react-id": "npm:1.1.0" + "@radix-ui/react-primitive": "npm:2.0.1" + "@radix-ui/react-use-callback-ref": "npm:1.1.0" + "@radix-ui/react-use-controllable-state": "npm:1.1.0" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/ee41eb60b0c300ef3bb130f7ca6c7333148669f2a50b841027910158c06be215967880da932ac14b83d130a9ca5ffb33d6a1a0f067d5048f8db2c3884bbd9b85 + languageName: node + linkType: hard + "@radix-ui/react-separator@npm:^1.0.3": version: 1.1.1 resolution: "@radix-ui/react-separator@npm:1.1.1" @@ -10051,6 +10149,16 @@ __metadata: languageName: node linkType: hard +"next-themes@npm:^0.4.4": + version: 0.4.4 + resolution: "next-themes@npm:0.4.4" + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + checksum: 10c0/45d82f968ccfc90f6e6e3cdb95962132f6d1e19eaf614c4e824fc5d079ec522dd50cc196c58da2f000d755b81dbb0caf378c4f512a9e6b6c0a0daa3f99f1a2c7 + languageName: node + linkType: hard + "next@npm:^15.1.4": version: 15.1.4 resolution: "next@npm:15.1.4" @@ -12466,6 +12574,7 @@ __metadata: dependencies: "@arcjet/next": "npm:^1.0.0-alpha.34" "@clerk/nextjs": "npm:^6.9.9" + "@clerk/themes": "npm:^2.2.5" "@codecov/nextjs-webpack-plugin": "npm:^1.7.0" "@content-collections/core": "npm:^0.8.0" "@content-collections/mdx": "npm:^0.2.0" @@ -12486,6 +12595,7 @@ __metadata: "@radix-ui/react-accordion": "npm:^1.2.2" "@radix-ui/react-avatar": "npm:^1.1.2" "@radix-ui/react-dialog": "npm:^1.1.3" + "@radix-ui/react-dropdown-menu": "npm:^2.1.4" "@radix-ui/react-label": "npm:^2.1.0" "@radix-ui/react-popover": "npm:^1.1.3" "@radix-ui/react-separator": "npm:^1.0.3" @@ -12527,6 +12637,7 @@ __metadata: lodash: "npm:^4.17.21" lucide-react: "npm:^0.471.0" next: "npm:^15.1.4" + next-themes: "npm:^0.4.4" postcss: "npm:^8.4.49" prettier: "npm:^3.4.2" prettier-plugin-tailwindcss: "npm:^0.6.9"