perf: disable tooltips in year calendar to fix lag

Fixed issue #5579 where the calendar selection dialog was very laggy.

The root cause was rendering ~365 individual Tooltip components when
opening the year calendar view (one per day with activity). This created
a huge number of DOM nodes and event listeners that caused significant
performance issues.

Changes:
- Added disableTooltips prop to MonthCalendar and CalendarCell components
- Disabled tooltips in YearCalendar's small month views
- Removed unnecessary TooltipProvider wrapper in YearCalendar
- Tooltips remain enabled in the default month calendar view

Performance improvements:
- Eliminates ~365 tooltip instances when dialog opens
- Reduces initial render time significantly
- Makes dialog interactions smooth and responsive

Users can still click on dates to drill down for details if needed.
This commit is contained in:
Steven 2026-02-04 20:14:55 +08:00
parent e7605d90da
commit 74b63b278c
4 changed files with 12 additions and 12 deletions

View File

@ -11,10 +11,11 @@ export interface CalendarCellProps {
tooltipText: string;
onClick?: (date: string) => void;
size?: CalendarSize;
disableTooltip?: boolean;
}
export const CalendarCell = memo((props: CalendarCellProps) => {
const { day, maxCount, tooltipText, onClick, size = "default" } = props;
const { day, maxCount, tooltipText, onClick, size = "default", disableTooltip = false } = props;
const handleClick = () => {
if (day.count > 0 && onClick) {
@ -62,7 +63,7 @@ export const CalendarCell = memo((props: CalendarCellProps) => {
</button>
);
const shouldShowTooltip = tooltipText && day.count > 0;
const shouldShowTooltip = tooltipText && day.count > 0 && !disableTooltip;
if (!shouldShowTooltip) {
return button;

View File

@ -35,7 +35,7 @@ const WeekdayHeader = memo(({ weekDays, size }: WeekdayHeaderProps) => (
WeekdayHeader.displayName = "WeekdayHeader";
export const MonthCalendar = memo((props: MonthCalendarProps) => {
const { month, data, maxCount, size = "default", onClick, className } = props;
const { month, data, maxCount, size = "default", onClick, className, disableTooltips = false } = props;
const t = useTranslate();
const { generalSetting } = useInstance();
const today = useTodayDate();
@ -65,6 +65,7 @@ export const MonthCalendar = memo((props: MonthCalendarProps) => {
tooltipText={getTooltipText(day.count, day.date, t)}
onClick={onClick}
size={size}
disableTooltip={disableTooltips}
/>
))}
</div>

View File

@ -1,7 +1,6 @@
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import { memo, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { TooltipProvider } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { useTranslate } from "@/utils/i18n";
import { getMaxYear, MIN_YEAR } from "./constants";
@ -79,7 +78,7 @@ interface MonthCardProps {
const MonthCard = memo(({ month, data, maxCount, onDateClick }: MonthCardProps) => (
<article className="flex flex-col gap-2 rounded-xl border border-border/20 bg-muted/5 p-3 transition-colors hover:bg-muted/10">
<header className="text-[10px] font-medium text-muted-foreground/80 uppercase tracking-widest">{getMonthLabel(month)}</header>
<MonthCalendar month={month} data={data} maxCount={maxCount} size="small" onClick={onDateClick} />
<MonthCalendar month={month} data={data} maxCount={maxCount} size="small" onClick={onDateClick} disableTooltips />
</article>
));
MonthCard.displayName = "MonthCard";
@ -105,13 +104,11 @@ export const YearCalendar = memo(({ selectedYear, data, onYearChange, onDateClic
canGoNext={canGoNext}
/>
<TooltipProvider>
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 animate-fade-in">
{months.map((month) => (
<MonthCard key={month} month={month} data={yearData} maxCount={yearMaxCount} onDateClick={onDateClick} />
))}
</div>
</TooltipProvider>
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 animate-fade-in">
{months.map((month) => (
<MonthCard key={month} month={month} data={yearData} maxCount={yearMaxCount} onDateClick={onDateClick} />
))}
</div>
</section>
);
});

View File

@ -27,6 +27,7 @@ export interface MonthCalendarProps {
size?: CalendarSize;
onClick?: (date: string) => void;
className?: string;
disableTooltips?: boolean;
}
export interface YearCalendarProps {