updates UI

This commit is contained in:
mike
2026-06-30 04:05:18 +02:00
parent 5cea78c406
commit 66685684c1
2 changed files with 190 additions and 32 deletions

View File

@@ -732,6 +732,26 @@
box-shadow: 0 0 8px rgba(59,130,246,0.6);
border-radius: 4px;
}
.lb-var-thumb.is-new {
outline: 2px solid #10b981 !important;
box-shadow: 0 0 12px rgba(16,185,129,0.8) !important;
z-index: 10;
opacity: 1 !important;
}
.lb-var-thumb.is-orbit::after {
content: '';
position: absolute;
top: 40px;
left: 50%;
transform: translateX(-50%);
width: 38px;
height: 8px;
border: 1px solid rgba(96, 165, 250, 0.6);
border-radius: 50%;
pointer-events: none;
box-shadow: 0 0 6px rgba(96, 165, 250, 0.4);
z-index: 1;
}
.lb-var-thumb-check {
position: absolute;
top: 2px;
@@ -2353,13 +2373,76 @@
// --- HYDRATION_START ---
const PRELOADED_IMAGES = [
"20260630_021844_view_000_000deg.png",
"20260630_031441_dup_20260621_032709_image.nobg.png",
"20260630_031430_dup_20260621_032709_image.nobg.png",
"20260630_031419_dup_20260621_032709_image.nobg.png",
"20260630_031408_dup_20260621_032709_image.nobg.png",
"20260630_031357_dup_20260621_032709_image.nobg.png",
"20260630_031346_dup_20260621_032709_image.nobg.png",
"20260630_031335_dup_20260621_032709_image.nobg.png",
"20260630_031324_dup_20260621_032709_image.nobg.png",
"20260630_031313_dup_20260621_032709_image.nobg.png",
"20260630_031302_dup_20260621_032709_image.nobg.png",
"20260630_031251_dup_20260621_032709_image.nobg.png",
"20260630_031240_dup_20260621_032709_image.nobg.png",
"20260630_031229_dup_20260621_032709_image.nobg.png",
"20260630_031218_dup_20260621_032709_image.nobg.png",
"20260630_031207_dup_20260621_032709_image.nobg.png",
"20260630_031156_dup_20260621_032709_image.nobg.png",
"20260630_031145_dup_20260621_032709_image.nobg.png",
"20260630_031134_dup_20260621_032709_image.nobg.png",
"20260630_031123_dup_20260621_032709_image.nobg.png",
"20260628_134529_dup_20260621_032709_image.nobg.png",
"20260630_031014_dup_20260621_032709_image.nobg.png",
"20260630_031004_dup_20260621_032709_image.nobg.png",
"20260630_030953_dup_20260621_032709_image.nobg.png",
"20260630_030942_dup_20260621_032709_image.nobg.png",
"20260630_030836_image.png",
"20260630_030824_image.png",
"20260630_030813_image.png",
"20260630_030802_image.png",
"20260630_030750_image.png",
"20260630_030739_image.png",
"20260630_030728_image.png",
"20260630_030717_image.png",
"20260630_030705_image.png",
"20260630_030654_image.png",
"20260630_030643_image.png",
"20260630_030632_image.png",
"20260630_030622_image.png",
"20260630_030611_image.png",
"20260630_024238_image.nobg.png",
"20260630_024227_image.nobg.png",
"20260630_024217_image.nobg.png",
"20260630_023627_view_000_000deg.png",
"20260630_023616_view_000_000deg.png",
"20260630_023605_view_000_000deg.png",
"20260630_023542_view_000_000deg.png",
"20260630_023519_view_000_000deg.png",
"20260630_023508_view_000_000deg.png",
"20260630_023457_view_000_000deg.png",
"20260630_023445_view_000_000deg.png",
"20260630_023434_view_000_000deg.png",
"20260630_023423_view_000_000deg.png",
"20260630_023411_view_000_000deg.png",
"20260630_023359_view_000_000deg.png",
"20260630_023348_view_000_000deg.png",
"20260630_023325_view_000_000deg.png",
"20260630_023314_view_000_000deg.png",
"20260630_023303_view_000_000deg.png",
"20260630_023252_view_000_000deg.png",
"20260630_023241_view_000_000deg.png",
"20260630_023230_view_000_000deg.png",
"20260630_022941_image.nobg.png",
"20260630_022941_image.png",
"20260620_152017_image.png",
"20260630_022002_view_000_000deg.png",
"20260630_021951_view_000_000deg.png",
"20260630_021940_view_000_000deg.png",
"20260630_021929_view_000_000deg.png",
"20260630_021906_view_000_000deg.png",
"20260630_021855_view_000_000deg.png",
"20260630_021844_view_000_000deg.png",
"20260630_021833_view_000_000deg.png",
"20260630_021821_view_000_000deg.png",
"20260630_021810_view_000_000deg.png",
@@ -2912,7 +2995,6 @@
"_turntable/cg_74544975/views/20260628_140758_view_000_000deg.png",
"up_3a05a2de_face.png",
"up_aa1add4d_face.png",
"20260628_134529_dup_20260621_032709_image.nobg.png",
"_turntable/cg_7ec17537/views/20260628_135858_dup_20260628_035257_dup_20260628_033600_dup_view_000_000deg.nobg.png",
"cg_7ec17537_face.png",
"20260628_134529_dup_20260621_032709_image.png",
@@ -6705,7 +6787,6 @@
"20260621_231051_image.png",
"20260621_231005_image.png",
"20260618_011539_20260617_133129_img_77.png",
"20260620_152017_image.png",
"20260618_013452_out4.png",
"20260620_025959_out4.png",
"20260621_212650_image.png",
@@ -7685,6 +7766,7 @@
let _sbGenJobPollTimer= null;
let _followLatestGid = null; // set to gid after generation to auto-jump to newest image
let _followLatestFilename = null;
let _highlightFilename = null; // visual highlight for newly generated item
let _slideshowActive = false;
let _slideshowTimer = null;
let _slideshowInterval= 4000;
@@ -7827,6 +7909,16 @@
}
function getRepresentativeLabel(n) {
// Priority 1: Pose Name
if (filePoses[n]) {
return filePoses[n];
}
// Priority 2: Custom Prompt Sign (prompt exists but no standard pose)
if (filePrompts[n]) {
return '✎ Custom';
}
if (isOrbitFile(n)) {
const m = n.match(/_(\d+)deg/i) || n.match(/(\d+)deg/i) || n.match(/view_(\d+)/i);
if (m) {
@@ -8984,6 +9076,10 @@
const act = i === lbIdx ? ' active' : '';
const isSel = _selectedFilenames.has(n);
const selCls = isSel ? ' selected' : '';
const isOrb = isOrbitFile(n);
const orbCls = isOrb ? ' is-orbit' : '';
const isNew = n === _highlightFilename;
const newCls = isNew ? ' is-new' : '';
// Badge: Generate uses _sbRefIndices order; Scenery uses positional slots.
const badge = _filmstripRefBadge(i);
const refCls = badge > 0 ? ' ref-selected' : '';
@@ -8993,7 +9089,7 @@
? ' draggable="true" ondragstart="sceneFilmDragStart(event,' + i + ')"'
: ' draggable="true" ondragstart="filmstripThumbDragStart(event,\'' + n.replace(/'/g, "\\'") + '\')"';
const titleStr = _multiSelectModeActive ? 'Click to select' : 'Click to view · Shift+Click to add as ref';
return '<div class="lb-var-thumb' + act + refCls + selCls + '" onclick="sbFilmstripClick(event,' + i + ')"' + dragAttr + ' title="' + titleStr + '">'
return '<div class="lb-var-thumb' + act + refCls + selCls + orbCls + newCls + '" onclick="sbFilmstripClick(event,' + i + ')"' + dragAttr + ' title="' + titleStr + '">'
+ '<img src="' + thumbSrc + '" loading="lazy" onerror="this.style.opacity=\'0.3\'">'
+ (isVideo(n) ? '<div class="lb-var-play">▶</div>' : '')
+ (pose ? '<div class="lb-var-pose">' + escHtml(pose) + '</div>' : '')
@@ -11440,21 +11536,6 @@
const visibleIdx = names.map((n, i) => i).filter(i => !fileHidden[names[i]]);
groupData.set(gid, { urls, names, visibleIdx });
// Auto-follow: if a generation just finished for this group, jump to the image
if (_followLatestFilename && names.includes(_followLatestFilename) && _isStudioOpen() && lbCurrentGid === gid) {
lbIdx = names.indexOf(_followLatestFilename);
_followLatestFilename = null;
_followLatestGid = null;
lbUrls = urls;
lbNames = names;
updateStudio();
} else if (!_followLatestFilename && _followLatestGid === gid && _isStudioOpen() && lbCurrentGid === gid && names.length > 0) {
_followLatestGid = null;
lbIdx = names.length - 1;
lbUrls = urls;
lbNames = names;
updateStudio();
}
const isNew = gf.some(f => newFileNames.has(f.cleanName));
const isRecent = gIdx < 3;
@@ -11563,20 +11644,87 @@
fresh.urls = mergedUrls;
fresh.visibleIdx = fresh.names.map((_, idx) => idx).filter(idx => !fileHidden[fresh.names[idx]]);
lbUrls = mergedUrls;
lbNames = mergedNames;
const newIdx = lbNames.indexOf(curName);
if (newIdx >= 0) {
lbIdx = newIdx;
} else if (lbIdx >= lbNames.length) {
lbIdx = lbNames.length - 1;
// Now, handle auto-follow logic inside the open studio and current group context!
let targetFname = null;
if (_followLatestFilename && mergedNames.includes(_followLatestFilename)) {
targetFname = _followLatestFilename;
_followLatestFilename = null;
_followLatestGid = null;
} else if (!_followLatestFilename && _followLatestGid === lbCurrentGid && mergedNames.length > 0) {
targetFname = mergedNames[mergedNames.length - 1];
_followLatestGid = null;
}
if (targetFname) {
_highlightFilename = targetFname;
// Find the appropriate tab for targetFname
let targetTab = _activeFilmstripTab;
const isVid = isVideo(targetFname) || fileContentType[targetFname] === 'video';
const isOrb = isOrbitFile(targetFname);
const isHidden = !!fileHidden[targetFname];
const isSource = !!fileIsSource[targetFname];
const isArchived = !!fileArchived[targetFname];
let isVisibleInCurrentTab = false;
if (_activeFilmstripTab === 'group') {
isVisibleInCurrentTab = !isArchived;
} else if (_activeFilmstripTab === 'active') {
isVisibleInCurrentTab = !isHidden && !isSource && !isArchived && !isVid && !isOrb;
} else if (_activeFilmstripTab === 'video') {
isVisibleInCurrentTab = isVid && !isArchived;
} else if (_activeFilmstripTab === 'orbit') {
isVisibleInCurrentTab = isOrb && !isArchived;
} else if (_activeFilmstripTab === 'hidden') {
isVisibleInCurrentTab = isHidden && !isArchived;
} else if (_activeFilmstripTab === 'source') {
isVisibleInCurrentTab = isSource && !isArchived;
} else if (_activeFilmstripTab === 'archived') {
isVisibleInCurrentTab = isArchived;
}
if (!isVisibleInCurrentTab) {
if (isArchived) targetTab = 'archived';
else if (isVid) targetTab = 'video';
else if (isOrb) targetTab = 'orbit';
else if (isHidden) targetTab = 'hidden';
else if (isSource) targetTab = 'source';
else targetTab = 'active';
}
// Switch to the correct tab. switchFilmstripTab will update lbNames/lbUrls, highlight tab UI, and call updateStudio().
switchFilmstripTab(targetTab);
// Locate and select targetFname in the newly loaded tab list
const targetIdx = lbNames.indexOf(targetFname);
if (targetIdx !== -1) {
lbIdx = targetIdx;
} else {
lbIdx = 0;
}
updateStudio();
// Clear highlight after 10 seconds
const hfn = _highlightFilename;
setTimeout(() => { if (_highlightFilename === hfn) { _highlightFilename = null; updateStudio(); } }, 10000);
} else {
// Regular reload sync: update lbNames and lbUrls filtered by the currently active tab
const activeImageToPreserve = curName;
switchFilmstripTab(_activeFilmstripTab);
// Overwrite switchFilmstripTab's selection if the image is still in this tab, otherwise fallback is already done
const preservedIdx = lbNames.indexOf(activeImageToPreserve);
if (preservedIdx !== -1) {
lbIdx = preservedIdx;
}
updateStudio();
}
// Re-map multi-ref selections to new positions by filename
_sbRefIndices = oldRefNames
.map(n => lbNames.indexOf(n))
.filter(i => i >= 0);
updateStudio();
}
}