Components
npx shadcn@latest add https://21st.dev/r/originui/calendarLoading preview...
"use client";
import { cn } from "@/lib/utils";
import { Calendar } from "@/components/ui/calendar";
import { format } from "date-fns";
import { useEffect, useState } from "react";
import { DayButtonProps } from "react-day-picker";
const GOOD_PRICE_THRESHOLD = 100;
function Component() {
const today = new Date();
const [date, setDate] = useState<Date | undefined>(today);
const [mockPriceData, setMockPriceData] = useState<Record<string, number>>({});
useEffect(() => {
const generateMockPriceData = () => {
const data: Record<string, number> = {};
for (let i = 0; i < 180; i++) {
const date = new Date(today);
date.setDate(today.getDate() + i);
const dateKey = format(date, "yyyy-MM-dd");
const randomPrice = Math.floor(Math.random() * (200 - 80 + 1)) + 80;
data[dateKey] = randomPrice;
}
return data;
};
setMockPriceData(generateMockPriceData());
}, []);
const isDateDisabled = (date: Date) => {
return !mockPriceData[format(date, "yyyy-MM-dd")];
};
return (
<div>
<Calendar
mode="single"
selected={date}
onSelect={setDate}
numberOfMonths={2}
pagedNavigation
showOutsideDays={false}
className="rounded-lg border border-border p-2 bg-background"
classNames={{
months: "sm:flex-col md:flex-row gap-8",
month:
"relative first-of-type:before:hidden before:absolute max-md:before:inset-x-2 max-md:before:inset-y-2 md:before:w-px before:bg-border md:before:-left-4",
weekday: "w-12",
day_button: "size-12",
today: "*:after:hidden",
}}
components={{
DayButton: (props: DayButtonProps) => <DayButton {...props} prices={mockPriceData} />,
}}
disabled={isDateDisabled}
/>
<p
className="mt-4 text-center text-xs text-muted-foreground"
role="region"
aria-live="polite"
>
Pricing calendar -{" "}
<a
className="underline hover:text-foreground"
href="https://daypicker.dev/"
target="_blank"
rel="noopener nofollow"
>
React DayPicker
</a>
</p>
</div>
);
}
function DayButton(props: DayButtonProps & { prices: Record<string, number> }) {
const { day, modifiers, prices, ...buttonProps } = props;
const price = prices[format(day.date, "yyyy-MM-dd")];
const isGoodPrice = price < GOOD_PRICE_THRESHOLD;
return (
<button {...buttonProps}>
<span className="flex flex-col">
{props.children}
{price && (
<span
className={cn(
"text-[10px] font-medium",
isGoodPrice
? "text-emerald-500"
: "text-muted-foreground group-data-[selected]:text-primary-foreground/70",
)}
>
${price}
</span>
)}
</span>
</button>
);
}
export { Component };
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...