This commit is contained in:
th committed 2026-04-07 21:58:45 +02:00
1 parent a9603aa0e8
commit 719f9d51ff
13 files changed
+625 -70

No files matched your search

+53 -30
View File
@@ -73,16 +73,8 @@ export async function openGallery() {
if (orphaned.length) {
html += `<div class="col-span-full font-pixel text-[10px] text-t-danger flex items-center gap-1.5 pt-2"><i class="ph ph-warning text-xs"></i>orphaned (not used by any card)</div>`;
html += orphaned.map(f => `
<div class="gallery-item group relative" data-orphan="${f.name}">
<div class="gallery-item group relative cursor-pointer" data-orphan="${f.name}">
${mediaTile(f.url, 'border-t-danger/30')}
<div class="absolute top-1 right-1 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
<button class="w-6 h-6 rounded bg-t-accent text-t-bg flex items-center justify-center text-xs" data-create="${f.url}" title="create card">
<i class="ph ph-plus"></i>
</button>
<button class="w-6 h-6 rounded bg-t-danger text-t-bg flex items-center justify-center text-xs" data-del="${f.name}" title="delete">
<i class="ph ph-trash"></i>
</button>
</div>
<div class="mt-1 font-pixel text-[8px] text-t-dim truncate">${esc(f.name)}</div>
</div>`).join('');
}
@@ -113,27 +105,13 @@ export async function openGallery() {
});
});
// Orphan: create card from image
grid.querySelectorAll('[data-create]').forEach(btn => {
btn.addEventListener('click', async e => {
e.stopPropagation();
const url = btn.dataset.create;
const name = url.split('/').pop().replace(/\.[^.]+$/, '');
await api('api/cards', { method: 'POST', body: { title: name, body: `![${name}](${url})`, color: '#38bdf8', position: -1 } });
await window._reloadAll();
openGallery(); // refresh
});
});
// Orphan: delete
grid.querySelectorAll('[data-del]').forEach(btn => {
btn.addEventListener('click', async e => {
e.stopPropagation();
const name = btn.dataset.del;
const ok = await showDialog({ title: 'delete_image', message: `"${name}" loeschen?`, danger: true, okLabel: 'delete' });
if (!ok) return;
await fetch(`api/uploads/${name}`, { method: 'DELETE', headers: { 'X-CSRF-Token': getCsrf() } });
openGallery(); // refresh
// Orphan: click to enlarge
grid.querySelectorAll('[data-orphan]').forEach(item => {
item.addEventListener('click', e => {
if (e.target.closest('button')) return;
const name = item.dataset.orphan;
const f = orphaned.find(o => o.name === name);
if (f && !isAudio(f.url)) openOrphanLightbox(f);
});
});
}
@@ -141,6 +119,51 @@ export async function openGallery() {
el.classList.add('open');
}
function openOrphanLightbox(file) {
let overlay = document.querySelector('.orphan-lightbox');
if (overlay) overlay.remove();
overlay = document.createElement('div');
overlay.className = 'orphan-lightbox';
overlay.style.cssText = 'position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;background:rgba(2,6,23,0.92);';
overlay.innerHTML = `
<img src="${file.url}" style="max-width:min(92vw,1400px);max-height:85vh;object-fit:contain;border:1px solid var(--t-border);box-shadow:0 16px 60px rgba(0,0,0,0.55);">
<div style="position:fixed;bottom:24px;left:50%;transform:translateX(-50%);display:flex;gap:8px;">
<button class="orphan-lb-create flex items-center gap-1.5 px-3 py-1.5 text-xs border border-t-accent text-t-accent hover:bg-t-accent hover:text-t-bg transition-colors" style="border-radius:4px;">
<i class="ph ph-plus text-sm"></i><span class="font-pixel text-[10px]">new card</span>
</button>
<button class="orphan-lb-delete flex items-center gap-1.5 px-3 py-1.5 text-xs border border-t-danger text-t-danger hover:bg-t-danger hover:text-t-bg transition-colors" style="border-radius:4px;">
<i class="ph ph-trash text-sm"></i><span class="font-pixel text-[10px]">delete</span>
</button>
</div>
<button style="position:fixed;top:12px;right:12px;color:rgba(255,255,255,0.6);font-size:20px;background:none;border:none;cursor:pointer;" class="orphan-lb-close">
<i class="ph ph-x"></i>
</button>
`;
const close = () => overlay.remove();
overlay.addEventListener('click', e => { if (e.target === overlay) close(); });
overlay.querySelector('.orphan-lb-close').addEventListener('click', close);
overlay.querySelector('.orphan-lb-create').addEventListener('click', async () => {
const name = file.url.split('/').pop().replace(/\.[^.]+$/, '');
await api('api/cards', { method: 'POST', body: { title: name, body: `![${name}](${file.url})`, color: '#38bdf8', position: -1 } });
await window._reloadAll();
close();
openGallery();
});
overlay.querySelector('.orphan-lb-delete').addEventListener('click', async () => {
const ok = await showDialog({ title: 'delete_image', message: `"${file.name}" loeschen?`, danger: true, okLabel: 'delete' });
if (!ok) return;
await fetch(`api/uploads/${file.name}`, { method: 'DELETE', headers: { 'X-CSRF-Token': getCsrf() } });
close();
openGallery();
});
document.body.appendChild(overlay);
}
export function closeGallery() {
$('gallery')?.classList.remove('open');
}