From 441b318334620f7a8f9db39bd56d576bf9f6a62d Mon Sep 17 00:00:00 2001 From: Gagancreates Date: Mon, 8 Jun 2026 00:58:40 +0530 Subject: [PATCH] fix: progressive right-to-left icon collapse for chat toolbar --- .../components/chat-input-with-mentions.tsx | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx b/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx index c46bbb11..979df9b5 100644 --- a/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx +++ b/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx @@ -283,41 +283,36 @@ function ChatInputInner({ const [permissionMode, setPermissionMode] = useState('auto') const [recentWorkDirs, setRecentWorkDirs] = useState([]) const toolbarRef = useRef(null) - const leftGroupRef = useRef(null) - const [isCompact, setIsCompact] = useState(false) - // Outer toolbar width when we last switched to compact — used to add hysteresis so - // we don't oscillate back to full mode the moment icons fit. - const compactAtWidthRef = useRef(null) + // 0 = all full; collapse order (right→left): 1=code, 2=search, 3=workDir, 4=perm + const [collapseLevel, setCollapseLevel] = useState(0) useEffect(() => { - const outer = toolbarRef.current - const left = leftGroupRef.current - if (!outer || !left) return - const ro = new ResizeObserver(() => { - const outerWidth = outer.clientWidth - setIsCompact(prev => { - if (!prev) { - // Full mode: switch to compact if left-group content overflows its box - if (left.scrollWidth > left.clientWidth) { - compactAtWidthRef.current = outerWidth - return true - } - return false - } else { - // Compact mode: only return to full when container has grown 60 px beyond - // where we went compact — prevents rapid oscillation at the boundary. - const trigger = compactAtWidthRef.current - if (trigger !== null && outerWidth >= trigger + 60) { - compactAtWidthRef.current = null - return false - } - return true - } - }) + const el = toolbarRef.current + if (!el) return + const ro = new ResizeObserver(([entry]) => { + const w = entry.contentRect.width + // Approximate full/compact px widths per item (icon = 28, gap = 8) + const codeOn = codeModeEnabled && codeModeFeatureEnabled + const codeFullW = codeOn ? 85 + 8 : 0 + const codeIconW = codeOn ? 28 + 8 : 0 + const searchFullW = searchAvailable ? (searchEnabled ? 75 + 8 : 28 + 8) : 0 + const searchIconW = searchAvailable ? 28 + 8 : 0 + const workDirFullW = workDir ? 120 + 8 : 0 + const workDirIconW = workDir ? 28 + 8 : 0 + const permFullW = 65 + 8 // "Auto" label + const permIconW = 28 + 8 + const base = 28 + 80 + 28 + 2 * 8 // +btn + model + submit + 2 outer gaps + // Min container width to fit each level without overflowing + const t0 = base + permFullW + workDirFullW + searchFullW + codeFullW // all full + const t1 = base + permFullW + workDirFullW + searchFullW + codeIconW // code → icon + const t2 = base + permFullW + workDirFullW + searchIconW + codeIconW // search → icon + const t3 = base + permFullW + workDirIconW + searchIconW + codeIconW // workDir → icon + const t4 = base + permIconW + workDirIconW + searchIconW + codeIconW // perm → icon + setCollapseLevel(w >= t0 ? 0 : w >= t1 ? 1 : w >= t2 ? 2 : w >= t3 ? 3 : w >= t4 ? 4 : 4) }) - ro.observe(outer) + ro.observe(el) return () => ro.disconnect() - }, []) + }, [workDir, searchAvailable, searchEnabled, codeModeEnabled, codeModeFeatureEnabled]) // When a run exists, freeze the dropdown to the run's resolved model+provider. useEffect(() => { @@ -794,7 +789,7 @@ function ChatInputInner({ />
-
+
@@ -902,7 +897,7 @@ function ChatInputInner({ {workDir && ( - {isCompact ? ( + {collapseLevel >= 3 ? ( @@ -992,7 +987,7 @@ function ChatInputInner({ {codeModeFeatureEnabled && (codeModeEnabled ? ( - isCompact ? ( + collapseLevel >= 1 ? (