A calendar component in neobrutalism style.
1"use client"
2
3import { ChevronLeft, ChevronRight } from "lucide-react"
4import { DayPicker } from "react-day-picker"
5
6import * as React from "react"
7
8import { buttonVariants } from "@/components/ui/button"
9
10import { cn } from "@/lib/utils"
11
12export type CalendarProps = React.ComponentProps<typeof DayPicker>
13
14function Calendar({
15 className,
16 classNames,
17 showOutsideDays = true,
18 ...props
19}: CalendarProps) {
20 return (
21 <DayPicker
22 showOutsideDays={showOutsideDays}
23 className={cn(
24 "rounded-base! border-2 border-border bg-main p-3 font-heading shadow-shadow",
25 className,
26 )}
27 classNames={{
28 months: "flex flex-col sm:flex-row gap-2",
29 month: "flex flex-col gap-4",
30 caption:
31 "flex justify-center pt-1 relative items-center w-full text-main-foreground",
32 caption_label: "text-sm font-heading",
33 nav: "gap-1 flex items-center",
34 nav_button: cn(
35 buttonVariants({ variant: "noShadow" }),
36 "size-7 bg-transparent p-0",
37 ),
38 nav_button_previous: "absolute left-1",
39 nav_button_next: "absolute right-1",
40 table: "w-full border-collapse space-y-1",
41 head_row: "flex",
42 head_cell:
43 "text-main-foreground rounded-base w-9 font-base text-[0.8rem]",
44 row: "flex w-full mt-2",
45 cell: cn(
46 "relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-black/50 [&:has([aria-selected])]:text-white! [&:has([aria-selected].day-range-end)]:rounded-r-base",
47 props.mode === "range"
48 ? "[&:has(>.day-range-end)]:rounded-r-base [&:has(>.day-range-start)]:rounded-l-base [&:has([aria-selected])]:bg-black/50! first:[&:has([aria-selected])]:rounded-l-base last:[&:has([aria-selected])]:rounded-r-base"
49 : "[&:has([aria-selected])]:rounded-base [&:has([aria-selected])]:bg-black/50",
50 ),
51 day: cn(
52 buttonVariants({ variant: "noShadow" }),
53 "size-9 p-0 font-base aria-selected:opacity-100",
54 ),
55 day_range_start:
56 "day-range-start aria-selected:bg-black! aria-selected:text-white rounded-base",
57 day_range_end:
58 "day-range-end aria-selected:bg-black! aria-selected:text-white rounded-base",
59 day_selected: "bg-black! text-white! rounded-base",
60 day_today: "bg-secondary-background text-foreground!",
61 day_outside:
62 "day-outside text-main-foreground opacity-50 aria-selected:bg-none",
63 day_disabled: "text-main-foreground opacity-50 rounded-base",
64 day_range_middle: "aria-selected:bg-black/50! aria-selected:text-white",
65 day_hidden: "invisible",
66 ...classNames,
67 }}
68 components={{
69 IconLeft: ({ className, ...props }) => (
70 <ChevronLeft className={cn("size-4", className)} {...props} />
71 ),
72 IconRight: ({ className, ...props }) => (
73 <ChevronRight className={cn("size-4", className)} {...props} />
74 ),
75 }}
76 {...props}
77 />
78 )
79}
80Calendar.displayName = "Calendar"
81
82export { Calendar }
83