diff --git a/js/CanvasView.js b/js/CanvasView.js index d532fa0..29e939b 100644 --- a/js/CanvasView.js +++ b/js/CanvasView.js @@ -393,37 +393,66 @@ async function createCanvasWidget(node, widget, app) { ]), $el("div.painter-separator"), $el("div.painter-button-group", { id: "mask-controls" }, [ - $el("button.painter-button.primary", { - id: `toggle-mask-btn-${node.id}`, - textContent: "M", // Fallback text until icon loads - title: "Toggle mask overlay visibility", - style: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - minWidth: '32px', - maxWidth: '32px', - padding: '4px', - fontSize: '12px', - fontWeight: 'bold' - }, - onclick: (e) => { - const button = e.currentTarget; - canvas.maskTool.toggleOverlayVisibility(); - canvas.render(); - const iconContainer = button.querySelector('.mask-icon-container'); - if (iconContainer) { - if (canvas.maskTool.isOverlayVisible) { - button.classList.add('primary'); - iconContainer.style.opacity = '1'; + $el("label.clipboard-switch.mask-switch", { + id: `toggle-mask-switch-${node.id}`, + style: { minWidth: "56px", maxWidth: "56px", width: "56px", paddingLeft: "0", paddingRight: "0" } + }, [ + $el("input", { + type: "checkbox", + checked: canvas.maskTool.isOverlayVisible, + onchange: (e) => { + const checked = e.target.checked; + canvas.maskTool.isOverlayVisible = checked; + canvas.render(); + } + }), + $el("span.switch-track"), + $el("span.switch-labels", { style: { fontSize: "11px" } }, [ + $el("span.text-clipspace", { style: { paddingRight: "22px" } }, ["On"]), + $el("span.text-system", { style: { paddingLeft: "20px" } }, ["Off"]) + ]), + $el("span.switch-knob", {}, [ + (() => { + // Ikona maski (SVG lub obrazek) + const iconContainer = document.createElement('span'); + iconContainer.className = 'switch-icon'; + iconContainer.style.display = 'flex'; + iconContainer.style.alignItems = 'center'; + iconContainer.style.justifyContent = 'center'; + iconContainer.style.width = '16px'; + iconContainer.style.height = '16px'; + // Pobierz ikonę maski z iconLoader + const icon = iconLoader.getIcon(LAYERFORGE_TOOLS.MASK); + if (icon instanceof HTMLImageElement) { + const img = icon.cloneNode(); + img.style.width = "16px"; + img.style.height = "16px"; + // Ustaw filtr w zależności od stanu checkboxa + setTimeout(() => { + const input = document.getElementById(`toggle-mask-switch-${node.id}`)?.querySelector('input[type="checkbox"]'); + const updateIconFilter = () => { + if (input && img) { + img.style.filter = input.checked + ? "brightness(0) invert(1)" + : "grayscale(1) brightness(0.7) opacity(0.6)"; + } + }; + if (input) { + input.addEventListener('change', updateIconFilter); + updateIconFilter(); + } + }, 0); + iconContainer.appendChild(img); } else { - button.classList.remove('primary'); - iconContainer.style.opacity = '0.5'; + iconContainer.textContent = "M"; + iconContainer.style.fontSize = "12px"; + iconContainer.style.color = "#fff"; } - } - } - }), + return iconContainer; + })() + ]) + ]), $el("button.painter-button", { textContent: "Edit Mask", title: "Open the current canvas view in the mask editor", diff --git a/js/css/canvas_view.css b/js/css/canvas_view.css index 3c27a68..c2b4982 100644 --- a/js/css/canvas_view.css +++ b/js/css/canvas_view.css @@ -2,16 +2,17 @@ background-color: #444; border: 1px solid #555; border-radius: 5px; - color: #e0e0e0; + color: #fff; padding: 6px 14px; font-size: 12px; - font-weight: 500; + font-weight: 550; cursor: pointer; transition: all 0.2s ease-in-out; min-width: 80px; text-align: center; margin: 2px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button:hover { @@ -42,7 +43,7 @@ background-color: #3a76d6; border-color: #2a6ac4; color: #fff; - text-shadow: none; + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button.primary:hover { @@ -54,6 +55,7 @@ background-color: #4a7c59; border-color: #3a6c49; color: #fff; + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button.success:hover { @@ -65,6 +67,7 @@ background-color: #c54747; border-color: #a53737; color: #fff; + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button.danger:hover { @@ -180,11 +183,11 @@ width: 90px; height: 30px; box-sizing: border-box; - background-color: #444; + background: linear-gradient(to right, #5a5a5a 30%, #3a76d6); border-radius: 5px; border: 1px solid #555; cursor: pointer; - transition: background-color 0.3s ease-in-out; + transition: background 0.3s ease-in-out, border-color 0.3s ease-in-out; user-select: none; padding: 0; font-family: inherit; @@ -192,11 +195,21 @@ box-shadow: 0 1px 2px rgba(0,0,0,0.1); } .clipboard-switch:hover { - background-color: #555; + background: linear-gradient(to right, #6a6a6a 30%, #4a86e4); border-color: #666; + box-shadow: 0 2px 4px rgba(0,0,0,0.15); + transform: translateY(-1px); +} + +/* Mask switch: szaro-czarny gradient tylko dla maski */ +.clipboard-switch.mask-switch { + background: linear-gradient(to right, #5a5a5a 30%, #e53935); +} +.clipboard-switch.mask-switch:hover { + background: linear-gradient(to right, #6a6a6a 30%, #ff5252); } .clipboard-switch:active { - background-color: #3a3a3a; + background: linear-gradient(135deg, #3a76d6, #3a3a3a); } .clipboard-switch input[type="checkbox"] { @@ -223,6 +236,14 @@ z-index: 2; } +.clipboard-switch:hover .switch-knob { + background-color: #6a6a6a; +} + +.clipboard-switch:hover .switch-knob { + background-color: #6a6a6a; +} + .clipboard-switch .switch-labels { position: absolute; top: 0; @@ -232,11 +253,12 @@ display: flex; align-items: center; justify-content: center; - font-weight: 500; - color: #e0e0e0; + font-weight: 550; + color: #ffffff; pointer-events: none; z-index: 1; transition: opacity 0.3s ease-in-out; + text-shadow: 0 1px 2px rgb(0, 0, 0); } .clipboard-switch .switch-labels .text-clipspace, .clipboard-switch .switch-labels .text-system { @@ -261,20 +283,19 @@ /* Checked state */ .clipboard-switch:has(input:checked) { - background-color: #3a76d6; + background: linear-gradient(to right, #3a76d6, #5a5a5a 70%); border-color: #2a6ac4; } .clipboard-switch:has(input:checked):hover { - background-color: #4a86e4; + background: linear-gradient(to right, #4a86e4, #6a6a6a 70%); border-color: #3a76d6; } .clipboard-switch input:checked ~ .switch-knob { left: calc(100% - 26px); - background-color: #fff; } .clipboard-switch input:checked ~ .switch-knob .switch-icon img { - filter: invert(35%) sepia(100%) saturate(1500%) hue-rotate(200deg) brightness(90%) contrast(100%); + filter: none; } .clipboard-switch input:checked ~ .switch-labels .text-clipspace { opacity: 1; diff --git a/src/CanvasView.ts b/src/CanvasView.ts index 050de0b..f8cb4de 100644 --- a/src/CanvasView.ts +++ b/src/CanvasView.ts @@ -435,37 +435,65 @@ async function createCanvasWidget(node: ComfyNode, widget: any, app: ComfyApp): ]), $el("div.painter-separator"), $el("div.painter-button-group", {id: "mask-controls"}, [ - $el("button.painter-button.primary", { - id: `toggle-mask-btn-${node.id}`, - textContent: "M", // Fallback text until icon loads - title: "Toggle mask overlay visibility", - style: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - minWidth: '32px', - maxWidth: '32px', - padding: '4px', - fontSize: '12px', - fontWeight: 'bold' - }, - onclick: (e: MouseEvent) => { - const button = e.currentTarget as HTMLButtonElement; - canvas.maskTool.toggleOverlayVisibility(); - canvas.render(); - - const iconContainer = button.querySelector('.mask-icon-container') as HTMLElement; - if (iconContainer) { - if (canvas.maskTool.isOverlayVisible) { - button.classList.add('primary'); - iconContainer.style.opacity = '1'; - } else { - button.classList.remove('primary'); - iconContainer.style.opacity = '0.5'; - } +$el("label.clipboard-switch.mask-switch", { + id: `toggle-mask-switch-${node.id}`, + style: { minWidth: "56px", maxWidth: "56px", width: "56px", paddingLeft: "0", paddingRight: "0" } +}, [ + $el("input", { + type: "checkbox", + checked: canvas.maskTool.isOverlayVisible, + onchange: (e: Event) => { + const checked = (e.target as HTMLInputElement).checked; + canvas.maskTool.isOverlayVisible = checked; + canvas.render(); + } + }), + $el("span.switch-track"), + $el("span.switch-labels", { style: { fontSize: "11px" } }, [ + $el("span.text-clipspace", { style: { paddingRight: "22px" } }, ["On"]), + $el("span.text-system", { style: { paddingLeft: "20px" } }, ["Off"]) + ]), + $el("span.switch-knob", {}, [ + (() => { + // Ikona maski (SVG lub obrazek) + const iconContainer = document.createElement('span') as HTMLElement; + iconContainer.className = 'switch-icon'; + iconContainer.style.display = 'flex'; + iconContainer.style.alignItems = 'center'; + iconContainer.style.justifyContent = 'center'; + iconContainer.style.width = '16px'; + iconContainer.style.height = '16px'; + // Pobierz ikonę maski z iconLoader + const icon = iconLoader.getIcon(LAYERFORGE_TOOLS.MASK); + if (icon instanceof HTMLImageElement) { + const img = icon.cloneNode() as HTMLImageElement; + img.style.width = "16px"; + img.style.height = "16px"; + // Ustaw filtr w zależności od stanu checkboxa + setTimeout(() => { + const input = document.getElementById(`toggle-mask-switch-${node.id}`)?.querySelector('input[type="checkbox"]') as HTMLInputElement; + const updateIconFilter = () => { + if (input && img) { + img.style.filter = input.checked + ? "brightness(0) invert(1)" + : "grayscale(1) brightness(0.7) opacity(0.6)"; } + }; + if (input) { + input.addEventListener('change', updateIconFilter); + updateIconFilter(); } - }), + }, 0); + iconContainer.appendChild(img); + } else { + iconContainer.textContent = "M"; + iconContainer.style.fontSize = "12px"; + iconContainer.style.color = "#fff"; + } + return iconContainer; + })() + ]) +]), $el("button.painter-button", { textContent: "Edit Mask", title: "Open the current canvas view in the mask editor", diff --git a/src/css/canvas_view.css b/src/css/canvas_view.css index 3c27a68..c2b4982 100644 --- a/src/css/canvas_view.css +++ b/src/css/canvas_view.css @@ -2,16 +2,17 @@ background-color: #444; border: 1px solid #555; border-radius: 5px; - color: #e0e0e0; + color: #fff; padding: 6px 14px; font-size: 12px; - font-weight: 500; + font-weight: 550; cursor: pointer; transition: all 0.2s ease-in-out; min-width: 80px; text-align: center; margin: 2px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button:hover { @@ -42,7 +43,7 @@ background-color: #3a76d6; border-color: #2a6ac4; color: #fff; - text-shadow: none; + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button.primary:hover { @@ -54,6 +55,7 @@ background-color: #4a7c59; border-color: #3a6c49; color: #fff; + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button.success:hover { @@ -65,6 +67,7 @@ background-color: #c54747; border-color: #a53737; color: #fff; + text-shadow: 0 1px 2px rgb(0,0,0); } .painter-button.danger:hover { @@ -180,11 +183,11 @@ width: 90px; height: 30px; box-sizing: border-box; - background-color: #444; + background: linear-gradient(to right, #5a5a5a 30%, #3a76d6); border-radius: 5px; border: 1px solid #555; cursor: pointer; - transition: background-color 0.3s ease-in-out; + transition: background 0.3s ease-in-out, border-color 0.3s ease-in-out; user-select: none; padding: 0; font-family: inherit; @@ -192,11 +195,21 @@ box-shadow: 0 1px 2px rgba(0,0,0,0.1); } .clipboard-switch:hover { - background-color: #555; + background: linear-gradient(to right, #6a6a6a 30%, #4a86e4); border-color: #666; + box-shadow: 0 2px 4px rgba(0,0,0,0.15); + transform: translateY(-1px); +} + +/* Mask switch: szaro-czarny gradient tylko dla maski */ +.clipboard-switch.mask-switch { + background: linear-gradient(to right, #5a5a5a 30%, #e53935); +} +.clipboard-switch.mask-switch:hover { + background: linear-gradient(to right, #6a6a6a 30%, #ff5252); } .clipboard-switch:active { - background-color: #3a3a3a; + background: linear-gradient(135deg, #3a76d6, #3a3a3a); } .clipboard-switch input[type="checkbox"] { @@ -223,6 +236,14 @@ z-index: 2; } +.clipboard-switch:hover .switch-knob { + background-color: #6a6a6a; +} + +.clipboard-switch:hover .switch-knob { + background-color: #6a6a6a; +} + .clipboard-switch .switch-labels { position: absolute; top: 0; @@ -232,11 +253,12 @@ display: flex; align-items: center; justify-content: center; - font-weight: 500; - color: #e0e0e0; + font-weight: 550; + color: #ffffff; pointer-events: none; z-index: 1; transition: opacity 0.3s ease-in-out; + text-shadow: 0 1px 2px rgb(0, 0, 0); } .clipboard-switch .switch-labels .text-clipspace, .clipboard-switch .switch-labels .text-system { @@ -261,20 +283,19 @@ /* Checked state */ .clipboard-switch:has(input:checked) { - background-color: #3a76d6; + background: linear-gradient(to right, #3a76d6, #5a5a5a 70%); border-color: #2a6ac4; } .clipboard-switch:has(input:checked):hover { - background-color: #4a86e4; + background: linear-gradient(to right, #4a86e4, #6a6a6a 70%); border-color: #3a76d6; } .clipboard-switch input:checked ~ .switch-knob { left: calc(100% - 26px); - background-color: #fff; } .clipboard-switch input:checked ~ .switch-knob .switch-icon img { - filter: invert(35%) sepia(100%) saturate(1500%) hue-rotate(200deg) brightness(90%) contrast(100%); + filter: none; } .clipboard-switch input:checked ~ .switch-labels .text-clipspace { opacity: 1;