// ── Image gallery ──
import { $, esc, api, getCsrf } from './util.js';
import { state } from './state.js';
import { showDialog } from './dialog.js';
function getReferencedUrls() {
const urls = new Set();
for (const card of state.cards) {
const body = card.body || '';
let m;
const mdRe = /!\[[^\]]*\]\(([^)]+)\)/g;
while ((m = mdRe.exec(body)) !== null) urls.add(m[1].split(/\s/)[0]);
const htmlRe = /]+src=["']([^"']+)["'][^>]*>/gi;
while ((m = htmlRe.exec(body)) !== null) urls.add(m[1]);
}
return urls;
}
function findCardForUrl(url) {
for (const card of state.cards) {
const body = card.body || '';
if (body.includes(url)) return card;
}
return null;
}
export async function openGallery() {
const el = $('gallery');
if (!el) return;
const files = await api('api/uploads');
const referenced = getReferencedUrls();
const grid = $('gallery-grid');
const count = $('gallery-count');
const linked = [];
const orphaned = [];
for (const f of files) {
const card = findCardForUrl(f.url);
if (card) {
linked.push({ ...f, cardId: card.id, cardTitle: card.title, cardColor: card.color });
} else {
orphaned.push(f);
}
}
const total = linked.length + orphaned.length;
if (count) count.textContent = `${total} image${total !== 1 ? 's' : ''}${orphaned.length ? ` · ${orphaned.length} orphaned` : ''}`;
if (!total) {
grid.innerHTML = `
no images