feat: enhance control panel UI and resize functionality
Panel UI improvements: - Replace heading elements (h1-h6) with styled divs to avoid navigation interference - Change ContentsControl position from northwest to west for better accessibility Panel collapse/expand enhancements: - Fix panel dragging to prevent unexpected positioning jumps - Keep panel width and upper-left position when collapsing to header-only mode - Complete height reduction when collapsed (no minimal size maintained) - Toggle resize handle visibility based on panel state Resize handle improvements: - Change resize symbol from arrow to clean dot (●) in bottom-right corner - Remove background circle, show transparent dot only - Fix resize direction to properly follow mouse movement from bottom-right - Set dynamic minimum size constraints (header height + padding) - Allow arbitrary panel sizing with proper bounds checking - Reset panel size to defaults when closed/collapsed 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -334,6 +334,17 @@ class ControlBase {
|
||||
this.element.style.transform = this.originalPosition.transform || '';
|
||||
}
|
||||
|
||||
// Reset panel size to defaults
|
||||
panel.style.width = '';
|
||||
panel.style.height = '';
|
||||
panel.style.minWidth = '300px';
|
||||
panel.style.minHeight = '200px';
|
||||
|
||||
// Reset internal size tracking
|
||||
this.size.width = 300;
|
||||
this.size.height = 200;
|
||||
this.storedWidth = null;
|
||||
|
||||
// Remove resize handle
|
||||
this.removeResizeHandle();
|
||||
}
|
||||
@@ -354,9 +365,52 @@ class ControlBase {
|
||||
}
|
||||
|
||||
const content = this.element?.querySelector('.control-content');
|
||||
if (content) {
|
||||
const panel = this.element?.querySelector('.control-panel-expanded');
|
||||
|
||||
if (content && panel) {
|
||||
this.isHeaderOnly = !this.isHeaderOnly;
|
||||
content.style.display = this.isHeaderOnly ? 'none' : 'block';
|
||||
const resizeHandle = this.element?.querySelector('.control-resize-handle');
|
||||
|
||||
if (this.isHeaderOnly) {
|
||||
// Store current width before collapsing
|
||||
const currentWidth = panel.offsetWidth;
|
||||
this.storedWidth = currentWidth;
|
||||
|
||||
// Hide content and shrink panel height only
|
||||
content.style.display = 'none';
|
||||
panel.style.minHeight = 'auto';
|
||||
panel.style.height = 'auto';
|
||||
|
||||
// Keep the same width and position
|
||||
panel.style.width = `${currentWidth}px`;
|
||||
panel.style.minWidth = `${currentWidth}px`;
|
||||
|
||||
// Hide resize handle in header-only mode
|
||||
if (resizeHandle) {
|
||||
resizeHandle.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
// Show content and restore full panel size
|
||||
content.style.display = 'block';
|
||||
panel.style.minHeight = '200px';
|
||||
|
||||
// Restore stored width or use default
|
||||
const widthToRestore = this.storedWidth || 300;
|
||||
panel.style.minWidth = `${widthToRestore}px`;
|
||||
|
||||
// Restore height if it was auto
|
||||
if (!panel.style.height || panel.style.height === 'auto') {
|
||||
panel.style.height = '200px';
|
||||
}
|
||||
if (!panel.style.width || panel.style.width === `${widthToRestore}px`) {
|
||||
panel.style.width = `${widthToRestore}px`;
|
||||
}
|
||||
|
||||
// Show resize handle when fully expanded
|
||||
if (resizeHandle) {
|
||||
resizeHandle.style.display = 'flex';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.isHeaderOnly;
|
||||
@@ -378,11 +432,24 @@ class ControlBase {
|
||||
y: event.clientY - rect.top
|
||||
};
|
||||
|
||||
// Store current computed position before clearing styles
|
||||
const computedStyle = window.getComputedStyle(this.element);
|
||||
const currentLeft = rect.left;
|
||||
const currentTop = rect.top;
|
||||
|
||||
// Clear any positioning styles that interfere with dragging
|
||||
this.element.style.right = '';
|
||||
this.element.style.bottom = '';
|
||||
this.element.style.transform = '';
|
||||
|
||||
// Set the element to its current visual position using left/top
|
||||
this.element.style.left = `${currentLeft}px`;
|
||||
this.element.style.top = `${currentTop}px`;
|
||||
|
||||
// Update internal position tracking
|
||||
this.position.x = currentLeft;
|
||||
this.position.y = currentTop;
|
||||
|
||||
// Add global mouse move and up handlers
|
||||
const handleMouseMove = (e) => this.handleDrag(e);
|
||||
const handleMouseUp = () => this.stopDrag();
|
||||
@@ -441,21 +508,19 @@ class ControlBase {
|
||||
|
||||
const resizeHandle = document.createElement('div');
|
||||
resizeHandle.className = 'control-resize-handle';
|
||||
resizeHandle.innerHTML = '↙'; // Bottom-left resize indicator
|
||||
resizeHandle.innerHTML = '●'; // Dot resize indicator
|
||||
resizeHandle.style.cssText = `
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: nw-resize;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0,0,0,0.1);
|
||||
border-radius: 0 8px 0 0;
|
||||
bottom: 4px;
|
||||
right: 4px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
cursor: se-resize;
|
||||
font-size: 8px;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
color: #999;
|
||||
background: transparent;
|
||||
`;
|
||||
|
||||
// Add to the expanded panel
|
||||
@@ -510,7 +575,7 @@ class ControlBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle resize movement (bottom-left corner resize)
|
||||
* Handle resize movement (bottom-right corner resize)
|
||||
*/
|
||||
handleResize(event) {
|
||||
if (!this.isResizing || !this.element) return;
|
||||
@@ -518,13 +583,18 @@ class ControlBase {
|
||||
const panel = this.element.querySelector('.control-panel-expanded');
|
||||
if (!panel) return;
|
||||
|
||||
// Calculate size change based on mouse movement
|
||||
const deltaX = this.resizeStart.mouseX - event.clientX; // Inverted for left edge
|
||||
const deltaY = event.clientY - this.resizeStart.mouseY;
|
||||
// Calculate size change based on mouse movement (bottom-right corner)
|
||||
const deltaX = event.clientX - this.resizeStart.mouseX; // Right direction
|
||||
const deltaY = event.clientY - this.resizeStart.mouseY; // Down direction
|
||||
|
||||
// Calculate new dimensions (minimum size constraints)
|
||||
const newWidth = Math.max(200, this.resizeStart.width + deltaX);
|
||||
const newHeight = Math.max(150, this.resizeStart.height + deltaY);
|
||||
// Get minimum size (collapsed header size or default minimum)
|
||||
const headerHeight = this.element.querySelector('.control-header')?.offsetHeight || 40;
|
||||
const minWidth = 200;
|
||||
const minHeight = headerHeight + 20; // Header plus small padding
|
||||
|
||||
// Calculate new dimensions with minimum constraints
|
||||
const newWidth = Math.max(minWidth, this.resizeStart.width + deltaX);
|
||||
const newHeight = Math.max(minHeight, this.resizeStart.height + deltaY);
|
||||
|
||||
// Apply new size to the panel
|
||||
panel.style.width = `${newWidth}px`;
|
||||
|
||||
Reference in New Issue
Block a user