99 lines
4.0 KiB
TypeScript
99 lines
4.0 KiB
TypeScript
'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>
|
|
);
|
|
}
|
|
|