From b8e4f6c20b80bdab05cb47d0ffcf268ac01ae258 Mon Sep 17 00:00:00 2001
From: bonzei
Date: Wed, 22 Apr 2026 23:50:21 +0200
Subject: [PATCH] origin
---
admin-server.js | 97 +++-
admin.html | 866 +++++++++++++++++++++++++++++++----
data/erfolge.json | 51 +++
data/gaestebuch.json | 55 +++
data/galerie.json | 17 +
data/global.json | 7 +
data/homepage.json | 42 +-
data/uebermich.json | 14 +-
hugo.toml | 2 +-
layouts/_default/single.html | 2 +-
layouts/erfolge/list.html | 148 +++---
layouts/gaestebuch/list.html | 142 ++----
layouts/galerie/list.html | 45 +-
layouts/index.html | 136 +++++-
layouts/uebermich/list.html | 15 +-
package.json | 2 +-
16 files changed, 1324 insertions(+), 317 deletions(-)
create mode 100644 data/erfolge.json
create mode 100644 data/gaestebuch.json
create mode 100644 data/galerie.json
create mode 100644 data/global.json
diff --git a/admin-server.js b/admin-server.js
index 45c688e..89d723c 100644
--- a/admin-server.js
+++ b/admin-server.js
@@ -15,10 +15,17 @@ const DATA_FILE = path.join(__dirname, 'data/gallery.json');
const HOMEPAGE_FILE = path.join(__dirname, 'data/homepage.json');
const CATEGORIES_FILE = path.join(__dirname, 'data/categories.json');
const UEBERMICH_FILE = path.join(__dirname, 'data/uebermich.json');
+const ERFOLGE_FILE = path.join(__dirname, 'data/erfolge.json');
+const ERFOLGE_IMG_DIR = path.join(__dirname, 'static/erfolge-img');
+const GALERIE_PAGE_FILE = path.join(__dirname, 'data/galerie.json');
+const GAESTEBUCH_FILE = path.join(__dirname, 'data/gaestebuch.json');
+const GLOBAL_FILE = path.join(__dirname, 'data/global.json');
+const GAESTEBUCH_IMG_DIR = path.join(__dirname, 'static/gaestebuch-img');
if (!fs.existsSync(UEBERMICH_IMG_DIR)) fs.mkdirSync(UEBERMICH_IMG_DIR, { recursive: true });
-
if (!fs.existsSync(HERO_DIR)) fs.mkdirSync(HERO_DIR, { recursive: true });
+if (!fs.existsSync(ERFOLGE_IMG_DIR)) fs.mkdirSync(ERFOLGE_IMG_DIR, { recursive: true });
+if (!fs.existsSync(GAESTEBUCH_IMG_DIR)) fs.mkdirSync(GAESTEBUCH_IMG_DIR, { recursive: true });
app.use(express.json());
app.use('/images', express.static(IMAGES_DIR));
@@ -164,9 +171,14 @@ function rebuildAndDeploy() {
app.put('/api/homepage', (req, res) => {
const hp = readHomepage();
+ if (req.body.siteTitle !== undefined) hp.siteTitle = req.body.siteTitle;
if (req.body.badge !== undefined) hp.hero.badge = req.body.badge;
if (req.body.description !== undefined) hp.hero.description = req.body.description;
if (req.body.stats !== undefined) hp.stats = req.body.stats;
+ if (req.body.hero_karte !== undefined) hp.hero_karte = req.body.hero_karte;
+ if (req.body.pruefung_karte !== undefined) hp.pruefung_karte = req.body.pruefung_karte;
+ if (req.body.dojo_karte !== undefined) hp.dojo_karte = req.body.dojo_karte;
+ if (req.body.cta !== undefined) hp.cta = req.body.cta;
writeHomepage(hp);
res.json({ ok: true });
rebuildAndDeploy();
@@ -191,6 +203,8 @@ app.post('/api/homepage/image', upload.single('image'), async (req, res) => {
app.use('/hero', express.static(HERO_DIR));
app.use('/uebermich', express.static(UEBERMICH_IMG_DIR));
+app.use('/erfolge-img', express.static(ERFOLGE_IMG_DIR));
+app.use('/gaestebuch-img', express.static(GAESTEBUCH_IMG_DIR));
// Über mich API
function readUebermich() {
@@ -228,6 +242,87 @@ app.post('/api/uebermich/image', upload.single('image'), async (req, res) => {
}
});
+// ── Erfolge API ───────────────────────────────────────────────
+function readErfolge() {
+ return JSON.parse(fs.readFileSync(ERFOLGE_FILE, 'utf8'));
+}
+function writeErfolge(data) {
+ fs.writeFileSync(ERFOLGE_FILE, JSON.stringify(data, null, 2));
+}
+
+app.get('/api/erfolge', (req, res) => {
+ res.json(readErfolge());
+});
+
+app.put('/api/erfolge', (req, res) => {
+ writeErfolge(req.body);
+ res.json({ ok: true });
+ rebuildAndDeploy();
+});
+
+app.post('/api/erfolge/image', upload.single('image'), async (req, res) => {
+ try {
+ const filename = 'hero.webp';
+ await sharp(req.file.buffer)
+ .resize(1200, 1500, { fit: 'inside', withoutEnlargement: true })
+ .webp({ quality: 88 })
+ .toFile(path.join(ERFOLGE_IMG_DIR, filename));
+ const data = readErfolge();
+ data.hero.image = filename;
+ writeErfolge(data);
+ res.json({ ok: true, image: filename });
+ rebuildAndDeploy();
+ } catch (e) {
+ res.status(500).json({ ok: false, error: e.message });
+ }
+});
+
+// ── Galerie Seiten-Texte API ──────────────────────────────────
+app.get('/api/galerie', (req, res) => {
+ res.json(JSON.parse(fs.readFileSync(GALERIE_PAGE_FILE, 'utf8')));
+});
+app.put('/api/galerie', (req, res) => {
+ fs.writeFileSync(GALERIE_PAGE_FILE, JSON.stringify(req.body, null, 2));
+ res.json({ ok: true });
+ rebuildAndDeploy();
+});
+
+// ── Gästebuch API ─────────────────────────────────────────────
+app.get('/api/gaestebuch', (req, res) => {
+ res.json(JSON.parse(fs.readFileSync(GAESTEBUCH_FILE, 'utf8')));
+});
+app.put('/api/gaestebuch', (req, res) => {
+ fs.writeFileSync(GAESTEBUCH_FILE, JSON.stringify(req.body, null, 2));
+ res.json({ ok: true });
+ rebuildAndDeploy();
+});
+app.post('/api/gaestebuch/image', upload.single('image'), async (req, res) => {
+ try {
+ const filename = 'hero.webp';
+ await sharp(req.file.buffer)
+ .resize(1400, 600, { fit: 'cover', position: 'center' })
+ .webp({ quality: 88 })
+ .toFile(path.join(GAESTEBUCH_IMG_DIR, filename));
+ const data = JSON.parse(fs.readFileSync(GAESTEBUCH_FILE, 'utf8'));
+ data.hero.image = filename;
+ fs.writeFileSync(GAESTEBUCH_FILE, JSON.stringify(data, null, 2));
+ res.json({ ok: true, image: filename });
+ rebuildAndDeploy();
+ } catch (e) {
+ res.status(500).json({ ok: false, error: e.message });
+ }
+});
+
+// ── Global (Social Links) API ─────────────────────────────────
+app.get('/api/global', (req, res) => {
+ res.json(JSON.parse(fs.readFileSync(GLOBAL_FILE, 'utf8')));
+});
+app.put('/api/global', (req, res) => {
+ fs.writeFileSync(GLOBAL_FILE, JSON.stringify(req.body, null, 2));
+ res.json({ ok: true });
+ rebuildAndDeploy();
+});
+
// Admin-UI
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'admin.html'));
diff --git a/admin.html b/admin.html
index 4016ca1..28eb2de 100644
--- a/admin.html
+++ b/admin.html
@@ -103,7 +103,7 @@ tailwind.config = {
bolt
-
MiyaKarate
+
MiyaKarate
Admin Panel
@@ -178,7 +178,7 @@ tailwind.config = {
@@ -265,6 +265,46 @@ tailwind.config = {
+
+ Hero-Karte (Rang auf dem Bild)
+
+
+
+ Prüfungs-Karte (pinke Box)
+
+
+ Titel
+
+
+
+ Beschreibung
+
+
+
+
+
+ Dojo-Karte (graue Box)
+
+
+ Titel
+
+
+
+ Beschreibung
+
+
+
+
+
+ Galerie-CTA (dunkler Bereich)
+
+
+ Überschrift (normal)
+
+
+
+ Überschrift (farbig/akzent)
+
+
+
+ Beschreibungstext
+
+
+
+ Button-Text
+
+
+
+
Änderungen speichern
@@ -459,42 +559,6 @@ tailwind.config = {
-
- Haupterfolg
-
-
-
- Weitere Erfolge
-
-
- add Erfolg hinzufügen
-
-
Statistik-Boxen
@@ -517,22 +581,245 @@ tailwind.config = {
-
- emoji_events
-
Erfolge — demnächst verfügbar
-
+
+
+ emoji_events
+ Erfolge-Seite bearbeiten
+
+
+
+ Hero-Bild
+
+
+
+
+ image
+ Kein Bild
+
+
+
+
+ upload_file
+ Bild auswählen
+ JPG, PNG, HEIC
+
+
+
Bild hochladen
+
+
+
+
+
+ Hero-Text
+
+
+
+ Haupt-Meilenstein (große Karte)
+
+
+
+ Weitere Auszeichnungen
+
+
+ add Auszeichnung hinzufügen
+
+
+
+ Statistiken (3 Boxen)
+ Box 1 = lila, Box 2 = grau, Box 3 = weiß mit pinker Linie.
+
+
+
+ Zitat
+
+
+
+
+ Autor
+
+
+
+
+ Erfolge speichern & deployen
+
+
+
+
+
+ share
+ Social Links
+
+ Diese Links erscheinen im Footer auf allen Seiten der Website.
+
+
+ save Speichern & deployen
+
+
+
+
+
+
+
+ badge
+ Site-Name
+
+ Dieser Name erscheint in der Navbar, im Footer und überall auf der Website.
+
+
+
+ save Speichern
+
+
+
+
+
label
@@ -634,10 +921,12 @@ tailwind.config = {
const [title, sub] = pageTitles[name] || ['Admin', ''];
document.getElementById('pageTitle').textContent = title;
document.getElementById('pageSubtitle').textContent = sub;
- if (name === 'media') loadPhotos();
+ if (name === 'media') { loadPhotos(); loadGaleriePage(); }
if (name === 'homepage') loadHomepage();
if (name === 'uebermich') loadUebermich();
- if (name === 'settings') renderCatManage();
+ if (name === 'career') loadCareer();
+ if (name === 'community') loadGaestebuch();
+ if (name === 'settings') { renderCatManage(); loadSiteTitle(); loadSocialLinks(); }
}
document.getElementById('sideNav').addEventListener('click', function (e) {
@@ -1179,15 +1468,29 @@ tailwind.config = {
const hero = data.hero || {};
document.getElementById('heroBadge').value = hero.badge || '';
document.getElementById('heroDescription').value = hero.description || '';
+ const hk = data.hero_karte || {};
+ document.getElementById('hpKarteRang').value = hk.rang || '';
+ document.getElementById('hpKarteStatus').value = hk.status || '';
+ const pk = data.pruefung_karte || {};
+ document.getElementById('hpPruefungTitel').value = pk.titel || '';
+ document.getElementById('hpPruefungDesc').value = pk.beschreibung || '';
+ const dk = data.dojo_karte || {};
+ document.getElementById('hpDojoTitel').value = dk.titel || '';
+ document.getElementById('hpDojoDesc').value = dk.beschreibung || '';
+ const cta = data.cta || {};
+ document.getElementById('hpCtaMain').value = cta.heading_main || '';
+ document.getElementById('hpCtaColored').value = cta.heading_colored || '';
+ document.getElementById('hpCtaDesc').value = cta.description || '';
+ document.getElementById('hpCtaBtn').value = cta.button_text || '';
const statsFields = document.getElementById('statsFields');
statsFields.innerHTML = '';
(data.stats || []).forEach(function(s) {
const row = document.createElement('div');
row.className = 'flex gap-3 items-center';
row.innerHTML =
- ' ' +
- ' ';
statsFields.appendChild(row);
});
@@ -1248,10 +1551,28 @@ tailwind.config = {
body: JSON.stringify({
badge: document.getElementById('heroBadge').value,
description: document.getElementById('heroDescription').value,
- stats: stats
+ stats: stats,
+ hero_karte: {
+ rang: document.getElementById('hpKarteRang').value,
+ status: document.getElementById('hpKarteStatus').value
+ },
+ pruefung_karte: {
+ titel: document.getElementById('hpPruefungTitel').value,
+ beschreibung: document.getElementById('hpPruefungDesc').value
+ },
+ dojo_karte: {
+ titel: document.getElementById('hpDojoTitel').value,
+ beschreibung: document.getElementById('hpDojoDesc').value
+ },
+ cta: {
+ heading_main: document.getElementById('hpCtaMain').value,
+ heading_colored: document.getElementById('hpCtaColored').value,
+ description: document.getElementById('hpCtaDesc').value,
+ button_text: document.getElementById('hpCtaBtn').value
+ }
})
});
- if (r.ok) showToast('✓ Startseite gespeichert');
+ if (r.ok) showToast('✓ Startseite gespeichert & Deploy gestartet');
} catch (err) { console.error('Save error:', err); }
});
@@ -1282,10 +1603,6 @@ tailwind.config = {
return row;
}
- document.getElementById('umWeitereAdd').addEventListener('click', function() {
- document.getElementById('umWeitereFields').appendChild(createWeitereRow('', ''));
- });
-
async function loadUebermich() {
try {
const r = await fetch('/api/uebermich');
@@ -1297,22 +1614,9 @@ tailwind.config = {
document.getElementById('umHSuffix').value = d.hero.heading_suffix || '';
document.getElementById('umDesc').value = d.hero.description || '';
document.getElementById('umGurt').value = d.gurtweg.aktiver_gurt || 'Blau';
- document.getElementById('umHeTitel').value = d.haupterfolg.titel || '';
- document.getElementById('umHePlatz').value = d.haupterfolg.platz || '';
- document.getElementById('umHeJahr').value = d.haupterfolg.jahr || '';
- document.getElementById('umHeOrt').value = d.haupterfolg.ort || '';
- document.getElementById('umHeKat').value = d.haupterfolg.kategorie || '';
- document.getElementById('umHeDesc').value = d.haupterfolg.beschreibung || '';
document.getElementById('umZitat').value = d.zitat.text || '';
document.getElementById('umZitatAutor').value = d.zitat.autor || '';
- // Weitere Erfolge
- const wf = document.getElementById('umWeitereFields');
- wf.innerHTML = '';
- (d.weitere_erfolge || []).forEach(function(e) {
- wf.appendChild(createWeitereRow(e.titel, e.detail, e.beschreibung, e.jahr, e.ort, e.kategorie));
- });
-
// Stats
const sf = document.getElementById('umStatsFields');
sf.innerHTML = '';
@@ -1378,27 +1682,9 @@ tailwind.config = {
data.hero.heading_suffix = document.getElementById('umHSuffix').value;
data.hero.description = document.getElementById('umDesc').value;
data.gurtweg.aktiver_gurt = document.getElementById('umGurt').value;
- data.haupterfolg.titel = document.getElementById('umHeTitel').value;
- data.haupterfolg.platz = document.getElementById('umHePlatz').value;
- data.haupterfolg.jahr = document.getElementById('umHeJahr').value;
- data.haupterfolg.ort = document.getElementById('umHeOrt').value;
- data.haupterfolg.kategorie = document.getElementById('umHeKat').value;
- data.haupterfolg.beschreibung = document.getElementById('umHeDesc').value;
data.zitat.text = document.getElementById('umZitat').value;
data.zitat.autor = document.getElementById('umZitatAutor').value;
- const weRows = document.getElementById('umWeitereFields').querySelectorAll(':scope > div');
- data.weitere_erfolge = Array.from(weRows).map(function(row) {
- return {
- titel: row.querySelector('[data-we="titel"]').value,
- detail: row.querySelector('[data-we="detail"]').value,
- beschreibung: row.querySelector('[data-we="beschreibung"]').value,
- jahr: row.querySelector('[data-we="jahr"]').value,
- ort: row.querySelector('[data-we="ort"]').value,
- kategorie: row.querySelector('[data-we="kategorie"]').value
- };
- });
-
const stRows = document.getElementById('umStatsFields').querySelectorAll('div.flex');
data.stats = Array.from(stRows).map(function(row) {
return {
@@ -1416,8 +1702,414 @@ tailwind.config = {
} catch(err) { console.error('Save error:', err); }
});
+ // ─── Erfolge (Career) ─────────────────────────────────────
+ function createAuszeichnungRow(titel, detail) {
+ const row = document.createElement('div');
+ row.className = 'bg-surface-container-low rounded-xl p-4 flex gap-3 items-center';
+ row.innerHTML =
+ ' ' +
+ ' ' +
+ '' +
+ 'delete ';
+ row.querySelector('.ea-delete').addEventListener('click', function() { row.remove(); });
+ return row;
+ }
+
+ document.getElementById('efWeitereAdd').addEventListener('click', function() {
+ document.getElementById('efWeitereFields').appendChild(createAuszeichnungRow('', ''));
+ });
+
+ document.getElementById('efHeroFileInput').addEventListener('change', function() {
+ const file = this.files[0];
+ if (!file) return;
+ document.getElementById('efHeroPreview').src = URL.createObjectURL(file);
+ document.getElementById('efHeroPreview').classList.remove('hidden');
+ document.getElementById('efHeroPlaceholder').classList.add('hidden');
+ document.getElementById('efHeroUploadBtn').disabled = false;
+ document.getElementById('efHeroUploadStatus').textContent = file.name;
+ });
+
+ document.getElementById('efHeroUploadBtn').addEventListener('click', async function() {
+ const file = document.getElementById('efHeroFileInput').files[0];
+ if (!file) return;
+ this.disabled = true;
+ document.getElementById('efHeroUploadStatus').textContent = 'Wird hochgeladen…';
+ try {
+ const fd = new FormData();
+ fd.append('image', file);
+ const r = await fetch('/api/erfolge/image', { method: 'POST', body: fd });
+ if (r.ok) {
+ showToast('✓ Bild gespeichert');
+ document.getElementById('efHeroUploadStatus').textContent = 'Gespeichert!';
+ } else {
+ document.getElementById('efHeroUploadStatus').textContent = 'Fehler beim Upload';
+ }
+ } catch(err) {
+ document.getElementById('efHeroUploadStatus').textContent = 'Verbindungsfehler';
+ }
+ this.disabled = false;
+ });
+
+ async function loadCareer() {
+ try {
+ const r = await fetch('/api/erfolge');
+ const d = await r.json();
+ const hero = d.hero || {};
+ document.getElementById('efBadge').value = hero.badge || '';
+ document.getElementById('efHeadingMain').value = hero.heading_main || '';
+ document.getElementById('efHeadingColored').value = hero.heading_colored || '';
+ document.getElementById('efDescription').value = hero.description || '';
+ document.getElementById('efRang').value = hero.rang_value || '';
+ if (hero.image) {
+ document.getElementById('efHeroPreview').src = '/erfolge-img/' + hero.image + '?t=' + Date.now();
+ document.getElementById('efHeroPreview').classList.remove('hidden');
+ document.getElementById('efHeroPlaceholder').classList.add('hidden');
+ }
+ const m = d.meilenstein || {};
+ document.getElementById('efMeilensteinEvent').value = m.event || '';
+ document.getElementById('efMeilensteinPlatz').value = m.platz || '';
+ document.getElementById('efMeilensteinDesc').value = m.beschreibung || '';
+ document.getElementById('efMeilensteinJahr').value = m.jahr || '';
+ document.getElementById('efMeilensteinOrt').value = m.ort || '';
+ document.getElementById('efMeilensteinKat').value = m.kategorie || '';
+ const wf = document.getElementById('efWeitereFields');
+ wf.innerHTML = '';
+ (d.weitere_auszeichnungen || []).forEach(function(a) {
+ wf.appendChild(createAuszeichnungRow(a.titel, a.detail));
+ });
+ const sf = document.getElementById('efStatsFields');
+ sf.innerHTML = '';
+ (d.stats || []).forEach(function(s) {
+ const row = document.createElement('div');
+ row.className = 'flex gap-3 items-center';
+ row.innerHTML =
+ ' ' +
+ ' ';
+ sf.appendChild(row);
+ });
+ document.getElementById('efZitatText').value = (d.zitat || {}).text || '';
+ document.getElementById('efZitatAutor').value = (d.zitat || {}).autor || '';
+ } catch(err) { console.error('Career load error:', err); }
+ }
+
+ document.getElementById('careerSaveBtn').addEventListener('click', async function() {
+ try {
+ const r0 = await fetch('/api/erfolge');
+ const existing = await r0.json();
+ const weRows = document.getElementById('efWeitereFields').querySelectorAll(':scope > div');
+ const stRows = document.getElementById('efStatsFields').querySelectorAll('div.flex');
+ const data = {
+ hero: {
+ badge: document.getElementById('efBadge').value,
+ heading_main: document.getElementById('efHeadingMain').value,
+ heading_colored: document.getElementById('efHeadingColored').value,
+ description: document.getElementById('efDescription').value,
+ rang_value: document.getElementById('efRang').value,
+ rang_label: (existing.hero || {}).rang_label || 'Aktueller Rang',
+ image: (existing.hero || {}).image || ''
+ },
+ meilenstein: {
+ event: document.getElementById('efMeilensteinEvent').value,
+ platz: document.getElementById('efMeilensteinPlatz').value,
+ beschreibung: document.getElementById('efMeilensteinDesc').value,
+ jahr: document.getElementById('efMeilensteinJahr').value,
+ ort: document.getElementById('efMeilensteinOrt').value,
+ kategorie: document.getElementById('efMeilensteinKat').value
+ },
+ weitere_auszeichnungen: Array.from(weRows).map(function(row) {
+ return {
+ titel: row.querySelector('[data-ea="titel"]').value,
+ detail: row.querySelector('[data-ea="detail"]').value
+ };
+ }),
+ stats: Array.from(stRows).map(function(row) {
+ return {
+ wert: row.querySelector('[data-es="wert"]').value,
+ label: row.querySelector('[data-es="label"]').value
+ };
+ }),
+ zitat: {
+ text: document.getElementById('efZitatText').value,
+ autor: document.getElementById('efZitatAutor').value
+ }
+ };
+
+ const res = await fetch('/api/erfolge', {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ });
+ if (res.ok) showToast('✓ Erfolge gespeichert & Deploy gestartet');
+ } catch(err) { console.error('Career save error:', err); }
+ });
+
+ // ─── Site-Name ────────────────────────────────────────────
+ async function loadSiteTitle() {
+ try {
+ const r = await fetch('/api/homepage');
+ const data = await r.json();
+ const title = data.siteTitle || '';
+ document.getElementById('siteTitleInput').value = title;
+ updateAdminTitle(title);
+ } catch (err) { console.error('SiteTitle load error:', err); }
+ }
+
+ function updateAdminTitle(title) {
+ if (!title) return;
+ document.getElementById('adminSiteTitle').textContent = title;
+ document.getElementById('adminSiteTitleHeader').textContent = title;
+ }
+
+ document.getElementById('saveSiteTitleBtn').addEventListener('click', async function () {
+ const status = document.getElementById('siteTitleStatus');
+ const val = document.getElementById('siteTitleInput').value.trim();
+ if (!val) { status.textContent = 'Bitte einen Namen eingeben.'; return; }
+ try {
+ const r = await fetch('/api/homepage', {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ siteTitle: val })
+ });
+ if (r.ok) {
+ updateAdminTitle(val);
+ showToast('✓ Site-Name gespeichert & Deploy gestartet');
+ status.textContent = '';
+ } else {
+ status.textContent = 'Fehler beim Speichern.';
+ }
+ } catch (err) { status.textContent = 'Verbindungsfehler'; }
+ });
+
+ // ─── Galerie Seiten-Texte ─────────────────────────────────
+ async function loadGaleriePage() {
+ try {
+ const r = await fetch('/api/galerie');
+ const d = await r.json();
+ const hero = d.hero || {};
+ document.getElementById('galBadge').value = hero.badge || '';
+ document.getElementById('galHeadingMain').value = hero.heading_main || '';
+ document.getElementById('galHeadingColored').value = hero.heading_colored || '';
+ document.getElementById('galDescription').value = hero.description || '';
+ const ribbon = d.ribbon || {};
+ document.getElementById('galRibbonHeading').value = ribbon.heading || '';
+ document.getElementById('galRibbonDesc').value = ribbon.description || '';
+ const sf = document.getElementById('galStatsFields');
+ sf.innerHTML = '';
+ (ribbon.stats || []).forEach(function(s) {
+ const row = document.createElement('div');
+ row.className = 'flex gap-3 items-center';
+ row.innerHTML =
+ ' ' +
+ ' ';
+ sf.appendChild(row);
+ });
+ } catch(err) { console.error('Galerie page load error:', err); }
+ }
+
+ document.getElementById('galSaveBtn').addEventListener('click', async function() {
+ try {
+ const stRows = document.getElementById('galStatsFields').querySelectorAll('div.flex');
+ const data = {
+ hero: {
+ badge: document.getElementById('galBadge').value,
+ heading_main: document.getElementById('galHeadingMain').value,
+ heading_colored: document.getElementById('galHeadingColored').value,
+ description: document.getElementById('galDescription').value
+ },
+ ribbon: {
+ heading: document.getElementById('galRibbonHeading').value,
+ description: document.getElementById('galRibbonDesc').value,
+ stats: Array.from(stRows).map(function(row) {
+ return {
+ wert: row.querySelector('[data-gs="wert"]').value,
+ label: row.querySelector('[data-gs="label"]').value
+ };
+ })
+ }
+ };
+ const res = await fetch('/api/galerie', {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ });
+ if (res.ok) showToast('✓ Galerie-Texte gespeichert & Deploy gestartet');
+ } catch(err) { console.error('Galerie save error:', err); }
+ });
+
+ // ─── Gästebuch ────────────────────────────────────────────
+ function createEintragRow(name, rolle, text, farbe, breit) {
+ const row = document.createElement('div');
+ row.className = 'bg-surface-container-low rounded-xl p-4 flex flex-col gap-3';
+ row.innerHTML =
+ '' +
+ '' +
+ ' ' +
+ '' +
+ ' ' +
+ 'Breite Karte ' +
+ ' ' +
+ '' +
+ 'Standard (weiß) ' +
+ 'Akzent (lila/pink) ' +
+ ' ' +
+ '
';
+ row.querySelector('.gb-delete').addEventListener('click', function() { row.remove(); });
+ return row;
+ }
+
+ document.getElementById('gbEintragAdd').addEventListener('click', function() {
+ document.getElementById('gbEintragFields').appendChild(createEintragRow('', '', '', 'default', false));
+ });
+
+ document.getElementById('gbHeroFileInput').addEventListener('change', function() {
+ const file = this.files[0];
+ if (!file) return;
+ document.getElementById('gbHeroPreview').src = URL.createObjectURL(file);
+ document.getElementById('gbHeroPreview').classList.remove('hidden');
+ document.getElementById('gbHeroPlaceholder').classList.add('hidden');
+ document.getElementById('gbHeroUploadBtn').disabled = false;
+ document.getElementById('gbHeroUploadStatus').textContent = file.name;
+ });
+
+ document.getElementById('gbHeroUploadBtn').addEventListener('click', async function() {
+ const file = document.getElementById('gbHeroFileInput').files[0];
+ if (!file) return;
+ this.disabled = true;
+ document.getElementById('gbHeroUploadStatus').textContent = 'Wird hochgeladen…';
+ try {
+ const fd = new FormData();
+ fd.append('image', file);
+ const r = await fetch('/api/gaestebuch/image', { method: 'POST', body: fd });
+ if (r.ok) {
+ showToast('✓ Bild gespeichert');
+ document.getElementById('gbHeroUploadStatus').textContent = 'Gespeichert!';
+ } else {
+ document.getElementById('gbHeroUploadStatus').textContent = 'Fehler beim Upload';
+ }
+ } catch(err) {
+ document.getElementById('gbHeroUploadStatus').textContent = 'Verbindungsfehler';
+ }
+ this.disabled = false;
+ });
+
+ async function loadGaestebuch() {
+ try {
+ const r = await fetch('/api/gaestebuch');
+ const d = await r.json();
+ const hero = d.hero || {};
+ document.getElementById('gbBadge').value = hero.badge || '';
+ document.getElementById('gbHeading').value = hero.heading || '';
+ document.getElementById('gbHeadingColored').value = hero.heading_colored || '';
+ document.getElementById('gbDescription').value = hero.description || '';
+ const kontakt = d.kontakt || {};
+ document.getElementById('gbEmail').value = kontakt.email || '';
+ document.getElementById('gbDojo').value = kontakt.dojo || '';
+ if (hero.image) {
+ document.getElementById('gbHeroPreview').src = '/gaestebuch-img/' + hero.image + '?t=' + Date.now();
+ document.getElementById('gbHeroPreview').classList.remove('hidden');
+ document.getElementById('gbHeroPlaceholder').classList.add('hidden');
+ }
+ const ef = document.getElementById('gbEintragFields');
+ ef.innerHTML = '';
+ (d.eintraege || []).forEach(function(e) {
+ ef.appendChild(createEintragRow(e.name, e.rolle, e.text, e.farbe, e.breit));
+ });
+ } catch(err) { console.error('Gaestebuch load error:', err); }
+ }
+
+ document.getElementById('gbSaveBtn').addEventListener('click', async function() {
+ try {
+ const r0 = await fetch('/api/gaestebuch');
+ const existing = await r0.json();
+ const rows = document.getElementById('gbEintragFields').querySelectorAll(':scope > div');
+ const eintraege = Array.from(rows).map(function(row, i) {
+ return {
+ id: String(i + 1),
+ name: row.querySelector('[data-gb="name"]').value,
+ rolle: row.querySelector('[data-gb="rolle"]').value,
+ text: row.querySelector('[data-gb="text"]').value,
+ farbe: row.querySelector('[data-gb="farbe"]').value,
+ breit: row.querySelector('[data-gb="breit"]').checked
+ };
+ });
+ const data = {
+ hero: {
+ badge: document.getElementById('gbBadge').value,
+ heading: document.getElementById('gbHeading').value,
+ heading_colored: document.getElementById('gbHeadingColored').value,
+ description: document.getElementById('gbDescription').value,
+ image: (existing.hero || {}).image || ''
+ },
+ kontakt: {
+ email: document.getElementById('gbEmail').value,
+ dojo: document.getElementById('gbDojo').value
+ },
+ eintraege: eintraege
+ };
+ const res = await fetch('/api/gaestebuch', {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ });
+ if (res.ok) showToast('✓ Gästebuch gespeichert & Deploy gestartet');
+ } catch(err) { console.error('Gaestebuch save error:', err); }
+ });
+
+ // ─── Social Links ─────────────────────────────────────────
+ async function loadSocialLinks() {
+ try {
+ const r = await fetch('/api/global');
+ const d = await r.json();
+ const social = d.social || {};
+ document.getElementById('socialInstagram').value = social.instagram || '';
+ document.getElementById('socialYoutube').value = social.youtube || '';
+ document.getElementById('socialEmail').value = social.email || '';
+ } catch(err) { console.error('Social load error:', err); }
+ }
+
+ document.getElementById('saveSocialBtn').addEventListener('click', async function() {
+ const status = document.getElementById('socialStatus');
+ try {
+ const r = await fetch('/api/global', {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ social: {
+ instagram: document.getElementById('socialInstagram').value,
+ youtube: document.getElementById('socialYoutube').value,
+ email: document.getElementById('socialEmail').value
+ }
+ })
+ });
+ if (r.ok) {
+ showToast('✓ Social Links gespeichert & Deploy gestartet');
+ status.textContent = '';
+ } else {
+ status.textContent = 'Fehler beim Speichern.';
+ }
+ } catch(err) { status.textContent = 'Verbindungsfehler'; }
+ });
+
// ─── Init ─────────────────────────────────────────────────
loadCategories().then(function () { loadStats(); });
+ loadSiteTitle();
+ loadSocialLinks();
})();
diff --git a/data/erfolge.json b/data/erfolge.json
new file mode 100644
index 0000000..4fd8123
--- /dev/null
+++ b/data/erfolge.json
@@ -0,0 +1,51 @@
+{
+ "hero": {
+ "badge": "Meine Wettkampf-Geschichte",
+ "heading_main": "JEDER SIEG",
+ "heading_colored": "ZÄHLT.",
+ "description": "Von der ersten Gürtelprüfung bis zur Landesmeisterschaft – hier sammle ich alle Momente, auf die ich besonders stolz bin.",
+ "rang_value": "Blaugurt",
+ "rang_label": "Aktueller Rang",
+ "image": "hero.webp"
+ },
+ "meilenstein": {
+ "event": "Landesmeisterschaft Berlin",
+ "platz": "Gold – Kata U14",
+ "beschreibung": "Mein bisher größter Erfolg. Monatelanges hartes Training gipfelte in einer Vorführung, die meinen Wettkampfgeist unter Beweis stellte.",
+ "jahr": "2024",
+ "ort": "Berlin",
+ "kategorie": "U14"
+ },
+ "weitere_auszeichnungen": [
+ {
+ "titel": "Norddeutsche Meisterschaft",
+ "detail": "Silber – Kata 2024"
+ },
+ {
+ "titel": "Dojo Champion",
+ "detail": "Kiai Berlin, intern"
+ },
+ {
+ "titel": "Fairness-Preis",
+ "detail": "Dojo-Auszeichnung 2023"
+ }
+ ],
+ "stats": [
+ {
+ "wert": "5+",
+ "label": "Jahre Training"
+ },
+ {
+ "wert": "32",
+ "label": "Turniere"
+ },
+ {
+ "wert": "12",
+ "label": "Goldmedaillen"
+ }
+ ],
+ "zitat": {
+ "text": "Karate ist nicht nur ein Sport. Es ist eine Linse, durch die ich die Welt sehe – mit Präzision, Respekt und unbeugsamer Konzentration.",
+ "autor": "Emy"
+ }
+}
\ No newline at end of file
diff --git a/data/gaestebuch.json b/data/gaestebuch.json
new file mode 100644
index 0000000..dc1dca0
--- /dev/null
+++ b/data/gaestebuch.json
@@ -0,0 +1,55 @@
+{
+ "hero": {
+ "badge": "Melde dich bei mir",
+ "heading": "Schreib mir &",
+ "heading_colored": "teile deine Geschichte",
+ "description": "Ob du eine Frage zu meinem Training hast oder einfach eine nette Nachricht hinterlassen möchtest – ich freue mich von dir zu hören!",
+ "image": ""
+ },
+ "kontakt": {
+ "email": "emy@meinewebsite.de",
+ "dojo": "Kiai Dojo Esslingen"
+ },
+ "eintraege": [
+ {
+ "id": "1",
+ "name": "Trainerin Elena",
+ "rolle": "Sensei",
+ "text": "Deine Konzentration beim letzten Grading war außergewöhnlich. Die Körperkontrolle, die du entwickelst, ist selten für dein Alter. Ich bin stolz auf dich!",
+ "farbe": "default",
+ "breit": false
+ },
+ {
+ "id": "2",
+ "name": "Opa Karl",
+ "rolle": "Familie",
+ "text": "Wir drücken dir von zuhause alle die Daumen! Kann es kaum erwarten, den nächsten Pokal auf dem Regal zu sehen!",
+ "farbe": "default",
+ "breit": true
+ },
+ {
+ "id": "3",
+ "name": "Lea M.",
+ "rolle": "Freundin",
+ "text": "Die Website sieht so professionell aus! Mega cool, alle deine Erfolge an einem Ort zu sehen. Wir müssen bald mal wieder eis essen gehen!",
+ "farbe": "default",
+ "breit": false
+ },
+ {
+ "id": "4",
+ "name": "Trainer Thomas",
+ "rolle": "Dojo Kiai Berlin",
+ "text": "Ich trainiere viele Kinder, aber die kinetische Flüssigkeit in deinen Bewegungen ist etwas Besonderes. Du machst jede Kata zu einem Tanz. Weiter so – der nächste schwarze Gürtel wartet schon!",
+ "farbe": "secondary",
+ "breit": true
+ },
+ {
+ "id": "5",
+ "name": "Herr Braun",
+ "rolle": "Lehrer",
+ "text": "Balance im Sport führt zu Balance im Leben. Halt die Disziplin, die du im Dojo zeigst, auch in der Schule!",
+ "farbe": "default",
+ "breit": false
+ }
+ ]
+}
\ No newline at end of file
diff --git a/data/galerie.json b/data/galerie.json
new file mode 100644
index 0000000..f8bf5a3
--- /dev/null
+++ b/data/galerie.json
@@ -0,0 +1,17 @@
+{
+ "hero": {
+ "badge": "Visuelle Reise",
+ "heading_main": "Eingefangene",
+ "heading_colored": "Momente.",
+ "description": "Die Kunst der Disziplin durch die Linse. Von intensiven Trainingseinheiten bis zum Triumph bei Gürtelprüfungen."
+ },
+ "ribbon": {
+ "heading": "Hinter der Linse",
+ "description": "Unsere Galerie ist nicht nur Fotos – sie ist ein Zeugnis der Disziplin, die wir jeden Tag im Dojo leben.",
+ "stats": [
+ { "wert": "24", "label": "Turniere" },
+ { "wert": "150+", "label": "Schüler" },
+ { "wert": "85", "label": "Gürtelprüfungen" }
+ ]
+ }
+}
diff --git a/data/global.json b/data/global.json
new file mode 100644
index 0000000..5b760b2
--- /dev/null
+++ b/data/global.json
@@ -0,0 +1,7 @@
+{
+ "social": {
+ "instagram": "#",
+ "youtube": "#",
+ "email": "hallo@miyakarate.de"
+ }
+}
diff --git a/data/homepage.json b/data/homepage.json
index 4527d5c..08d59db 100644
--- a/data/homepage.json
+++ b/data/homepage.json
@@ -1,21 +1,31 @@
{
+ "siteTitle": "EmyKarate",
"hero": {
- "badge": "MEINE REISE IN KATA hh",
- "description": "Entdecke die Welt des Karate durch meine Augen. Von den ersten Schritten im Dojo bis hin zu nationalen Meisterschaften – hier teile ich meine Leidenschaft für Bewegung, Disziplin und Erfolg. hh",
+ "badge": "MEINE REISE IN KATA ",
+ "description": "Entdecke die Welt des Karate durch meine Augen. Von den ersten Schritten im Dojo bis hin zu nationalen Meisterschaften – hier teile ich meine Leidenschaft für Bewegung, Disziplin und Erfolg. ",
"image": "hero.webp"
},
+ "hero_karte": {
+ "rang": "Blaugurt",
+ "status": "Status 2024"
+ },
"stats": [
- {
- "value": "7+",
- "label": "Jahre Training"
- },
- {
- "value": "1",
- "label": "Gold Medaillen"
- },
- {
- "value": "11",
- "label": "Turniere"
- }
- ]
-}
\ No newline at end of file
+ { "value": "7+", "label": "Jahre Training" },
+ { "value": "1", "label": "Gold Medaillen" },
+ { "value": "11", "label": "Turniere" }
+ ],
+ "pruefung_karte": {
+ "titel": "Prüfung bestanden",
+ "beschreibung": "Neuer Gürtelgrad erreicht! Jetzt stolze Trägerin des Blaugurts."
+ },
+ "dojo_karte": {
+ "titel": "Dojo Champion",
+ "beschreibung": "Hausinterner Wettbewerb im Dojo \"Kiai Berlin\"."
+ },
+ "cta": {
+ "heading_main": "Bereit für mehr",
+ "heading_colored": "Action?",
+ "description": "Schau dir hunderte Fotos von Trainingseinheiten, Turnieren und Reisen in meiner großen Galerie an.",
+ "button_text": "ZUR GALERIE GEHEN"
+ }
+}
diff --git a/data/uebermich.json b/data/uebermich.json
index 6f79590..38a4d8e 100644
--- a/data/uebermich.json
+++ b/data/uebermich.json
@@ -1,9 +1,9 @@
{
"hero": {
- "badge": "Meine Reise h",
- "heading_line1": "KINETISCHE h",
- "heading_line2": "ELEGANZ h",
- "heading_suffix": "IN JEDEM SCHLAG. h",
+ "badge": "Meine Reise ",
+ "heading_line1": "KINETISCHE",
+ "heading_line2": "ELEGANZ",
+ "heading_suffix": "IN JEDEM SCHLAG.",
"description": "Seit ich sechs Jahre alt bin, ist das Dojo mein zweites Zuhause. Für mich ist Karate mehr als Medaillen – es ist eine Symphonie aus Fokus, Disziplin und explosiver Energie in einer einzigen Bewegung. hhh",
"image": "portrait.webp",
"image_alt": "Miya beim Karate-Kick",
@@ -50,11 +50,11 @@
]
},
"haupterfolg": {
- "titel": "Landesmeisterschaft Berlin h",
- "platz": "Gold – Kata U14 h",
+ "titel": "Landesmeisterschaft Berlin ",
+ "platz": "Gold – Kata U14 ",
"beschreibung": "Mein bisher größter Erfolg. Monatelanges hartes Training gipfelte in einer Vorführung, die meinen Wettkampfgeist unter Beweis stellte. hh ",
"jahr": "2024 ",
- "ort": "Esslingen am Neckar h",
+ "ort": "Esslingen am Neckar ",
"kategorie": "U14"
},
"weitere_erfolge": [
diff --git a/hugo.toml b/hugo.toml
index 059f48c..e104026 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -1,3 +1,3 @@
baseURL = "https://emy.bonzeipunk.de/"
languageCode = "de"
-title = "MiyaKarate"
+title = "EmyKarate"
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
index b8dbd9d..dd4d339 100644
--- a/layouts/_default/single.html
+++ b/layouts/_default/single.html
@@ -3,7 +3,7 @@
-
{{ .Title }} | MiyaKarate
+
{{ .Title }} | EmyKarate
diff --git a/layouts/erfolge/list.html b/layouts/erfolge/list.html
index 0a1197c..0d51657 100644
--- a/layouts/erfolge/list.html
+++ b/layouts/erfolge/list.html
@@ -3,7 +3,7 @@
-
Erfolge | MiyaKarate
+
Erfolge | {{ .Site.Data.homepage.siteTitle | default .Site.Title }}
@@ -67,7 +67,7 @@
+{{ $e := .Site.Data.erfolge }}
+
-
Meine Wettkampf-Geschichte
+
{{ $e.hero.badge }}
- Von der ersten Gürtelprüfung bis zur Landesmeisterschaft – hier sammle ich alle Momente, auf die ich besonders stolz bin.
+ {{ $e.hero.description }}
-
+ {{ if $e.hero.image }}
+
+ {{ else }}
+
+ sports_martial_arts
+
+ {{ end }}
@@ -106,8 +112,8 @@
workspace_premium
-
Aktueller Rang
-
Blaugurt
+
{{ $e.hero.rang_label }}
+
{{ $e.hero.rang_value }}
@@ -119,49 +125,82 @@
Alle Erfolge
-
+
{{ range (where .Site.RegularPages "Section" "erfolge") }}
-
-
-
-
military_tech
+
+
+
+
+
+ military_tech
+
{{ .Params.rang | default "Highlight" }}
{{ .Title }}
-
{{ .Summary }}
-
- Bericht lesen arrow_forward
-
+
{{ .Summary }}
+
+ Mehr lesen
+ expand_more
+
-
sports_martial_arts
+
+
+
sports_martial_arts
{{ end }}
+
+
MEILENSTEINE DES ERFOLGS
-
+
+
military_tech
-
+
-
Gold – Kata U14
-
Mein bisher größter Erfolg. Monatelanges hartes Training gipfelte in einer Vorführung, die meinen Wettkampfgeist unter Beweis stellte.
+
{{ $e.meilenstein.platz }}
+
{{ $e.meilenstein.beschreibung }}
-
2024
-
Berlin
+
{{ $e.meilenstein.jahr }}
+
{{ $e.meilenstein.ort }}
-
U14
+
{{ $e.meilenstein.kategorie }}
Kategorie
@@ -171,48 +210,41 @@
Weitere Auszeichnungen
+ {{ $icons := slice "star" "emoji_events" "rewarded_ads" "workspace_premium" "military_tech" "sports_martial_arts" }}
+ {{ range $i, $a := $e.weitere_auszeichnungen }}
- star
+ {{ index $icons (mod $i (len $icons)) }}
-
Norddeutsche Meisterschaft
-
Silber – Kata 2024
-
-
-
-
- emoji_events
-
-
-
Dojo Champion
-
Kiai Berlin, intern
-
-
-
-
- rewarded_ads
-
-
-
Fairness-Preis
-
Dojo-Auszeichnung 2023
+
{{ $a.titel }}
+
{{ $a.detail }}
+ {{ end }}
+ {{ $stats := $e.stats }}
+ {{ with index $stats 0 }}
- 5+
- Jahre Training
+ {{ .wert }}
+ {{ .label }}
+ {{ end }}
+ {{ with index $stats 1 }}
- 32
- Turniere
+ {{ .wert }}
+ {{ .label }}
+ {{ end }}
+ {{ with index $stats 2 }}
- 12
- Goldmedaillen
+ {{ .wert }}
+ {{ .label }}
+ {{ end }}
+
@@ -220,22 +252,22 @@
format_quote
- "Karate ist nicht nur ein Sport. Es ist eine Linse, durch die ich die Welt sehe – mit Präzision, Respekt und unbeugsamer Konzentration."
+ "{{ $e.zitat.text }}"
- — Miya
+ — {{ $e.zitat.autor }}
diff --git a/layouts/gaestebuch/list.html b/layouts/gaestebuch/list.html
index 54aa0e8..e5180d3 100644
--- a/layouts/gaestebuch/list.html
+++ b/layouts/gaestebuch/list.html
@@ -3,7 +3,7 @@
-
Gästebuch | MiyaKarate
+
Gästebuch | {{ .Site.Data.homepage.siteTitle | default .Site.Title }}
@@ -57,16 +57,16 @@
-
+{{ $gb := .Site.Data.gaestebuch }}
- MiyaKarate
+ {{ .Site.Data.homepage.siteTitle | default .Site.Title }}
@@ -79,16 +79,20 @@
+ {{ if $gb.hero.image }}
+
+ {{ else }}
+ {{ end }}
-
Melde dich bei mir
+
{{ $gb.hero.badge }}
- Ob du eine Frage zu meinem Training hast oder einfach eine nette Nachricht hinterlassen möchtest – ich freue mich von dir zu hören!
+ {{ $gb.hero.description }}
@@ -154,7 +158,7 @@
E-Mail
-
hallo@miyakarate.de
+
{{ $gb.kontakt.email }}
@@ -163,7 +167,7 @@
Dojo
-
Kiai Dojo Berlin
+
{{ $gb.kontakt.dojo }}
@@ -175,23 +179,18 @@
Neuester Eintrag
Alle ansehen
+ {{ with index $gb.eintraege 0 }}
-
-
-
+
{{ substr .name 0 1 }}
-
Jonas L.
-
vor 2 Stunden
+
{{ .name }}
+
{{ .rolle }}
-
"Mega Fortschritte bei deiner letzten Kata! Deine Hingabe ist wirklich inspirierend. Weiter so! Oss!"
-
- Teamkamerad
- Inspiriert
-
+
"{{ .text }}"
+ {{ end }}
@@ -203,81 +202,33 @@
Nachrichten von Trainingspartnern, Familie und Freunden aus aller Welt.