perf(renderer): share sidebar task theme state

This commit is contained in:
777genius 2026-05-31 07:06:08 +03:00
parent 5f5b3dc62c
commit da7d71c0b8
2 changed files with 37 additions and 3 deletions

View file

@ -6,6 +6,7 @@ import { confirm } from '@renderer/components/common/ConfirmDialog';
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
import { useCollapsedGroups } from '@renderer/hooks/useCollapsedGroups'; import { useCollapsedGroups } from '@renderer/hooks/useCollapsedGroups';
import { useTaskLocalState } from '@renderer/hooks/useTaskLocalState'; import { useTaskLocalState } from '@renderer/hooks/useTaskLocalState';
import { useTheme } from '@renderer/hooks/useTheme';
import { cn } from '@renderer/lib/utils'; import { cn } from '@renderer/lib/utils';
import { markTaskUnread } from '@renderer/services/commentReadStorage'; import { markTaskUnread } from '@renderer/services/commentReadStorage';
import { useStore } from '@renderer/store'; import { useStore } from '@renderer/store';
@ -347,6 +348,7 @@ interface GlobalTaskRowProps {
hideTeamName?: boolean; hideTeamName?: boolean;
hideProjectName?: boolean; hideProjectName?: boolean;
showTeamName?: boolean; showTeamName?: boolean;
isLight: boolean;
onTogglePin: TaskRowAction; onTogglePin: TaskRowAction;
onToggleArchive: TaskRowAction; onToggleArchive: TaskRowAction;
onMarkUnread: TaskRowAction; onMarkUnread: TaskRowAction;
@ -409,6 +411,7 @@ const GlobalTaskRow = memo(
hideTeamName, hideTeamName,
hideProjectName, hideProjectName,
showTeamName, showTeamName,
isLight,
onTogglePin, onTogglePin,
onToggleArchive, onToggleArchive,
onMarkUnread, onMarkUnread,
@ -459,6 +462,7 @@ const GlobalTaskRow = memo(
hideTeamName={hideTeamName} hideTeamName={hideTeamName}
hideProjectName={hideProjectName} hideProjectName={hideProjectName}
showTeamName={showTeamName} showTeamName={showTeamName}
isLight={isLight}
teamOffline={teamOffline} teamOffline={teamOffline}
renamingKey={effectiveRenamingKey} renamingKey={effectiveRenamingKey}
onRenameComplete={onRenameComplete} onRenameComplete={onRenameComplete}
@ -481,6 +485,7 @@ const GlobalTaskRow = memo(
prev.hideTeamName === next.hideTeamName && prev.hideTeamName === next.hideTeamName &&
prev.hideProjectName === next.hideProjectName && prev.hideProjectName === next.hideProjectName &&
prev.showTeamName === next.showTeamName && prev.showTeamName === next.showTeamName &&
prev.isLight === next.isLight &&
prev.onTogglePin === next.onTogglePin && prev.onTogglePin === next.onTogglePin &&
prev.onToggleArchive === next.onToggleArchive && prev.onToggleArchive === next.onToggleArchive &&
prev.onMarkUnread === next.onMarkUnread && prev.onMarkUnread === next.onMarkUnread &&
@ -504,6 +509,7 @@ interface TaskRowsProps {
hideTeamName?: boolean; hideTeamName?: boolean;
hideProjectName?: boolean; hideProjectName?: boolean;
showTeamName?: boolean; showTeamName?: boolean;
isLight: boolean;
showTeamHeader?: boolean; showTeamHeader?: boolean;
pinnedOverride?: boolean; pinnedOverride?: boolean;
archivedOverride?: boolean; archivedOverride?: boolean;
@ -594,6 +600,7 @@ const TaskRows = memo(function TaskRows({
hideTeamName, hideTeamName,
hideProjectName, hideProjectName,
showTeamName, showTeamName,
isLight,
showTeamHeader, showTeamHeader,
pinnedOverride, pinnedOverride,
archivedOverride, archivedOverride,
@ -625,6 +632,7 @@ const TaskRows = memo(function TaskRows({
hideTeamName={hideTeamName} hideTeamName={hideTeamName}
hideProjectName={hideProjectName} hideProjectName={hideProjectName}
showTeamName={showTeamName} showTeamName={showTeamName}
isLight={isLight}
teamOffline={isTeamOffline(task.teamName)} teamOffline={isTeamOffline(task.teamName)}
ownerColorName={getOwnerColorName(task)} ownerColorName={getOwnerColorName(task)}
renamingKey={renamingKey} renamingKey={renamingKey}
@ -668,6 +676,7 @@ function areTaskRowsPropsEqual(prev: TaskRowsProps, next: TaskRowsProps): boolea
prev.hideTeamName === next.hideTeamName && prev.hideTeamName === next.hideTeamName &&
prev.hideProjectName === next.hideProjectName && prev.hideProjectName === next.hideProjectName &&
prev.showTeamName === next.showTeamName && prev.showTeamName === next.showTeamName &&
prev.isLight === next.isLight &&
prev.showTeamHeader === next.showTeamHeader && prev.showTeamHeader === next.showTeamHeader &&
prev.pinnedOverride === next.pinnedOverride && prev.pinnedOverride === next.pinnedOverride &&
prev.archivedOverride === next.archivedOverride && prev.archivedOverride === next.archivedOverride &&
@ -710,6 +719,7 @@ interface ProjectTaskGroupProps {
isNewTask: (task: GlobalTask) => boolean; isNewTask: (task: GlobalTask) => boolean;
isTeamOffline: TeamBooleanResolver; isTeamOffline: TeamBooleanResolver;
renamingKey: string | null; renamingKey: string | null;
isLight: boolean;
formatTeamHeader: TeamHeaderFormatter; formatTeamHeader: TeamHeaderFormatter;
onToggleGroup: (projectKey: string) => void; onToggleGroup: (projectKey: string) => void;
onVisibleCountChange: ProjectGroupVisibleCountChange; onVisibleCountChange: ProjectGroupVisibleCountChange;
@ -737,6 +747,7 @@ const ProjectTaskGroup = memo(
isNewTask, isNewTask,
isTeamOffline, isTeamOffline,
renamingKey, renamingKey,
isLight,
formatTeamHeader, formatTeamHeader,
onToggleGroup, onToggleGroup,
onVisibleCountChange, onVisibleCountChange,
@ -799,6 +810,7 @@ const ProjectTaskGroup = memo(
isArchived={isArchived} isArchived={isArchived}
isNewTask={isNewTask} isNewTask={isNewTask}
isTeamOffline={isTeamOffline} isTeamOffline={isTeamOffline}
isLight={isLight}
hideTeamName hideTeamName
hideProjectName hideProjectName
showTeamHeader showTeamHeader
@ -860,6 +872,7 @@ const ProjectTaskGroup = memo(
prev.showMoreLabel === next.showMoreLabel && prev.showMoreLabel === next.showMoreLabel &&
prev.showLessLabel === next.showLessLabel && prev.showLessLabel === next.showLessLabel &&
prev.renamingKey === next.renamingKey && prev.renamingKey === next.renamingKey &&
prev.isLight === next.isLight &&
prev.formatTeamHeader === next.formatTeamHeader && prev.formatTeamHeader === next.formatTeamHeader &&
prev.onToggleGroup === next.onToggleGroup && prev.onToggleGroup === next.onToggleGroup &&
prev.onVisibleCountChange === next.onVisibleCountChange && prev.onVisibleCountChange === next.onVisibleCountChange &&
@ -902,6 +915,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
onFiltersPopoverOpenChange: externalOnFiltersPopoverOpenChange, onFiltersPopoverOpenChange: externalOnFiltersPopoverOpenChange,
}: GlobalTaskListProps = {}): React.JSX.Element { }: GlobalTaskListProps = {}): React.JSX.Element {
const { t } = useAppTranslation('common'); const { t } = useAppTranslation('common');
const { isLight } = useTheme();
const { const {
globalTasks, globalTasks,
globalTasksLoading, globalTasksLoading,
@ -1498,6 +1512,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
isArchived={taskLocalState.isArchived} isArchived={taskLocalState.isArchived}
isNewTask={isNewTask} isNewTask={isNewTask}
isTeamOffline={isTeamOffline} isTeamOffline={isTeamOffline}
isLight={isLight}
pinnedOverride={true} pinnedOverride={true}
archivedOverride={false} archivedOverride={false}
showTeamName showTeamName
@ -1601,6 +1616,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
isArchived={taskLocalState.isArchived} isArchived={taskLocalState.isArchived}
isNewTask={isNewTask} isNewTask={isNewTask}
isTeamOffline={isTeamOffline} isTeamOffline={isTeamOffline}
isLight={isLight}
showTeamName showTeamName
renamingKey={renamingTaskKey} renamingKey={renamingTaskKey}
onTogglePin={handleToggleTaskPin} onTogglePin={handleToggleTaskPin}
@ -1634,6 +1650,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
isArchived={taskLocalState.isArchived} isArchived={taskLocalState.isArchived}
isNewTask={isNewTask} isNewTask={isNewTask}
isTeamOffline={isTeamOffline} isTeamOffline={isTeamOffline}
isLight={isLight}
renamingKey={renamingTaskKey} renamingKey={renamingTaskKey}
formatTeamHeader={formatTeamHeader} formatTeamHeader={formatTeamHeader}
onToggleGroup={handleToggleProjectGroup} onToggleGroup={handleToggleProjectGroup}
@ -1682,6 +1699,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
isArchived={taskLocalState.isArchived} isArchived={taskLocalState.isArchived}
isNewTask={isNewTask} isNewTask={isNewTask}
isTeamOffline={isTeamOffline} isTeamOffline={isTeamOffline}
isLight={isLight}
showTeamHeader showTeamHeader
formatTeamHeader={formatTeamHeader} formatTeamHeader={formatTeamHeader}
renamingKey={renamingTaskKey} renamingKey={renamingTaskKey}

View file

@ -69,6 +69,8 @@ interface SidebarTaskItemProps {
hideTeamName?: boolean; hideTeamName?: boolean;
hideProjectName?: boolean; hideProjectName?: boolean;
showTeamName?: boolean; showTeamName?: boolean;
/** Optional theme value from list parents to avoid one theme subscription per row. */
isLight?: boolean;
/** Pauses the in-progress spinner when the parent team is offline. */ /** Pauses the in-progress spinner when the parent team is offline. */
teamOffline?: boolean; teamOffline?: boolean;
/** The composite key "teamName:taskId" of the task being renamed, or null */ /** The composite key "teamName:taskId" of the task being renamed, or null */
@ -82,18 +84,19 @@ interface SidebarTaskItemProps {
ownerColorName?: string | null; ownerColorName?: string | null;
} }
export const SidebarTaskItem = memo(function SidebarTaskItem({ const SidebarTaskItemContent = ({
task, task,
hideTeamName, hideTeamName,
hideProjectName, hideProjectName,
showTeamName, showTeamName,
isLight,
teamOffline = false, teamOffline = false,
renamingKey, renamingKey,
onRenameComplete, onRenameComplete,
onRenameCancel, onRenameCancel,
getDisplaySubject, getDisplaySubject,
ownerColorName, ownerColorName,
}: SidebarTaskItemProps): React.JSX.Element { }: SidebarTaskItemProps & { isLight: boolean }): React.JSX.Element => {
const { t } = useAppTranslation('team'); const { t } = useAppTranslation('team');
const { t: tCommon } = useAppTranslation('common'); const { t: tCommon } = useAppTranslation('common');
const openGlobalTaskDetail = useStore((s) => s.openGlobalTaskDetail); const openGlobalTaskDetail = useStore((s) => s.openGlobalTaskDetail);
@ -104,7 +107,6 @@ export const SidebarTaskItem = memo(function SidebarTaskItem({
) )
); );
const unreadCount = useUnreadCommentCount(task.teamName, task.id, task.comments); const unreadCount = useUnreadCommentCount(task.teamName, task.id, task.comments);
const { isLight } = useTheme();
const isRenaming = renamingKey === `${task.teamName}:${task.id}`; const isRenaming = renamingKey === `${task.teamName}:${task.id}`;
const displaySubject = getDisplaySubject?.(task) ?? task.subject; const displaySubject = getDisplaySubject?.(task) ?? task.subject;
@ -317,4 +319,18 @@ export const SidebarTaskItem = memo(function SidebarTaskItem({
)} )}
</button> </button>
); );
};
const ThemedSidebarTaskItem = (props: SidebarTaskItemProps): React.JSX.Element => {
const { isLight } = useTheme();
return <SidebarTaskItemContent {...props} isLight={isLight} />;
};
export const SidebarTaskItem = memo(function SidebarTaskItem(
props: SidebarTaskItemProps
): React.JSX.Element {
if (typeof props.isLight === 'boolean') {
return <SidebarTaskItemContent {...props} isLight={props.isLight} />;
}
return <ThemedSidebarTaskItem {...props} />;
}); });