feat: add resizable desktop panes
ci / gitleaks (push) Successful in 6s
ci / docker (push) Successful in 3m32s

This commit is contained in:
2026-09-20 11:33:43 +08:00
parent 3a23c6cd44
commit 8ab5ad05a0
7 changed files with 259 additions and 19 deletions
@@ -0,0 +1,33 @@
import { describe, expect, it } from 'vitest'
import { clampDesktopPaneWidth, getDesktopPaneMax, readDesktopPaneWidth, writeDesktopPaneWidth } from './desktop-shell-resize'
describe('desktop shell resize', () => {
it('clamps the sidebar while preserving the center and detail panes', () => {
expect(clampDesktopPaneWidth('sidebar', 120, 1440, 350)).toBe(190)
expect(clampDesktopPaneWidth('sidebar', 500, 1440, 350)).toBe(360)
expect(clampDesktopPaneWidth('sidebar', 360, 931, 350)).toBe(251)
})
it('clamps the detail pane while preserving the center and sidebar panes', () => {
expect(clampDesktopPaneWidth('detail', 240, 1440, 236)).toBe(300)
expect(clampDesktopPaneWidth('detail', 600, 1440, 236)).toBe(520)
expect(clampDesktopPaneWidth('detail', 520, 931, 236)).toBe(365)
})
it('reports the effective maximum at narrow desktop widths', () => {
expect(getDesktopPaneMax('sidebar', 931, 350)).toBe(251)
expect(getDesktopPaneMax('detail', 931, 236)).toBe(365)
expect(getDesktopPaneMax('detail', 1440, 236)).toBe(520)
})
it('restores only finite persisted widths', () => {
const storage = { getItem: (key: string) => key.endsWith('sidebar') ? '288' : 'oops' }
expect(readDesktopPaneWidth(storage, 'dodo.desktop.sidebar', 236)).toBe(288)
expect(readDesktopPaneWidth(storage, 'dodo.desktop.detail', 350)).toBe(350)
expect(readDesktopPaneWidth({ getItem: () => { throw new Error('blocked') } }, 'key', 236)).toBe(236)
})
it('ignores storage write failures', () => {
expect(() => writeDesktopPaneWidth({ setItem: () => { throw new Error('blocked') } }, 'key', 300)).not.toThrow()
})
})
+31
View File
@@ -0,0 +1,31 @@
export type DesktopPane = 'sidebar' | 'detail'
const SIDEBAR_MIN = 190
const SIDEBAR_MAX = 360
const DETAIL_MIN = 300
const DETAIL_MAX = 520
const CENTER_MIN = 330
export function getDesktopPaneMax(pane: DesktopPane, viewportWidth: number, otherPaneWidth: number) {
const lower = pane === 'sidebar' ? SIDEBAR_MIN : DETAIL_MIN
const upper = pane === 'sidebar' ? SIDEBAR_MAX : DETAIL_MAX
return Math.round(Math.min(upper, Math.max(lower, viewportWidth - otherPaneWidth - CENTER_MIN)))
}
export function clampDesktopPaneWidth(pane: DesktopPane, width: number, viewportWidth: number, otherPaneWidth: number) {
const lower = pane === 'sidebar' ? SIDEBAR_MIN : DETAIL_MIN
return Math.round(Math.min(Math.max(width, lower), getDesktopPaneMax(pane, viewportWidth, otherPaneWidth)))
}
export function readDesktopPaneWidth(storage: Pick<Storage, 'getItem'>, key: string, fallback: number) {
try {
const value = Number(storage.getItem(key))
return Number.isFinite(value) && value > 0 ? value : fallback
} catch {
return fallback
}
}
export function writeDesktopPaneWidth(storage: Pick<Storage, 'setItem'>, key: string, width: number) {
try { storage.setItem(key, String(width)) } catch { /* storage can be unavailable */ }
}