diff --git a/public/assets/desktop/desktop.css b/public/assets/desktop/desktop.css index e3929de3..039bed03 100644 --- a/public/assets/desktop/desktop.css +++ b/public/assets/desktop/desktop.css @@ -180,6 +180,42 @@ h1 { .window-resize-handle { position: absolute; + z-index: 2; +} + +.window-resize-handle[data-edge="right"] { + top: 18px; + right: 0; + width: 8px; + height: calc(100% - 36px); + cursor: ew-resize; +} + +.window-resize-handle[data-edge="left"] { + top: 18px; + left: 0; + width: 8px; + height: calc(100% - 36px); + cursor: ew-resize; +} + +.window-resize-handle[data-edge="bottom"] { + left: 18px; + bottom: 0; + width: calc(100% - 36px); + height: 8px; + cursor: ns-resize; +} + +.window-resize-handle[data-edge="top"] { + left: 18px; + top: 0; + width: calc(100% - 36px); + height: 8px; + cursor: ns-resize; +} + +.window-resize-handle[data-edge="corner"] { right: 0; bottom: 0; width: 18px; diff --git a/public/assets/desktop/desktop.js b/public/assets/desktop/desktop.js index 14769558..0962cde9 100644 --- a/public/assets/desktop/desktop.js +++ b/public/assets/desktop/desktop.js @@ -295,46 +295,72 @@ if (payloadNode) { }; const wireResizing = (record) => { - const handle = record.node.querySelector('.window-resize-handle'); - if (!handle || window.matchMedia('(max-width: 1100px)').matches) { + const handles = record.node.querySelectorAll('.window-resize-handle'); + if (!handles.length || window.matchMedia('(max-width: 1100px)').matches) { return; } - let startX = 0; - let startY = 0; - let originWidth = 0; - let originHeight = 0; - let resizing = false; + handles.forEach((handle) => { + let startX = 0; + let startY = 0; + let originX = 0; + let originY = 0; + let originWidth = 0; + let originHeight = 0; + let resizing = false; + const edge = handle.dataset.edge; - handle.addEventListener('pointerdown', (event) => { - if (record.state.maximized) { - return; - } + handle.addEventListener('pointerdown', (event) => { + if (record.state.maximized) { + return; + } - resizing = true; - startX = event.clientX; - startY = event.clientY; - originWidth = record.layout.width; - originHeight = record.layout.height; - handle.setPointerCapture(event.pointerId); - focusWindow(record.id); - event.stopPropagation(); - }); + resizing = true; + startX = event.clientX; + startY = event.clientY; + originX = record.layout.x; + originY = record.layout.y; + originWidth = record.layout.width; + originHeight = record.layout.height; + handle.setPointerCapture(event.pointerId); + focusWindow(record.id); + event.stopPropagation(); + }); - handle.addEventListener('pointermove', (event) => { - if (!resizing) { - return; - } + handle.addEventListener('pointermove', (event) => { + if (!resizing) { + return; + } - record.layout.width = originWidth + event.clientX - startX; - record.layout.height = originHeight + event.clientY - startY; - clampWindowLayout(record); - applyWindowLayout(record); - }); + const deltaX = event.clientX - startX; + const deltaY = event.clientY - startY; - handle.addEventListener('pointerup', () => { - resizing = false; - saveWindowState(); + if (edge === 'right' || edge === 'corner') { + record.layout.width = originWidth + deltaX; + } + + if (edge === 'bottom' || edge === 'corner') { + record.layout.height = originHeight + deltaY; + } + + if (edge === 'left') { + record.layout.x = originX + deltaX; + record.layout.width = originWidth - deltaX; + } + + if (edge === 'top') { + record.layout.y = originY + deltaY; + record.layout.height = originHeight - deltaY; + } + + clampWindowLayout(record); + applyWindowLayout(record); + }); + + handle.addEventListener('pointerup', () => { + resizing = false; + saveWindowState(); + }); }); }; @@ -354,7 +380,11 @@ if (payloadNode) {

${definition.content}

Route: ${definition.app_id}

- + + + + + `; const persisted = persistedWindowState[definition.app_id] || {};