feat: Add gallery management and dynamic API-based data loading
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Introduced a gallery management section in `admin.astro` for uploading, listing, and deleting gallery images. - Added dynamic fetching of events and gallery images from the backend in `index.astro`. - Updated authentication to handle gallery-related UI visibility and actions.
This commit is contained in:
@ -67,6 +67,23 @@ const title = 'Admin';
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="sec-gallery" style="display:none">
|
||||
<h2>Gallery verwalten</h2>
|
||||
<div class="events-row">
|
||||
<div class="card">
|
||||
<h3>Neues Gallery-Bild</h3>
|
||||
<label>Bild-Datei<input id="gal-file" type="file" accept="image/*" /></label>
|
||||
<label>Alt-Text<input id="gal-alt" placeholder="Bildbeschreibung" /></label>
|
||||
<button id="btn-create-gal">Bild hochladen</button>
|
||||
<div id="gal-create-msg" class="muted"></div>
|
||||
</div>
|
||||
<div class="card" style="min-width:380px;">
|
||||
<h3>Gallery-Liste</h3>
|
||||
<div id="gallery-list" class="grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="sec-publish" style="display:none">
|
||||
<h2>Veröffentlichen</h2>
|
||||
<label>Commit-Message<input id="pub-msg" placeholder="Änderungen beschreiben" value="Update events" /></label>
|
||||
@ -91,15 +108,18 @@ const title = 'Admin';
|
||||
document.getElementById('auth-status').textContent = `Angemeldet als ${me.user?.giteaUsername || 'Admin'}`;
|
||||
// UI-Bereiche für eingeloggte Nutzer einblenden
|
||||
document.getElementById('sec-events').style.display = '';
|
||||
document.getElementById('sec-gallery').style.display = '';
|
||||
document.getElementById('sec-publish').style.display = '';
|
||||
// Direkt Events laden und auf Sektion fokussieren
|
||||
await loadEvents();
|
||||
await loadGallery();
|
||||
document.getElementById('sec-events').scrollIntoView({ behavior: 'smooth' });
|
||||
} catch (e) {
|
||||
const el = document.getElementById('auth-status');
|
||||
el.textContent = 'Nicht angemeldet';
|
||||
// Kein Auto-Redirect, damit keine Schleife entsteht. Login-Button verwenden.
|
||||
document.getElementById('sec-events').style.display = 'none';
|
||||
document.getElementById('sec-gallery').style.display = 'none';
|
||||
document.getElementById('sec-publish').style.display = 'none';
|
||||
}
|
||||
}
|
||||
@ -293,6 +313,59 @@ const title = 'Admin';
|
||||
} catch(e){ msg.textContent = 'Fehler: '+e.message }
|
||||
});
|
||||
|
||||
// ========== Gallery ==========
|
||||
async function loadGallery() {
|
||||
const listEl = document.getElementById('gallery-list');
|
||||
listEl.innerHTML = '<div class="muted">Lade...</div>';
|
||||
try {
|
||||
const data = await api('/api/gallery');
|
||||
listEl.innerHTML = '';
|
||||
const galleryImages = (data.images || []).slice();
|
||||
galleryImages.sort((a,b) => (a.displayOrder??0) - (b.displayOrder??0));
|
||||
|
||||
galleryImages.forEach((img) => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card';
|
||||
card.innerHTML = `
|
||||
<img src="${API_BASE}${img.imageUrl}" alt="${img.altText}" class="thumb" />
|
||||
<div class="muted">${img.altText || ''}</div>
|
||||
<div class="row-buttons">
|
||||
<button data-id="${img.id}" class="btn-del-gal">Löschen</button>
|
||||
</div>`;
|
||||
listEl.appendChild(card);
|
||||
});
|
||||
listEl.querySelectorAll('.btn-del-gal').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = btn.getAttribute('data-id');
|
||||
if (!id) return;
|
||||
if (!confirm('Bild wirklich löschen?')) return;
|
||||
try { await api(`/api/gallery/${id}`, { method: 'DELETE' }); await loadGallery(); } catch(e){ alert('Fehler: '+e.message); }
|
||||
})
|
||||
})
|
||||
} catch (e) {
|
||||
listEl.innerHTML = '<div class="muted">Fehler beim Laden</div>';
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('btn-create-gal').addEventListener('click', async () => {
|
||||
const file = /** @type {HTMLInputElement} */ (document.getElementById('gal-file')).files[0];
|
||||
const alt = (document.getElementById('gal-alt')).value.trim();
|
||||
const msg = document.getElementById('gal-create-msg');
|
||||
if (!file) {
|
||||
msg.textContent = 'Bitte Datei auswählen';
|
||||
return;
|
||||
}
|
||||
msg.textContent = 'Lade Bild hoch...';
|
||||
try {
|
||||
await uploadGalleryImage(file, alt);
|
||||
msg.textContent = 'Bild hochgeladen';
|
||||
(document.getElementById('gal-file')).value = '';
|
||||
(document.getElementById('gal-alt')).value = '';
|
||||
await loadGallery();
|
||||
} catch(e){ msg.textContent = 'Fehler: '+e.message }
|
||||
});
|
||||
|
||||
refreshAuth();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@ -8,14 +8,39 @@ import ImageCarousel from "../components/ImageCarousel.astro";
|
||||
import Contact from "../components/Contact.astro";
|
||||
import About from "../components/About.astro";
|
||||
|
||||
const events = [
|
||||
const API_BASE = 'https://cms.gallus-pub.ch';
|
||||
|
||||
];
|
||||
// Fetch events from backend API
|
||||
let events = [];
|
||||
try {
|
||||
const eventsResponse = await fetch(`${API_BASE}/api/events/public`);
|
||||
if (eventsResponse.ok) {
|
||||
const eventsData = await eventsResponse.json();
|
||||
events = (eventsData.events || []).map((ev: any) => ({
|
||||
image: `${API_BASE}${ev.imageUrl}`,
|
||||
title: ev.title,
|
||||
date: ev.date,
|
||||
description: ev.description
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch events:', error);
|
||||
}
|
||||
|
||||
const images = [
|
||||
{ src: "/static/images/gallery/miyma9zc-8he1di.webp", alt: "Schwarzes bild" },
|
||||
{ src: "/static/images/gallery/miyrhqng-i2kgtx.webp", alt: "test" }
|
||||
];
|
||||
// Fetch gallery images from backend API
|
||||
let images = [];
|
||||
try {
|
||||
const galleryResponse = await fetch(`${API_BASE}/api/gallery/public`);
|
||||
if (galleryResponse.ok) {
|
||||
const galleryData = await galleryResponse.json();
|
||||
images = (galleryData.images || []).map((img: any) => ({
|
||||
src: `${API_BASE}${img.imageUrl}`,
|
||||
alt: img.altText
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch gallery:', error);
|
||||
}
|
||||
---
|
||||
|
||||
<Layout>
|
||||
|
||||
Reference in New Issue
Block a user