From 47dc1775176b90dbbef2390cfcec8f6ced3c8b49 Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Fri, 16 Oct 2026 11:30:11 -0700 Subject: [PATCH] feat(ui): migrate saved-image viewer to shared window controls --- TESTING.md | 6 +- docs/screenshots/save-image-viewer/dark.png | Bin 0 -> 85564 bytes docs/screenshots/save-image-viewer/light.png | Bin 0 -> 90382 bytes tests/browser/workflows.spec.mjs | 142 ++ tests/comfyui/image-browser.spec.mjs | 50 +- tests/js/floating-window.test.mjs | 20 + tools/testing/frontend-coverage-baseline.json | 16 +- web/kiko_save_image_ui.js | 1171 ++++------------- web/ui/README.md | 17 + web/ui/floating-window.js | 80 ++ web/ui/window.css | 51 + 11 files changed, 627 insertions(+), 926 deletions(-) create mode 100644 docs/screenshots/save-image-viewer/dark.png create mode 100644 docs/screenshots/save-image-viewer/light.png create mode 100644 tests/js/floating-window.test.mjs create mode 100644 web/ui/floating-window.js create mode 100644 web/ui/window.css diff --git a/TESTING.md b/TESTING.md index bd4fa5b..77d39c2 100644 --- a/TESTING.md +++ b/TESTING.md @@ -93,7 +93,11 @@ so user settings, saved workflows and selections are not written to the live server. It does not execute a workflow or download models. Checks cover Classic/Nodes 2.0/live switching, theme changes, workflow save/reload -and removal. Screenshots/traces appear in +and removal for the loader. Save Image additionally checks real image output, +window close/reopen through the node control across renderer switches, theme +changes, exclusion of the launcher from serialized values and owner removal. +Its `/view` requests also use disposable fixture output rather than live files. +Screenshots/traces appear in `tools/testing/test-results/comfyui/`. This opt-in smoke suite is separate from the required fixture CI job; fully provisioned, pinned ComfyUI CI and testing alongside other node packs remain follow-up work in issue #81. diff --git a/docs/screenshots/save-image-viewer/dark.png b/docs/screenshots/save-image-viewer/dark.png new file mode 100644 index 0000000000000000000000000000000000000000..59c70877fc1e48e0cd4ed26c73e95004660c0422 GIT binary patch literal 85564 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 literal 0 HcmV?d00001 diff --git a/docs/screenshots/save-image-viewer/light.png b/docs/screenshots/save-image-viewer/light.png new file mode 100644 index 0000000000000000000000000000000000000000..c3984177a3e4ad2bd93e7c694479e0ac9a004554 GIT binary patch literal 90382 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 z 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

