Nutzer-Wunsch 20.08.2026: "eine richtig geile kachel ... wo die leute mit namen und tiktok namen mir eine nachricht schreiben können die ich in die verwaltung kriege, und dann kann ich die ausgewählten über die verwaltungsseite auf die website hinzufügen ... das wird mega persoenlich zu den fans, bitte wirklich krass geil speziell." - Neue, augenschonend gestaltete Einreich-Kachel auf stimmen.html: Name, TikTok-Name (optional), Nachricht -- landet NIE automatisch oeffentlich, sondern immer erst als Entwurf in der Verwaltung. Warmer Babyblau/Rosé-Farbverlauf, wandernder Lichtschein, pulsierendes Herz -- ersetzt die 3 ewigen "Hier steht bald..."-Platzhalterkarten. - Neue Verwaltungs-Sektion "💬 Stimmen verwalten": Warteschlange (offene zuerst), Freigeben/Ablehnen/Löschen pro Eintrag. - Freigegebene Stimmen erscheinen automatisch in einer neuen, spezielleren Zitat-Kartenoptik (großes Anführungszeichen, Name + TikTok-Chip) -- Abschnitt bleibt komplett unsichtbar, solange keine einzige freigegeben wurde. - Backend: neue Tabelle `testimonials` (Migration 0006), routes/ testimonials.js (oeffentliches Einreichen + Lesen freigegebener, admin-Warteschlange + Status/Loeschen mit neuer TESTIMONIALS_MANAGE- Berechtigung). 18 automatisierte Tests gegen eine Fake-DB bestanden. - Alles per Playwright visuell durchgespielt: leerer Zustand, Einreichen -> Erfolgsmeldung, freigegebene Stimmen-Anzeige, Verwaltungs-Warteschlange mit allen Aktionen. Backend-Teil (server-internal/, cloudflare-worker/migrations/) noch ohne Deploy-Zugriff -- Dogi muss ihn manuell auf dogiintern ausrollen. Co-Authored-By: Claude Opus 5 <[email protected]>
136 lines
6.2 KiB
HTML
136 lines
6.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de" data-theme="spicymedia">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Creator im Team — DOGFATHER UNIVERSE</title>
|
|
<meta name="description" content="Content Creator, die Teil von DogFather / Spicy Media sind." />
|
|
<link rel="icon" type="image/png" href="assets/img/favicon.png" />
|
|
<link rel="manifest" href="/manifest.json" />
|
|
<meta name="theme-color" content="#0b0d10" />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:site_name" content="DOGFATHER UNIVERSE" />
|
|
<meta property="og:title" content="Creator im Team — DOGFATHER UNIVERSE" />
|
|
<meta property="og:description" content="Content Creator, die Teil von DogFather / Spicy Media sind." />
|
|
<meta property="og:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
|
<meta property="og:url" content="https://dogfather-universe.com/creator.html" />
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
<meta name="twitter:title" content="Creator im Team — DOGFATHER UNIVERSE" />
|
|
<meta name="twitter:description" content="Content Creator, die Teil von DogFather / Spicy Media sind." />
|
|
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
|
|
|
<link rel="stylesheet" href="assets/css/main.css?v=20260820k" />
|
|
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820k" />
|
|
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820k" />
|
|
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820k" />
|
|
</head>
|
|
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-creator.jpg');--page-bg-mobile:url('/assets/img/bg-creator-mobile.jpg');">
|
|
<div id="site-header"></div>
|
|
|
|
<main>
|
|
<section class="hero page-bg">
|
|
<div class="hero-banner"><img src="/assets/img/bg-creator.jpg" alt="" loading="eager" /></div>
|
|
<div class="container">
|
|
<span class="eyebrow" data-i18n="crt_eyebrow">Manager DogFather — Team</span>
|
|
<h1 data-i18n="crt_h1">Creator im Team</h1>
|
|
<p class="lead worlds" data-i18n="crt_lead">Content Creator, die bei DogFather / Spicy Media mitmachen.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="section-tight">
|
|
<div class="container">
|
|
<div class="filter-bar" id="creator-filters"></div>
|
|
<div id="creator-grid" class="grid grid-4"></div>
|
|
<!-- Versteckte Textquelle für die JS-generierten Grid-/Filter-Texte:
|
|
main.js übersetzt data-i18n-Elemente automatisch (auch bei
|
|
Sprachwechsel), das Inline-Skript unten liest die fertigen Texte
|
|
von hier aus, statt sie selbst per JS zu übersetzen. -->
|
|
<div id="creator-i18n-strings" style="display:none;" aria-hidden="true">
|
|
<span data-i18n="crt_empty">Noch keine Creator-Profile veröffentlicht — bald verfügbar. 🩵</span>
|
|
<span data-i18n="crt_filter_alle">alle</span>
|
|
<span data-i18n="crt_profil_btn">Profil ansehen</span>
|
|
</div>
|
|
<!-- TODO: Noch keine Creator-Profile final geklärt. Sobald Namen/Infos feststehen, in assets/js/data-creator.js ergänzen — diese Seite rendert automatisch. -->
|
|
<div class="btn-row" style="justify-content:center;">
|
|
<a class="btn btn-primary" href="bewerben-creator.html" data-i18n="crt_bewerben_btn">Als Creator bewerben</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<div id="site-footer"></div>
|
|
<script src="assets/js/data-creator.js?v=20260820k"></script>
|
|
<script src="assets/js/i18n-creator.js?v=20260820k"></script>
|
|
<script src="assets/js/main.js?v=20260820k"></script>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const grid = document.getElementById("creator-grid");
|
|
const filterBar = document.getElementById("creator-filters");
|
|
const list = window.CREATORS || [];
|
|
|
|
// Texte fürs JS-generierte Grid/Filter kommen aus den versteckten
|
|
// data-i18n-Elementen oben — main.js übersetzt sie ganz normal (auch bei
|
|
// Sprachwechsel per "dogi-sprache-geaendert"), wir lesen hier nur den
|
|
// fertig übersetzten Text aus.
|
|
const uebersetzen = (schluessel) => {
|
|
const quelle = [...document.querySelectorAll("#creator-i18n-strings [data-i18n]")]
|
|
.find((el) => el.getAttribute("data-i18n") === schluessel);
|
|
return quelle ? quelle.textContent : schluessel;
|
|
};
|
|
|
|
if (!list.length) {
|
|
const texteNeuSetzen = () => {
|
|
grid.innerHTML = `<p class="muted text-center" style="grid-column:1/-1;">${uebersetzen("crt_empty")}</p>`;
|
|
};
|
|
texteNeuSetzen();
|
|
document.addEventListener("dogi-sprache-geaendert", texteNeuSetzen);
|
|
filterBar.style.display = "none";
|
|
return;
|
|
}
|
|
|
|
const categories = ["alle", ...new Set(list.map((c) => c.category))];
|
|
let aktiverFilter = "alle";
|
|
|
|
function zeichneFilterbar() {
|
|
filterBar.innerHTML = categories.map((c) =>
|
|
`<button class="filter-btn${c === aktiverFilter ? " active" : ""}" data-filter="${c}">${c === "alle" ? uebersetzen("crt_filter_alle") : c}</button>`).join("");
|
|
}
|
|
|
|
const feld = (x) => (window.dogiFeld ? window.dogiFeld(x) : x || "");
|
|
|
|
function draw(filter) {
|
|
const items = filter === "alle" ? list : list.filter((c) => c.category === filter);
|
|
grid.innerHTML = items.map((c) => {
|
|
const quoteText = feld(c.quote);
|
|
return `
|
|
<a class="profile-card" href="profil.html?p=${c.slug}">
|
|
<div class="avatar">${(c.avatar || c.photo) ? `<img src="${c.avatar || c.photo}" alt="${c.name}" loading="lazy">` : `<span class="avatar-initial">${c.name.charAt(0).toUpperCase()}</span>`}</div>
|
|
<h3>${c.name}</h3>
|
|
<div class="role">${feld(c.role)}</div>
|
|
${quoteText ? `<p class="quote">„${quoteText}"</p>` : ""}
|
|
<span class="btn btn-outline" style="margin-top:.7rem;pointer-events:none;">${uebersetzen("crt_profil_btn")}</span>
|
|
</a>`;
|
|
}).join("");
|
|
}
|
|
|
|
filterBar.addEventListener("click", (e) => {
|
|
const btn = e.target.closest(".filter-btn");
|
|
if (!btn) return;
|
|
aktiverFilter = btn.dataset.filter;
|
|
filterBar.querySelectorAll(".filter-btn").forEach((b) => b.classList.remove("active"));
|
|
btn.classList.add("active");
|
|
draw(aktiverFilter);
|
|
});
|
|
|
|
document.addEventListener("dogi-sprache-geaendert", () => {
|
|
zeichneFilterbar();
|
|
draw(aktiverFilter);
|
|
});
|
|
|
|
zeichneFilterbar();
|
|
draw("alle");
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|