Enhance admin panel with new features and UI improvements. Add remote image patterns to Next.js config for Unsplash integration. Update package.json with new dependencies including Radix UI components and date-fns. Refactor layout components to include a header in the admin layout, improve styling in notifications and side navigation, and enhance the booking and dashboard pages for better user experience.
This commit is contained in:
parent
7a6a2a3a20
commit
ce73cbde6c
211
app/(admin)/_components/header.tsx
Normal file
211
app/(admin)/_components/header.tsx
Normal file
@ -0,0 +1,211 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import {
|
||||
Inbox,
|
||||
Calendar,
|
||||
LayoutGrid,
|
||||
Heart,
|
||||
UserCog,
|
||||
Bell,
|
||||
Settings,
|
||||
LogOut,
|
||||
} from "lucide-react";
|
||||
|
||||
export function Header() {
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const [notificationsOpen, setNotificationsOpen] = useState(false);
|
||||
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
||||
|
||||
// Mock notifications data
|
||||
const notifications = [
|
||||
{
|
||||
id: 1,
|
||||
title: "New appointment scheduled",
|
||||
message: "John Smith booked an appointment for tomorrow",
|
||||
time: "2 hours ago",
|
||||
type: "info",
|
||||
read: false,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Payment received",
|
||||
message: "Payment of $150 received from Jane Doe",
|
||||
time: "5 hours ago",
|
||||
type: "success",
|
||||
read: false,
|
||||
},
|
||||
];
|
||||
|
||||
const unreadCount = notifications.filter((n) => !n.read).length;
|
||||
|
||||
return (
|
||||
<header className="bg-white border-b border-gray-200 fixed top-0 left-0 right-0 z-50">
|
||||
<div className="px-3 sm:px-4 md:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between h-14 sm:h-16">
|
||||
{/* Logo */}
|
||||
<Link href="/dashboard" className="flex items-center gap-2 sm:gap-3">
|
||||
<div className="flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-linear-to-r from-rose-100 to-pink-100">
|
||||
<Heart className="w-4 h-4 sm:w-6 sm:h-6 text-rose-600" fill="currentColor" />
|
||||
</div>
|
||||
<span className="text-base sm:text-lg md:text-xl font-semibold text-gray-900 hidden sm:inline">Attune Heart</span>
|
||||
</Link>
|
||||
|
||||
{/* Navigation Links */}
|
||||
<nav className="flex items-center gap-0.5 sm:gap-1">
|
||||
<Link
|
||||
href="/dashboard"
|
||||
className={`flex items-center gap-1 sm:gap-2 px-2 sm:px-3 md:px-4 py-1.5 sm:py-2 rounded-lg text-xs sm:text-sm font-medium transition-colors ${
|
||||
pathname === "/dashboard"
|
||||
? "bg-linear-to-r from-rose-500 to-pink-600 text-white"
|
||||
: "text-gray-600 hover:bg-gray-100"
|
||||
}`}
|
||||
>
|
||||
<LayoutGrid className="w-4 h-4 sm:w-5 sm:h-5" />
|
||||
<span className="hidden sm:inline">Dashboard</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/booking"
|
||||
className={`flex items-center gap-1 sm:gap-2 px-2 sm:px-3 md:px-4 py-1.5 sm:py-2 rounded-lg text-xs sm:text-sm font-medium transition-colors ${
|
||||
pathname === "/booking"
|
||||
? "bg-linear-to-r from-rose-500 to-pink-600 text-white"
|
||||
: "text-gray-600 hover:bg-gray-100"
|
||||
}`}
|
||||
>
|
||||
<Calendar className="w-4 h-4 sm:w-5 sm:h-5" />
|
||||
<span className="hidden sm:inline">Book Appointment</span>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
{/* Right Side Actions */}
|
||||
<div className="flex items-center gap-1.5 sm:gap-2 md:gap-3">
|
||||
<Popover open={notificationsOpen} onOpenChange={setNotificationsOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="relative w-8 h-8 sm:w-9 sm:h-9 md:w-10 md:h-10 cursor-pointer">
|
||||
<Inbox className="w-5 h-5 sm:w-6 sm:h-6 md:w-8 md:h-8 text-gray-600" />
|
||||
{unreadCount > 0 && (
|
||||
<span className="absolute top-0.5 right-0.5 sm:top-1 sm:right-1 w-1.5 h-1.5 sm:w-2 sm:h-2 bg-green-500 rounded-full"></span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[calc(100vw-2rem)] sm:w-80 md:w-96 p-0 bg-white shadow-xl" align="end">
|
||||
{/* Thumbtack Design at Top Right */}
|
||||
<div className="relative">
|
||||
<div className="absolute -top-2 right-8 w-4 h-4 bg-white border-l border-t border-gray-200 rotate-45"></div>
|
||||
<div className="absolute -top-1 right-8 w-2 h-2 bg-white translate-x-1/2"></div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-4 border-b">
|
||||
<h3 className="font-semibold text-gray-900">Notifications</h3>
|
||||
{unreadCount > 0 && (
|
||||
<span className="px-2 py-1 text-xs font-medium bg-rose-100 text-rose-700 rounded-full">
|
||||
{unreadCount} new
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="max-h-96 overflow-y-auto">
|
||||
{notifications.length === 0 ? (
|
||||
<div className="p-8 text-center text-gray-500">
|
||||
<Bell className="w-12 h-12 mx-auto mb-2 text-gray-300" />
|
||||
<p className="text-sm">No notifications</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="divide-y">
|
||||
{notifications.map((notification) => {
|
||||
return (
|
||||
<div
|
||||
key={notification.id}
|
||||
className={`p-4 hover:bg-gray-50 transition-colors cursor-pointer ${
|
||||
!notification.read ? "bg-rose-50/50" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<p
|
||||
className={`text-sm font-medium text-gray-900 ${
|
||||
!notification.read ? "font-semibold" : ""
|
||||
}`}
|
||||
>
|
||||
{notification.title}
|
||||
</p>
|
||||
{!notification.read && (
|
||||
<span className="shrink-0 w-2 h-2 bg-green-500 rounded-full mt-1"></span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 mt-1">
|
||||
{notification.message}
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 mt-1">
|
||||
{notification.time}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-3 border-t bg-gray-50">
|
||||
<Link
|
||||
href="/notifications"
|
||||
onClick={() => setNotificationsOpen(false)}
|
||||
className="block w-full text-center text-sm font-medium text-rose-600 hover:text-rose-700 hover:underline transition-colors"
|
||||
>
|
||||
View all notifications
|
||||
</Link>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Popover open={userMenuOpen} onOpenChange={setUserMenuOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="rounded-full bg-linear-to-r from-rose-100 to-pink-100 hover:from-rose-200 hover:to-pink-200 cursor-pointer w-8 h-8 sm:w-9 sm:h-9 md:w-10 md:h-10">
|
||||
<UserCog className="w-4 h-4 sm:w-5 sm:h-5 text-rose-600" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-56 sm:w-64 p-0 bg-white shadow-xl" align="end">
|
||||
{/* Thumbtack Design at Top Right */}
|
||||
<div className="relative">
|
||||
<div className="absolute -top-2 right-8 w-4 h-4 bg-white border-l border-t border-gray-200 rotate-45"></div>
|
||||
<div className="absolute -top-1 right-8 w-2 h-2 bg-white translate-x-1/2"></div>
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setUserMenuOpen(false);
|
||||
// Add settings navigation here
|
||||
}}
|
||||
className="w-full flex items-center gap-3 px-4 py-3 justify-start hover:bg-gray-50 transition-colors cursor-pointer"
|
||||
>
|
||||
<Settings className="w-5 h-5 text-gray-600" />
|
||||
<span className="text-sm font-medium text-gray-900">Settings</span>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setUserMenuOpen(false);
|
||||
router.push("/");
|
||||
}}
|
||||
className="w-full flex items-center gap-3 px-4 py-3 justify-start hover:bg-gray-50 transition-colors cursor-pointer"
|
||||
>
|
||||
<LogOut className="w-5 h-5 text-red-500" />
|
||||
<span className="text-sm font-medium text-red-500">Logout</span>
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ export function Notifications({
|
||||
<Bell className="w-6 h-6 text-gray-900" />
|
||||
<h2 className="text-2xl font-bold text-gray-900">Notifications</h2>
|
||||
{unreadCount > 0 && (
|
||||
<span className="px-2.5 py-0.5 bg-gradient-to-r from-rose-500 to-pink-500 text-white text-sm font-medium rounded-full">
|
||||
<span className="px-2.5 py-0.5 bg-linear-to-r from-rose-500 to-pink-500 text-white text-sm font-medium rounded-full">
|
||||
{unreadCount}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
LayoutGrid,
|
||||
Calendar,
|
||||
@ -21,6 +22,7 @@ const navItems = [
|
||||
export default function SideNav() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
|
||||
const getActiveIndex = () => {
|
||||
return navItems.findIndex((item) => pathname?.includes(item.href)) ?? -1;
|
||||
@ -43,14 +45,19 @@ export default function SideNav() {
|
||||
{/* Mobile Top Bar */}
|
||||
<div className="flex md:hidden items-center justify-between px-4 py-3 border-b border-gray-200 bg-white z-30 fixed top-0 left-0 right-0">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-br from-rose-100 to-pink-100">
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-linear-to-r from-rose-100 to-pink-100">
|
||||
<Heart className="w-5 h-5 text-rose-600" fill="currentColor" />
|
||||
</div>
|
||||
<span className="text-lg font-semibold text-gray-900">Attune Heart Therapy</span>
|
||||
</div>
|
||||
<button onClick={() => setOpen((v) => !v)} aria-label="Open menu">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
aria-label="Open menu"
|
||||
>
|
||||
{open ? <X size={28} /> : <Menu size={28} />}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Drawer Overlay */}
|
||||
@ -68,16 +75,16 @@ export default function SideNav() {
|
||||
} md:translate-x-0`}
|
||||
>
|
||||
{/* Logo Section */}
|
||||
<div className="flex-shrink-0 px-3 pb-4 flex flex-col gap-1 md:block mb-5 pt-16 md:pt-4">
|
||||
<div className="shrink-0 px-3 pb-4 flex flex-col gap-1 md:block mb-5 pt-16 md:pt-4">
|
||||
<div className="flex items-center gap-2 mb-1 ml-2 md:ml-3">
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-br from-rose-100 to-pink-100">
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-linear-to-r from-rose-100 to-pink-100">
|
||||
<Heart className="w-5 h-5 text-rose-600" fill="currentColor" />
|
||||
</div>
|
||||
<span className="text-sm font-semibold text-gray-900">Attune Heart</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="flex-shrink-0 -mt-10 mb-4 mx-3 border-gray-200 md:block hidden" />
|
||||
<hr className="shrink-0 -mt-10 mb-4 mx-3 border-gray-200 md:block hidden" />
|
||||
|
||||
{/* Navigation Items */}
|
||||
<nav className="flex-1 overflow-y-auto flex flex-col gap-2 px-2 md:px-0">
|
||||
@ -89,7 +96,7 @@ export default function SideNav() {
|
||||
<div className="relative flex items-center w-full" key={item.label}>
|
||||
{isActive && (
|
||||
<span
|
||||
className="absolute left-0 top-0 h-[40px] w-[3px] bg-gradient-to-b from-rose-500 to-pink-600"
|
||||
className="absolute left-0 top-0 h-[40px] w-[3px] bg-linear-to-r from-rose-500 to-pink-600"
|
||||
style={{ left: 0 }}
|
||||
/>
|
||||
)}
|
||||
@ -98,7 +105,7 @@ export default function SideNav() {
|
||||
onClick={() => setOpen(false)}
|
||||
className={`group flex items-center gap-2 py-2.5 pl-3 md:pl-3 pr-3 md:pr-3 transition-colors duration-200 focus:outline-none w-[90%] md:w-[90%] ml-1 md:ml-2 cursor-pointer justify-start ${
|
||||
isActive
|
||||
? "bg-gradient-to-r from-rose-500 to-pink-600 text-white border border-rose-500 rounded-[5px] shadow-sm"
|
||||
? "bg-linear-to-r from-rose-500 to-pink-600 text-white border border-rose-500 rounded-[5px] shadow-sm"
|
||||
: "bg-transparent text-gray-600 hover:bg-rose-50 hover:text-rose-600 rounded-lg"
|
||||
}`}
|
||||
style={isActive ? { height: 40 } : {}}
|
||||
@ -135,10 +142,11 @@ export default function SideNav() {
|
||||
Settings
|
||||
</span>
|
||||
</Link>
|
||||
<button
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
// Handle logout
|
||||
router.push("/");
|
||||
}}
|
||||
className="group flex items-center gap-2 py-2.5 pl-3 md:pl-3 pr-3 md:pr-3 transition-colors duration-200 w-[90%] md:w-[90%] ml-1 md:ml-2 cursor-pointer justify-start text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg"
|
||||
>
|
||||
@ -146,7 +154,7 @@ export default function SideNav() {
|
||||
<span className="font-light leading-none text-[12px]" style={{ fontWeight: 300 }}>
|
||||
Logout
|
||||
</span>
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import SideNav from "@/app/(admin)/_components/side-nav";
|
||||
import {
|
||||
Search,
|
||||
Bell,
|
||||
Calendar,
|
||||
Clock,
|
||||
User,
|
||||
DollarSign,
|
||||
Video,
|
||||
FileText,
|
||||
MoreVertical,
|
||||
@ -171,47 +167,20 @@ export default function Booking() {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Side Navigation */}
|
||||
<SideNav />
|
||||
|
||||
<div className="md:ml-[200px]">
|
||||
{/* Top Header Bar */}
|
||||
<div className="bg-white border-b border-gray-200 px-4 sm:px-6 lg:px-8 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex-1 max-w-md">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search bookings..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 ml-4">
|
||||
<button className="relative p-2 hover:bg-gray-100 rounded-lg transition-colors">
|
||||
<Bell className="w-5 h-5 text-gray-600" />
|
||||
<span className="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="p-4 sm:p-6 lg:p-8">
|
||||
<main className="p-3 sm:p-4 md:p-6 lg:p-8">
|
||||
{/* Page Header */}
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="mb-4 sm:mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold text-gray-900 mb-1">
|
||||
<h1 className="text-xl sm:text-2xl font-semibold text-gray-900 mb-1">
|
||||
Bookings
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500">
|
||||
<p className="text-xs sm:text-sm text-gray-500">
|
||||
Manage and view all appointment bookings
|
||||
</p>
|
||||
</div>
|
||||
<button className="px-4 py-2 bg-gray-900 text-white rounded-lg text-sm font-medium hover:bg-gray-800 transition-colors">
|
||||
<button className="w-full sm:w-auto px-3 sm:px-4 py-2 bg-gray-900 text-white rounded-lg text-xs sm:text-sm font-medium hover:bg-gray-800 transition-colors">
|
||||
+ New Booking
|
||||
</button>
|
||||
</div>
|
||||
@ -236,25 +205,25 @@ export default function Booking() {
|
||||
<table className="w-full">
|
||||
<thead className="bg-gray-50 border-b border-gray-200">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Patient
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden md:table-cell">
|
||||
Date & Time
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden lg:table-cell">
|
||||
Duration
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Status
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden lg:table-cell">
|
||||
Payment
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden xl:table-cell">
|
||||
Amount
|
||||
</th>
|
||||
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
<th className="px-3 sm:px-4 md:px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
@ -265,34 +234,37 @@ export default function Booking() {
|
||||
key={booking.ID}
|
||||
className="hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<td className="px-3 sm:px-4 md:px-6 py-4">
|
||||
<div className="flex items-center">
|
||||
<div className="shrink-0 h-10 w-10 rounded-full bg-gray-100 flex items-center justify-center">
|
||||
<User className="w-5 h-5 text-gray-600" />
|
||||
<div className="shrink-0 h-8 w-8 sm:h-10 sm:w-10 rounded-full bg-gray-100 flex items-center justify-center">
|
||||
<User className="w-4 h-4 sm:w-5 sm:h-5 text-gray-600" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<div className="text-sm font-medium text-gray-900">
|
||||
<div className="ml-2 sm:ml-4 min-w-0">
|
||||
<div className="text-xs sm:text-sm font-medium text-gray-900 truncate">
|
||||
{booking.user.first_name} {booking.user.last_name}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
<div className="text-xs sm:text-sm text-gray-500 truncate hidden sm:block">
|
||||
{booking.user.email}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 sm:hidden mt-0.5">
|
||||
{formatDate(booking.scheduled_at)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="text-sm text-gray-900">
|
||||
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap hidden md:table-cell">
|
||||
<div className="text-xs sm:text-sm text-gray-900">
|
||||
{formatDate(booking.scheduled_at)}
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 flex items-center gap-1">
|
||||
<div className="text-xs sm:text-sm text-gray-500 flex items-center gap-1">
|
||||
<Clock className="w-3 h-3" />
|
||||
{formatTime(booking.scheduled_at)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm text-gray-900 hidden lg:table-cell">
|
||||
{booking.duration} min
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap">
|
||||
<span
|
||||
className={`px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full ${getStatusColor(
|
||||
booking.status
|
||||
@ -301,7 +273,7 @@ export default function Booking() {
|
||||
{booking.status}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap hidden lg:table-cell">
|
||||
<span
|
||||
className={`px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full ${getPaymentStatusColor(
|
||||
booking.payment_status
|
||||
@ -310,17 +282,17 @@ export default function Booking() {
|
||||
{booking.payment_status}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
||||
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm font-medium text-gray-900 hidden xl:table-cell">
|
||||
${booking.amount}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<div className="flex items-center justify-end gap-1 sm:gap-2">
|
||||
{booking.jitsi_room_url && (
|
||||
<a
|
||||
href={booking.jitsi_room_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
className="p-1.5 sm:p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
title="Join Meeting"
|
||||
>
|
||||
<Video className="w-4 h-4" />
|
||||
@ -328,13 +300,13 @@ export default function Booking() {
|
||||
)}
|
||||
{booking.notes && (
|
||||
<button
|
||||
className="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
className="p-1.5 sm:p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
title="View Notes"
|
||||
>
|
||||
<FileText className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
<button className="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors">
|
||||
<button className="p-1.5 sm:p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors">
|
||||
<MoreVertical className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
@ -348,7 +320,6 @@ export default function Booking() {
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import SideNav from "@/app/(admin)/_components/side-nav";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Users,
|
||||
UserCheck,
|
||||
@ -10,8 +16,8 @@ import {
|
||||
CalendarX,
|
||||
DollarSign,
|
||||
TrendingUp,
|
||||
Search,
|
||||
Bell,
|
||||
ArrowUpRight,
|
||||
ArrowDownRight,
|
||||
} from "lucide-react";
|
||||
|
||||
interface DashboardStats {
|
||||
@ -28,6 +34,7 @@ interface DashboardStats {
|
||||
export default function Dashboard() {
|
||||
const [stats, setStats] = useState<DashboardStats | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [timePeriod, setTimePeriod] = useState<string>("last_month");
|
||||
|
||||
useEffect(() => {
|
||||
// Simulate API call
|
||||
@ -60,94 +67,86 @@ export default function Dashboard() {
|
||||
title: "Total Users",
|
||||
value: stats?.total_users ?? 0,
|
||||
icon: Users,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-gray-600",
|
||||
trend: "+12%",
|
||||
trendUp: true,
|
||||
},
|
||||
{
|
||||
title: "Active Users",
|
||||
value: stats?.active_users ?? 0,
|
||||
icon: UserCheck,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-gray-600",
|
||||
trend: "+8%",
|
||||
trendUp: true,
|
||||
},
|
||||
{
|
||||
title: "Total Bookings",
|
||||
value: stats?.total_bookings ?? 0,
|
||||
icon: Calendar,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-gray-600",
|
||||
trend: "+24%",
|
||||
trendUp: true,
|
||||
},
|
||||
{
|
||||
title: "Upcoming Bookings",
|
||||
value: stats?.upcoming_bookings ?? 0,
|
||||
icon: CalendarCheck,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-gray-600",
|
||||
trend: "+6",
|
||||
trendUp: true,
|
||||
},
|
||||
{
|
||||
title: "Completed Bookings",
|
||||
value: stats?.completed_bookings ?? 0,
|
||||
icon: CalendarCheck,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-green-600",
|
||||
trend: "0%",
|
||||
trendUp: true,
|
||||
},
|
||||
{
|
||||
title: "Cancelled Bookings",
|
||||
value: stats?.cancelled_bookings ?? 0,
|
||||
icon: CalendarX,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-red-600",
|
||||
trend: "0%",
|
||||
trendUp: false,
|
||||
},
|
||||
{
|
||||
title: "Total Revenue",
|
||||
value: `$${stats?.total_revenue.toLocaleString() ?? 0}`,
|
||||
icon: DollarSign,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-gray-600",
|
||||
trend: "+18%",
|
||||
trendUp: true,
|
||||
},
|
||||
{
|
||||
title: "Monthly Revenue",
|
||||
value: `$${stats?.monthly_revenue.toLocaleString() ?? 0}`,
|
||||
icon: TrendingUp,
|
||||
bgColor: "bg-gray-50",
|
||||
iconColor: "text-gray-600",
|
||||
trend: "+32%",
|
||||
trendUp: true,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Side Navigation */}
|
||||
<SideNav />
|
||||
|
||||
<div className="md:ml-[200px]">
|
||||
{/* Top Header Bar */}
|
||||
<div className="bg-white border-b border-gray-200 px-4 sm:px-6 lg:px-8 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex-1 max-w-md">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search something..."
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 ml-4">
|
||||
<button className="relative p-2 hover:bg-gray-100 rounded-lg transition-colors">
|
||||
<Bell className="w-5 h-5 text-gray-600" />
|
||||
<span className="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="p-4 sm:p-6 lg:p-8">
|
||||
{/* Page Header */}
|
||||
<div className="mb-6">
|
||||
<h1 className="text-2xl font-semibold text-gray-900 mb-1">Dashboard</h1>
|
||||
<p className="text-sm text-gray-500">Overview of your practice statistics</p>
|
||||
<main className="p-4 sm:p-6 lg:p-8 space-y-6">
|
||||
{/* Welcome Section */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold text-gray-900 mb-1">
|
||||
Welcome Back! Hammond
|
||||
</h1>
|
||||
<p className="text-sm text-gray-500">
|
||||
Here's an overview of your practice today
|
||||
</p>
|
||||
</div>
|
||||
<Select value={timePeriod} onValueChange={setTimePeriod}>
|
||||
<SelectTrigger className="w-[180px] cursor-pointer">
|
||||
<SelectValue placeholder="Select period" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="bg-white cursor-pointer">
|
||||
<SelectItem value="last_week">Last Week</SelectItem>
|
||||
<SelectItem value="last_month">Last Month</SelectItem>
|
||||
<SelectItem value="last_year">Last Year</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
@ -155,33 +154,54 @@ export default function Dashboard() {
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-400"></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<>
|
||||
{/* Stats Grid */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 sm:gap-4">
|
||||
{statCards.map((card, index) => {
|
||||
const Icon = card.icon;
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-white rounded-lg border border-gray-200 p-5 hover:shadow-md transition-shadow"
|
||||
className="bg-white rounded-lg border border-gray-200 p-4 sm:p-5 md:p-6 hover:shadow-md transition-shadow"
|
||||
>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className={`p-2.5 rounded-lg ${card.bgColor}`}>
|
||||
<Icon className={`w-5 h-5 ${card.iconColor}`} />
|
||||
<div className="flex items-start justify-between mb-3 sm:mb-4">
|
||||
<div className="p-2 sm:p-2.5 rounded-lg bg-gray-50">
|
||||
<Icon className="w-4 h-4 sm:w-5 sm:h-5 text-gray-600" />
|
||||
</div>
|
||||
<div className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium ${
|
||||
card.trendUp
|
||||
? "bg-green-50 text-green-700"
|
||||
: "bg-red-50 text-red-700"
|
||||
}`}>
|
||||
{card.trendUp ? (
|
||||
<ArrowUpRight className="w-3 h-3" />
|
||||
) : (
|
||||
<ArrowDownRight className="w-3 h-3" />
|
||||
)}
|
||||
<span className="hidden sm:inline">{card.trend}</span>
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-xs font-medium text-gray-500 mb-1 uppercase tracking-wide">
|
||||
|
||||
<div>
|
||||
<h3 className="text-xs font-medium text-rose-600 mb-1 sm:mb-2 uppercase tracking-wider">
|
||||
{card.title}
|
||||
</h3>
|
||||
<p className="text-2xl font-semibold text-gray-900">
|
||||
<p className="text-xl sm:text-2xl font-bold text-gray-900 mb-1">
|
||||
{card.value}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">
|
||||
vs last month
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
import { Header } from "./_components/header";
|
||||
|
||||
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<div className="pt-14 sm:pt-16">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,30 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import SideNav from "@/app/(admin)/_components/side-nav";
|
||||
import { Notifications, Notification } from "@/app/(admin)/_components/notifications";
|
||||
import { Bell } from "lucide-react";
|
||||
|
||||
interface Notification {
|
||||
id: string;
|
||||
title: string;
|
||||
message: string;
|
||||
time: string;
|
||||
read: boolean;
|
||||
}
|
||||
|
||||
export default function NotificationsPage() {
|
||||
const [notifications, setNotifications] = useState<Notification[]>([
|
||||
{
|
||||
id: "1",
|
||||
type: "appointment",
|
||||
title: "New Appointment Request",
|
||||
message: "Sarah Johnson requested an appointment for tomorrow at 2:00 PM",
|
||||
time: "2 minutes ago",
|
||||
title: "New appointment scheduled",
|
||||
message: "John Smith booked an appointment for tomorrow",
|
||||
time: "2 hours ago",
|
||||
read: false,
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
type: "success",
|
||||
title: "Appointment Confirmed",
|
||||
message: "Your appointment with Michael Chen has been confirmed for today at 10:00 AM",
|
||||
time: "1 hour ago",
|
||||
title: "Payment received",
|
||||
message: "Payment of $150 received from Jane Doe",
|
||||
time: "5 hours ago",
|
||||
read: false,
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
type: "warning",
|
||||
title: "Appointment Reminder",
|
||||
message: "You have an appointment in 30 minutes with Emily Davis",
|
||||
time: "3 hours ago",
|
||||
@ -32,7 +36,6 @@ export default function NotificationsPage() {
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
type: "info",
|
||||
title: "New Message",
|
||||
message: "You received a new message from John Smith",
|
||||
time: "5 hours ago",
|
||||
@ -40,7 +43,6 @@ export default function NotificationsPage() {
|
||||
},
|
||||
{
|
||||
id: "5",
|
||||
type: "appointment",
|
||||
title: "Appointment Cancelled",
|
||||
message: "Robert Wilson cancelled his appointment scheduled for tomorrow",
|
||||
time: "1 day ago",
|
||||
@ -48,35 +50,71 @@ export default function NotificationsPage() {
|
||||
},
|
||||
]);
|
||||
|
||||
const handleMarkAsRead = (id: string) => {
|
||||
setNotifications((prev) =>
|
||||
prev.map((n) => (n.id === id ? { ...n, read: true } : n))
|
||||
);
|
||||
};
|
||||
|
||||
const handleDismiss = (id: string) => {
|
||||
setNotifications((prev) => prev.filter((n) => n.id !== id));
|
||||
};
|
||||
|
||||
const handleMarkAllAsRead = () => {
|
||||
setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
|
||||
};
|
||||
const unreadCount = notifications.filter((n) => !n.read).length;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Side Navigation */}
|
||||
<SideNav />
|
||||
{/* Main Content */}
|
||||
<main className="p-3 sm:p-4 md:p-6 lg:p-8">
|
||||
{/* Page Header */}
|
||||
<div className="mb-4 sm:mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<Bell className="w-5 h-5 sm:w-6 sm:h-6 text-gray-900" />
|
||||
<h1 className="text-xl sm:text-2xl font-semibold text-gray-900">
|
||||
Notifications
|
||||
</h1>
|
||||
{unreadCount > 0 && (
|
||||
<span className="px-2 py-1 text-xs font-medium bg-rose-100 text-rose-700 rounded-full">
|
||||
{unreadCount} new
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="md:ml-[250px]">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<Notifications
|
||||
notifications={notifications}
|
||||
onMarkAsRead={handleMarkAsRead}
|
||||
onDismiss={handleDismiss}
|
||||
onMarkAllAsRead={handleMarkAllAsRead}
|
||||
/>
|
||||
{/* Notifications List */}
|
||||
<div className="bg-white rounded-lg border border-gray-200 overflow-hidden">
|
||||
{notifications.length === 0 ? (
|
||||
<div className="p-8 sm:p-12 text-center text-gray-500">
|
||||
<Bell className="w-12 h-12 mx-auto mb-2 text-gray-300" />
|
||||
<p className="text-sm">No notifications</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="divide-y">
|
||||
{notifications.map((notification) => {
|
||||
return (
|
||||
<div
|
||||
key={notification.id}
|
||||
className={`p-4 sm:p-6 hover:bg-gray-50 transition-colors cursor-pointer ${
|
||||
!notification.read ? "bg-rose-50/50" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<p
|
||||
className={`text-sm sm:text-base font-medium text-gray-900 ${
|
||||
!notification.read ? "font-semibold" : ""
|
||||
}`}
|
||||
>
|
||||
{notification.title}
|
||||
</p>
|
||||
{!notification.read && (
|
||||
<span className="shrink-0 w-2 h-2 bg-green-500 rounded-full mt-1"></span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 mt-1">
|
||||
{notification.message}
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 mt-1">
|
||||
{notification.time}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -47,11 +47,10 @@ export default function Login() {
|
||||
className="ml-auto mb-6 w-8 h-8 rounded-full"
|
||||
aria-label="Close"
|
||||
>
|
||||
<X className="w-5 h-5 text-black" />
|
||||
</Button>
|
||||
|
||||
{/* Heading */}
|
||||
<h1 className="text-3xl font-bold bg-gradient-to-r from-rose-600 via-pink-600 to-rose-600 bg-clip-text text-transparent mb-2">
|
||||
<h1 className="text-3xl font-bold bg-linear-to-r from-rose-600 via-pink-600 to-rose-600 bg-clip-text text-transparent mb-2">
|
||||
Welcome back
|
||||
</h1>
|
||||
|
||||
@ -64,7 +63,10 @@ export default function Login() {
|
||||
</p>
|
||||
|
||||
{/* Login Form */}
|
||||
<form className="space-y-6" onSubmit={(e) => e.preventDefault()}>
|
||||
<form className="space-y-6" onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
router.push("/dashboard");
|
||||
}}>
|
||||
{/* Email Field */}
|
||||
<div className="space-y-2">
|
||||
<label htmlFor="email" className="text-sm font-medium text-black">
|
||||
@ -112,7 +114,7 @@ export default function Login() {
|
||||
{/* Submit Button */}
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full h-12 text-base font-semibold bg-gradient-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white shadow-lg hover:shadow-xl transition-all"
|
||||
className="w-full h-12 text-base font-semibold bg-linear-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white shadow-lg hover:shadow-xl transition-all"
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
|
||||
98
components/DatePicker.tsx
Normal file
98
components/DatePicker.tsx
Normal file
@ -0,0 +1,98 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import { Calendar as CalendarIcon } from 'lucide-react';
|
||||
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
|
||||
interface DatePickerProps {
|
||||
date: Date | undefined;
|
||||
setDate: (date: Date | undefined) => void;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export function DatePicker({ date, setDate, label }: DatePickerProps) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
{label && (
|
||||
<label className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
<DropdownMenu open={open} onOpenChange={setOpen}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
size="sm"
|
||||
className={cn(
|
||||
'justify-start text-left font-normal',
|
||||
!date && 'text-muted-foreground'
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{date ? format(date, 'PPP') : <span>Pick a date</span>}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-auto p-5 bg-gradient-to-br from-white to-gray-50 dark:from-gray-800 dark:to-gray-900 shadow-2xl border-2 border-gray-100 dark:border-gray-700 rounded-2xl" align="end" sideOffset={5}>
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={(selectedDate) => {
|
||||
setDate(selectedDate);
|
||||
setOpen(false);
|
||||
}}
|
||||
initialFocus
|
||||
classNames={{
|
||||
months: "space-y-4",
|
||||
month: "space-y-4",
|
||||
caption: "flex justify-center pt-3 pb-5 relative items-center border-b border-gray-200 dark:border-gray-700 mb-4",
|
||||
caption_label: "text-lg font-bold text-gray-800 dark:text-gray-100",
|
||||
nav: "flex items-center justify-between absolute inset-0",
|
||||
nav_button: cn(
|
||||
"h-9 w-9 rounded-full bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 hover:bg-rose-50 dark:hover:bg-gray-600 hover:border-rose-300 dark:hover:border-rose-500 p-0 transition-all shadow-sm"
|
||||
),
|
||||
nav_button_previous: "absolute left-0",
|
||||
nav_button_next: "absolute right-0",
|
||||
table: "w-full border-collapse space-y-3",
|
||||
head_row: "flex mb-3",
|
||||
head_cell: "text-gray-600 dark:text-gray-400 rounded-md w-11 font-semibold text-xs",
|
||||
row: "flex w-full mt-2",
|
||||
cell: cn(
|
||||
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20",
|
||||
"[&>button]:h-11 [&>button]:w-11 [&>button]:p-0 [&>button]:font-semibold [&>button]:cursor-pointer [&>button]:rounded-full [&>button]:transition-all"
|
||||
),
|
||||
day: cn(
|
||||
"h-11 w-11 p-0 font-semibold aria-selected:opacity-100 hover:bg-rose-500 hover:text-white rounded-full transition-all cursor-pointer",
|
||||
"hover:scale-110 active:scale-95 hover:shadow-md"
|
||||
),
|
||||
day_selected:
|
||||
"bg-rose-600 text-white hover:bg-rose-700 hover:text-white focus:bg-rose-600 focus:text-white font-bold shadow-xl scale-110 ring-4 ring-rose-200 dark:ring-rose-800",
|
||||
day_today: "bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 font-bold border-2 border-blue-300 dark:border-blue-600",
|
||||
day_outside: "text-gray-300 dark:text-gray-600 opacity-50",
|
||||
day_disabled: "text-gray-200 dark:text-gray-700 opacity-30 cursor-not-allowed",
|
||||
day_range_middle:
|
||||
"aria-selected:bg-rose-100 dark:aria-selected:bg-rose-900/30 aria-selected:text-rose-700 dark:aria-selected:text-rose-300",
|
||||
day_hidden: "invisible",
|
||||
}}
|
||||
/>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
"cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
216
components/ui/calendar.tsx
Normal file
216
components/ui/calendar.tsx
Normal file
@ -0,0 +1,216 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
} from "lucide-react"
|
||||
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button, buttonVariants } from "@/components/ui/button"
|
||||
|
||||
function Calendar({
|
||||
className,
|
||||
classNames,
|
||||
showOutsideDays = true,
|
||||
captionLayout = "label",
|
||||
buttonVariant = "ghost",
|
||||
formatters,
|
||||
components,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DayPicker> & {
|
||||
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
|
||||
}) {
|
||||
const defaultClassNames = getDefaultClassNames()
|
||||
|
||||
return (
|
||||
<DayPicker
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn(
|
||||
"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
||||
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
||||
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
||||
className
|
||||
)}
|
||||
captionLayout={captionLayout}
|
||||
formatters={{
|
||||
formatMonthDropdown: (date) =>
|
||||
date.toLocaleString("default", { month: "short" }),
|
||||
...formatters,
|
||||
}}
|
||||
classNames={{
|
||||
root: cn("w-fit", defaultClassNames.root),
|
||||
months: cn(
|
||||
"flex gap-4 flex-col md:flex-row relative",
|
||||
defaultClassNames.months
|
||||
),
|
||||
month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
|
||||
nav: cn(
|
||||
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
|
||||
defaultClassNames.nav
|
||||
),
|
||||
button_previous: cn(
|
||||
buttonVariants({ variant: buttonVariant }),
|
||||
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
|
||||
defaultClassNames.button_previous
|
||||
),
|
||||
button_next: cn(
|
||||
buttonVariants({ variant: buttonVariant }),
|
||||
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
|
||||
defaultClassNames.button_next
|
||||
),
|
||||
month_caption: cn(
|
||||
"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
|
||||
defaultClassNames.month_caption
|
||||
),
|
||||
dropdowns: cn(
|
||||
"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
|
||||
defaultClassNames.dropdowns
|
||||
),
|
||||
dropdown_root: cn(
|
||||
"relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
|
||||
defaultClassNames.dropdown_root
|
||||
),
|
||||
dropdown: cn(
|
||||
"absolute bg-popover inset-0 opacity-0",
|
||||
defaultClassNames.dropdown
|
||||
),
|
||||
caption_label: cn(
|
||||
"select-none font-medium",
|
||||
captionLayout === "label"
|
||||
? "text-sm"
|
||||
: "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
|
||||
defaultClassNames.caption_label
|
||||
),
|
||||
table: "w-full border-collapse",
|
||||
weekdays: cn("flex", defaultClassNames.weekdays),
|
||||
weekday: cn(
|
||||
"text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
|
||||
defaultClassNames.weekday
|
||||
),
|
||||
week: cn("flex w-full mt-2", defaultClassNames.week),
|
||||
week_number_header: cn(
|
||||
"select-none w-(--cell-size)",
|
||||
defaultClassNames.week_number_header
|
||||
),
|
||||
week_number: cn(
|
||||
"text-[0.8rem] select-none text-muted-foreground",
|
||||
defaultClassNames.week_number
|
||||
),
|
||||
day: cn(
|
||||
"relative w-full h-full p-0 text-center [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
|
||||
props.showWeekNumber
|
||||
? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
|
||||
: "[&:first-child[data-selected=true]_button]:rounded-l-md",
|
||||
defaultClassNames.day
|
||||
),
|
||||
range_start: cn(
|
||||
"rounded-l-md bg-accent",
|
||||
defaultClassNames.range_start
|
||||
),
|
||||
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
||||
range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
|
||||
today: cn(
|
||||
"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
|
||||
defaultClassNames.today
|
||||
),
|
||||
outside: cn(
|
||||
"text-muted-foreground aria-selected:text-muted-foreground",
|
||||
defaultClassNames.outside
|
||||
),
|
||||
disabled: cn(
|
||||
"text-muted-foreground opacity-50",
|
||||
defaultClassNames.disabled
|
||||
),
|
||||
hidden: cn("invisible", defaultClassNames.hidden),
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
Root: ({ className, rootRef, ...props }) => {
|
||||
return (
|
||||
<div
|
||||
data-slot="calendar"
|
||||
ref={rootRef}
|
||||
className={cn(className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
},
|
||||
Chevron: ({ className, orientation, ...props }) => {
|
||||
if (orientation === "left") {
|
||||
return (
|
||||
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
|
||||
)
|
||||
}
|
||||
|
||||
if (orientation === "right") {
|
||||
return (
|
||||
<ChevronRightIcon
|
||||
className={cn("size-4", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<ChevronDownIcon className={cn("size-4", className)} {...props} />
|
||||
)
|
||||
},
|
||||
DayButton: CalendarDayButton,
|
||||
WeekNumber: ({ children, ...props }) => {
|
||||
return (
|
||||
<td {...props}>
|
||||
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
||||
{children}
|
||||
</div>
|
||||
</td>
|
||||
)
|
||||
},
|
||||
...components,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarDayButton({
|
||||
className,
|
||||
day,
|
||||
modifiers,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DayButton>) {
|
||||
const defaultClassNames = getDefaultClassNames()
|
||||
|
||||
const ref = React.useRef<HTMLButtonElement>(null)
|
||||
React.useEffect(() => {
|
||||
if (modifiers.focused) ref.current?.focus()
|
||||
}, [modifiers.focused])
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
data-day={day.date.toLocaleDateString()}
|
||||
data-selected-single={
|
||||
modifiers.selected &&
|
||||
!modifiers.range_start &&
|
||||
!modifiers.range_end &&
|
||||
!modifiers.range_middle
|
||||
}
|
||||
data-range-start={modifiers.range_start}
|
||||
data-range-end={modifiers.range_end}
|
||||
data-range-middle={modifiers.range_middle}
|
||||
className={cn(
|
||||
"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
|
||||
defaultClassNames.day,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Calendar, CalendarDayButton }
|
||||
257
components/ui/dropdown-menu.tsx
Normal file
257
components/ui/dropdown-menu.tsx
Normal file
@ -0,0 +1,257 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function DropdownMenu({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
||||
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
||||
}
|
||||
|
||||
function DropdownMenuPortal({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Trigger
|
||||
data-slot="dropdown-menu-trigger"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuContent({
|
||||
className,
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
data-slot="dropdown-menu-content"
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground 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 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuItem({
|
||||
className,
|
||||
inset,
|
||||
variant = "default",
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
variant?: "default" | "destructive"
|
||||
}) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Item
|
||||
data-slot="dropdown-menu-item"
|
||||
data-inset={inset}
|
||||
data-variant={variant}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuCheckboxItem({
|
||||
className,
|
||||
children,
|
||||
checked,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
data-slot="dropdown-menu-checkbox-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuRadioGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.RadioGroup
|
||||
data-slot="dropdown-menu-radio-group"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuRadioItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
data-slot="dropdown-menu-radio-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CircleIcon className="size-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuLabel({
|
||||
className,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Label
|
||||
data-slot="dropdown-menu-label"
|
||||
data-inset={inset}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
data-slot="dropdown-menu-separator"
|
||||
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuShortcut({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) {
|
||||
return (
|
||||
<span
|
||||
data-slot="dropdown-menu-shortcut"
|
||||
className={cn(
|
||||
"text-muted-foreground ml-auto text-xs tracking-widest",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuSub({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
||||
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
||||
}
|
||||
|
||||
function DropdownMenuSubTrigger({
|
||||
className,
|
||||
inset,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
data-slot="dropdown-menu-sub-trigger"
|
||||
data-inset={inset}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon className="ml-auto size-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuSubContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
data-slot="dropdown-menu-sub-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground 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 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuSubContent,
|
||||
}
|
||||
48
components/ui/popover.tsx
Normal file
48
components/ui/popover.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Popover({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
||||
}
|
||||
|
||||
function PopoverTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
||||
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
||||
}
|
||||
|
||||
function PopoverContent({
|
||||
className,
|
||||
align = "center",
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||
return (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
data-slot="popover-content"
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground 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 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverAnchor({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
||||
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
||||
}
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
||||
187
components/ui/select.tsx
Normal file
187
components/ui/select.tsx
Normal file
@ -0,0 +1,187 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Select({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot="select" {...props} />
|
||||
}
|
||||
|
||||
function SelectGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
||||
}
|
||||
|
||||
function SelectValue({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
||||
}
|
||||
|
||||
function SelectTrigger({
|
||||
className,
|
||||
size = "default",
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: "sm" | "default"
|
||||
}) {
|
||||
return (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = "popper",
|
||||
align = "center",
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
data-slot="select-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground 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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
align={align}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLabel({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||
return (
|
||||
<SelectPrimitive.Label
|
||||
data-slot="select-label"
|
||||
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||
return (
|
||||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||
return (
|
||||
<SelectPrimitive.Separator
|
||||
data-slot="select-separator"
|
||||
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollUpButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
data-slot="select-scroll-up-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUpIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollDownButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
data-slot="select-scroll-down-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
}
|
||||
@ -1,7 +1,14 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'images.unsplash.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@ -12,14 +12,19 @@
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"framer-motion": "^12.23.24",
|
||||
"lucide-react": "^0.552.0",
|
||||
"next": "16.0.1",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.0",
|
||||
"react-day-picker": "^9.11.1",
|
||||
"react-dom": "19.2.0",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1"
|
||||
|
||||
797
pnpm-lock.yaml
797
pnpm-lock.yaml
@ -8,6 +8,15 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@radix-ui/react-dropdown-menu':
|
||||
specifier: ^2.1.16
|
||||
version: 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-popover':
|
||||
specifier: ^1.1.15
|
||||
version: 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-select':
|
||||
specifier: ^2.2.6
|
||||
version: 2.2.6(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-slot':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4(@types/react@19.2.2)(react@19.2.0)
|
||||
@ -17,6 +26,9 @@ importers:
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
date-fns:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
framer-motion:
|
||||
specifier: ^12.23.24
|
||||
version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
@ -32,6 +44,9 @@ importers:
|
||||
react:
|
||||
specifier: 19.2.0
|
||||
version: 19.2.0
|
||||
react-day-picker:
|
||||
specifier: ^9.11.1
|
||||
version: 9.11.1(react@19.2.0)
|
||||
react-dom:
|
||||
specifier: 19.2.0
|
||||
version: 19.2.0(react@19.2.0)
|
||||
@ -143,6 +158,9 @@ packages:
|
||||
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@date-fns/tz@1.4.1':
|
||||
resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==}
|
||||
|
||||
'@emnapi/core@1.7.0':
|
||||
resolution: {integrity: sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==}
|
||||
|
||||
@ -190,6 +208,21 @@ packages:
|
||||
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@floating-ui/core@1.7.3':
|
||||
resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==}
|
||||
|
||||
'@floating-ui/dom@1.7.4':
|
||||
resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==}
|
||||
|
||||
'@floating-ui/react-dom@2.1.6':
|
||||
resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
'@floating-ui/utils@0.2.10':
|
||||
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
|
||||
|
||||
'@humanfs/core@0.19.1':
|
||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
@ -421,6 +454,38 @@ packages:
|
||||
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
|
||||
engines: {node: '>=12.4.0'}
|
||||
|
||||
'@radix-ui/number@1.1.1':
|
||||
resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==}
|
||||
|
||||
'@radix-ui/primitive@1.1.3':
|
||||
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
|
||||
|
||||
'@radix-ui/react-arrow@1.1.7':
|
||||
resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-collection@1.1.7':
|
||||
resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-compose-refs@1.1.2':
|
||||
resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==}
|
||||
peerDependencies:
|
||||
@ -430,6 +495,194 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-context@1.1.2':
|
||||
resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-direction@1.1.1':
|
||||
resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-dismissable-layer@1.1.11':
|
||||
resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-dropdown-menu@2.1.16':
|
||||
resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-focus-guards@1.1.3':
|
||||
resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-focus-scope@1.1.7':
|
||||
resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-id@1.1.1':
|
||||
resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-menu@2.1.16':
|
||||
resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-popover@1.1.15':
|
||||
resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-popper@1.2.8':
|
||||
resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-portal@1.1.9':
|
||||
resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-presence@1.1.5':
|
||||
resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-primitive@2.1.3':
|
||||
resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.11':
|
||||
resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-select@2.2.6':
|
||||
resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==}
|
||||
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
|
||||
|
||||
'@radix-ui/react-slot@1.2.3':
|
||||
resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-slot@1.2.4':
|
||||
resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==}
|
||||
peerDependencies:
|
||||
@ -439,6 +692,94 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-callback-ref@1.1.1':
|
||||
resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.2.2':
|
||||
resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-effect-event@0.0.2':
|
||||
resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-escape-keydown@1.1.1':
|
||||
resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.1.1':
|
||||
resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-previous@1.1.1':
|
||||
resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-rect@1.1.1':
|
||||
resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-size@1.1.1':
|
||||
resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-visually-hidden@1.2.3':
|
||||
resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==}
|
||||
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
|
||||
|
||||
'@radix-ui/rect@1.1.1':
|
||||
resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
|
||||
|
||||
'@rtsao/scc@1.1.0':
|
||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||
|
||||
@ -730,6 +1071,10 @@ packages:
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
aria-hidden@1.2.6:
|
||||
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
aria-query@5.3.2:
|
||||
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -875,6 +1220,12 @@ packages:
|
||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
date-fns-jalali@4.1.0-0:
|
||||
resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==}
|
||||
|
||||
date-fns@4.1.0:
|
||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||
|
||||
debug@3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
peerDependencies:
|
||||
@ -907,6 +1258,9 @@ packages:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
detect-node-es@1.1.0:
|
||||
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
|
||||
|
||||
doctrine@2.1.0:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -1169,6 +1523,10 @@ packages:
|
||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-nonce@1.0.1:
|
||||
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
get-proto@1.0.1:
|
||||
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1694,6 +2052,12 @@ packages:
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
react-day-picker@9.11.1:
|
||||
resolution: {integrity: sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
react-dom@19.2.0:
|
||||
resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==}
|
||||
peerDependencies:
|
||||
@ -1702,6 +2066,36 @@ packages:
|
||||
react-is@16.13.1:
|
||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
|
||||
react-remove-scroll-bar@2.3.8:
|
||||
resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-remove-scroll@2.7.1:
|
||||
resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-style-singleton@2.2.3:
|
||||
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react@19.2.0:
|
||||
resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -1954,6 +2348,26 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
use-callback-ref@1.3.3:
|
||||
resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
use-sidecar@1.1.3:
|
||||
resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
which-boxed-primitive@1.1.1:
|
||||
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -2099,6 +2513,8 @@ snapshots:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
||||
'@date-fns/tz@1.4.1': {}
|
||||
|
||||
'@emnapi/core@1.7.0':
|
||||
dependencies:
|
||||
'@emnapi/wasi-threads': 1.1.0
|
||||
@ -2161,6 +2577,23 @@ snapshots:
|
||||
'@eslint/core': 0.17.0
|
||||
levn: 0.4.1
|
||||
|
||||
'@floating-ui/core@1.7.3':
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.10
|
||||
|
||||
'@floating-ui/dom@1.7.4':
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.7.3
|
||||
'@floating-ui/utils': 0.2.10
|
||||
|
||||
'@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.7.4
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
|
||||
'@floating-ui/utils@0.2.10': {}
|
||||
|
||||
'@humanfs/core@0.19.1': {}
|
||||
|
||||
'@humanfs/node@0.16.7':
|
||||
@ -2331,12 +2764,250 @@ snapshots:
|
||||
|
||||
'@nolyfill/is-core-module@1.0.39': {}
|
||||
|
||||
'@radix-ui/number@1.1.1': {}
|
||||
|
||||
'@radix-ui/primitive@1.1.3': {}
|
||||
|
||||
'@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
aria-hidden: 1.2.6
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0)
|
||||
aria-hidden: 1.2.6
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/rect': 1.1.1
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-select@2.2.6(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/number': 1.1.1
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
aria-hidden: 1.2.6
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-slot@1.2.4(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.2.0)
|
||||
@ -2344,6 +3015,71 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.2.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-previous@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-rect@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/rect': 1.1.1
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-use-size@1.1.1(@types/react@19.2.2)(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.2.0)
|
||||
react: 19.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
'@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
|
||||
'@radix-ui/rect@1.1.1': {}
|
||||
|
||||
'@rtsao/scc@1.1.0': {}
|
||||
|
||||
'@swc/helpers@0.5.15':
|
||||
@ -2613,6 +3349,10 @@ snapshots:
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
aria-hidden@1.2.6:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
aria-query@5.3.2: {}
|
||||
|
||||
array-buffer-byte-length@1.0.2:
|
||||
@ -2791,6 +3531,10 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.2
|
||||
|
||||
date-fns-jalali@4.1.0-0: {}
|
||||
|
||||
date-fns@4.1.0: {}
|
||||
|
||||
debug@3.2.7:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@ -2815,6 +3559,8 @@ snapshots:
|
||||
|
||||
detect-libc@2.1.2: {}
|
||||
|
||||
detect-node-es@1.1.0: {}
|
||||
|
||||
doctrine@2.1.0:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
@ -3235,6 +3981,8 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
math-intrinsics: 1.1.0
|
||||
|
||||
get-nonce@1.0.1: {}
|
||||
|
||||
get-proto@1.0.1:
|
||||
dependencies:
|
||||
dunder-proto: 1.0.1
|
||||
@ -3728,6 +4476,13 @@ snapshots:
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
react-day-picker@9.11.1(react@19.2.0):
|
||||
dependencies:
|
||||
'@date-fns/tz': 1.4.1
|
||||
date-fns: 4.1.0
|
||||
date-fns-jalali: 4.1.0-0
|
||||
react: 19.2.0
|
||||
|
||||
react-dom@19.2.0(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
@ -3735,6 +4490,33 @@ snapshots:
|
||||
|
||||
react-is@16.13.1: {}
|
||||
|
||||
react-remove-scroll-bar@2.3.8(@types/react@19.2.2)(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0)
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
react-remove-scroll@2.7.1(@types/react@19.2.2)(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
react-remove-scroll-bar: 2.3.8(@types/react@19.2.2)(react@19.2.0)
|
||||
react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.2.0)
|
||||
tslib: 2.8.1
|
||||
use-callback-ref: 1.3.3(@types/react@19.2.2)(react@19.2.0)
|
||||
use-sidecar: 1.1.3(@types/react@19.2.2)(react@19.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
react-style-singleton@2.2.3(@types/react@19.2.2)(react@19.2.0):
|
||||
dependencies:
|
||||
get-nonce: 1.0.1
|
||||
react: 19.2.0
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
react@19.2.0: {}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
@ -4094,6 +4876,21 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
use-sidecar@1.1.3(@types/react@19.2.2)(react@19.2.0):
|
||||
dependencies:
|
||||
detect-node-es: 1.1.0
|
||||
react: 19.2.0
|
||||
tslib: 2.8.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.2
|
||||
|
||||
which-boxed-primitive@1.1.1:
|
||||
dependencies:
|
||||
is-bigint: 1.1.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user