The two months rendered reversed (current month on the left). Pin the calendar row to dir=rtl and render the base month first so the current month sits on the right and the next month on the left, matching the design. Pin each month header to dir=ltr so the nav arrows stay on the expected outer edges regardless of the RTL flip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
119 lines
3.3 KiB
JavaScript
119 lines
3.3 KiB
JavaScript
"use client";
|
||
|
||
import moment from "moment-jalaali";
|
||
|
||
moment.loadPersian({ dialect: "persian-modern", usePersianDigits: false });
|
||
|
||
const WEEKDAYS = ["شنبه", "۱ شنبه", "۲ شنبه", "۳ شنبه", "۴ شنبه", "۵ شنبه", "جمعه"];
|
||
const MONTHS = [
|
||
"فروردین",
|
||
"اردیبهشت",
|
||
"خرداد",
|
||
"تیر",
|
||
"مرداد",
|
||
"شهریور",
|
||
"مهر",
|
||
"آبان",
|
||
"آذر",
|
||
"دی",
|
||
"بهمن",
|
||
"اسفند",
|
||
];
|
||
|
||
function buildDays(displayDate) {
|
||
const year = displayDate.jYear();
|
||
const month = displayDate.jMonth();
|
||
const daysInMonth = moment.jDaysInMonth(year, month);
|
||
const firstDayOfMonth = moment(`${year}/${month + 1}/1`, "jYYYY/jM/jD").day();
|
||
const startOffset = (firstDayOfMonth + 1) % 7;
|
||
|
||
const days = [];
|
||
for (let i = 0; i < startOffset; i++) days.push(null);
|
||
for (let day = 1; day <= daysInMonth; day++) days.push(day);
|
||
return days;
|
||
}
|
||
|
||
function InlineJalaliMonth({
|
||
displayDate,
|
||
selectedDate,
|
||
onSelectDay,
|
||
isDisabled,
|
||
onPrev,
|
||
onNext,
|
||
showPrev = true,
|
||
showNext = true,
|
||
}) {
|
||
const days = buildDays(displayDate);
|
||
|
||
return (
|
||
<div className="w-full">
|
||
<div dir="ltr" className="flex items-center justify-between mb-[16px] px-1">
|
||
<button
|
||
type="button"
|
||
onClick={onNext}
|
||
className={`p-1 text-[#525252] ${showNext ? "" : "invisible"}`}
|
||
aria-label="ماه بعد"
|
||
>
|
||
‹
|
||
</button>
|
||
<p className="text-[#3B3B3B] text-[14px] md:text-[16px] font-bold">
|
||
{MONTHS[displayDate.jMonth()]} {displayDate.jYear()}
|
||
</p>
|
||
<button
|
||
type="button"
|
||
onClick={onPrev}
|
||
className={`p-1 text-[#525252] ${showPrev ? "" : "invisible"}`}
|
||
aria-label="ماه قبل"
|
||
>
|
||
›
|
||
</button>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-7 gap-y-[12px] mb-[8px]">
|
||
{WEEKDAYS.map((label, idx) => (
|
||
<span
|
||
key={idx}
|
||
className="text-center text-[#9B9B9B] text-[11px] md:text-[12px] font-normal"
|
||
>
|
||
{label}
|
||
</span>
|
||
))}
|
||
</div>
|
||
|
||
<div className="grid grid-cols-7 gap-y-[12px]">
|
||
{days.map((day, index) => {
|
||
if (!day) return <span key={index} />;
|
||
|
||
const dayDate = moment(displayDate).jDate(day);
|
||
const isFriday = dayDate.day() === 5;
|
||
const disabled = isDisabled(dayDate);
|
||
const selected =
|
||
selectedDate &&
|
||
dayDate.jYear() === selectedDate.jYear() &&
|
||
dayDate.jMonth() === selectedDate.jMonth() &&
|
||
dayDate.jDate() === selectedDate.jDate();
|
||
|
||
return (
|
||
<button
|
||
type="button"
|
||
key={index}
|
||
disabled={disabled}
|
||
onClick={() => onSelectDay(dayDate)}
|
||
className={`
|
||
mx-auto flex items-center justify-center w-[34px] h-[34px] rounded-full
|
||
text-[14px] md:text-[16px] font-normal transition-colors
|
||
${selected ? "!bg-[#F17732] !text-[#FFF]" : ""}
|
||
${disabled ? "text-[#D7D7D7] cursor-not-allowed" : isFriday ? "text-[#E0383B]" : "text-[#525252] hover:bg-[#F5F5F5]"}
|
||
`}
|
||
>
|
||
{day}
|
||
</button>
|
||
);
|
||
})}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default InlineJalaliMonth;
|