YixvG3F;K>Rk%bE~Ws}2UXf*yz;)PGr`e&owj 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 X=O(-4*(JN`3@eC9RV$_3mfj( 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 literal 0 HcmV?d00001 diff --git a/tests/browser/workflows.spec.mjs b/tests/browser/workflows.spec.mjs index fd091d1..04e9839 100644 --- a/tests/browser/workflows.spec.mjs +++ b/tests/browser/workflows.spec.mjs @@ -315,6 +315,148 @@ test('real image save output opens a preview, closes, and reuses the viewer on e await expect(viewer.locator('.kiko-viewer-container')).toBeHidden(); }); +async function savedImageResult(page, request, count = 1) { + const id = await createNode(page, 'KikoSaveImage', { format: 'PNG', quality: 90 }); + const response = await request.post('/__test__/execute/KikoSaveImage', { data: { filename_prefix: 'Window test' } }); + await expect(response).toBeOK(); + const message = (await response.json()).ui; + message.kiko_enhanced = Array.from({ length: count }, () => ({ ...message.kiko_enhanced[0] })); + await page.evaluate(({ id, message }) => kikoHost.nodes.get(String(id)).onExecuted(message), { id, message }); + return { id, message }; +} + +test('shared saved-image window follows themes and supports keyboard close and reopen', async ({ page, request }) => { + await openHost(page); + const { id } = await savedImageResult(page, request); + const viewer = page.getByRole('dialog', { name: 'Saved images', exact: true }); + await expect(viewer).toBeVisible(); + await page.evaluate(() => document.body.style.setProperty('--bg-color', '#fafafa')); + await expect(viewer).toHaveAttribute('data-ca-theme', 'light'); + await viewer.getByTitle('Minimize', { exact: true }).click(); + await expect(viewer.locator('.kiko-viewer-container')).toBeHidden(); + await viewer.getByTitle('Restore', { exact: true }).click(); + await expect(viewer.locator('.kiko-viewer-container')).toBeVisible(); + await viewer.getByTitle('Close', { exact: true }).focus(); + await page.keyboard.press('Escape'); + await expect(viewer).toBeHidden(); + await page.locator(`[data-node="KikoSaveImage"]`).getByRole('button', { name: 'Show images', exact: true }).click(); + await expect(viewer).toBeVisible(); + expect(await page.evaluate(id => kikoHost.nodes.get(String(id)).kikoViewer.isConnected, id)).toBe(true); +}); + +test('saved-image ownership transfers safely and deletion cleans up only the owner window', async ({ page, request }) => { + await openHost(page); + const first = await savedImageResult(page, request); + const second = await savedImageResult(page, request); + expect(await page.evaluate(id => Boolean(kikoHost.nodes.get(String(id)).kikoViewer), second.id)).toBe(true); + await page.evaluate(id => kikoHost.removeNode(id), first.id); + await expect(page.locator('kiko-image-viewer')).toBeVisible(); + await page.evaluate(id => kikoHost.removeNode(id), second.id); + await expect(page.locator('kiko-image-viewer')).toHaveCount(0); +}); + +test('saved-image window moves and resizes by keyboard and remains inside a shrinking viewport', async ({ page, request }) => { + await page.setViewportSize({ width: 1200, height: 900 }); + await openHost(page); + await savedImageResult(page, request); + const viewer = page.locator('kiko-image-viewer'); + const move = viewer.getByRole('button', { name: 'Move image viewer with arrow keys', exact: true }); + await move.focus(); + const before = await viewer.boundingBox(); + await page.keyboard.press('ArrowLeft'); + expect((await viewer.boundingBox()).x).toBeLessThan(before.x); + const resize = viewer.getByRole('button', { name: 'Resize image viewer with arrow keys', exact: true }); + await resize.focus(); + await page.keyboard.press('ArrowRight'); + expect((await viewer.boundingBox()).width).toBeGreaterThan(before.width); + const imageBefore = await viewer.locator('img').boundingBox(); + await page.keyboard.press('ArrowDown'); + expect((await viewer.locator('img').boundingBox()).height).toBeGreaterThan(imageBefore.height); + const info = await viewer.locator('.kiko-image-info').boundingBox(); + const content = await viewer.locator('.kiko-viewer-container').boundingBox(); + expect(info.y + info.height).toBeLessThanOrEqual(content.y + content.height); + await page.setViewportSize({ width: 360, height: 500 }); + await expect.poll(async () => { + const rect = await viewer.boundingBox(); + return rect.x >= 0 && rect.y >= 0 && rect.x + rect.width <= 361 && rect.y + rect.height <= 501; + }).toBe(true); +}); + +test('saved-image batch selection downloads and resets for new execution results', async ({ page, request }) => { + await openHost(page); + const { id, message } = await savedImageResult(page, request, 2); + const viewer = page.locator('kiko-image-viewer'); + const choices = viewer.getByRole('checkbox'); + await expect(choices).toHaveCount(2); + await choices.first().check(); + await expect(viewer.locator('.selected-count')).toHaveText('1'); + await viewer.getByRole('button', { name: 'Select all', exact: true }).click(); + await expect(choices.nth(1)).toBeChecked(); + const download = page.waitForEvent('download'); + await viewer.getByRole('button', { name: /Download image 1:/ }).click(); + expect((await download).suggestedFilename()).toBe(message.kiko_enhanced[0].filename); + await page.evaluate(({ id, message }) => kikoHost.nodes.get(String(id)).onExecuted(message), { id, message: { kiko_enhanced: [message.kiko_enhanced[0]] } }); + expect(await viewer.evaluate(element => element.selectedImages.size)).toBe(0); + await expect(viewer.getByRole('checkbox')).toHaveCount(0); +}); + +test('saved-image window pointer handles drag resize and cancel without losing reachability', async ({ page, request }) => { + await page.setViewportSize({ width: 1200, height: 900 }); + await openHost(page); + await savedImageResult(page, request); + const viewer = page.locator('kiko-image-viewer'); + const before = await viewer.boundingBox(); + const handle = await viewer.locator('[data-window-move]').boundingBox(); + await page.mouse.move(handle.x + 20, handle.y + 15); + await page.mouse.down(); + await page.mouse.move(handle.x - 100, handle.y + 35, { steps: 4 }); + await page.mouse.up(); + const moved = await viewer.boundingBox(); + expect(moved.x).toBeLessThan(before.x); + await expect(viewer).not.toHaveClass(/ca-dragging/); + const resize = await viewer.locator('[data-window-resize]').boundingBox(); + await page.mouse.move(resize.x + 12, resize.y + 12); + await page.mouse.down(); + await page.mouse.move(resize.x + 60, resize.y + 15, { steps: 4 }); + await page.mouse.up(); + expect((await viewer.boundingBox()).width).toBeGreaterThan(moved.width); + const next = await viewer.locator('[data-window-move]').boundingBox(); + await page.mouse.move(next.x + 20, next.y + 15); + await page.mouse.down(); + await viewer.dispatchEvent('pointercancel'); + await expect(viewer).not.toHaveClass(/ca-dragging/); + await page.mouse.up(); +}); + +test('delayed selected-image opens stop on close replacement and owner removal', async ({ page, request }) => { + await openHost(page); + const { id, message } = await savedImageResult(page, request, 2); + await page.clock.install(); + await page.evaluate(() => { + window.openedImages = []; + window.open = url => { window.openedImages.push(url); return {}; }; + const viewer = document.querySelector('kiko-image-viewer'); + viewer.handleBulkAction('select-all'); + viewer.handleBulkAction('open-all'); + }); + await page.clock.runFor(200); + expect(await page.evaluate(() => window.openedImages.length)).toBe(2); + for (const action of ['close', 'replace', 'remove']) { + await page.evaluate(({ id, message, action }) => { + const node = kikoHost.nodes.get(String(id)); + node.onExecuted(message); + const viewer = document.querySelector('kiko-image-viewer'); + viewer.handleBulkAction('select-all'); + viewer.handleBulkAction('open-all'); + if (action === 'close') viewer.close(); + if (action === 'replace') node.onExecuted(message); + if (action === 'remove') kikoHost.removeNode(id); + }, { id, message, action }); + await page.clock.runFor(500); + expect(await page.evaluate(() => window.openedImages.length)).toBe(2); + } +}); + test('Display Any renders real multiline output and restores serialized values without duplicate widgets', async ({ page, request }) => { await openHost(page); const id = await createNode(page, 'DisplayAny'); diff --git a/tests/comfyui/image-browser.spec.mjs b/tests/comfyui/image-browser.spec.mjs index 2142478..0d77518 100644 --- a/tests/comfyui/image-browser.spec.mjs +++ b/tests/comfyui/image-browser.spec.mjs @@ -17,7 +17,7 @@ test.beforeEach(async ({ page, context, request, baseURL }, testInfo) => { const request = route.request(); const url = new URL(request.url()); const path = url.pathname.replace(/^\/api\//, '/'); - if (path.startsWith('/kiko_local_image_loader/')) { + if (path.startsWith('/kiko_local_image_loader/') || path === '/view') { const response = await route.fetch({ url: `${fixture}${path}${url.search}` }); return route.fulfill({ response }); } @@ -47,6 +47,54 @@ test.beforeEach(async ({ page, context, request, baseURL }, testInfo) => { }); }); +test('saved-image window survives real renderer switching and is removed with its owner', async ({ page, request }, testInfo) => { + const result = await request.post(`${fixture}/__test__/execute/KikoSaveImage`, { data: { filename_prefix: 'Real host viewer' } }); + await expect(result).toBeOK(); + const message = (await result.json()).ui; + const id = await page.evaluate(async message => { + const { app } = await import('/scripts/app.js'); + const node = LiteGraph.createNode('KikoSaveImage'); + app.graph.add(node); + node.onExecuted(message); + app.canvas.centerOnNode(node); + return node.id; + }, message); + const viewer = page.getByRole('dialog', { name: 'Saved images', exact: true }); + await expect(viewer).toBeVisible(); + await expect.poll(() => viewer.locator('img').evaluate(image => image.complete && image.naturalWidth > 0)).toBe(true); + for (const renderer of [false, true, false]) { + await page.evaluate(async renderer => { + const { app } = await import('/scripts/app.js'); + await app.ui.settings.setSettingValue('Comfy.VueNodes.Enabled', renderer); + }, renderer); + await expect.poll(() => page.evaluate(() => LiteGraph.vueNodesMode)).toBe(renderer); + await expect(viewer).toHaveCount(1); + await viewer.getByTitle('Close', { exact: true }).click(); + await page.getByRole('button', { name: 'Show images', exact: true }).click(); + await expect(viewer).toBeVisible(); + expect(await page.evaluate(async id => { + const { app } = await import('/scripts/app.js'); + return app.graph.serialize().nodes.find(node => String(node.id) === String(id)).widgets_values.includes('Show images'); + }, id)).toBe(false); + } + for (const theme of ['light', 'dark']) { + await page.evaluate(async theme => { + const { app } = await import('/scripts/app.js'); + await app.ui.settings.setSettingValue('Comfy.ColorPalette', theme); + }, theme); + await expect(viewer).toHaveAttribute('data-ca-theme', theme); + const info = await viewer.locator('.kiko-image-info').boundingBox(); + const content = await viewer.locator('.kiko-viewer-container').boundingBox(); + expect(info.y + info.height).toBeLessThanOrEqual(content.y + content.height); + await page.screenshot({ path: testInfo.outputPath(`viewer-${theme}.png`) }); + } + await page.evaluate(async id => { + const { app } = await import('/scripts/app.js'); + app.graph.remove(app.graph.getNodeById(id)); + }, id); + await expect(viewer).toHaveCount(0); +}); + test('actual host preserves the widget through renderer changes, theme changes and save/reload', async ({ page, request }, testInfo) => { await expect(await request.post(`${fixture}/__test__/reset`, { data: { extra_images: 52 } })).toBeOK(); await page.evaluate(async () => { diff --git a/tests/js/floating-window.test.mjs b/tests/js/floating-window.test.mjs new file mode 100644 index 0000000..2dd3936 --- /dev/null +++ b/tests/js/floating-window.test.mjs @@ -0,0 +1,20 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { fitWindowRect } from '../../web/ui/floating-window.js'; + +test('window bounds keep its controls reachable after moving outside the viewport', () => { + const rect = fitWindowRect({ x: -100, y: 900, width: 420, height: 400 }, { width: 1000, height: 700 }); + assert.equal(rect.x, 8); + assert.equal(rect.y + rect.height, 692); +}); + +test('window fitting respects minimum sizes and small viewports', () => { + const small = fitWindowRect({ x: 0, y: 0, width: 10, height: 10 }, { width: 1000, height: 700 }); + assert.equal(small.width, 280); + assert.equal(small.height, 200); + const narrow = fitWindowRect({ x: 800, y: 600, width: 900, height: 800 }, { width: 260, height: 180 }); + assert.equal(narrow.width, 244); + assert.equal(narrow.height, 164); + assert.equal(narrow.x, 8); + assert.equal(narrow.y, 8); +}); diff --git a/tools/testing/frontend-coverage-baseline.json b/tools/testing/frontend-coverage-baseline.json index 63ada88..e98db14 100644 --- a/tools/testing/frontend-coverage-baseline.json +++ b/tools/testing/frontend-coverage-baseline.json @@ -48,10 +48,10 @@ "statements": 77 }, "kiko_save_image_ui.js": { - "lines": 66, - "branches": 49, - "functions": 57, - "statements": 66 + "lines": 84, + "branches": 74, + "functions": 78, + "statements": 84 }, "kiko_workflow_timer_ui.js": { "lines": 44, @@ -73,10 +73,16 @@ }, "ui/core.js": { "lines": 98, - "branches": 91, + "branches": 92, "functions": 98, "statements": 98 }, + "ui/floating-window.js": { + "lines": 93, + "branches": 80, + "functions": 98, + "statements": 93 + }, "views/image-browser.js": { "lines": 98, "branches": 98, diff --git a/web/kiko_save_image_ui.js b/web/kiko_save_image_ui.js index 8bc45ac..b252fce 100644 --- a/web/kiko_save_image_ui.js +++ b/web/kiko_save_image_ui.js @@ -4,387 +4,15 @@ */ import { app } from "../../scripts/app.js"; +import { createButton, createScope, mountTheme } from "./ui/core.js"; +import { mountFloatingWindow } from "./ui/floating-window.js"; -// CSS styles for enhanced image previews and web component -const KIKO_SAVE_IMAGE_STYLES = ` -/* Custom Web Component Styles - Floating Draggable Window */ -kiko-image-viewer { - position: fixed; - top: 100px; - right: 20px; - width: 420px; - max-width: 90vw; - max-height: 80vh; - background: #2a2a2a; - border-radius: 12px; - overflow: hidden; - box-shadow: 0 8px 32px rgba(0,0,0,0.5); - border: 1px solid #444; - z-index: 10000; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - resize: both; - min-width: 300px; - min-height: 200px; - transition: background 0.3s ease, box-shadow 0.3s ease, border 0.3s ease; -} - -kiko-image-viewer.rolled-up { - background: transparent; - box-shadow: none; - border: none; - overflow: visible; - resize: none; - min-height: auto; -} - -kiko-image-viewer.dragging { - transition: none; - z-index: 10001; -} - -kiko-image-viewer.dragging .kiko-viewer-header { - background: linear-gradient(135deg, #388E3C, #2E7D32); -} - -.kiko-viewer-container { - padding: 12px; - max-height: calc(80vh - 80px); - overflow-y: auto; - overflow-x: hidden; - transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), - padding 0.3s cubic-bezier(0.4, 0, 0.2, 1), - opacity 0.3s ease; -} - -kiko-image-viewer.rolled-up .kiko-viewer-container { - max-height: 0; - padding: 0 12px; - opacity: 0; - overflow: hidden; -} - -.kiko-viewer-header { - background: linear-gradient(135deg, #4CAF50, #45a049); - padding: 12px 16px; - color: #fff; - font-size: 13px; - font-weight: 600; - border-bottom: 1px solid #555; - cursor: move; - user-select: none; - display: flex; - justify-content: space-between; - align-items: center; - position: relative; -} - -.kiko-viewer-header::after { - content: ''; - position: absolute; - bottom: 2px; - left: 50%; - transform: translateX(-50%); - width: 30px; - height: 3px; - background: rgba(255, 255, 255, 0.3); - border-radius: 2px; - opacity: 0; - transition: opacity 0.3s ease; -} - -kiko-image-viewer.rolled-up .kiko-viewer-header::after { - opacity: 1; -} - -kiko-image-viewer.rolled-up .kiko-viewer-header { - border-bottom: none; - border-radius: 12px; - box-shadow: 0 4px 16px rgba(0,0,0,0.3); -} - -.kiko-viewer-title { - flex: 1; -} - -.kiko-viewer-controls { - display: flex; - gap: 8px; - align-items: center; -} - -.kiko-control-btn { - background: rgba(255,255,255,0.2); - border: none; - color: white; - width: 24px; - height: 24px; - border-radius: 4px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 12px; - transition: background 0.2s ease; -} - -.kiko-control-btn:hover { - background: rgba(255,255,255,0.3); -} - -.kiko-minimize-btn:hover { - background: rgba(255,193,7,0.8); -} - -.kiko-close-btn:hover { - background: rgba(244,67,54,0.8); -} - -.kiko-image-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); - gap: 10px; - margin-top: 8px; -} - -.kiko-image-item { - position: relative; - background: #1a1a1a; - border-radius: 8px; - overflow: hidden; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - border: 2px solid transparent; - cursor: default; -} - -.kiko-image-item:hover { - border-color: #4CAF50; - transform: translateY(-3px); - box-shadow: 0 8px 25px rgba(76, 175, 80, 0.4); -} - -.kiko-image-item img { - width: 100%; - height: 120px; - display: block; - object-fit: cover; - transition: transform 0.3s ease; -} - -.kiko-image-item:hover img { - transform: scale(1.05); -} - -.kiko-image-actions { - position: absolute; - top: 8px; - right: 8px; - display: flex; - gap: 6px; - opacity: 0; - transform: translateY(-10px); - transition: all 0.3s ease; -} - -.kiko-image-item:hover .kiko-image-actions { - opacity: 1; - transform: translateY(0); -} - -.kiko-action-btn { - background: rgba(0,0,0,0.8); - border: none; - color: white; - width: 32px; - height: 32px; - border-radius: 6px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 14px; - transition: all 0.2s ease; - backdrop-filter: blur(10px); -} - -.kiko-action-btn:hover { - background: rgba(76, 175, 80, 0.9); - transform: scale(1.1); -} - -.kiko-action-btn.download:hover { - background: rgba(33, 150, 243, 0.9); -} - -.kiko-action-btn.copy:hover { - background: rgba(156, 39, 176, 0.9); -} - -.kiko-image-selector { - position: absolute; - top: 8px; - left: 8px; - width: 24px; - height: 24px; - background: rgba(0,0,0,0.8); - border: 2px solid white; - border-radius: 4px; - cursor: pointer; - opacity: 0; - transition: all 0.3s ease; - display: flex; - align-items: center; - justify-content: center; -} - -.kiko-image-item:hover .kiko-image-selector { - opacity: 1; -} - -.kiko-image-selector.selected { - background: #4CAF50; - border-color: #4CAF50; - opacity: 1; -} - -.kiko-image-selector.selected::after { - content: '✓'; - color: white; - font-size: 12px; - font-weight: bold; -} - -.kiko-image-info { - position: absolute; - bottom: 0; - left: 0; - right: 0; - background: linear-gradient(transparent, rgba(0,0,0,0.9)); - color: white; - padding: 8px 6px 4px; - font-size: 10px; - line-height: 1.2; -} - -.kiko-image-filename { - font-weight: bold; - margin-bottom: 2px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.kiko-image-details { - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - gap: 4px; -} - -.kiko-format-badge { - display: inline-block; - padding: 1px 4px; - border-radius: 3px; - font-size: 9px; - font-weight: bold; - text-transform: uppercase; -} - -.kiko-format-png { background-color: #2196F3; } -.kiko-format-jpeg { background-color: #FF9800; } -.kiko-format-webp { background-color: #4CAF50; } - -.kiko-image-stats { - font-size: 9px; - opacity: 0.8; -} - -.kiko-click-hint { - position: absolute; - top: 4px; - right: 4px; - background: rgba(0,0,0,0.7); - color: white; - padding: 2px 6px; - border-radius: 3px; - font-size: 9px; - opacity: 0; - transition: opacity 0.2s ease; -} - -.kiko-image-item:hover .kiko-click-hint { - opacity: 1; -} - -.kiko-bulk-btn { - background: #444; - border: 1px solid #666; - color: white; - padding: 4px 8px; - border-radius: 4px; - cursor: pointer; - font-size: 10px; - transition: all 0.2s ease; -} - -.kiko-bulk-btn:hover { - background: #4CAF50; - border-color: #4CAF50; - transform: translateY(-1px); -} - -/* Legacy styles for fallback */ -.kiko-save-image-preview { - position: relative; - display: inline-block; - margin: 4px; - border: 2px solid #333; - border-radius: 8px; - overflow: hidden; - cursor: pointer; - transition: all 0.2s ease; -} - -.kiko-save-image-preview:hover { - border-color: #555; - transform: scale(1.02); - box-shadow: 0 4px 12px rgba(0,0,0,0.3); -} - -.kiko-format-indicator { - display: inline-block; - padding: 2px 6px; - border-radius: 4px; - font-size: 10px; - font-weight: bold; - margin-left: 4px; -} - -.kiko-quality-preview { - font-size: 11px; - color: #888; - margin-top: 2px; -} -`; - -// Inject CSS styles function injectStyles() { - if (!document.getElementById('kiko-save-image-styles')) { - const style = document.createElement('style'); - style.id = 'kiko-save-image-styles'; - style.textContent = KIKO_SAVE_IMAGE_STYLES; - document.head.appendChild(style); - } -} - -// Escape a value for safe interpolation into HTML text or attribute contexts -function escapeHtml(value) { - return String(value ?? '') - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); + const url = new URL('./ui/window.css', import.meta.url).href; + if ([...document.querySelectorAll('link[rel="stylesheet"]')].some(link => link.href === url)) return; + const link = document.createElement('link'); + Object.assign(link, { rel: 'stylesheet', href: url }); + document.head.append(link); } // Build a ComfyUI /api/view URL with every parameter encoded @@ -407,19 +35,11 @@ function formatFileSize(bytes) { } // Open image in new tab -function openImageInTab(imagePath, subfolder = '', enablePopup = true) { +function openImageInTab(imagePath, subfolder = '', enablePopup = true, type = 'output') { // Note: enablePopup parameter is kept for compatibility but not used // since popup now controls viewer visibility, not individual image clicks - const basePath = window.location.origin; - - // Construct proper image URL handling subfolder - let fullPath; - if (subfolder && subfolder.trim()) { - fullPath = `${basePath}/api/view?filename=${encodeURIComponent(imagePath)}&subfolder=${encodeURIComponent(subfolder)}&type=output`; - } else { - fullPath = `${basePath}/api/view?filename=${encodeURIComponent(imagePath)}&type=output`; - } + const fullPath = buildViewUrl(imagePath, subfolder, type); // Extract clean filename for window name (remove timestamp and batch number) const cleanName = imagePath.split('_').slice(0, -2).join('_') || 'KikoSaveImage'; @@ -443,430 +63,248 @@ class KikoImageViewer extends HTMLElement { super(); this.imageData = []; this.selectedImages = new Set(); - this.isDragging = false; this.isMinimized = false; this.isRolledUp = false; - this.dragOffset = { x: 0, y: 0 }; - this.lastHeaderClick = 0; - - // Bind document-level drag handlers once so they can be removed later - this.boundHandleDrag = this.handleDrag.bind(this); - this.boundEndDrag = this.endDrag.bind(this); - - // Always start at default position + this.openTimers = new Set(); + this.viewerId = `kiko-viewer-${Math.random().toString(36).slice(2)}`; } - static get observedAttributes() { - return ['data']; - } + static get observedAttributes() { return ['data']; } connectedCallback() { - document.addEventListener('mousemove', this.boundHandleDrag); - document.addEventListener('mouseup', this.boundEndDrag); + this.classList.add('ca-tools', 'ca-floating-window'); + this.setAttribute('role', 'dialog'); + this.setAttribute('aria-label', 'Saved images'); + this.activate(); } disconnectedCallback() { - document.removeEventListener('mousemove', this.boundHandleDrag); - document.removeEventListener('mouseup', this.boundEndDrag); + this.scope?.dispose(); + this.cancelOpens(); + } + + activate() { + if (this.scope && !this.scope.signal.aborted) return; + this.scope = createScope(); + mountTheme(this, app.ui.settings, this.scope); + this.windowController = mountFloatingWindow(this, this.scope, () => this.close()); + this.scope.listen(this, 'click', event => { + const button = event.target.closest('button[data-action]'); + if (!button) return; + event.stopPropagation(); + const action = button.dataset.action; + if (action === 'close') this.close(); + else if (action === 'minimize') this.toggleMinimize(); + else if (button.hasAttribute('data-index')) this.handleActionButton(action, Number(button.dataset.index)); + else this.handleBulkAction(action); + }); + this.scope.listen(this, 'change', event => { + if (event.target.matches('input[data-index]')) this.toggleImageSelection(Number(event.target.dataset.index)); + }); + this.scope.listen(this, 'dblclick', event => { + if (event.target.closest('[data-window-move]')) this.toggleRollUp(); + }); + this.scope.cleanup(() => this.cancelOpens()); } attributeChangedCallback(name, oldValue, newValue) { - if (name === 'data' && newValue) { - try { - this.imageData = JSON.parse(newValue); - this.autoUnrollOnNewImages(); - this.render(); - } catch (e) { - console.error('KikoImageViewer: Failed to parse image data:', e); - } - } + if (name !== 'data' || !newValue || oldValue === newValue) return; + try { this.setImageData(JSON.parse(newValue)); } + catch (error) { console.error('KikoImageViewer: Invalid image data', error); } } setImageData(data) { + if (!Array.isArray(data)) return; + this.cancelOpens(); this.imageData = data; - this.autoUnrollOnNewImages(); + this.classList.toggle('ca-single-image', data.length === 1); + this.selectedImages.clear(); + this.isMinimized = false; + this.isRolledUp = false; + this.classList.remove('ca-minimized', 'rolled-up'); this.render(); - this.setupEventListeners(); } - setupEventListeners() { - // Window dragging and double-click functionality - const header = this.querySelector('.kiko-viewer-header'); - if (header) { - header.addEventListener('mousedown', this.startDrag.bind(this)); - header.addEventListener('dblclick', this.handleHeaderDoubleClick.bind(this)); - } - - // Control buttons - const minimizeBtn = this.querySelector('.kiko-minimize-btn'); - const closeBtn = this.querySelector('.kiko-close-btn'); - - if (minimizeBtn) { - minimizeBtn.addEventListener('click', this.toggleMinimize.bind(this)); - } - - if (closeBtn) { - closeBtn.addEventListener('click', this.close.bind(this)); - } - - // Image selection checkboxes - const selectors = this.querySelectorAll('.kiko-image-selector'); - selectors.forEach((selector, index) => { - selector.addEventListener('click', (e) => { - e.stopPropagation(); - this.toggleImageSelection(index); - }); - }); - - // Action buttons - const actionButtons = this.querySelectorAll('.kiko-action-btn'); - actionButtons.forEach((btn) => { - btn.addEventListener('click', (e) => { - e.stopPropagation(); - const action = btn.dataset.action; - const index = parseInt(btn.dataset.index); - this.handleActionButton(action, index); - }); - }); - - // Bulk action buttons - const bulkButtons = this.querySelectorAll('.kiko-bulk-btn'); - bulkButtons.forEach((btn) => { - btn.addEventListener('click', (e) => { - e.stopPropagation(); - const action = btn.dataset.action; - this.handleBulkAction(action); - }); - }); - - // Document-level drag listeners are managed in connectedCallback/disconnectedCallback - } - - startDrag(e) { - // Don't start dragging if clicking on control buttons - if (e.target.closest('.kiko-viewer-controls')) { - return; - } - - this.isDragging = true; - const rect = this.getBoundingClientRect(); - this.dragOffset = { - x: e.clientX - rect.left, - y: e.clientY - rect.top - }; - - // Prevent text selection while dragging - e.preventDefault(); - - // Add dragging class for visual feedback - this.classList.add('dragging'); - } - - handleDrag(e) { - if (!this.isDragging) return; - - e.preventDefault(); - - const x = e.clientX - this.dragOffset.x; - const y = e.clientY - this.dragOffset.y; - - // Keep window within viewport bounds - const maxX = window.innerWidth - this.offsetWidth; - const maxY = window.innerHeight - this.offsetHeight; - - const boundedX = Math.max(0, Math.min(x, maxX)); - const boundedY = Math.max(0, Math.min(y, maxY)); - - this.style.left = boundedX + 'px'; - this.style.top = boundedY + 'px'; - this.style.right = 'auto'; // Override CSS right positioning - } - - endDrag(e) { - if (!this.isDragging) return; - - this.isDragging = false; - this.classList.remove('dragging'); - } - - handleHeaderDoubleClick(e) { - // Don't toggle if clicking on control buttons - if (e.target.closest('.kiko-viewer-controls')) { - return; - } - - this.toggleRollUp(); - } - - autoUnrollOnNewImages() { - // Auto-unroll if currently rolled up and we have new image data - if (this.isRolledUp && this.imageData && this.imageData.length > 0) { - this.isRolledUp = false; - this.classList.remove('rolled-up'); - } - } - - toggleRollUp() { - this.isRolledUp = !this.isRolledUp; - - if (this.isRolledUp) { - this.classList.add('rolled-up'); - } else { - this.classList.remove('rolled-up'); - } + cancelOpens() { + this.openTimers.forEach(timer => clearTimeout(timer)); + this.openTimers.clear(); } toggleMinimize() { this.isMinimized = !this.isMinimized; - const container = this.querySelector('.kiko-viewer-container'); - const minimizeBtn = this.querySelector('.kiko-minimize-btn'); - - if (container && minimizeBtn) { - if (this.isMinimized) { - container.style.display = 'none'; - minimizeBtn.textContent = '+'; - minimizeBtn.title = 'Restore'; - } else { - container.style.display = 'block'; - minimizeBtn.textContent = '−'; - minimizeBtn.title = 'Minimize'; - } - } + this.isRolledUp = this.isMinimized; + this.classList.toggle('ca-minimized', this.isMinimized); + this.classList.toggle('rolled-up', this.isMinimized); + this.querySelector('.kiko-viewer-container').hidden = this.isMinimized; + this.querySelector('[data-window-resize]').hidden = this.isMinimized; + this.querySelector('.ca-window-status').hidden = this.isMinimized; + const button = this.querySelector('.kiko-minimize-btn'); + button.textContent = this.isMinimized ? '+' : '−'; + button.title = this.isMinimized ? 'Restore' : 'Minimize'; + button.setAttribute('aria-label', `${button.title} image viewer`); + button.setAttribute('aria-expanded', String(!this.isMinimized)); + this.windowController?.fit(); } + toggleRollUp() { this.toggleMinimize(); } + close() { - this.style.display = 'none'; + const restoreFocus = this.contains(document.activeElement); + this.hidden = true; + this.scope?.dispose(); + this.ownerNode?.updateViewerButton(); + if (restoreFocus && this.returnFocus?.isConnected) this.returnFocus.focus(); } - show() { - this.style.display = 'block'; + show(focus = false) { + if (focus && !this.contains(document.activeElement)) this.returnFocus = document.activeElement; + this.hidden = false; + if (this.isConnected) this.activate(); + this.windowController?.fit(); + this.ownerNode?.updateViewerButton(); + if (focus) this.querySelector('[data-window-move]')?.focus(); } toggleImageSelection(index) { - const selector = this.querySelector(`[data-index="${index}"].kiko-image-selector`); - if (!selector) return; - - if (this.selectedImages.has(index)) { - this.selectedImages.delete(index); - selector.classList.remove('selected'); - } else { - this.selectedImages.add(index); - selector.classList.add('selected'); - } - - this.updateBulkActionsVisibility(); - this.updateSelectedCount(); + const checkbox = this.querySelector(`input[data-index="${index}"]`); + if (!checkbox) return; + if (checkbox.checked) this.selectedImages.add(index); + else this.selectedImages.delete(index); + this.updateSelection(); } - updateBulkActionsVisibility() { - const bulkActions = this.querySelector('.kiko-bulk-actions'); - if (bulkActions) { - bulkActions.style.display = this.selectedImages.size > 0 ? 'block' : 'none'; - } - } - - updateSelectedCount() { - const countSpan = this.querySelector('.selected-count'); - if (countSpan) { - countSpan.textContent = this.selectedImages.size; - } + updateSelection() { + this.querySelectorAll('input[data-index]').forEach(input => { input.checked = this.selectedImages.has(Number(input.dataset.index)); }); + const count = this.querySelector('.selected-count'); + if (count) count.textContent = this.selectedImages.size; + this.querySelectorAll('[data-action="open-all"], [data-action="download-all"], [data-action="clear-selection"]').forEach(button => { button.disabled = this.selectedImages.size === 0; }); } handleActionButton(action, index) { - const imageData = this.imageData[index]; - if (!imageData) return; - - switch (action) { - case 'download': - this.downloadImage(imageData); - break; - } + const image = this.imageData[index]; + if (!image) return; + if (action === 'download') this.downloadImage(image); + else if (action === 'open') openImageInTab(image.filename, image.subfolder || '', true, image.type); } handleBulkAction(action) { - switch (action) { - case 'open-all': - this.openAllImagesWithDelay(); - break; - case 'download-all': - this.selectedImages.forEach(index => { - const imageData = this.imageData[index]; - if (imageData) { - this.downloadImage(imageData); - } - }); - break; - case 'select-all': - this.imageData.forEach((_, index) => { - this.selectedImages.add(index); - const selector = this.querySelector(`[data-index="${index}"].kiko-image-selector`); - if (selector) { - selector.classList.add('selected'); - } - }); - this.updateBulkActionsVisibility(); - this.updateSelectedCount(); - break; - case 'clear-selection': - this.selectedImages.clear(); - this.querySelectorAll('.kiko-image-selector.selected').forEach(selector => { - selector.classList.remove('selected'); - }); - this.updateBulkActionsVisibility(); - this.updateSelectedCount(); - break; - } + if (action === 'select-all') this.imageData.forEach((_, index) => this.selectedImages.add(index)); + else if (action === 'clear-selection') this.selectedImages.clear(); + else if (action === 'open-all') this.openAllImagesWithDelay(); + else if (action === 'download-all') this.selectedImages.forEach(index => this.downloadImage(this.imageData[index])); + this.updateSelection(); } openAllImagesWithDelay() { - const selectedIndices = Array.from(this.selectedImages); - if (selectedIndices.length === 0) { - return; - } - - // Open images with 150ms delay between each to prevent popup blocking - selectedIndices.forEach((index, i) => { - setTimeout(() => { - const imageData = this.imageData[index]; - if (imageData) { - openImageInTab(imageData.filename, imageData.subfolder || ''); - } - }, i * 150); + this.cancelOpens(); + [...this.selectedImages].forEach((index, offset) => { + const image = this.imageData[index]; + const timer = setTimeout(() => { + this.openTimers.delete(timer); + openImageInTab(image.filename, image.subfolder || '', true, image.type); + }, offset * 150); + this.openTimers.add(timer); }); } - downloadImage(imageData) { - // Construct proper image URL handling subfolder - const imageUrl = buildViewUrl(imageData.filename, imageData.subfolder, imageData.type); - - // Create temporary link and trigger download + downloadImage(image) { const link = document.createElement('a'); - link.href = imageUrl; - link.download = imageData.filename; - link.style.display = 'none'; - document.body.appendChild(link); + link.href = buildViewUrl(image.filename, image.subfolder, image.type); + link.download = image.filename; + document.body.append(link); link.click(); - document.body.removeChild(link); + link.remove(); } - render() { - if (!this.imageData || this.imageData.length === 0) { - this.innerHTML = ` -
-
No images to display
-
- -
-
- `; - return; - } - - const header = this.imageData.length === 1 - ? `Saved Image (${escapeHtml(this.imageData[0].format)})` - : `Saved Images (${this.imageData.length} files)`; - - const containerStyle = this.isMinimized ? 'style="display: none;"' : ''; - - this.innerHTML = ` -
-
${header}
-
- - -
-
-
-
- ${this.imageData.map((data, index) => this.createImageItem(data, index)).join('')} -
- ${this.imageData.length > 1 ? this.createBulkActions() : ''} -
- `; - - // Add all event handlers - this.addClickHandlers(); + this.innerHTML = '
'; + const header = this.querySelector('header'); + const move = createButton(this.imageData.length === 1 ? 'Saved image' : `Saved images · ${this.imageData.length}`, 'ca-window-handle'); + move.setAttribute('data-window-move', ''); + move.setAttribute('aria-label', 'Move image viewer with arrow keys'); + move.title = 'Drag to move · Double-click to minimize'; + header.prepend(move); + const brand = document.createElement('span'); + brand.className = 'ca-window-brand'; + brand.textContent = 'ComfyAssets'; + move.after(brand); + const controls = this.querySelector('.kiko-viewer-controls'); + const minimize = createButton('−', 'kiko-control-btn kiko-minimize-btn'); + minimize.dataset.action = 'minimize'; + minimize.title = 'Minimize'; + minimize.setAttribute('aria-label', 'Minimize image viewer'); + minimize.setAttribute('aria-expanded', 'true'); + const close = createButton('×', 'kiko-control-btn kiko-close-btn ca-danger'); + close.dataset.action = 'close'; + close.title = 'Close'; + close.setAttribute('aria-label', 'Close image viewer'); + controls.append(minimize, close); + this.querySelector('.kiko-image-grid').append(...this.imageData.map((image, index) => this.createImageItem(image, index))); + if (this.imageData.length > 1) this.createBulkActions(); + const resize = createButton('◢', 'ca-window-resize'); + resize.setAttribute('data-window-resize', ''); + resize.setAttribute('aria-label', 'Resize image viewer with arrow keys'); + this.append(resize); + this.querySelector('footer').textContent = this.imageData.length ? `${this.imageData.length} saved ${this.imageData.length === 1 ? 'image' : 'images'} · Click a preview to open` : 'No images to display'; + this.updateSelection(); } createBulkActions() { - return ` - - `; - } - - createImageItem(data, index) { - // Construct proper image URL handling subfolder - // ComfyUI expects subfolder to be passed separately - const imageUrl = buildViewUrl(data.filename, data.subfolder, data.type); - - const formatClass = `kiko-format-${String(data.format ?? '').toLowerCase().replace(/[^a-z0-9_-]/g, '')}`; - - // Format file size - const fileSize = data.file_size ? formatFileSize(data.file_size) : 'Unknown'; - - // Build quality info - let qualityInfo = ''; - if (data.format === 'PNG' && data.compress_level !== undefined) { - qualityInfo = `C${data.compress_level}`; - } else if ((data.format === 'JPEG' || data.format === 'WEBP') && data.quality !== undefined) { - if (data.format === 'WEBP' && data.lossless) { - qualityInfo = 'Lossless'; - } else { - qualityInfo = `Q${data.quality}`; - } + const toolbar = document.createElement('div'); + toolbar.className = 'kiko-bulk-actions'; + toolbar.innerHTML = '0 selected
'; + for (const [action, text] of [['select-all', 'Select all'], ['clear-selection', 'Clear selection'], ['open-all', 'Open selected'], ['download-all', 'Download selected']]) { + const button = createButton(text, `kiko-bulk-btn${action === 'download-all' ? ' ca-primary' : ''}`); + button.dataset.action = action; + toolbar.querySelector('div').append(button); } - - return ` -
- ${escapeHtml(data.filename)} - - ${this.imageData.length > 1 ? ` -
- ` : ''} - -
- -
- -
-
- ${escapeHtml(data.filename)} -
-
-
- ${escapeHtml(data.format)} - ${escapeHtml(data.dimensions || 'Unknown')} • ${escapeHtml(fileSize)} - ${qualityInfo ? ` • ${escapeHtml(qualityInfo)}` : ''} -
-
-
-
- `; + this.querySelector('.kiko-viewer-container').append(toolbar); } - addClickHandlers() { - const items = this.querySelectorAll('.kiko-image-item'); - items.forEach((item, index) => { - const data = this.imageData[index]; - if (data) { - item.addEventListener('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - openImageInTab(data.filename, data.subfolder || ''); - }); - } - }); + createImageItem(image, index) { + const item = document.createElement('div'); + item.className = 'kiko-image-item'; + const open = createButton('', 'kiko-image-open'); + open.dataset.action = 'open'; + open.dataset.index = index; + open.setAttribute('aria-label', `Open image ${index + 1}: ${image.filename}`); + const img = document.createElement('img'); + Object.assign(img, { src: buildViewUrl(image.filename, image.subfolder, image.type), alt: image.filename, loading: 'lazy' }); + open.append(img); + const actions = document.createElement('div'); + actions.className = 'kiko-image-actions'; + if (this.imageData.length > 1) { + const label = document.createElement('label'); + label.className = 'kiko-image-selector'; + const checkbox = document.createElement('input'); + Object.assign(checkbox, { type: 'checkbox', id: `${this.viewerId}-select-${index}` }); + checkbox.dataset.index = index; + checkbox.setAttribute('aria-label', `Select image ${index + 1}: ${image.filename}`); + label.htmlFor = checkbox.id; + label.append(checkbox, document.createTextNode('Select')); + actions.append(label); + } + const download = createButton('↓ Download', 'kiko-action-btn ca-primary'); + download.dataset.action = 'download'; + download.dataset.index = index; + download.title = 'Download'; + download.setAttribute('aria-label', `Download image ${index + 1}: ${image.filename}`); + actions.append(download); + const info = document.createElement('div'); + info.className = 'kiko-image-info'; + const filename = document.createElement('div'); + filename.className = 'kiko-image-filename'; + filename.textContent = image.filename; + const stats = document.createElement('div'); + stats.className = 'kiko-image-stats'; + let quality = ''; + if (image.format === 'PNG' && image.compress_level !== undefined) quality = ` · C${image.compress_level}`; + else if (image.format === 'WEBP' && image.lossless) quality = ' · Lossless'; + else if (image.quality !== undefined) quality = ` · Q${image.quality}`; + stats.textContent = `${image.format || 'PNG'} · ${image.dimensions || 'Unknown'} · ${formatFileSize(image.file_size || 0)}${quality}`; + info.append(filename, stats); + item.append(open, actions, info); + return item; } } @@ -875,64 +313,6 @@ if (!customElements.get('kiko-image-viewer')) { customElements.define('kiko-image-viewer', KikoImageViewer); } -// Create enhanced image preview element -function createImagePreview(imageData) { - const container = document.createElement('div'); - container.className = 'kiko-save-image-preview'; - - // Create image element - const img = document.createElement('img'); - img.src = buildViewUrl(imageData.filename, imageData.subfolder, imageData.type); - img.alt = imageData.filename; - - // Create info overlay - const info = document.createElement('div'); - info.className = 'kiko-save-image-info'; - - const formatSpan = document.createElement('span'); - formatSpan.className = 'kiko-save-image-format'; - formatSpan.textContent = imageData.format || 'PNG'; - - const sizeSpan = document.createElement('span'); - sizeSpan.className = 'kiko-save-image-size'; - sizeSpan.textContent = ` • ${imageData.dimensions || 'Unknown'}`; - - const fileSizeSpan = document.createElement('span'); - fileSizeSpan.className = 'kiko-save-image-size'; - fileSizeSpan.textContent = ` • ${formatFileSize(imageData.file_size || 0)}`; - - info.appendChild(formatSpan); - info.appendChild(sizeSpan); - info.appendChild(fileSizeSpan); - - // Add quality info for JPEG/WebP - if (imageData.quality && (imageData.format === 'JPEG' || imageData.format === 'WEBP')) { - const qualitySpan = document.createElement('span'); - qualitySpan.className = 'kiko-save-image-quality'; - let qualityText = ` • Q${imageData.quality}`; - if (imageData.format === 'WEBP' && imageData.lossless) { - qualityText = ' • Lossless'; - } - qualitySpan.textContent = qualityText; - info.appendChild(qualitySpan); - } else if (imageData.compress_level !== undefined && imageData.format === 'PNG') { - const compressSpan = document.createElement('span'); - compressSpan.className = 'kiko-save-image-quality'; - compressSpan.textContent = ` • C${imageData.compress_level}`; - info.appendChild(compressSpan); - } - - container.appendChild(img); - container.appendChild(info); - - // Add click handler to open in new tab - container.addEventListener('click', () => { - openImageInTab(imageData.filename, imageData.subfolder || ''); - }); - - return container; -} - // Add format indicator to widget function addFormatIndicator(node, widget) { const indicator = document.createElement('span'); @@ -968,10 +348,10 @@ app.registerExtension({ const onNodeCreated = nodeType.prototype.onNodeCreated; nodeType.prototype.onNodeCreated = function() { - // Call original onNodeCreated - if (onNodeCreated) { - onNodeCreated.apply(this, arguments); - } + const result = onNodeCreated?.apply(this, arguments); + + this.kikoViewerScope = createScope(); + this.createToggleButton(); // Add format indicator to format widget const formatWidget = this.widgets?.find(w => w.name === "format"); @@ -980,6 +360,7 @@ app.registerExtension({ // Store update function for later use this.updateFormatIndicator = updateIndicator; + this.kikoViewerScope.cleanup(() => indicator.remove()); } // Add quality preview for quality widget @@ -996,7 +377,9 @@ app.registerExtension({ // Store preview element for updates this.qualityPreview = preview; + this.kikoViewerScope.cleanup(() => preview.remove()); } + return result; }; // Override onWidgetChange to update indicators @@ -1035,106 +418,61 @@ app.registerExtension({ } }; - // Add method to create custom image viewer - nodeType.prototype.createCustomImageViewer = function(imageData) { - // Check if popup is enabled for any image (use first image's popup setting) - const popupEnabled = imageData.length > 0 ? imageData[0].popup : true; - - if (!popupEnabled) { - return; - } - - // Check if viewer already exists - let existingViewer = document.querySelector('kiko-image-viewer'); - if (existingViewer) { - // Update existing viewer with new data - existingViewer.setImageData(imageData); - existingViewer.show(); // Make sure it's visible - return; - } - - // Create toggle button in node if it doesn't exist - if (!this.kikoToggleButton) { - this.createToggleButton(); - } - - // Create new viewer - always visible on workflow execution - const viewer = document.createElement('kiko-image-viewer'); - viewer.setImageData(imageData); - - // Store reference for toggle button - this.kikoViewer = viewer; - - // Update toggle button text - if (this.kikoToggleButton) { - this.kikoToggleButton.textContent = '👁️ Hide Images'; - } - - // Append to body (floating window) - always visible - document.body.appendChild(viewer); + const originalOnRemoved = nodeType.prototype.onRemoved; + nodeType.prototype.onRemoved = function () { + this.kikoViewerScope?.dispose(); + if (this.kikoViewer?.ownerNode === this) this.kikoViewer.remove(); + this.kikoViewer = null; + return originalOnRemoved?.apply(this, arguments); }; - // Add method to create toggle button - nodeType.prototype.createToggleButton = function() { - // Find the node element to add button to - let nodeElement = null; + nodeType.prototype.updateViewerButton = function () { + if (!this.kikoToggleButton) return; + const visible = this.kikoViewer?.isConnected && this.kikoViewer.ownerNode === this && !this.kikoViewer.hidden; + this.kikoToggleButton.disabled = !this.kikoLastImages?.length; + this.kikoToggleButton.textContent = visible ? 'Hide images' : 'Show images'; + this.kikoToggleButton.setAttribute('aria-expanded', String(Boolean(visible))); + }; - if (this.domElement) { - nodeElement = this.domElement; - } else if (this.widgets && this.widgets[0] && this.widgets[0].element) { - nodeElement = this.widgets[0].element.closest('.litegraph-node'); - } else { - // Find by node title - const allNodes = document.querySelectorAll('.litegraph-node'); - for (const node of allNodes) { - if (node.textContent && node.textContent.includes('Kiko Save Image')) { - nodeElement = node; - break; - } - } - } + nodeType.prototype.createCustomImageViewer = function (imageData) { + if (!Array.isArray(imageData) || !imageData.length) return; + this.kikoLastImages = imageData; + this.updateViewerButton(); + if (!imageData[0].popup) return; + let viewer = document.querySelector('kiko-image-viewer'); + const previousOwner = viewer?.ownerNode; + if (!viewer) viewer = document.createElement('kiko-image-viewer'); + viewer.ownerNode = this; + this.kikoViewer = viewer; + viewer.setImageData(imageData); + if (!viewer.isConnected) document.body.append(viewer); + viewer.show(); + previousOwner?.updateViewerButton(); + this.updateViewerButton(); + }; - if (!nodeElement) return; - - // Create toggle button - const toggleButton = document.createElement('button'); - toggleButton.textContent = '👁️ Show Images'; - toggleButton.className = 'kiko-toggle-viewer-btn'; - toggleButton.style.cssText = ` - margin: 4px; - padding: 4px 8px; - background: #4CAF50; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - font-size: 11px; - font-family: inherit; - `; - - toggleButton.addEventListener('click', () => { - if (this.kikoViewer) { - const isHidden = this.kikoViewer.style.display === 'none'; - if (isHidden) { - this.kikoViewer.show(); - toggleButton.textContent = '👁️ Hide Images'; - } else { - this.kikoViewer.close(); - toggleButton.textContent = '👁️ Show Images'; - } + nodeType.prototype.createToggleButton = function () { + const container = document.createElement('div'); + container.className = 'ca-tools ca-viewer-launcher'; + const button = createButton('Show images', 'ca-primary kiko-toggle-viewer-btn'); + button.disabled = true; + button.setAttribute('aria-expanded', 'false'); + container.append(button); + mountTheme(container, app.ui.settings, this.kikoViewerScope); + this.addDOMWidget('kiko_saved_image_controls', 'div', container, { + serialize: false, hideOnZoom: false, + getMinHeight: () => 38, getMaxHeight: () => 38, + }); + this.kikoToggleButton = button; + this.kikoViewerScope.cleanup(() => container.remove()); + this.kikoViewerScope.listen(button, 'click', () => { + if (!this.kikoLastImages?.length) return; + if (this.kikoViewer?.ownerNode === this && this.kikoViewer.isConnected && !this.kikoViewer.hidden) this.kikoViewer.close(); + else { + this.createCustomImageViewer(this.kikoLastImages.map(image => ({ ...image, popup: true }))); + this.kikoViewer.show(true); } }); - - // Add hover effects - toggleButton.addEventListener('mouseenter', () => { - toggleButton.style.background = '#45a049'; - }); - toggleButton.addEventListener('mouseleave', () => { - toggleButton.style.background = '#4CAF50'; - }); - - nodeElement.appendChild(toggleButton); - this.kikoToggleButton = toggleButton; }; // Legacy method kept for compatibility (not used with web component) @@ -1157,7 +495,7 @@ window.kikoResetViewer = function() { const toggleButtons = document.querySelectorAll('.kiko-toggle-viewer-btn'); toggleButtons.forEach(btn => { btn.textContent = '👁️ Show Images'; - btn.style.background = '#4CAF50'; + }); console.log('✨ Reset complete! Run your workflow to create a new viewer!'); @@ -1178,8 +516,3 @@ window.kikoForceViewer = function() { console.log('⚠️ No existing viewer found. Run your KikoSaveImage workflow to create a real viewer with actual images!'); alert('⚠️ No viewer found! Run your KikoSaveImage workflow to create a viewer with real images.'); }; - -console.log('🎉 KikoSaveImage: Extension loaded!'); -console.log('💡 Helper functions available:'); -console.log(' 📞 kikoResetViewer() - Remove existing viewer windows'); -console.log(' 🚀 kikoForceViewer() - Show demo viewer'); diff --git a/web/ui/README.md b/web/ui/README.md index 7f6fbcf..b1ab6bb 100644 --- a/web/ui/README.md +++ b/web/ui/README.md @@ -24,3 +24,20 @@ of `ui/`; add abstractions only as demonstrated by the next consumer. Architecture and control organization were inspired by [Pixaroma](https://github.com/pixaroma/ComfyUI-Pixaroma). This implementation and styling are original; none of his toolkit code or assets are vendored. + +## Floating windows + +`floating-window.js` owns pointer capture, keyboard movement/resizing, viewport +bounds and observer cleanup. `window.css` consumes the same control tokens as the +loader. Kiko Save Image is its first consumer; the controller has no node, API or +gallery dependencies. + +Drag the title or bottom-right resize handle. Focus either handle and use arrow +keys (Shift for larger steps). Escape closes the focused window. The viewer stays +nonmodal so the canvas remains usable. Window position and size survive new +results and minimize/reopen within the session; they are not written into a +workflow or persisted across browser reloads. + +The owning node controls removal. Another node may take over the shared viewer, +but deleting the previous owner must not remove it. Closing or deleting a viewer, +or replacing its results, cancels delayed bulk-open actions. diff --git a/web/ui/floating-window.js b/web/ui/floating-window.js new file mode 100644 index 0000000..e2deb84 --- /dev/null +++ b/web/ui/floating-window.js @@ -0,0 +1,80 @@ +export function fitWindowRect(rect, viewport) { + const width = Math.min(Math.max(280, rect.width), Math.max(1, viewport.width - 16)); + const height = Math.min(Math.max(200, rect.height), Math.max(1, viewport.height - 16)); + return { + width, height, + x: Math.max(8, Math.min(rect.x, viewport.width - width - 8)), + y: Math.max(8, Math.min(rect.y, viewport.height - height - 8)), + }; +} + +export function mountFloatingWindow(element, scope, onClose) { + const stylesheet = new URL('./window.css', import.meta.url).href; + if (![...document.querySelectorAll('link[rel="stylesheet"]')].some(link => link.href === stylesheet)) { + const link = document.createElement('link'); + Object.assign(link, { rel: 'stylesheet', href: stylesheet }); + document.head.append(link); + } + let gesture; + const viewport = () => ({ width: innerWidth, height: innerHeight }); + const move = (x, y) => { + const rect = element.getBoundingClientRect(); + const next = fitWindowRect({ x, y, width: rect.width, height: rect.height }, viewport()); + element.style.left = `${next.x}px`; + element.style.top = `${next.y}px`; + element.style.right = 'auto'; + }; + const resize = (width, height) => { + const rect = element.getBoundingClientRect(); + const next = fitWindowRect({ x: rect.x, y: rect.y, width, height }, viewport()); + element.style.setProperty('--ca-window-width', `${next.width}px`); + element.style.setProperty('--ca-window-height', `${next.height}px`); + move(next.x, next.y); + }; + const end = () => { + if (gesture && element.hasPointerCapture(gesture.id)) element.releasePointerCapture(gesture.id); + gesture = null; + element.classList.remove('ca-dragging'); + }; + scope.listen(element, 'pointerdown', event => { + const handle = event.target.closest('[data-window-move], [data-window-resize]'); + if (!handle || event.button !== 0) return; + const rect = element.getBoundingClientRect(); + gesture = { id: event.pointerId, kind: handle.hasAttribute('data-window-resize') ? 'resize' : 'move', rect, x: event.clientX, y: event.clientY }; + handle.focus(); + element.setPointerCapture(event.pointerId); + element.classList.add('ca-dragging'); + event.preventDefault(); + }); + scope.listen(element, 'pointermove', event => { + if (!gesture || event.pointerId !== gesture.id) return; + const dx = event.clientX - gesture.x; + const dy = event.clientY - gesture.y; + if (gesture.kind === 'resize') resize(gesture.rect.width + dx, gesture.rect.height + dy); + else move(gesture.rect.x + dx, gesture.rect.y + dy); + }); + for (const event of ['pointerup', 'pointercancel', 'lostpointercapture']) scope.listen(element, event, end); + scope.listen(element, 'keydown', event => { + if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); onClose(); return; } + const handle = event.target.closest('[data-window-move], [data-window-resize]'); + if (!handle || !['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)) return; + event.preventDefault(); + event.stopPropagation(); + const delta = event.shiftKey ? 40 : 16; + const dx = event.key === 'ArrowLeft' ? -delta : event.key === 'ArrowRight' ? delta : 0; + const dy = event.key === 'ArrowUp' ? -delta : event.key === 'ArrowDown' ? delta : 0; + const rect = element.getBoundingClientRect(); + if (handle.hasAttribute('data-window-resize')) resize(rect.width + dx, rect.height + dy); + else move(rect.x + dx, rect.y + dy); + }); + const keepReachable = () => { + if (element.hidden) return; + const rect = element.getBoundingClientRect(); + move(rect.x, rect.y); + }; + scope.listen(window, 'resize', keepReachable); + const observer = new ResizeObserver(keepReachable); + observer.observe(element); + scope.cleanup(() => { observer.disconnect(); end(); }); + return { fit: keepReachable }; +} diff --git a/web/ui/window.css b/web/ui/window.css new file mode 100644 index 0000000..bb35ba7 --- /dev/null +++ b/web/ui/window.css @@ -0,0 +1,51 @@ +.ca-floating-window { + box-sizing: border-box; + position: fixed; + inset-block-start: 100px; + right: 20px; + inline-size: min(var(--ca-window-width, 600px), calc(100dvw - 16px)); + block-size: min(var(--ca-window-height, 560px), calc(100dvh - 16px)); + min-inline-size: min(280px, calc(100dvw - 16px)); + min-block-size: min(200px, calc(100dvh - 16px)); + display: flex; + flex-direction: column; + overflow: hidden; + border: 1px solid var(--ca-border); + border-radius: 8px; + box-shadow: 0 8px 28px #00000040; + z-index: 10000; +} +.ca-floating-window[hidden], .ca-floating-window [hidden] { display: none; } +.ca-floating-window.ca-minimized { block-size: auto; min-block-size: 0; } +.ca-window-header { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-block-end: 1px solid var(--ca-line); flex-shrink: 0; } +.ca-window-header .ca-window-handle { min-inline-size: 0; flex: 1; justify-content: start; border: 0; background: transparent; padding-inline: 0; overflow: hidden; text-overflow: ellipsis; cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none; } +.ca-floating-window.ca-dragging [data-window-move] { cursor: grabbing; } +.ca-window-header .kiko-viewer-controls { display: flex; align-items: center; gap: 6px; } +.ca-window-header button.kiko-control-btn { min-inline-size: 30px; padding-inline: 6px; } +.ca-window-header .ca-window-brand { color: var(--ca-muted); font-size: 10px; } +.ca-floating-window .ca-window-resize { position: absolute; inset-inline-end: 2px; inset-block-end: 2px; min-inline-size: 24px; min-block-size: 24px; border: 0; background: var(--ca-surface); color: var(--ca-muted); cursor: nwse-resize; touch-action: none; padding: 0; } +.ca-floating-window .kiko-viewer-container { padding: 12px 12px 28px; overflow: auto; min-block-size: 0; flex: 1; } +.ca-floating-window .kiko-image-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 224px), 1fr)); gap: 10px; align-items: start; } +.ca-floating-window .kiko-image-item { min-inline-size: 0; border: 1px solid var(--ca-border); border-radius: 5px; background: var(--ca-field); padding: 6px; } +.ca-floating-window .kiko-image-open { padding: 0; border: 0; background: var(--ca-field); inline-size: 100%; display: block; } +.ca-floating-window .kiko-image-open img { display: block; inline-size: 100%; block-size: 230px; object-fit: contain; } +.ca-floating-window.ca-single-image .kiko-viewer-container:not([hidden]) { display: flex; flex-direction: column; } +.ca-floating-window.ca-single-image .kiko-image-grid { display: flex; flex: 1; min-block-size: 0; align-items: stretch; } +.ca-floating-window.ca-single-image .kiko-image-item { display: flex; flex-direction: column; flex: 1; min-block-size: 0; } +.ca-floating-window.ca-single-image .kiko-image-open { position: relative; flex: 1; min-block-size: 100px; overflow: hidden; } +.ca-floating-window.ca-single-image .kiko-image-open img { position: absolute; inset: 0; block-size: 100%; } +.ca-floating-window .kiko-image-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding-block-start: 8px; flex-wrap: wrap; } +.ca-floating-window .kiko-image-selector { display: inline-flex; gap: 6px; align-items: center; cursor: pointer; font-size: 12px; min-block-size: 30px; } +.ca-floating-window .kiko-image-selector input { inline-size: 18px; block-size: 18px; min-block-size: 18px; } +.ca-floating-window .kiko-image-info { padding-block-start: 6px; font-size: 11px; } +.ca-floating-window .kiko-image-filename { overflow-wrap: anywhere; } +.ca-floating-window .kiko-image-stats { color: var(--ca-muted); margin-block-start: 3px; } +.ca-floating-window .kiko-format-badge { display: inline-block; border: 1px solid var(--ca-border); border-radius: 3px; padding: 1px 4px; margin-inline-end: 3px; } +.ca-floating-window .kiko-bulk-actions { border-block-start: 1px solid var(--ca-line); margin-block-start: 12px; padding-block-start: 10px; font-size: 12px; color: var(--ca-muted); } +.ca-floating-window .kiko-bulk-buttons { display: flex; flex-wrap: wrap; gap: 7px; margin-block-start: 7px; } +.ca-floating-window .kiko-bulk-buttons button { font-size: 12px; } +.ca-floating-window .ca-window-status { color: var(--ca-muted); font-size: 11px; padding: 6px 30px 6px 12px; border-block-start: 1px solid var(--ca-line); flex-shrink: 0; } +.ca-viewer-launcher { padding: 3px 0; } +.ca-viewer-launcher button { inline-size: 100%; } +@media (pointer: coarse) { .ca-floating-window .ca-window-header button, .ca-floating-window .ca-window-resize { min-inline-size: 40px; min-block-size: 40px; } } +@media (forced-colors: active) { .ca-floating-window { box-shadow: none; border-color: CanvasText; } }