Der Tastatur-Test (pruef-tastatur.mjs, neu) zeigte auf allen fünf geprüften Seiten dasselbe Bild: jedes Bedienelement erreichbar, Fokus durchgehend sichtbar, keine Tastaturfalle -- aber kein Sprunglink. Ohne ihn muss sich jemand, der die Tastatur benutzt, auf JEDER Seite erneut durch das komplette Menü tabben (31 bis 52 Punkte), bevor der eigentliche Inhalt beginnt. WCAG 2.4.1 verlangt genau diesen Ausweg. An einer Stelle gelöst statt in 35 Dateien: renderHeader() in main.js setzt das Sprungziel und stellt den Link davor. Das tabindex="-1" am <main> ist der Teil, der meistens fehlt: ohne ihn verschiebt der Sprung in Chrome und Safari nur die Bildlaufleiste, der Tastaturfokus bleibt in der Navigation -- der nächste Tab landet wieder im Menü und der Sprung war wirkungslos. Cache-Buster auf 20260827a (244 Stellen), sonst bekäme niemand die geänderte main.js und main.css ausgeliefert. Co-Authored-By: Claude Opus 5 <[email protected]>
157 lines
7.4 KiB
HTML
157 lines
7.4 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=20260827a" />
|
|
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260827a" />
|
|
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260827a" />
|
|
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260827a" />
|
|
</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" data-site-text-key="seitentitel_creator">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>
|
|
<span data-i18n="crt_kategorie_sonstige">Sonstige</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=20260827a"></script>
|
|
<script src="assets/js/i18n-creator.js?v=20260827a"></script>
|
|
<script src="assets/js/main.js?v=20260827a"></script>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
const grid = document.getElementById("creator-grid");
|
|
const filterBar = document.getElementById("creator-filters");
|
|
let list = window.CREATORS || [];
|
|
|
|
// 21.08.2026: über die Verwaltung angelegte Creator ergänzen, BEVOR
|
|
// entschieden wird, ob die Seite "leer" ist (Nutzer-Wunsch "überall wo
|
|
// ... Creator ... sind, will ich dass ich die easy über meine
|
|
// Verwaltungsseite hinzufüge"). Vorher gab es direkt darunter ein
|
|
// "return", sobald window.CREATORS leer war (bisher der Normalfall, da
|
|
// noch keine echten Creator-Profile feststehen) -- dadurch wären
|
|
// admin-gepflegte Creator NIE geladen worden.
|
|
if (window.dogiTeamLaden) {
|
|
const neue = await window.dogiTeamLaden("creator");
|
|
// Runde 2 (21.08.2026, "wenn ich eine änderung mache ist es auch für
|
|
// jeden"): überschreibt bereits importierte Creator (gleicher slug)
|
|
// statt sie zu duplizieren.
|
|
list = window.dogiTeamZusammenfuehren(list, neue);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 21.08.2026: über die Verwaltung angelegte Creator haben (noch) kein
|
|
// eigenes Genre-Feld (category) -- ohne diesen Fallback würde die
|
|
// Filterleiste einen kaputten "undefined"-Knopf zeigen.
|
|
list = list.map((c) => (c.category ? c : { ...c, category: uebersetzen("crt_kategorie_sonstige") }));
|
|
|
|
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>
|