with '#' will be ignored, and an empty message aborts the commit. On branch main Initial commit Changes to be committed: new file: .DS_Store new file: .env new file: .gitignore new file: ai-worker/Dockerfile new file: ai-worker/requirements.txt new file: ai-worker/worker.py new file: background-worker/Dockerfile new file: background-worker/go.mod new file: background-worker/go.sum new file: background-worker/main.go new file: background-worker/market.go new file: background-worker/rmv.go new file: background-worker/rss.go new file: background-worker/sql_work.go new file: db/Dockerfile new file: db/init.sql new file: docker-compose.yml new file: server-app/dockerfile new file: server-app/go.mod new file: server-app/go.sum new file: server-app/main.go new file: volumes/.DS_Store new file: volumes/db-init/.DS_Store new file: volumes/db-init/data/news_rss_feeds.csv new file: volumes/web/.DS_Store new file: volumes/web/static/css/blog.css new file: volumes/web/static/css/index-lite.css new file: volumes/web/static/css/index.css new file: volumes/web/static/css/mandelbrot.css new file: volumes/web/static/img/minecraft.png new file: volumes/web/static/js/blog.js new file: volumes/web/static/js/index-lite.js new file: volumes/web/static/js/index.js new file: volumes/web/static/js/mandelbrot.js new file: volumes/web/static/media/cantina.mp3 new file: volumes/web/static/media/countdowns.json new file: volumes/web/static/media/gong.mp4 new file: volumes/web/template/blog.html new file: volumes/web/template/index-lite.html new file: volumes/web/template/index.html new file: volumes/web/template/mandelbrot.html
90 lines
2.1 KiB
JavaScript
90 lines
2.1 KiB
JavaScript
const grid = document.getElementById("grid");
|
|
|
|
function createTile(artikel) {
|
|
const tile = document.createElement("div");
|
|
tile.className = "tile";
|
|
|
|
const img = document.createElement("img");
|
|
img.src = artikel.image;
|
|
img.alt = artikel.title || "Artikelbild";
|
|
tile.appendChild(img);
|
|
|
|
const overlay = document.createElement("div");
|
|
overlay.className = "overlay";
|
|
|
|
const title = document.createElement("h3");
|
|
title.textContent = artikel.title || "Ohne Titel";
|
|
overlay.appendChild(title);
|
|
|
|
tile.appendChild(overlay);
|
|
|
|
tile.addEventListener("click", () => tile.classList.toggle("open"));
|
|
return tile;
|
|
}
|
|
|
|
async function ladeGalerie() {
|
|
grid.innerHTML = "";
|
|
let foundAny = false;
|
|
|
|
try {
|
|
const res = await fetch("/api/images", {
|
|
headers: { "Accept": "application/x-ndjson" }
|
|
});
|
|
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
if (!res.body) throw new Error("Streaming nicht unterstützt");
|
|
|
|
const reader = res.body.getReader();
|
|
const decoder = new TextDecoder("utf-8");
|
|
let buffer = "";
|
|
|
|
while (true) {
|
|
const { value, done } = await reader.read();
|
|
if (done) break;
|
|
|
|
buffer += decoder.decode(value, { stream: true });
|
|
|
|
const lines = buffer.split("\n");
|
|
buffer = lines.pop() ?? "";
|
|
|
|
for (const line of lines) {
|
|
const s = line.trim();
|
|
if (!s) continue;
|
|
|
|
let artikel;
|
|
try {
|
|
artikel = JSON.parse(s);
|
|
} catch {
|
|
continue;
|
|
}
|
|
|
|
if (artikel?.image) {
|
|
grid.appendChild(createTile(artikel));
|
|
foundAny = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Rest verarbeiten
|
|
const last = buffer.trim();
|
|
if (last) {
|
|
try {
|
|
const artikel = JSON.parse(last);
|
|
if (artikel?.image) {
|
|
grid.appendChild(createTile(artikel));
|
|
foundAny = true;
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
if (!foundAny) {
|
|
grid.innerHTML = '<div class="empty">Keine Bilder gefunden.</div>';
|
|
}
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
grid.innerHTML = '<div class="empty">Fehler beim Laden der Galerie.</div>';
|
|
}
|
|
}
|
|
|
|
ladeGalerie(); |