feat(calendar): add visual indicator for selected date

This commit is contained in:
Yuhan Zhang 2026-01-29 22:40:40 +09:00
parent 710eff6f57
commit 468425547f
4 changed files with 15 additions and 6 deletions

View File

@ -7,6 +7,7 @@ import { useTodayDate, useWeekdayLabels } from "./hooks";
import type { CalendarSize, MonthCalendarProps } from "./types";
import { useCalendarMatrix } from "./useCalendar";
import { getTooltipText } from "./utils";
import dayjs from "dayjs";
const GRID_STYLES: Record<CalendarSize, { gap: string; headerText: string }> = {
small: { gap: "gap-1.5", headerText: "text-[10px]" },
@ -35,11 +36,15 @@ const WeekdayHeader = memo(({ weekDays, size }: WeekdayHeaderProps) => (
WeekdayHeader.displayName = "WeekdayHeader";
export const MonthCalendar = memo((props: MonthCalendarProps) => {
const { month, data, maxCount, size = "default", onClick, className, disableTooltips = false } = props;
const { month, selectedDate, data, maxCount, size = "default", onClick, className, disableTooltips = false } = props;
const t = useTranslate();
const { generalSetting } = useInstance();
const today = useTodayDate();
const weekDays = useWeekdayLabels();
const selectedDateFormatted = useMemo(() => {
if (!selectedDate) return null;
return dayjs(selectedDate).format("YYYY-MM-DD");
}, [selectedDate]);
const { weeks, weekDays: rotatedWeekDays } = useCalendarMatrix({
month,
@ -47,7 +52,7 @@ export const MonthCalendar = memo((props: MonthCalendarProps) => {
weekDays,
weekStartDayOffset: generalSetting.weekStartDayOffset,
today,
selectedDate: "",
selectedDate: selectedDateFormatted,
});
const flatDays = useMemo(() => weeks.flatMap((week) => week.days), [weeks]);

View File

@ -22,6 +22,7 @@ export interface CalendarMatrixResult {
export interface MonthCalendarProps {
month: string;
selectedDate: string | null;
data: Record<string, number>;
maxCount: number;
size?: CalendarSize;

View File

@ -9,7 +9,7 @@ export interface UseCalendarMatrixParams {
weekDays: string[];
weekStartDayOffset: number;
today: string;
selectedDate: string;
selectedDate: string | null;
}
const createCalendarDayCell = (
@ -17,7 +17,7 @@ const createCalendarDayCell = (
monthKey: string,
data: Record<string, number>,
today: string,
selectedDate: string,
selectedDate: string | null,
): CalendarDayCell => {
const isoDate = current.format("YYYY-MM-DD");
const isCurrentMonth = current.format("YYYY-MM") === monthKey;

View File

@ -12,6 +12,7 @@ interface Props {
const StatisticsView = (props: Props) => {
const { statisticsData } = props;
const { activityStats } = statisticsData;
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
const [visibleMonthString, setVisibleMonthString] = useState(dayjs().format("YYYY-MM"));
const { getFiltersByFactor, addFilter, removeFilter } = useMemoFilterContext();
@ -26,6 +27,7 @@ const StatisticsView = (props: Props) => {
if (isActive) {
removeFilter((f: MemoFilter) => f.factor === "displayTime" && f.value === date);
setSelectedDate(null);
} else {
// Remove all existing tag filters first, then add the new one
removeFilter((f: MemoFilter) => f.factor === "displayTime");
@ -33,15 +35,16 @@ const StatisticsView = (props: Props) => {
factor: "displayTime",
value: date,
});
setSelectedDate(new Date(date));
}
}
};
return (
<div className="group w-full mt-2 flex flex-col text-muted-foreground animate-fade-in">
<MonthNavigator visibleMonth={visibleMonthString} onMonthChange={setVisibleMonthString} activityStats={activityStats} />
<div className="w-full animate-scale-in">
<MonthCalendar month={visibleMonthString} data={activityStats} maxCount={maxCount} onClick={handleClick} />
<MonthCalendar month={visibleMonthString} selectedDate={selectedDate?.toDateString()} data={activityStats} maxCount={maxCount} onClick={handleClick} />
</div>
</div>
);