From 8cdfc42300e5088465be6d7e4aa14647ad602935 Mon Sep 17 00:00:00 2001 From: Harald Schilly Date: Tue, 25 Nov 2025 10:55:42 +0100 Subject: [PATCH] frontend/projects/starred: recalc layout only when really necessary --- .../frontend/projects/projects-starred.tsx | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/packages/frontend/projects/projects-starred.tsx b/src/packages/frontend/projects/projects-starred.tsx index 3eba337478..9d406c9b67 100644 --- a/src/packages/frontend/projects/projects-starred.tsx +++ b/src/packages/frontend/projects/projects-starred.tsx @@ -21,7 +21,7 @@ import { import { CSS, useActions, useTypedRedux } from "@cocalc/frontend/app-framework"; import { Icon, TimeAgo } from "@cocalc/frontend/components"; -import { trunc } from "@cocalc/util/misc"; +import { sha1, trunc } from "@cocalc/util/misc"; import { COLORS } from "@cocalc/util/theme"; import { useBookmarkedProjects } from "./use-bookmarked-projects"; @@ -131,9 +131,7 @@ export function StarredProjectsBar() { title: project.get("title") ?? "Untitled", description: project.get("description") ?? "", last_edited: project.get("last_edited"), - state: project.get("state"), avatar_image_tiny: project.get("avatar_image_tiny"), - users: project.get("users"), color: project.get("color"), }; }) @@ -143,6 +141,24 @@ export function StarredProjectsBar() { return projects; }, [bookmarkedProjects, project_map]); + // Hash only the fields that impact layout so we can avoid unnecessary re-measurements. + const layoutKey = useMemo(() => { + if (starredProjects.length === 0) { + return ""; + } + const signature = starredProjects + .map((project) => + [ + project.project_id, + project.title, + project.color ?? "", + project.avatar_image_tiny ?? "", + ].join("|"), + ) + .join("::"); + return sha1(signature); + }, [starredProjects]); + // Drag and drop sensors const mouseSensor = useSensor(MouseSensor, { activationConstraint: { distance: 5 }, // 5px to activate drag @@ -215,7 +231,7 @@ export function StarredProjectsBar() { useLayoutEffect(() => { setMeasurementPhase(true); setVisibleCount(0); - }, [starredProjects]); + }, [layoutKey]); // Measure button widths from hidden container and calculate visible count useLayoutEffect(() => {