From 6cab50e58447f664828f3299e15f469fc674f4bc Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Mon, 1 Dec 2025 05:18:23 -0800 Subject: [PATCH] Overhaul custom element styling Large performance improvement due to only needing a single style source instead of creating and parsing thousands of style elements. --- javascript/gallery.js | 67 ++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/javascript/gallery.js b/javascript/gallery.js index b679e1fd3..649e16583 100644 --- a/javascript/gallery.js +++ b/javascript/gallery.js @@ -9,6 +9,8 @@ let lastSort = 0; let lastSortName = 'None'; const galleryHashes = new Set(); let maintenanceController = new AbortController(); +const folderStylesheet = new CSSStyleSheet(); +const fileStylesheet = new CSSStyleSheet(); // Store separator states for the session const separatorStates = new Map(); const el = { @@ -38,6 +40,32 @@ async function awaitForGallery(expectedSize, signal) { while (galleryHashes.size < expectedSize && !combinedSignals.aborted) await new Promise((resolve) => { setTimeout(resolve, 500); }); // longer interval because it's a low priority check } +function updateGalleryStyles() { + folderStylesheet.replaceSync((window.opts.theme_type + === 'Modern' + ? `.gallery-folder { cursor: pointer; padding: 8px 6px 8px 6px; background-color: var(--sd-button-normal-color); border-radius: var(--sd-border-radius); text-align: left; min-width: 12em;} + .gallery-folder:hover { background-color: var(--button-primary-background-fill-hover); } + .gallery-folder-selected { background-color: var(--sd-button-selected-color); color: var(--sd-button-selected-text-color); } + .gallery-folder-icon { font-size: 1.2em; color: var(--sd-button-icon-color); margin-right: 1em; filter: drop-shadow(1px 1px 2px black); float: left; } + ` + : ` + .gallery-folder { cursor: pointer; padding: 8px 6px 8px 6px; } + .gallery-folder:hover { background-color: var(--button-primary-background-fill-hover); } + .gallery-folder-selected { background-color: var(--button-primary-background-fill); } + `)); + fileStylesheet.replaceSync(` + .gallery-file { + object-fit: contain; + cursor: pointer; + height: ${opts.extra_networks_card_size}px; + width: ${opts.browser_fixed_width ? `${opts.extra_networks_card_size}px` : 'unset'}; + } + .gallery-file:hover { + filter: grayscale(100%); + } + `); +} + // Classes class SimpleFunctionQueue { @@ -95,32 +123,17 @@ class GalleryFolder extends HTMLElement { super(); this.name = decodeURI(name); this.shadow = this.attachShadow({ mode: 'open' }); + this.shadow.adoptedStyleSheets = [folderStylesheet]; } connectedCallback() { - const style = document.createElement('style'); // silly but necessasry since we're inside shadowdom - if (window.opts.theme_type === 'Modern') { - style.textContent = ` - .gallery-folder { cursor: pointer; padding: 8px 6px 8px 6px; background-color: var(--sd-button-normal-color); border-radius: var(--sd-border-radius); text-align: left; min-width: 12em;} - .gallery-folder:hover { background-color: var(--button-primary-background-fill-hover); } - .gallery-folder-selected { background-color: var(--sd-button-selected-color); color: var(--sd-button-selected-text-color); } - .gallery-folder-icon { font-size: 1.2em; color: var(--sd-button-icon-color); margin-right: 1em; filter: drop-shadow(1px 1px 2px black); float: left; } - `; - } else { - style.textContent = ` - .gallery-folder { cursor: pointer; padding: 8px 6px 8px 6px; } - .gallery-folder:hover { background-color: var(--button-primary-background-fill-hover); } - .gallery-folder-selected { background-color: var(--button-primary-background-fill); } - `; - } - this.shadow.appendChild(style); const div = document.createElement('div'); div.className = 'gallery-folder'; div.innerHTML = `\uf03e ${this.name}`; div.addEventListener('click', () => { for (const folder of el.folders.children) { - if (folder.name === this.name) folder.shadow.children[1].classList.add('gallery-folder-selected'); - else folder.shadow.children[1].classList.remove('gallery-folder-selected'); + if (folder.name === this.name) folder.shadow.firstElementChild.classList.add('gallery-folder-selected'); + else folder.shadow.firstElementChild.classList.remove('gallery-folder-selected'); } }); div.addEventListener('click', fetchFilesWS); // eslint-disable-line no-use-before-define @@ -286,6 +299,7 @@ class GalleryFile extends HTMLElement { this.height = 0; this.src = `${this.folder}/${this.name}`; this.shadow = this.attachShadow({ mode: 'open' }); + this.shadow.adoptedStyleSheets = [fileStylesheet]; } async connectedCallback() { @@ -304,20 +318,6 @@ class GalleryFile extends HTMLElement { } this.hash = await getHash(`${this.folder}/${this.name}/${this.size}/${this.mtime}`); // eslint-disable-line no-use-before-define - const style = document.createElement('style'); - const width = opts.browser_fixed_width ? `${opts.extra_networks_card_size}px` : 'unset'; - style.textContent = ` - .gallery-file { - object-fit: contain; - cursor: pointer; - height: ${opts.extra_networks_card_size}px; - width: ${width}; - } - .gallery-file:hover { - filter: grayscale(100%); - } - `; - const cache = (this.hash && opts.browser_cache) ? await idbGet(this.hash) : undefined; const img = document.createElement('img'); img.className = 'gallery-file'; @@ -395,7 +395,6 @@ class GalleryFile extends HTMLElement { this.style.display = shouldDisplayBasedOnSearch ? 'unset' : 'none'; } - this.shadow.appendChild(style); this.shadow.appendChild(img); } } @@ -749,6 +748,7 @@ async function fetchFilesWS(evt) { // fetch file-by-file list over websockets galleryHashes.clear(); // Must happen AFTER the AbortController steps el.files.innerHTML = ''; + updateGalleryStyles(); if (ws && ws.readyState === WebSocket.OPEN) ws.close(); // abort previous request let wsConnected = false; try { @@ -862,6 +862,7 @@ async function initGallery() { // triggered on gradio change to monitor when ui error('initGallery', 'Missing gallery elements'); return; } + updateGalleryStyles(); setOverlayAnimation(); el.search.addEventListener('input', gallerySearch); el.btnSend = gradioApp().getElementById('tab-gallery-send-image');