mirror of
https://github.com/vladmandic/automatic
synced 2026-09-05 04:20:44 +02:00
Merge branch 'dev' into master
This commit is contained in:
+4
-4
@@ -98,7 +98,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
|
||||
.extra-network-cards .card:hover .overlay { background: rgba(0, 0, 0, 0.40); }
|
||||
.extra-network-cards .card:hover .preview { box-shadow: none; filter: grayscale(100%); }
|
||||
.extra-network-cards .card:hover .overlay { background: rgba(0, 0, 0, 0.40); }
|
||||
.extra-network-cards .card .tags { margin: 4px; display: none; overflow-wrap: break-word; }
|
||||
.extra-network-cards .card .tags { margin: 4px; display: none; overflow-wrap: anywhere; }
|
||||
.extra-network-cards .card .tag { padding: 2px; margin: 2px; background: var(--neutral-700); cursor: pointer; display: inline-block; }
|
||||
.extra-network-cards .card .actions > span { padding: 4px; }
|
||||
.extra-network-cards .card:hover .actions { display: block; }
|
||||
@@ -128,8 +128,8 @@ div:has(>#tab-browser-folders) { flex-grow: 0 !important; background-color: var(
|
||||
|
||||
/* loader */
|
||||
.splash { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1000; display: block; text-align: center; }
|
||||
.motd { margin-top: 2em; color: var(--body-text-color-subdued); font-family: monospace; font-variant: all-petite-caps; }
|
||||
.splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: color 10s infinite alternate; max-width: 80vw; background-size: contain; }
|
||||
.motd { margin-top: 2em; color: var(--body-text-color-subdued); font-family: monospace; font-variant: all-petite-caps; font-size: 1.2em; }
|
||||
.splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: hue 5s infinite alternate; max-width: 80vw; background-size: contain; }
|
||||
.loading { color: white; position: absolute; top: 20%; left: 50%; transform: translateX(-50%); }
|
||||
.loader { width: 300px; height: 300px; border: var(--spacing-md) solid transparent; border-radius: 50%; border-top: var(--spacing-md) solid var(--primary-600); animation: spin 4s linear infinite; position: relative; }
|
||||
.loader::before, .loader::after { content: ""; position: absolute; top: 6px; bottom: 6px; left: 6px; right: 6px; border-radius: 50%; border: var(--spacing-md) solid transparent; }
|
||||
@@ -137,4 +137,4 @@ div:has(>#tab-browser-folders) { flex-grow: 0 !important; background-color: var(
|
||||
.loader::after { border-top-color: var(--primary-300); animation: spin 1.5s linear infinite; }
|
||||
@keyframes move { from { background-position-x: 0, -40px; } to { background-position-x: 0, 40px; } }
|
||||
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
||||
@keyframes color { from { filter: hue-rotate(0deg) } to { filter: hue-rotate(360deg) } }
|
||||
@keyframes hue { from { filter: hue-rotate(0deg) } to { filter: hue-rotate(360deg) } }
|
||||
|
||||
@@ -953,7 +953,7 @@ svg.feather.feather-image,
|
||||
}
|
||||
|
||||
/* No Preview Card Styles */
|
||||
.extra-network-cards .card:has(>img[src*="card-no-preview.png"])::before {
|
||||
.extra-network-cards .card:has(>img[src*="missing.png"])::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
@@ -1007,11 +1007,11 @@ svg.feather.feather-image,
|
||||
}
|
||||
|
||||
.splash-img {
|
||||
margin: 0;
|
||||
margin: 10% auto 0 auto;
|
||||
width: 512px;
|
||||
height: 512px;
|
||||
background-repeat: no-repeat;
|
||||
animation: color 8s infinite alternate, move 3s infinite alternate;
|
||||
animation: hue 5s infinite alternate;
|
||||
}
|
||||
|
||||
.loading {
|
||||
|
||||
@@ -107,7 +107,7 @@ async function modelCardClick(id) {
|
||||
downloads: data.downloads?.toString() || '',
|
||||
creator,
|
||||
desc: data.desc || 'no description available',
|
||||
image: images.length > 0 ? images[0] : '/sdapi/v1/network/thumb?filename=html/card-no-preview.png',
|
||||
image: images.length > 0 ? images[0] : '/sdapi/v1/network/thumb?filename=html/missing.png',
|
||||
versions: versionsHTML || '',
|
||||
});
|
||||
el.innerHTML = modelHTML;
|
||||
|
||||
@@ -14,8 +14,13 @@ const getENActiveTab = () => {
|
||||
else if (gradioApp().getElementById('extras_image')?.checkVisibility()) tabName = 'process';
|
||||
else if (gradioApp().getElementById('interrogate_image')?.checkVisibility()) tabName = 'caption';
|
||||
else if (gradioApp().getElementById('tab-gallery-search')?.checkVisibility()) tabName = 'gallery';
|
||||
if (tabName in ['process', 'caption', 'gallery']) tabName = lastTab;
|
||||
else lastTab = tabName;
|
||||
|
||||
if (['process', 'caption', 'gallery'].includes(tabName)) {
|
||||
tabName = lastTab;
|
||||
} else if (tabName !== '') {
|
||||
lastTab = tabName;
|
||||
}
|
||||
|
||||
if (tabName !== '') return tabName;
|
||||
// legacy method
|
||||
if (gradioApp().getElementById('tab_txt2img')?.style.display === 'block') tabName = 'txt2img';
|
||||
@@ -277,8 +282,31 @@ function extraNetworksSearchButton(event) {
|
||||
const tabName = getENActiveTab();
|
||||
const searchTextarea = gradioApp().querySelector(`#${tabName}_extra_search textarea`);
|
||||
const button = event.target;
|
||||
searchTextarea.value = `${button.textContent.trim()}/`;
|
||||
updateInput(searchTextarea);
|
||||
if (searchTextarea) {
|
||||
searchTextarea.value = `${button.textContent.trim()}/`;
|
||||
updateInput(searchTextarea);
|
||||
} else {
|
||||
console.error(`Could not find the search textarea for the tab: ${tabName}`);
|
||||
}
|
||||
}
|
||||
|
||||
function extraNetworksFilterVersion(event) {
|
||||
// log('extraNetworksFilterVersion', event);
|
||||
const version = event.target.textContent.trim();
|
||||
const activeTab = gradioApp().querySelector('.extra-networks-tab:not([style*="display: none"])');
|
||||
if (!activeTab) return;
|
||||
const cardContainer = activeTab.querySelector('.extra-network-cards');
|
||||
if (!cardContainer) return;
|
||||
if (cardContainer.dataset.activeVersion === version) {
|
||||
cardContainer.dataset.activeVersion = '';
|
||||
cardContainer.querySelectorAll('.card').forEach((card) => card.style.display = '');
|
||||
} else {
|
||||
cardContainer.dataset.activeVersion = version;
|
||||
cardContainer.querySelectorAll('.card').forEach((card) => {
|
||||
if (card.dataset.version === version) card.style.display = '';
|
||||
else card.style.display = 'none';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let desiredStyle = '';
|
||||
|
||||
+96
-50
@@ -1197,7 +1197,7 @@ table.settings-value-table td {
|
||||
}
|
||||
|
||||
.extra-networks .search textarea {
|
||||
width: calc(120px / 1.1);
|
||||
width: calc(140px / 1.1);
|
||||
resize: none;
|
||||
margin-right: 2px;
|
||||
}
|
||||
@@ -1233,7 +1233,7 @@ table.settings-value-table td {
|
||||
padding: 3px 3px 3px 12px;
|
||||
text-align: left;
|
||||
text-indent: -6px;
|
||||
width: 120px;
|
||||
width: 140px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -1249,7 +1249,7 @@ table.settings-value-table td {
|
||||
.extra-network-subdirs {
|
||||
background: var(--input-background-fill);
|
||||
border-radius: 4px;
|
||||
min-width: max(15%, 120px);
|
||||
min-width: max(15%, 140px);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-top: 0.5em;
|
||||
@@ -1376,7 +1376,17 @@ table.settings-value-table td {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.extra-network-cards .card:has(>img[src*="card-no-preview.png"])::before {
|
||||
.extra-network-cards .card:hover {
|
||||
z-index: 100;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.extra-network-cards .card:hover .tags {
|
||||
display: block;
|
||||
z-index: 101; /* Optional: ensure tags are above everything */
|
||||
}
|
||||
|
||||
.extra-network-cards .card:has(>img[src*="missing.png"])::before {
|
||||
background-color: var(--data-color);
|
||||
content: '';
|
||||
height: 100%;
|
||||
@@ -1461,7 +1471,6 @@ table.settings-value-table td {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
.extra-details td:first-child {
|
||||
font-weight: bold;
|
||||
vertical-align: top;
|
||||
@@ -1471,6 +1480,29 @@ table.settings-value-table td {
|
||||
max-height: 50vh;
|
||||
}
|
||||
|
||||
.network-folder::before {
|
||||
content: " ";
|
||||
margin-right: 0.8em;
|
||||
}
|
||||
|
||||
.network-reference {
|
||||
filter: contrast(0.9);
|
||||
}
|
||||
|
||||
.network-reference::before {
|
||||
content: " ";
|
||||
margin-right: 0.8em;
|
||||
}
|
||||
|
||||
.network-model {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.network-model::before {
|
||||
content: " ";
|
||||
margin-right: 0.8em;
|
||||
}
|
||||
|
||||
.input-accordion-checkbox {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -1716,6 +1748,13 @@ background: var(--background-color)
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
#tab-gallery-files gallery-file {
|
||||
/* Add a vertical gutter between items (left/right), matching existing small row spacing */
|
||||
display: inline-block;
|
||||
margin-right: 0.2em;
|
||||
vertical-align: top; /* keep rows aligned on the top edge */
|
||||
}
|
||||
|
||||
#tab-gallery-files {
|
||||
display: block;
|
||||
height: 75vh;
|
||||
@@ -1813,6 +1852,24 @@ div:has(>#tab-gallery-folders) {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* Gallery video preview matches image preview sizing and layout */
|
||||
#tab-gallery-video {
|
||||
height: 63vh;
|
||||
}
|
||||
|
||||
/* Ensure the <video> element fills the preview column and preserves aspect */
|
||||
#tab-gallery-video video {
|
||||
width: 100%;
|
||||
height: 100% !important;
|
||||
object-fit: contain;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Gradio container around the video should not add extra spacing */
|
||||
#tab-gallery-video .wrap {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gallery-sort {
|
||||
background: var(--input-background-fill) !important;
|
||||
margin: 0 !important;
|
||||
@@ -1867,70 +1924,73 @@ div:has(>#tab-gallery-folders) {
|
||||
}
|
||||
|
||||
.splash {
|
||||
display: block;
|
||||
height: 100vh;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.motd {
|
||||
margin-top: 1em;
|
||||
color: var(--body-text-color-subdued);
|
||||
font-family: monospace;
|
||||
font-variant: all-petite-caps;
|
||||
margin-top: 2em;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.splash-img {
|
||||
animation: color 10s infinite alternate;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
height: 512px;
|
||||
margin: 10% auto 0 auto;
|
||||
max-width: 80vw;
|
||||
width: 512px;
|
||||
height: 512px;
|
||||
background-repeat: no-repeat;
|
||||
animation: hue 5s infinite alternate;
|
||||
}
|
||||
|
||||
.loading {
|
||||
color: white;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
transform: translateX(-50%);
|
||||
position: border-box;
|
||||
top: 85%;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.loader {
|
||||
animation: spin 4s linear infinite;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: var(--spacing-md) solid transparent;
|
||||
border-radius: 50%;
|
||||
border-top: var(--spacing-md) solid var(--primary-600);
|
||||
height: 300px;
|
||||
position: relative;
|
||||
width: 300px;
|
||||
animation: spin 2s linear infinite, hue 5s infinite alternate;
|
||||
position: border-box;
|
||||
}
|
||||
|
||||
.loader::before, .loader::after {
|
||||
border: var(--spacing-md) solid transparent;
|
||||
border-radius: 50%;
|
||||
bottom: 6px;
|
||||
.loader::before,
|
||||
.loader::after {
|
||||
content: "";
|
||||
left: 6px;
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
bottom: 6px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
border-radius: 50%;
|
||||
border: var(--spacing-md) solid transparent;
|
||||
animation: hue 5s infinite alternate;
|
||||
}
|
||||
|
||||
.loader::before {
|
||||
animation: 3s spin linear infinite;
|
||||
border-top-color: var(--primary-900);
|
||||
animation: spin 3s linear infinite;
|
||||
}
|
||||
|
||||
.loader::after {
|
||||
animation: spin 1.5s linear infinite;
|
||||
border-top-color: var(--primary-300);
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
|
||||
.docs-search textarea {
|
||||
@@ -2087,35 +2147,21 @@ div:has(>#tab-gallery-folders) {
|
||||
filter: blur(0);
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
from {
|
||||
background-position-x: 0, -40px;
|
||||
}
|
||||
|
||||
to {
|
||||
background-position-x: 0, 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes color {
|
||||
from {
|
||||
|
||||
filter: hue-rotate(0deg)
|
||||
@keyframes hue {
|
||||
0% {
|
||||
filter: hue-rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
|
||||
filter: hue-rotate(360deg)
|
||||
100% {
|
||||
filter: hue-rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+114
-52
@@ -9,10 +9,12 @@ const localeData = {
|
||||
type: 2,
|
||||
hint: null,
|
||||
btn: null,
|
||||
expandTimeout: null, // New property for expansion timeout
|
||||
expandTimeout: null, // Property for expansion timeout
|
||||
currentElement: null, // Track current element for expansion
|
||||
observer: null, // MutationObserver for DOM changes
|
||||
};
|
||||
let localeTimeout = null;
|
||||
const isTouchDevice = 'ontouchstart' in window;
|
||||
|
||||
async function cycleLocale() {
|
||||
clearTimeout(localeTimeout);
|
||||
@@ -62,43 +64,49 @@ async function tooltipCreate() {
|
||||
if (window.opts.tooltips === 'None') localeData.type = 0;
|
||||
if (window.opts.tooltips === 'Browser default') localeData.type = 1;
|
||||
if (window.opts.tooltips === 'UI tooltips') localeData.type = 2;
|
||||
|
||||
if (localeData.type === 2) { // setup event delegation for tooltips instead of individual listeners
|
||||
if (isTouchDevice) {
|
||||
gradioApp().addEventListener('touchstart', tooltipShowDelegated); // eslint-disable-line no-use-before-define
|
||||
gradioApp().addEventListener('touchend', tooltipHideDelegated); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
gradioApp().addEventListener('pointerover', tooltipShowDelegated); // eslint-disable-line no-use-before-define
|
||||
gradioApp().addEventListener('pointerout', tooltipHideDelegated); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
if (!localeData.observer) initializeDOMObserver(); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
async function expandTooltip(element, longHint) {
|
||||
if (localeData.currentElement === element && localeData.hint.classList.contains('tooltip-show')) {
|
||||
// Hide the progress ring
|
||||
const ring = localeData.hint.querySelector('.tooltip-progress-ring');
|
||||
if (ring) {
|
||||
ring.style.opacity = '0';
|
||||
}
|
||||
|
||||
// Expand the container
|
||||
if (ring) ring.style.opacity = '0';
|
||||
localeData.hint.classList.add('tooltip-expanded');
|
||||
|
||||
// After container starts expanding, reveal the long content
|
||||
setTimeout(() => {
|
||||
const longContent = localeData.hint.querySelector('.long-content');
|
||||
if (longContent) {
|
||||
longContent.classList.add('show');
|
||||
}
|
||||
if (longContent) longContent.classList.add('show');
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
async function tooltipShowDelegated(e) { // use event delegation to handle dynamically created elements
|
||||
if (e.target.dataset && e.target.dataset.hint) tooltipShow(e); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
async function tooltipHideDelegated(e) {
|
||||
if (e.target.dataset && e.target.dataset.hint) tooltipHide(e); // eslint-disable-line no-use-before-define
|
||||
}
|
||||
|
||||
async function tooltipShow(e) {
|
||||
// Clear any existing expansion timeout
|
||||
if (localeData.expandTimeout) {
|
||||
if (localeData.expandTimeout) { // clear any existing expansion timeout
|
||||
clearTimeout(localeData.expandTimeout);
|
||||
localeData.expandTimeout = null;
|
||||
}
|
||||
|
||||
// Remove expanded class and reset current element
|
||||
localeData.hint.classList.remove('tooltip-expanded');
|
||||
localeData.hint.classList.remove('tooltip-expanded'); // remove expanded class and reset current element
|
||||
localeData.currentElement = e.target;
|
||||
|
||||
if (e.target.dataset.hint) {
|
||||
// Create progress ring SVG
|
||||
const progressRing = `
|
||||
const progressRing = ` // create progress ring SVG
|
||||
<div class="tooltip-progress-ring">
|
||||
<svg viewBox="0 0 12 12">
|
||||
<circle class="ring-background" cx="6" cy="6" r="5"></circle>
|
||||
@@ -106,8 +114,7 @@ async function tooltipShow(e) {
|
||||
</svg>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Set up the complete content structure from the start
|
||||
// set up the complete content structure from the start
|
||||
let content = `
|
||||
<div class="tooltip-header">
|
||||
<b>${e.target.textContent}</b>
|
||||
@@ -116,21 +123,12 @@ async function tooltipShow(e) {
|
||||
<div class="separator"></div>
|
||||
${e.target.dataset.hint}
|
||||
`;
|
||||
|
||||
// Add long content if available, but keep it hidden
|
||||
if (e.target.dataset.longHint) {
|
||||
content += `<div class="long-content"><div class="separator"></div>${e.target.dataset.longHint}</div>`;
|
||||
}
|
||||
|
||||
// Add reload notice if needed
|
||||
if (e.target.dataset.reload) {
|
||||
if (e.target.dataset.longHint) content += `<div class="long-content"><div class="separator"></div>${e.target.dataset.longHint}</div>`; // add long content if available, but keep it hidden
|
||||
if (e.target.dataset.reload) { // add reload notice if needed
|
||||
const reloadType = e.target.dataset.reload;
|
||||
let reloadText = '';
|
||||
if (reloadType === 'model') {
|
||||
reloadText = 'Requires model reload';
|
||||
} else if (reloadType === 'server') {
|
||||
reloadText = 'Requires server restart';
|
||||
}
|
||||
if (reloadType === 'model') reloadText = 'Requires model reload';
|
||||
else if (reloadType === 'server') reloadText = 'Requires server restart';
|
||||
if (reloadText) {
|
||||
content += `
|
||||
<div class="tooltip-reload-notice">
|
||||
@@ -144,40 +142,28 @@ async function tooltipShow(e) {
|
||||
localeData.hint.innerHTML = content;
|
||||
localeData.hint.classList.add('tooltip-show');
|
||||
|
||||
if (e.clientX > window.innerWidth / 2) {
|
||||
localeData.hint.classList.add('tooltip-left');
|
||||
} else {
|
||||
localeData.hint.classList.remove('tooltip-left');
|
||||
}
|
||||
if (e.clientX > window.innerWidth / 2) localeData.hint.classList.add('tooltip-left');
|
||||
else localeData.hint.classList.remove('tooltip-left');
|
||||
|
||||
// Set up expansion timer if long hint is available
|
||||
if (e.target.dataset.longHint) {
|
||||
// Start progress ring animation
|
||||
const ring = localeData.hint.querySelector('.tooltip-progress-ring');
|
||||
if (e.target.dataset.longHint) { // set up expansion timer if long hint is available
|
||||
const ring = localeData.hint.querySelector('.tooltip-progress-ring'); // start progress ring animation
|
||||
const ringProgress = localeData.hint.querySelector('.ring-progress');
|
||||
|
||||
if (ring && ringProgress) {
|
||||
// Show the ring and start animation
|
||||
setTimeout(() => {
|
||||
ring.classList.add('active');
|
||||
ringProgress.classList.add('animate');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
localeData.expandTimeout = setTimeout(() => {
|
||||
expandTooltip(e.target, e.target.dataset.longHint);
|
||||
}, 3000);
|
||||
localeData.expandTimeout = setTimeout(() => expandTooltip(e.target, e.target.dataset.longHint), 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function tooltipHide(e) {
|
||||
// Clear expansion timeout when hiding
|
||||
if (localeData.expandTimeout) {
|
||||
clearTimeout(localeData.expandTimeout);
|
||||
localeData.expandTimeout = null;
|
||||
}
|
||||
|
||||
localeData.hint.classList.remove('tooltip-show', 'tooltip-expanded');
|
||||
localeData.currentElement = null;
|
||||
}
|
||||
@@ -294,8 +280,6 @@ async function setHint(el, entry) {
|
||||
el.dataset.hint = entry.hint;
|
||||
if (entry.longHint && entry.longHint.length > 0) el.dataset.longHint = entry.longHint;
|
||||
if (entry.reload && entry.reload.length > 0) el.dataset.reload = entry.reload;
|
||||
el.addEventListener('mouseover', tooltipShow);
|
||||
el.addEventListener('mouseout', tooltipHide);
|
||||
} else {
|
||||
// tooltips disabled
|
||||
}
|
||||
@@ -345,6 +329,7 @@ async function setHints(analyze = false) {
|
||||
localeData.initial = false;
|
||||
const t1 = performance.now();
|
||||
// localeData.btn.style.backgroundColor = localeData.locale !== 'en' ? 'var(--primary-500)' : '';
|
||||
log('touchDevice', isTouchDevice);
|
||||
log('setHints', { type: localeData.type, locale: localeData.locale, elements: elements.length, localized, hints, data: localeData.data.length, override: overrideData.length, time: Math.round(t1 - t0) });
|
||||
// sortUIElements();
|
||||
if (analyze) {
|
||||
@@ -359,3 +344,80 @@ const analyzeHints = async () => {
|
||||
localeData.data = [];
|
||||
await setHints(true);
|
||||
};
|
||||
|
||||
// Apply hints to a single element immediately
|
||||
async function applyHintToElement(el) {
|
||||
if (!localeData.data || localeData.data.length === 0) return;
|
||||
if (!el.textContent) return;
|
||||
|
||||
// check if element matches our selector criteria
|
||||
const isValidElement = el.tagName === 'BUTTON'
|
||||
|| el.tagName === 'H2'
|
||||
|| (el.tagName === 'SPAN' && (el.parentElement?.tagName === 'LABEL' || el.parentElement?.classList.contains('label-wrap')));
|
||||
if (!isValidElement) return;
|
||||
|
||||
let found; // find matching hint data
|
||||
if (el.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.dataset.original.toLowerCase().trim());
|
||||
else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());
|
||||
|
||||
if (found?.localized?.length > 0) { // apply localization if found
|
||||
if (!el.dataset.original) el.dataset.original = el.textContent;
|
||||
replaceTextContent(el, found.localized);
|
||||
}
|
||||
|
||||
if (found?.hint?.length > 0) setHint(el, found); // apply hint if found
|
||||
}
|
||||
|
||||
// Initialize MutationObserver for immediate hint application
|
||||
function initializeDOMObserver() {
|
||||
if (localeData.observer) {
|
||||
localeData.observer.disconnect();
|
||||
}
|
||||
|
||||
localeData.observer = new MutationObserver((mutations) => {
|
||||
// Process added nodes immediately
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.type === 'childList') {
|
||||
for (const node of mutation.addedNodes) {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
// Apply hints to the node itself
|
||||
applyHintToElement(node);
|
||||
|
||||
// Apply hints to all relevant children
|
||||
const elements = [
|
||||
...Array.from(node.querySelectorAll('button')),
|
||||
...Array.from(node.querySelectorAll('h2')),
|
||||
...Array.from(node.querySelectorAll('label > span')),
|
||||
...Array.from(node.querySelectorAll('.label-wrap > span')),
|
||||
];
|
||||
|
||||
// Include the node itself if it matches
|
||||
if (node.matches && (
|
||||
node.matches('button')
|
||||
|| node.matches('h2')
|
||||
|| node.matches('label > span')
|
||||
|| node.matches('.label-wrap > span')
|
||||
)) {
|
||||
elements.push(node);
|
||||
}
|
||||
|
||||
// Apply hints immediately to all found elements
|
||||
elements.forEach((el) => applyHintToElement(el));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Start observing the entire gradio app for changes
|
||||
const targetNode = gradioApp();
|
||||
if (targetNode) {
|
||||
localeData.observer.observe(targetNode, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Export for external use if needed
|
||||
const forceReapplyHints = () => setHints();
|
||||
|
||||
+12
-12
@@ -8,18 +8,18 @@ async function initStartup() {
|
||||
if (window.setupLogger) await setupLogger();
|
||||
|
||||
// all items here are non-blocking async calls
|
||||
initModels();
|
||||
getUIDefaults();
|
||||
initPromptChecker();
|
||||
initContextMenu();
|
||||
initDragDrop();
|
||||
initAccordions();
|
||||
initSettings();
|
||||
initImageViewer();
|
||||
initGallery();
|
||||
initiGenerationParams();
|
||||
initChangelog();
|
||||
setupControlUI();
|
||||
await initModels();
|
||||
await getUIDefaults();
|
||||
await initPromptChecker();
|
||||
await initContextMenu();
|
||||
await initDragDrop();
|
||||
await initAccordions();
|
||||
await initSettings();
|
||||
await initImageViewer();
|
||||
await initGallery();
|
||||
await initiGenerationParams();
|
||||
await initChangelog();
|
||||
await setupControlUI();
|
||||
|
||||
// reconnect server session
|
||||
await reconnectUI();
|
||||
|
||||
Reference in New Issue
Block a user