mirror of
https://github.com/superschnups/Emy.git
synced 2026-06-22 03:13:10 +00:00
meine erfolge
neue erfolge hinzufügen, tausch von bild, angabe von datu und ort
This commit is contained in:
parent
ad8e5a5b8e
commit
eaddeb16be
5 changed files with 535 additions and 82 deletions
|
|
@ -10,9 +10,13 @@ const PORT = 3001;
|
||||||
|
|
||||||
const IMAGES_DIR = path.join(__dirname, 'static/gallery/images');
|
const IMAGES_DIR = path.join(__dirname, 'static/gallery/images');
|
||||||
const HERO_DIR = path.join(__dirname, 'static/hero');
|
const HERO_DIR = path.join(__dirname, 'static/hero');
|
||||||
|
const UEBERMICH_IMG_DIR = path.join(__dirname, 'static/uebermich');
|
||||||
const DATA_FILE = path.join(__dirname, 'data/gallery.json');
|
const DATA_FILE = path.join(__dirname, 'data/gallery.json');
|
||||||
const HOMEPAGE_FILE = path.join(__dirname, 'data/homepage.json');
|
const HOMEPAGE_FILE = path.join(__dirname, 'data/homepage.json');
|
||||||
const CATEGORIES_FILE = path.join(__dirname, 'data/categories.json');
|
const CATEGORIES_FILE = path.join(__dirname, 'data/categories.json');
|
||||||
|
const UEBERMICH_FILE = path.join(__dirname, 'data/uebermich.json');
|
||||||
|
|
||||||
|
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(HERO_DIR)) fs.mkdirSync(HERO_DIR, { recursive: true });
|
||||||
|
|
||||||
|
|
@ -186,6 +190,43 @@ app.post('/api/homepage/image', upload.single('image'), async (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use('/hero', express.static(HERO_DIR));
|
app.use('/hero', express.static(HERO_DIR));
|
||||||
|
app.use('/uebermich', express.static(UEBERMICH_IMG_DIR));
|
||||||
|
|
||||||
|
// Über mich API
|
||||||
|
function readUebermich() {
|
||||||
|
return JSON.parse(fs.readFileSync(UEBERMICH_FILE, 'utf8'));
|
||||||
|
}
|
||||||
|
function writeUebermich(data) {
|
||||||
|
fs.writeFileSync(UEBERMICH_FILE, JSON.stringify(data, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/api/uebermich', (req, res) => {
|
||||||
|
res.json(readUebermich());
|
||||||
|
});
|
||||||
|
|
||||||
|
app.put('/api/uebermich', (req, res) => {
|
||||||
|
const data = req.body;
|
||||||
|
writeUebermich(data);
|
||||||
|
res.json({ ok: true });
|
||||||
|
rebuildAndDeploy();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/uebermich/image', upload.single('image'), async (req, res) => {
|
||||||
|
try {
|
||||||
|
const filename = 'portrait.webp';
|
||||||
|
await sharp(req.file.buffer)
|
||||||
|
.resize(800, 1000, { fit: 'cover', position: 'top' })
|
||||||
|
.webp({ quality: 88 })
|
||||||
|
.toFile(path.join(UEBERMICH_IMG_DIR, filename));
|
||||||
|
const data = readUebermich();
|
||||||
|
data.hero.image = filename;
|
||||||
|
writeUebermich(data);
|
||||||
|
res.json({ ok: true, image: filename });
|
||||||
|
rebuildAndDeploy();
|
||||||
|
} catch (e) {
|
||||||
|
res.status(500).json({ ok: false, error: e.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Admin-UI
|
// Admin-UI
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
|
|
|
||||||
296
admin.html
296
admin.html
|
|
@ -135,6 +135,11 @@ tailwind.config = {
|
||||||
<span class="material-symbols-outlined">home</span>
|
<span class="material-symbols-outlined">home</span>
|
||||||
<span>Startseite</span>
|
<span>Startseite</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a data-section="uebermich"
|
||||||
|
class="nav-link text-zinc-600 hover:bg-zinc-100 rounded-xl mx-2 flex items-center gap-3 px-4 py-3 font-lexend font-medium hover:translate-x-1 duration-300 transition-all cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined">person</span>
|
||||||
|
<span>Über mich</span>
|
||||||
|
</a>
|
||||||
<a data-section="settings"
|
<a data-section="settings"
|
||||||
class="nav-link text-zinc-600 hover:bg-zinc-100 rounded-xl mx-2 flex items-center gap-3 px-4 py-3 font-lexend font-medium hover:translate-x-1 duration-300 transition-all cursor-pointer">
|
class="nav-link text-zinc-600 hover:bg-zinc-100 rounded-xl mx-2 flex items-center gap-3 px-4 py-3 font-lexend font-medium hover:translate-x-1 duration-300 transition-all cursor-pointer">
|
||||||
<span class="material-symbols-outlined">tune</span>
|
<span class="material-symbols-outlined">tune</span>
|
||||||
|
|
@ -384,6 +389,132 @@ tailwind.config = {
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ══ SECTION: ÜBER MICH ══ -->
|
||||||
|
<div id="section-uebermich" class="hidden">
|
||||||
|
<section class="bg-surface-container-lowest rounded-xl p-8 shadow-sm mb-8">
|
||||||
|
<h3 class="text-xl font-black font-lexend text-on-surface mb-8 flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-primary">person</span>
|
||||||
|
Über mich – Seite bearbeiten
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<!-- Bild -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-3">Portrait-Bild</label>
|
||||||
|
<div class="flex gap-6 items-start flex-wrap">
|
||||||
|
<div class="w-36 h-44 rounded-xl overflow-hidden bg-surface-container flex-shrink-0">
|
||||||
|
<img id="umPreview" src="" alt="Portrait" class="w-full h-full object-cover hidden"/>
|
||||||
|
<div id="umPlaceholder" class="w-full h-full flex flex-col items-center justify-center text-on-surface-variant">
|
||||||
|
<span class="material-symbols-outlined text-4xl mb-2">image</span>
|
||||||
|
<span class="text-xs font-medium">Kein Bild</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-48">
|
||||||
|
<label for="umFileInput" class="block border-2 border-dashed border-primary/30 bg-surface-container-low rounded-xl p-6 text-center cursor-pointer hover:border-primary/60 transition-all mb-3">
|
||||||
|
<span class="material-symbols-outlined text-primary block mb-2">upload_file</span>
|
||||||
|
<p class="text-sm font-bold text-primary font-lexend">Bild auswählen</p>
|
||||||
|
<p class="text-xs text-on-surface-variant mt-1">JPG, PNG, HEIC</p>
|
||||||
|
</label>
|
||||||
|
<input type="file" id="umFileInput" accept="image/*" class="sr-only"/>
|
||||||
|
<button id="umUploadBtn" disabled class="w-full py-3 rounded-xl font-bold text-sm bg-gradient-to-r from-primary to-primary-container text-on-primary shadow-md shadow-primary/20 disabled:opacity-40 disabled:cursor-not-allowed active:scale-95 transition-all font-lexend">Bild hochladen</button>
|
||||||
|
<p id="umUploadStatus" class="text-xs text-on-surface-variant mt-2 text-center"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hero-Texte -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Badge (z.B. "Meine Reise")</label>
|
||||||
|
<input id="umBadge" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Aktueller Rang</label>
|
||||||
|
<input id="umRang" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Überschrift Zeile 1</label>
|
||||||
|
<input id="umH1" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm font-black uppercase"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Überschrift Zeile 2 (farbig)</label>
|
||||||
|
<input id="umH2" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm font-black uppercase"/>
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Überschrift Rest</label>
|
||||||
|
<input id="umHSuffix" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm font-black uppercase"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-6">
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Beschreibungstext</label>
|
||||||
|
<textarea id="umDesc" rows="4" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm leading-relaxed resize-none"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Aktiver Gurt -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Aktiver Gurt</label>
|
||||||
|
<select id="umGurt" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm">
|
||||||
|
<option>Weiß</option><option>Gelb</option><option>Orange</option><option>Grün</option>
|
||||||
|
<option>Blau</option><option>Lila</option><option>Braun</option><option>Schwarz</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Haupterfolg -->
|
||||||
|
<h4 class="text-sm font-black font-lexend text-on-surface-variant uppercase tracking-widest mt-8 mb-4">Haupterfolg</h4>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Titel</label>
|
||||||
|
<input id="umHeTitel" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Platz / Ergebnis</label>
|
||||||
|
<input id="umHePlatz" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Jahr</label>
|
||||||
|
<input id="umHeJahr" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Ort</label>
|
||||||
|
<input id="umHeOrt" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Kategorie</label>
|
||||||
|
<input id="umHeKat" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-2">
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Beschreibung</label>
|
||||||
|
<textarea id="umHeDesc" rows="3" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm resize-none"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Weitere Erfolge -->
|
||||||
|
<h4 class="text-sm font-black font-lexend text-on-surface-variant uppercase tracking-widest mt-8 mb-4">Weitere Erfolge</h4>
|
||||||
|
<div id="umWeitereFields" class="space-y-3 mb-3"></div>
|
||||||
|
<button id="umWeitereAdd" type="button" class="flex items-center gap-2 text-sm font-bold text-primary border border-primary/30 rounded-xl px-4 py-2 hover:bg-pink-50 transition-all mb-6">
|
||||||
|
<span class="material-symbols-outlined text-base">add</span> Erfolg hinzufügen
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Stats -->
|
||||||
|
<h4 class="text-sm font-black font-lexend text-on-surface-variant uppercase tracking-widest mt-8 mb-4">Statistik-Boxen</h4>
|
||||||
|
<div id="umStatsFields" class="space-y-3 mb-6"></div>
|
||||||
|
|
||||||
|
<!-- Zitat -->
|
||||||
|
<h4 class="text-sm font-black font-lexend text-on-surface-variant uppercase tracking-widest mt-8 mb-4">Zitat</h4>
|
||||||
|
<div class="mb-4">
|
||||||
|
<textarea id="umZitat" rows="3" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm resize-none"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-8">
|
||||||
|
<label class="block text-xs font-bold text-on-surface-variant uppercase tracking-widest mb-2">Autor</label>
|
||||||
|
<input id="umZitatAutor" type="text" class="w-full bg-surface-container-low rounded-DEFAULT px-4 py-3 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="umSaveBtn" class="w-full py-4 rounded-xl font-black text-lg bg-gradient-to-r from-primary to-primary-container text-on-primary shadow-lg shadow-primary/20 active:scale-95 transition-all font-lexend">
|
||||||
|
Änderungen speichern & deployen
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- ══ SECTION: CAREER ══ -->
|
<!-- ══ SECTION: CAREER ══ -->
|
||||||
<div id="section-career" class="hidden">
|
<div id="section-career" class="hidden">
|
||||||
<div class="bg-surface-container-low rounded-xl p-12 text-center">
|
<div class="bg-surface-container-low rounded-xl p-12 text-center">
|
||||||
|
|
@ -477,11 +608,12 @@ tailwind.config = {
|
||||||
let pendingFiles = [];
|
let pendingFiles = [];
|
||||||
|
|
||||||
// ─── Navigation ──────────────────────────────────────────
|
// ─── Navigation ──────────────────────────────────────────
|
||||||
const sections = ['overview', 'media', 'homepage', 'career', 'community', 'settings'];
|
const sections = ['overview', 'media', 'homepage', 'uebermich', 'career', 'community', 'settings'];
|
||||||
const pageTitles = {
|
const pageTitles = {
|
||||||
overview: ['Übersicht', 'Willkommen zurück. Hier ist dein aktueller Stand.'],
|
overview: ['Übersicht', 'Willkommen zurück. Hier ist dein aktueller Stand.'],
|
||||||
media: ['Galerie', 'Fotos hochladen und verwalten.'],
|
media: ['Galerie', 'Fotos hochladen und verwalten.'],
|
||||||
homepage: ['Startseite', 'Hero-Bild und Text der Startseite bearbeiten.'],
|
homepage: ['Startseite', 'Hero-Bild und Text der Startseite bearbeiten.'],
|
||||||
|
uebermich: ['Über mich', 'Seite "Über mich" bearbeiten – Text, Bild, Erfolge, Zitat.'],
|
||||||
career: ['Erfolge', 'Meilensteine und Gürtelprüfungen.'],
|
career: ['Erfolge', 'Meilensteine und Gürtelprüfungen.'],
|
||||||
community: ['Gästebuch', 'Kommentare und Einträge.'],
|
community: ['Gästebuch', 'Kommentare und Einträge.'],
|
||||||
settings: ['Einstellungen', 'Konfiguration des Admin-Bereichs.']
|
settings: ['Einstellungen', 'Konfiguration des Admin-Bereichs.']
|
||||||
|
|
@ -504,6 +636,7 @@ tailwind.config = {
|
||||||
document.getElementById('pageSubtitle').textContent = sub;
|
document.getElementById('pageSubtitle').textContent = sub;
|
||||||
if (name === 'media') loadPhotos();
|
if (name === 'media') loadPhotos();
|
||||||
if (name === 'homepage') loadHomepage();
|
if (name === 'homepage') loadHomepage();
|
||||||
|
if (name === 'uebermich') loadUebermich();
|
||||||
if (name === 'settings') renderCatManage();
|
if (name === 'settings') renderCatManage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1122,6 +1255,167 @@ tailwind.config = {
|
||||||
} catch (err) { console.error('Save error:', err); }
|
} catch (err) { console.error('Save error:', err); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Über mich ────────────────────────────────────────────
|
||||||
|
function createWeitereRow(titel, detail, beschreibung, jahr, ort, kategorie) {
|
||||||
|
const row = document.createElement('div');
|
||||||
|
row.className = 'bg-surface-container-low rounded-xl p-4 flex flex-col gap-2';
|
||||||
|
row.innerHTML =
|
||||||
|
'<div class="flex gap-3 items-center">' +
|
||||||
|
'<input type="text" value="' + (titel||'') + '" placeholder="Titel" data-we="titel"' +
|
||||||
|
' class="flex-1 bg-white rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm font-bold"/>' +
|
||||||
|
'<input type="text" value="' + (detail||'') + '" placeholder="Untertitel (z.B. Silber – Kata 2024)" data-we="detail"' +
|
||||||
|
' class="flex-1 bg-white rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>' +
|
||||||
|
'<button type="button" class="we-delete shrink-0 w-8 h-8 flex items-center justify-center rounded-lg text-error hover:bg-error/10 transition-all">' +
|
||||||
|
'<span class="material-symbols-outlined text-lg">delete</span></button>' +
|
||||||
|
'</div>' +
|
||||||
|
'<textarea data-we="beschreibung" rows="2" placeholder="Beschreibung (optional)"' +
|
||||||
|
' class="w-full bg-white rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm resize-none">' + (beschreibung||'') + '</textarea>' +
|
||||||
|
'<div class="flex gap-3">' +
|
||||||
|
'<input type="text" value="' + (jahr||'') + '" placeholder="Jahr (z.B. 2024)" data-we="jahr"' +
|
||||||
|
' class="w-28 bg-white rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>' +
|
||||||
|
'<input type="text" value="' + (ort||'') + '" placeholder="Ort (z.B. Berlin)" data-we="ort"' +
|
||||||
|
' class="flex-1 bg-white rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>' +
|
||||||
|
'<input type="text" value="' + (kategorie||'') + '" placeholder="Kategorie (z.B. U14)" data-we="kategorie"' +
|
||||||
|
' class="w-28 bg-white rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>' +
|
||||||
|
'</div>';
|
||||||
|
row.querySelector('.we-delete').addEventListener('click', function() { row.remove(); });
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('umWeitereAdd').addEventListener('click', function() {
|
||||||
|
document.getElementById('umWeitereFields').appendChild(createWeitereRow('', ''));
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadUebermich() {
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/uebermich');
|
||||||
|
const d = await r.json();
|
||||||
|
document.getElementById('umBadge').value = d.hero.badge || '';
|
||||||
|
document.getElementById('umRang').value = d.hero.rang_value || '';
|
||||||
|
document.getElementById('umH1').value = d.hero.heading_line1 || '';
|
||||||
|
document.getElementById('umH2').value = d.hero.heading_line2 || '';
|
||||||
|
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 = '';
|
||||||
|
(d.stats || []).forEach(function(s) {
|
||||||
|
const row = document.createElement('div');
|
||||||
|
row.className = 'flex gap-3 items-center';
|
||||||
|
row.innerHTML =
|
||||||
|
'<input type="text" value="' + (s.wert||'') + '" placeholder="Wert" data-us="wert"' +
|
||||||
|
' class="w-24 bg-surface-container-low rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm font-black text-center"/>' +
|
||||||
|
'<input type="text" value="' + (s.label||'') + '" placeholder="Bezeichnung" data-us="label"' +
|
||||||
|
' class="flex-1 bg-surface-container-low rounded-DEFAULT px-3 py-2 text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/30 text-sm"/>';
|
||||||
|
sf.appendChild(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (d.hero.image) {
|
||||||
|
document.getElementById('umPreview').src = '/uebermich/' + d.hero.image + '?t=' + Date.now();
|
||||||
|
document.getElementById('umPreview').classList.remove('hidden');
|
||||||
|
document.getElementById('umPlaceholder').classList.add('hidden');
|
||||||
|
}
|
||||||
|
} catch(err) { console.error('Uebermich load error:', err); }
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('umFileInput').addEventListener('change', function() {
|
||||||
|
const file = this.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
document.getElementById('umPreview').src = URL.createObjectURL(file);
|
||||||
|
document.getElementById('umPreview').classList.remove('hidden');
|
||||||
|
document.getElementById('umPlaceholder').classList.add('hidden');
|
||||||
|
document.getElementById('umUploadBtn').disabled = false;
|
||||||
|
document.getElementById('umUploadStatus').textContent = file.name;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('umUploadBtn').addEventListener('click', async function() {
|
||||||
|
const file = document.getElementById('umFileInput').files[0];
|
||||||
|
if (!file) return;
|
||||||
|
this.disabled = true;
|
||||||
|
document.getElementById('umUploadStatus').textContent = 'Wird hochgeladen…';
|
||||||
|
try {
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('image', file);
|
||||||
|
const r = await fetch('/api/uebermich/image', { method: 'POST', body: fd });
|
||||||
|
if (r.ok) {
|
||||||
|
showToast('✓ Bild gespeichert');
|
||||||
|
document.getElementById('umUploadStatus').textContent = 'Gespeichert!';
|
||||||
|
} else {
|
||||||
|
document.getElementById('umUploadStatus').textContent = 'Fehler beim Upload';
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
document.getElementById('umUploadStatus').textContent = 'Verbindungsfehler';
|
||||||
|
}
|
||||||
|
this.disabled = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('umSaveBtn').addEventListener('click', async function() {
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/uebermich');
|
||||||
|
const data = await r.json();
|
||||||
|
|
||||||
|
data.hero.badge = document.getElementById('umBadge').value;
|
||||||
|
data.hero.rang_value = document.getElementById('umRang').value;
|
||||||
|
data.hero.heading_line1 = document.getElementById('umH1').value;
|
||||||
|
data.hero.heading_line2 = document.getElementById('umH2').value;
|
||||||
|
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 {
|
||||||
|
wert: row.querySelector('[data-us="wert"]').value,
|
||||||
|
label: row.querySelector('[data-us="label"]').value
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await fetch('/api/uebermich', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
if (res.ok) showToast('✓ Über mich gespeichert & Deploy gestartet');
|
||||||
|
} catch(err) { console.error('Save error:', err); }
|
||||||
|
});
|
||||||
|
|
||||||
// ─── Init ─────────────────────────────────────────────────
|
// ─── Init ─────────────────────────────────────────────────
|
||||||
loadCategories().then(function () { loadStats(); });
|
loadCategories().then(function () { loadStats(); });
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -1 +1,6 @@
|
||||||
["Training", "Wettkämpfe", "Gürtelprüfungen"]
|
[
|
||||||
|
"Training",
|
||||||
|
"Wettkämpfe",
|
||||||
|
"Gürtelprüfungen",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
112
data/uebermich.json
Normal file
112
data/uebermich.json
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
"hero": {
|
||||||
|
"badge": "Meine Reise h",
|
||||||
|
"heading_line1": "KINETISCHE h",
|
||||||
|
"heading_line2": "ELEGANZ h",
|
||||||
|
"heading_suffix": "IN JEDEM SCHLAG. h",
|
||||||
|
"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",
|
||||||
|
"rang_label": "Aktueller Rang",
|
||||||
|
"rang_value": "Lila "
|
||||||
|
},
|
||||||
|
"gurtweg": {
|
||||||
|
"title": "Der Weg zur Meisterschaft",
|
||||||
|
"subtitle": "Jeder Gürtel erzählt eine Geschichte aus Hingabe und Wachstum.",
|
||||||
|
"aktiver_gurt": "Lila",
|
||||||
|
"gurte": [
|
||||||
|
{
|
||||||
|
"name": "Weiß",
|
||||||
|
"farbe": "bg-white border-2 border-zinc-300"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gelb",
|
||||||
|
"farbe": "bg-yellow-400"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Orange",
|
||||||
|
"farbe": "bg-orange-500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Grün",
|
||||||
|
"farbe": "bg-green-600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Blau",
|
||||||
|
"farbe": "bg-blue-600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lila",
|
||||||
|
"farbe": "bg-purple-700"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Braun",
|
||||||
|
"farbe": "bg-red-700"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Schwarz",
|
||||||
|
"farbe": "bg-zinc-900"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"haupterfolg": {
|
||||||
|
"titel": "Landesmeisterschaft Berlin h",
|
||||||
|
"platz": "Gold – Kata U14 h",
|
||||||
|
"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",
|
||||||
|
"kategorie": "U14"
|
||||||
|
},
|
||||||
|
"weitere_erfolge": [
|
||||||
|
{
|
||||||
|
"titel": "Norddeutsche Meisterschaft",
|
||||||
|
"detail": "Silber – Kata 2024",
|
||||||
|
"beschreibung": "fdfffdfdfdfd\nfdf",
|
||||||
|
"jahr": "2099",
|
||||||
|
"ort": "Heilbronn",
|
||||||
|
"kategorie": "haha"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"titel": "Dojo Champion",
|
||||||
|
"detail": "Kiai Berlin, intern",
|
||||||
|
"beschreibung": "fdffdfdfde",
|
||||||
|
"jahr": "",
|
||||||
|
"ort": "",
|
||||||
|
"kategorie": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"titel": "Fairness-Preis",
|
||||||
|
"detail": "Dojo-Auszeichnung 2023",
|
||||||
|
"beschreibung": "hghghfghfghfghfg",
|
||||||
|
"jahr": "",
|
||||||
|
"ort": "",
|
||||||
|
"kategorie": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"titel": "Der beste",
|
||||||
|
"detail": "Ganz oben auf dem Treppchen",
|
||||||
|
"beschreibung": "eqweqweqw",
|
||||||
|
"jahr": "",
|
||||||
|
"ort": "",
|
||||||
|
"kategorie": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
.editorial-shadow { box-shadow: 0 24px 40px -10px rgba(44, 47, 48, 0.06); }
|
.editorial-shadow { box-shadow: 0 24px 40px -10px rgba(44, 47, 48, 0.06); }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
{{ $um := .Site.Data.uebermich }}
|
||||||
<body class="bg-surface font-body text-on-surface">
|
<body class="bg-surface font-body text-on-surface">
|
||||||
|
|
||||||
<!-- TopAppBar -->
|
<!-- TopAppBar -->
|
||||||
|
|
@ -86,19 +87,21 @@
|
||||||
<section class="max-w-7xl mx-auto px-6 mb-24">
|
<section class="max-w-7xl mx-auto px-6 mb-24">
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
|
<div class="grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
|
||||||
<div class="lg:col-span-7">
|
<div class="lg:col-span-7">
|
||||||
<span class="text-primary font-bold tracking-[0.2em] uppercase text-sm mb-4 block">Meine Reise</span>
|
<span class="text-primary font-bold tracking-[0.2em] uppercase text-sm mb-4 block">{{ $um.hero.badge }}</span>
|
||||||
<h1 class="text-6xl md:text-8xl font-headline font-extrabold text-on-surface leading-[0.9] tracking-tighter mb-8">
|
<h1 class="text-6xl md:text-8xl font-headline font-extrabold text-on-surface leading-[0.9] tracking-tighter mb-8">
|
||||||
KINETISCHE <span class="text-glass-gradient">ELEGANZ</span> IN JEDEM SCHLAG.
|
{{ $um.hero.heading_line1 }} <span class="text-glass-gradient">{{ $um.hero.heading_line2 }}</span> {{ $um.hero.heading_suffix }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-xl text-on-surface-variant leading-relaxed max-w-xl">
|
<p class="text-xl text-on-surface-variant leading-relaxed max-w-xl">
|
||||||
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.
|
{{ $um.hero.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="lg:col-span-5 relative">
|
<div class="lg:col-span-5 relative">
|
||||||
<div class="aspect-[4/5] rounded-xl overflow-hidden editorial-shadow bg-surface-container-highest">
|
<div class="aspect-[4/5] rounded-xl overflow-hidden editorial-shadow bg-surface-container-highest">
|
||||||
<img class="w-full h-full object-cover"
|
{{ if $um.hero.image }}
|
||||||
src="https://lh3.googleusercontent.com/aida-public/AB6AXuD_gAlNnXIZRs_NnR68igfJUfHX1ueNZlrjMt15L5xNz3bnL4235YADrLG-nT3wz2ZWYEZy6Dom8-fgsolN77eu_0JF52Xp-YjWEre5kwxN2D6V5LAoXI_T8I2YSU6LI5ZybF1Y1Ynqp8Y2IzCh0DYZOqY_tlPOuzsExGMn7nO0jWw58sR7Ny1674begJzhSNxELjEE7oQfgLjSZaO17dv1vGG5LykvtL9NEqM2JXdOVh0SlsnUN4416utgLZpV8km6wUza_TY7Fg"
|
<img class="w-full h-full object-cover" src="/uebermich/{{ $um.hero.image }}" alt="{{ $um.hero.image_alt }}"/>
|
||||||
alt="Miya beim Karate-Kick"/>
|
{{ else }}
|
||||||
|
<div class="w-full h-full flex items-center justify-center text-on-surface-variant text-sm">Kein Bild hochgeladen</div>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute -bottom-10 -left-10 bg-white p-8 rounded-lg editorial-shadow hidden md:block">
|
<div class="absolute -bottom-10 -left-10 bg-white p-8 rounded-lg editorial-shadow hidden md:block">
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
|
|
@ -106,8 +109,8 @@
|
||||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">workspace_premium</span>
|
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">workspace_premium</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-sm font-bold uppercase tracking-widest text-secondary">Aktueller Rang</div>
|
<div class="text-sm font-bold uppercase tracking-widest text-secondary">{{ $um.hero.rang_label }}</div>
|
||||||
<div class="text-2xl font-headline font-black text-on-surface">Blaugurt</div>
|
<div class="text-2xl font-headline font-black text-on-surface">{{ $um.hero.rang_value }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -120,8 +123,8 @@
|
||||||
<div class="max-w-7xl mx-auto px-6">
|
<div class="max-w-7xl mx-auto px-6">
|
||||||
<div class="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
|
<div class="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-4xl font-headline font-bold text-on-surface mb-2">Der Weg zur Meisterschaft</h2>
|
<h2 class="text-4xl font-headline font-bold text-on-surface mb-2">{{ $um.gurtweg.title }}</h2>
|
||||||
<p class="text-on-surface-variant">Jeder Gürtel erzählt eine Geschichte aus Hingabe und Wachstum.</p>
|
<p class="text-on-surface-variant">{{ $um.gurtweg.subtitle }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<span class="px-4 py-2 bg-secondary text-on-secondary rounded-full text-xs font-bold uppercase tracking-widest">Aktiver Status</span>
|
<span class="px-4 py-2 bg-secondary text-on-secondary rounded-full text-xs font-bold uppercase tracking-widest">Aktiver Status</span>
|
||||||
|
|
@ -129,115 +132,87 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap justify-between gap-4">
|
<div class="flex flex-wrap justify-between gap-4">
|
||||||
<div class="flex flex-col items-center gap-4 opacity-40">
|
{{ range $um.gurtweg.gurte }}
|
||||||
<div class="w-24 h-4 bg-white rounded-full border-2 border-zinc-300"></div>
|
{{ $aktiv := eq .name $um.gurtweg.aktiver_gurt }}
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter">Weiß</span>
|
<div class="flex flex-col items-center gap-4 {{ if not $aktiv }}{{ if eq .name "Schwarz" }}opacity-10{{ else if eq .name "Braun" }}opacity-20{{ else if eq .name "Lila" }}opacity-30{{ else if eq .name "Grün" }}opacity-50{{ else }}opacity-40{{ end }}{{ end }}">
|
||||||
</div>
|
<div class="w-24 {{ if $aktiv }}h-6 shadow-lg ring-4 ring-primary/20{{ else }}h-4{{ end }} {{ .farbe }} rounded-full"></div>
|
||||||
<div class="flex flex-col items-center gap-4 opacity-40">
|
<span class="font-bold text-xs uppercase tracking-tighter {{ if $aktiv }}text-primary{{ end }}">{{ .name }}{{ if $aktiv }} ✓{{ end }}</span>
|
||||||
<div class="w-24 h-4 bg-yellow-400 rounded-full"></div>
|
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter">Gelb</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col items-center gap-4 opacity-40">
|
|
||||||
<div class="w-24 h-4 bg-orange-500 rounded-full"></div>
|
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter">Orange</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col items-center gap-4 opacity-50">
|
|
||||||
<div class="w-24 h-4 bg-green-600 rounded-full"></div>
|
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter">Grün</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col items-center gap-4">
|
|
||||||
<div class="w-24 h-6 bg-blue-600 rounded-full shadow-lg ring-4 ring-primary/20"></div>
|
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter text-primary">Blau ✓</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col items-center gap-4 opacity-30">
|
|
||||||
<div class="w-24 h-4 bg-purple-700 rounded-full"></div>
|
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter">Lila</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col items-center gap-4 opacity-20">
|
|
||||||
<div class="w-24 h-4 bg-red-700 rounded-full"></div>
|
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter">Braun</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col items-center gap-4 opacity-10">
|
|
||||||
<div class="w-24 h-4 bg-zinc-900 rounded-full"></div>
|
|
||||||
<span class="font-bold text-xs uppercase tracking-tighter">Schwarz</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Meilensteine Bento Grid -->
|
<!-- Meilensteine -->
|
||||||
<section class="max-w-7xl mx-auto px-6 mt-24">
|
<section class="max-w-7xl mx-auto px-6 mt-24">
|
||||||
<h2 class="text-5xl font-headline font-black mb-16 tracking-tight">MEILENSTEINE DES <span class="text-primary italic">ERFOLGS</span></h2>
|
<h2 class="text-5xl font-headline font-black mb-16 tracking-tight">MEILENSTEINE DES <span class="text-primary italic">ERFOLGS</span></h2>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
<!-- Große Achievement-Karte -->
|
<!-- Haupterfolg -->
|
||||||
<div class="md:col-span-2 bg-surface-container-lowest rounded-xl p-10 editorial-shadow flex flex-col justify-between relative overflow-hidden group">
|
<div class="md:col-span-2 bg-surface-container-lowest rounded-xl p-10 editorial-shadow flex flex-col justify-between relative overflow-hidden group">
|
||||||
<div class="relative z-10">
|
<div class="relative z-10">
|
||||||
<div class="flex items-center gap-4 mb-6">
|
<div class="flex items-center gap-4 mb-6">
|
||||||
<span class="material-symbols-outlined text-4xl text-primary" style="font-variation-settings: 'FILL' 1;">military_tech</span>
|
<span class="material-symbols-outlined text-4xl text-primary" style="font-variation-settings: 'FILL' 1;">military_tech</span>
|
||||||
<span class="font-headline font-extrabold text-2xl uppercase italic">Landesmeisterschaft Berlin</span>
|
<span id="he-titel" class="font-headline font-extrabold text-2xl uppercase italic">{{ $um.haupterfolg.titel }}</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-4xl font-headline font-bold text-on-surface mb-4">Gold – Kata U14</h3>
|
<h3 id="he-platz" class="text-4xl font-headline font-bold text-on-surface mb-4">{{ $um.haupterfolg.platz }}</h3>
|
||||||
<p class="text-on-surface-variant max-w-md text-lg">Mein bisher größter Erfolg. Monatelanges hartes Training gipfelte in einer Vorführung, die meinen Wettkampfgeist unter Beweis stellte.</p>
|
<p id="he-desc" class="text-on-surface-variant max-w-md text-lg">{{ $um.haupterfolg.beschreibung }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-12 flex items-center gap-6 relative z-10">
|
<div class="mt-12 flex items-center gap-6 relative z-10">
|
||||||
<div class="text-left">
|
<div class="text-left">
|
||||||
<div class="text-3xl font-black text-on-surface">2024</div>
|
<div id="he-jahr" class="text-3xl font-black text-on-surface">{{ $um.haupterfolg.jahr }}</div>
|
||||||
<div class="text-xs uppercase tracking-widest font-bold text-primary">Berlin</div>
|
<div id="he-ort" class="text-xs uppercase tracking-widest font-bold text-primary">{{ $um.haupterfolg.ort }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-10 w-[1px] bg-outline-variant/30"></div>
|
<div class="h-10 w-[1px] bg-outline-variant/30"></div>
|
||||||
<div class="text-left">
|
<div class="text-left">
|
||||||
<div class="text-3xl font-black text-on-surface">U14</div>
|
<div id="he-kat" class="text-3xl font-black text-on-surface">{{ $um.haupterfolg.kategorie }}</div>
|
||||||
<div class="text-xs uppercase tracking-widest font-bold text-primary">Kategorie</div>
|
<div class="text-xs uppercase tracking-widest font-bold text-primary">Kategorie</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span class="material-symbols-outlined absolute -bottom-10 -right-10 text-[15rem] text-surface-container opacity-20 group-hover:opacity-30 transition-opacity">sports_martial_arts</span>
|
<span class="material-symbols-outlined absolute -bottom-10 -right-10 text-[15rem] text-surface-container opacity-20 group-hover:opacity-30 transition-opacity">sports_martial_arts</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Weitere Auszeichnungen -->
|
<!-- Weitere Erfolge -->
|
||||||
<div class="bg-primary rounded-xl p-8 text-on-primary flex flex-col gap-8 shadow-2xl shadow-primary/20">
|
<div class="bg-primary rounded-xl p-8 text-on-primary flex flex-col gap-8 shadow-2xl shadow-primary/20">
|
||||||
<h4 class="font-headline font-bold text-xl border-b border-on-primary/20 pb-4">Weitere Erfolge</h4>
|
<h4 class="font-headline font-bold text-xl border-b border-on-primary/20 pb-4">Weitere Erfolge</h4>
|
||||||
<div class="flex gap-4">
|
{{ $icons := slice "star" "emoji_events" "rewarded_ads" "military_tech" "workspace_premium" }}
|
||||||
|
{{ range $i, $e := $um.weitere_erfolge }}
|
||||||
|
<div class="weitere-erfolg-item flex gap-4 cursor-pointer rounded-lg p-2 -m-2 hover:bg-white/10 transition-all active:scale-95"
|
||||||
|
data-titel="{{ $e.titel }}"
|
||||||
|
data-detail="{{ $e.detail }}"
|
||||||
|
data-beschreibung="{{ $e.beschreibung }}"
|
||||||
|
data-jahr="{{ $e.jahr }}"
|
||||||
|
data-ort="{{ $e.ort }}"
|
||||||
|
data-kategorie="{{ $e.kategorie }}">
|
||||||
<div class="w-10 h-10 rounded-full bg-white/20 flex items-center justify-center shrink-0">
|
<div class="w-10 h-10 rounded-full bg-white/20 flex items-center justify-center shrink-0">
|
||||||
<span class="material-symbols-outlined text-xl">star</span>
|
<span class="material-symbols-outlined text-xl">{{ index $icons $i }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="font-bold">Norddeutsche Meisterschaft</p>
|
<p class="font-bold">{{ $e.titel }}</p>
|
||||||
<p class="text-sm opacity-80">Silber – Kata 2024</p>
|
<p class="text-sm opacity-80">{{ $e.detail }}</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-4">
|
|
||||||
<div class="w-10 h-10 rounded-full bg-white/20 flex items-center justify-center shrink-0">
|
|
||||||
<span class="material-symbols-outlined text-xl">emoji_events</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p class="font-bold">Dojo Champion</p>
|
|
||||||
<p class="text-sm opacity-80">Kiai Berlin, intern</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-4">
|
|
||||||
<div class="w-10 h-10 rounded-full bg-white/20 flex items-center justify-center shrink-0">
|
|
||||||
<span class="material-symbols-outlined text-xl">rewarded_ads</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p class="font-bold">Fairness-Preis</p>
|
|
||||||
<p class="text-sm opacity-80">Dojo-Auszeichnung 2023</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Stats -->
|
<!-- Stats -->
|
||||||
|
{{ range $i, $s := $um.stats }}
|
||||||
|
{{ if eq $i 0 }}
|
||||||
<div class="bg-secondary-container rounded-xl p-8 flex flex-col justify-center gap-2">
|
<div class="bg-secondary-container rounded-xl p-8 flex flex-col justify-center gap-2">
|
||||||
<span class="text-on-secondary-container font-headline font-black text-6xl italic">5+</span>
|
<span class="text-on-secondary-container font-headline font-black text-6xl italic">{{ $s.wert }}</span>
|
||||||
<span class="text-secondary font-bold uppercase tracking-[0.2em] text-sm">Jahre Training</span>
|
<span class="text-secondary font-bold uppercase tracking-[0.2em] text-sm">{{ $s.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{{ else if eq $i 1 }}
|
||||||
<div class="bg-surface-container-highest rounded-xl p-8 flex flex-col justify-center gap-2">
|
<div class="bg-surface-container-highest rounded-xl p-8 flex flex-col justify-center gap-2">
|
||||||
<span class="text-on-surface font-headline font-black text-6xl italic">32</span>
|
<span class="text-on-surface font-headline font-black text-6xl italic">{{ $s.wert }}</span>
|
||||||
<span class="text-on-surface-variant font-bold uppercase tracking-[0.2em] text-sm">Turniere</span>
|
<span class="text-on-surface-variant font-bold uppercase tracking-[0.2em] text-sm">{{ $s.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{{ else }}
|
||||||
<div class="bg-white rounded-xl p-8 editorial-shadow flex flex-col justify-center gap-2 border-t-4 border-pink-500">
|
<div class="bg-white rounded-xl p-8 editorial-shadow flex flex-col justify-center gap-2 border-t-4 border-pink-500">
|
||||||
<span class="text-pink-600 font-headline font-black text-6xl italic">12</span>
|
<span class="text-pink-600 font-headline font-black text-6xl italic">{{ $s.wert }}</span>
|
||||||
<span class="text-zinc-500 font-bold uppercase tracking-[0.2em] text-sm">Goldmedaillen</span>
|
<span class="text-zinc-500 font-bold uppercase tracking-[0.2em] text-sm">{{ $s.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -245,9 +220,9 @@
|
||||||
<section class="max-w-4xl mx-auto px-6 py-32 text-center">
|
<section class="max-w-4xl mx-auto px-6 py-32 text-center">
|
||||||
<span class="material-symbols-outlined text-primary text-6xl mb-8" style="font-variation-settings: 'FILL' 1;">format_quote</span>
|
<span class="material-symbols-outlined text-primary text-6xl mb-8" style="font-variation-settings: 'FILL' 1;">format_quote</span>
|
||||||
<blockquote class="text-3xl md:text-5xl font-headline font-bold text-on-surface leading-tight tracking-tight italic">
|
<blockquote class="text-3xl md:text-5xl font-headline font-bold text-on-surface leading-tight tracking-tight italic">
|
||||||
"Karate ist nicht nur ein Sport. Es ist eine Linse, durch die ich die Welt sehe – mit Präzision, Respekt und unbeugsamer Konzentration."
|
"{{ $um.zitat.text }}"
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<p class="mt-8 font-bold uppercase tracking-widest text-on-surface-variant">— Miya</p>
|
<p class="mt-8 font-bold uppercase tracking-widest text-on-surface-variant">— {{ $um.zitat.autor }}</p>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
@ -264,5 +239,31 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('.weitere-erfolg-item').forEach(function(item) {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
const titel = this.dataset.titel;
|
||||||
|
const detail = this.dataset.detail;
|
||||||
|
const beschreibung = this.dataset.beschreibung || '';
|
||||||
|
const jahr = this.dataset.jahr || '';
|
||||||
|
const ort = this.dataset.ort || '';
|
||||||
|
const kategorie = this.dataset.kategorie || '';
|
||||||
|
|
||||||
|
// Hauptkarte tauschen
|
||||||
|
document.getElementById('he-titel').textContent = titel;
|
||||||
|
document.getElementById('he-platz').textContent = detail;
|
||||||
|
document.getElementById('he-desc').textContent = beschreibung;
|
||||||
|
document.getElementById('he-jahr').textContent = jahr;
|
||||||
|
document.getElementById('he-ort').textContent = ort;
|
||||||
|
document.getElementById('he-kat').textContent = kategorie;
|
||||||
|
|
||||||
|
// Aktives Item hervorheben
|
||||||
|
document.querySelectorAll('.weitere-erfolg-item').forEach(function(el) {
|
||||||
|
el.classList.remove('bg-white/20', 'ring-2', 'ring-white/40');
|
||||||
|
});
|
||||||
|
this.classList.add('bg-white/20', 'ring-2', 'ring-white/40');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue