diff --git a/.DS_Store b/.DS_Store
index 75356a6..9bdb7f2 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/admin-server.js b/admin-server.js
index 840e446..0aab7e0 100644
--- a/admin-server.js
+++ b/admin-server.js
@@ -33,10 +33,10 @@ app.use('/images', express.static(IMAGES_DIR));
// Multer: temporärer Speicher, dann sharp übernimmt
const upload = multer({
storage: multer.memoryStorage(),
- limits: { fileSize: 20 * 1024 * 1024 },
+ limits: { fileSize: 100 * 1024 * 1024 }, // 100MB limit für Videos
fileFilter: (req, file, cb) => {
- if (file.mimetype.startsWith('image/')) cb(null, true);
- else cb(new Error('Nur Bilder erlaubt!'));
+ if (file.mimetype.startsWith('image/') || file.mimetype.startsWith('video/')) cb(null, true);
+ else cb(new Error('Nur Bilder und Videos erlaubt!'));
}
});
@@ -300,11 +300,43 @@ app.get('/api/individual-successes', (req, res) => {
const list = files.map(f => {
const c = fs.readFileSync(path.join(ERFOLGE_CONTENT_DIR, f), 'utf8');
const { data } = parseFM(c);
- return { fileName: f, title: data.title || f, rang: data.rang, image: data.image };
+ return { fileName: f, title: data.title || f, rang: data.rang, image: data.image, weight: parseInt(data.weight) || 999 };
});
+ list.sort((a, b) => a.weight - b.weight);
res.json(list);
});
+app.put('/api/individual-successes/reorder', (req, res) => {
+ const { order } = req.body;
+ if (!Array.isArray(order)) return res.status(400).json({ ok: false });
+
+ order.forEach((fileName, index) => {
+ const filePath = path.join(ERFOLGE_CONTENT_DIR, fileName);
+ if (!fs.existsSync(filePath)) return;
+
+ const content = fs.readFileSync(filePath, 'utf8');
+ const { data, content: body } = parseFM(content);
+
+ data.weight = index + 1;
+
+ let fmStr = '---\n';
+ for (const k in data) {
+ if (data[k] !== undefined && data[k] !== null) {
+ if (k === 'weight') {
+ fmStr += `${k}: ${data[k]}\n`;
+ } else {
+ fmStr += `${k}: "${data[k]}"\n`;
+ }
+ }
+ }
+ fmStr += '---\n';
+ fs.writeFileSync(filePath, fmStr + '\n' + body);
+ });
+
+ res.json({ ok: true });
+ rebuildAndDeploy();
+});
+
app.get('/api/individual-success/:file', (req, res) => {
const c = fs.readFileSync(path.join(ERFOLGE_CONTENT_DIR, req.params.file), 'utf8');
const { data, content } = parseFM(c);
@@ -315,12 +347,20 @@ app.put('/api/individual-success/:file', (req, res) => {
const filePath = path.join(ERFOLGE_CONTENT_DIR, req.params.file);
const oldContent = fs.readFileSync(filePath, 'utf8');
const { data: oldData } = parseFM(oldContent);
- const { title, rang, summary, content } = req.body;
+ const { title, rang, summary, content, ort, datum, kategorie, is_weitere_auszeichnung, image, images } = req.body;
- const newData = { ...oldData, title, rang, summary };
+ const newData = { ...oldData, title, rang, summary, ort, datum, kategorie, is_weitere_auszeichnung };
+ if (image !== undefined) newData.image = image;
+ if (images !== undefined) newData.images = images;
let fmStr = '---\n';
for (const k in newData) {
- if (newData[k]) fmStr += `${k}: "${newData[k]}"\n`;
+ if (newData[k]) {
+ if (k === 'weight') {
+ fmStr += `${k}: ${newData[k]}\n`;
+ } else {
+ fmStr += `${k}: "${newData[k]}"\n`;
+ }
+ }
}
fmStr += '---\n';
fs.writeFileSync(filePath, fmStr + '\n' + content);
@@ -328,20 +368,47 @@ app.put('/api/individual-success/:file', (req, res) => {
rebuildAndDeploy();
});
-app.post('/api/individual-success/:file/image', upload.single('image'), async (req, res) => {
+app.post('/api/individual-success/:file/images', upload.array('images', 5), async (req, res) => {
try {
const baseName = req.params.file.replace('.md', '');
- const filename = `success-${baseName}-${Date.now()}.webp`;
- await sharp(req.file.buffer)
- .resize(1000, 1000, { fit: 'inside', withoutEnlargement: true })
- .webp({ quality: 85 })
- .toFile(path.join(ERFOLGE_IMG_DIR, filename));
+ const filenames = [];
+
+ for (const file of req.files) {
+ const isVideo = file.mimetype.startsWith('video/');
+ const origExt = path.extname(file.originalname).toLowerCase();
+ const ext = isVideo ? origExt : '.webp';
+ const filename = `success-${baseName}-${Date.now()}-${Math.random().toString(36).slice(2,7)}${ext}`;
+
+ if (isVideo) {
+ fs.writeFileSync(path.join(ERFOLGE_IMG_DIR, filename), file.buffer);
+ } else {
+ await sharp(file.buffer)
+ .resize(1000, 1000, { fit: 'inside', withoutEnlargement: true })
+ .webp({ quality: 85 })
+ .toFile(path.join(ERFOLGE_IMG_DIR, filename));
+ }
+ filenames.push(filename);
+ }
// In Markdown Datei schreiben
const filePath = path.join(ERFOLGE_CONTENT_DIR, req.params.file);
const c = fs.readFileSync(filePath, 'utf8');
const { data, content } = parseFM(c);
- data.image = filename;
+
+ let existingImages = [];
+ try { existingImages = JSON.parse(req.body.existingImages || '[]'); } catch(e){}
+ const allImages = [...existingImages, ...filenames];
+
+ let mainIdx = parseInt(req.body.mainImageIndex) || 0;
+ if (mainIdx < 0 || mainIdx >= allImages.length) mainIdx = 0;
+
+ if (allImages.length > 0) {
+ data.image = allImages[mainIdx]; // Vom User gewähltes Hauptbild
+ data.images = allImages.join(',');
+ } else {
+ delete data.image;
+ delete data.images;
+ }
let fmStr = '---\n';
for (const k in data) {
@@ -350,7 +417,7 @@ app.post('/api/individual-success/:file/image', upload.single('image'), async (r
fmStr += '---\n';
fs.writeFileSync(filePath, fmStr + '\n' + content);
- res.json({ ok: true, image: filename });
+ res.json({ ok: true, images: filenames });
rebuildAndDeploy();
} catch (e) {
res.status(500).json({ ok: false, error: e.message });
diff --git a/admin.html b/admin.html
index fccbe3b..77ddbe4 100644
--- a/admin.html
+++ b/admin.html
@@ -857,7 +857,26 @@ tailwind.config = {
-...
+
+
+ edit Foto bearbeiten
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -877,6 +896,22 @@ tailwind.config = {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -889,19 +924,16 @@ tailwind.config = {
-
-
-
-
![]()
-
- image
-
-
-
-
-
-
Nichts ausgewählt
-
+
+
+
+
Keine Bilder vorhanden.
+
+
+
+
+
+
Nichts ausgewählt
@@ -925,6 +957,70 @@ tailwind.config = {
let allPhotos = [];
let allCategories = [];
let pendingFiles = [];
+
+ let esCurrentImages = [];
+ let esMainImageIndex = 0;
+ let esNewFilesSelected = false;
+
+ function renderEsImages(items) {
+ const container = document.getElementById('esImagesPreviewContainer');
+ container.innerHTML = '';
+ if (!items || items.length === 0) {
+ container.innerHTML = '
Keine Bilder vorhanden.
';
+ return;
+ }
+
+ for (let i = 0; i < items.length; i++) {
+ const item = items[i];
+ const isFile = item instanceof File;
+ const isVideo = isFile ? item.type.startsWith('video/') : item.match(/\.(mp4|webm|mov|m4v)$/i);
+ const src = isFile ? URL.createObjectURL(item) : '/erfolge-img/' + item + '?t=' + Date.now();
+
+ const div = document.createElement('div');
+ div.className = 'relative w-20 h-20 rounded-lg overflow-hidden border-4 cursor-pointer transition-all ' + (i === esMainImageIndex ? 'border-primary shadow-lg scale-105 z-10' : 'border-transparent hover:border-primary/50');
+ div.onclick = () => {
+ esMainImageIndex = i;
+ renderEsImages(items);
+ };
+
+ if (isVideo) {
+ const vid = document.createElement('video');
+ vid.src = src;
+ vid.className = 'w-full h-full object-cover';
+ vid.muted = true;
+ div.appendChild(vid);
+
+ const playIcon = document.createElement('span');
+ playIcon.className = 'material-symbols-outlined absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-white drop-shadow-md pointer-events-none';
+ playIcon.textContent = 'play_circle';
+ div.appendChild(playIcon);
+ } else {
+ const img = document.createElement('img');
+ img.src = src;
+ img.className = 'w-full h-full object-cover';
+ div.appendChild(img);
+ }
+
+ const badge = document.createElement('div');
+ badge.className = 'absolute bottom-0 left-0 right-0 bg-primary/90 text-white text-[9px] text-center font-bold py-1 z-20 ' + (i === esMainImageIndex ? 'block' : 'hidden');
+ badge.textContent = 'HAUPTBILD';
+
+ const deleteBtn = document.createElement('button');
+ deleteBtn.className = 'absolute top-1 right-1 bg-red-500 text-white rounded-full w-5 h-5 flex items-center justify-center text-[10px] shadow-md z-30 hover:bg-red-600 transition-colors';
+ deleteBtn.innerHTML = '✕';
+ deleteBtn.onclick = (e) => {
+ e.stopPropagation();
+ items.splice(i, 1);
+ if (esMainImageIndex >= items.length) esMainImageIndex = Math.max(0, items.length - 1);
+ renderEsImages(items);
+ document.getElementById('esFileStatus').textContent = items.length + ' Dateien insgesamt';
+ };
+
+ div.appendChild(badge);
+ div.appendChild(deleteBtn);
+ container.appendChild(div);
+ }
+ }
// ─── Navigation ──────────────────────────────────────────
const sections = ['overview', 'media', 'homepage', 'uebermich', 'career', 'community', 'settings'];
@@ -1886,91 +1982,170 @@ tailwind.config = {
} catch(err) { console.error('Career save error:', err); }
});
+ let individualSuccessData = [];
+
async function loadIndividualSuccesses() {
try {
const r = await fetch('/api/individual-successes');
- const list = await r.json();
- const container = document.getElementById('individualSuccessList');
- container.innerHTML = '';
- list.forEach(item => {
- const div = document.createElement('div');
- div.className = 'flex items-center justify-between bg-surface-container-low rounded-xl px-6 py-4';
- div.innerHTML = `
-
-
- description
-
-
-
${escHtml(item.title)}
-
${escHtml(item.rang || 'Bericht')}
-
-
-
- `;
- container.appendChild(div);
- });
+ individualSuccessData = await r.json();
+ renderIndividualSuccesses();
} catch(err) { console.error('Load individual successes error:', err); }
}
- async function editSuccess(fileName) {
+ function renderIndividualSuccesses() {
+ const container = document.getElementById('individualSuccessList');
+ container.innerHTML = '';
+ individualSuccessData.forEach((item, index) => {
+ const div = document.createElement('div');
+ div.className = 'flex items-center justify-between bg-surface-container-low rounded-xl px-6 py-4';
+ div.innerHTML = `
+
+
+
+
+
+
+ description
+
+
+
${escHtml(item.title)}
+
${escHtml(item.rang || 'Bericht')}
+
+
+
+ `;
+ container.appendChild(div);
+ });
+ }
+
+ window.moveSuccessUp = async function(index) {
+ if (index <= 0) return;
+ const temp = individualSuccessData[index - 1];
+ individualSuccessData[index - 1] = individualSuccessData[index];
+ individualSuccessData[index] = temp;
+ renderIndividualSuccesses();
+ await saveIndividualSuccessOrder();
+ };
+
+ window.moveSuccessDown = async function(index) {
+ if (index >= individualSuccessData.length - 1) return;
+ const temp = individualSuccessData[index + 1];
+ individualSuccessData[index + 1] = individualSuccessData[index];
+ individualSuccessData[index] = temp;
+ renderIndividualSuccesses();
+ await saveIndividualSuccessOrder();
+ };
+
+ async function saveIndividualSuccessOrder() {
+ try {
+ const order = individualSuccessData.map(item => item.fileName);
+ const res = await fetch('/api/individual-successes/reorder', {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ order })
+ });
+ if (!res.ok) throw new Error('Reorder failed');
+ } catch(err) {
+ console.error('Save order error:', err);
+ }
+ }
+
+ window.editSuccess = async function(fileName) {
try {
const r = await fetch('/api/individual-success/' + fileName);
const data = await r.json();
document.getElementById('esFileName').value = fileName;
document.getElementById('esTitle').value = data.title || '';
document.getElementById('esRang').value = data.rang || '';
+ document.getElementById('esOrt').value = data.ort || '';
+ document.getElementById('esDatum').value = data.datum || '';
+ document.getElementById('esKat').value = data.kategorie || '';
+ document.getElementById('esIsWeitere').checked = data.is_weitere_auszeichnung === 'true' || data.is_weitere_auszeichnung === true;
document.getElementById('esSummary').value = data.summary || '';
document.getElementById('esContent').value = data.content || '';
- const preview = document.getElementById('esPreview');
- const placeholder = document.getElementById('esPlaceholder');
- if (data.image) {
- preview.src = '/erfolge-img/' + data.image + '?t=' + Date.now();
- preview.classList.remove('hidden');
- placeholder.classList.add('hidden');
- } else {
- preview.classList.add('hidden');
- placeholder.classList.remove('hidden');
+ esNewFilesSelected = false;
+ document.getElementById('esFileInput').value = '';
+ document.getElementById('esFileStatus').textContent = 'Keine neuen Dateien gewählt';
+
+ let existingImages = [];
+ if (data.images) {
+ existingImages = data.images.split(',').map(s => s.trim()).filter(Boolean);
+ } else if (data.image) {
+ existingImages = [data.image];
}
- document.getElementById('esFileStatus').textContent = 'Keine neue Datei gewählt';
+ esCurrentImages = existingImages;
+ esMainImageIndex = 0;
+ if (data.image && existingImages.includes(data.image)) {
+ esMainImageIndex = existingImages.indexOf(data.image);
+ }
+
+ renderEsImages(esCurrentImages);
document.getElementById('editSuccessModal').classList.remove('hidden');
} catch(err) { console.error('Edit success error:', err); }
}
document.getElementById('esFileInput').addEventListener('change', function() {
- const file = this.files[0];
- if (file) {
- document.getElementById('esPreview').src = URL.createObjectURL(file);
- document.getElementById('esPreview').classList.remove('hidden');
- document.getElementById('esPlaceholder').classList.add('hidden');
- document.getElementById('esFileStatus').textContent = file.name;
+ const newFiles = Array.from(this.files);
+ if (esCurrentImages.length + newFiles.length > 5) {
+ alert(`Bitte maximal 5 Dateien insgesamt auswählen! (Aktuell: ${esCurrentImages.length})`);
+ this.value = '';
+ return;
}
+ if (newFiles.length > 0) {
+ esNewFilesSelected = true;
+ esCurrentImages = esCurrentImages.concat(newFiles);
+ renderEsImages(esCurrentImages);
+ document.getElementById('esFileStatus').textContent = esCurrentImages.length + ' Dateien insgesamt';
+ }
+ this.value = '';
});
document.getElementById('saveSuccessBtn').addEventListener('click', async function() {
const fileName = document.getElementById('esFileName').value;
const title = document.getElementById('esTitle').value;
const rang = document.getElementById('esRang').value;
+ const ort = document.getElementById('esOrt').value;
+ const datum = document.getElementById('esDatum').value;
+ const kategorie = document.getElementById('esKat').value;
+ const is_weitere_auszeichnung = document.getElementById('esIsWeitere').checked;
const summary = document.getElementById('esSummary').value;
const content = document.getElementById('esContent').value;
const fileInput = document.getElementById('esFileInput');
try {
+ const existingOnly = esCurrentImages.filter(x => typeof x === 'string');
+ const newFilesOnly = esCurrentImages.filter(x => x instanceof File);
+ const selectedMainImage = (newFilesOnly.length === 0 && existingOnly.length > 0) ? existingOnly[esMainImageIndex] : '';
+ const finalImagesStr = existingOnly.join(',');
+
// 1. Metadaten & Inhalt speichern
const r = await fetch('/api/individual-success/' + fileName, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ title, rang, summary, content })
+ body: JSON.stringify({
+ title, rang, ort, datum, kategorie, is_weitere_auszeichnung, summary, content,
+ image: selectedMainImage,
+ images: finalImagesStr
+ })
});
- // 2. Bild falls gewählt
- if (fileInput.files.length > 0) {
+ // 2. Bilder falls gewählt
+ if (newFilesOnly.length > 0) {
const fd = new FormData();
- fd.append('image', fileInput.files[0]);
- await fetch('/api/individual-success/' + fileName + '/image', {
+ for (let i = 0; i < newFilesOnly.length; i++) {
+ fd.append('images', newFilesOnly[i]);
+ }
+ fd.append('existingImages', JSON.stringify(existingOnly));
+ fd.append('mainImageIndex', esMainImageIndex);
+ await fetch('/api/individual-success/' + fileName + '/images', {
method: 'POST',
body: fd
});
diff --git a/content/.DS_Store b/content/.DS_Store
index 8a35b5e..f135321 100644
Binary files a/content/.DS_Store and b/content/.DS_Store differ
diff --git a/content/erfolge/dojo-champion.md b/content/erfolge/dojo-champion.md
new file mode 100644
index 0000000..e3f3c45
--- /dev/null
+++ b/content/erfolge/dojo-champion.md
@@ -0,0 +1,34 @@
+---
+title: "Dojo Champion"
+rang: "Kiai Berlin"
+date: "2024-01-15"
+summary: "Interner Titel als Dojo Champion beim Kiai Berlin."
+weight: "4"
+ort: "Entenhausen"
+datum: "2025-6"
+kategorie: "Fight"
+images: "success-dojo-champion-1778543253478-vs81l.mp4,success-dojo-champion-1778544116200-5pv3h.mp4,success-dojo-champion-1778544116201-cnz9d.webp,success-dojo-champion-1778544116302-845ro.webp,success-dojo-champion-1778544116365-61zfd.webp"
+image: "success-dojo-champion-1778543253478-vs81l.mp4"
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Ein toller Start ins Jahr! Beim internen Vereinsturnier des Kiai Berlin konnte ich mir den Titel als Dojo Champion sichern. Solche internen Wettkämpfe sind immer ein tolles Erlebnis und stärken den Zusammenhalt.
diff --git a/content/erfolge/fairness-preis.md b/content/erfolge/fairness-preis.md
new file mode 100644
index 0000000..5ecdbf5
--- /dev/null
+++ b/content/erfolge/fairness-preis.md
@@ -0,0 +1,26 @@
+---
+title: "Fairness-Preis"
+rang: "Gold"
+date: "2023-12-01"
+summary: "Auszeichnung mit dem Fairness-Preis 2023 unseres Dojos."
+weight: 1
+image: "success-fairness-preis-1778528590374.webp"
+ort: "Esslingen"
+datum: "2024-08"
+kategorie: "Wettkampf"
+is_weitere_auszeichnung: "true"
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zum Jahresabschluss 2023 wurde mir eine ganz besondere Ehre zuteil: Ich durfte den Fairness-Preis unseres Dojos entgegennehmen. Respekt und Fairness sind die Grundpfeiler des Karate, daher bedeutet mir diese Auszeichnung sehr viel.
diff --git a/content/erfolge/landesmeisterschaft-2024.md b/content/erfolge/landesmeisterschaft-2024.md
index aa66be8..7029250 100644
--- a/content/erfolge/landesmeisterschaft-2024.md
+++ b/content/erfolge/landesmeisterschaft-2024.md
@@ -1,8 +1,24 @@
---
title: "Landesmeisterschaft Berlin 2024"
rang: "Gold"
-date: 2024-11-15
+date: "2024-11-15"
summary: "Erster Platz in der Kategorie Kata U14 bei der Berliner Landesmeisterschaft. Ein unvergesslicher Moment!"
+image: "success-landesmeisterschaft-2024-1778536783289-lv750.webp"
+weight: "2"
+is_weitere_auszeichnung: "true"
+images: "success-landesmeisterschaft-2024-1778536783289-lv750.webp,success-landesmeisterschaft-2024-1778536783364-ykhep.webp,success-landesmeisterschaft-2024-1778536783524-58ch3.webp,success-landesmeisterschaft-2024-1778536783576-qd5nb.webp"
---
+
+
+
+
+
+
+
+
+
+
+
+
Es war ein langer Weg bis zur Landesmeisterschaft. Monatelang haben wir jeden Tag trainiert, die Kata immer wieder verfeinert. Und dann dieser Moment auf der Matte...
diff --git a/content/erfolge/landesmeisterschaft-platz3.md b/content/erfolge/landesmeisterschaft-platz3.md
new file mode 100644
index 0000000..52523de
--- /dev/null
+++ b/content/erfolge/landesmeisterschaft-platz3.md
@@ -0,0 +1,16 @@
+---
+title: "Landesmeisterschaft (3. Platz)"
+rang: "Bronze"
+date: "2024-05-09"
+summary: "Ein harter Wettkampf, der mit dem 3. Platz belohnt wurde. Im Sommer geht es um die Meisterschaft!"
+weight: 3
+---
+
+
+
+
+
+
+
+
+Unglaublich, dass ich das geschafft habe. Nach vielen intensiven Runden konnte ich mir den 3. Platz bei den Landesmeisterschaften sichern! Dieser Erfolg gibt mir wahnsinnig viel Motivation, denn im Sommer kämpfe ich dann um die Meisterschaft. Das Training hat sich gelohnt!
diff --git a/content/erfolge/norddeutsche-2024.md b/content/erfolge/norddeutsche-2024.md
index 348af66..fcf70b2 100644
--- a/content/erfolge/norddeutsche-2024.md
+++ b/content/erfolge/norddeutsche-2024.md
@@ -1,8 +1,16 @@
---
title: "Norddeutsche Meisterschaft 2024"
rang: "Silber"
-date: 2024-08-20
+date: "2024-08-20"
summary: "Silbermedaille beim Norddeutschen Turnier – das bisher größte Turnier, an dem ich teilgenommen habe."
+weight: 5
---
+
+
+
+
+
+
+
Über 200 Teilnehmer, drei Kampftage, und am Ende eine silberne Medaille um den Hals. Ein Riesenschritt für mich!
diff --git a/data/erfolge.json b/data/erfolge.json
index f64a61a..e78d561 100644
--- a/data/erfolge.json
+++ b/data/erfolge.json
@@ -16,23 +16,7 @@
"ort": "Berlin",
"kategorie": "U14"
},
- "weitere_auszeichnungen": [
- {
- "titel": "Norddeutsche Meisterschaft",
- "detail": "Silber – Kata 2024",
- "beschreibung": "War eine harter Fight"
- },
- {
- "titel": "Dojo Champion",
- "detail": "Kiai Berlin, intern",
- "beschreibung": ""
- },
- {
- "titel": "Fairness-Preis",
- "detail": "Dojo-Auszeichnung 2023",
- "beschreibung": ""
- }
- ],
+ "weitere_auszeichnungen": [],
"stats": [
{
"wert": "5+",
diff --git a/data/galerie.json b/data/galerie.json
index cfc67d6..5107138 100644
--- a/data/galerie.json
+++ b/data/galerie.json
@@ -6,7 +6,7 @@
"description": "Die Kunst der Disziplin durch die Linse. Von intensiven Trainingseinheiten bis zum Triumph bei Gürtelprüfungen."
},
"ribbon": {
- "heading": "Hinter der Linse",
+ "heading": "Hinter der Linse ha",
"description": "Unsere Galerie ist nicht nur Fotos – sie ist ein Zeugnis der Disziplin, die wir jeden Tag im Dojo leben.",
"stats": [
{
diff --git a/data/gallery.json b/data/gallery.json
index bd6dca4..00c135b 100644
--- a/data/gallery.json
+++ b/data/gallery.json
@@ -1,5 +1,13 @@
{
"photos": [
+ {
+ "id": "1778361895205-amw83",
+ "filename": "1778361895205-amw83.webp",
+ "thumb": "1778361895205-amw83-thumb.webp",
+ "title": "EF75AE9A-1670-46F8-AB04-798D22334E66",
+ "kategorie": "Haudrauf",
+ "datum": "2026-05-09"
+ },
{
"id": "1777571196788-em155",
"filename": "1777571196788-em155.webp",
diff --git a/layouts/.DS_Store b/layouts/.DS_Store
index 6bc5d88..066d830 100644
Binary files a/layouts/.DS_Store and b/layouts/.DS_Store differ
diff --git a/layouts/erfolge/list.html b/layouts/erfolge/list.html
index a469d1f..a370986 100644
--- a/layouts/erfolge/list.html
+++ b/layouts/erfolge/list.html
@@ -124,35 +124,87 @@
-
Alle Erfolge
-
- {{ range (where .Site.RegularPages "Section" "erfolge") }}
-
-
-
-
+
MEILENSTEINE DES ERFOLGS
+
+ {{ range (where (where .Site.RegularPages "Section" "erfolge") "Params.is_weitere_auszeichnung" "!=" "true").ByWeight }}
+
+
+ {{ if .Params.image }}
+
+
+

+
+
+ military_tech
+ {{ .Params.rang | default "Highlight" }}
+
+
+
+
+ {{ else }}
+
+
+
military_tech
{{ .Params.rang | default "Highlight" }}
-
{{ .Title }}
-
{{ .Summary }}
+ {{ end }}
+
+
+
{{ .Summary }}
+
-
-
-
-
-
+
+
+
+
{{ .Content }}
+
+ {{ if .Params.images }}
+
+ {{ range $img := split .Params.images "," }}
+
+ {{ if (or (strings.HasSuffix (lower $img) ".mp4") (strings.HasSuffix (lower $img) ".mov") (strings.HasSuffix (lower $img) ".webm") (strings.HasSuffix (lower $img) ".m4v")) }}
+
+
play_circle
+ {{ else }}
+

+ {{ end }}
+
+ {{ end }}
+
+ {{ end }}
+
+ {{ if or .Params.datum .Params.ort .Params.kategorie }}
+
+ {{ if or .Params.datum .Params.ort }}
+
+ {{ if .Params.datum }}
{{ .Params.datum }}
{{ end }}
+ {{ if .Params.ort }}
{{ .Params.ort }}
{{ end }}
+
+ {{ end }}
+ {{ if .Params.kategorie }}
+
+
{{ .Params.kategorie }}
+
Kategorie
+
+ {{ end }}
+
+ {{ end }}
-
sports_martial_arts
+
+
+ {{ if not .Params.image }}
+
workspace_premium
+ {{ end }}
{{ end }}
@@ -179,32 +231,38 @@
-
- MEILENSTEINE DES ERFOLGS
+
-
-
+
+
+
+
![]()
+
+
+
+
military_tech
-
+
-
{{ $e.meilenstein.platz }}
-
{{ $e.meilenstein.beschreibung }}
+
{{ $e.meilenstein.platz }}
+
{{ $e.meilenstein.beschreibung }}
-
{{ $e.meilenstein.jahr }}
-
{{ $e.meilenstein.ort }}
+
{{ $e.meilenstein.jahr }}
+
{{ $e.meilenstein.ort }}
-
{{ $e.meilenstein.kategorie }}
+
{{ $e.meilenstein.kategorie }}
Kategorie
sports_martial_arts
+
@@ -212,7 +270,13 @@
Weitere Auszeichnungen
{{ $icons := slice "star" "emoji_events" "rewarded_ads" "workspace_premium" "military_tech" "sports_martial_arts" }}
{{ range $i, $a := $e.weitere_auszeichnungen }}
-
+
{{ index $icons (mod $i (len $icons)) }}
@@ -225,6 +289,29 @@
{{ end }}
+
+ {{ $weitereMarkdown := where (where .Site.RegularPages "Section" "erfolge") "Params.is_weitere_auszeichnung" "true" }}
+ {{ range $i, $page := $weitereMarkdown }}
+
+
+ {{ index $icons (mod $i (len $icons)) }}
+
+
+
{{ .Title }}
+
{{ .Params.rang }}
+ {{ if .Summary }}
+
{{ .Summary }}
+ {{ end }}
+
+
+ {{ end }}
@@ -274,5 +361,85 @@
+
+
+
![]()
+
+
+
+
+