Spaces:
Running
on
Zero
Running
on
Zero
| import { app } from '../../scripts/app.js' | |
| import { api } from '../../scripts/api.js' | |
| // import * as shared from './comfy_shared.js' | |
| import { | |
| // defineCSSClass, | |
| ensureMTBStyles, | |
| makeElement, | |
| makeSelect, | |
| makeSlider, | |
| renderSidebar, | |
| } from './mtb_ui.js' | |
| let offset = 0 | |
| let currentWidth = 200 | |
| let currentMode = 'input' | |
| let currentSort = 'None' | |
| const IMAGE_NODES = ['LoadImage'] | |
| const updateImage = (node, image) => { | |
| if (IMAGE_NODES.includes(node.type)) { | |
| const w = node.widgets?.find((w) => w.name === 'image') | |
| if (w) { | |
| w.value = image | |
| w.callback() | |
| } | |
| } | |
| } | |
| const getImgsFromUrls = (urls, target) => { | |
| const imgs = [] | |
| if (urls === undefined) { | |
| return imgs | |
| } | |
| for (const [key, url] of Object.entries(urls)) { | |
| const a = makeElement('img') | |
| a.src = url | |
| a.width = currentWidth | |
| if (currentMode === 'input') { | |
| a.onclick = (_e) => { | |
| const selected = app.canvas.selected_nodes | |
| if (selected && Object.keys(selected).length === 0) { | |
| app.extensionManager.toast.add({ | |
| severity: 'warn', | |
| summary: 'No LoadImage node selected!', | |
| detail: | |
| 'For now the only action when clicking images in the sidebar is to set the image on all selected LoadImage nodes.', | |
| life: 5000, | |
| }) | |
| return | |
| } | |
| for (const [_id, node] of Object.entries(app.canvas.selected_nodes)) { | |
| updateImage(node, `${key}.png`) | |
| } | |
| } | |
| } else { | |
| a.onclick = (_e) => | |
| // window.MTB?.notify?.("Output import isn't supported yet...", 5000) | |
| app.extensionManager.toast.add({ | |
| severity: 'warn', | |
| summary: 'Outputs not supported', | |
| detail: | |
| 'For now only inputs can be clicked to load the image on the active LoadImage node.', | |
| life: 5000, | |
| }) | |
| } | |
| imgs.push(a) | |
| } | |
| if (target !== undefined) { | |
| target.append(...imgs) | |
| } | |
| return imgs | |
| } | |
| const getUrls = async () => { | |
| const count = await api.getSetting('mtb.io-sidebar.count') | |
| console.log('Sidebar count', count) | |
| const inputs = await api.fetchApi('/mtb/actions', { | |
| method: 'POST', | |
| body: JSON.stringify({ | |
| name: 'getUserImages', | |
| // mode, count, offset | |
| args: [currentMode, count, offset, currentSort], | |
| }), | |
| }) | |
| const output = await inputs.json() | |
| return output?.result || {} | |
| } | |
| if (window?.__COMFYUI_FRONTEND_VERSION__) { | |
| let handle | |
| const version = window?.__COMFYUI_FRONTEND_VERSION__ | |
| console.log(`%c ${version}`, 'background: orange; color: white;') | |
| ensureMTBStyles() | |
| app.ui.settings.addSetting({ | |
| id: 'mtb.io-sidebar.count', | |
| category: ['mtb', 'Input & Output Sidebar', 'count'], | |
| name: 'Number of images to fetch', | |
| type: 'number', | |
| defaultValue: 1000, | |
| tooltip: | |
| "This setting affects the input/output sidebar to determine how many images to fetch per pagination (pagination is not yet supported so for now it's the static total)", | |
| attrs: { | |
| style: { | |
| // fontFamily: 'monospace', | |
| }, | |
| }, | |
| }) | |
| app.ui.settings.addSetting({ | |
| id: 'mtb.io-sidebar.img-size', | |
| category: ['mtb', 'Input & Output Sidebar', 'img-size'], | |
| name: 'Resolution of the images', | |
| type: 'number', | |
| defaultValue: 512, | |
| tooltip: "It's recommended to keep it at 512px", | |
| attrs: { | |
| style: { | |
| // fontFamily: 'monospace', | |
| }, | |
| }, | |
| }) | |
| app.ui.settings.addSetting({ | |
| id: 'mtb.io-sidebar.sort', | |
| category: ['mtb', 'Input & Output Sidebar', 'sort'], | |
| name: 'Default sort mode', | |
| type: 'combo', | |
| onChange: (v) => { | |
| // alert(`Sort is now ${v}`) | |
| currentSort = v | |
| }, | |
| defaultValue: 'Modified', | |
| // tooltip: "It's recommended to keep it at 512px", | |
| options: ['None', 'Modified', 'Modified-Reverse', 'Name', 'Name-Reverse'], | |
| }) | |
| app.extensionManager.registerSidebarTab({ | |
| id: 'mtb-inputs-outputs', | |
| icon: 'pi pi-images', | |
| title: 'Input & Outputs', | |
| tooltip: 'MTB: Browse inputs and outputs directories.', | |
| type: 'custom', | |
| // this is run everytime the tab's diplay is toggled on. | |
| render: async (el) => { | |
| if (handle) { | |
| handle.unregister() | |
| handle = undefined | |
| } | |
| if (el.parentNode) { | |
| el.parentNode.style.overflowY = 'clip' | |
| } | |
| const urls = await getUrls(currentMode) | |
| let imgs = {} | |
| const cont = makeElement('div.mtb_sidebar') | |
| const imgGrid = makeElement('div.mtb_img_grid') | |
| const selector = makeSelect(['input', 'output'], currentMode) | |
| selector.addEventListener('change', async (e) => { | |
| const newMode = e.target.value | |
| const changed = newMode !== currentMode | |
| currentMode = newMode | |
| if (changed) { | |
| imgGrid.innerHTML = '' | |
| const urls = await getUrls() | |
| if (urls) { | |
| imgs = getImgsFromUrls(urls, imgGrid) | |
| } | |
| } | |
| }) | |
| const imgTools = makeElement('div.mtb_tools') | |
| const orderSelect = makeSelect( | |
| ['None', 'Modified', 'Modified-Reverse', 'Name', 'Name-Reverse'], | |
| currentSort, | |
| ) | |
| orderSelect.addEventListener('change', async (e) => { | |
| const newSort = e.target.value | |
| const changed = newSort !== currentSort | |
| currentSort = newSort | |
| if (changed) { | |
| imgGrid.innerHTML = '' | |
| const urls = await getUrls() | |
| if (urls) { | |
| imgs = getImgsFromUrls(urls, imgGrid) | |
| } | |
| } | |
| }) | |
| const sizeSlider = makeSlider(64, 1024, currentWidth, 1) | |
| imgTools.appendChild(orderSelect) | |
| imgTools.appendChild(sizeSlider) | |
| imgs = getImgsFromUrls(urls, imgGrid) | |
| sizeSlider.addEventListener('input', (e) => { | |
| currentWidth = e.target.value | |
| for (const img of imgs) { | |
| img.style.width = `${e.target.value}px` | |
| } | |
| }) | |
| handle = renderSidebar(el, cont, [selector, imgGrid, imgTools]) | |
| }, | |
| destroy: () => { | |
| if (handle) { | |
| handle.unregister() | |
| handle = undefined | |
| } | |
| }, | |
| }) | |
| } | |