diff --git a/src/lib/components/chat/ChatControls.svelte b/src/lib/components/chat/ChatControls.svelte index aa15ee4476..894b545162 100644 --- a/src/lib/components/chat/ChatControls.svelte +++ b/src/lib/components/chat/ChatControls.svelte @@ -310,6 +310,9 @@ open={$showControls} bind:width={controlsWidth} minWidth={350} + minSiblingWidth={360} + closeOnDragBelowMinWidth + onClose={() => showControls.set(false)} storageKey="chatControlsSize" className="h-full z-10 bg-white dark:bg-gray-900" > diff --git a/src/lib/components/common/ResizableSidePanel.svelte b/src/lib/components/common/ResizableSidePanel.svelte index c1d469f2fe..76da0e7c40 100644 --- a/src/lib/components/common/ResizableSidePanel.svelte +++ b/src/lib/components/common/ResizableSidePanel.svelte @@ -6,16 +6,36 @@ export let width = 350; export let minWidth = 300; export let maxWidth: number | null = null; + export let minSiblingWidth = 0; + export let closeOnDragBelowMinWidth = false; export let storageKey = ''; export let className = ''; export let resizerId = 'controls-resizer'; + export let onClose: () => void = () => {}; + let panelElement: HTMLDivElement | null = null; let isResizing = false; let startClientX = 0; let startWidth = 0; - const clamp = (value: number) => - maxWidth === null ? Math.max(minWidth, value) : Math.min(maxWidth, Math.max(minWidth, value)); + const getMaxWidth = () => { + const siblingMaxWidth = + minSiblingWidth > 0 && panelElement?.parentElement + ? Math.max(0, panelElement.parentElement.clientWidth - minSiblingWidth) + : null; + + if (maxWidth === null) { + return siblingMaxWidth; + } + return siblingMaxWidth === null ? maxWidth : Math.min(maxWidth, siblingMaxWidth); + }; + + const clamp = (value: number) => { + const resolvedMaxWidth = getMaxWidth(); + const minimum = resolvedMaxWidth === null ? minWidth : Math.min(minWidth, resolvedMaxWidth); + const clampedToMin = Math.max(minimum, value); + return resolvedMaxWidth === null ? clampedToMin : Math.min(resolvedMaxWidth, clampedToMin); + }; const persistWidth = () => { if (storageKey) { @@ -23,6 +43,11 @@ } }; + const close = () => { + open = false; + onClose(); + }; + const resizeStartHandler = (e: MouseEvent) => { if (!open) return; @@ -42,7 +67,13 @@ const resizeHandler = (endClientX: number) => { const dx = endClientX - startClientX; - width = clamp(side === 'right' ? startWidth - dx : startWidth + dx); + const nextWidth = side === 'right' ? startWidth - dx : startWidth + dx; + if (closeOnDragBelowMinWidth && nextWidth < minWidth) { + close(); + resizeEndHandler(); + return; + } + width = clamp(nextWidth); }; const resizeKeyHandler = (e: KeyboardEvent) => { @@ -63,6 +94,13 @@ } }); + $: if (open && panelElement) { + const clampedWidth = clamp(width); + if (clampedWidth !== width) { + width = clampedWidth; + } + } + onDestroy(() => { if (isResizing) { document.body.style.userSelect = ''; @@ -75,6 +113,9 @@ if (!isResizing) return; resizeHandler(e.clientX); }} + on:resize={() => { + if (open) width = clamp(width); + }} on:mouseup={resizeEndHandler} /> @@ -97,7 +138,7 @@ {/if} -