diff --git a/packages/coding-agent/src/core/export-html/template.css b/packages/coding-agent/src/core/export-html/template.css index 6ef5d3976..311af7f74 100644 --- a/packages/coding-agent/src/core/export-html/template.css +++ b/packages/coding-agent/src/core/export-html/template.css @@ -9,6 +9,10 @@ :root { --line-height: 18px; /* 12px font * 1.5 */ + --sidebar-width: 400px; + --sidebar-min-width: 240px; + --sidebar-max-width: 840px; + --sidebar-resizer-width: 6px; } body { @@ -19,6 +23,11 @@ background: var(--body-bg); } + body.sidebar-resizing { + cursor: col-resize; + user-select: none; + } + #app { display: flex; min-height: 100vh; @@ -26,7 +35,9 @@ /* Sidebar */ #sidebar { - width: 400px; + width: var(--sidebar-width); + min-width: var(--sidebar-width); + max-width: var(--sidebar-width); background: var(--container-bg); flex-shrink: 0; display: flex; @@ -37,6 +48,24 @@ border-right: 1px solid var(--dim); } + #sidebar-resizer { + width: var(--sidebar-resizer-width); + flex-shrink: 0; + position: sticky; + top: 0; + height: 100vh; + cursor: col-resize; + touch-action: none; + background: transparent; + border-right: 1px solid transparent; + } + + #sidebar-resizer:hover, + body.sidebar-resizing #sidebar-resizer { + background: var(--selectedBg); + border-right-color: var(--dim); + } + .sidebar-header { padding: 8px 12px; flex-shrink: 0; @@ -213,6 +242,7 @@ /* Main content */ #content { flex: 1; + min-width: 0; overflow-y: auto; padding: var(--line-height) calc(var(--line-height) * 2); display: flex; @@ -923,17 +953,24 @@ @media (max-width: 900px) { #sidebar { position: fixed; - left: -400px; - width: 400px; + left: 0; + width: min(var(--sidebar-width), 100vw); + min-width: min(var(--sidebar-width), 100vw); + max-width: min(var(--sidebar-width), 100vw); top: 0; bottom: 0; height: 100vh; z-index: 99; - transition: left 0.3s; + transform: translateX(-100%); + transition: transform 0.3s; } #sidebar.open { - left: 0; + transform: translateX(0); + } + + #sidebar-resizer { + display: none; } #sidebar-overlay.open { @@ -957,15 +994,8 @@ } } - @media (max-width: 500px) { - #sidebar { - width: 100vw; - left: -100vw; - } - } - @media print { - #sidebar, #sidebar-toggle { display: none !important; } + #sidebar, #sidebar-resizer, #sidebar-toggle { display: none !important; } body { background: white; color: black; } #content { max-width: none; } } diff --git a/packages/coding-agent/src/core/export-html/template.html b/packages/coding-agent/src/core/export-html/template.html index 42f2a45b0..c1d678a0a 100644 --- a/packages/coding-agent/src/core/export-html/template.html +++ b/packages/coding-agent/src/core/export-html/template.html @@ -29,6 +29,7 @@
+
diff --git a/packages/coding-agent/src/core/export-html/template.js b/packages/coding-agent/src/core/export-html/template.js index e170d7a6b..6b53516b1 100644 --- a/packages/coding-agent/src/core/export-html/template.js +++ b/packages/coding-agent/src/core/export-html/template.js @@ -1510,6 +1510,113 @@ const sidebar = document.getElementById('sidebar'); const overlay = document.getElementById('sidebar-overlay'); const hamburger = document.getElementById('hamburger'); + const sidebarResizer = document.getElementById('sidebar-resizer'); + const SIDEBAR_WIDTH_STORAGE_KEY = 'pi-share:v1:sidebar-width'; + const MIN_CONTENT_WIDTH = 320; + + function isMobileLayout() { + return window.matchMedia('(max-width: 900px)').matches; + } + + function getSidebarBounds() { + const rootStyles = getComputedStyle(document.documentElement); + const minWidth = parseFloat(rootStyles.getPropertyValue('--sidebar-min-width')) || 240; + const maxWidth = parseFloat(rootStyles.getPropertyValue('--sidebar-max-width')) || 720; + const viewportMaxWidth = window.innerWidth - MIN_CONTENT_WIDTH; + return { + minWidth, + maxWidth: Math.max(minWidth, Math.min(maxWidth, viewportMaxWidth)) + }; + } + + function clampSidebarWidth(width) { + const { minWidth, maxWidth } = getSidebarBounds(); + return Math.max(minWidth, Math.min(maxWidth, width)); + } + + function applySidebarWidth(width) { + document.documentElement.style.setProperty('--sidebar-width', `${Math.round(clampSidebarWidth(width))}px`); + } + + function loadSidebarWidth() { + try { + const raw = localStorage.getItem(SIDEBAR_WIDTH_STORAGE_KEY); + if (raw === null) return null; + const width = Number(raw); + return Number.isFinite(width) ? width : null; + } catch { + return null; + } + } + + function saveSidebarWidth(width) { + try { + localStorage.setItem(SIDEBAR_WIDTH_STORAGE_KEY, String(Math.round(clampSidebarWidth(width)))); + } catch { + // Ignore storage failures (e.g. private browsing restrictions) + } + } + + function setupSidebarResize() { + const savedWidth = loadSidebarWidth(); + if (savedWidth !== null) { + applySidebarWidth(savedWidth); + } + + if (!sidebarResizer) return; + + let cleanupDrag = null; + + const stopDrag = (pointerId) => { + if (cleanupDrag) { + cleanupDrag(pointerId); + cleanupDrag = null; + } + }; + + sidebarResizer.addEventListener('pointerdown', (e) => { + if (isMobileLayout()) return; + + e.preventDefault(); + const startX = e.clientX; + const startWidth = sidebar.getBoundingClientRect().width; + document.body.classList.add('sidebar-resizing'); + sidebarResizer.setPointerCapture?.(e.pointerId); + + const onPointerMove = (event) => { + applySidebarWidth(startWidth + (event.clientX - startX)); + }; + + cleanupDrag = (pointerIdToRelease) => { + document.body.classList.remove('sidebar-resizing'); + sidebarResizer.releasePointerCapture?.(pointerIdToRelease); + window.removeEventListener('pointermove', onPointerMove); + window.removeEventListener('pointerup', onPointerUp); + window.removeEventListener('pointercancel', onPointerCancel); + saveSidebarWidth(sidebar.getBoundingClientRect().width); + }; + + const onPointerUp = (event) => stopDrag(event.pointerId); + const onPointerCancel = (event) => stopDrag(event.pointerId); + + window.addEventListener('pointermove', onPointerMove); + window.addEventListener('pointerup', onPointerUp); + window.addEventListener('pointercancel', onPointerCancel); + }); + + sidebarResizer.addEventListener('dblclick', () => { + if (isMobileLayout()) return; + applySidebarWidth(400); + saveSidebarWidth(400); + }); + + window.addEventListener('resize', () => { + if (isMobileLayout()) return; + applySidebarWidth(sidebar.getBoundingClientRect().width); + }); + } + + setupSidebarResize(); hamburger.addEventListener('click', () => { sidebar.classList.add('open');