feat: unified sort overview with n.i.O./i.O. badges, sortable by filename
This commit is contained in:
101
index.html
101
index.html
@@ -133,8 +133,8 @@
|
||||
|
||||
<!-- Review -->
|
||||
<div id="view-review" class="view card">
|
||||
<h2 style="margin-bottom: 0.5rem;">Vorschau aussortierter Fotos</h2>
|
||||
<p style="color: #888; font-size: 0.85rem; margin-bottom: 1rem;">Klicke "Behalten", um ein Foto von der Liste zu entfernen.</p>
|
||||
<h2 style="margin-bottom: 0.5rem;">Sortierübersicht</h2>
|
||||
<p style="color: #888; font-size: 0.85rem; margin-bottom: 1rem;">Alle Fotos auf einen Blick — klicke auf ein Vorschaubild zum Vergrößern oder ändere die Entscheidung per Button.</p>
|
||||
<div id="review-list"></div>
|
||||
<button class="primary" id="confirm-btn">Alle bestaetigen & verschieben</button>
|
||||
</div>
|
||||
@@ -264,20 +264,20 @@
|
||||
const list = el("review-list");
|
||||
list.textContent = "";
|
||||
|
||||
// --- Aussortierte Fotos ---
|
||||
if (analysisResults.length > 0) {
|
||||
const div = document.createElement("div");
|
||||
div.className = "section-divider";
|
||||
div.textContent = "Aussortieren (" + analysisResults.length + ")";
|
||||
list.appendChild(div);
|
||||
}
|
||||
// Alle Fotos zusammenführen und nach Dateiname sortieren
|
||||
const flaggedMap = {};
|
||||
analysisResults.forEach((item, idx) => { flaggedMap[item.path] = { item, idx }; });
|
||||
|
||||
analysisResults.forEach((item, idx) => {
|
||||
const name = item.path.split("/").pop();
|
||||
const allEntries = [
|
||||
...analysisResults.map((item, idx) => ({ path: item.path, flagged: true, reasons: item.reasons, idx })),
|
||||
...okPaths.map(path => ({ path, flagged: false, reasons: [], idx: null })),
|
||||
].sort((a, b) => a.path.split("/").pop().localeCompare(b.path.split("/").pop()));
|
||||
|
||||
allEntries.forEach(entry => {
|
||||
const name = entry.path.split("/").pop();
|
||||
const row = document.createElement("div");
|
||||
row.className = "photo-item";
|
||||
row.id = "item-" + idx;
|
||||
if (entry.idx !== null) row.id = "item-" + entry.idx;
|
||||
|
||||
const info = document.createElement("div");
|
||||
info.className = "photo-info";
|
||||
@@ -287,76 +287,57 @@
|
||||
nameEl.textContent = name;
|
||||
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "badge-reject";
|
||||
badge.textContent = "aussortieren";
|
||||
badge.className = entry.flagged ? "badge-reject" : "badge-ok";
|
||||
badge.textContent = entry.flagged ? "n.i.O." : "i.O.";
|
||||
nameEl.appendChild(badge);
|
||||
|
||||
info.appendChild(nameEl);
|
||||
|
||||
if (entry.reasons.length > 0) {
|
||||
const reasonsEl = document.createElement("div");
|
||||
reasonsEl.className = "photo-reasons";
|
||||
reasonsEl.textContent = item.reasons.join(", ");
|
||||
|
||||
info.appendChild(nameEl);
|
||||
reasonsEl.textContent = entry.reasons.join(", ");
|
||||
info.appendChild(reasonsEl);
|
||||
}
|
||||
|
||||
const btn = document.createElement("button");
|
||||
btn.className = "keep-btn";
|
||||
btn.textContent = "Behalten";
|
||||
btn.textContent = entry.flagged ? "Behalten" : "Aussortieren";
|
||||
btn.addEventListener("click", () => {
|
||||
row.classList.toggle("kept");
|
||||
const isKept = row.classList.contains("kept");
|
||||
btn.textContent = isKept ? "Aussortieren" : "Behalten";
|
||||
badge.textContent = isKept ? "i.O." : "aussortieren";
|
||||
badge.className = isKept ? "badge-ok" : "badge-reject";
|
||||
entry.flagged = !entry.flagged;
|
||||
badge.className = entry.flagged ? "badge-reject" : "badge-ok";
|
||||
badge.textContent = entry.flagged ? "n.i.O." : "i.O.";
|
||||
btn.textContent = entry.flagged ? "Behalten" : "Aussortieren";
|
||||
// Sync mit analysisResults für doMove
|
||||
if (entry.idx !== null) {
|
||||
row.classList.toggle("kept", !entry.flagged);
|
||||
} else {
|
||||
// Manuell zum Aussortieren markiert
|
||||
row.id = "manual-" + entry.path;
|
||||
}
|
||||
});
|
||||
|
||||
row.appendChild(makeThumb(item.path, name));
|
||||
row.appendChild(makeThumb(entry.path, name));
|
||||
row.appendChild(info);
|
||||
row.appendChild(btn);
|
||||
list.appendChild(row);
|
||||
});
|
||||
|
||||
// --- i.O. Fotos ---
|
||||
if (okPaths.length > 0) {
|
||||
const div = document.createElement("div");
|
||||
div.className = "section-divider";
|
||||
div.textContent = "Behalten – i.O. (" + okPaths.length + ")";
|
||||
list.appendChild(div);
|
||||
|
||||
okPaths.forEach(path => {
|
||||
const name = path.split("/").pop();
|
||||
const row = document.createElement("div");
|
||||
row.className = "photo-item";
|
||||
|
||||
const info = document.createElement("div");
|
||||
info.className = "photo-info";
|
||||
|
||||
const nameEl = document.createElement("div");
|
||||
nameEl.className = "photo-name";
|
||||
nameEl.textContent = name;
|
||||
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "badge-ok";
|
||||
badge.textContent = "i.O.";
|
||||
nameEl.appendChild(badge);
|
||||
|
||||
info.appendChild(nameEl);
|
||||
row.appendChild(makeThumb(path, name));
|
||||
row.appendChild(info);
|
||||
list.appendChild(row);
|
||||
});
|
||||
}
|
||||
// Für doMove: manuelle Auswahl über allEntries tracken
|
||||
list._allEntries = allEntries;
|
||||
}
|
||||
|
||||
// --- Confirm & Move ---
|
||||
el("confirm-btn").addEventListener("click", () => doMove(false));
|
||||
|
||||
async function doMove(skipReview = true) {
|
||||
const toMove = skipReview
|
||||
? analysisResults.map(r => r.path)
|
||||
: analysisResults.filter((_, idx) => {
|
||||
const row = el("item-" + idx);
|
||||
return row && !row.classList.contains("kept");
|
||||
}).map(r => r.path);
|
||||
let toMove;
|
||||
if (skipReview) {
|
||||
toMove = analysisResults.map(r => r.path);
|
||||
} else {
|
||||
const entries = el("review-list")._allEntries || [];
|
||||
toMove = entries.filter(e => e.flagged).map(e => e.path);
|
||||
}
|
||||
|
||||
if (toMove.length === 0) {
|
||||
renderResult(0);
|
||||
|
||||
Reference in New Issue
Block a user