oh gott was mach ich nur

This commit is contained in:
2025-11-25 03:21:52 +01:00
parent b8471bff3e
commit 888ab3dfa7
21 changed files with 2664 additions and 794 deletions

View File

@@ -1,31 +1,63 @@
<?php
// partials/structure/app_config.php
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? app_primary_domain();
// Host-Infos ermitteln (für URLs / Redirects etc.)
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? app_primary_domain();
$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
// -----------------------------------------------
// USBCheck JavaScript-Konfiguration
// (für fakecheck.*, header.js, i18n, usw.)
// -----------------------------------------------
$usbConfig = [
'lang' => $lang ?? 'en',
// Basis-Pfade
'assetsBase' => '/assets',
// NEU: Versionierung für JS/CSS aus PHP-Config
// Versionierung für JS/CSS
// → wenn ASSET_VERSION definiert ist, wird sie genutzt
// → sonst null (JS-Loader sorgt für ?v= fallback)
'assetVersion'=> defined('ASSET_VERSION') ? ASSET_VERSION : null,
// Environment (prod, staging, dev)
'env' => $GLOBALS['ENV'] ?? 'prod',
'domains' => [
// Domains
'domains' => [
'primaryDomain' => app_primary_domain(),
'primaryUrl' => app_primary_url(),
'fakecheckDomain' => app_fakecheck_domain(),
'fakecheckUrl' => app_fakecheck_url(),
],
// Fakecheck-Tool-Config
'fakecheck' => [
'baseUrl' => $GLOBALS['usb_base_url'] ?? '',
'apiBaseUrl' => $GLOBALS['usb_api_base'] ?? 'https://api.usbcheck.it',
'locale' => $lang ?? 'en',
],
// -----------------------------------------------
// i18n: aus fileload.php gefüllt
// -----------------------------------------------
'i18n' => [
// Alle verfügbaren Sprachen (code, label, flag)
'available' => $availableLangs ?? [],
// Aktuelle Sprache als Code (de/en/fr/it …)
'current' => $lang ?? 'en',
],
];
// -----------------------------------------------
// Javascript-Konfiguration in die Seite schreiben
// -----------------------------------------------
?>
<script>
window.usbConfig = <?= json_encode($usbConfig, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
window.usbConfig = <?= json_encode(
$usbConfig,
JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE
) ?>;
</script>

View File

@@ -44,13 +44,52 @@ if ($isLoggedIn) {
$userInitials = mb_strtoupper($initials);
}
}
// -----------------------------------------
// Dynamische Sprachliste
// kommt aus app_config.php:
//
// $usbConfig['i18n']['available'] = [
// 'de' => ['code'=>'de','label'=>'Deutsch','flag'=>'🇩🇪'],
// ...
// ];
// $usbConfig['i18n']['current'] = 'de';
// -----------------------------------------
// aktuelle Sprache aus globalem Kontext
$currentLang = $usbConfig['i18n']['current'] ?? ($lang ?? 'en');
// verfügbare Sprachen aus Config
$availableLangs = $usbConfig['i18n']['available'] ?? [];
// Fallback: Wenn Config noch nichts liefert, nimm nur die aktuelle Sprache
if (!$availableLangs || !is_array($availableLangs)) {
$availableLangs = [
$currentLang => [
'code' => $currentLang,
'label' => strtoupper($currentLang),
'flag' => '🏳️'
]
];
}
// Sicherstellen, dass currentLang in der Liste ist
if (!isset($availableLangs[$currentLang])) {
$currentLang = array_key_first($availableLangs);
}
// aktuelle Sprache-Info
$currentLangInfo = $availableLangs[$currentLang] ?? ['code' => $currentLang];
$currentLangFlag = $currentLangInfo['flag'] ?? '🏳️';
$currentLangCode = strtoupper($currentLangInfo['code'] ?? $currentLang);
$currentLangLabel = $currentLangInfo['label'] ?? $currentLangCode;
?>
<header class="sticky top-0 z-40 border-b border-brand-border/70 backdrop-blur bg-brand-bg/85">
<div class="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8 flex items-center justify-between h-16">
<!-- Logo -->
<div class="flex items-center gap-3">
<a href="/?lang=<?= htmlspecialchars($lang ?? 'de') ?>" class="flex items-center gap-3">
<a href="/?lang=<?= htmlspecialchars($currentLang) ?>" class="flex items-center gap-3">
<img src="<?= $baseUrl ?>/assets/img/logo_slogan.png"
alt="<?= htmlspecialchars(app_primary_domain()) ?> Logo"
class="h-9 w-auto">
@@ -84,38 +123,28 @@ if ($isLoggedIn) {
<button id="langCurrent"
type="button"
class="flex items-center gap-1 text-xs uppercase tracking-[0.18em] text-brand-muted hover:text-brand-primary transition">
<span id="langCurrentLabel"><?= strtoupper($lang ?? 'de') ?></span>
<span class="text-base mr-1" id="langCurrentFlag"><?= htmlspecialchars($currentLangFlag) ?></span>
<span id="langCurrentLabel"><?= htmlspecialchars($currentLangCode) ?></span>
<svg class="w-3 h-3 opacity-70" viewBox="0 0 20 20" aria-hidden="true">
<path d="M5 7l5 6 5-6" fill="currentColor" />
</svg>
</button>
<div id="langMenu"
class="hidden absolute right-0 mt-2 w-24 rounded-xl bg-brand-surface border border-brand-border shadow-lg py-1 text-xs z-40">
<button type="button"
class="lang-pill flex items-center gap-2 w-full text-left px-3 py-1.5 uppercase tracking-[0.18em] text-brand-muted hover:text-brand-primary hover:bg-brand-bg/60"
data-lang="de">
<span class="text-base">🇩🇪</span>
<span>DE</span>
</button>
<button type="button"
class="lang-pill flex items-center gap-2 w-full text-left px-3 py-1.5 uppercase tracking-[0.18em] text-brand-muted hover:text-brand-primary hover:bg-brand-bg/60"
data-lang="en">
<span class="text-base">🇬🇧</span>
<span>EN</span>
</button>
<button type="button"
class="lang-pill flex items-center gap-2 w-full text-left px-3 py-1.5 uppercase tracking-[0.18em] text-brand-muted hover:text-brand-primary hover:bg-brand-bg/60"
data-lang="it">
<span class="text-base">🇮🇹</span>
<span>IT</span>
</button>
<button type="button"
class="lang-pill flex items-center gap-2 w-full text-left px-3 py-1.5 uppercase tracking-[0.18em] text-brand-muted hover:text-brand-primary hover:bg-brand-bg/60"
data-lang="fr">
<span class="text-base">🇫🇷</span>
<span>FR</span>
</button>
class="hidden absolute right-0 mt-2 w-32 rounded-xl bg-brand-surface border border-brand-border shadow-lg py-1 text-xs z-40">
<?php foreach ($availableLangs as $code => $info): ?>
<?php
$isActive = ($code === $currentLang);
$flag = $info['flag'] ?? '🏳️';
$label = strtoupper($info['code'] ?? $code);
?>
<button type="button"
class="lang-pill flex items-center gap-2 w-full text-left px-3 py-1.5 uppercase tracking-[0.18em] text-brand-muted hover:text-brand-primary hover:bg-brand-bg/60 <?= $isActive ? 'bg-brand-bg/60' : '' ?>"
data-lang="<?= htmlspecialchars($code) ?>">
<span class="text-base"><?= htmlspecialchars($flag) ?></span>
<span><?= htmlspecialchars($label) ?></span>
</button>
<?php endforeach; ?>
</div>
</div>
@@ -127,7 +156,7 @@ if ($isLoggedIn) {
type="button"
class="relative inline-flex items-center justify-center rounded-full bg-brand-primary px-4 py-1.5 text-xs font-semibold uppercase tracking-[0.18em] text-brand-bg shadow-soft hover:bg-cyan-400 transition-colors"
data-i18n="header_btn_login"
data-login-url="/login/?lang=<?= htmlspecialchars($lang ?? 'de') ?>">
data-login-url="/login/?lang=<?= htmlspecialchars($currentLang) ?>">
Login
</button>
<?php else: ?>
@@ -143,7 +172,7 @@ if ($isLoggedIn) {
<div id="userMenu"
class="hidden absolute right-0 mt-2 w-44 rounded-xl bg-brand-surface border border-brand-border shadow-lg py-1 text-xs z-40">
<a href="/dashboard/?lang=<?= htmlspecialchars($lang ?? 'de') ?>"
<a href="/dashboard/?lang=<?= htmlspecialchars($currentLang) ?>"
class="flex items-center gap-2 px-3 py-2 text-brand-muted hover:text-brand-primary hover:bg-brand-bg/60 transition-colors"
data-i18n="header_menu_dashboard">
Dashboard
@@ -151,7 +180,7 @@ if ($isLoggedIn) {
<button type="button"
class="flex items-center gap-2 w-full text-left px-3 py-2 text-brand-muted hover:text-red-400 hover:bg-red-500/10 transition-colors"
data-logout-link="true"
data-logout-href="/auth/logout?lang=<?= htmlspecialchars($lang ?? 'de') ?>"
data-logout-href="/auth/logout?lang=<?= htmlspecialchars($currentLang) ?>"
data-i18n="header_menu_logout">
Logout
</button>

View File

@@ -2,44 +2,62 @@
// public/partials/layout_start.php
// Erwartet (vor require):
// - $lang (de|en|it|fr) bereits validiert
// - $pageTitle (string)
// - $pageDescription (string, optional)
// - $userInitials (optional, kann null sein)
// - optional: $canonical (string) → überschreibt die automatisch berechnete Canonical-URL
// - $pageKey (string) Seiten-Key für i18n, z. B. 'landing', 'fakecheck', 'login', 'dashboard'
// - $lang (2-letter ISO, z. B. 'de', 'en', 'it', 'fr'), möglichst bereits aus fileload.php
// - optional: $pageTitle (string)
// - optional: $pageDescription (string)
// - optional: $canonical (string)
// - optional: $userInitials (string|null)
// Fallbacks:
if (!isset($lang) || !in_array($lang, ['de', 'en', 'it', 'fr'], true)) {
$lang = 'en';
// -----------------------------------------------------------
// Fallbacks & i18n Title/Description
// -----------------------------------------------------------
// Sicherstellen, dass availableLangs existiert (kommt aus fileload.php)
$availableLangs = $availableLangs ?? [];
// Page-Key Fallback
if (!isset($pageKey) || !is_string($pageKey) || $pageKey === '') {
$pageKey = 'landing';
}
// Fallback für Sprache: lieber auf $availableLangs statt feste Liste
if (!isset($lang) || !isset($availableLangs[$lang])) {
$lang = array_key_first($availableLangs) ?: 'en';
}
// Title aus i18n, falls nichts explizit gesetzt wurde
if (!isset($pageTitle) || !is_string($pageTitle) || $pageTitle === '') {
$pageTitle = app_primary_domain();
// pages.{pageKey}.meta.title
$pageTitle = i18n_get("pages.$pageKey.meta.title", app_primary_domain());
}
if (!isset($pageDescription) || !is_string($pageDescription)) {
$pageDescription = '';
// Description aus i18n, falls nichts explizit gesetzt wurde
if (!isset($pageDescription) || !is_string($pageDescription) || $pageDescription === '') {
// pages.{pageKey}.meta.description
$pageDescription = i18n_get("pages.$pageKey.meta.description", '');
}
// -----------------------------------------------------------
// Standard-Script für Header-Interaktionen
// -----------------------------------------------------------
if (function_exists('tpl_add_script')) {
// header.js kommt wie gehabt in den Footer
tpl_add_script('/assets/js/header.js', 'footer', true, false, '', null);
}
// Scheme + Host + Request-URI für Canonical & sonstige Host-bezogene Dinge
// -----------------------------------------------------------
// Canonical-URL bestimmen
// -----------------------------------------------------------
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? app_primary_domain();
$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
// Canonical bestimmen:
// - Wenn $canonical gesetzt ist (z. B. auf einer Landingpage explizit)
// → diese URL verwenden
// - Sonst: aktuelle URL ohne Query-Parameter (alles hinter '?')
// Wenn $canonical gesetzt → verwenden, sonst aktuelle URL ohne Query-String
$effectiveCanonical = isset($canonical) && is_string($canonical) && $canonical !== ''
? $canonical
: ($scheme . '://' . $host . strtok($requestUri, '?'));
// Kann später genutzt werden, falls du host-spezifische Sachen brauchst
?>
<!DOCTYPE html>
<html lang="<?= htmlspecialchars($lang) ?>">
@@ -59,44 +77,45 @@ $effectiveCanonical = isset($canonical) && is_string($canonical) && $canonical !
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Montserrat:wght@600;700;800&display=swap" rel="stylesheet">
<?php tpl('app_config', 'structure'); ?>
<?php
<?php
// App-Config (usbConfig + i18n.available/current) ins Fenster schreiben
tpl('app_config', 'structure');
// CSS im Header
foreach ($GLOBALS['page_styles'] as $style) {
if ($style['pos'] !== 'header') {
continue;
// CSS im Header aus der zentralen Registry
foreach ($GLOBALS['page_styles'] as $style) {
if (($style['pos'] ?? 'header') !== 'header') {
continue;
}
$href = $style['href'];
if (!empty($style['version'])) {
$href .= (str_contains($href, '?') ? '&' : '?') . 'v=' . urlencode($style['version']);
}
echo '<link rel="stylesheet" href="' . htmlspecialchars($href) . '">' . PHP_EOL;
}
$href = $style['href'];
if (!empty($style['version'])) {
$href .= (str_contains($href, '?') ? '&' : '?') . 'v=' . urlencode($style['version']);
}
// Scripts im Header aus der zentralen Registry
foreach ($GLOBALS['page_header_scripts'] as $script) {
$src = $script['src'];
if (!empty($script['version'])) {
$src .= (str_contains($src, '?') ? '&' : '?') . 'v=' . urlencode($script['version']);
}
echo '<link rel="stylesheet" href="' . htmlspecialchars($href) . '">' . PHP_EOL;
}
$attr = '';
if (!empty($script['async'])) {
$attr .= ' async';
} elseif (!empty($script['defer'])) {
$attr .= ' defer';
}
if (!empty($script['type'])) {
$attr .= ' type="' . htmlspecialchars($script['type']) . '"';
}
// Scripts im Header
foreach ($GLOBALS['page_header_scripts'] as $script) {
$src = $script['src'];
if (!empty($script['version'])) {
$src .= (str_contains($src, '?') ? '&' : '?') . 'v=' . urlencode($script['version']);
echo '<script src="' . htmlspecialchars($src) . '"' . $attr . '></script>' . PHP_EOL;
}
$attr = '';
if ($script['async']) {
$attr .= ' async';
} elseif ($script['defer']) {
$attr .= ' defer';
}
if ($script['type']) {
$attr .= ' type="' . htmlspecialchars($script['type']) . '"';
}
echo '<script src="' . htmlspecialchars($src) . '"' . $attr . '></script>' . PHP_EOL;
}
?>
?>
<script>
window.tailwind = window.tailwind || {};
@@ -129,8 +148,7 @@ foreach ($GLOBALS['page_header_scripts'] as $script) {
<!-- Tailwind (Dev) -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Eigenes CSS -->
<!-- Eigenes CSS (falls du das irgendwann auch versionieren willst, gerne über tpl_add_style) -->
<link rel="stylesheet" href="/assets/css/main.css">
</head>