Emy/layouts/erfolge/list.html

720 lines
38 KiB
HTML
Raw Normal View History

2026-04-11 21:48:34 +00:00
<!DOCTYPE html>
<html class="scroll-smooth" lang="de">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
2026-04-22 21:50:21 +00:00
<title>Erfolge | {{ .Site.Data.homepage.siteTitle | default .Site.Title }}</title>
2026-04-11 21:48:34 +00:00
<link href="https://fonts.googleapis.com" rel="preconnect"/>
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
<link href="https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700;800;900&family=Be+Vietnam+Pro:wght@300;400;500;600;700&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<script id="tailwind-config">
tailwind.config = {
darkMode: "class",
theme: {
extend: {
"colors": {
2026-05-21 09:51:56 +00:00
"belt-green": "#10b981", "belt-green-glow": "#059669",
2026-04-11 21:48:34 +00:00
"tertiary-container": "#ffffff", "surface-bright": "#f5f6f7",
"on-tertiary-container": "#636262", "error-dim": "#a70138",
"on-surface-variant": "#595c5d", "surface-tint": "#b30065",
"surface-container-highest": "#dadddf", "on-secondary-fixed-variant": "#7d21a4",
"inverse-on-surface": "#9b9d9e", "inverse-surface": "#0c0f10",
"surface-container": "#e6e8ea", "surface": "#f5f6f7",
"primary-fixed": "#ff6ea9", "surface-container-low": "#eff1f2",
"secondary": "#8930b0", "tertiary": "#5c5b5b",
"on-secondary": "#ffedff", "secondary-dim": "#7c20a3",
"secondary-container": "#f0c1ff", "surface-dim": "#d1d5d7",
"primary": "#b30065", "on-primary-fixed": "#000000",
"surface-container-high": "#e0e3e4", "primary-fixed-dim": "#ff4e9e",
"primary-dim": "#9d0058", "outline": "#757778",
"error": "#b41340", "outline-variant": "#abadae",
"secondary-fixed": "#f0c1ff", "secondary-fixed-dim": "#eaaeff",
"tertiary-fixed-dim": "#f3f0ef", "on-surface": "#2c2f30",
"on-tertiary-fixed-variant": "#6e6d6d", "on-tertiary": "#f5f2f1",
"tertiary-fixed": "#ffffff", "background": "#f5f6f7",
"on-primary": "#ffeff2", "surface-container-lowest": "#ffffff",
"inverse-primary": "#ff479c", "primary-container": "#ff6ea9",
"on-primary-fixed-variant": "#5c0031", "on-secondary-container": "#72129a",
"error-container": "#f74b6d", "surface-variant": "#dadddf",
"on-background": "#2c2f30", "on-error": "#ffefef",
"on-tertiary-fixed": "#515050", "tertiary-dim": "#504f4f",
"on-primary-container": "#4b0027", "on-secondary-fixed": "#580079",
"on-error-container": "#510017"
},
"borderRadius": {
"DEFAULT": "1rem", "lg": "2rem", "xl": "3rem", "full": "9999px"
},
"fontFamily": {
"headline": ["Lexend"], "body": ["Be Vietnam Pro"], "label": ["Be Vietnam Pro"]
2026-05-21 09:51:56 +00:00
},
"keyframes": {
"reveal-up": {
"0%": { opacity: "0", transform: "translateY(50px) scale(0.95)" },
"100%": { opacity: "1", transform: "translateY(0) scale(1)" }
},
"orb-float": {
"0%, 100%": { transform: "translate(0px, 0px) scale(1)" },
"33%": { transform: "translate(30px, -50px) scale(1.1)" },
"66%": { transform: "translate(-20px, 20px) scale(0.9)" }
}
},
"animation": {
"reveal-up": "reveal-up 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards",
"orb-float": "orb-float 15s ease-in-out infinite",
"orb-float-slow": "orb-float 20s ease-in-out infinite reverse"
2026-04-11 21:48:34 +00:00
}
},
},
}
</script>
<style>
.material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
.text-glass-gradient {
background: linear-gradient(135deg, #b30065, #ff6ea9);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.editorial-shadow { box-shadow: 0 24px 40px -10px rgba(44, 47, 48, 0.06); }
</style>
</head>
<body class="bg-surface font-body text-on-surface">
<!-- TopAppBar -->
<header class="bg-white/70 dark:bg-zinc-900/70 backdrop-blur-lg fixed top-0 left-0 w-full z-50 shadow-xl shadow-pink-500/5">
<div class="flex justify-between items-center h-20 px-6 md:px-12 max-w-screen-2xl mx-auto">
2026-05-21 09:51:56 +00:00
<a href="{{ "/" | relURL }}" class="flex items-center gap-3 text-2xl font-black text-pink-600 dark:text-pink-400 italic font-headline tracking-tight uppercase group hover:opacity-80 transition-opacity">
<span>{{ .Site.Data.homepage.siteTitle | default .Site.Title }}</span>
</a>
2026-04-11 21:48:34 +00:00
<nav class="hidden md:flex items-center space-x-8 font-headline tracking-tight uppercase font-bold">
<a class="text-zinc-600 dark:text-zinc-400 font-medium hover:text-pink-500 dark:hover:text-pink-300 transition-colors duration-300" href="/">Home</a>
<a class="text-zinc-600 dark:text-zinc-400 font-medium hover:text-pink-500 dark:hover:text-pink-300 transition-colors duration-300" href="/galerie/">Galerie</a>
<a class="text-zinc-600 dark:text-zinc-400 font-medium hover:text-pink-500 dark:hover:text-pink-300 transition-colors duration-300" href="/uebermich/">Über mich</a>
<a class="text-pink-600 dark:text-pink-400 border-b-2 border-pink-500 pb-1" href="/erfolge/">Erfolge</a>
<a class="text-zinc-600 dark:text-zinc-400 font-medium hover:text-pink-500 dark:hover:text-pink-300 transition-colors duration-300" href="/gaestebuch/">Gästebuch</a>
</nav>
<button class="bg-gradient-to-br from-primary to-primary-container text-on-primary px-8 py-3 rounded-xl font-bold font-headline uppercase tracking-wider scale-95 active:scale-90 transition-transform">
Kontakt
</button>
</div>
</header>
2026-04-22 21:50:21 +00:00
{{ $e := .Site.Data.erfolge }}
2026-04-11 21:48:34 +00:00
<main class="pt-32 pb-20">
<!-- Hero -->
<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="lg:col-span-7">
2026-04-22 21:50:21 +00:00
<span class="text-primary font-bold tracking-[0.2em] uppercase text-sm mb-4 block">{{ $e.hero.badge }}</span>
2026-04-11 21:48:34 +00:00
<h1 class="text-6xl md:text-8xl font-headline font-extrabold text-on-surface leading-[0.9] tracking-tighter mb-8">
2026-04-22 21:50:21 +00:00
{{ $e.hero.heading_main }} <span class="text-glass-gradient">{{ $e.hero.heading_colored }}</span>
2026-04-11 21:48:34 +00:00
</h1>
<p class="text-xl text-on-surface-variant leading-relaxed max-w-xl">
2026-04-22 21:50:21 +00:00
{{ $e.hero.description }}
2026-04-11 21:48:34 +00:00
</p>
</div>
<div class="lg:col-span-5 relative">
<div class="aspect-[4/5] rounded-xl overflow-hidden editorial-shadow bg-surface-container-highest">
2026-04-22 21:50:21 +00:00
{{ if $e.hero.image }}
<img class="w-full h-full object-cover" src="/erfolge-img/{{ $e.hero.image }}" alt="{{ $e.hero.rang_value }} beim Wettkampf"/>
{{ else }}
<div class="w-full h-full bg-surface-container-high flex items-center justify-center">
<span class="material-symbols-outlined text-surface-variant" style="font-size:6rem;">sports_martial_arts</span>
</div>
{{ end }}
2026-04-11 21:48:34 +00:00
</div>
<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="w-12 h-12 rounded-full bg-secondary flex items-center justify-center text-on-secondary">
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">workspace_premium</span>
</div>
<div>
2026-04-22 21:50:21 +00:00
<div class="text-sm font-bold uppercase tracking-widest text-secondary">{{ $e.hero.rang_label }}</div>
<div class="text-2xl font-headline font-black text-on-surface">{{ $e.hero.rang_value }}</div>
2026-04-11 21:48:34 +00:00
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Alle Erfolge aus Content-Dateien -->
2026-05-21 09:51:56 +00:00
<section class="relative bg-surface-container-low py-24 rounded-t-[5rem] overflow-hidden">
<!-- Animated Orbs Background -->
<div class="absolute top-20 -left-20 w-96 h-96 bg-primary/20 rounded-full mix-blend-multiply filter blur-[100px] opacity-70 animate-orb-float pointer-events-none"></div>
<div class="absolute top-1/2 -right-20 w-[30rem] h-[30rem] bg-belt-green/10 rounded-full mix-blend-multiply filter blur-[120px] opacity-50 animate-orb-float-slow pointer-events-none"></div>
<div class="absolute bottom-20 left-1/3 w-80 h-80 bg-primary-container/20 rounded-full mix-blend-multiply filter blur-[100px] opacity-60 animate-orb-float pointer-events-none"></div>
<div class="max-w-7xl mx-auto px-6 relative z-10">
<h2 class="text-5xl font-headline font-black mb-16 tracking-tight uppercase text-transparent bg-clip-text bg-gradient-to-r from-on-surface via-on-surface-variant to-primary">MEILENSTEINE DES <span class="text-primary italic">ERFOLGS</span></h2>
<!-- Timeline Layout -->
<div class="relative pl-12 md:pl-20 space-y-24">
<!-- Vertical glowing timeline line -->
<div class="absolute left-4 md:left-8 top-12 bottom-0 w-1 bg-gradient-to-b from-primary via-belt-green to-primary opacity-30 blur-[2px]"></div>
<div class="absolute left-[1.1rem] md:left-[2.1rem] top-12 bottom-0 w-[2px] bg-gradient-to-b from-primary via-belt-green to-primary opacity-60"></div>
{{ $mainErfolge := (where (where .Site.RegularPages "Section" "erfolge") "Params.is_weitere_auszeichnung" "!=" "true").ByWeight }}
{{ $totalErfolge := len $mainErfolge }}
{{ range $index, $element := $mainErfolge }}
<div class="relative group opacity-0 translate-y-12 transition-all duration-1000 ease-out scroll-reveal-item">
<!-- Timeline Node / Glowing Dot -->
<div class="absolute -left-[3.5rem] md:-left-[5.5rem] top-12 w-6 h-6 rounded-full bg-surface-container-lowest border-4 border-primary z-10 group-hover:border-belt-green group-hover:shadow-[0_0_15px_rgba(16,185,129,1),0_0_5px_rgba(16,185,129,1)] transition-all duration-500 group-hover:scale-125"></div>
<!-- The Card -->
<div class="erfolg-card flex flex-col {{ if modBool $index 2 }}md:flex-row{{ else }}md:flex-row-reverse{{ end }} bg-surface-container-lowest rounded-3xl editorial-shadow relative overflow-hidden transition-all duration-500 hover:shadow-[0_0_25px_rgba(16,185,129,0.4)] hover:-translate-y-2 group-hover:ring-2 group-hover:ring-belt-green">
2026-05-12 00:17:31 +00:00
{{ if .Params.image }}
<!-- Bild-Bereich -->
<div class="md:w-2/5 relative overflow-hidden bg-surface-container-high shrink-0">
<img src="/erfolge-img/{{ .Params.image }}" class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105" alt="{{ .Title }}" />
<!-- Glassmorphism Overlay für den Rang -->
<div class="absolute top-6 left-6 bg-white/30 backdrop-blur-md border border-white/40 px-4 py-2 rounded-full flex items-center gap-2 shadow-lg">
<span class="material-symbols-outlined text-primary text-sm" style="font-variation-settings: 'FILL' 1;">military_tech</span>
<span class="text-pink-900 font-bold uppercase tracking-widest text-xs">{{ .Params.rang | default "Highlight" }}</span>
</div>
</div>
<!-- Text-Bereich -->
<div class="md:w-3/5 p-10 md:p-14 flex flex-col justify-center relative z-10">
{{ else }}
<!-- Text-Bereich (Kein Bild) -->
<div class="w-full p-10 md:p-14 flex flex-col justify-center relative z-10">
<div class="flex items-center gap-4 mb-6">
2026-04-22 21:50:21 +00:00
<div class="w-12 h-12 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0">
<span class="material-symbols-outlined text-2xl text-primary" style="font-variation-settings: 'FILL' 1;">military_tech</span>
</div>
2026-04-11 21:48:34 +00:00
<span class="bg-secondary text-white px-4 py-1 rounded-full text-xs font-bold uppercase tracking-widest">{{ .Params.rang | default "Highlight" }}</span>
</div>
2026-05-12 00:17:31 +00:00
{{ end }}
<h3 class="text-3xl md:text-4xl font-headline font-extrabold text-on-surface mb-4 leading-tight">{{ .Title }}</h3>
<p class="text-lg text-on-surface-variant leading-relaxed mb-8">{{ .Summary }}</p>
2026-04-22 21:50:21 +00:00
<button onclick="toggleErfolg(this)"
2026-05-12 00:17:31 +00:00
class="inline-flex self-start items-center gap-3 text-white bg-gradient-to-r from-primary to-primary-container px-6 py-3 rounded-xl font-bold text-sm font-headline uppercase tracking-wider hover:scale-105 active:scale-95 transition-all shadow-lg shadow-primary/20">
<span class="btn-label">Ganze Geschichte lesen</span>
2026-04-22 21:50:21 +00:00
<span class="material-symbols-outlined transition-transform duration-300 text-base">expand_more</span>
</button>
2026-05-12 00:17:31 +00:00
<!-- Aufklappbarer Inhalt -->
<div class="erfolg-body overflow-hidden transition-all duration-500 ease-in-out" style="max-height:0">
<div class="pt-8 mt-8 border-t border-surface-container text-on-surface-variant leading-relaxed space-y-4 text-lg">
2026-04-22 21:50:21 +00:00
{{ .Content }}
2026-05-12 00:17:31 +00:00
{{ if .Params.images }}
<div class="mt-8 flex gap-4 overflow-x-auto pb-4 snap-x">
{{ range $img := split .Params.images "," }}
<div class="shrink-0 snap-start relative">
{{ if (or (strings.HasSuffix (lower $img) ".mp4") (strings.HasSuffix (lower $img) ".mov") (strings.HasSuffix (lower $img) ".webm") (strings.HasSuffix (lower $img) ".m4v")) }}
<video src="{{ printf "/erfolge-img/%s" $img | relURL }}" class="h-24 w-24 md:h-32 md:w-32 object-cover rounded-xl cursor-pointer hover:opacity-80 transition-opacity editorial-shadow" onclick="openLightbox(this.src, true)"></video>
<span class="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 text-3xl">play_circle</span>
{{ else }}
<img src="{{ printf "/erfolge-img/%s" $img | relURL }}" class="h-24 w-24 md:h-32 md:w-32 object-cover rounded-xl cursor-pointer hover:opacity-80 transition-opacity editorial-shadow" onclick="openLightbox(this.src, false)"/>
{{ end }}
</div>
{{ end }}
</div>
{{ end }}
{{ if or .Params.datum .Params.ort .Params.kategorie }}
<div class="mt-8 pt-6 border-t border-outline-variant/20 flex flex-wrap items-center justify-between gap-6">
{{ if or .Params.datum .Params.ort }}
<div>
{{ if .Params.datum }}<div class="text-xl font-headline text-on-surface">{{ .Params.datum }}</div>{{ end }}
{{ if .Params.ort }}<div class="text-xs uppercase tracking-widest font-bold text-primary">{{ .Params.ort }}</div>{{ end }}
</div>
{{ end }}
{{ if .Params.kategorie }}
<div class="text-right">
<div class="text-xl font-headline text-on-surface">{{ .Params.kategorie }}</div>
<div class="text-xs uppercase tracking-widest font-bold text-primary">Kategorie</div>
</div>
{{ end }}
</div>
{{ end }}
2026-04-22 21:50:21 +00:00
</div>
2026-05-21 09:51:56 +00:00
<!-- Interaktionsbereich: Likes & Kommentare -->
<div class="mt-8 pt-8 border-t border-outline-variant/20 space-y-6 px-10 pb-8 erfolg-interactions" data-erfolg-id="{{ .File.TranslationBaseName }}">
<!-- Likes & Kommentare Header -->
<div class="flex flex-wrap items-center justify-between gap-4">
<button onclick="likeErfolg('{{ .File.TranslationBaseName }}', this)" class="like-btn flex items-center gap-3 px-6 py-3 rounded-full bg-primary/5 hover:bg-primary/10 text-primary transition-all duration-300 transform active:scale-95 group/like">
<span class="material-symbols-outlined heart-icon transition-transform duration-300 group-hover/like:scale-120" style="font-variation-settings: 'FILL' 0;">favorite</span>
<span class="font-headline font-bold text-sm tracking-wide"><span class="like-count">0</span> Likes</span>
</button>
<div class="flex items-center gap-2.5 text-on-surface-variant text-sm font-bold font-headline uppercase tracking-wider bg-surface-container-low px-5 py-3 rounded-full">
<span class="material-symbols-outlined text-base">forum</span>
<span><span class="comment-count">0</span> Kommentare</span>
</div>
</div>
<!-- Kommentare Liste -->
<div class="comment-list space-y-4 max-h-[350px] overflow-y-auto pr-2 hidden">
<!-- Dynamisch geladen -->
</div>
<!-- Neuen Kommentar schreiben -->
<form onsubmit="submitComment('{{ .File.TranslationBaseName }}', this, event)" class="comment-form space-y-4 bg-surface-container-low p-6 rounded-2xl relative overflow-hidden">
<div class="absolute top-0 left-0 w-2 h-full bg-gradient-to-b from-primary to-primary-container"></div>
<h4 class="text-sm font-bold font-label uppercase tracking-widest text-on-surface-variant mb-1">Deine Geschichte teilen / Kommentar schreiben</h4>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 items-end">
<div class="md:col-span-2 space-y-4">
<input required name="name" type="text" placeholder="Dein Name" class="w-full bg-surface-container-lowest border-none rounded-lg focus:ring-2 focus:ring-primary/20 p-4 text-sm transition-all placeholder:text-outline-variant" />
<textarea required name="text" rows="2" placeholder="Schreib einen kurzen Kommentar..." class="w-full bg-surface-container-lowest border-none rounded-lg focus:ring-2 focus:ring-primary/20 p-4 text-sm transition-all placeholder:text-outline-variant resize-none"></textarea>
</div>
<div class="h-full flex items-end">
<button type="submit" class="w-full h-[52px] bg-gradient-to-r from-primary to-primary-container text-on-primary rounded-lg font-headline font-bold shadow-lg shadow-primary/20 hover:scale-[1.02] active:scale-98 transition-all flex items-center justify-center gap-2">
<span class="material-symbols-outlined text-sm">send</span>
<span>Kommentieren</span>
</button>
</div>
</div>
</form>
</div>
2026-04-22 21:50:21 +00:00
</div>
2026-04-11 21:48:34 +00:00
</div>
2026-05-12 00:17:31 +00:00
<!-- Deko Icon im Hintergrund wenn kein Bild -->
{{ if not .Params.image }}
<span class="material-symbols-outlined absolute -bottom-10 -right-10 text-[20rem] text-surface-container opacity-30 group-hover:opacity-40 transition-opacity pointer-events-none">workspace_premium</span>
{{ end }}
2026-05-21 09:51:56 +00:00
</div> <!-- Ende erfolg-card -->
<!-- Karate Trenner (nicht beim letzten Element) -->
{{ if lt (add $index 1) $totalErfolge }}
<div class="absolute -bottom-[3rem] left-8 right-8 flex items-center justify-center opacity-60 z-0 pointer-events-none">
<div class="h-[2px] bg-gradient-to-r from-transparent via-primary to-transparent flex-grow opacity-50"></div>
<div class="px-4 text-primary bg-surface-container-low rounded-full border border-primary/20 shadow-[0_0_15px_rgba(179,0,101,0.2)] flex items-center justify-center h-8">
<span class="material-symbols-outlined text-2xl">sports_martial_arts</span>
</div>
<div class="h-[2px] bg-gradient-to-r from-primary via-transparent to-transparent flex-grow opacity-50"></div>
</div>
{{ end }}
</div> <!-- Ende relative group -->
2026-04-11 21:48:34 +00:00
{{ end }}
</div>
</div>
</section>
2026-04-22 21:50:21 +00:00
<script>
function toggleErfolg(btn) {
var card = btn.closest('.erfolg-card');
var body = card.querySelector('.erfolg-body');
var icon = btn.querySelector('.material-symbols-outlined');
var label = btn.querySelector('.btn-label');
2026-05-21 09:51:56 +00:00
var isOpen = body.classList.contains('is-open');
2026-04-22 21:50:21 +00:00
if (isOpen) {
2026-05-21 09:51:56 +00:00
body.style.maxHeight = body.scrollHeight + 'px';
body.offsetHeight; // Force reflow
2026-04-22 21:50:21 +00:00
body.style.maxHeight = '0';
2026-05-21 09:51:56 +00:00
body.classList.remove('is-open');
2026-04-22 21:50:21 +00:00
icon.style.transform = '';
2026-05-21 09:51:56 +00:00
label.textContent = 'Ganze Geschichte lesen';
2026-04-22 21:50:21 +00:00
} else {
body.style.maxHeight = body.scrollHeight + 'px';
2026-05-21 09:51:56 +00:00
body.classList.add('is-open');
2026-04-22 21:50:21 +00:00
icon.style.transform = 'rotate(180deg)';
label.textContent = 'Weniger anzeigen';
2026-05-21 09:51:56 +00:00
setTimeout(function() {
if (body.classList.contains('is-open')) {
body.style.maxHeight = 'none';
}
}, 500);
2026-04-22 21:50:21 +00:00
}
}
</script>
2026-04-11 21:48:34 +00:00
<!-- Meilensteine Bento Grid -->
2026-05-12 00:17:31 +00:00
<section class="max-w-7xl mx-auto px-6 mt-48">
2026-04-11 21:48:34 +00:00
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
2026-04-22 21:50:21 +00:00
<!-- Große Karte: Haupt-Meilenstein -->
2026-05-21 09:51:56 +00:00
{{ if $e.meilenstein.event }}
2026-05-12 00:17:31 +00:00
<div class="md:col-span-2 relative">
<!-- Herausfahrendes Bild -->
<div class="absolute top-0 left-8 right-8 flex justify-center z-0 h-48 overflow-visible">
<img id="he-image" src="" class="h-48 w-64 md:w-80 object-cover rounded-t-2xl shadow-2xl opacity-0 translate-y-full" style="will-change: transform, opacity;" />
</div>
<div class="bg-surface-container-lowest rounded-xl p-10 editorial-shadow flex flex-col justify-between relative overflow-hidden group h-full z-10">
<div class="relative z-10">
2026-04-11 21:48:34 +00:00
<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>
2026-05-12 00:17:31 +00:00
<span id="he-titel" class="font-headline font-extrabold text-2xl uppercase italic">{{ $e.meilenstein.event }}</span>
2026-04-11 21:48:34 +00:00
</div>
2026-05-12 00:17:31 +00:00
<h3 id="he-platz" class="text-4xl font-headline font-bold text-on-surface mb-4">{{ $e.meilenstein.platz }}</h3>
<p id="he-desc" class="text-on-surface-variant max-w-md text-lg">{{ $e.meilenstein.beschreibung }}</p>
2026-04-11 21:48:34 +00:00
</div>
<div class="mt-12 flex items-center gap-6 relative z-10">
<div>
2026-05-12 00:17:31 +00:00
<div id="he-jahr" class="text-3xl font-black text-on-surface">{{ $e.meilenstein.jahr }}</div>
<div id="he-ort" class="text-xs uppercase tracking-widest font-bold text-primary">{{ $e.meilenstein.ort }}</div>
2026-04-11 21:48:34 +00:00
</div>
<div class="h-10 w-[1px] bg-outline-variant/30"></div>
<div>
2026-05-12 00:17:31 +00:00
<div id="he-kat" class="text-3xl font-black text-on-surface">{{ $e.meilenstein.kategorie }}</div>
2026-04-11 21:48:34 +00:00
<div class="text-xs uppercase tracking-widest font-bold text-primary">Kategorie</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>
2026-05-12 00:17:31 +00:00
</div>
2026-04-11 21:48:34 +00:00
</div>
2026-05-21 09:51:56 +00:00
{{ end }}
2026-04-11 21:48:34 +00:00
<!-- Weitere Auszeichnungen -->
<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 Auszeichnungen</h4>
2026-04-22 21:50:21 +00:00
{{ $icons := slice "star" "emoji_events" "rewarded_ads" "workspace_premium" "military_tech" "sports_martial_arts" }}
{{ range $i, $a := $e.weitere_auszeichnungen }}
2026-05-12 00:17:31 +00:00
<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="{{ $a.titel }}"
data-detail="{{ $a.detail }}"
data-beschreibung="{{ $a.beschreibung }}"
data-jahr=""
data-ort=""
data-kategorie="">
2026-04-11 21:48:34 +00:00
<div class="w-10 h-10 rounded-full bg-white/20 flex items-center justify-center shrink-0">
2026-04-22 21:50:21 +00:00
<span class="material-symbols-outlined text-xl">{{ index $icons (mod $i (len $icons)) }}</span>
2026-04-11 21:48:34 +00:00
</div>
<div>
2026-04-22 21:50:21 +00:00
<p class="font-bold">{{ $a.titel }}</p>
<p class="text-sm opacity-80">{{ $a.detail }}</p>
2026-05-01 19:00:04 +00:00
{{ if $a.beschreibung }}
<p class="text-xs opacity-70 mt-1 leading-relaxed">{{ $a.beschreibung }}</p>
{{ end }}
2026-04-11 21:48:34 +00:00
</div>
</div>
2026-04-22 21:50:21 +00:00
{{ end }}
2026-05-12 00:17:31 +00:00
{{ $weitereMarkdown := where (where .Site.RegularPages "Section" "erfolge") "Params.is_weitere_auszeichnung" "true" }}
{{ range $i, $page := $weitereMarkdown }}
<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="{{ .Title }}"
data-detail="{{ .Params.rang }}"
data-beschreibung="{{ .Summary }}"
data-jahr="{{ .Params.datum }}"
data-ort="{{ .Params.ort }}"
data-kategorie="{{ .Params.kategorie }}"
data-image="{{ if .Params.image }}{{ printf "/erfolge-img/%s" .Params.image | relURL }}{{ end }}">
<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">{{ index $icons (mod $i (len $icons)) }}</span>
</div>
<div>
<p class="font-bold">{{ .Title }}</p>
<p class="text-sm opacity-80">{{ .Params.rang }}</p>
{{ if .Summary }}
<p class="text-xs opacity-70 mt-1 leading-relaxed">{{ .Summary }}</p>
{{ end }}
</div>
</div>
{{ end }}
2026-04-11 21:48:34 +00:00
</div>
<!-- Stats -->
2026-04-22 21:50:21 +00:00
{{ $stats := $e.stats }}
{{ with index $stats 0 }}
2026-04-11 21:48:34 +00:00
<div class="bg-secondary-container rounded-xl p-8 flex flex-col justify-center gap-2">
2026-04-22 21:50:21 +00:00
<span class="text-on-secondary-container font-headline font-black text-6xl italic">{{ .wert }}</span>
<span class="text-secondary font-bold uppercase tracking-[0.2em] text-sm">{{ .label }}</span>
2026-04-11 21:48:34 +00:00
</div>
2026-04-22 21:50:21 +00:00
{{ end }}
{{ with index $stats 1 }}
2026-04-11 21:48:34 +00:00
<div class="bg-surface-container-highest rounded-xl p-8 flex flex-col justify-center gap-2">
2026-04-22 21:50:21 +00:00
<span class="text-on-surface font-headline font-black text-6xl italic">{{ .wert }}</span>
<span class="text-on-surface-variant font-bold uppercase tracking-[0.2em] text-sm">{{ .label }}</span>
2026-04-11 21:48:34 +00:00
</div>
2026-04-22 21:50:21 +00:00
{{ end }}
{{ with index $stats 2 }}
2026-04-11 21:48:34 +00:00
<div class="bg-white rounded-xl p-8 editorial-shadow flex flex-col justify-center gap-2 border-t-4 border-pink-500">
2026-04-22 21:50:21 +00:00
<span class="text-pink-600 font-headline font-black text-6xl italic">{{ .wert }}</span>
<span class="text-zinc-500 font-bold uppercase tracking-[0.2em] text-sm">{{ .label }}</span>
2026-04-11 21:48:34 +00:00
</div>
2026-04-22 21:50:21 +00:00
{{ end }}
2026-04-11 21:48:34 +00:00
</div>
</section>
<!-- Zitat -->
<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>
<blockquote class="text-3xl md:text-5xl font-headline font-bold text-on-surface leading-tight tracking-tight italic">
2026-04-22 21:50:21 +00:00
"{{ $e.zitat.text }}"
2026-04-11 21:48:34 +00:00
</blockquote>
2026-04-22 21:50:21 +00:00
<p class="mt-8 font-bold uppercase tracking-widest text-on-surface-variant">— {{ $e.zitat.autor }}</p>
2026-04-11 21:48:34 +00:00
</section>
</main>
<!-- Footer -->
<footer class="bg-zinc-50 dark:bg-zinc-950 w-full rounded-t-[3rem] mt-20">
<div class="flex flex-col md:flex-row justify-between items-center py-12 px-8 max-w-7xl mx-auto gap-6 text-sm tracking-wide">
2026-04-22 21:50:21 +00:00
<div class="text-lg font-bold text-zinc-900 dark:text-zinc-100 font-headline uppercase italic">{{ .Site.Data.homepage.siteTitle | default .Site.Title }}</div>
2026-04-11 21:48:34 +00:00
<div class="flex gap-8 text-zinc-500">
<a class="hover:text-pink-500 hover:underline decoration-pink-500 decoration-2 underline-offset-4 transition-opacity" href="#">Instagram</a>
<a class="hover:text-pink-500 hover:underline decoration-pink-500 decoration-2 underline-offset-4 transition-opacity" href="#">YouTube</a>
<a class="hover:text-pink-500 hover:underline decoration-pink-500 decoration-2 underline-offset-4 transition-opacity" href="#">Email</a>
</div>
2026-04-22 21:50:21 +00:00
<div class="text-zinc-500 opacity-80">© 2024 {{ .Site.Data.homepage.siteTitle | default .Site.Title }}. Alle Rechte vorbehalten.</div>
2026-04-11 21:48:34 +00:00
</div>
</footer>
2026-05-12 00:17:31 +00:00
<!-- Lightbox Modal -->
<div id="imageLightbox" class="hidden fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/90 backdrop-blur-sm transition-opacity" onclick="closeLightbox(event)">
<img id="lightboxImage" src="" class="hidden max-w-[90vw] max-h-[90vh] object-contain rounded-xl shadow-2xl" />
<video id="lightboxVideo" src="" class="hidden max-w-[90vw] max-h-[90vh] object-contain rounded-xl shadow-2xl" controls autoplay></video>
<button class="absolute top-8 right-8 text-white bg-white/10 hover:bg-white/20 rounded-full p-2" onclick="closeLightbox(event, true)">
<span class="material-symbols-outlined text-3xl">close</span>
</button>
</div>
<script>
function openLightbox(src, isVideo) {
const img = document.getElementById('lightboxImage');
const vid = document.getElementById('lightboxVideo');
if (isVideo) {
img.classList.add('hidden');
vid.classList.remove('hidden');
vid.src = src;
} else {
vid.classList.add('hidden');
vid.pause();
img.classList.remove('hidden');
img.src = src;
}
document.getElementById('imageLightbox').classList.remove('hidden');
}
function closeLightbox(e, force) {
if (force || e.target.id === 'imageLightbox') {
document.getElementById('imageLightbox').classList.add('hidden');
document.getElementById('lightboxVideo').pause();
}
}
let animTimeout;
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 || '';
const imageUrl = this.dataset.image || '';
// Bild zurücksetzen
const imgEl = document.getElementById('he-image');
if (imgEl) {
imgEl.style.transition = 'none';
imgEl.style.transform = 'translateY(100%)';
imgEl.style.opacity = '0';
clearTimeout(animTimeout);
}
// 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');
// Bild animieren
if (imgEl && imageUrl) {
imgEl.src = imageUrl;
animTimeout = setTimeout(() => {
imgEl.style.transition = 'all 2000ms cubic-bezier(0.2, 0.8, 0.2, 1)';
imgEl.style.transform = 'translateY(-98%)';
imgEl.style.opacity = '1';
}, 2000); // nach 2 Sekunden
}
});
});
</script>
2026-05-21 09:51:56 +00:00
<script>
// Intersection Observer for scroll animations
document.addEventListener("DOMContentLoaded", function() {
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.15
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-reveal-up');
entry.target.classList.remove('opacity-0', 'translate-y-12');
observer.unobserve(entry.target);
}
});
}, observerOptions);
document.querySelectorAll('.scroll-reveal-item').forEach(item => {
observer.observe(item);
});
});
</script>
<script>
// Erfolge Likes & Kommentare System
(function() {
const isLocal = window.location.hostname === 'localhost' || window.location.hostname === 'karate' || window.location.hostname.startsWith('192.168.');
const apiBase = isLocal ? 'http://' + window.location.hostname + ':3001' : '';
let erfolgInteractions = {};
async function loadInteractions() {
try {
const r = await fetch(apiBase + '/api/erfolge/interactions');
if (r.ok) {
erfolgInteractions = await r.json();
renderAllInteractions();
}
} catch (e) {
console.error('Fehler beim Laden der Interaktionen:', e);
}
}
function renderAllInteractions() {
document.querySelectorAll('.erfolg-interactions').forEach(container => {
const id = container.dataset.erfolgId;
const data = erfolgInteractions[id] || { likes: 0, comments: [] };
// Update counters
container.querySelector('.like-count').textContent = data.likes || 0;
container.querySelector('.comment-count').textContent = data.comments ? data.comments.length : 0;
// Highlight liked status if saved in localStorage
const likedKeys = JSON.parse(localStorage.getItem('emy_liked_erfolge') || '[]');
const heartIcon = container.querySelector('.heart-icon');
if (likedKeys.includes(id)) {
heartIcon.style.fontVariationSettings = "'FILL' 1";
heartIcon.classList.add('text-primary');
heartIcon.classList.remove('group-hover/like:scale-120'); // static filled look
} else {
heartIcon.style.fontVariationSettings = "'FILL' 0";
heartIcon.classList.remove('text-primary');
}
// Render comment list
const list = container.querySelector('.comment-list');
if (data.comments && data.comments.length > 0) {
list.classList.remove('hidden');
list.innerHTML = data.comments.map(c => {
const letter = c.name ? c.name.charAt(0).toUpperCase() : '?';
const dateObj = new Date(c.date);
const dateStr = dateObj.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' });
return `
<div class="bg-surface-container-lowest p-4 rounded-xl shadow-sm border border-outline-variant/10">
<div class="flex items-center justify-between mb-2">
<div class="flex items-center gap-2.5">
<div class="w-8 h-8 rounded-full bg-secondary-container text-on-secondary-container flex items-center justify-center font-bold text-sm uppercase">${letter}</div>
<span class="font-bold text-sm text-on-surface">${escapeHtml(c.name)}</span>
</div>
<span class="text-xs text-outline font-medium">${dateStr}</span>
</div>
<p class="text-sm text-on-surface-variant leading-relaxed pl-10.5">${escapeHtml(c.text)}</p>
</div>
`;
}).join('');
} else {
list.classList.add('hidden');
list.innerHTML = '';
}
});
}
function escapeHtml(str) {
return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
}
window.likeErfolg = async function(id, btn) {
const likedKeys = JSON.parse(localStorage.getItem('emy_liked_erfolge') || '[]');
if (likedKeys.includes(id)) {
return;
}
try {
const r = await fetch(apiBase + '/api/erfolge/interactions/like', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id })
});
if (r.ok) {
const res = await r.json();
erfolgInteractions[id] = res.data;
likedKeys.push(id);
localStorage.setItem('emy_liked_erfolge', JSON.stringify(likedKeys));
renderAllInteractions();
// Heart trigger animation
const heart = btn.querySelector('.heart-icon');
heart.classList.add('scale-150');
setTimeout(() => heart.classList.remove('scale-150'), 300);
}
} catch (e) {
console.error('Fehler beim Liken:', e);
}
};
window.submitComment = async function(id, form, event) {
event.preventDefault();
const btn = form.querySelector('button[type="submit"]');
const nameInput = form.querySelector('input[name="name"]');
const textInput = form.querySelector('textarea[name="text"]');
const name = nameInput.value;
const text = textInput.value;
if (!name || !text) return;
btn.disabled = true;
try {
const r = await fetch(apiBase + '/api/erfolge/interactions/comment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, name, text })
});
if (r.ok) {
const res = await r.json();
erfolgInteractions[id] = res.data;
textInput.value = '';
renderAllInteractions();
const card = form.closest('.erfolg-card');
const body = card.querySelector('.erfolg-body');
if (body.style.maxHeight !== 'none') {
body.style.maxHeight = body.scrollHeight + 'px';
}
}
} catch (e) {
console.error('Fehler beim Kommentieren:', e);
} finally {
btn.disabled = false;
}
};
document.addEventListener('DOMContentLoaded', loadInteractions);
})();
</script>
2026-04-11 21:48:34 +00:00
</body>
</html>