Skip to content
29 changes: 27 additions & 2 deletions internal/server/static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -626,17 +647,21 @@ 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;
border-right: none;
font-family: inherit;
font-size: 0.9em;
color: var(--text-primary-gray);
box-sizing: border-box;

&:focus {
outline: none;
Expand Down
116 changes: 116 additions & 0 deletions internal/server/static/js/resize.js
Original file line number Diff line number Diff line change
@@ -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`;
}
Comment thread
duwenxin99 marked this conversation as resolved.

10 changes: 7 additions & 3 deletions internal/server/static/tools.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ <h4>My Tools</h4>
<script type="module" src="/ui/js/tools.js"></script>
<script src="/ui/js/navbar.js"></script>
<script src="/ui/js/mainContent.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
<script type="module">
document.addEventListener('DOMContentLoaded', async () => {
const navbarContainer = document.getElementById('navbar-container');
const activeNav = navbarContainer.getAttribute('data-active-nav');
renderNavbar('navbar-container', activeNav);
renderMainContent('main-content-container', 'tool-display-area', getToolInstructions())
renderMainContent('main-content-container', 'tool-display-area', getToolInstructions());

// Initialize resize functionality
const { initializeResize } = await import('/ui/js/resize.js');
initializeResize();
});
</script>
</body>
Expand Down
8 changes: 6 additions & 2 deletions internal/server/static/toolsets.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ <h4>Retrieve Toolset</h4>
<script type="module" src="/ui/js/toolsets.js"></script>
<script src="/ui/js/navbar.js"></script>
<script src="/ui/js/mainContent.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
<script type="module">
document.addEventListener('DOMContentLoaded', async () => {
const navbarContainer = document.getElementById('navbar-container');
const activeNav = navbarContainer.getAttribute('data-active-nav');
renderNavbar('navbar-container', activeNav);
renderMainContent('main-content-container', 'tool-display-area', getToolsetInstructions());

// Initialize resize functionality
const { initializeResize } = await import('/ui/js/resize.js');
initializeResize();
});
</script>
</body>
Expand Down
Loading