diff --git a/README.md b/README.md index 552275e..2f2ce16 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ Restart ComfyUI after installation. No additional `pip install` steps are typica 3. **Controls (while active)**: - **Arrow Keys**: Nudge the magnified view (adjusts `offsetX`/`offsetY`). - **Shift + Arrow Keys**: Nudge the magnified view by a larger step. - - **Reset Key (default 'O')**: Resets `offsetX` and `offsetY` to zero. (Configurable, respects the global "Require Alt/Option Key" setting). + - **Reset Key (default 'R')**: Resets `offsetX` and `offsetY` to zero. (Configurable, respects the global "Require Alt/Option Key" setting). - **Toggle Follow Key (default 'H')**: Toggles the `Follow Cursor` behavior on/off. (Configurable, respects the global "Require Alt/Option Key" setting). 4. **Configuration**: - Access all settings by clicking the ⚙️ (Settings) icon in ComfyUI, then find the "🔍 Magnify Glass" section. @@ -122,13 +122,13 @@ All options are available in the ComfyUI settings dialog under the "🔍 Magnify | Option | Description | Default Value | |--------------------------------------|-----------------------------------------------------------------------------------------------------------|------------------| -| **Zoom Factor** | Magnification level (e.g., 250 means 2.5x zoom). | `3` | +| **Zoom Factor** | Magnification level (e.g., 2.5 means 2.5x zoom). | `3` | | **Glass Size (px)** | Diameter of the magnifying glass in pixels. | `300` | -| **Border Width (px)** | Width of the border around the magnifying glass. | `1` | +| **Border Width (px)** | Width of the border around the magnifying glass. | `2` | | **Border Color** | Color of the border around the magnifying glass. | `#ffffff` | -| **Activation Key** | The key (case-insensitive) to press to activate the magnifier. | `x` | +| **Activation Key** | The key (case-insensitive) to hold down to activate the magnifier. | `x` | | **Require Alt/Option Key** | If Yes, Alt (Windows/Linux) or Option (Mac) must be held for activation and for reset. | `No (false)` | -| **Follow Cursor Position** | If Yes, the magnifier window moves with the cursor. If No, it stays where activated. | `No (false)` | +| **Follow Cursor Position** | If Yes, the magnifier window moves with the cursor. If No, it stays where activated. | `Yes (true)` | | **Offset Adjust Step (Graph Units)** | How many graph units the view shifts when pressing arrow keys (Shift+Arrow = 5x). | `5` | | **Reset Offset Key** | The key to press to reset the view offset while active. | `o` | | **Debug Mode** | Show detailed logging and the debug visualization overlay. | `Disabled (false)`| @@ -148,14 +148,14 @@ These settings control the behavior and appearance of the optional Info Panel. | **Info Panel** | Enable or disable the professional information panel. | `Enabled` | | **Info Panel Position** | Position of the info panel relative to the magnifying glass. | `Left` | | **Info Panel Width** | Width of the information panel in pixels. | `320` | -| **Info Panel Opacity** | Opacity of the information panel background. | `100` | +| **Info Panel Opacity** | Opacity of the information panel background. | `0.95` | | **Info Panel Max Height** | Maximum height of the information panel in pixels. | `500` | -| **Info Panel Theme** | Color theme for the information panel. | `Auto (based on Comfy Theme)` | -| **Info Panel Animations**| Enable or disable animations for the info panel. | `Disabled` | +| **Info Panel Theme** | Color theme for the information panel. | `Dark` | +| **Info Panel Animations**| Enable or disable animations for the info panel. | `Enabled` | | **Show Inspector Tab** | Show or hide the Inspector tab with cursor and canvas information. | `Disabled` | | **Info Panel Toggle Hotkey**| Key to toggle the info panel visibility while the magnifier is active. | `i` | | **Preview Toggle Hotkey**| Key to toggle the magnifying glass preview visibility. | `g` | -| **Pin Panel Hotkey** | Key to use with to pin the info panel at mouse location.| `u` | +| **Pin Panel Hotkey** | Key to use with Alt to pin the info panel at mouse location (e.g., Alt+P). | `p` | | **Show Hover Controls**| Show or hide hovering UI controls above the info panel. | `Enabled` | | **Controls Position** | Position of the floating control buttons relative to the info panel. | `bottom-centered` | @@ -163,9 +163,10 @@ These settings control the behavior and appearance of the optional Info Panel. - **Magnifier not appearing**: - Ensure you are pressing the correct activation key combination (check settings for current keys). + - Make sure ComfyUI has focus. - Check the browser console (F12) for any errors related to "ComfyUI Magnifying Glass". - **Performance issues on very complex graphs**: - - While WebGL is used for efficiency, extremely complex scenes might impact performance. Try reducing the `Glass Size` if issues occur. + - While WebGL is used for efficiency, extremely complex scenes might still impact performance. Try reducing the `Glass Size` if issues occur. - **Text in widgets not sharp enough**: - The HTML overlay feature aims to render text crisply. If you notice issues, ensure your browser zoom is at 100%. diff --git a/web/magnify_info_panel.js b/web/magnify_info_panel.js index c388522..d9065e2 100644 --- a/web/magnify_info_panel.js +++ b/web/magnify_info_panel.js @@ -822,12 +822,16 @@ app.registerExtension({
- ${section.content.map(item => ` + ${section.content.map(item => { + const value = this.formatValue(item.value, item.label); + const valueClass = this.getValueClass(item.value); + const valueAttributes = this.getValueAttributes(item.value); + return `
${item.label} - ${item.value} -
- `).join('')} + ${value} +
`; + }).join('')}
@@ -851,6 +855,55 @@ app.registerExtension({ }); } + formatValue(value, label) { + if (!value) return value; + + const str = String(value); + + // Show full text for prompts, text content, model names, and file paths + if (label && ( + label.toLowerCase().includes('text') || + label.toLowerCase().includes('prompt') || + label.toLowerCase().includes('model') || + label.toLowerCase().includes('file') || + label.toLowerCase().includes('conditioning') || + label.toLowerCase().includes('positive') || + label.toLowerCase().includes('negative') + )) { + return str; + } + + // Show full text for very long values (no truncation) + return str; + } + + getValueClass(value) { + if (!value) return ''; + + const str = String(value); + let classes = []; + + // Mark text that might benefit from special styling for readability + if (str.length > 100) { + classes.push('long-text'); + } + + return classes.join(' '); + } + + getValueAttributes(value) { + // Since we show full text now, we don't need title attributes for long text + // Only add title for very long text that might benefit from tooltips + if (!value) return ''; + + const str = String(value); + if (str.length > 500) { // Only for extremely long text + return `title="${str.replace(/"/g, '"')}"`; + } + + return ''; + } + updateHeaderSubtitle(info) { const subtitleElement = this.elements.header.querySelector('.header-subtitle'); if (subtitleElement) { @@ -967,10 +1020,7 @@ app.registerExtension({ widget.type === 'string' || widget.name.toLowerCase().includes('text')) && typeof widget.value === 'string' && widget.value.length > 0) { - const maxLength = 150; - if (widget.value.length > maxLength) { - return widget.value.substring(0, maxLength) + '...'; - } + // Show full text without truncation return widget.value; } } @@ -1005,7 +1055,7 @@ app.registerExtension({ if (value === null) return "null"; if (value === undefined) return "undefined"; if (typeof value === "string") { - return value.length > 30 ? value.substring(0, 27) + "..." : value; + return value; // Show full text without truncation } if (typeof value === "number") { return Number.isInteger(value) ? value.toString() : value.toFixed(3); @@ -1037,7 +1087,7 @@ app.registerExtension({ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.1); overflow: hidden; font-size: 16px; - line-height: 1.5; + line-height: 1.6; pointer-events: auto; } @@ -1046,15 +1096,19 @@ app.registerExtension({ } .magnify-info-panel.theme-dark { - background: linear-gradient(135deg, rgba(0, 0, 0, 0.95), rgba(10, 10, 15, 0.95)); + background: linear-gradient(135deg, rgba(0, 0, 0, 0.96), rgba(10, 10, 15, 0.96)); color: var(--info-panel-text-color, #e0e0e0); - border: 1px solid rgba(100, 100, 120, 0.3); + border: 1px solid rgba(100, 100, 120, 0.4); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 2px 16px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(12px); } .magnify-info-panel.theme-light { - background: linear-gradient(135deg, rgba(250, 250, 255, 0.95), rgba(240, 240, 250, 0.95)); + background: linear-gradient(135deg, rgba(250, 250, 255, 0.96), rgba(240, 240, 250, 0.96)); color: var(--info-panel-text-color, #2a2a2a); - border: 1px solid rgba(200, 200, 220, 0.4); + border: 1px solid rgba(200, 200, 220, 0.5); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), 0 2px 16px rgba(0, 0, 0, 0.05); + backdrop-filter: blur(12px); } .magnify-info-panel.visible { @@ -1263,19 +1317,47 @@ app.registerExtension({ } .info-section { - border-bottom: 1px solid rgba(255, 255, 255, 0.08); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + margin-bottom: 8px; + border-radius: 10px; + overflow: visible; + background: rgba(255, 255, 255, 0.02); + transition: all 0.3s ease; + } + + .info-section:hover { + background: rgba(255, 255, 255, 0.04); + transform: translateY(-1px); } .section-header { display: flex; align-items: center; - gap: 10px; - padding: 14px 18px; + gap: 12px; + padding: 16px 20px; cursor: pointer; - transition: all 0.2s; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); font-weight: 500; - border-radius: 6px; - margin: 2px; + border-radius: 8px; + margin: 3px; + position: relative; + overflow: hidden; + } + + .section-header::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.05) 50%, transparent 100%); + transform: translateX(-100%); + transition: transform 0.6s ease; + } + + .section-header:hover::before { + transform: translateX(100%); } .section-header:hover { @@ -1361,6 +1443,8 @@ app.registerExtension({ flex: 1; font-size: 16px; font-weight: 600; + letter-spacing: 0.3px; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .section-badge { @@ -1373,61 +1457,108 @@ app.registerExtension({ } .expand-icon { - font-size: 13px; - transition: all 0.2s; - opacity: 0.7; + font-size: 14px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + color: rgba(255, 255, 255, 0.6); + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + background: rgba(255, 255, 255, 0.05); margin-left: auto; } .section-header:hover .expand-icon { - opacity: 1; color: var(--info-panel-accent-color, #74b9ff); + background: rgba(116, 185, 255, 0.15); + transform: scale(1.1); } .section-header.expanded .expand-icon { - transform: rotate(90deg); + transform: rotate(90deg) scale(1.1); color: var(--info-panel-accent-color, #74b9ff); + background: rgba(116, 185, 255, 0.2); } .section-content { max-height: 0; - overflow: hidden; - transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1); + overflow: visible; + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease; + opacity: 0; } - + .section-content.expanded { - max-height: 1000px; + max-height: 2000px; + opacity: 1; + overflow: visible; } .section-body { - padding: 0 18px 14px 42px; + padding: 0 18px 16px 24px; } .info-row { display: flex; justify-content: space-between; - align-items: center; - padding: 6px 0; - border-bottom: 1px solid rgba(255, 255, 255, 0.03); + align-items: flex-start; + padding: 10px 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); + transition: all 0.2s ease; + border-radius: 4px; + margin: 0 -8px; + padding-left: 8px; + padding-right: 8px; } .info-row:last-child { border-bottom: none; } + .info-row:hover { + background: rgba(255, 255, 255, 0.03); + border-bottom-color: rgba(255, 255, 255, 0.08); + } + .info-label { font-weight: 500; - opacity: 0.8; + opacity: 0.85; font-size: 15px; + min-width: 80px; + padding-right: 12px; + line-height: 1.5; } .info-value { font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 14px; color: var(--info-panel-accent-color, #a0d468); - background: rgba(160, 212, 104, 0.1); - padding: 3px 8px; - border-radius: 4px; + background: rgba(160, 212, 104, 0.12); + padding: 4px 10px; + border-radius: 6px; + max-width: 100%; + word-wrap: break-word; + word-break: break-word; + hyphens: auto; + line-height: 1.4; + text-align: left; + white-space: pre-wrap; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + transition: all 0.2s ease; + } + + .info-value:hover { + background: rgba(160, 212, 104, 0.18); + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + } + + .info-value.long-text { + white-space: pre-wrap; + word-wrap: break-word; + max-width: 100%; + line-height: 1.4; } .empty-state { @@ -1442,6 +1573,61 @@ app.registerExtension({ opacity: 0.5; } + /* Copy to clipboard functionality */ + .info-value[title]:hover::after { + content: '📋'; + position: absolute; + right: -20px; + top: 50%; + transform: translateY(-50%); + font-size: 12px; + opacity: 0.7; + } + + /* Smooth loading states */ + .section-body.loading { + opacity: 0.5; + pointer-events: none; + } + + .section-body.loading::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 20px; + height: 20px; + border: 2px solid transparent; + border-top: 2px solid var(--info-panel-accent-color, #74b9ff); + border-radius: 50%; + animation: spin 1s linear infinite; + transform: translate(-50%, -50%); + } + + @keyframes spin { + to { transform: translate(-50%, -50%) rotate(360deg); } + } + + /* Enhanced scrollbar for better UX */ + .section-body::-webkit-scrollbar { + width: 4px; + } + + .section-body::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.05); + border-radius: 2px; + } + + .section-body::-webkit-scrollbar-thumb { + background: var(--info-panel-accent-color, #74b9ff); + border-radius: 2px; + opacity: 0.6; + } + + .section-body::-webkit-scrollbar-thumb:hover { + opacity: 1; + } + .empty-state-text { font-size: 16px; font-style: italic; @@ -2352,43 +2538,43 @@ app.registerExtension({ detectNodeRegion(localPos, node) { const titleHeight = 30; const regions = []; - + if (localPos.y <= titleHeight) { regions.push("Title Bar"); } - + if (localPos.x <= 10) { regions.push("Left Edge"); } else if (localPos.x >= node.size[0] - 10) { regions.push("Right Edge"); } - + if (localPos.y <= 10) { regions.push("Top Edge"); } else if (localPos.y >= node.size[1] - 10) { regions.push("Bottom Edge"); } - + if (regions.length === 0) { if (localPos.y > titleHeight) { regions.push("Content Area"); } } - + if (localPos.x <= 20 && localPos.y > titleHeight) { regions.push("Input Area"); } else if (localPos.x >= node.size[0] - 20 && localPos.y > titleHeight) { regions.push("Output Area"); } - + return regions.length > 0 ? regions.join(", ") : "Unknown"; } - + formatValue(value) { if (value === null) return "null"; if (value === undefined) return "undefined"; if (typeof value === "string") { - return value.length > 30 ? value.substring(0, 27) + "..." : value; + return value; // Show full text without truncation } if (typeof value === "number") { return Number.isInteger(value) ? value.toString() : value.toFixed(3);