diff --git a/capabilities/testdrive-jsui/js/controls/control-base.js b/capabilities/testdrive-jsui/js/controls/control-base.js index 0706c4b7..7b42d94a 100644 --- a/capabilities/testdrive-jsui/js/controls/control-base.js +++ b/capabilities/testdrive-jsui/js/controls/control-base.js @@ -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`; diff --git a/capabilities/testdrive-jsui/js/controls/debug-control.js b/capabilities/testdrive-jsui/js/controls/debug-control.js index 592ddea8..dfc63209 100644 --- a/capabilities/testdrive-jsui/js/controls/debug-control.js +++ b/capabilities/testdrive-jsui/js/controls/debug-control.js @@ -432,7 +432,7 @@ class DebugControl extends ControlBase { if (content) { content.innerHTML = `
-

Debug Information

+
Debug Information
${this.generateSystemInfoHTML()} ${this.generatePerformanceHTML()} diff --git a/capabilities/testdrive-jsui/js/controls/edit-control.js b/capabilities/testdrive-jsui/js/controls/edit-control.js index c42c9109..b62dacf0 100644 --- a/capabilities/testdrive-jsui/js/controls/edit-control.js +++ b/capabilities/testdrive-jsui/js/controls/edit-control.js @@ -68,11 +68,11 @@ class EditControl extends ControlBase { return this.safeOperation(() => { return `
-

Edit Tools

+
Edit Tools
-
Document Actions
+
Document Actions
diff --git a/capabilities/testdrive-jsui/js/controls/status-control.js b/capabilities/testdrive-jsui/js/controls/status-control.js index f3ca19d2..934a0efd 100644 --- a/capabilities/testdrive-jsui/js/controls/status-control.js +++ b/capabilities/testdrive-jsui/js/controls/status-control.js @@ -132,7 +132,7 @@ class StatusControl extends ControlBase { return `
-

Document Statistics

+
Document Statistics
@@ -161,7 +161,7 @@ class StatusControl extends ControlBase {
-
Document Structure
+
Document Structure
Paragraphs: diff --git a/markitect/static/js/main-updated.js b/markitect/static/js/main-updated.js index 82984441..1ce2fea3 100644 --- a/markitect/static/js/main-updated.js +++ b/markitect/static/js/main-updated.js @@ -82,13 +82,13 @@ const MarkitectMain = { initializeControlPanels: function() { console.log('🎛️ Initializing enhanced control panels with compass positioning...'); - // ContentsControl (Northwest) + // ContentsControl (West) if (typeof ContentsControl !== 'undefined') { this.contentsControl = new ContentsControl(); - this.contentsControl.config.position = 'nw'; + this.contentsControl.config.position = 'w'; this.contentsControl.show(); window.contentsControl = this.contentsControl; - console.log('✅ ContentsControl initialized (Northwest) with enhanced ControlBase'); + console.log('✅ ContentsControl initialized (West) with enhanced ControlBase'); } // StatusControl (East) diff --git a/testdrive-jsui/static/js/controls/control-base.js b/testdrive-jsui/static/js/controls/control-base.js index 0706c4b7..7b42d94a 100644 --- a/testdrive-jsui/static/js/controls/control-base.js +++ b/testdrive-jsui/static/js/controls/control-base.js @@ -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`; diff --git a/testdrive-jsui/static/js/controls/debug-control.js b/testdrive-jsui/static/js/controls/debug-control.js index 592ddea8..dfc63209 100644 --- a/testdrive-jsui/static/js/controls/debug-control.js +++ b/testdrive-jsui/static/js/controls/debug-control.js @@ -432,7 +432,7 @@ class DebugControl extends ControlBase { if (content) { content.innerHTML = `
-

Debug Information

+
Debug Information
${this.generateSystemInfoHTML()} ${this.generatePerformanceHTML()} diff --git a/testdrive-jsui/static/js/controls/edit-control.js b/testdrive-jsui/static/js/controls/edit-control.js index c42c9109..b62dacf0 100644 --- a/testdrive-jsui/static/js/controls/edit-control.js +++ b/testdrive-jsui/static/js/controls/edit-control.js @@ -68,11 +68,11 @@ class EditControl extends ControlBase { return this.safeOperation(() => { return `
-

Edit Tools

+
Edit Tools
-
Document Actions
+
Document Actions
diff --git a/testdrive-jsui/static/js/controls/status-control.js b/testdrive-jsui/static/js/controls/status-control.js index f3ca19d2..934a0efd 100644 --- a/testdrive-jsui/static/js/controls/status-control.js +++ b/testdrive-jsui/static/js/controls/status-control.js @@ -132,7 +132,7 @@ class StatusControl extends ControlBase { return `
-

Document Statistics

+
Document Statistics
@@ -161,7 +161,7 @@ class StatusControl extends ControlBase {
-
Document Structure
+
Document Structure
Paragraphs: