feat: thumbnail picker custom per selezione modello/scena
- GET /folder_image/{filename}?w=N: PNG ridotto cache 1h
- Frontend: 2 thumb-picker al posto dei select (thumb + nome + caret)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+51
-17
@@ -80,18 +80,56 @@ async function fetchImagesList() {
|
||||
return await r.json();
|
||||
}
|
||||
|
||||
function populateSelect(selectEl, files) {
|
||||
selectEl.innerHTML = "";
|
||||
const opt0 = document.createElement("option");
|
||||
opt0.value = ""; opt0.textContent = "-- seleziona --";
|
||||
selectEl.appendChild(opt0);
|
||||
for (const f of files) {
|
||||
const o = document.createElement("option");
|
||||
o.value = f; o.textContent = f;
|
||||
selectEl.appendChild(o);
|
||||
}
|
||||
function buildThumbPicker(pickerId, files, onSelect) {
|
||||
const picker = document.getElementById(pickerId);
|
||||
const current = picker.querySelector(".picker-current");
|
||||
const list = picker.querySelector(".picker-list");
|
||||
const text = current.querySelector(".picker-text");
|
||||
// Rimuovi eventuale vecchia thumbnail
|
||||
const oldImg = current.querySelector("img");
|
||||
if (oldImg) oldImg.remove();
|
||||
list.innerHTML = "";
|
||||
|
||||
files.forEach((f) => {
|
||||
const item = document.createElement("div");
|
||||
item.className = "picker-item";
|
||||
const img = document.createElement("img");
|
||||
img.src = `/folder_image/${encodeURIComponent(f)}?w=120`;
|
||||
img.loading = "lazy";
|
||||
const name = document.createElement("span");
|
||||
name.className = "name"; name.textContent = f;
|
||||
item.appendChild(img); item.appendChild(name);
|
||||
item.addEventListener("click", () => {
|
||||
// Aggiorna la visual del "current"
|
||||
let thumb = current.querySelector("img");
|
||||
if (!thumb) {
|
||||
thumb = document.createElement("img");
|
||||
current.insertBefore(thumb, text);
|
||||
}
|
||||
thumb.src = `/folder_image/${encodeURIComponent(f)}?w=80`;
|
||||
text.textContent = f;
|
||||
picker.classList.remove("open");
|
||||
onSelect(f);
|
||||
});
|
||||
list.appendChild(item);
|
||||
});
|
||||
|
||||
current.onclick = () => {
|
||||
// Chiudi altri picker aperti
|
||||
document.querySelectorAll(".thumb-picker.open")
|
||||
.forEach((p) => { if (p !== picker) p.classList.remove("open"); });
|
||||
picker.classList.toggle("open");
|
||||
};
|
||||
}
|
||||
|
||||
// Close picker on outside click
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!e.target.closest(".thumb-picker")) {
|
||||
document.querySelectorAll(".thumb-picker.open")
|
||||
.forEach((p) => p.classList.remove("open"));
|
||||
}
|
||||
});
|
||||
|
||||
function loadImage(src) {
|
||||
return new Promise((res, rej) => {
|
||||
const img = new Image();
|
||||
@@ -310,19 +348,15 @@ function setStatus(s) {
|
||||
window.addEventListener("DOMContentLoaded", async () => {
|
||||
buildAdvancedForm();
|
||||
setupROI();
|
||||
// Popola dropdown immagini da IMAGES_DIR
|
||||
// Popola picker immagini da IMAGES_DIR (con thumbnail)
|
||||
const {files, dir} = await fetchImagesList();
|
||||
const selM = document.getElementById("sel-model");
|
||||
const selS = document.getElementById("sel-scene");
|
||||
populateSelect(selM, files);
|
||||
populateSelect(selS, files);
|
||||
buildThumbPicker("picker-model", files, onSelectModel);
|
||||
buildThumbPicker("picker-scene", files, onSelectScene);
|
||||
if (files.length === 0) {
|
||||
setStatus(`Nessuna immagine in ${dir} (configura IMAGES_DIR in .env)`);
|
||||
} else {
|
||||
setStatus(`${files.length} immagini disponibili in ${dir}`);
|
||||
}
|
||||
selM.addEventListener("change", (e) => onSelectModel(e.target.value));
|
||||
selS.addEventListener("change", (e) => onSelectScene(e.target.value));
|
||||
document.getElementById("btn-match").addEventListener("click", doMatch);
|
||||
const slider = document.getElementById("p-min-score");
|
||||
slider.addEventListener("input", (e) => {
|
||||
|
||||
Reference in New Issue
Block a user