diff --git a/internal/server/static/css/style.css b/internal/server/static/css/style.css index 47d8a35974b..b0c1968c1b6 100644 --- a/internal/server/static/css/style.css +++ b/internal/server/static/css/style.css @@ -87,8 +87,29 @@ body { display: flex; flex-direction: column; padding: 15px; - align-items: center; + align-items: stretch; position: relative; + min-width: 200px; + max-width: 50vw; + overflow: visible; + box-sizing: border-box; +} + +.resize-handle { + position: absolute; + right: -2px; + top: 0; + bottom: 0; + width: 4px; + cursor: ew-resize; + background-color: transparent; + z-index: 10; + transition: background-color 0.2s ease; +} + +.resize-handle:hover, +.resize-handle.active { + background-color: var(--toolbox-blue); } .nav-logo { @@ -626,10 +647,13 @@ body { .search-container { display: flex; width: 100%; + min-width: 0; margin-bottom: 15px; + box-sizing: border-box; #toolset-search-input { - flex-grow: 1; + flex: 1; + min-width: 0; padding: 10px 12px; border: 1px solid #ccc; border-radius: 20px 0 0 20px; @@ -637,6 +661,7 @@ body { font-family: inherit; font-size: 0.9em; color: var(--text-primary-gray); + box-sizing: border-box; &:focus { outline: none; diff --git a/internal/server/static/js/resize.js b/internal/server/static/js/resize.js new file mode 100644 index 00000000000..f2ff490fe33 --- /dev/null +++ b/internal/server/static/js/resize.js @@ -0,0 +1,116 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const STORAGE_KEY = 'toolbox-second-nav-width'; +const DEFAULT_WIDTH = 250; +const MIN_WIDTH = 200; +const MAX_WIDTH_PERCENT = 50; + +/** + * Creates and attaches a resize handle to the second navigation panel + */ +export function initializeResize() { + const secondNav = document.querySelector('.second-nav'); + if (!secondNav) { + return; + } + + // Create resize handle + const resizeHandle = document.createElement('div'); + resizeHandle.className = 'resize-handle'; + resizeHandle.setAttribute('aria-label', 'Resize panel'); + secondNav.appendChild(resizeHandle); + + // Load saved width or use default + let initialWidth = DEFAULT_WIDTH; + try { + const savedWidth = localStorage.getItem(STORAGE_KEY); + if (savedWidth) { + const parsed = parseInt(savedWidth, 10); + if (!isNaN(parsed) && parsed >= MIN_WIDTH) { + initialWidth = parsed; + } + } + } catch (e) { + // localStorage may be unavailable in private browsing mode + console.warn('Failed to load saved panel width:', e); + } + setPanelWidth(secondNav, initialWidth); + + // Setup resize functionality + let startX = 0; + let startWidth = 0; + + const onMouseMove = (e) => { + const deltaX = e.clientX - startX; + const newWidth = startWidth + deltaX; + const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100; + + const clampedWidth = Math.max(MIN_WIDTH, Math.min(newWidth, maxWidth)); + setPanelWidth(secondNav, clampedWidth); + }; + + const onMouseUp = () => { + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); + + resizeHandle.classList.remove('active'); + document.body.style.cursor = ''; + document.body.style.userSelect = ''; + + // Save width to localStorage + try { + localStorage.setItem(STORAGE_KEY, secondNav.offsetWidth.toString()); + } catch (e) { + // localStorage may be unavailable in private browsing mode + console.warn('Failed to save panel width:', e); + } + }; + + resizeHandle.addEventListener('mousedown', (e) => { + startX = e.clientX; + startWidth = secondNav.offsetWidth; + resizeHandle.classList.add('active'); + document.body.style.cursor = 'ew-resize'; + document.body.style.userSelect = 'none'; + e.preventDefault(); + + document.addEventListener('mousemove', onMouseMove); + document.addEventListener('mouseup', onMouseUp); + }); + + // Handle window resize to enforce max width + window.addEventListener('resize', () => { + const currentWidth = secondNav.offsetWidth; + const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100; + + if (currentWidth > maxWidth) { + setPanelWidth(secondNav, maxWidth); + try { + localStorage.setItem(STORAGE_KEY, maxWidth.toString()); + } catch (e) { + // localStorage may be unavailable in private browsing mode + console.warn('Failed to save panel width:', e); + } + } + }); +} + +/** + * Sets the width of the panel and updates flex property + */ +function setPanelWidth(panel, width) { + panel.style.flex = `0 0 ${width}px`; +} + diff --git a/internal/server/static/tools.html b/internal/server/static/tools.html index c618c5111b4..f461cc80ad5 100644 --- a/internal/server/static/tools.html +++ b/internal/server/static/tools.html @@ -22,12 +22,16 @@

My Tools

- diff --git a/internal/server/static/toolsets.html b/internal/server/static/toolsets.html index adcd5fdfde8..84907222603 100644 --- a/internal/server/static/toolsets.html +++ b/internal/server/static/toolsets.html @@ -29,12 +29,16 @@

Retrieve Toolset

-