Skip to content

Commit 1340518

Browse files
committed
Calendar restructured to include nav buttons inline
1 parent 36e9987 commit 1340518

File tree

1 file changed

+70
-16
lines changed

1 file changed

+70
-16
lines changed

apps/webapp/app/components/primitives/Calendar.tsx

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,76 @@
33
import * as React from "react";
44
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/20/solid";
55
import { format } from "date-fns";
6-
import { DayPicker } from "react-day-picker";
6+
import { DayPicker, useDayPicker } from "react-day-picker";
77
import { cn } from "~/utils/cn";
88

99
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
1010

11+
const navButtonClass =
12+
"size-7 rounded-[3px] bg-secondary border border-charcoal-600 text-text-bright hover:bg-charcoal-600 hover:border-charcoal-550 transition inline-flex items-center justify-center";
13+
14+
function CustomMonthCaption({ calendarMonth }: { calendarMonth: { date: Date } }) {
15+
const { goToMonth, nextMonth, previousMonth } = useDayPicker();
16+
17+
return (
18+
<div className="flex w-full items-center justify-between px-1">
19+
<button
20+
type="button"
21+
className={navButtonClass}
22+
disabled={!previousMonth}
23+
onClick={() => previousMonth && goToMonth(previousMonth)}
24+
aria-label="Go to previous month"
25+
>
26+
<ChevronLeftIcon className="size-4" />
27+
</button>
28+
<div className="flex items-center gap-2">
29+
<select
30+
className="rounded border border-charcoal-600 bg-charcoal-750 px-2 py-1 text-sm text-text-bright focus:border-charcoal-500 focus:outline-none"
31+
value={calendarMonth.date.getMonth()}
32+
onChange={(e) => {
33+
const newDate = new Date(calendarMonth.date);
34+
newDate.setMonth(parseInt(e.target.value));
35+
goToMonth(newDate);
36+
}}
37+
>
38+
{Array.from({ length: 12 }, (_, i) => (
39+
<option key={i} value={i}>
40+
{format(new Date(2000, i), "MMM")}
41+
</option>
42+
))}
43+
</select>
44+
<select
45+
className="rounded border border-charcoal-600 bg-charcoal-750 px-2 py-1 text-sm text-text-bright focus:border-charcoal-500 focus:outline-none"
46+
value={calendarMonth.date.getFullYear()}
47+
onChange={(e) => {
48+
const newDate = new Date(calendarMonth.date);
49+
newDate.setFullYear(parseInt(e.target.value));
50+
goToMonth(newDate);
51+
}}
52+
>
53+
{Array.from({ length: 100 }, (_, i) => {
54+
const year = new Date().getFullYear() - 50 + i;
55+
return (
56+
<option key={year} value={year}>
57+
{year}
58+
</option>
59+
);
60+
})}
61+
</select>
62+
</div>
63+
<button
64+
type="button"
65+
className={navButtonClass}
66+
disabled={!nextMonth}
67+
onClick={() => nextMonth && goToMonth(nextMonth)}
68+
aria-label="Go to next month"
69+
>
70+
<ChevronRightIcon className="size-4" />
71+
</button>
72+
</div>
73+
);
74+
}
75+
1176
export function Calendar({
1277
className,
1378
classNames,
@@ -17,24 +82,21 @@ export function Calendar({
1782
return (
1883
<DayPicker
1984
showOutsideDays={showOutsideDays}
85+
weekStartsOn={1}
2086
className={cn("p-3", className)}
2187
classNames={{
2288
months: "flex flex-col sm:flex-row gap-2",
2389
month: "flex flex-col gap-4",
2490
month_caption: "flex justify-center pt-1 relative items-center w-full",
2591
caption_label: "sr-only",
26-
nav: "flex items-center justify-between w-full absolute inset-x-0 top-1 px-3",
27-
button_previous:
28-
"size-6 rounded-[3px] bg-secondary border border-charcoal-600 text-text-bright hover:bg-charcoal-600 hover:border-charcoal-550 transition inline-flex items-center justify-center",
29-
button_next:
30-
"size-6 rounded-[3px] bg-secondary border border-charcoal-600 text-text-bright hover:bg-charcoal-600 hover:border-charcoal-550 transition inline-flex items-center justify-center",
92+
nav: "hidden",
3193
month_grid: "w-full border-collapse",
3294
weekdays: "flex",
3395
weekday: "text-text-dimmed rounded-md w-8 font-normal text-[0.8rem]",
3496
week: "flex w-full mt-2",
3597
day: "relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-charcoal-700 [&:has([aria-selected].day-outside)]:bg-charcoal-700/50 [&:has([aria-selected].day-range-end)]:rounded-r-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md",
3698
day_button: cn(
37-
"size-8 p-0 font-normal text-text-bright",
99+
"size-8 p-0 font-normal text-text-bright rounded-md",
38100
"hover:bg-charcoal-700 hover:text-text-bright",
39101
"focus:bg-charcoal-700 focus:text-text-bright focus:outline-none",
40102
"aria-selected:opacity-100"
@@ -55,15 +117,7 @@ export function Calendar({
55117
...classNames,
56118
}}
57119
components={{
58-
Chevron: ({ orientation }) => {
59-
if (orientation === "left") {
60-
return <ChevronLeftIcon className="size-4" />;
61-
}
62-
return <ChevronRightIcon className="size-4" />;
63-
},
64-
}}
65-
formatters={{
66-
formatMonthDropdown: (date) => format(date, "MMM"),
120+
MonthCaption: CustomMonthCaption,
67121
}}
68122
{...props}
69123
/>

0 commit comments

Comments
 (0)