feat: enhance header with notification buttons and user dropdown
- Updated header component to include notification buttons with icons. - Introduced a new NavUser component for user-related actions in the sidebar. - Added NotificationDot component for visual notification indicators. - Created UserCard component to display user information. - Implemented UserDropdown for user settings and logout functionality. - Added Avatar component for user images with fallback support. - Refactored Sheet and Tooltip components for consistency and improved styling. - Introduced QueryProvider for managing React Query context. - Updated SidebarProvider to use custom sidebar implementation. - Enhanced mobile detection hook for better responsiveness. - Updated dependencies in yarn.lock for new features and fixes. feat: remove dot
This commit is contained in:
parent
9225d8435a
commit
1d9ab84047
19 changed files with 501 additions and 104 deletions
|
@ -27,9 +27,10 @@
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.0.1",
|
||||||
"@prisma/client": "^6.9.0",
|
"@prisma/client": "^6.9.0",
|
||||||
|
"@radix-ui/react-avatar": "^1.1.10",
|
||||||
"@radix-ui/react-collapsible": "^1.1.11",
|
"@radix-ui/react-collapsible": "^1.1.11",
|
||||||
"@radix-ui/react-dialog": "^1.1.14",
|
"@radix-ui/react-dialog": "^1.1.14",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.14",
|
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||||
"@radix-ui/react-hover-card": "^1.1.13",
|
"@radix-ui/react-hover-card": "^1.1.13",
|
||||||
"@radix-ui/react-label": "^2.1.6",
|
"@radix-ui/react-label": "^2.1.6",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.8",
|
"@radix-ui/react-scroll-area": "^1.2.8",
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
--text-alt: var(--neutral-900);
|
--text-alt: var(--neutral-900);
|
||||||
--text-input: var(--text);
|
--text-input: var(--text);
|
||||||
--text-muted-input: var(--neutral-450);
|
--text-muted-input: var(--neutral-450);
|
||||||
|
--text-muted: var(--neutral-300);
|
||||||
--muted-input: var(--neutral-600);
|
--muted-input: var(--neutral-600);
|
||||||
--background-disabled: var(--neutral-500);
|
--background-disabled: var(--neutral-500);
|
||||||
--text-disabled: var(--neutral-700);
|
--text-disabled: var(--neutral-700);
|
||||||
|
@ -157,6 +158,7 @@
|
||||||
--color-text-alt: var(--text-alt);
|
--color-text-alt: var(--text-alt);
|
||||||
--color-text-input: var(--text-input);
|
--color-text-input: var(--text-input);
|
||||||
--color-text-muted-input: var(--text-muted-input);
|
--color-text-muted-input: var(--text-muted-input);
|
||||||
|
--color-text-muted: var(--text-muted);
|
||||||
--color-muted-input: var(--muted-input);
|
--color-muted-input: var(--muted-input);
|
||||||
|
|
||||||
--color-background-disabled: var(--neutral-500);
|
--color-background-disabled: var(--neutral-500);
|
||||||
|
@ -280,6 +282,7 @@
|
||||||
--text-alt: var(--neutral-900);
|
--text-alt: var(--neutral-900);
|
||||||
--text-input: var(--text);
|
--text-input: var(--text);
|
||||||
--text-muted-input: var(--neutral-450);
|
--text-muted-input: var(--neutral-450);
|
||||||
|
--text-muted: var(--neutral-300);
|
||||||
--muted-input: var(--neutral-500);
|
--muted-input: var(--neutral-500);
|
||||||
--background-disabled: var(--neutral-500);
|
--background-disabled: var(--neutral-500);
|
||||||
--text-disabled: var(--neutral-700);
|
--text-disabled: var(--neutral-700);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ThemeProvider } from '@/components/wrappers/theme-provider';
|
||||||
|
|
||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import './globals.css';
|
import './globals.css';
|
||||||
import { QueryProvider } from '@/components/query-provider';
|
import { QueryProvider } from '@/components/wrappers/query-provider';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'MeetUp',
|
title: 'MeetUp',
|
||||||
|
|
40
src/components/buttons/notification-button.tsx
Normal file
40
src/components/buttons/notification-button.tsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
// DropdownMenuGroup,
|
||||||
|
// DropdownMenuItem,
|
||||||
|
// DropdownMenuLabel,
|
||||||
|
// DropdownMenuPortal,
|
||||||
|
// DropdownMenuSeparator,
|
||||||
|
// DropdownMenuShortcut,
|
||||||
|
// DropdownMenuSub,
|
||||||
|
// DropdownMenuSubContent,
|
||||||
|
// DropdownMenuSubTrigger,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import { NDot, NotificationDot } from '@/components/misc/notification-dot';
|
||||||
|
|
||||||
|
export function NotificationButton({
|
||||||
|
dotVariant,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
dotVariant?: NDot;
|
||||||
|
children: React.ReactNode;
|
||||||
|
} & React.ComponentProps<typeof Button>) {
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button type='button' variant='outline_primary' {...props}>
|
||||||
|
{children}
|
||||||
|
<NotificationDot
|
||||||
|
dotVariant={dotVariant}
|
||||||
|
className='absolute ml-[30px] mt-[30px]'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align='end'></DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
|
@ -6,27 +6,27 @@ import {
|
||||||
SidebarContent,
|
SidebarContent,
|
||||||
SidebarFooter,
|
SidebarFooter,
|
||||||
SidebarGroup,
|
SidebarGroup,
|
||||||
SidebarGroupAction,
|
// SidebarGroupAction,
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
SidebarGroupLabel,
|
SidebarGroupLabel,
|
||||||
SidebarHeader,
|
SidebarHeader,
|
||||||
SidebarInput,
|
// SidebarInput,
|
||||||
SidebarInset,
|
// SidebarInset,
|
||||||
SidebarMenu,
|
SidebarMenu,
|
||||||
SidebarMenuAction,
|
// SidebarMenuAction,
|
||||||
SidebarMenuBadge,
|
// SidebarMenuBadge,
|
||||||
SidebarMenuButton,
|
SidebarMenuButton,
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
SidebarMenuSkeleton,
|
// SidebarMenuSkeleton,
|
||||||
SidebarMenuSub,
|
// SidebarMenuSub,
|
||||||
SidebarMenuSubButton,
|
// SidebarMenuSubButton,
|
||||||
SidebarMenuSubItem,
|
// SidebarMenuSubItem,
|
||||||
SidebarProvider,
|
// SidebarProvider,
|
||||||
SidebarRail,
|
// SidebarRail,
|
||||||
SidebarSeparator,
|
// SidebarSeparator,
|
||||||
SidebarTrigger,
|
// SidebarTrigger,
|
||||||
useSidebar,
|
// useSidebar,
|
||||||
} from '@/components/ui/sidebar';
|
} from '@/components/custom-ui/sidebar';
|
||||||
|
|
||||||
import { ChevronDown } from 'lucide-react';
|
import { ChevronDown } from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
|
@ -39,8 +39,6 @@ import Logo from '@/components/misc/logo';
|
||||||
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
import { ThemePicker } from '@/components/misc/theme-picker';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Star,
|
Star,
|
||||||
CalendarDays,
|
CalendarDays,
|
||||||
|
|
|
@ -466,7 +466,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>) {
|
||||||
<li
|
<li
|
||||||
data-slot='sidebar-menu-item'
|
data-slot='sidebar-menu-item'
|
||||||
data-sidebar='menu-item'
|
data-sidebar='menu-item'
|
||||||
className={cn('group/menu-item relative', className)}
|
className={cn('group/menu-item relative list-none', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
|
@ -1,5 +1,22 @@
|
||||||
import { SidebarTrigger } from '@/components/ui/sidebar';
|
import { SidebarTrigger } from '@/components/custom-ui/sidebar';
|
||||||
import { ThemePicker } from '@/components/misc/theme-picker';
|
import { ThemePicker } from '@/components/misc/theme-picker';
|
||||||
|
import { NotificationButton } from '@/components/buttons/notification-button';
|
||||||
|
|
||||||
|
import { BellRing, Inbox } from 'lucide-react';
|
||||||
|
import UserDropdown from '@/components/misc/user-dropdown';
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
title: 'Calendar',
|
||||||
|
url: '#',
|
||||||
|
icon: Inbox,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Friends',
|
||||||
|
url: '#',
|
||||||
|
icon: BellRing,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function Header({
|
export default function Header({
|
||||||
children,
|
children,
|
||||||
|
@ -8,13 +25,24 @@ export default function Header({
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<div className='w-full grid grid-rows-[50px_1fr] h-screen'>
|
<div className='w-full grid grid-rows-[50px_1fr] h-screen'>
|
||||||
<header className='border-b-1 grid-cols-[1fr_3fr_1fr] grid items-center px-2'>
|
<header className='border-b-1 grid-cols-[1fr_3fr_1fr] grid items-center px-2 shadow-md'>
|
||||||
<span className='flex justify-start'>
|
<span className='flex justify-start'>
|
||||||
<SidebarTrigger variant='outline_primary' size='icon' />
|
<SidebarTrigger variant='outline_primary' size='icon' />
|
||||||
</span>
|
</span>
|
||||||
<span className='flex justify-center'>Search</span>
|
<span className='flex justify-center'>Search</span>
|
||||||
<span className='flex justify-end'>
|
<span className='flex gap-1 justify-end'>
|
||||||
<ThemePicker />
|
<ThemePicker />
|
||||||
|
{items.map((item) => (
|
||||||
|
<NotificationButton
|
||||||
|
key={item.title}
|
||||||
|
variant='outline_primary'
|
||||||
|
dotVariant='hidden'
|
||||||
|
size='icon'
|
||||||
|
>
|
||||||
|
<item.icon />
|
||||||
|
</NotificationButton>
|
||||||
|
))}
|
||||||
|
<UserDropdown />
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
<main>{children}</main>
|
<main>{children}</main>
|
||||||
|
|
110
src/components/misc/nav-user.tsx
Normal file
110
src/components/misc/nav-user.tsx
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BadgeCheck,
|
||||||
|
Bell,
|
||||||
|
ChevronsUpDown,
|
||||||
|
CreditCard,
|
||||||
|
LogOut,
|
||||||
|
Sparkles,
|
||||||
|
} from 'lucide-react';
|
||||||
|
|
||||||
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuGroup,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import {
|
||||||
|
SidebarMenu,
|
||||||
|
SidebarMenuButton,
|
||||||
|
SidebarMenuItem,
|
||||||
|
useSidebar,
|
||||||
|
} from '@/components/custom-ui/sidebar';
|
||||||
|
|
||||||
|
export function NavUser({
|
||||||
|
user,
|
||||||
|
}: {
|
||||||
|
user: {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
avatar: string;
|
||||||
|
};
|
||||||
|
}) {
|
||||||
|
const { isMobile } = useSidebar();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarMenu>
|
||||||
|
<SidebarMenuItem>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<SidebarMenuButton
|
||||||
|
size='lg'
|
||||||
|
className='data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground'
|
||||||
|
>
|
||||||
|
<Avatar className='h-8 w-8 rounded-lg'>
|
||||||
|
<AvatarImage src={user.avatar} alt={user.name} />
|
||||||
|
<AvatarFallback className='rounded-lg'>CN</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div className='grid flex-1 text-left text-sm leading-tight'>
|
||||||
|
<span className='truncate font-medium'>{user.name}</span>
|
||||||
|
<span className='truncate text-xs'>{user.email}</span>
|
||||||
|
</div>
|
||||||
|
<ChevronsUpDown className='ml-auto size-4' />
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent
|
||||||
|
className='w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg'
|
||||||
|
side={isMobile ? 'bottom' : 'right'}
|
||||||
|
align='end'
|
||||||
|
sideOffset={4}
|
||||||
|
>
|
||||||
|
<DropdownMenuLabel className='p-0 font-normal'>
|
||||||
|
<div className='flex items-center gap-2 px-1 py-1.5 text-left text-sm'>
|
||||||
|
<Avatar className='h-8 w-8 rounded-lg'>
|
||||||
|
<AvatarImage src={user.avatar} alt={user.name} />
|
||||||
|
<AvatarFallback className='rounded-lg'>CN</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div className='grid flex-1 text-left text-sm leading-tight'>
|
||||||
|
<span className='truncate font-medium'>{user.name}</span>
|
||||||
|
<span className='truncate text-xs'>{user.email}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuLabel>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuGroup>
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<Sparkles />
|
||||||
|
Upgrade to Pro
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuGroup>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuGroup>
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<BadgeCheck />
|
||||||
|
Account
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<CreditCard />
|
||||||
|
Billing
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<Bell />
|
||||||
|
Notifications
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuGroup>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<LogOut />
|
||||||
|
Log out
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</SidebarMenuItem>
|
||||||
|
</SidebarMenu>
|
||||||
|
);
|
||||||
|
}
|
35
src/components/misc/notification-dot.tsx
Normal file
35
src/components/misc/notification-dot.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
import { CircleSmall } from 'lucide-react';
|
||||||
|
|
||||||
|
const dotVariants = cva('', {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
neutral: 'fill-neutral-900',
|
||||||
|
active: 'fill-red-600 stroke-red-600',
|
||||||
|
hidden: 'hidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'hidden',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function NotificationDot({
|
||||||
|
className,
|
||||||
|
dotVariant,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
className: string;
|
||||||
|
dotVariant: VariantProps<typeof dotVariants>['variant'];
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<CircleSmall
|
||||||
|
className={cn(dotVariants({ variant: dotVariant }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NDot = VariantProps<typeof dotVariants>['variant'];
|
||||||
|
export { NotificationDot, dotVariants };
|
29
src/components/misc/user-card.tsx
Normal file
29
src/components/misc/user-card.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { useGetApiUserMe } from '@/generated/api/user/user';
|
||||||
|
import { Avatar } from '@/components/ui/avatar';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import { User } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function UserCard() {
|
||||||
|
const { data } = useGetApiUserMe();
|
||||||
|
return (
|
||||||
|
<div className='w-full'>
|
||||||
|
<Avatar className='flex justify-center items-center'>
|
||||||
|
{data?.data.user.image ? (
|
||||||
|
<Image
|
||||||
|
className='border-2 rounded-md'
|
||||||
|
src={data?.data.user.image}
|
||||||
|
alt='Avatar'
|
||||||
|
width='50'
|
||||||
|
height='50'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<User />
|
||||||
|
)}
|
||||||
|
</Avatar>
|
||||||
|
<div className='flex justify-center'>{data?.data.user.name}</div>
|
||||||
|
<div className='flex justify-center text-text-muted'>
|
||||||
|
{data?.data.user.email}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
59
src/components/misc/user-dropdown.tsx
Normal file
59
src/components/misc/user-dropdown.tsx
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Avatar } from '@/components/ui/avatar';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuGroup,
|
||||||
|
DropdownMenuItem,
|
||||||
|
// DropdownMenuLabel,
|
||||||
|
// DropdownMenuPortal,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
// DropdownMenuShortcut,
|
||||||
|
// DropdownMenuSub,
|
||||||
|
// DropdownMenuSubContent,
|
||||||
|
// DropdownMenuSubTrigger,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import { useGetApiUserMe } from '@/generated/api/user/user';
|
||||||
|
import { ChevronDown, User } from 'lucide-react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import UserCard from '@/components/misc/user-card';
|
||||||
|
|
||||||
|
export default function UserDropdown() {
|
||||||
|
const { data } = useGetApiUserMe();
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant='outline_primary'>
|
||||||
|
<Avatar className='flex justify-center items-center'>
|
||||||
|
{data?.data.user.image ? (
|
||||||
|
<Image
|
||||||
|
src={data?.data.user.image}
|
||||||
|
alt='Avatar'
|
||||||
|
width='20'
|
||||||
|
height='20'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<User />
|
||||||
|
)}
|
||||||
|
</Avatar>
|
||||||
|
<ChevronDown />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align='end'>
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<UserCard />
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<Link href='/logout'>Logout</Link>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
53
src/components/ui/avatar.tsx
Normal file
53
src/components/ui/avatar.tsx
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
function Avatar({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
||||||
|
return (
|
||||||
|
<AvatarPrimitive.Root
|
||||||
|
data-slot='avatar'
|
||||||
|
className={cn(
|
||||||
|
'relative flex shrink-0 overflow-hidden rounded-md',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AvatarImage({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
||||||
|
return (
|
||||||
|
<AvatarPrimitive.Image
|
||||||
|
data-slot='avatar-image'
|
||||||
|
className={cn('aspect-square size-full', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AvatarFallback({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
||||||
|
return (
|
||||||
|
<AvatarPrimitive.Fallback
|
||||||
|
data-slot='avatar-fallback'
|
||||||
|
className={cn(
|
||||||
|
'bg-muted flex size-full items-center justify-center rounded-full',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Avatar, AvatarImage, AvatarFallback };
|
|
@ -1,31 +1,31 @@
|
||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
import * as SheetPrimitive from '@radix-ui/react-dialog';
|
||||||
import { XIcon } from "lucide-react"
|
import { XIcon } from 'lucide-react';
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
||||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />
|
return <SheetPrimitive.Root data-slot='sheet' {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetTrigger({
|
function SheetTrigger({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
||||||
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
return <SheetPrimitive.Trigger data-slot='sheet-trigger' {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetClose({
|
function SheetClose({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
||||||
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
|
return <SheetPrimitive.Close data-slot='sheet-close' {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetPortal({
|
function SheetPortal({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
||||||
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
|
return <SheetPrimitive.Portal data-slot='sheet-portal' {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetOverlay({
|
function SheetOverlay({
|
||||||
|
@ -34,71 +34,71 @@ function SheetOverlay({
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
||||||
return (
|
return (
|
||||||
<SheetPrimitive.Overlay
|
<SheetPrimitive.Overlay
|
||||||
data-slot="sheet-overlay"
|
data-slot='sheet-overlay'
|
||||||
className={cn(
|
className={cn(
|
||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetContent({
|
function SheetContent({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
side = "right",
|
side = 'right',
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
||||||
side?: "top" | "right" | "bottom" | "left"
|
side?: 'top' | 'right' | 'bottom' | 'left';
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<SheetPortal>
|
<SheetPortal>
|
||||||
<SheetOverlay />
|
<SheetOverlay />
|
||||||
<SheetPrimitive.Content
|
<SheetPrimitive.Content
|
||||||
data-slot="sheet-content"
|
data-slot='sheet-content'
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
||||||
side === "right" &&
|
side === 'right' &&
|
||||||
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
|
'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
|
||||||
side === "left" &&
|
side === 'left' &&
|
||||||
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
|
'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
|
||||||
side === "top" &&
|
side === 'top' &&
|
||||||
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
|
'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
|
||||||
side === "bottom" &&
|
side === 'bottom' &&
|
||||||
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
|
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
<SheetPrimitive.Close className='ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none'>
|
||||||
<XIcon className="size-4" />
|
<XIcon className='size-4' />
|
||||||
<span className="sr-only">Close</span>
|
<span className='sr-only'>Close</span>
|
||||||
</SheetPrimitive.Close>
|
</SheetPrimitive.Close>
|
||||||
</SheetPrimitive.Content>
|
</SheetPrimitive.Content>
|
||||||
</SheetPortal>
|
</SheetPortal>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="sheet-header"
|
data-slot='sheet-header'
|
||||||
className={cn("flex flex-col gap-1.5 p-4", className)}
|
className={cn('flex flex-col gap-1.5 p-4', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
|
function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="sheet-footer"
|
data-slot='sheet-footer'
|
||||||
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetTitle({
|
function SheetTitle({
|
||||||
|
@ -107,11 +107,11 @@ function SheetTitle({
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Title>) {
|
}: React.ComponentProps<typeof SheetPrimitive.Title>) {
|
||||||
return (
|
return (
|
||||||
<SheetPrimitive.Title
|
<SheetPrimitive.Title
|
||||||
data-slot="sheet-title"
|
data-slot='sheet-title'
|
||||||
className={cn("text-foreground font-semibold", className)}
|
className={cn('text-foreground font-semibold', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetDescription({
|
function SheetDescription({
|
||||||
|
@ -120,11 +120,11 @@ function SheetDescription({
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Description>) {
|
}: React.ComponentProps<typeof SheetPrimitive.Description>) {
|
||||||
return (
|
return (
|
||||||
<SheetPrimitive.Description
|
<SheetPrimitive.Description
|
||||||
data-slot="sheet-description"
|
data-slot='sheet-description'
|
||||||
className={cn("text-muted-foreground text-sm", className)}
|
className={cn('text-muted-foreground text-sm', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -136,4 +136,4 @@ export {
|
||||||
SheetFooter,
|
SheetFooter,
|
||||||
SheetTitle,
|
SheetTitle,
|
||||||
SheetDescription,
|
SheetDescription,
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="skeleton"
|
data-slot='skeleton'
|
||||||
className={cn("bg-accent animate-pulse rounded-md", className)}
|
className={cn('bg-accent animate-pulse rounded-md', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Skeleton }
|
export { Skeleton };
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"use client"
|
'use client';
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
function TooltipProvider({
|
function TooltipProvider({
|
||||||
delayDuration = 0,
|
delayDuration = 0,
|
||||||
|
@ -11,11 +11,11 @@ function TooltipProvider({
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
||||||
return (
|
return (
|
||||||
<TooltipPrimitive.Provider
|
<TooltipPrimitive.Provider
|
||||||
data-slot="tooltip-provider"
|
data-slot='tooltip-provider'
|
||||||
delayDuration={delayDuration}
|
delayDuration={delayDuration}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Tooltip({
|
function Tooltip({
|
||||||
|
@ -23,15 +23,15 @@ function Tooltip({
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
<TooltipPrimitive.Root data-slot='tooltip' {...props} />
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TooltipTrigger({
|
function TooltipTrigger({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
||||||
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
return <TooltipPrimitive.Trigger data-slot='tooltip-trigger' {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TooltipContent({
|
function TooltipContent({
|
||||||
|
@ -43,19 +43,19 @@ function TooltipContent({
|
||||||
return (
|
return (
|
||||||
<TooltipPrimitive.Portal>
|
<TooltipPrimitive.Portal>
|
||||||
<TooltipPrimitive.Content
|
<TooltipPrimitive.Content
|
||||||
data-slot="tooltip-content"
|
data-slot='tooltip-content'
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
'bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
<TooltipPrimitive.Arrow className='bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]' />
|
||||||
</TooltipPrimitive.Content>
|
</TooltipPrimitive.Content>
|
||||||
</TooltipPrimitive.Portal>
|
</TooltipPrimitive.Portal>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SidebarProvider } from '../ui/sidebar';
|
import { SidebarProvider } from '../custom-ui/sidebar';
|
||||||
|
|
||||||
export default function SidebarProviderWrapper({
|
export default function SidebarProviderWrapper({
|
||||||
defaultOpen,
|
defaultOpen,
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
import * as React from "react"
|
import * as React from 'react';
|
||||||
|
|
||||||
const MOBILE_BREAKPOINT = 768
|
const MOBILE_BREAKPOINT = 768;
|
||||||
|
|
||||||
export function useIsMobile() {
|
export function useIsMobile() {
|
||||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
|
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
||||||
}
|
};
|
||||||
mql.addEventListener("change", onChange)
|
mql.addEventListener('change', onChange);
|
||||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
||||||
return () => mql.removeEventListener("change", onChange)
|
return () => mql.removeEventListener('change', onChange);
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
return !!isMobile
|
return !!isMobile;
|
||||||
}
|
}
|
||||||
|
|
45
yarn.lock
45
yarn.lock
|
@ -1299,6 +1299,29 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@radix-ui/react-avatar@npm:^1.1.10":
|
||||||
|
version: 1.1.10
|
||||||
|
resolution: "@radix-ui/react-avatar@npm:1.1.10"
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-context": "npm:1.1.2"
|
||||||
|
"@radix-ui/react-primitive": "npm:2.1.3"
|
||||||
|
"@radix-ui/react-use-callback-ref": "npm:1.1.1"
|
||||||
|
"@radix-ui/react-use-is-hydrated": "npm:0.1.0"
|
||||||
|
"@radix-ui/react-use-layout-effect": "npm:1.1.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/9fb0cf9a9d0fdbeaa2efda476402fc09db2e6ff9cd9aa3ea1d315d9c9579840722a4833725cb196c455e0bd775dfe04221a4f6855685ce89d2133c42e2b07e5f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@radix-ui/react-collapsible@npm:^1.1.11":
|
"@radix-ui/react-collapsible@npm:^1.1.11":
|
||||||
version: 1.1.11
|
version: 1.1.11
|
||||||
resolution: "@radix-ui/react-collapsible@npm:1.1.11"
|
resolution: "@radix-ui/react-collapsible@npm:1.1.11"
|
||||||
|
@ -1441,7 +1464,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@radix-ui/react-dropdown-menu@npm:^2.1.14":
|
"@radix-ui/react-dropdown-menu@npm:^2.1.15":
|
||||||
version: 2.1.15
|
version: 2.1.15
|
||||||
resolution: "@radix-ui/react-dropdown-menu@npm:2.1.15"
|
resolution: "@radix-ui/react-dropdown-menu@npm:2.1.15"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1951,6 +1974,21 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@radix-ui/react-use-is-hydrated@npm:0.1.0":
|
||||||
|
version: 0.1.0
|
||||||
|
resolution: "@radix-ui/react-use-is-hydrated@npm:0.1.0"
|
||||||
|
dependencies:
|
||||||
|
use-sync-external-store: "npm:^1.5.0"
|
||||||
|
peerDependencies:
|
||||||
|
"@types/react": "*"
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
peerDependenciesMeta:
|
||||||
|
"@types/react":
|
||||||
|
optional: true
|
||||||
|
checksum: 10c0/635079bafe32829fc7405895154568ea94a22689b170489fd6d77668e4885e72ff71ed6d0ea3d602852841ef0f1927aa400fee2178d5dfbeb8bc9297da7d6498
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@radix-ui/react-use-layout-effect@npm:1.1.1":
|
"@radix-ui/react-use-layout-effect@npm:1.1.1":
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1"
|
resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1"
|
||||||
|
@ -6637,9 +6675,10 @@ __metadata:
|
||||||
"@fortawesome/react-fontawesome": "npm:^0.2.2"
|
"@fortawesome/react-fontawesome": "npm:^0.2.2"
|
||||||
"@hookform/resolvers": "npm:^5.0.1"
|
"@hookform/resolvers": "npm:^5.0.1"
|
||||||
"@prisma/client": "npm:^6.9.0"
|
"@prisma/client": "npm:^6.9.0"
|
||||||
|
"@radix-ui/react-avatar": "npm:^1.1.10"
|
||||||
"@radix-ui/react-collapsible": "npm:^1.1.11"
|
"@radix-ui/react-collapsible": "npm:^1.1.11"
|
||||||
"@radix-ui/react-dialog": "npm:^1.1.14"
|
"@radix-ui/react-dialog": "npm:^1.1.14"
|
||||||
"@radix-ui/react-dropdown-menu": "npm:^2.1.14"
|
"@radix-ui/react-dropdown-menu": "npm:^2.1.15"
|
||||||
"@radix-ui/react-hover-card": "npm:^1.1.13"
|
"@radix-ui/react-hover-card": "npm:^1.1.13"
|
||||||
"@radix-ui/react-label": "npm:^2.1.6"
|
"@radix-ui/react-label": "npm:^2.1.6"
|
||||||
"@radix-ui/react-scroll-area": "npm:^1.2.8"
|
"@radix-ui/react-scroll-area": "npm:^1.2.8"
|
||||||
|
@ -9394,7 +9433,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"use-sync-external-store@npm:^1.4.0":
|
"use-sync-external-store@npm:^1.4.0, use-sync-external-store@npm:^1.5.0":
|
||||||
version: 1.5.0
|
version: 1.5.0
|
||||||
resolution: "use-sync-external-store@npm:1.5.0"
|
resolution: "use-sync-external-store@npm:1.5.0"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue