diff --git a/src/info-panel/InformationGatherer.ts b/src/info-panel/InformationGatherer.ts
index 7c7731a..188437d 100644
--- a/src/info-panel/InformationGatherer.ts
+++ b/src/info-panel/InformationGatherer.ts
@@ -144,12 +144,14 @@ export class InformationGatherer {
let author: string | undefined;
let category: string | undefined;
let executionOrder: number | undefined;
+ let pythonModule: string | undefined;
try {
// Check for node.constructor.nodeData (ComfyUI stores metadata here)
const nodeData = (node as any).constructor?.nodeData;
if (nodeData) {
- author = nodeData.author || nodeData.python_module?.split('.')[0];
+ pythonModule = nodeData.python_module;
+ author = nodeData.author || pythonModule?.split('.')[0];
category = nodeData.category;
}
@@ -159,6 +161,9 @@ export class InformationGatherer {
if (nodeType) {
author = nodeType.nodeData?.author || nodeType.author;
category = nodeType.category || category;
+ if (!pythonModule && nodeType.nodeData?.python_module) {
+ pythonModule = nodeType.nodeData.python_module;
+ }
}
}
@@ -203,9 +208,10 @@ export class InformationGatherer {
outputs: node.outputs || [],
properties: node.properties || {},
hoverRegion: this.detectNodeRegion(localPos, node),
- executionOrder,
- author,
- category
+ executionOrder: executionOrder,
+ author: author,
+ category: category,
+ pythonModule: pythonModule
};
}
diff --git a/src/info-panel/UIManager.ts b/src/info-panel/UIManager.ts
index 485ec28..647f665 100644
--- a/src/info-panel/UIManager.ts
+++ b/src/info-panel/UIManager.ts
@@ -411,6 +411,10 @@ export class UIManager {
this.elements.panel.style.userSelect = 'none';
this.elements.panel.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
+ // Apply Font Size
+ const fontSize = settings["🔍MagnifyGlass.InfoPanelFontSize"] || 14;
+ this.elements.panel.style.fontSize = `${fontSize}px`;
+
// 3. Apply transition
this.elements.panel.style.transition = settings["🔍MagnifyGlass.InfoPanelAnimations"]
? 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
@@ -591,9 +595,10 @@ export class UIManager {
nodeContent.push({ label: 'Category', value: info.hoveredNode.category });
}
- // Add author if available
- if (info.hoveredNode.author) {
- nodeContent.push({ label: 'Author', value: info.hoveredNode.author });
+ // Add python module path if available
+ if (info.hoveredNode.pythonModule) {
+ const path = info.hoveredNode.pythonModule.replace(/\./g, '/') + '.py';
+ nodeContent.push({ label: 'Path', value: path });
}
// Check if this is a complex node that shows all widgets
diff --git a/src/shared/settings/defaults.ts b/src/shared/settings/defaults.ts
index e003eb4..bb1cd2e 100644
--- a/src/shared/settings/defaults.ts
+++ b/src/shared/settings/defaults.ts
@@ -56,4 +56,5 @@ export const DEFAULT_PANEL_SETTINGS: PanelSettings = {
"🔍MagnifyGlass.ControlsPosition": "left",
"🔍MagnifyGlass.InfoPanelTextColor": "#6b7280",
"🔍MagnifyGlass.InfoPanelAccentColor": "#3b82f6",
+ "🔍MagnifyGlass.InfoPanelFontSize": 14,
};
diff --git a/src/shared/settings/panelSettings.ts b/src/shared/settings/panelSettings.ts
index 0d0e6f1..0fff4a2 100644
--- a/src/shared/settings/panelSettings.ts
+++ b/src/shared/settings/panelSettings.ts
@@ -109,6 +109,25 @@ export function registerPanelSettings(stateManager: any, uiManager: any, positio
}
});
+ app.ui.settings.addSetting({
+ id: "🔍MagnifyGlass.InfoPanelFontSize",
+ name: "📊 Info Panel: Font Size (px)",
+ type: "slider",
+ defaultValue: settings["🔍MagnifyGlass.InfoPanelFontSize"],
+ min: 8,
+ max: 24,
+ step: 1,
+ tooltip: "Font size of the information panel text.",
+ onChange: (value: any) => {
+ if (stateManager) {
+ stateManager.state.settings["🔍MagnifyGlass.InfoPanelFontSize"] = parseInt(String(value), 10);
+ if (uiManager) {
+ uiManager.applyStyles();
+ }
+ }
+ }
+ });
+
app.ui.settings.addSetting({
id: "🔍MagnifyGlass.InfoPanelAnimations",
name: "📊 Info Panel: Animations",
diff --git a/src/shared/settings/types.ts b/src/shared/settings/types.ts
index a3fe15d..de9c507 100644
--- a/src/shared/settings/types.ts
+++ b/src/shared/settings/types.ts
@@ -44,6 +44,7 @@ export interface PanelSettings {
"🔍MagnifyGlass.ControlsPosition": string;
"🔍MagnifyGlass.InfoPanelTextColor": string;
"🔍MagnifyGlass.InfoPanelAccentColor": string;
+ "🔍MagnifyGlass.InfoPanelFontSize": number;
[key: string]: string | number | boolean; // Allow indexing
}
diff --git a/src/sidebar/SidebarSettings.ts b/src/sidebar/SidebarSettings.ts
index 7c7339f..29ae308 100644
--- a/src/sidebar/SidebarSettings.ts
+++ b/src/sidebar/SidebarSettings.ts
@@ -498,6 +498,19 @@ export function renderSettingsPanel(container: HTMLElement): void {
}
));
+ panelSection.body.appendChild(createSlider('Font Size',
+ getSettingValue('🔍MagnifyGlass.InfoPanelFontSize', 14), 8, 24, 1, 'px',
+ (value) => setSettingValue('🔍MagnifyGlass.InfoPanelFontSize', value),
+ 'Font size of text in the info panel',
+ (value) => {
+ const infoPanel = (window as any).infoPanelManager;
+ if (infoPanel?.stateManager?.state?.settings) {
+ infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelFontSize'] = value;
+ infoPanel.uiManager.applyStyles();
+ }
+ }
+ ));
+
panelSection.body.appendChild(createSlider('Opacity',
getSettingValue('🔍MagnifyGlass.InfoPanelOpacity', 95), 10, 100, 5, '%',
(value) => setSettingValue('🔍MagnifyGlass.InfoPanelOpacity', value),
@@ -676,6 +689,7 @@ export function renderSettingsPanel(container: HTMLElement): void {
setSettingValue('🔍MagnifyGlass.InfoPanelWidth', 300);
setSettingValue('🔍MagnifyGlass.InfoPanelMaxHeight', 300);
setSettingValue('🔍MagnifyGlass.InfoPanelOpacity', 100);
+ setSettingValue('🔍MagnifyGlass.InfoPanelFontSize', 14);
setSettingValue('🔍MagnifyGlass.InfoPanelTextColor', '#6b7280');
setSettingValue('🔍MagnifyGlass.InfoPanelAccentColor', '#3b82f6');
setSettingValue('🔍MagnifyGlass.InfoPanelAnimations', false);
diff --git a/src/types/comfyui.d.ts b/src/types/comfyui.d.ts
index ab6db8c..afa4d5e 100644
--- a/src/types/comfyui.d.ts
+++ b/src/types/comfyui.d.ts
@@ -325,6 +325,7 @@ export interface NodeInfo {
executionOrder?: number;
author?: string;
category?: string;
+ pythonModule?: string;
}
/**
diff --git a/web/info-panel.css b/web/info-panel.css
index fbd0790..4de536c 100644
--- a/web/info-panel.css
+++ b/web/info-panel.css
@@ -347,11 +347,11 @@
.header-title {
font-weight: 600;
- font-size: 18px;
+ font-size: 1.125em;
}
.header-subtitle {
- font-size: 14px;
+ font-size: 0.875em;
opacity: 0.7;
font-style: italic;
}
@@ -531,7 +531,7 @@
.section-title {
flex: 1;
- font-size: 16px;
+ font-size: 1em;
font-weight: 600;
letter-spacing: 0.3px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
@@ -542,7 +542,7 @@
color: #8bb3ff;
padding: 3px 10px;
border-radius: 10px;
- font-size: 13px;
+ font-size: 0.81em;
font-weight: 500;
}
@@ -614,7 +614,7 @@
.info-label {
font-weight: 500;
opacity: 0.85;
- font-size: 15px;
+ font-size: 0.94em;
min-width: 80px;
padding-right: 12px;
line-height: 1.5;
@@ -622,7 +622,7 @@
.info-value {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-size: 14px;
+ font-size: 0.88em;
color: var(--info-panel-accent-color, #a0d468);
background: rgba(160, 212, 104, 0.12);
padding: 4px 10px;
diff --git a/web/info-panel/InformationGatherer.js b/web/info-panel/InformationGatherer.js
index 909e2bc..2a77813 100644
--- a/web/info-panel/InformationGatherer.js
+++ b/web/info-panel/InformationGatherer.js
@@ -109,17 +109,22 @@ class InformationGatherer {
let author;
let category;
let executionOrder;
+ let pythonModule;
try {
const nodeData = (_a = node.constructor) == null ? void 0 : _a.nodeData;
if (nodeData) {
- author = nodeData.author || ((_b = nodeData.python_module) == null ? void 0 : _b.split(".")[0]);
+ pythonModule = nodeData.python_module;
+ author = nodeData.author || (pythonModule == null ? void 0 : pythonModule.split(".")[0]);
category = nodeData.category;
}
if (!author && typeof LiteGraph !== "undefined") {
- const nodeType = (_c = LiteGraph.registered_node_types) == null ? void 0 : _c[node.type];
+ const nodeType = (_b = LiteGraph.registered_node_types) == null ? void 0 : _b[node.type];
if (nodeType) {
- author = ((_d = nodeType.nodeData) == null ? void 0 : _d.author) || nodeType.author;
+ author = ((_c = nodeType.nodeData) == null ? void 0 : _c.author) || nodeType.author;
category = nodeType.category || category;
+ if (!pythonModule && ((_d = nodeType.nodeData) == null ? void 0 : _d.python_module)) {
+ pythonModule = nodeType.nodeData.python_module;
+ }
}
}
executionOrder = node.order;
@@ -162,7 +167,8 @@ class InformationGatherer {
hoverRegion: this.detectNodeRegion(localPos, node),
executionOrder,
author,
- category
+ category,
+ pythonModule
};
}
getNodeInfo(node) {
diff --git a/web/info-panel/InformationGatherer.js.map b/web/info-panel/InformationGatherer.js.map
index 2d57dec..e0a3dc8 100644
--- a/web/info-panel/InformationGatherer.js.map
+++ b/web/info-panel/InformationGatherer.js.map
@@ -1 +1 @@
-{"version":3,"file":"InformationGatherer.js","sources":["../../src/info-panel/InformationGatherer.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Info Panel Information Gatherer (TypeScript)\n * \n * Complete Information Gatherer extracted from magnify_info_panel.js\n * Responsible for collecting information about nodes, widgets, and canvas state.\n */\n\nimport type { ComfyApp, ComfyNode, ComfyWidget, GatheredInfo, NodeInfo, WidgetInfo, MediaInfo } from '../types/comfyui';\n\ndeclare const app: ComfyApp;\n\n/**\n * Information Gatherer class.\n * Collects information about the current state under the cursor.\n */\nexport class InformationGatherer {\n constructor() { }\n\n gatherInformation(): GatheredInfo {\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (!magnifyGlass) {\n return {\n timestamp: Date.now(),\n cursor: { screenX: 0, screenY: 0, canvasX: 0, canvasY: 0 },\n zoom: 1,\n nodeCount: 0,\n hoveredNode: null,\n hoveredWidget: null,\n mediaElement: null\n };\n }\n\n const info: GatheredInfo = {\n timestamp: Date.now(),\n cursor: {\n screenX: magnifyGlass.lastKnownMousePosition.x,\n screenY: magnifyGlass.lastKnownMousePosition.y,\n canvasX: magnifyGlass.state.x,\n canvasY: magnifyGlass.state.y\n },\n zoom: magnifyGlass.state.canvasScale,\n nodeCount: app.graph?._nodes?.length ?? 0,\n hoveredNode: null,\n hoveredWidget: null,\n mediaElement: null\n };\n\n if (magnifyGlass.isOverMedia && magnifyGlass.currentMediaElement) {\n info.mediaElement = this.getMediaInfo(magnifyGlass.currentMediaElement);\n }\n\n const nodeUnderCursor = this.getNodeUnderCursor();\n if (nodeUnderCursor) {\n info.hoveredNode = this.getDetailedNodeInfo(nodeUnderCursor.node, nodeUnderCursor.localPos);\n\n const widget = this.getWidgetUnderCursor(nodeUnderCursor.node, nodeUnderCursor.localPos);\n if (widget) {\n info.hoveredWidget = this.getWidgetInfo(widget);\n }\n }\n\n return info;\n }\n\n getNodeUnderCursor(): { node: ComfyNode, localPos: { x: number, y: number } } | null {\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (!app.graph || !app.canvas || !magnifyGlass) {\n return null;\n }\n\n try {\n // Try to get the node from ComfyUI's state\n if (app.canvas.node_over) {\n const node = app.canvas.node_over;\n if (node && node.pos && node.size) {\n const canvasRect = app.canvas.canvas.getBoundingClientRect();\n const mouseX = magnifyGlass.lastKnownMousePosition.x - canvasRect.left;\n const mouseY = magnifyGlass.lastKnownMousePosition.y - canvasRect.top;\n\n let graphPos: [number, number];\n if (app.canvas.convertOffsetToCanvasPos) {\n graphPos = app.canvas.convertOffsetToCanvasPos([mouseX, mouseY]);\n } else {\n const ds = app.canvas.ds || { scale: 1, offset: [0, 0] };\n graphPos = [\n (mouseX / ds.scale) - (ds.offset[0] / ds.scale),\n (mouseY / ds.scale) - (ds.offset[1] / ds.scale)\n ];\n }\n\n return {\n node: node,\n localPos: {\n x: graphPos[0] - node.pos[0],\n y: graphPos[1] - node.pos[1]\n }\n };\n }\n }\n\n // Fallback to manual detection\n const canvasRect = app.canvas.canvas.getBoundingClientRect();\n const mouseX = magnifyGlass.lastKnownMousePosition.x - canvasRect.left;\n const mouseY = magnifyGlass.lastKnownMousePosition.y - canvasRect.top;\n\n let graphPos: [number, number];\n if (app.canvas.convertOffsetToCanvasPos) {\n graphPos = app.canvas.convertOffsetToCanvasPos([mouseX, mouseY]);\n } else {\n const ds = app.canvas.ds || { scale: 1, offset: [0, 0] };\n graphPos = [\n (mouseX / ds.scale) - (ds.offset[0] / ds.scale),\n (mouseY / ds.scale) - (ds.offset[1] / ds.scale)\n ];\n }\n\n for (let i = app.graph._nodes.length - 1; i >= 0; i--) {\n const node = app.graph._nodes[i];\n if (!node.pos || !node.size || (node.flags && node.flags.collapsed)) continue;\n\n if (graphPos[0] >= node.pos[0] &&\n graphPos[0] <= node.pos[0] + node.size[0] &&\n graphPos[1] >= node.pos[1] &&\n graphPos[1] <= node.pos[1] + node.size[1]) {\n\n return {\n node: node,\n localPos: {\n x: graphPos[0] - node.pos[0],\n y: graphPos[1] - node.pos[1]\n }\n };\n }\n }\n } catch (err) {\n console.warn(\"Error in node detection:\", err);\n }\n\n return null;\n }\n\n getDetailedNodeInfo(node: ComfyNode, localPos: { x: number, y: number }): NodeInfo {\n // Try to get author and category from node constructor or registered node types\n let author: string | undefined;\n let category: string | undefined;\n let executionOrder: number | undefined;\n\n try {\n // Check for node.constructor.nodeData (ComfyUI stores metadata here)\n const nodeData = (node as any).constructor?.nodeData;\n if (nodeData) {\n author = nodeData.author || nodeData.python_module?.split('.')[0];\n category = nodeData.category;\n }\n\n // Try to get from LiteGraph registered node types\n if (!author && typeof LiteGraph !== 'undefined') {\n const nodeType = (LiteGraph as any).registered_node_types?.[node.type];\n if (nodeType) {\n author = nodeType.nodeData?.author || nodeType.author;\n category = nodeType.category || category;\n }\n }\n\n // Execution order - try to get from node.order (set during graph execution)\n executionOrder = (node as any).order;\n } catch (e) {\n // Silently ignore errors accessing node metadata\n }\n\n return {\n id: node.id,\n title: node.title || \"Untitled Node\",\n type: node.type,\n mode: this.getNodeModeText(node.mode),\n position: {\n x: Math.round(node.pos[0]),\n y: Math.round(node.pos[1]),\n formatted: `(${Math.round(node.pos[0])}, ${Math.round(node.pos[1])})`\n },\n size: {\n width: Math.round(node.size[0]),\n height: Math.round(node.size[1]),\n formatted: `${Math.round(node.size[0])}×${Math.round(node.size[1])}`\n },\n localPosition: {\n x: Math.round(localPos.x),\n y: Math.round(localPos.y),\n formatted: `(${Math.round(localPos.x)}, ${Math.round(localPos.y)})`,\n percentage: {\n x: ((localPos.x / node.size[0]) * 100).toFixed(1),\n y: ((localPos.y / node.size[1]) * 100).toFixed(1)\n }\n },\n counts: {\n widgets: node.widgets ? node.widgets.length : 0,\n inputs: node.inputs ? node.inputs.length : 0,\n outputs: node.outputs ? node.outputs.length : 0,\n properties: node.properties ? Object.keys(node.properties).length : 0\n },\n widgets: node.widgets || [],\n inputs: node.inputs || [],\n outputs: node.outputs || [],\n properties: node.properties || {},\n hoverRegion: this.detectNodeRegion(localPos, node),\n executionOrder,\n author,\n category\n };\n }\n\n getNodeInfo(node: ComfyNode): NodeInfo {\n return {\n id: node.id,\n title: node.title || \"Untitled\",\n type: node.type,\n mode: node.mode,\n size: node.size ? `${Math.round(node.size[0])}×${Math.round(node.size[1])}` : \"Unknown\",\n position: node.pos ? `(${Math.round(node.pos[0])}, ${Math.round(node.pos[1])})` : \"Unknown\",\n widgets: node.widgets || [],\n inputs: node.inputs || [],\n outputs: node.outputs || [],\n properties: node.properties || {}\n };\n }\n\n getWidgetUnderCursor(node: ComfyNode, localPos: { x: number, y: number }): ComfyWidget | null {\n if (!node.widgets || !node.widgets.length) return null;\n\n const titleHeight = 30;\n let currentY = titleHeight;\n\n for (const widget of node.widgets) {\n const widgetHeight = 25;\n\n if (localPos.y >= currentY && localPos.y <= currentY + widgetHeight) {\n return widget;\n }\n\n currentY += widgetHeight + 5;\n }\n\n return null;\n }\n\n getWidgetInfo(widget: ComfyWidget): WidgetInfo {\n return {\n name: widget.name,\n type: widget.type,\n value: this.formatValue(widget.value),\n options: widget.options || null,\n min: widget.min,\n max: widget.max,\n step: widget.step\n };\n }\n\n getMediaInfo(mediaElement: HTMLImageElement | HTMLVideoElement): MediaInfo {\n const info: MediaInfo = {\n type: mediaElement instanceof HTMLImageElement ? 'image' : 'video',\n tagName: mediaElement.tagName,\n src: mediaElement.src ? mediaElement.src.substring(mediaElement.src.lastIndexOf('/') + 1) : 'No source',\n naturalWidth: 0,\n naturalHeight: 0,\n displayWidth: 0,\n displayHeight: 0,\n aspectRatio: ''\n };\n\n if (mediaElement instanceof HTMLImageElement) {\n info.naturalWidth = mediaElement.naturalWidth;\n info.naturalHeight = mediaElement.naturalHeight;\n info.displayWidth = Math.round(mediaElement.width);\n info.displayHeight = Math.round(mediaElement.height);\n if (mediaElement.naturalWidth && mediaElement.naturalHeight) {\n info.aspectRatio = (mediaElement.naturalWidth / mediaElement.naturalHeight).toFixed(2);\n }\n } else if (mediaElement instanceof HTMLVideoElement) {\n info.naturalWidth = mediaElement.videoWidth;\n info.naturalHeight = mediaElement.videoHeight;\n info.displayWidth = Math.round(mediaElement.width);\n info.displayHeight = Math.round(mediaElement.height);\n info.duration = mediaElement.duration;\n info.currentTime = mediaElement.currentTime;\n if (mediaElement.videoWidth && mediaElement.videoHeight) {\n info.aspectRatio = (mediaElement.videoWidth / mediaElement.videoHeight).toFixed(2);\n }\n }\n\n return info;\n }\n\n getNodeModeText(mode: number): string {\n const modes: { [key: number]: string } = {\n 0: 'Always',\n 1: 'On Event',\n 2: 'Never',\n 3: 'On Trigger',\n 4: 'On Request'\n };\n return modes[mode] || `Mode ${mode}`;\n }\n\n detectNodeRegion(localPos: { x: number, y: number }, node: ComfyNode): string {\n const titleHeight = 30;\n const regions: string[] = [];\n\n if (localPos.y <= titleHeight) {\n regions.push(\"Title Bar\");\n }\n\n if (localPos.x <= 10) {\n regions.push(\"Left Edge\");\n } else if (localPos.x >= node.size[0] - 10) {\n regions.push(\"Right Edge\");\n }\n\n if (localPos.y <= 10) {\n regions.push(\"Top Edge\");\n } else if (localPos.y >= node.size[1] - 10) {\n regions.push(\"Bottom Edge\");\n }\n\n if (regions.length === 0) {\n if (localPos.y > titleHeight) {\n regions.push(\"Content Area\");\n }\n }\n\n if (localPos.x <= 20 && localPos.y > titleHeight) {\n regions.push(\"Input Area\");\n } else if (localPos.x >= node.size[0] - 20 && localPos.y > titleHeight) {\n regions.push(\"Output Area\");\n }\n\n return regions.length > 0 ? regions.join(\", \") : \"Unknown\";\n }\n\n formatValue(value: unknown): string {\n if (value === null) return \"null\";\n if (value === undefined) return \"undefined\";\n if (typeof value === \"string\") {\n return value; // Show full text without truncation\n }\n if (typeof value === \"number\") {\n return Number.isInteger(value) ? value.toString() : value.toFixed(3);\n }\n if (typeof value === \"boolean\") return value.toString();\n if (Array.isArray(value)) {\n return `Array(${value.length})`;\n }\n if (typeof value === \"object\") {\n return \"Object\";\n }\n return String(value);\n }\n}\n"],"names":["canvasRect","mouseX","mouseY","graphPos"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"InformationGatherer.js","sources":["../../src/info-panel/InformationGatherer.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Info Panel Information Gatherer (TypeScript)\n * \n * Complete Information Gatherer extracted from magnify_info_panel.js\n * Responsible for collecting information about nodes, widgets, and canvas state.\n */\n\nimport type { ComfyApp, ComfyNode, ComfyWidget, GatheredInfo, NodeInfo, WidgetInfo, MediaInfo } from '../types/comfyui';\n\ndeclare const app: ComfyApp;\n\n/**\n * Information Gatherer class.\n * Collects information about the current state under the cursor.\n */\nexport class InformationGatherer {\n constructor() { }\n\n gatherInformation(): GatheredInfo {\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (!magnifyGlass) {\n return {\n timestamp: Date.now(),\n cursor: { screenX: 0, screenY: 0, canvasX: 0, canvasY: 0 },\n zoom: 1,\n nodeCount: 0,\n hoveredNode: null,\n hoveredWidget: null,\n mediaElement: null\n };\n }\n\n const info: GatheredInfo = {\n timestamp: Date.now(),\n cursor: {\n screenX: magnifyGlass.lastKnownMousePosition.x,\n screenY: magnifyGlass.lastKnownMousePosition.y,\n canvasX: magnifyGlass.state.x,\n canvasY: magnifyGlass.state.y\n },\n zoom: magnifyGlass.state.canvasScale,\n nodeCount: app.graph?._nodes?.length ?? 0,\n hoveredNode: null,\n hoveredWidget: null,\n mediaElement: null\n };\n\n if (magnifyGlass.isOverMedia && magnifyGlass.currentMediaElement) {\n info.mediaElement = this.getMediaInfo(magnifyGlass.currentMediaElement);\n }\n\n const nodeUnderCursor = this.getNodeUnderCursor();\n if (nodeUnderCursor) {\n info.hoveredNode = this.getDetailedNodeInfo(nodeUnderCursor.node, nodeUnderCursor.localPos);\n\n const widget = this.getWidgetUnderCursor(nodeUnderCursor.node, nodeUnderCursor.localPos);\n if (widget) {\n info.hoveredWidget = this.getWidgetInfo(widget);\n }\n }\n\n return info;\n }\n\n getNodeUnderCursor(): { node: ComfyNode, localPos: { x: number, y: number } } | null {\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (!app.graph || !app.canvas || !magnifyGlass) {\n return null;\n }\n\n try {\n // Try to get the node from ComfyUI's state\n if (app.canvas.node_over) {\n const node = app.canvas.node_over;\n if (node && node.pos && node.size) {\n const canvasRect = app.canvas.canvas.getBoundingClientRect();\n const mouseX = magnifyGlass.lastKnownMousePosition.x - canvasRect.left;\n const mouseY = magnifyGlass.lastKnownMousePosition.y - canvasRect.top;\n\n let graphPos: [number, number];\n if (app.canvas.convertOffsetToCanvasPos) {\n graphPos = app.canvas.convertOffsetToCanvasPos([mouseX, mouseY]);\n } else {\n const ds = app.canvas.ds || { scale: 1, offset: [0, 0] };\n graphPos = [\n (mouseX / ds.scale) - (ds.offset[0] / ds.scale),\n (mouseY / ds.scale) - (ds.offset[1] / ds.scale)\n ];\n }\n\n return {\n node: node,\n localPos: {\n x: graphPos[0] - node.pos[0],\n y: graphPos[1] - node.pos[1]\n }\n };\n }\n }\n\n // Fallback to manual detection\n const canvasRect = app.canvas.canvas.getBoundingClientRect();\n const mouseX = magnifyGlass.lastKnownMousePosition.x - canvasRect.left;\n const mouseY = magnifyGlass.lastKnownMousePosition.y - canvasRect.top;\n\n let graphPos: [number, number];\n if (app.canvas.convertOffsetToCanvasPos) {\n graphPos = app.canvas.convertOffsetToCanvasPos([mouseX, mouseY]);\n } else {\n const ds = app.canvas.ds || { scale: 1, offset: [0, 0] };\n graphPos = [\n (mouseX / ds.scale) - (ds.offset[0] / ds.scale),\n (mouseY / ds.scale) - (ds.offset[1] / ds.scale)\n ];\n }\n\n for (let i = app.graph._nodes.length - 1; i >= 0; i--) {\n const node = app.graph._nodes[i];\n if (!node.pos || !node.size || (node.flags && node.flags.collapsed)) continue;\n\n if (graphPos[0] >= node.pos[0] &&\n graphPos[0] <= node.pos[0] + node.size[0] &&\n graphPos[1] >= node.pos[1] &&\n graphPos[1] <= node.pos[1] + node.size[1]) {\n\n return {\n node: node,\n localPos: {\n x: graphPos[0] - node.pos[0],\n y: graphPos[1] - node.pos[1]\n }\n };\n }\n }\n } catch (err) {\n console.warn(\"Error in node detection:\", err);\n }\n\n return null;\n }\n\n getDetailedNodeInfo(node: ComfyNode, localPos: { x: number, y: number }): NodeInfo {\n // Try to get author and category from node constructor or registered node types\n let author: string | undefined;\n let category: string | undefined;\n let executionOrder: number | undefined;\n let pythonModule: string | undefined;\n\n try {\n // Check for node.constructor.nodeData (ComfyUI stores metadata here)\n const nodeData = (node as any).constructor?.nodeData;\n if (nodeData) {\n pythonModule = nodeData.python_module;\n author = nodeData.author || pythonModule?.split('.')[0];\n category = nodeData.category;\n }\n\n // Try to get from LiteGraph registered node types\n if (!author && typeof LiteGraph !== 'undefined') {\n const nodeType = (LiteGraph as any).registered_node_types?.[node.type];\n if (nodeType) {\n author = nodeType.nodeData?.author || nodeType.author;\n category = nodeType.category || category;\n if (!pythonModule && nodeType.nodeData?.python_module) {\n pythonModule = nodeType.nodeData.python_module;\n }\n }\n }\n\n // Execution order - try to get from node.order (set during graph execution)\n executionOrder = (node as any).order;\n } catch (e) {\n // Silently ignore errors accessing node metadata\n }\n\n return {\n id: node.id,\n title: node.title || \"Untitled Node\",\n type: node.type,\n mode: this.getNodeModeText(node.mode),\n position: {\n x: Math.round(node.pos[0]),\n y: Math.round(node.pos[1]),\n formatted: `(${Math.round(node.pos[0])}, ${Math.round(node.pos[1])})`\n },\n size: {\n width: Math.round(node.size[0]),\n height: Math.round(node.size[1]),\n formatted: `${Math.round(node.size[0])}×${Math.round(node.size[1])}`\n },\n localPosition: {\n x: Math.round(localPos.x),\n y: Math.round(localPos.y),\n formatted: `(${Math.round(localPos.x)}, ${Math.round(localPos.y)})`,\n percentage: {\n x: ((localPos.x / node.size[0]) * 100).toFixed(1),\n y: ((localPos.y / node.size[1]) * 100).toFixed(1)\n }\n },\n counts: {\n widgets: node.widgets ? node.widgets.length : 0,\n inputs: node.inputs ? node.inputs.length : 0,\n outputs: node.outputs ? node.outputs.length : 0,\n properties: node.properties ? Object.keys(node.properties).length : 0\n },\n widgets: node.widgets || [],\n inputs: node.inputs || [],\n outputs: node.outputs || [],\n properties: node.properties || {},\n hoverRegion: this.detectNodeRegion(localPos, node),\n executionOrder: executionOrder,\n author: author,\n category: category,\n pythonModule: pythonModule\n };\n }\n\n getNodeInfo(node: ComfyNode): NodeInfo {\n return {\n id: node.id,\n title: node.title || \"Untitled\",\n type: node.type,\n mode: node.mode,\n size: node.size ? `${Math.round(node.size[0])}×${Math.round(node.size[1])}` : \"Unknown\",\n position: node.pos ? `(${Math.round(node.pos[0])}, ${Math.round(node.pos[1])})` : \"Unknown\",\n widgets: node.widgets || [],\n inputs: node.inputs || [],\n outputs: node.outputs || [],\n properties: node.properties || {}\n };\n }\n\n getWidgetUnderCursor(node: ComfyNode, localPos: { x: number, y: number }): ComfyWidget | null {\n if (!node.widgets || !node.widgets.length) return null;\n\n const titleHeight = 30;\n let currentY = titleHeight;\n\n for (const widget of node.widgets) {\n const widgetHeight = 25;\n\n if (localPos.y >= currentY && localPos.y <= currentY + widgetHeight) {\n return widget;\n }\n\n currentY += widgetHeight + 5;\n }\n\n return null;\n }\n\n getWidgetInfo(widget: ComfyWidget): WidgetInfo {\n return {\n name: widget.name,\n type: widget.type,\n value: this.formatValue(widget.value),\n options: widget.options || null,\n min: widget.min,\n max: widget.max,\n step: widget.step\n };\n }\n\n getMediaInfo(mediaElement: HTMLImageElement | HTMLVideoElement): MediaInfo {\n const info: MediaInfo = {\n type: mediaElement instanceof HTMLImageElement ? 'image' : 'video',\n tagName: mediaElement.tagName,\n src: mediaElement.src ? mediaElement.src.substring(mediaElement.src.lastIndexOf('/') + 1) : 'No source',\n naturalWidth: 0,\n naturalHeight: 0,\n displayWidth: 0,\n displayHeight: 0,\n aspectRatio: ''\n };\n\n if (mediaElement instanceof HTMLImageElement) {\n info.naturalWidth = mediaElement.naturalWidth;\n info.naturalHeight = mediaElement.naturalHeight;\n info.displayWidth = Math.round(mediaElement.width);\n info.displayHeight = Math.round(mediaElement.height);\n if (mediaElement.naturalWidth && mediaElement.naturalHeight) {\n info.aspectRatio = (mediaElement.naturalWidth / mediaElement.naturalHeight).toFixed(2);\n }\n } else if (mediaElement instanceof HTMLVideoElement) {\n info.naturalWidth = mediaElement.videoWidth;\n info.naturalHeight = mediaElement.videoHeight;\n info.displayWidth = Math.round(mediaElement.width);\n info.displayHeight = Math.round(mediaElement.height);\n info.duration = mediaElement.duration;\n info.currentTime = mediaElement.currentTime;\n if (mediaElement.videoWidth && mediaElement.videoHeight) {\n info.aspectRatio = (mediaElement.videoWidth / mediaElement.videoHeight).toFixed(2);\n }\n }\n\n return info;\n }\n\n getNodeModeText(mode: number): string {\n const modes: { [key: number]: string } = {\n 0: 'Always',\n 1: 'On Event',\n 2: 'Never',\n 3: 'On Trigger',\n 4: 'On Request'\n };\n return modes[mode] || `Mode ${mode}`;\n }\n\n detectNodeRegion(localPos: { x: number, y: number }, node: ComfyNode): string {\n const titleHeight = 30;\n const regions: string[] = [];\n\n if (localPos.y <= titleHeight) {\n regions.push(\"Title Bar\");\n }\n\n if (localPos.x <= 10) {\n regions.push(\"Left Edge\");\n } else if (localPos.x >= node.size[0] - 10) {\n regions.push(\"Right Edge\");\n }\n\n if (localPos.y <= 10) {\n regions.push(\"Top Edge\");\n } else if (localPos.y >= node.size[1] - 10) {\n regions.push(\"Bottom Edge\");\n }\n\n if (regions.length === 0) {\n if (localPos.y > titleHeight) {\n regions.push(\"Content Area\");\n }\n }\n\n if (localPos.x <= 20 && localPos.y > titleHeight) {\n regions.push(\"Input Area\");\n } else if (localPos.x >= node.size[0] - 20 && localPos.y > titleHeight) {\n regions.push(\"Output Area\");\n }\n\n return regions.length > 0 ? regions.join(\", \") : \"Unknown\";\n }\n\n formatValue(value: unknown): string {\n if (value === null) return \"null\";\n if (value === undefined) return \"undefined\";\n if (typeof value === \"string\") {\n return value; // Show full text without truncation\n }\n if (typeof value === \"number\") {\n return Number.isInteger(value) ? value.toString() : value.toFixed(3);\n }\n if (typeof value === \"boolean\") return value.toString();\n if (Array.isArray(value)) {\n return `Array(${value.length})`;\n }\n if (typeof value === \"object\") {\n return \"Object\";\n }\n return String(value);\n }\n}\n"],"names":["canvasRect","mouseX","mouseY","graphPos"],"mappings":"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"}
\ No newline at end of file
diff --git a/web/info-panel/UIManager.js b/web/info-panel/UIManager.js
index 75758eb..0e44687 100644
--- a/web/info-panel/UIManager.js
+++ b/web/info-panel/UIManager.js
@@ -268,6 +268,8 @@ class UIManager {
this.elements.panel.style.pointerEvents = "auto";
this.elements.panel.style.userSelect = "none";
this.elements.panel.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
+ const fontSize = settings["🔍MagnifyGlass.InfoPanelFontSize"] || 14;
+ this.elements.panel.style.fontSize = `${fontSize}px`;
this.elements.panel.style.transition = settings["🔍MagnifyGlass.InfoPanelAnimations"] ? "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)" : "none";
const textColor = settings["🔍MagnifyGlass.InfoPanelTextColor"];
if (textColor && typeof textColor === "string") {
@@ -405,8 +407,9 @@ class UIManager {
if (info.hoveredNode.category) {
nodeContent.push({ label: "Category", value: info.hoveredNode.category });
}
- if (info.hoveredNode.author) {
- nodeContent.push({ label: "Author", value: info.hoveredNode.author });
+ if (info.hoveredNode.pythonModule) {
+ const path = info.hoveredNode.pythonModule.replace(/\./g, "/") + ".py";
+ nodeContent.push({ label: "Path", value: path });
}
const nodeType = info.hoveredNode.type ? info.hoveredNode.type.toLowerCase() : "";
const isSaveNode = nodeType.includes("save") && !nodeType.includes("checkpoint") && !nodeType.includes("model") && !nodeType.includes("preview");
diff --git a/web/info-panel/UIManager.js.map b/web/info-panel/UIManager.js.map
index 945a669..d32c656 100644
--- a/web/info-panel/UIManager.js.map
+++ b/web/info-panel/UIManager.js.map
@@ -1 +1 @@
-{"version":3,"file":"UIManager.js","sources":["../../src/info-panel/UIManager.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Info Panel UI Manager (TypeScript)\n * \n * Complete UI Manager extracted from magnify_info_panel.js\n * Handles all DOM manipulation and UI creation for the info panel.\n */\n\nimport { StateManager } from './StateManager';\nimport { Icons } from '../shared/icons';\nimport { Logger } from '../shared/logger';\nimport { formatValue, getValueClass, getValueAttributes, formatWidgetValue } from './ValueFormatter';\nimport {\n getCheckpointInfo,\n getImageInfo,\n getTextBoxContent,\n getImportantNodeParameters,\n type ImageInfoResult\n} from './NodeDataExtractor';\n\ninterface InfoPanelElements {\n panel: HTMLDivElement | null;\n header: HTMLDivElement | null;\n content: HTMLDivElement | null;\n controls: HTMLDivElement | null;\n}\n\n/**\n * UI Manager class.\n * Handles all DOM manipulation and UI creation.\n */\nexport class UIManager {\n stateManager: StateManager;\n elements: InfoPanelElements;\n\n constructor(stateManager: StateManager) {\n this.stateManager = stateManager;\n this.elements = {\n panel: null,\n header: null,\n content: null,\n controls: null\n };\n\n this.createPanel();\n this.injectStyles();\n }\n\n /**\n * Create the main panel and its components.\n */\n createPanel(): void {\n // Main panel container\n this.elements.panel = document.createElement(\"div\");\n this.elements.panel.id = \"comfyui-magnify-info-panel-pro-v2\";\n this.elements.panel.className = `magnify-info-panel theme-${this.stateManager.state.currentTheme}`;\n\n // Header\n this.elements.header = document.createElement(\"div\");\n this.elements.header.className = \"panel-header\";\n this.elements.header.innerHTML = `\n
\n \n `;\n\n // Content container\n this.elements.content = document.createElement(\"div\");\n this.elements.content.className = \"panel-content\";\n\n this.elements.panel.appendChild(this.elements.header);\n this.elements.panel.appendChild(this.elements.content);\n\n this.applyStyles();\n // Apply initial minimized state if set\n if (this.stateManager.state.isPanelMinimized) {\n this.elements.panel.classList.add('panel-minimized');\n }\n document.body.appendChild(this.elements.panel);\n\n // Hover-expand: Add/remove 'is-expanded' class, reposition, and resize font if needed\n let originalTop: number | null = null;\n let originalFontSize: number | null = null;\n const MIN_FONT_SIZE = 10; // Minimum font size in pixels\n const MARGIN = 20; // Minimum margin from viewport edges\n\n this.elements.panel.addEventListener('mouseenter', () => {\n if (!this.stateManager.state.isPanelMinimized && this.elements.panel) {\n // Save original position\n originalTop = this.elements.panel.offsetTop;\n // Save original font size just in case, though we won't change it\n originalFontSize = parseFloat(getComputedStyle(this.elements.panel).fontSize);\n\n // Add expanded class\n this.elements.panel.classList.add('is-expanded');\n\n // Simple repositioning logic only (no font scaling)\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (!this.elements.panel) return;\n\n const viewportHeight = window.innerHeight;\n const rect = this.elements.panel.getBoundingClientRect();\n\n // Position the panel to fit (move up if needed)\n if (rect.bottom > viewportHeight - MARGIN) {\n const newTop = Math.max(MARGIN, originalTop! - (rect.bottom - viewportHeight + MARGIN));\n this.elements.panel.style.top = `${newTop}px`;\n }\n });\n });\n }\n });\n\n this.elements.panel.addEventListener('mouseleave', () => {\n if (this.elements.panel) {\n this.elements.panel.classList.remove('is-expanded');\n\n // Restore original position\n if (originalTop !== null) {\n this.elements.panel.style.top = `${originalTop}px`;\n originalTop = null;\n }\n\n // Restore original font size (if it was somehow changed)\n if (originalFontSize !== null) {\n this.elements.panel.style.fontSize = `${originalFontSize}px`;\n originalFontSize = null;\n }\n\n // Clear any inline styles that might have been set\n this.elements.panel.style.transform = '';\n this.elements.panel.style.transformOrigin = '';\n }\n });\n\n // Add click event delegation for panel elements\n this.elements.panel.addEventListener('click', (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n\n // Handle minimize button\n const minimizeBtn = target.closest('[data-action=\"minimize\"]');\n if (minimizeBtn) {\n this.stateManager.state.isPanelMinimized = !this.stateManager.state.isPanelMinimized;\n this.updateMinimizedState();\n return;\n }\n\n // Handle section header clicks for expand/collapse\n const sectionHeader = target.closest('.section-header') as HTMLElement;\n if (sectionHeader) {\n const sectionId = sectionHeader.getAttribute('data-section');\n // Skip node section (always expanded)\n if (sectionId && sectionId !== 'node') {\n const isExpanded = this.stateManager.state.expandedSections.has(sectionId);\n if (isExpanded) {\n this.stateManager.state.expandedSections.delete(sectionId);\n } else {\n this.stateManager.state.expandedSections.add(sectionId);\n }\n\n // Update visual state\n sectionHeader.classList.toggle('expanded', !isExpanded);\n const sectionContent = sectionHeader.nextElementSibling as HTMLElement;\n if (sectionContent && sectionContent.classList.contains('section-content')) {\n sectionContent.classList.toggle('expanded', !isExpanded);\n }\n }\n }\n });\n\n // Create floating controls after panel is in DOM\n if (!this.elements.controls) {\n this.createFloatingControls();\n // Update control states immediately after creation\n this.updateControlStates();\n }\n }\n\n /**\n * Create floating control buttons.\n */\n createFloatingControls(): void {\n this.elements.controls = document.createElement(\"div\");\n this.elements.controls.className = `floating-controls vertical-layout theme-${this.stateManager.state.currentTheme}`; // Default to vertical + theme\n\n /**\n * BUTTON MAPPING DOCUMENTATION:\n * =============================\n * Button 1 (Unlock Icon): data-action=\"pin\" → controls isPanelPinned\n * - Unpinned (default): Panel follows magnify glass\n * - Pinned: Panel stays at fixed position (unlocked from following glass)\n * \n * Button 2 (Pin Icon): data-action=\"lock\" → controls isPanelLocked\n * - Unlocked (default): Panel can be dragged\n * - Locked: Panel cannot be dragged (pinned in place)\n * \n * NOTE: The data-action names are counterintuitive but kept for backwards compatibility.\n * The ICONS correctly represent the functionality:\n * - Unlock icon = unlock from following glass\n * - Pin icon = pin position (prevent drag)\n */\n this.elements.controls.innerHTML = `\n \n \n \n \n `;\n\n // Insert before the panel in the document body, not as a child\n document.body.appendChild(this.elements.controls);\n\n // Hide and position off-screen initially - will be shown when magnify glass activates and positions them\n this.elements.controls.style.display = 'none';\n this.elements.controls.style.visibility = 'hidden';\n this.elements.controls.style.left = '-9999px';\n this.elements.controls.style.top = '-9999px';\n\n // Add click event delegation for control buttons\n this.elements.controls.addEventListener('click', (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n const button = target.closest('button[data-action]') as HTMLButtonElement;\n if (!button) return;\n\n const action = button.getAttribute('data-action');\n Logger.debug(`Control button clicked: ${action}`);\n\n switch (action) {\n case 'pin':\n this.stateManager.togglePinning();\n this.updatePinnedState();\n this.updateControlStates();\n break;\n case 'lock':\n this.stateManager.state.isPanelLocked = !this.stateManager.state.isPanelLocked;\n this.updateControlStates();\n if (this.elements.panel) {\n this.elements.panel.classList.toggle('panel-locked', this.stateManager.state.isPanelLocked);\n }\n break;\n case 'toggle-panel':\n if (this.stateManager.state.isPanelVisible) {\n this.hide();\n } else {\n this.show();\n }\n this.updateControlStates();\n break;\n case 'toggle-glass':\n this.stateManager.state.isGlassPreviewVisible = !this.stateManager.state.isGlassPreviewVisible;\n\n // Link Glass Visibility to Panel Pinning\n if (!this.stateManager.state.isGlassPreviewVisible) {\n // Glass Hidden\n console.log(`[MagnifyGlass Debug] Glass Hidden. pinned=${this.stateManager.state.isPanelPinned}, autoPinned=${this.stateManager.state.isAutoPinned}`);\n // Only auto-pin if not already pinned by the user\n if (!this.stateManager.state.isPanelPinned) {\n if (this.elements.panel) {\n const rect = this.elements.panel.getBoundingClientRect();\n this.stateManager.state.pinnedPosition = { x: rect.left, y: rect.top };\n }\n this.stateManager.state.isPanelPinned = true;\n this.stateManager.state.isAutoPinned = true; // Track that this was auto-pinned\n console.log(`[MagnifyGlass Debug] Auto-Pinned panel.`);\n }\n // Do NOT reset isPanelLocked here - preserve user's lock state\n } else {\n // Glass Shown\n console.log(`[MagnifyGlass Debug] Glass Shown. pinned=${this.stateManager.state.isPanelPinned}, autoPinned=${this.stateManager.state.isAutoPinned}`);\n // Only unpin if it was auto-pinned (not user-pinned)\n if (this.stateManager.state.isAutoPinned) {\n this.stateManager.state.isPanelPinned = false;\n this.stateManager.state.isAutoPinned = false;\n console.log(`[MagnifyGlass Debug] Auto-Unpinned panel.`);\n }\n // If user manually pinned, keep the panel pinned\n }\n\n this.updateControlStates();\n this.updatePinnedState(); // Update visual class\n\n // Toggle ONLY the visual visibility (opacity) of the glass preview\n // The tool remains active so the inspector can track position\n const magnifyGlass = (window as any).comfyUIMagnifyGlass;\n if (magnifyGlass && magnifyGlass.ui?.setPreviewVisibility) {\n magnifyGlass.ui.setPreviewVisibility(this.stateManager.state.isGlassPreviewVisible);\n }\n break;\n }\n });\n\n // Set initial layout based on settings\n const controlsPosition = String(this.stateManager.state.settings[\"🔍MagnifyGlass.ControlsPosition\"] || \"top-right\");\n this.updateControlsLayout(controlsPosition);\n\n // Initial state update\n this.updateControlStates();\n }\n\n /**\n * Update control button states.\n */\n updateControlStates(): void {\n if (!this.elements.controls) return;\n\n const pinBtn = this.elements.controls.querySelector('[data-action=\"pin\"]') as HTMLButtonElement;\n const lockBtn = this.elements.controls.querySelector('[data-action=\"lock\"]') as HTMLButtonElement;\n const visibilityBtn = this.elements.controls.querySelector('[data-action=\"toggle-panel\"]') as HTMLButtonElement;\n const glassBtn = this.elements.controls.querySelector('[data-action=\"toggle-glass\"]') as HTMLButtonElement;\n const isPanelVisible = this.stateManager.state.isPanelVisible;\n const isGlassVisible = this.stateManager.state.isGlassPreviewVisible;\n\n if (pinBtn) {\n pinBtn.classList.toggle('active', this.stateManager.state.isPanelPinned);\n pinBtn.title = this.stateManager.state.isPanelPinned ? \"Lock Panel\" : \"Unlock Panel\";\n pinBtn.innerHTML = this.stateManager.state.isPanelPinned ? Icons.lock : Icons.unlock;\n // Hide unlock button when panel is hidden\n pinBtn.style.display = isPanelVisible ? 'flex' : 'none';\n\n // Do not disable the pin button even if glass is hidden.\n // If the user unpins while glass is hidden, the panel will just attach to the hidden glass (and disappear).\n pinBtn.disabled = false;\n pinBtn.style.opacity = '';\n\n // Only update title if glass is hidden to warn user\n if (!isGlassVisible && !this.stateManager.state.isPanelPinned) {\n // Optional: You could add a tooltip warning here if really needed, \n // but keeping it simple is better.\n }\n }\n\n if (lockBtn) {\n // Only show pin button when panel is visible AND unlocked from glass\n const showLockBtn = isPanelVisible && this.stateManager.state.isPanelPinned;\n lockBtn.style.display = showLockBtn ? 'flex' : 'none';\n lockBtn.classList.toggle('active', this.stateManager.state.isPanelLocked);\n lockBtn.title = this.stateManager.state.isPanelLocked ? \"Unpin Panel Position\" : \"Pin Panel Position\";\n lockBtn.disabled = !this.stateManager.state.isPanelPinned;\n }\n\n if (visibilityBtn) {\n // Active means \"Panel is Visible\"\n visibilityBtn.classList.toggle('active', isPanelVisible);\n visibilityBtn.title = isPanelVisible ? \"Hide Panel\" : \"Show Panel\";\n\n // Disable hide button if glass is hidden (prevent hiding everything)\n if (!isGlassVisible) {\n visibilityBtn.disabled = true;\n visibilityBtn.style.opacity = '0.5';\n visibilityBtn.title = \"Cannot hide panel when glass preview is hidden\";\n } else {\n visibilityBtn.disabled = false;\n visibilityBtn.style.opacity = '';\n }\n }\n\n if (glassBtn) {\n glassBtn.classList.toggle('active', isGlassVisible);\n glassBtn.title = isGlassVisible ? \"Hide Glass Preview\" : \"Show Glass Preview\";\n\n // Only show glass toggle button if the inspector panel is visible\n glassBtn.style.display = isPanelVisible ? 'flex' : 'none';\n }\n }\n\n /**\n * Update controls layout based on position setting.\n * @param position \n */\n updateControlsLayout(position: string): void {\n if (!this.elements.controls) return;\n\n // Remove existing layout classes\n this.elements.controls.classList.remove('horizontal-layout', 'vertical-layout');\n\n // Add appropriate layout class\n if (['top', 'bottom'].includes(position)) {\n this.elements.controls.classList.add('horizontal-layout');\n } else {\n this.elements.controls.classList.add('vertical-layout');\n }\n }\n\n /**\n * Apply current styles to elements.\n */\n applyStyles(): void {\n if (!this.elements.panel) return;\n\n const settings = this.stateManager.state.settings;\n\n // Debug Log\n console.log(`[UIManager] applyStyles - MaxHeight: ${settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"]}`);\n\n // 1. Apply dimensions\n this.elements.panel.style.width = `${settings[\"🔍MagnifyGlass.InfoPanelWidth\"]}px`;\n // Set max-height via CSS variable so CSS :hover rules can override\n const maxHeight = settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"];\n this.elements.panel.style.setProperty('--panel-max-height', `${maxHeight}px`);\n this.elements.panel.style.height = 'auto';\n\n // 2. Apply static styles (only needed once or if overwritten, but safe to set)\n this.elements.panel.style.position = 'absolute';\n this.elements.panel.style.zIndex = '99999';\n this.elements.panel.style.transform = 'translateY(-10px)';\n this.elements.panel.style.pointerEvents = 'auto';\n this.elements.panel.style.userSelect = 'none';\n this.elements.panel.style.fontFamily = \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\";\n\n // 3. Apply transition\n this.elements.panel.style.transition = settings[\"🔍MagnifyGlass.InfoPanelAnimations\"]\n ? 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'\n : 'none';\n\n // 4. Apply Custom Colors (CSS Variables)\n const textColor = settings[\"🔍MagnifyGlass.InfoPanelTextColor\"] as string | undefined;\n if (textColor && typeof textColor === 'string') {\n const normalizedTextColor = textColor.startsWith('#') ? textColor : `#${textColor}`;\n this.elements.panel.style.setProperty('--info-panel-text-color', normalizedTextColor);\n }\n\n const accentColor = settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"] as string | undefined;\n if (accentColor && typeof accentColor === 'string') {\n const normalizedAccentColor = accentColor.startsWith('#') ? accentColor : `#${accentColor}`;\n this.elements.panel.style.setProperty('--info-panel-accent-color', normalizedAccentColor);\n }\n\n // 5. Apply Opacity\n // Logic: If visible, use setting. If hidden, use 0.\n // We do NOT touch 'display' here to avoid hiding it if it's currently shown.\n // 'display' is managed by show() / hide() methods exclusively.\n if (this.stateManager.state.isPanelVisible) {\n const opacityPercent = Number(settings[\"🔍MagnifyGlass.InfoPanelOpacity\"]) || 100;\n this.elements.panel.style.opacity = (opacityPercent / 100).toString();\n } else {\n this.elements.panel.style.opacity = '0';\n }\n }\n\n /**\n * Show the panel.\n */\n show(): void {\n if (!this.elements.panel) return;\n\n if (this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelEnabled\"]) {\n this.elements.panel.style.display = \"block\";\n // Controls are shown by positionFloatingControls() after proper positioning\n // Apply user's opacity setting when showing (convert percentage to decimal)\n const opacityPercent = Number(this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelOpacity\"]) || 100;\n this.elements.panel.style.opacity = (opacityPercent / 100).toString();\n // Trigger reflow\n this.elements.panel.offsetHeight;\n this.elements.panel.classList.add('visible');\n this.stateManager.state.isPanelVisible = true;\n this.updateControlStates();\n }\n }\n\n /**\n * Hide the panel.\n */\n hide(): void {\n if (!this.elements.panel) return;\n\n this.elements.panel.classList.remove('visible');\n setTimeout(() => {\n if (!this.stateManager.state.isPanelVisible && this.elements.panel) {\n this.elements.panel.style.display = \"none\";\n // Do NOT hide controls when panel is hidden - they should remain visible on glass\n // if (this.elements.controls) {\n // this.elements.controls.style.display = \"none\";\n // }\n }\n }, this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAnimations\"] ? 300 : 0);\n this.stateManager.state.isPanelVisible = false;\n this.updateControlStates();\n }\n\n /**\n * Update minimized state.\n */\n updateMinimizedState(): void {\n if (!this.elements.panel || !this.elements.header) return;\n\n this.elements.panel.classList.toggle('panel-minimized', this.stateManager.state.isPanelMinimized);\n const minimizeBtn = this.elements.header.querySelector('.minimize-btn');\n if (minimizeBtn) {\n minimizeBtn.textContent = this.stateManager.state.isPanelMinimized ? '+' : '−';\n (minimizeBtn as HTMLElement).title = this.stateManager.state.isPanelMinimized ? 'Expand Panel' : 'Minimize Panel';\n }\n }\n\n /**\n * Update pinned state.\n */\n updatePinnedState(): void {\n if (!this.elements.panel) return;\n\n this.elements.panel.classList.toggle('panel-pinned', this.stateManager.state.isPanelPinned);\n this.elements.panel.classList.toggle('panel-locked', this.stateManager.state.isPanelLocked);\n this.updateControlStates();\n }\n\n /**\n * Update theme class.\n * @param newTheme \n */\n updateTheme(newTheme: string): void {\n if (this.elements.panel) {\n this.elements.panel.className = this.elements.panel.className.replace(/theme-\\w+/, `theme-${newTheme.toLowerCase()}`);\n }\n if (this.elements.controls) {\n this.elements.controls.className = this.elements.controls.className.replace(/theme-\\w+/, `theme-${newTheme.toLowerCase()}`);\n }\n }\n\n /**\n * Display information in the panel.\n * @param info \n */\n displayInfo(info: any): void {\n const sections = this.buildSections(info);\n this.renderSections(sections);\n this.updateSectionStates();\n this.updateHeaderSubtitle(info);\n }\n\n /**\n * Build section data from info object.\n * @param info \n * @returns \n */\n buildSections(info: any): any[] {\n const sections: any[] = [];\n const settings = this.stateManager.state.settings;\n\n // Inspector section\n if (settings[\"🔍MagnifyGlass.ShowInspectorTab\"] && info.cursor && info.cursor.canvas) {\n const inspectorContent = [\n { label: 'Cursor Canvas', value: `(${Math.round(info.cursor.canvas.x)}, ${Math.round(info.cursor.canvas.y)})` },\n { label: 'Canvas Scale', value: `${(info.canvas.scale * 100).toFixed(1)}%` },\n { label: 'Magnifier Zoom', value: `${info.magnifier.zoomFactor}×` }\n ];\n\n sections.push({\n id: 'inspector',\n icon: Icons.info,\n title: 'Inspector',\n content: inspectorContent\n });\n }\n\n // Media section\n if (info.media) {\n const mediaContent = [\n { label: 'Type', value: info.media.tagName },\n { label: 'Source', value: info.media.src }\n ];\n\n if (info.media.naturalSize) {\n mediaContent.push({ label: 'Natural', value: info.media.naturalSize });\n }\n\n sections.push({\n id: 'media',\n icon: Icons.camera,\n title: 'Media',\n badge: info.media.tagName,\n content: mediaContent\n });\n }\n\n // Node Details section\n if (info.hoveredNode) {\n const nodeContent = [\n { label: 'Title', value: info.hoveredNode.title }\n ];\n\n // Add execution order if available\n if (info.hoveredNode.executionOrder !== undefined) {\n nodeContent.push({ label: 'Exec Order', value: info.hoveredNode.executionOrder });\n }\n\n // Add category if available\n if (info.hoveredNode.category) {\n nodeContent.push({ label: 'Category', value: info.hoveredNode.category });\n }\n\n // Add author if available\n if (info.hoveredNode.author) {\n nodeContent.push({ label: 'Author', value: info.hoveredNode.author });\n }\n\n // Check if this is a complex node that shows all widgets\n const nodeType = info.hoveredNode.type ? info.hoveredNode.type.toLowerCase() : '';\n const isSaveNode = nodeType.includes('save') &&\n !nodeType.includes('checkpoint') &&\n !nodeType.includes('model') &&\n !nodeType.includes('preview');\n\n const showAllWidgets = info.hoveredNode.type && (\n nodeType.includes('ksampler') ||\n nodeType.includes('sampler') ||\n nodeType.includes('k_samplers') ||\n nodeType.includes('checkpoint') ||\n nodeType.includes('model') ||\n nodeType.includes('lora') ||\n nodeType.includes('controlnet') ||\n nodeType.includes('advanced') ||\n nodeType.includes('detailer') ||\n nodeType.includes('inpaint') ||\n nodeType.includes('upscale') ||\n nodeType.includes('clip') ||\n nodeType.includes('text') ||\n nodeType.includes('encode')\n ) && !isSaveNode;\n\n if (!showAllWidgets) {\n // Add specific extractions for simple nodes\n const checkpoint = getCheckpointInfo(info.hoveredNode);\n if (checkpoint) {\n nodeContent.push({ label: 'Model', value: checkpoint });\n }\n\n const imgInfo = getImageInfo(info.hoveredNode);\n if (imgInfo) {\n if (typeof imgInfo === 'string') {\n nodeContent.push({ label: 'Image', value: imgInfo });\n } else if (typeof imgInfo === 'object' && imgInfo !== null) {\n const imgResult = imgInfo as ImageInfoResult;\n nodeContent.push({ label: 'Image Size', value: `${imgResult.width}×${imgResult.height}` });\n if (imgResult.src) {\n nodeContent.push({ label: 'Image Source', value: imgResult.src });\n }\n }\n }\n\n const textContent = getTextBoxContent(info.hoveredNode);\n if (textContent) {\n nodeContent.push({ label: 'Text', value: textContent });\n }\n }\n\n const importantParameters = getImportantNodeParameters(info.hoveredNode);\n nodeContent.push(...importantParameters);\n\n sections.push({\n id: 'node',\n icon: Icons.box,\n title: 'Node',\n badge: info.hoveredNode.type,\n content: nodeContent\n });\n }\n\n return sections;\n }\n\n /**\n * Render sections to the panel.\n * @param sections \n */\n renderSections(sections: any[]): void {\n if (!this.elements.content) return;\n\n if (sections.length === 0) {\n this.elements.content.innerHTML = `\n \n
${Icons.mapPin}
\n
Empty canvas area
\n
\n `;\n return;\n }\n\n this.elements.content.innerHTML = sections.map(section => `\n \n \n
\n
\n ${section.content.map((item: any) => {\n const value = formatValue(item.value, item.label);\n const valueClass = getValueClass(item.value);\n const valueAttributes = getValueAttributes(item.value);\n return `\n
\n ${item.label}\n ${value}\n
`;\n }).join('')}\n
\n
\n
`).join('');\n }\n\n /**\n * Update section expansion states.\n */\n updateSectionStates(): void {\n if (!this.elements.content) return;\n\n const sections = this.elements.content.querySelectorAll('.info-section');\n sections.forEach(section => {\n const sectionId = (section as HTMLElement).dataset.section;\n if (!sectionId) return;\n\n const header = section.querySelector('.section-header');\n const content = section.querySelector('.section-content');\n\n if (header && content) {\n if (this.stateManager.state.expandedSections.has(sectionId)) {\n header.classList.add('expanded');\n content.classList.add('expanded');\n } else {\n header.classList.remove('expanded');\n content.classList.remove('expanded');\n }\n }\n });\n }\n\n /**\n * Update header subtitle.\n * @param info \n */\n updateHeaderSubtitle(info: any): void {\n if (!this.elements.header) return;\n\n const subtitleElement = this.elements.header.querySelector('.header-subtitle') as HTMLElement;\n if (subtitleElement) {\n const accentColor = String(this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"] || '');\n if (info.hoveredNode) {\n subtitleElement.textContent = `Analyzing: ${info.hoveredNode.title} `;\n subtitleElement.style.color = accentColor;\n } else if (info.media) {\n subtitleElement.textContent = `Media: ${info.media.tagName} `;\n subtitleElement.style.color = accentColor;\n } else if (info.connection) {\n subtitleElement.textContent = `Connection: ${info.connection.type} `;\n subtitleElement.style.color = accentColor;\n } else {\n subtitleElement.textContent = 'Real-time analysis';\n subtitleElement.style.color = '';\n }\n }\n }\n\n /**\n * Inject CSS styles by loading external stylesheet.\n */\n injectStyles(): void {\n if (!document.getElementById('magnify-info-panel-styles-v2')) {\n const link = document.createElement('link');\n link.id = 'magnify-info-panel-styles-v2';\n link.rel = 'stylesheet';\n link.type = 'text/css';\n link.href = 'extensions/comfyui-magnifyglass/info-panel.css';\n document.head.appendChild(link);\n }\n }\n\n cleanup(): void {\n if (this.elements.panel && this.elements.panel.parentNode) {\n this.elements.panel.parentNode.removeChild(this.elements.panel);\n }\n if (this.elements.controls && this.elements.controls.parentNode) {\n this.elements.controls.parentNode.removeChild(this.elements.controls);\n }\n }\n}\n"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"UIManager.js","sources":["../../src/info-panel/UIManager.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Info Panel UI Manager (TypeScript)\n * \n * Complete UI Manager extracted from magnify_info_panel.js\n * Handles all DOM manipulation and UI creation for the info panel.\n */\n\nimport { StateManager } from './StateManager';\nimport { Icons } from '../shared/icons';\nimport { Logger } from '../shared/logger';\nimport { formatValue, getValueClass, getValueAttributes, formatWidgetValue } from './ValueFormatter';\nimport {\n getCheckpointInfo,\n getImageInfo,\n getTextBoxContent,\n getImportantNodeParameters,\n type ImageInfoResult\n} from './NodeDataExtractor';\n\ninterface InfoPanelElements {\n panel: HTMLDivElement | null;\n header: HTMLDivElement | null;\n content: HTMLDivElement | null;\n controls: HTMLDivElement | null;\n}\n\n/**\n * UI Manager class.\n * Handles all DOM manipulation and UI creation.\n */\nexport class UIManager {\n stateManager: StateManager;\n elements: InfoPanelElements;\n\n constructor(stateManager: StateManager) {\n this.stateManager = stateManager;\n this.elements = {\n panel: null,\n header: null,\n content: null,\n controls: null\n };\n\n this.createPanel();\n this.injectStyles();\n }\n\n /**\n * Create the main panel and its components.\n */\n createPanel(): void {\n // Main panel container\n this.elements.panel = document.createElement(\"div\");\n this.elements.panel.id = \"comfyui-magnify-info-panel-pro-v2\";\n this.elements.panel.className = `magnify-info-panel theme-${this.stateManager.state.currentTheme}`;\n\n // Header\n this.elements.header = document.createElement(\"div\");\n this.elements.header.className = \"panel-header\";\n this.elements.header.innerHTML = `\n \n \n `;\n\n // Content container\n this.elements.content = document.createElement(\"div\");\n this.elements.content.className = \"panel-content\";\n\n this.elements.panel.appendChild(this.elements.header);\n this.elements.panel.appendChild(this.elements.content);\n\n this.applyStyles();\n // Apply initial minimized state if set\n if (this.stateManager.state.isPanelMinimized) {\n this.elements.panel.classList.add('panel-minimized');\n }\n document.body.appendChild(this.elements.panel);\n\n // Hover-expand: Add/remove 'is-expanded' class, reposition, and resize font if needed\n let originalTop: number | null = null;\n let originalFontSize: number | null = null;\n const MIN_FONT_SIZE = 10; // Minimum font size in pixels\n const MARGIN = 20; // Minimum margin from viewport edges\n\n this.elements.panel.addEventListener('mouseenter', () => {\n if (!this.stateManager.state.isPanelMinimized && this.elements.panel) {\n // Save original position\n originalTop = this.elements.panel.offsetTop;\n // Save original font size just in case, though we won't change it\n originalFontSize = parseFloat(getComputedStyle(this.elements.panel).fontSize);\n\n // Add expanded class\n this.elements.panel.classList.add('is-expanded');\n\n // Simple repositioning logic only (no font scaling)\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (!this.elements.panel) return;\n\n const viewportHeight = window.innerHeight;\n const rect = this.elements.panel.getBoundingClientRect();\n\n // Position the panel to fit (move up if needed)\n if (rect.bottom > viewportHeight - MARGIN) {\n const newTop = Math.max(MARGIN, originalTop! - (rect.bottom - viewportHeight + MARGIN));\n this.elements.panel.style.top = `${newTop}px`;\n }\n });\n });\n }\n });\n\n this.elements.panel.addEventListener('mouseleave', () => {\n if (this.elements.panel) {\n this.elements.panel.classList.remove('is-expanded');\n\n // Restore original position\n if (originalTop !== null) {\n this.elements.panel.style.top = `${originalTop}px`;\n originalTop = null;\n }\n\n // Restore original font size (if it was somehow changed)\n if (originalFontSize !== null) {\n this.elements.panel.style.fontSize = `${originalFontSize}px`;\n originalFontSize = null;\n }\n\n // Clear any inline styles that might have been set\n this.elements.panel.style.transform = '';\n this.elements.panel.style.transformOrigin = '';\n }\n });\n\n // Add click event delegation for panel elements\n this.elements.panel.addEventListener('click', (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n\n // Handle minimize button\n const minimizeBtn = target.closest('[data-action=\"minimize\"]');\n if (minimizeBtn) {\n this.stateManager.state.isPanelMinimized = !this.stateManager.state.isPanelMinimized;\n this.updateMinimizedState();\n return;\n }\n\n // Handle section header clicks for expand/collapse\n const sectionHeader = target.closest('.section-header') as HTMLElement;\n if (sectionHeader) {\n const sectionId = sectionHeader.getAttribute('data-section');\n // Skip node section (always expanded)\n if (sectionId && sectionId !== 'node') {\n const isExpanded = this.stateManager.state.expandedSections.has(sectionId);\n if (isExpanded) {\n this.stateManager.state.expandedSections.delete(sectionId);\n } else {\n this.stateManager.state.expandedSections.add(sectionId);\n }\n\n // Update visual state\n sectionHeader.classList.toggle('expanded', !isExpanded);\n const sectionContent = sectionHeader.nextElementSibling as HTMLElement;\n if (sectionContent && sectionContent.classList.contains('section-content')) {\n sectionContent.classList.toggle('expanded', !isExpanded);\n }\n }\n }\n });\n\n // Create floating controls after panel is in DOM\n if (!this.elements.controls) {\n this.createFloatingControls();\n // Update control states immediately after creation\n this.updateControlStates();\n }\n }\n\n /**\n * Create floating control buttons.\n */\n createFloatingControls(): void {\n this.elements.controls = document.createElement(\"div\");\n this.elements.controls.className = `floating-controls vertical-layout theme-${this.stateManager.state.currentTheme}`; // Default to vertical + theme\n\n /**\n * BUTTON MAPPING DOCUMENTATION:\n * =============================\n * Button 1 (Unlock Icon): data-action=\"pin\" → controls isPanelPinned\n * - Unpinned (default): Panel follows magnify glass\n * - Pinned: Panel stays at fixed position (unlocked from following glass)\n * \n * Button 2 (Pin Icon): data-action=\"lock\" → controls isPanelLocked\n * - Unlocked (default): Panel can be dragged\n * - Locked: Panel cannot be dragged (pinned in place)\n * \n * NOTE: The data-action names are counterintuitive but kept for backwards compatibility.\n * The ICONS correctly represent the functionality:\n * - Unlock icon = unlock from following glass\n * - Pin icon = pin position (prevent drag)\n */\n this.elements.controls.innerHTML = `\n \n \n \n \n `;\n\n // Insert before the panel in the document body, not as a child\n document.body.appendChild(this.elements.controls);\n\n // Hide and position off-screen initially - will be shown when magnify glass activates and positions them\n this.elements.controls.style.display = 'none';\n this.elements.controls.style.visibility = 'hidden';\n this.elements.controls.style.left = '-9999px';\n this.elements.controls.style.top = '-9999px';\n\n // Add click event delegation for control buttons\n this.elements.controls.addEventListener('click', (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n const button = target.closest('button[data-action]') as HTMLButtonElement;\n if (!button) return;\n\n const action = button.getAttribute('data-action');\n Logger.debug(`Control button clicked: ${action}`);\n\n switch (action) {\n case 'pin':\n this.stateManager.togglePinning();\n this.updatePinnedState();\n this.updateControlStates();\n break;\n case 'lock':\n this.stateManager.state.isPanelLocked = !this.stateManager.state.isPanelLocked;\n this.updateControlStates();\n if (this.elements.panel) {\n this.elements.panel.classList.toggle('panel-locked', this.stateManager.state.isPanelLocked);\n }\n break;\n case 'toggle-panel':\n if (this.stateManager.state.isPanelVisible) {\n this.hide();\n } else {\n this.show();\n }\n this.updateControlStates();\n break;\n case 'toggle-glass':\n this.stateManager.state.isGlassPreviewVisible = !this.stateManager.state.isGlassPreviewVisible;\n\n // Link Glass Visibility to Panel Pinning\n if (!this.stateManager.state.isGlassPreviewVisible) {\n // Glass Hidden\n console.log(`[MagnifyGlass Debug] Glass Hidden. pinned=${this.stateManager.state.isPanelPinned}, autoPinned=${this.stateManager.state.isAutoPinned}`);\n // Only auto-pin if not already pinned by the user\n if (!this.stateManager.state.isPanelPinned) {\n if (this.elements.panel) {\n const rect = this.elements.panel.getBoundingClientRect();\n this.stateManager.state.pinnedPosition = { x: rect.left, y: rect.top };\n }\n this.stateManager.state.isPanelPinned = true;\n this.stateManager.state.isAutoPinned = true; // Track that this was auto-pinned\n console.log(`[MagnifyGlass Debug] Auto-Pinned panel.`);\n }\n // Do NOT reset isPanelLocked here - preserve user's lock state\n } else {\n // Glass Shown\n console.log(`[MagnifyGlass Debug] Glass Shown. pinned=${this.stateManager.state.isPanelPinned}, autoPinned=${this.stateManager.state.isAutoPinned}`);\n // Only unpin if it was auto-pinned (not user-pinned)\n if (this.stateManager.state.isAutoPinned) {\n this.stateManager.state.isPanelPinned = false;\n this.stateManager.state.isAutoPinned = false;\n console.log(`[MagnifyGlass Debug] Auto-Unpinned panel.`);\n }\n // If user manually pinned, keep the panel pinned\n }\n\n this.updateControlStates();\n this.updatePinnedState(); // Update visual class\n\n // Toggle ONLY the visual visibility (opacity) of the glass preview\n // The tool remains active so the inspector can track position\n const magnifyGlass = (window as any).comfyUIMagnifyGlass;\n if (magnifyGlass && magnifyGlass.ui?.setPreviewVisibility) {\n magnifyGlass.ui.setPreviewVisibility(this.stateManager.state.isGlassPreviewVisible);\n }\n break;\n }\n });\n\n // Set initial layout based on settings\n const controlsPosition = String(this.stateManager.state.settings[\"🔍MagnifyGlass.ControlsPosition\"] || \"top-right\");\n this.updateControlsLayout(controlsPosition);\n\n // Initial state update\n this.updateControlStates();\n }\n\n /**\n * Update control button states.\n */\n updateControlStates(): void {\n if (!this.elements.controls) return;\n\n const pinBtn = this.elements.controls.querySelector('[data-action=\"pin\"]') as HTMLButtonElement;\n const lockBtn = this.elements.controls.querySelector('[data-action=\"lock\"]') as HTMLButtonElement;\n const visibilityBtn = this.elements.controls.querySelector('[data-action=\"toggle-panel\"]') as HTMLButtonElement;\n const glassBtn = this.elements.controls.querySelector('[data-action=\"toggle-glass\"]') as HTMLButtonElement;\n const isPanelVisible = this.stateManager.state.isPanelVisible;\n const isGlassVisible = this.stateManager.state.isGlassPreviewVisible;\n\n if (pinBtn) {\n pinBtn.classList.toggle('active', this.stateManager.state.isPanelPinned);\n pinBtn.title = this.stateManager.state.isPanelPinned ? \"Lock Panel\" : \"Unlock Panel\";\n pinBtn.innerHTML = this.stateManager.state.isPanelPinned ? Icons.lock : Icons.unlock;\n // Hide unlock button when panel is hidden\n pinBtn.style.display = isPanelVisible ? 'flex' : 'none';\n\n // Do not disable the pin button even if glass is hidden.\n // If the user unpins while glass is hidden, the panel will just attach to the hidden glass (and disappear).\n pinBtn.disabled = false;\n pinBtn.style.opacity = '';\n\n // Only update title if glass is hidden to warn user\n if (!isGlassVisible && !this.stateManager.state.isPanelPinned) {\n // Optional: You could add a tooltip warning here if really needed, \n // but keeping it simple is better.\n }\n }\n\n if (lockBtn) {\n // Only show pin button when panel is visible AND unlocked from glass\n const showLockBtn = isPanelVisible && this.stateManager.state.isPanelPinned;\n lockBtn.style.display = showLockBtn ? 'flex' : 'none';\n lockBtn.classList.toggle('active', this.stateManager.state.isPanelLocked);\n lockBtn.title = this.stateManager.state.isPanelLocked ? \"Unpin Panel Position\" : \"Pin Panel Position\";\n lockBtn.disabled = !this.stateManager.state.isPanelPinned;\n }\n\n if (visibilityBtn) {\n // Active means \"Panel is Visible\"\n visibilityBtn.classList.toggle('active', isPanelVisible);\n visibilityBtn.title = isPanelVisible ? \"Hide Panel\" : \"Show Panel\";\n\n // Disable hide button if glass is hidden (prevent hiding everything)\n if (!isGlassVisible) {\n visibilityBtn.disabled = true;\n visibilityBtn.style.opacity = '0.5';\n visibilityBtn.title = \"Cannot hide panel when glass preview is hidden\";\n } else {\n visibilityBtn.disabled = false;\n visibilityBtn.style.opacity = '';\n }\n }\n\n if (glassBtn) {\n glassBtn.classList.toggle('active', isGlassVisible);\n glassBtn.title = isGlassVisible ? \"Hide Glass Preview\" : \"Show Glass Preview\";\n\n // Only show glass toggle button if the inspector panel is visible\n glassBtn.style.display = isPanelVisible ? 'flex' : 'none';\n }\n }\n\n /**\n * Update controls layout based on position setting.\n * @param position \n */\n updateControlsLayout(position: string): void {\n if (!this.elements.controls) return;\n\n // Remove existing layout classes\n this.elements.controls.classList.remove('horizontal-layout', 'vertical-layout');\n\n // Add appropriate layout class\n if (['top', 'bottom'].includes(position)) {\n this.elements.controls.classList.add('horizontal-layout');\n } else {\n this.elements.controls.classList.add('vertical-layout');\n }\n }\n\n /**\n * Apply current styles to elements.\n */\n applyStyles(): void {\n if (!this.elements.panel) return;\n\n const settings = this.stateManager.state.settings;\n\n // Debug Log\n console.log(`[UIManager] applyStyles - MaxHeight: ${settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"]}`);\n\n // 1. Apply dimensions\n this.elements.panel.style.width = `${settings[\"🔍MagnifyGlass.InfoPanelWidth\"]}px`;\n // Set max-height via CSS variable so CSS :hover rules can override\n const maxHeight = settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"];\n this.elements.panel.style.setProperty('--panel-max-height', `${maxHeight}px`);\n this.elements.panel.style.height = 'auto';\n\n // 2. Apply static styles (only needed once or if overwritten, but safe to set)\n this.elements.panel.style.position = 'absolute';\n this.elements.panel.style.zIndex = '99999';\n this.elements.panel.style.transform = 'translateY(-10px)';\n this.elements.panel.style.pointerEvents = 'auto';\n this.elements.panel.style.userSelect = 'none';\n this.elements.panel.style.fontFamily = \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\";\n\n // Apply Font Size\n const fontSize = settings[\"🔍MagnifyGlass.InfoPanelFontSize\"] || 14;\n this.elements.panel.style.fontSize = `${fontSize}px`;\n\n // 3. Apply transition\n this.elements.panel.style.transition = settings[\"🔍MagnifyGlass.InfoPanelAnimations\"]\n ? 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'\n : 'none';\n\n // 4. Apply Custom Colors (CSS Variables)\n const textColor = settings[\"🔍MagnifyGlass.InfoPanelTextColor\"] as string | undefined;\n if (textColor && typeof textColor === 'string') {\n const normalizedTextColor = textColor.startsWith('#') ? textColor : `#${textColor}`;\n this.elements.panel.style.setProperty('--info-panel-text-color', normalizedTextColor);\n }\n\n const accentColor = settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"] as string | undefined;\n if (accentColor && typeof accentColor === 'string') {\n const normalizedAccentColor = accentColor.startsWith('#') ? accentColor : `#${accentColor}`;\n this.elements.panel.style.setProperty('--info-panel-accent-color', normalizedAccentColor);\n }\n\n // 5. Apply Opacity\n // Logic: If visible, use setting. If hidden, use 0.\n // We do NOT touch 'display' here to avoid hiding it if it's currently shown.\n // 'display' is managed by show() / hide() methods exclusively.\n if (this.stateManager.state.isPanelVisible) {\n const opacityPercent = Number(settings[\"🔍MagnifyGlass.InfoPanelOpacity\"]) || 100;\n this.elements.panel.style.opacity = (opacityPercent / 100).toString();\n } else {\n this.elements.panel.style.opacity = '0';\n }\n }\n\n /**\n * Show the panel.\n */\n show(): void {\n if (!this.elements.panel) return;\n\n if (this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelEnabled\"]) {\n this.elements.panel.style.display = \"block\";\n // Controls are shown by positionFloatingControls() after proper positioning\n // Apply user's opacity setting when showing (convert percentage to decimal)\n const opacityPercent = Number(this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelOpacity\"]) || 100;\n this.elements.panel.style.opacity = (opacityPercent / 100).toString();\n // Trigger reflow\n this.elements.panel.offsetHeight;\n this.elements.panel.classList.add('visible');\n this.stateManager.state.isPanelVisible = true;\n this.updateControlStates();\n }\n }\n\n /**\n * Hide the panel.\n */\n hide(): void {\n if (!this.elements.panel) return;\n\n this.elements.panel.classList.remove('visible');\n setTimeout(() => {\n if (!this.stateManager.state.isPanelVisible && this.elements.panel) {\n this.elements.panel.style.display = \"none\";\n // Do NOT hide controls when panel is hidden - they should remain visible on glass\n // if (this.elements.controls) {\n // this.elements.controls.style.display = \"none\";\n // }\n }\n }, this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAnimations\"] ? 300 : 0);\n this.stateManager.state.isPanelVisible = false;\n this.updateControlStates();\n }\n\n /**\n * Update minimized state.\n */\n updateMinimizedState(): void {\n if (!this.elements.panel || !this.elements.header) return;\n\n this.elements.panel.classList.toggle('panel-minimized', this.stateManager.state.isPanelMinimized);\n const minimizeBtn = this.elements.header.querySelector('.minimize-btn');\n if (minimizeBtn) {\n minimizeBtn.textContent = this.stateManager.state.isPanelMinimized ? '+' : '−';\n (minimizeBtn as HTMLElement).title = this.stateManager.state.isPanelMinimized ? 'Expand Panel' : 'Minimize Panel';\n }\n }\n\n /**\n * Update pinned state.\n */\n updatePinnedState(): void {\n if (!this.elements.panel) return;\n\n this.elements.panel.classList.toggle('panel-pinned', this.stateManager.state.isPanelPinned);\n this.elements.panel.classList.toggle('panel-locked', this.stateManager.state.isPanelLocked);\n this.updateControlStates();\n }\n\n /**\n * Update theme class.\n * @param newTheme \n */\n updateTheme(newTheme: string): void {\n if (this.elements.panel) {\n this.elements.panel.className = this.elements.panel.className.replace(/theme-\\w+/, `theme-${newTheme.toLowerCase()}`);\n }\n if (this.elements.controls) {\n this.elements.controls.className = this.elements.controls.className.replace(/theme-\\w+/, `theme-${newTheme.toLowerCase()}`);\n }\n }\n\n /**\n * Display information in the panel.\n * @param info \n */\n displayInfo(info: any): void {\n const sections = this.buildSections(info);\n this.renderSections(sections);\n this.updateSectionStates();\n this.updateHeaderSubtitle(info);\n }\n\n /**\n * Build section data from info object.\n * @param info \n * @returns \n */\n buildSections(info: any): any[] {\n const sections: any[] = [];\n const settings = this.stateManager.state.settings;\n\n // Inspector section\n if (settings[\"🔍MagnifyGlass.ShowInspectorTab\"] && info.cursor && info.cursor.canvas) {\n const inspectorContent = [\n { label: 'Cursor Canvas', value: `(${Math.round(info.cursor.canvas.x)}, ${Math.round(info.cursor.canvas.y)})` },\n { label: 'Canvas Scale', value: `${(info.canvas.scale * 100).toFixed(1)}%` },\n { label: 'Magnifier Zoom', value: `${info.magnifier.zoomFactor}×` }\n ];\n\n sections.push({\n id: 'inspector',\n icon: Icons.info,\n title: 'Inspector',\n content: inspectorContent\n });\n }\n\n // Media section\n if (info.media) {\n const mediaContent = [\n { label: 'Type', value: info.media.tagName },\n { label: 'Source', value: info.media.src }\n ];\n\n if (info.media.naturalSize) {\n mediaContent.push({ label: 'Natural', value: info.media.naturalSize });\n }\n\n sections.push({\n id: 'media',\n icon: Icons.camera,\n title: 'Media',\n badge: info.media.tagName,\n content: mediaContent\n });\n }\n\n // Node Details section\n if (info.hoveredNode) {\n const nodeContent = [\n { label: 'Title', value: info.hoveredNode.title }\n ];\n\n // Add execution order if available\n if (info.hoveredNode.executionOrder !== undefined) {\n nodeContent.push({ label: 'Exec Order', value: info.hoveredNode.executionOrder });\n }\n\n // Add category if available\n if (info.hoveredNode.category) {\n nodeContent.push({ label: 'Category', value: info.hoveredNode.category });\n }\n\n // Add python module path if available\n if (info.hoveredNode.pythonModule) {\n const path = info.hoveredNode.pythonModule.replace(/\\./g, '/') + '.py';\n nodeContent.push({ label: 'Path', value: path });\n }\n\n // Check if this is a complex node that shows all widgets\n const nodeType = info.hoveredNode.type ? info.hoveredNode.type.toLowerCase() : '';\n const isSaveNode = nodeType.includes('save') &&\n !nodeType.includes('checkpoint') &&\n !nodeType.includes('model') &&\n !nodeType.includes('preview');\n\n const showAllWidgets = info.hoveredNode.type && (\n nodeType.includes('ksampler') ||\n nodeType.includes('sampler') ||\n nodeType.includes('k_samplers') ||\n nodeType.includes('checkpoint') ||\n nodeType.includes('model') ||\n nodeType.includes('lora') ||\n nodeType.includes('controlnet') ||\n nodeType.includes('advanced') ||\n nodeType.includes('detailer') ||\n nodeType.includes('inpaint') ||\n nodeType.includes('upscale') ||\n nodeType.includes('clip') ||\n nodeType.includes('text') ||\n nodeType.includes('encode')\n ) && !isSaveNode;\n\n if (!showAllWidgets) {\n // Add specific extractions for simple nodes\n const checkpoint = getCheckpointInfo(info.hoveredNode);\n if (checkpoint) {\n nodeContent.push({ label: 'Model', value: checkpoint });\n }\n\n const imgInfo = getImageInfo(info.hoveredNode);\n if (imgInfo) {\n if (typeof imgInfo === 'string') {\n nodeContent.push({ label: 'Image', value: imgInfo });\n } else if (typeof imgInfo === 'object' && imgInfo !== null) {\n const imgResult = imgInfo as ImageInfoResult;\n nodeContent.push({ label: 'Image Size', value: `${imgResult.width}×${imgResult.height}` });\n if (imgResult.src) {\n nodeContent.push({ label: 'Image Source', value: imgResult.src });\n }\n }\n }\n\n const textContent = getTextBoxContent(info.hoveredNode);\n if (textContent) {\n nodeContent.push({ label: 'Text', value: textContent });\n }\n }\n\n const importantParameters = getImportantNodeParameters(info.hoveredNode);\n nodeContent.push(...importantParameters);\n\n sections.push({\n id: 'node',\n icon: Icons.box,\n title: 'Node',\n badge: info.hoveredNode.type,\n content: nodeContent\n });\n }\n\n return sections;\n }\n\n /**\n * Render sections to the panel.\n * @param sections \n */\n renderSections(sections: any[]): void {\n if (!this.elements.content) return;\n\n if (sections.length === 0) {\n this.elements.content.innerHTML = `\n \n
${Icons.mapPin}
\n
Empty canvas area
\n
\n `;\n return;\n }\n\n this.elements.content.innerHTML = sections.map(section => `\n \n \n
\n
\n ${section.content.map((item: any) => {\n const value = formatValue(item.value, item.label);\n const valueClass = getValueClass(item.value);\n const valueAttributes = getValueAttributes(item.value);\n return `\n
\n ${item.label}\n ${value}\n
`;\n }).join('')}\n
\n
\n
`).join('');\n }\n\n /**\n * Update section expansion states.\n */\n updateSectionStates(): void {\n if (!this.elements.content) return;\n\n const sections = this.elements.content.querySelectorAll('.info-section');\n sections.forEach(section => {\n const sectionId = (section as HTMLElement).dataset.section;\n if (!sectionId) return;\n\n const header = section.querySelector('.section-header');\n const content = section.querySelector('.section-content');\n\n if (header && content) {\n if (this.stateManager.state.expandedSections.has(sectionId)) {\n header.classList.add('expanded');\n content.classList.add('expanded');\n } else {\n header.classList.remove('expanded');\n content.classList.remove('expanded');\n }\n }\n });\n }\n\n /**\n * Update header subtitle.\n * @param info \n */\n updateHeaderSubtitle(info: any): void {\n if (!this.elements.header) return;\n\n const subtitleElement = this.elements.header.querySelector('.header-subtitle') as HTMLElement;\n if (subtitleElement) {\n const accentColor = String(this.stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"] || '');\n if (info.hoveredNode) {\n subtitleElement.textContent = `Analyzing: ${info.hoveredNode.title} `;\n subtitleElement.style.color = accentColor;\n } else if (info.media) {\n subtitleElement.textContent = `Media: ${info.media.tagName} `;\n subtitleElement.style.color = accentColor;\n } else if (info.connection) {\n subtitleElement.textContent = `Connection: ${info.connection.type} `;\n subtitleElement.style.color = accentColor;\n } else {\n subtitleElement.textContent = 'Real-time analysis';\n subtitleElement.style.color = '';\n }\n }\n }\n\n /**\n * Inject CSS styles by loading external stylesheet.\n */\n injectStyles(): void {\n if (!document.getElementById('magnify-info-panel-styles-v2')) {\n const link = document.createElement('link');\n link.id = 'magnify-info-panel-styles-v2';\n link.rel = 'stylesheet';\n link.type = 'text/css';\n link.href = 'extensions/comfyui-magnifyglass/info-panel.css';\n document.head.appendChild(link);\n }\n }\n\n cleanup(): void {\n if (this.elements.panel && this.elements.panel.parentNode) {\n this.elements.panel.parentNode.removeChild(this.elements.panel);\n }\n if (this.elements.controls && this.elements.controls.parentNode) {\n this.elements.controls.parentNode.removeChild(this.elements.controls);\n }\n }\n}\n"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/web/shared/settings/defaults.js b/web/shared/settings/defaults.js
index aa3b036..ad8824b 100644
--- a/web/shared/settings/defaults.js
+++ b/web/shared/settings/defaults.js
@@ -31,7 +31,8 @@ const DEFAULT_PANEL_SETTINGS = {
"🔍MagnifyGlass.ShowHoveringControls": true,
"🔍MagnifyGlass.ControlsPosition": "left",
"🔍MagnifyGlass.InfoPanelTextColor": "#6b7280",
- "🔍MagnifyGlass.InfoPanelAccentColor": "#3b82f6"
+ "🔍MagnifyGlass.InfoPanelAccentColor": "#3b82f6",
+ "🔍MagnifyGlass.InfoPanelFontSize": 14
};
export {
DEFAULT_GLASS_SETTINGS,
diff --git a/web/shared/settings/defaults.js.map b/web/shared/settings/defaults.js.map
index 8ae134c..b8ffd5a 100644
--- a/web/shared/settings/defaults.js.map
+++ b/web/shared/settings/defaults.js.map
@@ -1 +1 @@
-{"version":3,"file":"defaults.js","sources":["../../../src/shared/settings/defaults.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Default Settings Values\n * \n * Default values for all magnify glass and info panel settings.\n */\n\nimport {\n DEFAULT_GLASS_SIZE,\n DEFAULT_ZOOM_FACTOR,\n DEFAULT_BORDER_WIDTH,\n DEFAULT_BORDER_COLOR,\n DEFAULT_OFFSET_STEP,\n DEFAULT_PANEL_WIDTH,\n DEFAULT_PANEL_MAX_HEIGHT,\n DEFAULT_PANEL_OPACITY\n} from '../constants';\nimport type { GlassSettings, PanelSettings } from './types';\n\n/**\n * Default settings for the magnify glass component.\n */\nexport const DEFAULT_GLASS_SETTINGS: GlassSettings = {\n \"🔍MagnifyGlass.ZoomFactor\": DEFAULT_ZOOM_FACTOR,\n \"🔍MagnifyGlass.GlassSize\": DEFAULT_GLASS_SIZE,\n \"🔍MagnifyGlass.BorderColor\": DEFAULT_BORDER_COLOR,\n \"🔍MagnifyGlass.BorderWidth\": DEFAULT_BORDER_WIDTH,\n \"🔍MagnifyGlass.ActivationKey\": \"x\",\n \"🔍MagnifyGlass.AltRequired\": false,\n \"🔍MagnifyGlass.FollowCursor\": false,\n \"🔍MagnifyGlass.DebugMode\": false,\n \"🔍MagnifyGlass.OffsetStep\": DEFAULT_OFFSET_STEP,\n \"🔍MagnifyGlass.GlassPosition\": \"Top-Right\",\n \"🔍MagnifyGlass.ResetKey\": \"o\",\n \"🔍MagnifyGlass.GlassShape\": \"Rounded Square\",\n \"🔍MagnifyGlass.BorderEnabled\": true,\n \"🔍MagnifyGlass.TextureFiltering\": \"Linear\",\n \"🔍MagnifyGlass.AlwaysActiveMode\": true,\n \"🔍MagnifyGlass.ToggleFollowCursorKey\": \"h\",\n};\n\n/**\n * Default settings for the info panel component.\n */\nexport const DEFAULT_PANEL_SETTINGS: PanelSettings = {\n \"🔍MagnifyGlass.InfoPanelEnabled\": true,\n \"🔍MagnifyGlass.InfoPanelPosition\": \"Bottom\",\n \"🔍MagnifyGlass.InfoPanelWidth\": DEFAULT_PANEL_WIDTH,\n \"🔍MagnifyGlass.InfoPanelOpacity\": DEFAULT_PANEL_OPACITY,\n \"🔍MagnifyGlass.InfoPanelMaxHeight\": DEFAULT_PANEL_MAX_HEIGHT,\n \"🔍MagnifyGlass.InfoPanelAnimations\": false,\n \"🔍MagnifyGlass.ShowInspectorTab\": false,\n \"🔍MagnifyGlass.ToggleHotkey\": \"i\",\n \"🔍MagnifyGlass.GlassPreviewToggleHotkey\": \"g\",\n \"🔍MagnifyGlass.PinPanelHotkey\": \"u\",\n \"🔍MagnifyGlass.ShowHoveringControls\": true,\n \"🔍MagnifyGlass.ControlsPosition\": \"left\",\n \"🔍MagnifyGlass.InfoPanelTextColor\": \"#6b7280\",\n \"🔍MagnifyGlass.InfoPanelAccentColor\": \"#3b82f6\",\n};\n"],"names":[],"mappings":";AAqBO,MAAM,yBAAwC;AAAA,EACjD,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA,EAC5B,8BAA8B;AAAA,EAC9B,8BAA8B;AAAA,EAC9B,gCAAgC;AAAA,EAChC,8BAA8B;AAAA,EAC9B,+BAA+B;AAAA,EAC/B,4BAA4B;AAAA,EAC5B,6BAA6B;AAAA,EAC7B,gCAAgC;AAAA,EAChC,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,gCAAgC;AAAA,EAChC,mCAAmC;AAAA,EACnC,mCAAmC;AAAA,EACnC,wCAAwC;AAC5C;AAKO,MAAM,yBAAwC;AAAA,EACjD,mCAAmC;AAAA,EACnC,oCAAoC;AAAA,EACpC,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,qCAAqC;AAAA,EACrC,sCAAsC;AAAA,EACtC,mCAAmC;AAAA,EACnC,+BAA+B;AAAA,EAC/B,2CAA2C;AAAA,EAC3C,iCAAiC;AAAA,EACjC,uCAAuC;AAAA,EACvC,mCAAmC;AAAA,EACnC,qCAAqC;AAAA,EACrC,uCAAuC;AAC3C;"}
\ No newline at end of file
+{"version":3,"file":"defaults.js","sources":["../../../src/shared/settings/defaults.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Default Settings Values\n * \n * Default values for all magnify glass and info panel settings.\n */\n\nimport {\n DEFAULT_GLASS_SIZE,\n DEFAULT_ZOOM_FACTOR,\n DEFAULT_BORDER_WIDTH,\n DEFAULT_BORDER_COLOR,\n DEFAULT_OFFSET_STEP,\n DEFAULT_PANEL_WIDTH,\n DEFAULT_PANEL_MAX_HEIGHT,\n DEFAULT_PANEL_OPACITY\n} from '../constants';\nimport type { GlassSettings, PanelSettings } from './types';\n\n/**\n * Default settings for the magnify glass component.\n */\nexport const DEFAULT_GLASS_SETTINGS: GlassSettings = {\n \"🔍MagnifyGlass.ZoomFactor\": DEFAULT_ZOOM_FACTOR,\n \"🔍MagnifyGlass.GlassSize\": DEFAULT_GLASS_SIZE,\n \"🔍MagnifyGlass.BorderColor\": DEFAULT_BORDER_COLOR,\n \"🔍MagnifyGlass.BorderWidth\": DEFAULT_BORDER_WIDTH,\n \"🔍MagnifyGlass.ActivationKey\": \"x\",\n \"🔍MagnifyGlass.AltRequired\": false,\n \"🔍MagnifyGlass.FollowCursor\": false,\n \"🔍MagnifyGlass.DebugMode\": false,\n \"🔍MagnifyGlass.OffsetStep\": DEFAULT_OFFSET_STEP,\n \"🔍MagnifyGlass.GlassPosition\": \"Top-Right\",\n \"🔍MagnifyGlass.ResetKey\": \"o\",\n \"🔍MagnifyGlass.GlassShape\": \"Rounded Square\",\n \"🔍MagnifyGlass.BorderEnabled\": true,\n \"🔍MagnifyGlass.TextureFiltering\": \"Linear\",\n \"🔍MagnifyGlass.AlwaysActiveMode\": true,\n \"🔍MagnifyGlass.ToggleFollowCursorKey\": \"h\",\n};\n\n/**\n * Default settings for the info panel component.\n */\nexport const DEFAULT_PANEL_SETTINGS: PanelSettings = {\n \"🔍MagnifyGlass.InfoPanelEnabled\": true,\n \"🔍MagnifyGlass.InfoPanelPosition\": \"Bottom\",\n \"🔍MagnifyGlass.InfoPanelWidth\": DEFAULT_PANEL_WIDTH,\n \"🔍MagnifyGlass.InfoPanelOpacity\": DEFAULT_PANEL_OPACITY,\n \"🔍MagnifyGlass.InfoPanelMaxHeight\": DEFAULT_PANEL_MAX_HEIGHT,\n \"🔍MagnifyGlass.InfoPanelAnimations\": false,\n \"🔍MagnifyGlass.ShowInspectorTab\": false,\n \"🔍MagnifyGlass.ToggleHotkey\": \"i\",\n \"🔍MagnifyGlass.GlassPreviewToggleHotkey\": \"g\",\n \"🔍MagnifyGlass.PinPanelHotkey\": \"u\",\n \"🔍MagnifyGlass.ShowHoveringControls\": true,\n \"🔍MagnifyGlass.ControlsPosition\": \"left\",\n \"🔍MagnifyGlass.InfoPanelTextColor\": \"#6b7280\",\n \"🔍MagnifyGlass.InfoPanelAccentColor\": \"#3b82f6\",\n \"🔍MagnifyGlass.InfoPanelFontSize\": 14,\n};\n"],"names":[],"mappings":";AAqBO,MAAM,yBAAwC;AAAA,EACjD,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA,EAC5B,8BAA8B;AAAA,EAC9B,8BAA8B;AAAA,EAC9B,gCAAgC;AAAA,EAChC,8BAA8B;AAAA,EAC9B,+BAA+B;AAAA,EAC/B,4BAA4B;AAAA,EAC5B,6BAA6B;AAAA,EAC7B,gCAAgC;AAAA,EAChC,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,gCAAgC;AAAA,EAChC,mCAAmC;AAAA,EACnC,mCAAmC;AAAA,EACnC,wCAAwC;AAC5C;AAKO,MAAM,yBAAwC;AAAA,EACjD,mCAAmC;AAAA,EACnC,oCAAoC;AAAA,EACpC,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,qCAAqC;AAAA,EACrC,sCAAsC;AAAA,EACtC,mCAAmC;AAAA,EACnC,+BAA+B;AAAA,EAC/B,2CAA2C;AAAA,EAC3C,iCAAiC;AAAA,EACjC,uCAAuC;AAAA,EACvC,mCAAmC;AAAA,EACnC,qCAAqC;AAAA,EACrC,uCAAuC;AAAA,EACvC,oCAAoC;AACxC;"}
\ No newline at end of file
diff --git a/web/shared/settings/panelSettings.js b/web/shared/settings/panelSettings.js
index 831bd92..539e774 100644
--- a/web/shared/settings/panelSettings.js
+++ b/web/shared/settings/panelSettings.js
@@ -89,6 +89,24 @@ function registerPanelSettings(stateManager, uiManager, positionManager) {
}
}
});
+ app.ui.settings.addSetting({
+ id: "🔍MagnifyGlass.InfoPanelFontSize",
+ name: "📊 Info Panel: Font Size (px)",
+ type: "slider",
+ defaultValue: settings["🔍MagnifyGlass.InfoPanelFontSize"],
+ min: 8,
+ max: 24,
+ step: 1,
+ tooltip: "Font size of the information panel text.",
+ onChange: (value) => {
+ if (stateManager) {
+ stateManager.state.settings["🔍MagnifyGlass.InfoPanelFontSize"] = parseInt(String(value), 10);
+ if (uiManager) {
+ uiManager.applyStyles();
+ }
+ }
+ }
+ });
app.ui.settings.addSetting({
id: "🔍MagnifyGlass.InfoPanelAnimations",
name: "📊 Info Panel: Animations",
diff --git a/web/shared/settings/panelSettings.js.map b/web/shared/settings/panelSettings.js.map
index 608069c..c92c1fb 100644
--- a/web/shared/settings/panelSettings.js.map
+++ b/web/shared/settings/panelSettings.js.map
@@ -1 +1 @@
-{"version":3,"file":"panelSettings.js","sources":["../../../src/shared/settings/panelSettings.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Panel Settings Registration\n * \n * Registers all info panel settings with ComfyUI.\n */\n\n// @ts-ignore\nimport { app } from \"/scripts/app.js\";\nimport { PANEL_POSITIONS } from '../constants';\nimport { DEFAULT_PANEL_SETTINGS } from './defaults';\n\n/**\n * Register all info panel settings with ComfyUI.\n * @param stateManager - The StateManager instance for the info panel\n * @param uiManager - The UIManager instance for the info panel\n * @param positionManager - The PositionManager instance for the info panel\n */\nexport function registerPanelSettings(stateManager: any, uiManager: any, positionManager: any): void {\n const settings = DEFAULT_PANEL_SETTINGS;\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelEnabled\",\n name: \"📊 Info Panel: Enable\",\n type: \"combo\",\n options: [{ value: true, text: \"Yes\" }, { value: false, text: \"No\" }],\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelEnabled\"],\n tooltip: \"Enable or disable the information panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelEnabled\"] = !!value;\n if (!value && uiManager) {\n uiManager.hide();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelPosition\",\n name: \"📊 Info Panel: Position\",\n type: \"combo\",\n options: PANEL_POSITIONS.map(p => ({ value: p, text: p })),\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelPosition\"],\n tooltip: \"Position of the info panel relative to the magnifying glass.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelPosition\"] = String(value);\n if (positionManager) {\n positionManager.positionPanel();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelWidth\",\n name: \"📊 Info Panel: Width (px)\",\n type: \"slider\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelWidth\"],\n min: 200,\n max: 600,\n step: 20,\n tooltip: \"Width of the information panel in pixels.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelWidth\"] = parseInt(String(value), 10);\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelOpacity\",\n name: \"📊 Info Panel: Opacity (%)\",\n type: \"slider\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelOpacity\"],\n min: 10,\n max: 100,\n step: 5,\n tooltip: \"Opacity of the information panel background.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelOpacity\"] = parseInt(String(value), 10);\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelMaxHeight\",\n name: \"📊 Info Panel: Max Height (px)\",\n type: \"slider\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"],\n min: 200,\n max: 1500,\n step: 50,\n tooltip: \"Maximum height of the information panel in pixels.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"] = parseInt(String(value), 10);\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelAnimations\",\n name: \"📊 Info Panel: Animations\",\n type: \"combo\",\n options: [{ value: true, text: \"Enabled\" }, { value: false, text: \"Disabled\" }],\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelAnimations\"],\n tooltip: \"Enable or disable animations for the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAnimations\"] = !!value;\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.ShowInspectorTab\",\n name: \"📊 Info Panel: Show Inspector Tab\",\n type: \"combo\",\n options: [{ value: true, text: \"Yes\" }, { value: false, text: \"No\" }],\n defaultValue: settings[\"🔍MagnifyGlass.ShowInspectorTab\"],\n tooltip: \"Show or hide the Inspector tab with cursor and canvas information.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.ShowInspectorTab\"] = !!value;\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.ShowHoveringControls\",\n name: \"📊 Info Panel: Show Hover Controls\",\n type: \"combo\",\n options: [{ value: true, text: \"Yes\" }, { value: false, text: \"No\" }],\n defaultValue: settings[\"🔍MagnifyGlass.ShowHoveringControls\"],\n tooltip: \"Show or hide hovering UI controls above the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.ShowHoveringControls\"] = !!value;\n if (uiManager && uiManager.elements.controls) {\n uiManager.elements.controls.style.display = value ? 'flex' : 'none';\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelTextColor\",\n name: \"🎨 Info Panel: Text Color\",\n type: \"color\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelTextColor\"],\n tooltip: \"Custom text color for the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n const strValue = String(value);\n const normalizedColor = strValue && !strValue.startsWith('#') ? `#${strValue}` : strValue;\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelTextColor\"] = normalizedColor;\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelAccentColor\",\n name: \"🎨 Info Panel: Accent Color\",\n type: \"color\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"],\n tooltip: \"Custom accent color for the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n const strValue = String(value);\n const normalizedColor = strValue && !strValue.startsWith('#') ? `#${strValue}` : strValue;\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"] = normalizedColor;\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n}\n"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"panelSettings.js","sources":["../../../src/shared/settings/panelSettings.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Panel Settings Registration\n * \n * Registers all info panel settings with ComfyUI.\n */\n\n// @ts-ignore\nimport { app } from \"/scripts/app.js\";\nimport { PANEL_POSITIONS } from '../constants';\nimport { DEFAULT_PANEL_SETTINGS } from './defaults';\n\n/**\n * Register all info panel settings with ComfyUI.\n * @param stateManager - The StateManager instance for the info panel\n * @param uiManager - The UIManager instance for the info panel\n * @param positionManager - The PositionManager instance for the info panel\n */\nexport function registerPanelSettings(stateManager: any, uiManager: any, positionManager: any): void {\n const settings = DEFAULT_PANEL_SETTINGS;\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelEnabled\",\n name: \"📊 Info Panel: Enable\",\n type: \"combo\",\n options: [{ value: true, text: \"Yes\" }, { value: false, text: \"No\" }],\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelEnabled\"],\n tooltip: \"Enable or disable the information panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelEnabled\"] = !!value;\n if (!value && uiManager) {\n uiManager.hide();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelPosition\",\n name: \"📊 Info Panel: Position\",\n type: \"combo\",\n options: PANEL_POSITIONS.map(p => ({ value: p, text: p })),\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelPosition\"],\n tooltip: \"Position of the info panel relative to the magnifying glass.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelPosition\"] = String(value);\n if (positionManager) {\n positionManager.positionPanel();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelWidth\",\n name: \"📊 Info Panel: Width (px)\",\n type: \"slider\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelWidth\"],\n min: 200,\n max: 600,\n step: 20,\n tooltip: \"Width of the information panel in pixels.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelWidth\"] = parseInt(String(value), 10);\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelOpacity\",\n name: \"📊 Info Panel: Opacity (%)\",\n type: \"slider\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelOpacity\"],\n min: 10,\n max: 100,\n step: 5,\n tooltip: \"Opacity of the information panel background.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelOpacity\"] = parseInt(String(value), 10);\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelMaxHeight\",\n name: \"📊 Info Panel: Max Height (px)\",\n type: \"slider\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"],\n min: 200,\n max: 1500,\n step: 50,\n tooltip: \"Maximum height of the information panel in pixels.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelMaxHeight\"] = parseInt(String(value), 10);\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelFontSize\",\n name: \"📊 Info Panel: Font Size (px)\",\n type: \"slider\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelFontSize\"],\n min: 8,\n max: 24,\n step: 1,\n tooltip: \"Font size of the information panel text.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelFontSize\"] = parseInt(String(value), 10);\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelAnimations\",\n name: \"📊 Info Panel: Animations\",\n type: \"combo\",\n options: [{ value: true, text: \"Enabled\" }, { value: false, text: \"Disabled\" }],\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelAnimations\"],\n tooltip: \"Enable or disable animations for the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAnimations\"] = !!value;\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.ShowInspectorTab\",\n name: \"📊 Info Panel: Show Inspector Tab\",\n type: \"combo\",\n options: [{ value: true, text: \"Yes\" }, { value: false, text: \"No\" }],\n defaultValue: settings[\"🔍MagnifyGlass.ShowInspectorTab\"],\n tooltip: \"Show or hide the Inspector tab with cursor and canvas information.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.ShowInspectorTab\"] = !!value;\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.ShowHoveringControls\",\n name: \"📊 Info Panel: Show Hover Controls\",\n type: \"combo\",\n options: [{ value: true, text: \"Yes\" }, { value: false, text: \"No\" }],\n defaultValue: settings[\"🔍MagnifyGlass.ShowHoveringControls\"],\n tooltip: \"Show or hide hovering UI controls above the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n stateManager.state.settings[\"🔍MagnifyGlass.ShowHoveringControls\"] = !!value;\n if (uiManager && uiManager.elements.controls) {\n uiManager.elements.controls.style.display = value ? 'flex' : 'none';\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelTextColor\",\n name: \"🎨 Info Panel: Text Color\",\n type: \"color\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelTextColor\"],\n tooltip: \"Custom text color for the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n const strValue = String(value);\n const normalizedColor = strValue && !strValue.startsWith('#') ? `#${strValue}` : strValue;\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelTextColor\"] = normalizedColor;\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n\n app.ui.settings.addSetting({\n id: \"🔍MagnifyGlass.InfoPanelAccentColor\",\n name: \"🎨 Info Panel: Accent Color\",\n type: \"color\",\n defaultValue: settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"],\n tooltip: \"Custom accent color for the info panel.\",\n onChange: (value: any) => {\n if (stateManager) {\n const strValue = String(value);\n const normalizedColor = strValue && !strValue.startsWith('#') ? `#${strValue}` : strValue;\n stateManager.state.settings[\"🔍MagnifyGlass.InfoPanelAccentColor\"] = normalizedColor;\n if (uiManager) {\n uiManager.applyStyles();\n }\n }\n }\n });\n}\n"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/web/sidebar/SidebarSettings.js b/web/sidebar/SidebarSettings.js
index 1dd781e..f0a39c7 100644
--- a/web/sidebar/SidebarSettings.js
+++ b/web/sidebar/SidebarSettings.js
@@ -380,6 +380,24 @@ function renderSettingsPanel(container) {
}
}
));
+ panelSection.body.appendChild(createSlider(
+ "Font Size",
+ getSettingValue("🔍MagnifyGlass.InfoPanelFontSize", 14),
+ 8,
+ 24,
+ 1,
+ "px",
+ (value) => setSettingValue("🔍MagnifyGlass.InfoPanelFontSize", value),
+ "Font size of text in the info panel",
+ (value) => {
+ var _a, _b;
+ const infoPanel = window.infoPanelManager;
+ if ((_b = (_a = infoPanel == null ? void 0 : infoPanel.stateManager) == null ? void 0 : _a.state) == null ? void 0 : _b.settings) {
+ infoPanel.stateManager.state.settings["🔍MagnifyGlass.InfoPanelFontSize"] = value;
+ infoPanel.uiManager.applyStyles();
+ }
+ }
+ ));
panelSection.body.appendChild(createSlider(
"Opacity",
getSettingValue("🔍MagnifyGlass.InfoPanelOpacity", 95),
@@ -546,6 +564,7 @@ function renderSettingsPanel(container) {
setSettingValue("🔍MagnifyGlass.InfoPanelWidth", 300);
setSettingValue("🔍MagnifyGlass.InfoPanelMaxHeight", 300);
setSettingValue("🔍MagnifyGlass.InfoPanelOpacity", 100);
+ setSettingValue("🔍MagnifyGlass.InfoPanelFontSize", 14);
setSettingValue("🔍MagnifyGlass.InfoPanelTextColor", "#6b7280");
setSettingValue("🔍MagnifyGlass.InfoPanelAccentColor", "#3b82f6");
setSettingValue("🔍MagnifyGlass.InfoPanelAnimations", false);
diff --git a/web/sidebar/SidebarSettings.js.map b/web/sidebar/SidebarSettings.js.map
index a60ddab..faec9c8 100644
--- a/web/sidebar/SidebarSettings.js.map
+++ b/web/sidebar/SidebarSettings.js.map
@@ -1 +1 @@
-{"version":3,"file":"SidebarSettings.js","sources":["../../src/sidebar/SidebarSettings.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Sidebar Settings Panel\n * \n * All settings controls for the sidebar.\n */\n\n// @ts-ignore\nimport { app } from \"/scripts/app.js\";\nimport {\n GLASS_POSITIONS,\n GLASS_SHAPES,\n ACTIVATION_KEYS,\n RESET_KEYS,\n TOGGLE_FOLLOW_KEYS,\n PANEL_POSITIONS\n} from '../shared/constants';\n\n/**\n * Icons for the settings panel\n */\nconst Icons = {\n chevronDown: ``,\n reset: ``,\n};\n\n/**\n * Create a slider control with tooltip\n */\n/**\n * Create a slider control with tooltip\n */\nfunction createSlider(\n label: string,\n value: number,\n min: number,\n max: number,\n step: number,\n unit: string,\n onChange: (value: number) => void,\n tooltip?: string,\n onInput?: (value: number) => void\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-control-row';\n if (tooltip) row.title = tooltip;\n\n const labelRow = document.createElement('div');\n labelRow.className = 'magnify-control-label-row';\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const valueEl = document.createElement('span');\n valueEl.className = 'control-value';\n valueEl.textContent = `${value}${unit}`;\n\n labelRow.appendChild(labelEl);\n labelRow.appendChild(valueEl);\n\n const slider = document.createElement('input');\n slider.type = 'range';\n slider.className = 'magnify-slider';\n slider.min = String(min);\n slider.max = String(max);\n slider.step = String(step);\n slider.value = String(value);\n\n // Prevent ComfyUI from capturing mouse events during drag\n slider.addEventListener('mousedown', (e) => e.stopPropagation());\n slider.addEventListener('touchstart', (e) => e.stopPropagation());\n slider.addEventListener('pointerdown', (e) => e.stopPropagation());\n\n slider.addEventListener('input', (e) => {\n e.stopPropagation();\n const newValue = parseFloat(slider.value);\n valueEl.textContent = `${newValue}${unit}`;\n if (onInput) onInput(newValue);\n });\n\n slider.addEventListener('change', (e) => {\n e.stopPropagation();\n const newValue = parseFloat(slider.value);\n onChange(newValue);\n });\n\n row.appendChild(labelRow);\n row.appendChild(slider);\n\n return row;\n}\n\n/**\n * Create a toggle control with tooltip\n */\nfunction createToggle(\n label: string,\n checked: boolean,\n onChange: (checked: boolean) => void,\n tooltip?: string\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-toggle-row';\n if (tooltip) row.title = tooltip;\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const toggle = document.createElement('div');\n toggle.className = `magnify-toggle${checked ? ' active' : ''}`;\n\n toggle.addEventListener('click', () => {\n const isActive = toggle.classList.toggle('active');\n onChange(isActive);\n });\n\n row.appendChild(labelEl);\n row.appendChild(toggle);\n\n return row;\n}\n\n/**\n * Create a select dropdown control with tooltip\n */\nfunction createSelect(\n label: string,\n value: string,\n options: readonly string[] | string[],\n onChange: (value: string) => void,\n tooltip?: string,\n onInput?: (value: string) => void\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-control-row';\n if (tooltip) row.title = tooltip;\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const select = document.createElement('select');\n select.className = 'magnify-select';\n\n options.forEach(opt => {\n const option = document.createElement('option');\n option.value = opt;\n option.textContent = opt;\n if (opt === value) option.selected = true;\n select.appendChild(option);\n });\n\n select.addEventListener('change', () => {\n // Call onInput first for live preview\n if (onInput) {\n onInput(select.value);\n }\n // Then persist the setting\n onChange(select.value);\n });\n\n row.appendChild(labelEl);\n row.appendChild(select);\n\n return row;\n}\n\n/**\n * Create a color picker control with tooltip\n */\n/**\n * Create a color picker control with tooltip\n */\nfunction createColorPicker(\n label: string,\n value: string,\n onChange: (value: string) => void,\n tooltip?: string,\n onInput?: (value: string) => void\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-control-row magnify-color-row';\n if (tooltip) row.title = tooltip;\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const colorWrapper = document.createElement('div');\n colorWrapper.className = 'magnify-color-wrapper';\n\n const colorInput = document.createElement('input');\n colorInput.type = 'color';\n colorInput.className = 'magnify-color-input';\n colorInput.value = value;\n\n const colorPreview = document.createElement('span');\n colorPreview.className = 'magnify-color-preview';\n colorPreview.textContent = value;\n\n colorInput.addEventListener('input', () => {\n colorPreview.textContent = colorInput.value;\n if (onInput) onInput(colorInput.value);\n });\n\n colorInput.addEventListener('change', () => {\n onChange(colorInput.value);\n });\n\n colorWrapper.appendChild(colorInput);\n colorWrapper.appendChild(colorPreview);\n\n row.appendChild(labelEl);\n row.appendChild(colorWrapper);\n\n return row;\n}\n\n/**\n * Get current MagnifyGlass settings from app.ui.settings\n */\nfunction getSettingValue(id: string, defaultValue: any): any {\n try {\n const value = app.ui.settings.getSettingValue(id);\n return value !== undefined ? value : defaultValue;\n } catch {\n return defaultValue;\n }\n}\n\n/**\n * Set a MagnifyGlass setting via app.ui.settings\n */\nfunction setSettingValue(id: string, value: any): void {\n try {\n app.ui.settings.setSettingValue(id, value);\n } catch (e) {\n console.warn(`Failed to set setting ${id}:`, e);\n }\n}\n\n/** Storage key for section states */\nconst SECTION_STATE_KEY = 'magnifyglass-sidebar-sections';\n\n/**\n * Get saved section states from localStorage\n */\nfunction getSectionStates(): Record {\n try {\n const saved = localStorage.getItem(SECTION_STATE_KEY);\n return saved ? JSON.parse(saved) : {};\n } catch {\n return {};\n }\n}\n\n/**\n * Save section state to localStorage\n */\nfunction saveSectionState(title: string, collapsed: boolean): void {\n try {\n const states = getSectionStates();\n states[title] = collapsed;\n localStorage.setItem(SECTION_STATE_KEY, JSON.stringify(states));\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Create a collapsible section with persistent state\n */\nfunction createSection(title: string, defaultCollapsed: boolean = false): { section: HTMLElement; body: HTMLElement } {\n const section = document.createElement('div');\n section.className = 'magnify-sidebar-section';\n\n // Check if we have a saved state for this section\n const savedStates = getSectionStates();\n const collapsed = savedStates[title] !== undefined ? savedStates[title] : defaultCollapsed;\n\n const header = document.createElement('div');\n header.className = `magnify-sidebar-section-header${collapsed ? ' collapsed' : ''}`;\n header.innerHTML = `${Icons.chevronDown}${title}`;\n\n const body = document.createElement('div');\n body.className = `magnify-sidebar-section-body${collapsed ? ' collapsed' : ''}`;\n\n header.addEventListener('click', () => {\n const isCollapsed = header.classList.toggle('collapsed');\n body.classList.toggle('collapsed');\n // Save the new state\n saveSectionState(title, isCollapsed);\n });\n\n section.appendChild(header);\n section.appendChild(body);\n\n return { section, body };\n}\n\n/**\n * Render the settings panel into the container\n */\nexport function renderSettingsPanel(container: HTMLElement): void {\n // Get current hotkey values for tooltips\n const activationKey = getSettingValue('🔍MagnifyGlass.ActivationKey', 'x').toUpperCase();\n const resetKey = getSettingValue('🔍MagnifyGlass.ResetKey', 'o').toUpperCase();\n const toggleFollowKey = getSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', 'h').toUpperCase();\n\n // ===== Glass Settings Section =====\n const glassSection = createSection('Glass Settings');\n\n glassSection.body.appendChild(createSlider('Zoom Factor',\n getSettingValue('🔍MagnifyGlass.ZoomFactor', 300), 100, 1000, 25, '%',\n (value) => setSettingValue('🔍MagnifyGlass.ZoomFactor', value),\n 'Magnification level of the glass (100-1000%)',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.zoomFactor = value / 100;\n if (mg.state.active) mg.updateMagnifiedView();\n }\n }\n ));\n\n glassSection.body.appendChild(createSlider('Glass Size',\n getSettingValue('🔍MagnifyGlass.GlassSize', 250), 50, 500, 10, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.GlassSize', value),\n 'Size of the magnifying glass in pixels',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.glassSize = value;\n mg.applyUiChanges();\n if (mg.state.active) mg.updateMagnifiedView();\n }\n }\n ));\n\n glassSection.body.appendChild(createSelect('Shape',\n getSettingValue('🔍MagnifyGlass.GlassShape', 'Rounded Square'), GLASS_SHAPES,\n (value) => setSettingValue('🔍MagnifyGlass.GlassShape', value),\n 'Shape of the magnifying glass'\n ));\n\n glassSection.body.appendChild(createSelect('Position',\n getSettingValue('🔍MagnifyGlass.GlassPosition', 'Top-Right'), GLASS_POSITIONS,\n (value) => setSettingValue('🔍MagnifyGlass.GlassPosition', value),\n `Default position of the glass. Press ${resetKey} to reset.`\n ));\n\n glassSection.body.appendChild(createSelect('Filtering',\n getSettingValue('🔍MagnifyGlass.TextureFiltering', 'Linear'), ['Linear', 'Nearest'],\n (value) => setSettingValue('🔍MagnifyGlass.TextureFiltering', value),\n 'Texture filtering: Linear (smooth) or Nearest (pixelated)'\n ));\n\n glassSection.body.appendChild(createSlider('Border Width',\n getSettingValue('🔍MagnifyGlass.BorderWidth', 2), 0, 10, 0.5, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.BorderWidth', value),\n 'Width of the glass border in pixels',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.borderWidth = value;\n mg.applyUiChanges();\n }\n }\n ));\n\n glassSection.body.appendChild(createColorPicker('Border Color',\n getSettingValue('🔍MagnifyGlass.BorderColor', '#ffffff'),\n (value) => setSettingValue('🔍MagnifyGlass.BorderColor', value),\n 'Color of the glass border',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.borderColor = value;\n mg.applyUiChanges();\n }\n }\n ));\n\n glassSection.body.appendChild(createToggle('Show Border',\n getSettingValue('🔍MagnifyGlass.BorderEnabled', true),\n (checked) => setSettingValue('🔍MagnifyGlass.BorderEnabled', checked),\n 'Show or hide the glass border'\n ));\n\n glassSection.body.appendChild(createToggle('Follow Cursor',\n getSettingValue('🔍MagnifyGlass.FollowCursor', false),\n (checked) => setSettingValue('🔍MagnifyGlass.FollowCursor', checked),\n `Glass follows the cursor. Hotkey: ${toggleFollowKey}`\n ));\n\n glassSection.body.appendChild(createToggle('Always Active Mode',\n getSettingValue('🔍MagnifyGlass.AlwaysActiveMode', true),\n (checked) => setSettingValue('🔍MagnifyGlass.AlwaysActiveMode', checked),\n `When enabled, glass stays visible. Toggle with ${activationKey}`\n ));\n\n container.appendChild(glassSection.section);\n\n // ===== Hotkeys Section =====\n const hotkeySection = createSection('Hotkeys', true);\n\n hotkeySection.body.appendChild(createSelect('Activation Key',\n getSettingValue('🔍MagnifyGlass.ActivationKey', 'x'), ACTIVATION_KEYS,\n (value) => setSettingValue('🔍MagnifyGlass.ActivationKey', value),\n 'Key to toggle or hold to activate the magnifying glass'\n ));\n\n hotkeySection.body.appendChild(createSelect('Reset Key',\n getSettingValue('🔍MagnifyGlass.ResetKey', 'o'), RESET_KEYS,\n (value) => setSettingValue('🔍MagnifyGlass.ResetKey', value),\n 'Key to reset glass position and disable follow cursor'\n ));\n\n hotkeySection.body.appendChild(createSelect('Toggle Follow Key',\n getSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', 'h'), TOGGLE_FOLLOW_KEYS,\n (value) => setSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', value),\n 'Key to toggle follow cursor mode'\n ));\n\n hotkeySection.body.appendChild(createToggle('Require Alt Key',\n getSettingValue('🔍MagnifyGlass.AltRequired', false),\n (checked) => setSettingValue('🔍MagnifyGlass.AltRequired', checked),\n 'Require Alt key to be held with activation key'\n ));\n\n hotkeySection.body.appendChild(createSlider('Offset Step',\n getSettingValue('🔍MagnifyGlass.OffsetStep', 10), 1, 50, 1, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.OffsetStep', value),\n 'Amount to move glass per arrow key press (pixels)'\n ));\n\n container.appendChild(hotkeySection.section);\n\n // ===== Info Panel Section =====\n const panelSection = createSection('Info Panel', true);\n\n const toggleHotkey = getSettingValue('🔍MagnifyGlass.ToggleHotkey', 'i').toUpperCase();\n const glassToggleKey = getSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', 'g').toUpperCase();\n const pinHotkeyVal = getSettingValue('🔍MagnifyGlass.PinPanelHotkey', 'u').toUpperCase();\n\n panelSection.body.appendChild(createToggle('Enable Panel',\n getSettingValue('🔍MagnifyGlass.InfoPanelEnabled', true),\n (checked) => setSettingValue('🔍MagnifyGlass.InfoPanelEnabled', checked),\n `Show info panel with node details. Toggle: ${toggleHotkey}`\n ));\n\n panelSection.body.appendChild(createSelect('Position',\n getSettingValue('🔍MagnifyGlass.InfoPanelPosition', 'Bottom'), PANEL_POSITIONS,\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelPosition', value),\n 'Position of the info panel relative to the glass'\n ));\n\n panelSection.body.appendChild(createSlider('Width',\n getSettingValue('🔍MagnifyGlass.InfoPanelWidth', 300), 200, 600, 20, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelWidth', value),\n 'Width of the info panel',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelWidth'] = value;\n infoPanel.uiManager.applyStyles();\n\n // Ensure visible and reflow if active\n if (infoPanel.magnifyGlass.state.active) {\n infoPanel.uiManager.show();\n infoPanel.positionManager.positionPanel();\n }\n }\n }\n ));\n\n panelSection.body.appendChild(createSlider('Max Height',\n getSettingValue('🔍MagnifyGlass.InfoPanelMaxHeight', 300), 200, 1500, 50, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelMaxHeight', value),\n 'Maximum height of the info panel',\n (value) => {\n console.log('[MaxHeight] Handler called with value:', value);\n const infoPanel = (window as any).infoPanelManager;\n console.log('[MaxHeight] infoPanelManager:', infoPanel ? 'found' : 'NOT FOUND');\n if (infoPanel?.stateManager?.state?.settings) {\n console.log('[MaxHeight] Updating setting and calling applyStyles');\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelMaxHeight'] = value;\n infoPanel.uiManager.applyStyles();\n\n // Ensure visible and reflow if active\n if (infoPanel.magnifyGlass.state.active) {\n console.log('[MaxHeight] Glass is active, calling show() and positionPanel()');\n infoPanel.uiManager.show();\n infoPanel.positionManager.positionPanel();\n } else {\n console.log('[MaxHeight] Glass is NOT active, skipping show()');\n }\n } else {\n console.warn('[MaxHeight] Check failed - stateManager/state/settings missing');\n }\n }\n ));\n\n panelSection.body.appendChild(createSlider('Opacity',\n getSettingValue('🔍MagnifyGlass.InfoPanelOpacity', 95), 10, 100, 5, '%',\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelOpacity', value),\n 'Background opacity of the info panel',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelOpacity'] = value;\n infoPanel.uiManager.applyStyles();\n }\n }\n ));\n\n panelSection.body.appendChild(createColorPicker('Text Color',\n getSettingValue('🔍MagnifyGlass.InfoPanelTextColor', '#6b7280'),\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelTextColor', value),\n 'Text color in the info panel',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelTextColor'] = value;\n infoPanel.uiManager.applyStyles();\n }\n }\n ));\n\n panelSection.body.appendChild(createColorPicker('Accent Color',\n getSettingValue('🔍MagnifyGlass.InfoPanelAccentColor', '#3b82f6'),\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelAccentColor', value),\n 'Accent color for highlights',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelAccentColor'] = value;\n infoPanel.uiManager.applyStyles();\n }\n }\n ));\n\n panelSection.body.appendChild(createToggle('Animations',\n getSettingValue('🔍MagnifyGlass.InfoPanelAnimations', false),\n (checked) => setSettingValue('🔍MagnifyGlass.InfoPanelAnimations', checked),\n 'Enable smooth animations for panel updates'\n ));\n\n panelSection.body.appendChild(createToggle('Hover Controls',\n getSettingValue('🔍MagnifyGlass.ShowHoveringControls', true),\n (checked) => setSettingValue('🔍MagnifyGlass.ShowHoveringControls', checked),\n 'Show floating control buttons near the panel'\n ));\n\n panelSection.body.appendChild(createSelect('Controls Position',\n getSettingValue('🔍MagnifyGlass.ControlsPosition', 'left'),\n ['top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],\n (value) => setSettingValue('🔍MagnifyGlass.ControlsPosition', value),\n 'Position of floating control buttons',\n (value) => {\n // Live update controls position\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.ControlsPosition'] = value;\n infoPanel.uiManager.updateControlsLayout(value);\n if (infoPanel.magnifyGlass.state.active) {\n infoPanel.positionManager.positionFloatingControls();\n }\n }\n }\n ));\n\n container.appendChild(panelSection.section);\n\n // ===== Panel Hotkeys Section =====\n const panelHotkeySection = createSection('Panel Hotkeys', true);\n\n panelHotkeySection.body.appendChild(createSelect('Toggle Key',\n getSettingValue('🔍MagnifyGlass.ToggleHotkey', 'i'), ['i', 'j', 'k', 'l', 'n', 'm'],\n (value) => setSettingValue('🔍MagnifyGlass.ToggleHotkey', value),\n 'Key to toggle info panel visibility'\n ));\n\n panelHotkeySection.body.appendChild(createSelect('Glass Toggle Key',\n getSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', 'g'), ['g', 'f', 'v', 'b'],\n (value) => setSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', value),\n 'Key to toggle glass preview in panel'\n ));\n\n panelHotkeySection.body.appendChild(createSelect('Pin Key',\n getSettingValue('🔍MagnifyGlass.PinPanelHotkey', 'u'), ['u', 'p', 'y', 't'],\n (value) => setSettingValue('🔍MagnifyGlass.PinPanelHotkey', value),\n 'Key to pin/unpin the info panel position'\n ));\n\n container.appendChild(panelHotkeySection.section);\n\n // ===== Debug Section =====\n const debugSection = createSection('Debug', true);\n\n debugSection.body.appendChild(createToggle('Debug Mode',\n getSettingValue('🔍MagnifyGlass.DebugMode', false),\n (checked) => setSettingValue('🔍MagnifyGlass.DebugMode', checked),\n 'Enable debug logging and visual indicators'\n ));\n\n container.appendChild(debugSection.section);\n\n // ===== Button Row =====\n const buttonRow = document.createElement('div');\n buttonRow.style.padding = '16px';\n buttonRow.style.borderTop = '1px solid var(--border-color, #333)';\n buttonRow.style.display = 'flex';\n buttonRow.style.flexDirection = 'column';\n buttonRow.style.gap = '8px';\n\n // Reset Position Button\n const resetBtn = document.createElement('button');\n resetBtn.className = 'magnify-btn';\n resetBtn.style.width = '100%';\n resetBtn.innerHTML = `${Icons.reset} Reset Position`;\n resetBtn.title = `Reset glass position and disable follow cursor. Hotkey: ${resetKey}`;\n\n resetBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (magnifyGlass && magnifyGlass.resetOffsets) {\n magnifyGlass.resetOffsets();\n // Update follow cursor toggle in UI\n const followToggles = container.querySelectorAll('.magnify-toggle-row');\n followToggles.forEach(row => {\n const label = row.querySelector('label');\n if (label && label.textContent === 'Follow Cursor') {\n const toggle = row.querySelector('.magnify-toggle');\n if (toggle) toggle.classList.remove('active');\n }\n });\n }\n });\n\n buttonRow.appendChild(resetBtn);\n\n // Reset All Settings Button\n const resetAllBtn = document.createElement('button');\n resetAllBtn.className = 'magnify-btn magnify-btn-secondary';\n resetAllBtn.style.width = '100%';\n resetAllBtn.innerHTML = `${Icons.reset} Reset All Settings`;\n resetAllBtn.title = 'Reset all settings to their default values';\n\n resetAllBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n\n // Confirm with user\n if (!confirm('Reset all MagnifyGlass settings to defaults?')) {\n return;\n }\n\n // Default glass settings\n setSettingValue('🔍MagnifyGlass.ZoomFactor', 300);\n setSettingValue('🔍MagnifyGlass.GlassSize', 300);\n setSettingValue('🔍MagnifyGlass.GlassShape', 'Rounded Square');\n setSettingValue('🔍MagnifyGlass.GlassPosition', 'Top-Right');\n setSettingValue('🔍MagnifyGlass.TextureFiltering', 'Linear');\n setSettingValue('🔍MagnifyGlass.BorderWidth', 1);\n setSettingValue('🔍MagnifyGlass.BorderColor', '#6b7280');\n setSettingValue('🔍MagnifyGlass.BorderEnabled', true);\n setSettingValue('🔍MagnifyGlass.FollowCursor', false);\n setSettingValue('🔍MagnifyGlass.AlwaysActiveMode', true);\n setSettingValue('🔍MagnifyGlass.ActivationKey', 'x');\n setSettingValue('🔍MagnifyGlass.ResetKey', 'o');\n setSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', 'h');\n setSettingValue('🔍MagnifyGlass.AltRequired', false);\n setSettingValue('🔍MagnifyGlass.OffsetStep', 5);\n setSettingValue('🔍MagnifyGlass.DebugMode', false);\n\n // Default panel settings\n setSettingValue('🔍MagnifyGlass.InfoPanelEnabled', true);\n setSettingValue('🔍MagnifyGlass.InfoPanelPosition', 'Bottom');\n setSettingValue('🔍MagnifyGlass.InfoPanelWidth', 300);\n setSettingValue('🔍MagnifyGlass.InfoPanelMaxHeight', 300);\n setSettingValue('🔍MagnifyGlass.InfoPanelOpacity', 100);\n setSettingValue('🔍MagnifyGlass.InfoPanelTextColor', '#6b7280');\n setSettingValue('🔍MagnifyGlass.InfoPanelAccentColor', '#3b82f6');\n setSettingValue('🔍MagnifyGlass.InfoPanelAnimations', false);\n setSettingValue('🔍MagnifyGlass.ShowHoveringControls', true);\n setSettingValue('🔍MagnifyGlass.ControlsPosition', 'left');\n setSettingValue('🔍MagnifyGlass.ToggleHotkey', 'i');\n setSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', 'g');\n setSettingValue('🔍MagnifyGlass.PinPanelHotkey', 'u');\n\n // Also reset position\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (magnifyGlass && magnifyGlass.resetOffsets) {\n magnifyGlass.resetOffsets();\n }\n });\n\n buttonRow.appendChild(resetAllBtn);\n container.appendChild(buttonRow);\n}\n"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"SidebarSettings.js","sources":["../../src/sidebar/SidebarSettings.ts"],"sourcesContent":["/**\n * ComfyUI MagnifyGlass - Sidebar Settings Panel\n * \n * All settings controls for the sidebar.\n */\n\n// @ts-ignore\nimport { app } from \"/scripts/app.js\";\nimport {\n GLASS_POSITIONS,\n GLASS_SHAPES,\n ACTIVATION_KEYS,\n RESET_KEYS,\n TOGGLE_FOLLOW_KEYS,\n PANEL_POSITIONS\n} from '../shared/constants';\n\n/**\n * Icons for the settings panel\n */\nconst Icons = {\n chevronDown: ``,\n reset: ``,\n};\n\n/**\n * Create a slider control with tooltip\n */\n/**\n * Create a slider control with tooltip\n */\nfunction createSlider(\n label: string,\n value: number,\n min: number,\n max: number,\n step: number,\n unit: string,\n onChange: (value: number) => void,\n tooltip?: string,\n onInput?: (value: number) => void\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-control-row';\n if (tooltip) row.title = tooltip;\n\n const labelRow = document.createElement('div');\n labelRow.className = 'magnify-control-label-row';\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const valueEl = document.createElement('span');\n valueEl.className = 'control-value';\n valueEl.textContent = `${value}${unit}`;\n\n labelRow.appendChild(labelEl);\n labelRow.appendChild(valueEl);\n\n const slider = document.createElement('input');\n slider.type = 'range';\n slider.className = 'magnify-slider';\n slider.min = String(min);\n slider.max = String(max);\n slider.step = String(step);\n slider.value = String(value);\n\n // Prevent ComfyUI from capturing mouse events during drag\n slider.addEventListener('mousedown', (e) => e.stopPropagation());\n slider.addEventListener('touchstart', (e) => e.stopPropagation());\n slider.addEventListener('pointerdown', (e) => e.stopPropagation());\n\n slider.addEventListener('input', (e) => {\n e.stopPropagation();\n const newValue = parseFloat(slider.value);\n valueEl.textContent = `${newValue}${unit}`;\n if (onInput) onInput(newValue);\n });\n\n slider.addEventListener('change', (e) => {\n e.stopPropagation();\n const newValue = parseFloat(slider.value);\n onChange(newValue);\n });\n\n row.appendChild(labelRow);\n row.appendChild(slider);\n\n return row;\n}\n\n/**\n * Create a toggle control with tooltip\n */\nfunction createToggle(\n label: string,\n checked: boolean,\n onChange: (checked: boolean) => void,\n tooltip?: string\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-toggle-row';\n if (tooltip) row.title = tooltip;\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const toggle = document.createElement('div');\n toggle.className = `magnify-toggle${checked ? ' active' : ''}`;\n\n toggle.addEventListener('click', () => {\n const isActive = toggle.classList.toggle('active');\n onChange(isActive);\n });\n\n row.appendChild(labelEl);\n row.appendChild(toggle);\n\n return row;\n}\n\n/**\n * Create a select dropdown control with tooltip\n */\nfunction createSelect(\n label: string,\n value: string,\n options: readonly string[] | string[],\n onChange: (value: string) => void,\n tooltip?: string,\n onInput?: (value: string) => void\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-control-row';\n if (tooltip) row.title = tooltip;\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const select = document.createElement('select');\n select.className = 'magnify-select';\n\n options.forEach(opt => {\n const option = document.createElement('option');\n option.value = opt;\n option.textContent = opt;\n if (opt === value) option.selected = true;\n select.appendChild(option);\n });\n\n select.addEventListener('change', () => {\n // Call onInput first for live preview\n if (onInput) {\n onInput(select.value);\n }\n // Then persist the setting\n onChange(select.value);\n });\n\n row.appendChild(labelEl);\n row.appendChild(select);\n\n return row;\n}\n\n/**\n * Create a color picker control with tooltip\n */\n/**\n * Create a color picker control with tooltip\n */\nfunction createColorPicker(\n label: string,\n value: string,\n onChange: (value: string) => void,\n tooltip?: string,\n onInput?: (value: string) => void\n): HTMLElement {\n const row = document.createElement('div');\n row.className = 'magnify-control-row magnify-color-row';\n if (tooltip) row.title = tooltip;\n\n const labelEl = document.createElement('label');\n labelEl.textContent = label;\n\n const colorWrapper = document.createElement('div');\n colorWrapper.className = 'magnify-color-wrapper';\n\n const colorInput = document.createElement('input');\n colorInput.type = 'color';\n colorInput.className = 'magnify-color-input';\n colorInput.value = value;\n\n const colorPreview = document.createElement('span');\n colorPreview.className = 'magnify-color-preview';\n colorPreview.textContent = value;\n\n colorInput.addEventListener('input', () => {\n colorPreview.textContent = colorInput.value;\n if (onInput) onInput(colorInput.value);\n });\n\n colorInput.addEventListener('change', () => {\n onChange(colorInput.value);\n });\n\n colorWrapper.appendChild(colorInput);\n colorWrapper.appendChild(colorPreview);\n\n row.appendChild(labelEl);\n row.appendChild(colorWrapper);\n\n return row;\n}\n\n/**\n * Get current MagnifyGlass settings from app.ui.settings\n */\nfunction getSettingValue(id: string, defaultValue: any): any {\n try {\n const value = app.ui.settings.getSettingValue(id);\n return value !== undefined ? value : defaultValue;\n } catch {\n return defaultValue;\n }\n}\n\n/**\n * Set a MagnifyGlass setting via app.ui.settings\n */\nfunction setSettingValue(id: string, value: any): void {\n try {\n app.ui.settings.setSettingValue(id, value);\n } catch (e) {\n console.warn(`Failed to set setting ${id}:`, e);\n }\n}\n\n/** Storage key for section states */\nconst SECTION_STATE_KEY = 'magnifyglass-sidebar-sections';\n\n/**\n * Get saved section states from localStorage\n */\nfunction getSectionStates(): Record {\n try {\n const saved = localStorage.getItem(SECTION_STATE_KEY);\n return saved ? JSON.parse(saved) : {};\n } catch {\n return {};\n }\n}\n\n/**\n * Save section state to localStorage\n */\nfunction saveSectionState(title: string, collapsed: boolean): void {\n try {\n const states = getSectionStates();\n states[title] = collapsed;\n localStorage.setItem(SECTION_STATE_KEY, JSON.stringify(states));\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Create a collapsible section with persistent state\n */\nfunction createSection(title: string, defaultCollapsed: boolean = false): { section: HTMLElement; body: HTMLElement } {\n const section = document.createElement('div');\n section.className = 'magnify-sidebar-section';\n\n // Check if we have a saved state for this section\n const savedStates = getSectionStates();\n const collapsed = savedStates[title] !== undefined ? savedStates[title] : defaultCollapsed;\n\n const header = document.createElement('div');\n header.className = `magnify-sidebar-section-header${collapsed ? ' collapsed' : ''}`;\n header.innerHTML = `${Icons.chevronDown}${title}`;\n\n const body = document.createElement('div');\n body.className = `magnify-sidebar-section-body${collapsed ? ' collapsed' : ''}`;\n\n header.addEventListener('click', () => {\n const isCollapsed = header.classList.toggle('collapsed');\n body.classList.toggle('collapsed');\n // Save the new state\n saveSectionState(title, isCollapsed);\n });\n\n section.appendChild(header);\n section.appendChild(body);\n\n return { section, body };\n}\n\n/**\n * Render the settings panel into the container\n */\nexport function renderSettingsPanel(container: HTMLElement): void {\n // Get current hotkey values for tooltips\n const activationKey = getSettingValue('🔍MagnifyGlass.ActivationKey', 'x').toUpperCase();\n const resetKey = getSettingValue('🔍MagnifyGlass.ResetKey', 'o').toUpperCase();\n const toggleFollowKey = getSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', 'h').toUpperCase();\n\n // ===== Glass Settings Section =====\n const glassSection = createSection('Glass Settings');\n\n glassSection.body.appendChild(createSlider('Zoom Factor',\n getSettingValue('🔍MagnifyGlass.ZoomFactor', 300), 100, 1000, 25, '%',\n (value) => setSettingValue('🔍MagnifyGlass.ZoomFactor', value),\n 'Magnification level of the glass (100-1000%)',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.zoomFactor = value / 100;\n if (mg.state.active) mg.updateMagnifiedView();\n }\n }\n ));\n\n glassSection.body.appendChild(createSlider('Glass Size',\n getSettingValue('🔍MagnifyGlass.GlassSize', 250), 50, 500, 10, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.GlassSize', value),\n 'Size of the magnifying glass in pixels',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.glassSize = value;\n mg.applyUiChanges();\n if (mg.state.active) mg.updateMagnifiedView();\n }\n }\n ));\n\n glassSection.body.appendChild(createSelect('Shape',\n getSettingValue('🔍MagnifyGlass.GlassShape', 'Rounded Square'), GLASS_SHAPES,\n (value) => setSettingValue('🔍MagnifyGlass.GlassShape', value),\n 'Shape of the magnifying glass'\n ));\n\n glassSection.body.appendChild(createSelect('Position',\n getSettingValue('🔍MagnifyGlass.GlassPosition', 'Top-Right'), GLASS_POSITIONS,\n (value) => setSettingValue('🔍MagnifyGlass.GlassPosition', value),\n `Default position of the glass. Press ${resetKey} to reset.`\n ));\n\n glassSection.body.appendChild(createSelect('Filtering',\n getSettingValue('🔍MagnifyGlass.TextureFiltering', 'Linear'), ['Linear', 'Nearest'],\n (value) => setSettingValue('🔍MagnifyGlass.TextureFiltering', value),\n 'Texture filtering: Linear (smooth) or Nearest (pixelated)'\n ));\n\n glassSection.body.appendChild(createSlider('Border Width',\n getSettingValue('🔍MagnifyGlass.BorderWidth', 2), 0, 10, 0.5, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.BorderWidth', value),\n 'Width of the glass border in pixels',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.borderWidth = value;\n mg.applyUiChanges();\n }\n }\n ));\n\n glassSection.body.appendChild(createColorPicker('Border Color',\n getSettingValue('🔍MagnifyGlass.BorderColor', '#ffffff'),\n (value) => setSettingValue('🔍MagnifyGlass.BorderColor', value),\n 'Color of the glass border',\n (value) => {\n const mg = (window as any).comfyUIMagnifyGlass;\n if (mg?.config) {\n mg.config.borderColor = value;\n mg.applyUiChanges();\n }\n }\n ));\n\n glassSection.body.appendChild(createToggle('Show Border',\n getSettingValue('🔍MagnifyGlass.BorderEnabled', true),\n (checked) => setSettingValue('🔍MagnifyGlass.BorderEnabled', checked),\n 'Show or hide the glass border'\n ));\n\n glassSection.body.appendChild(createToggle('Follow Cursor',\n getSettingValue('🔍MagnifyGlass.FollowCursor', false),\n (checked) => setSettingValue('🔍MagnifyGlass.FollowCursor', checked),\n `Glass follows the cursor. Hotkey: ${toggleFollowKey}`\n ));\n\n glassSection.body.appendChild(createToggle('Always Active Mode',\n getSettingValue('🔍MagnifyGlass.AlwaysActiveMode', true),\n (checked) => setSettingValue('🔍MagnifyGlass.AlwaysActiveMode', checked),\n `When enabled, glass stays visible. Toggle with ${activationKey}`\n ));\n\n container.appendChild(glassSection.section);\n\n // ===== Hotkeys Section =====\n const hotkeySection = createSection('Hotkeys', true);\n\n hotkeySection.body.appendChild(createSelect('Activation Key',\n getSettingValue('🔍MagnifyGlass.ActivationKey', 'x'), ACTIVATION_KEYS,\n (value) => setSettingValue('🔍MagnifyGlass.ActivationKey', value),\n 'Key to toggle or hold to activate the magnifying glass'\n ));\n\n hotkeySection.body.appendChild(createSelect('Reset Key',\n getSettingValue('🔍MagnifyGlass.ResetKey', 'o'), RESET_KEYS,\n (value) => setSettingValue('🔍MagnifyGlass.ResetKey', value),\n 'Key to reset glass position and disable follow cursor'\n ));\n\n hotkeySection.body.appendChild(createSelect('Toggle Follow Key',\n getSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', 'h'), TOGGLE_FOLLOW_KEYS,\n (value) => setSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', value),\n 'Key to toggle follow cursor mode'\n ));\n\n hotkeySection.body.appendChild(createToggle('Require Alt Key',\n getSettingValue('🔍MagnifyGlass.AltRequired', false),\n (checked) => setSettingValue('🔍MagnifyGlass.AltRequired', checked),\n 'Require Alt key to be held with activation key'\n ));\n\n hotkeySection.body.appendChild(createSlider('Offset Step',\n getSettingValue('🔍MagnifyGlass.OffsetStep', 10), 1, 50, 1, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.OffsetStep', value),\n 'Amount to move glass per arrow key press (pixels)'\n ));\n\n container.appendChild(hotkeySection.section);\n\n // ===== Info Panel Section =====\n const panelSection = createSection('Info Panel', true);\n\n const toggleHotkey = getSettingValue('🔍MagnifyGlass.ToggleHotkey', 'i').toUpperCase();\n const glassToggleKey = getSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', 'g').toUpperCase();\n const pinHotkeyVal = getSettingValue('🔍MagnifyGlass.PinPanelHotkey', 'u').toUpperCase();\n\n panelSection.body.appendChild(createToggle('Enable Panel',\n getSettingValue('🔍MagnifyGlass.InfoPanelEnabled', true),\n (checked) => setSettingValue('🔍MagnifyGlass.InfoPanelEnabled', checked),\n `Show info panel with node details. Toggle: ${toggleHotkey}`\n ));\n\n panelSection.body.appendChild(createSelect('Position',\n getSettingValue('🔍MagnifyGlass.InfoPanelPosition', 'Bottom'), PANEL_POSITIONS,\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelPosition', value),\n 'Position of the info panel relative to the glass'\n ));\n\n panelSection.body.appendChild(createSlider('Width',\n getSettingValue('🔍MagnifyGlass.InfoPanelWidth', 300), 200, 600, 20, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelWidth', value),\n 'Width of the info panel',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelWidth'] = value;\n infoPanel.uiManager.applyStyles();\n\n // Ensure visible and reflow if active\n if (infoPanel.magnifyGlass.state.active) {\n infoPanel.uiManager.show();\n infoPanel.positionManager.positionPanel();\n }\n }\n }\n ));\n\n panelSection.body.appendChild(createSlider('Max Height',\n getSettingValue('🔍MagnifyGlass.InfoPanelMaxHeight', 300), 200, 1500, 50, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelMaxHeight', value),\n 'Maximum height of the info panel',\n (value) => {\n console.log('[MaxHeight] Handler called with value:', value);\n const infoPanel = (window as any).infoPanelManager;\n console.log('[MaxHeight] infoPanelManager:', infoPanel ? 'found' : 'NOT FOUND');\n if (infoPanel?.stateManager?.state?.settings) {\n console.log('[MaxHeight] Updating setting and calling applyStyles');\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelMaxHeight'] = value;\n infoPanel.uiManager.applyStyles();\n\n // Ensure visible and reflow if active\n if (infoPanel.magnifyGlass.state.active) {\n console.log('[MaxHeight] Glass is active, calling show() and positionPanel()');\n infoPanel.uiManager.show();\n infoPanel.positionManager.positionPanel();\n } else {\n console.log('[MaxHeight] Glass is NOT active, skipping show()');\n }\n } else {\n console.warn('[MaxHeight] Check failed - stateManager/state/settings missing');\n }\n }\n ));\n\n panelSection.body.appendChild(createSlider('Font Size',\n getSettingValue('🔍MagnifyGlass.InfoPanelFontSize', 14), 8, 24, 1, 'px',\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelFontSize', value),\n 'Font size of text in the info panel',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelFontSize'] = value;\n infoPanel.uiManager.applyStyles();\n }\n }\n ));\n\n panelSection.body.appendChild(createSlider('Opacity',\n getSettingValue('🔍MagnifyGlass.InfoPanelOpacity', 95), 10, 100, 5, '%',\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelOpacity', value),\n 'Background opacity of the info panel',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelOpacity'] = value;\n infoPanel.uiManager.applyStyles();\n }\n }\n ));\n\n panelSection.body.appendChild(createColorPicker('Text Color',\n getSettingValue('🔍MagnifyGlass.InfoPanelTextColor', '#6b7280'),\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelTextColor', value),\n 'Text color in the info panel',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelTextColor'] = value;\n infoPanel.uiManager.applyStyles();\n }\n }\n ));\n\n panelSection.body.appendChild(createColorPicker('Accent Color',\n getSettingValue('🔍MagnifyGlass.InfoPanelAccentColor', '#3b82f6'),\n (value) => setSettingValue('🔍MagnifyGlass.InfoPanelAccentColor', value),\n 'Accent color for highlights',\n (value) => {\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.InfoPanelAccentColor'] = value;\n infoPanel.uiManager.applyStyles();\n }\n }\n ));\n\n panelSection.body.appendChild(createToggle('Animations',\n getSettingValue('🔍MagnifyGlass.InfoPanelAnimations', false),\n (checked) => setSettingValue('🔍MagnifyGlass.InfoPanelAnimations', checked),\n 'Enable smooth animations for panel updates'\n ));\n\n panelSection.body.appendChild(createToggle('Hover Controls',\n getSettingValue('🔍MagnifyGlass.ShowHoveringControls', true),\n (checked) => setSettingValue('🔍MagnifyGlass.ShowHoveringControls', checked),\n 'Show floating control buttons near the panel'\n ));\n\n panelSection.body.appendChild(createSelect('Controls Position',\n getSettingValue('🔍MagnifyGlass.ControlsPosition', 'left'),\n ['top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],\n (value) => setSettingValue('🔍MagnifyGlass.ControlsPosition', value),\n 'Position of floating control buttons',\n (value) => {\n // Live update controls position\n const infoPanel = (window as any).infoPanelManager;\n if (infoPanel?.stateManager?.state?.settings) {\n infoPanel.stateManager.state.settings['🔍MagnifyGlass.ControlsPosition'] = value;\n infoPanel.uiManager.updateControlsLayout(value);\n if (infoPanel.magnifyGlass.state.active) {\n infoPanel.positionManager.positionFloatingControls();\n }\n }\n }\n ));\n\n container.appendChild(panelSection.section);\n\n // ===== Panel Hotkeys Section =====\n const panelHotkeySection = createSection('Panel Hotkeys', true);\n\n panelHotkeySection.body.appendChild(createSelect('Toggle Key',\n getSettingValue('🔍MagnifyGlass.ToggleHotkey', 'i'), ['i', 'j', 'k', 'l', 'n', 'm'],\n (value) => setSettingValue('🔍MagnifyGlass.ToggleHotkey', value),\n 'Key to toggle info panel visibility'\n ));\n\n panelHotkeySection.body.appendChild(createSelect('Glass Toggle Key',\n getSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', 'g'), ['g', 'f', 'v', 'b'],\n (value) => setSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', value),\n 'Key to toggle glass preview in panel'\n ));\n\n panelHotkeySection.body.appendChild(createSelect('Pin Key',\n getSettingValue('🔍MagnifyGlass.PinPanelHotkey', 'u'), ['u', 'p', 'y', 't'],\n (value) => setSettingValue('🔍MagnifyGlass.PinPanelHotkey', value),\n 'Key to pin/unpin the info panel position'\n ));\n\n container.appendChild(panelHotkeySection.section);\n\n // ===== Debug Section =====\n const debugSection = createSection('Debug', true);\n\n debugSection.body.appendChild(createToggle('Debug Mode',\n getSettingValue('🔍MagnifyGlass.DebugMode', false),\n (checked) => setSettingValue('🔍MagnifyGlass.DebugMode', checked),\n 'Enable debug logging and visual indicators'\n ));\n\n container.appendChild(debugSection.section);\n\n // ===== Button Row =====\n const buttonRow = document.createElement('div');\n buttonRow.style.padding = '16px';\n buttonRow.style.borderTop = '1px solid var(--border-color, #333)';\n buttonRow.style.display = 'flex';\n buttonRow.style.flexDirection = 'column';\n buttonRow.style.gap = '8px';\n\n // Reset Position Button\n const resetBtn = document.createElement('button');\n resetBtn.className = 'magnify-btn';\n resetBtn.style.width = '100%';\n resetBtn.innerHTML = `${Icons.reset} Reset Position`;\n resetBtn.title = `Reset glass position and disable follow cursor. Hotkey: ${resetKey}`;\n\n resetBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (magnifyGlass && magnifyGlass.resetOffsets) {\n magnifyGlass.resetOffsets();\n // Update follow cursor toggle in UI\n const followToggles = container.querySelectorAll('.magnify-toggle-row');\n followToggles.forEach(row => {\n const label = row.querySelector('label');\n if (label && label.textContent === 'Follow Cursor') {\n const toggle = row.querySelector('.magnify-toggle');\n if (toggle) toggle.classList.remove('active');\n }\n });\n }\n });\n\n buttonRow.appendChild(resetBtn);\n\n // Reset All Settings Button\n const resetAllBtn = document.createElement('button');\n resetAllBtn.className = 'magnify-btn magnify-btn-secondary';\n resetAllBtn.style.width = '100%';\n resetAllBtn.innerHTML = `${Icons.reset} Reset All Settings`;\n resetAllBtn.title = 'Reset all settings to their default values';\n\n resetAllBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n\n // Confirm with user\n if (!confirm('Reset all MagnifyGlass settings to defaults?')) {\n return;\n }\n\n // Default glass settings\n setSettingValue('🔍MagnifyGlass.ZoomFactor', 300);\n setSettingValue('🔍MagnifyGlass.GlassSize', 300);\n setSettingValue('🔍MagnifyGlass.GlassShape', 'Rounded Square');\n setSettingValue('🔍MagnifyGlass.GlassPosition', 'Top-Right');\n setSettingValue('🔍MagnifyGlass.TextureFiltering', 'Linear');\n setSettingValue('🔍MagnifyGlass.BorderWidth', 1);\n setSettingValue('🔍MagnifyGlass.BorderColor', '#6b7280');\n setSettingValue('🔍MagnifyGlass.BorderEnabled', true);\n setSettingValue('🔍MagnifyGlass.FollowCursor', false);\n setSettingValue('🔍MagnifyGlass.AlwaysActiveMode', true);\n setSettingValue('🔍MagnifyGlass.ActivationKey', 'x');\n setSettingValue('🔍MagnifyGlass.ResetKey', 'o');\n setSettingValue('🔍MagnifyGlass.ToggleFollowCursorKey', 'h');\n setSettingValue('🔍MagnifyGlass.AltRequired', false);\n setSettingValue('🔍MagnifyGlass.OffsetStep', 5);\n setSettingValue('🔍MagnifyGlass.DebugMode', false);\n\n // Default panel settings\n setSettingValue('🔍MagnifyGlass.InfoPanelEnabled', true);\n setSettingValue('🔍MagnifyGlass.InfoPanelPosition', 'Bottom');\n setSettingValue('🔍MagnifyGlass.InfoPanelWidth', 300);\n setSettingValue('🔍MagnifyGlass.InfoPanelMaxHeight', 300);\n setSettingValue('🔍MagnifyGlass.InfoPanelOpacity', 100);\n setSettingValue('🔍MagnifyGlass.InfoPanelFontSize', 14);\n setSettingValue('🔍MagnifyGlass.InfoPanelTextColor', '#6b7280');\n setSettingValue('🔍MagnifyGlass.InfoPanelAccentColor', '#3b82f6');\n setSettingValue('🔍MagnifyGlass.InfoPanelAnimations', false);\n setSettingValue('🔍MagnifyGlass.ShowHoveringControls', true);\n setSettingValue('🔍MagnifyGlass.ControlsPosition', 'left');\n setSettingValue('🔍MagnifyGlass.ToggleHotkey', 'i');\n setSettingValue('🔍MagnifyGlass.GlassPreviewToggleHotkey', 'g');\n setSettingValue('🔍MagnifyGlass.PinPanelHotkey', 'u');\n\n // Also reset position\n const magnifyGlass = window.comfyUIMagnifyGlass;\n if (magnifyGlass && magnifyGlass.resetOffsets) {\n magnifyGlass.resetOffsets();\n }\n });\n\n buttonRow.appendChild(resetAllBtn);\n container.appendChild(buttonRow);\n}\n"],"names":[],"mappings":"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"}
\ No newline at end of file