Last active
June 6, 2025 09:55
-
-
Save maxgfr/94b00cfc2a8bb4031f36e52b0923b56d to your computer and use it in GitHub Desktop.
Revisions
-
maxgfr revised this gist
Feb 8, 2025 . 1 changed file with 46 additions and 9 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -99,20 +99,56 @@ function Calendar({ className, classNames, showOutsideDays = true, defaultMonth, index = 0, // Ajout d'un index pour gérer plusieurs calendriers ...props }: CalendarProps & { index?: number }) { const [currentMonth, setCurrentMonth] = React.useState<Date>(() => { if (props.selected instanceof Date) { return props.selected; } if (Array.isArray(props.selected) && props.selected[0]) { const selectedDate = props.selected[0]; if (selectedDate instanceof Date) { return new Date( selectedDate.getFullYear(), selectedDate.getMonth() + index, 1, ); } return new Date(); } if (defaultMonth) { return new Date( defaultMonth.getFullYear(), defaultMonth.getMonth() + index, 1, ); } const now = new Date(); return new Date(now.getFullYear(), now.getMonth() + index, 1); }); const [currentYear, setCurrentYear] = React.useState<number>(() => currentMonth.getFullYear(), ); React.useEffect(() => { if (props.selected instanceof Date) { const newDate = new Date(props.selected); newDate.setMonth(newDate.getMonth() + index); setCurrentMonth(newDate); setCurrentYear(newDate.getFullYear()); } else if ( Array.isArray(props.selected) && props.selected[0] instanceof Date ) { const newDate = new Date(props.selected[0]); newDate.setMonth(newDate.getMonth() + index); setCurrentMonth(newDate); setCurrentYear(newDate.getFullYear()); } }, [props.selected, index]); const handleMonthChange = (newMonth: Date) => { setCurrentMonth(newMonth); @@ -133,6 +169,7 @@ function Calendar({ className={cn("p-3", className)} locale={fr} month={currentMonth} defaultMonth={defaultMonth} onMonthChange={handleMonthChange} classNames={{ months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0", -
maxgfr revised this gist
Feb 8, 2025 . 1 changed file with 59 additions and 18 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -20,21 +20,27 @@ export type CalendarProps = React.ComponentProps<typeof DayPicker>; function CalendarDropdown({ displayMonth, displayYear, onChangeMonth, onChangeYear, }: { displayMonth: Date; displayYear: number; onChangeMonth: (date: Date) => void; onChangeYear: (year: number) => void; }) { const months = Array.from({ length: 12 }, (_, i) => { const month = new Date(displayYear, i, 1); return { value: i.toString(), label: format(month, "MMMM", { locale: fr }), }; }); const years = Array.from( { length: 20 }, (_, i) => new Date().getFullYear() - 5 + i, ).sort((a, b) => a - b); return ( <div className="flex items-center justify-center gap-1 pt-1"> @@ -43,7 +49,7 @@ function CalendarDropdown({ onValueChange={(value) => { const newDate = new Date(displayMonth); newDate.setMonth(parseInt(value)); onChangeMonth(newDate); }} > <SelectTrigger className="h-7 w-[110px]"> @@ -53,27 +59,33 @@ function CalendarDropdown({ </SelectTrigger> <SelectContent> {months.map((month) => ( <SelectItem key={month.value} value={month.value} className="cursor-pointer" > {month.label} </SelectItem> ))} </SelectContent> </Select> <Select value={displayYear.toString()} onValueChange={(value) => { onChangeYear(parseInt(value)); }} > <SelectTrigger className="h-7 w-[80px]"> <SelectValue>{displayYear}</SelectValue> </SelectTrigger> <SelectContent className="max-h-[300px]"> {years.map((year) => ( <SelectItem key={year} value={year.toString()} className="cursor-pointer" > {year} </SelectItem> ))} @@ -87,17 +99,41 @@ function Calendar({ className, classNames, showOutsideDays = true, selected, ...props }: CalendarProps) { const [currentMonth, setCurrentMonth] = React.useState<Date>(new Date()); const [currentYear, setCurrentYear] = React.useState<number>( new Date().getFullYear(), ); React.useEffect(() => { if (selected instanceof Date) { setCurrentMonth(selected); setCurrentYear(selected.getFullYear()); } }, [selected]); const handleMonthChange = (newMonth: Date) => { setCurrentMonth(newMonth); props.onMonthChange?.(newMonth); }; const handleYearChange = (year: number) => { const newDate = new Date(currentMonth); newDate.setFullYear(year); setCurrentYear(year); setCurrentMonth(newDate); props.onMonthChange?.(newDate); }; return ( <DayPicker showOutsideDays={showOutsideDays} className={cn("p-3", className)} locale={fr} month={currentMonth} onMonthChange={handleMonthChange} classNames={{ months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0", month: "space-y-4", @@ -140,7 +176,12 @@ function Calendar({ <ChevronRight className={cn("h-4 w-4", className)} {...props} /> ), Caption: () => ( <CalendarDropdown displayMonth={currentMonth} displayYear={currentYear} onChangeMonth={handleMonthChange} onChangeYear={handleYearChange} /> ), }} {...props} -
maxgfr created this gist
Feb 8, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,152 @@ "use client"; import * as React from "react"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { DayPicker } from "react-day-picker"; import { format } from "date-fns"; import { cn } from "~/lib/utils"; import { buttonVariants } from "~/components/ui/button"; import { fr } from "date-fns/locale"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "~/components/ui/select"; export type CalendarProps = React.ComponentProps<typeof DayPicker>; function CalendarDropdown({ displayMonth, onChange, }: { displayMonth: Date; onChange: (month: Date) => void; }) { const months = Array.from({ length: 12 }, (_, i) => { const month = new Date(displayMonth.getFullYear(), i, 1); return { value: i.toString(), label: format(month, "MMMM", { locale: fr }), }; }); const currentYear = displayMonth.getFullYear(); const years = Array.from({ length: 20 }, (_, i) => currentYear - 5 + i); return ( <div className="flex items-center justify-center gap-1 pt-1"> <Select value={displayMonth.getMonth().toString()} onValueChange={(value) => { const newDate = new Date(displayMonth); newDate.setMonth(parseInt(value)); onChange(newDate); }} > <SelectTrigger className="h-7 w-[110px]"> <SelectValue> {format(displayMonth, "MMMM", { locale: fr })} </SelectValue> </SelectTrigger> <SelectContent> {months.map((month) => ( <SelectItem key={month.value} value={month.value}> {month.label} </SelectItem> ))} </SelectContent> </Select> <Select value={displayMonth.getFullYear().toString()} onValueChange={(value) => { const newDate = new Date(displayMonth); newDate.setFullYear(parseInt(value)); onChange(newDate); }} > <SelectTrigger className="h-7 w-[80px]"> <SelectValue>{displayMonth.getFullYear()}</SelectValue> </SelectTrigger> <SelectContent> {years.map((year) => ( <SelectItem key={year} value={year.toString()}> {year} </SelectItem> ))} </SelectContent> </Select> </div> ); } function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) { const [month, setMonth] = React.useState<Date>(new Date()); return ( <DayPicker showOutsideDays={showOutsideDays} className={cn("p-3", className)} locale={fr} month={month} onMonthChange={setMonth} classNames={{ months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0", month: "space-y-4", caption: "flex justify-center pt-1 relative items-center", caption_label: "text-sm font-medium", nav: "space-x-1 flex items-center", nav_button: cn( buttonVariants({ variant: "outline" }), "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100", ), nav_button_previous: "absolute left-1", nav_button_next: "absolute right-1", table: "w-full border-collapse space-y-1", head_row: "flex", head_cell: "text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]", row: "flex w-full mt-2", cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20", day: cn( buttonVariants({ variant: "ghost" }), "h-9 w-9 p-0 font-normal aria-selected:opacity-100", ), day_range_end: "day-range-end", day_selected: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground", day_today: "bg-accent text-accent-foreground", day_outside: "day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground", day_disabled: "text-muted-foreground opacity-50", day_range_middle: "aria-selected:bg-accent aria-selected:text-accent-foreground", day_hidden: "invisible", ...classNames, }} components={{ IconLeft: ({ className, ...props }) => ( <ChevronLeft className={cn("h-4 w-4", className)} {...props} /> ), IconRight: ({ className, ...props }) => ( <ChevronRight className={cn("h-4 w-4", className)} {...props} /> ), Caption: () => ( <CalendarDropdown displayMonth={month} onChange={setMonth} /> ), }} {...props} /> ); } Calendar.displayName = "Calendar"; export { Calendar };