diff --git a/static/script.js b/static/script.js index 0a08ef2..277c2c1 100644 --- a/static/script.js +++ b/static/script.js @@ -8,6 +8,8 @@ const SETTINGS_STORAGE_KEY = 'gemini-image-app-settings'; const ZOOM_STEP = 0.1; const MIN_ZOOM = 0.4; const MAX_ZOOM = 4; +const SIDEBAR_MIN_WIDTH = 260; +const SIDEBAR_MAX_WIDTH = 520; const infoContent = { title: 'Thông tin', @@ -47,9 +49,13 @@ const docsContent = { ], }; +const helpContent = { + title: 'Thông tin & Hướng dẫn', + sections: [...infoContent.sections, ...docsContent.sections], +}; + const POPUP_CONTENT = { - info: infoContent, - docs: docsContent, + help: helpContent, }; document.addEventListener('DOMContentLoaded', () => { @@ -70,6 +76,8 @@ document.addEventListener('DOMContentLoaded', () => { const imageInputGrid = document.getElementById('image-input-grid'); const imageDisplayArea = document.querySelector('.image-display-area'); const canvasToolbar = document.querySelector('.canvas-toolbar'); + const sidebar = document.querySelector('.sidebar'); + const resizeHandle = document.querySelector('.sidebar-resize-handle'); let zoomLevel = 1; let panOffset = { x: 0, y: 0 }; @@ -224,6 +232,7 @@ document.addEventListener('DOMContentLoaded', () => { }); loadGallery(); + setupSidebarResizer(sidebar, resizeHandle); function setViewState(state) { placeholderState.classList.add('hidden'); @@ -472,4 +481,48 @@ document.addEventListener('DOMContentLoaded', () => { panOffset = { x: 0, y: 0 }; setImageTransform(); } + + function setupSidebarResizer(sidebar, handle) { + if (!sidebar || !handle) return; + let isResizing = false; + let activePointerId = null; + + const updateWidth = (clientX) => { + const sidebarRect = sidebar.getBoundingClientRect(); + let newWidth = clientX - sidebarRect.left; + newWidth = clamp(newWidth, SIDEBAR_MIN_WIDTH, SIDEBAR_MAX_WIDTH); + sidebar.style.width = `${newWidth}px`; + }; + + const stopResize = () => { + if (!isResizing) return; + isResizing = false; + if (activePointerId !== null) { + try { + handle.releasePointerCapture(activePointerId); + } catch (error) { + console.warn('Unable to release pointer capture', error); + } + activePointerId = null; + } + document.body.style.cursor = ''; + }; + + handle.addEventListener('pointerdown', (event) => { + isResizing = true; + activePointerId = event.pointerId; + handle.setPointerCapture(activePointerId); + document.body.style.cursor = 'ew-resize'; + event.preventDefault(); + }); + + document.addEventListener('pointermove', (event) => { + if (!isResizing) return; + updateWidth(event.clientX); + }); + + document.addEventListener('pointerup', stopResize); + document.addEventListener('pointercancel', stopResize); + } + }); diff --git a/static/style.css b/static/style.css index a04efc9..799db05 100644 --- a/static/style.css +++ b/static/style.css @@ -47,7 +47,7 @@ a:hover { display: flex; height: 100vh; width: 100%; - gap: 1rem; + gap: 0; padding: 1rem; position: relative; z-index: 1; @@ -69,21 +69,25 @@ a:hover { border-radius: 1rem; } -.top-toolbar { - background: transparent; - border: 1px solid rgba(255, 255, 255, 0.08); +.sidebar-resize-handle { + width: 4px; + flex-shrink: 0; + cursor: ew-resize; + position: relative; display: flex; - flex-direction: row; - justify-content: flex-end; - align-items: center; - gap: 0.75rem; - padding: 1rem; - border-radius: 1rem; - width: 100%; + align-self: stretch; +} + +.sidebar-resize-handle::before { + content: ''; + position: absolute; + inset: 0; + background: transparent; } .content-area { flex: 1; + margin-left: 0.5rem; display: flex; flex-direction: column; gap: 1rem; @@ -93,21 +97,19 @@ a:hover { min-height: 0; } -.toolbar-info { - display: flex; - gap: 0.5rem; -} - .toolbar-info-btn { border: 1px solid rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.04); color: var(--text-secondary); - padding: 0.2rem 0.6rem; - border-radius: 999px; - font-size: 0.7rem; + padding: 0.35rem 0.6rem; + border-radius: 0; + font-size: 0.8rem; cursor: pointer; transition: border-color 0.2s, color 0.2s, background 0.2s, box-shadow 0.2s; - line-height: 1.2; + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; } .toolbar-info-btn:hover:not(:disabled) { @@ -122,9 +124,29 @@ a:hover { cursor: not-allowed; } +.sidebar-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1rem; + width: 100%; +} + +.info-icon-btn { + width: 36px; + height: 36px; + padding: 0; + min-width: 36px; + border-radius: 0; + font-size: 1rem; + font-weight: 600; + line-height: 1; +} + .brand { - margin-bottom: 2rem; + margin-bottom: 0; } .brand h1 { diff --git a/templates/index.html b/templates/index.html index b7a15ce..81f19f8 100644 --- a/templates/index.html +++ b/templates/index.html @@ -15,73 +15,74 @@
-