refactor(splitpanes): extract pixel-aware minSize helper

This commit is contained in:
Guilhem Lemouel
2026-05-21 09:54:20 +02:00
parent 20d45916c4
commit c1dbca92a8
3 changed files with 60 additions and 5 deletions
@@ -1,5 +1,6 @@
<script lang="ts">
import { buildWsUrl } from '$lib/wsUrl'
import { paneMinPercent } from '$lib/utils/splitpaneSizing'
import { processSecretArgs } from './secretArgUtils'
import type { Schema, SupportedLanguage } from '$lib/common'
import {
@@ -1351,7 +1352,7 @@
let splitContainerWidth = $state(0)
const TEST_PANE_MIN_PX = 400
const testPaneMinPercent = $derived(
splitContainerWidth > 0 ? Math.min(80, (TEST_PANE_MIN_PX / splitContainerWidth) * 100) : 0
paneMinPercent(splitContainerWidth, TEST_PANE_MIN_PX)
)
// Raw user-controlled test size (what the splitter wrote, or what the
@@ -1,5 +1,6 @@
<script lang="ts">
import { Pane, Splitpanes } from 'svelte-splitpanes'
import { paneMinPercent } from '$lib/utils/splitpaneSizing'
import RawAppInlineScriptsPanel from './RawAppInlineScriptsPanel.svelte'
import type { JobById } from '../apps/types'
import RawAppEditorHeader from './RawAppEditorHeader.svelte'
@@ -400,7 +401,20 @@
}
let yamlEditorDrawer: Drawer | undefined = $state(undefined)
let sidebarPanelSize = $state(15)
// Sidebar uses a dynamic pixel-aware minimum: the user's `%` preference is
// honored, but the pane can never shrink below SIDEBAR_PX_MIN — including
// when the container itself shrinks. svelte-splitpanes' `minSize` only
// blocks splitter drag, so we clamp `sidebarPanelSize` ourselves and use a
// getter/setter bind so the user's preference is preserved.
let rawSidebarSize = $state(15)
let splitContainerWidth = $state(0)
const SIDEBAR_PX_MIN = 160
const sidebarMinPercent = $derived(
paneMinPercent(splitContainerWidth, SIDEBAR_PX_MIN)
)
const sidebarPanelSize = $derived(
Math.max(rawSidebarSize, sidebarMinPercent)
)
// Persisted across opens. Seeded with `defaultSidebarCollapsed` only when
// localStorage has no entry yet — callers (like the session preview pane)
@@ -1339,9 +1353,14 @@
onApply={handleYamlApply}
/>
<Splitpanes id="o2" class="grow min-h-0 border-t">
{#if !sidebarCollapsed.val}
<Pane bind:size={sidebarPanelSize} maxSize={20} class="h-full overflow-y-auto relative">
<div bind:clientWidth={splitContainerWidth} class="grow min-h-0 flex flex-col">
<Splitpanes id="o2" class="grow min-h-0 border-t">
{#if !sidebarCollapsed.val}
<Pane
bind:size={() => sidebarPanelSize, (v) => (rawSidebarSize = v)}
minSize={sidebarMinPercent}
class="h-full overflow-y-auto relative"
>
<RawAppSidebar
bind:files={
() => files,
@@ -1604,6 +1623,7 @@
</div>
</Pane>
</Splitpanes>
</div>
</div>
<style>
+34
View File
@@ -0,0 +1,34 @@
/**
* Helpers for using `svelte-splitpanes` with pixel-aware minimum widths.
*
* `svelte-splitpanes` only takes percentages for its `size`/`minSize`/`maxSize`
* props, so when we need a pane to never shrink below a pixel threshold
* (e.g. a sidebar that's unreadable under 160 px) we have to convert the
* threshold into a percentage of the splitpane container's current width.
*
* Pattern at call sites:
*
* ```svelte
* <div bind:clientWidth={containerWidth} class="h-full">
* <Splitpanes>
* <Pane minSize={paneMinPercent(containerWidth, 160)}>...</Pane>
* </Splitpanes>
* </div>
* ```
*/
/**
* Returns the percentage of `containerWidth` that corresponds to `minPx`,
* capped at `cap` percent (default 80) so callers can't accidentally make
* the pane fill the container in very narrow viewports.
*
* Returns 0 when the container width isn't yet known (initial render).
*/
export function paneMinPercent(
containerWidth: number,
minPx: number,
cap: number = 80
): number {
if (containerWidth <= 0) return 0
return Math.min(cap, (minPx / containerWidth) * 100)
}