285 lines
12 KiB
PHP
285 lines
12 KiB
PHP
<?php
|
||
$title = isset($pageTitle) && is_string($pageTitle) && $pageTitle !== ''
|
||
? $pageTitle
|
||
: 'Skyview & AstroTools — Astronomiemuseum der Sternwarte Sonneberg';
|
||
|
||
$bodyClassAttr = '';
|
||
if (isset($bodyClass) && is_string($bodyClass) && trim($bodyClass) !== '') {
|
||
$bodyClassAttr = ' class="' . htmlspecialchars(trim($bodyClass), ENT_QUOTES, 'UTF-8') . '"';
|
||
}
|
||
|
||
$headerIntroPre = isset($headerIntroPre) && is_string($headerIntroPre) ? trim($headerIntroPre) : '';
|
||
$headerIntroTitle = isset($headerIntroTitle) && is_string($headerIntroTitle) ? trim($headerIntroTitle) : '';
|
||
$headerIntroSub = isset($headerIntroSub) && is_string($headerIntroSub) ? trim($headerIntroSub) : '';
|
||
$showHeaderIntro = $headerIntroPre !== '' || $headerIntroTitle !== '' || $headerIntroSub !== '';
|
||
$publicBasePath = isset($publicBasePath) && is_string($publicBasePath) ? rtrim($publicBasePath, '/') . '/' : '';
|
||
$pdoHeader = isset($pdo) ? $pdo : null;
|
||
$isAdmin = $loggedIn && (($_SESSION['role'] ?? '') === 'admin');
|
||
$pendingApprovals = 0;
|
||
|
||
if (($loggedIn || $isAdmin) && $pdoHeader === null) {
|
||
$cfgHeader = require __DIR__ . '/../config/database.php';
|
||
$pdoHeader = new PDO(
|
||
sprintf('mysql:host=%s;dbname=%s;charset=%s', $cfgHeader['host'], $cfgHeader['dbname'], $cfgHeader['charset'] ?? 'utf8mb4'),
|
||
$cfgHeader['user'],
|
||
$cfgHeader['pass'],
|
||
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
|
||
);
|
||
}
|
||
// Standard-Standort des eingeloggten Benutzers laden
|
||
$currentLocation = null;
|
||
if (!empty($defaultLocation)) {
|
||
// Seite hat den Standort bereits geladen – direkt übernehmen
|
||
$currentLocation = $defaultLocation;
|
||
} elseif ($loggedIn && isset($_SESSION['user_id'])) {
|
||
// Eigene DB-Verbindung aufbauen falls die Seite keine bereitstellt
|
||
$stmtLoc = $pdoHeader->prepare(
|
||
'SELECT id, name, latitude, longitude, elevation, timezone
|
||
FROM app_user_locations
|
||
WHERE user_id = ? AND is_default = 1
|
||
LIMIT 1'
|
||
);
|
||
$stmtLoc->execute([(int)$_SESSION['user_id']]);
|
||
$currentLocation = $stmtLoc->fetch() ?: null;
|
||
}
|
||
|
||
if ($isAdmin && $pdoHeader !== null) {
|
||
$stmtPendingUsers = $pdoHeader->query('SELECT COUNT(*) FROM app_users WHERE is_active = 0');
|
||
$pendingApprovals = (int)$stmtPendingUsers->fetchColumn();
|
||
}
|
||
|
||
$menuGroups = [
|
||
[
|
||
'title' => 'Himmel & Planeten',
|
||
'links' => [
|
||
['href' => 'moonphase.php', 'label' => 'Mondphase'],
|
||
['href' => 'index_py.php', 'label' => 'Sonne & Mond'],
|
||
['href' => 'planetensichtbarkeit.php', 'label' => 'Planetensichtbarkeit'],
|
||
['href' => 'solarsystem.php', 'label' => 'Sonnensystem'],
|
||
['href' => 'jupitersystem.php', 'label' => 'Jupitersystem'],
|
||
['href' => 'tagbogen.php', 'label' => 'Tagbogen'],
|
||
['href' => 'sternenhimmel.php', 'label' => 'Sternenhimmel'],
|
||
['href' => 'meteorshowers.php', 'label' => 'Meteorstroeme'],
|
||
['href' => 'geocron/index.php', 'label' => 'Geocron'],
|
||
['href' => 'geocron3d.php', 'label' => 'Geocron 3D'],
|
||
],
|
||
],
|
||
[
|
||
'title' => 'Finsternisse & Bedeckungen',
|
||
'links' => [
|
||
['href' => 'mondfinsternis.php', 'label' => 'Mondfinsternis'],
|
||
['href' => 'sonnenfinsternis.php', 'label' => 'Sonnenfinsternis'],
|
||
['href' => 'bedeckung.php', 'label' => 'Bedeckungsphänomene'],
|
||
['href' => 'sternbedeckungen.php', 'label' => 'Mond-Stern-Bedeckungen'],
|
||
],
|
||
],
|
||
];
|
||
|
||
$adminLinks = [
|
||
['href' => 'admin_users.php', 'label' => 'Benutzerverwaltung'],
|
||
['href' => 'monatsvorhersage.php', 'label' => 'Monatsvorhersage'],
|
||
['href' => 'telegram/broadcast_test.php', 'label' => 'Telegram-Test'],
|
||
];
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title><?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8') ?></title>
|
||
<link rel="stylesheet" href="<?= htmlspecialchars($publicBasePath . 'css/style.css', ENT_QUOTES, 'UTF-8') ?>">
|
||
</head>
|
||
<body<?= $bodyClassAttr ?>>
|
||
|
||
<!-- Sternenhimmel -->
|
||
<canvas id="starfield"></canvas>
|
||
<script>
|
||
(function () {
|
||
const canvas = document.getElementById('starfield');
|
||
const ctx = canvas.getContext('2d');
|
||
let stars = [];
|
||
|
||
// Bilder vorladen
|
||
const imgRound = new Image();
|
||
const imgRays = new Image();
|
||
imgRound.src = <?= json_encode($publicBasePath . 'images/star16x16.png', JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
|
||
imgRays.src = <?= json_encode($publicBasePath . 'images/star16x16_rays.png', JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
|
||
|
||
function resize() {
|
||
canvas.width = window.innerWidth;
|
||
canvas.height = window.innerHeight;
|
||
}
|
||
|
||
function generateStars() {
|
||
stars = [];
|
||
const count = Math.floor((canvas.width * canvas.height) / 2800);
|
||
for (let i = 0; i < count; i++) {
|
||
const r = Math.random();
|
||
// Klassen: 80% klein-rund, 17% mittel-rund, 3% mit Strahlen
|
||
const hasRays = r > 0.97;
|
||
const size = hasRays ? (Math.random() * 6 + 8) // 8–14 px
|
||
: r > 0.80 ? (Math.random() * 4 + 5) // 5–9 px
|
||
: (Math.random() * 3 + 2); // 2–5 px
|
||
stars.push({
|
||
x: Math.random() * canvas.width,
|
||
y: Math.random() * canvas.height,
|
||
size,
|
||
img: hasRays ? imgRays : imgRound,
|
||
base: hasRays ? Math.random() * 0.20 + 0.12
|
||
: Math.random() * 0.18 + 0.04,
|
||
amp: Math.random() * 0.08 + 0.01,
|
||
phase: Math.random() * Math.PI * 2,
|
||
speed: Math.random() * 0.0003 + 0.00008,
|
||
});
|
||
}
|
||
}
|
||
|
||
let t = 0;
|
||
function draw() {
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
t++;
|
||
for (const s of stars) {
|
||
const a = s.base + s.amp * Math.sin(s.phase + t * s.speed * Math.PI * 2);
|
||
ctx.globalAlpha = a;
|
||
ctx.drawImage(s.img, s.x - s.size / 2, s.y - s.size / 2, s.size, s.size);
|
||
}
|
||
ctx.globalAlpha = 1;
|
||
requestAnimationFrame(draw);
|
||
}
|
||
|
||
// Erst zeichnen wenn beide Bilder geladen sind
|
||
let loaded = 0;
|
||
function onLoad() { if (++loaded === 2) { resize(); generateStars(); draw(); } }
|
||
imgRound.onload = onLoad;
|
||
imgRays.onload = onLoad;
|
||
|
||
window.addEventListener('resize', () => { resize(); generateStars(); });
|
||
})();
|
||
</script>
|
||
|
||
<header>
|
||
<div class="container">
|
||
<div class="header-inner">
|
||
<div class="header-brand">
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'index.php', ENT_QUOTES, 'UTF-8') ?>">Skyview & AstroTools</a>
|
||
<span class="header-sub"><a href="https://www.astronomiemuseum.de" target="_blank" rel="noopener">Astronomiemuseum der Sternwarte Sonneberg</a></span>
|
||
</div>
|
||
<?php if ($isAdmin && $pendingApprovals > 0): ?>
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'admin_users.php', ENT_QUOTES, 'UTF-8') ?>" class="admin-alert" aria-live="polite">
|
||
<span class="admin-alert-icon" aria-hidden="true">!</span>
|
||
<span class="admin-alert-text">Achtung: <?= $pendingApprovals ?> <?= $pendingApprovals === 1 ? 'Benutzer wartet' : 'Benutzer warten' ?> auf Freischaltung</span>
|
||
</a>
|
||
<?php endif; ?>
|
||
<div class="header-menu">
|
||
<button type="button" class="menu-toggle" id="menuToggle" aria-expanded="false" aria-controls="headerMenuPanel" aria-label="Menue oeffnen">
|
||
<span></span>
|
||
<span></span>
|
||
<span></span>
|
||
</button>
|
||
<nav class="menu-panel" id="headerMenuPanel" hidden>
|
||
<div class="menu-cols">
|
||
<?php foreach ($menuGroups as $group): ?>
|
||
<div class="menu-group">
|
||
<div class="menu-title"><?= $group['title'] ?></div>
|
||
<?php foreach ($group['links'] as $link): ?>
|
||
<a href="<?= htmlspecialchars($publicBasePath . $link['href'], ENT_QUOTES, 'UTF-8') ?>">
|
||
<?= htmlspecialchars($link['label'], ENT_QUOTES, 'UTF-8') ?>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<div class="menu-divider"></div>
|
||
<div class="menu-bottom">
|
||
<div class="menu-group">
|
||
<div class="menu-title">Konto</div>
|
||
<?php if ($loggedIn): ?>
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'settings.php', ENT_QUOTES, 'UTF-8') ?>">Einstellungen</a>
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'my_favorites.php', ENT_QUOTES, 'UTF-8') ?>">Favoriten</a>
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'satellitenhimmel.php', ENT_QUOTES, 'UTF-8') ?>">Satellitenhimmel</a>
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'logout.php', ENT_QUOTES, 'UTF-8') ?>" class="nav-logout">Abmelden</a>
|
||
<?php else: ?>
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'login.php', ENT_QUOTES, 'UTF-8') ?>">Anmelden</a>
|
||
<a href="<?= htmlspecialchars($publicBasePath . 'register.php', ENT_QUOTES, 'UTF-8') ?>">Registrieren</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php if ($isAdmin): ?>
|
||
<div class="menu-group">
|
||
<div class="menu-title">Administration</div>
|
||
<?php foreach ($adminLinks as $adminLink): ?>
|
||
<a href="<?= htmlspecialchars($publicBasePath . $adminLink['href'], ENT_QUOTES, 'UTF-8') ?>">
|
||
<?= htmlspecialchars($adminLink['label'], ENT_QUOTES, 'UTF-8') ?>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
<?php if ($showHeaderIntro): ?>
|
||
<div class="page-header-intro">
|
||
<?php if ($headerIntroPre !== ''): ?>
|
||
<div class="page-header-pre"><?= htmlspecialchars($headerIntroPre, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<?php endif; ?>
|
||
<?php if ($headerIntroTitle !== ''): ?>
|
||
<h1 class="page-header-title"><?= htmlspecialchars($headerIntroTitle, ENT_QUOTES, 'UTF-8') ?></h1>
|
||
<?php endif; ?>
|
||
<?php if ($headerIntroSub !== ''): ?>
|
||
<div class="page-header-sub"><?= htmlspecialchars($headerIntroSub, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</header>
|
||
|
||
<main>
|
||
<div class="container">
|
||
<script>
|
||
(function () {
|
||
const toggle = document.getElementById('menuToggle');
|
||
const panel = document.getElementById('headerMenuPanel');
|
||
|
||
if (!toggle || !panel) {
|
||
return;
|
||
}
|
||
|
||
function closeMenu() {
|
||
toggle.setAttribute('aria-expanded', 'false');
|
||
panel.hidden = true;
|
||
document.body.classList.remove('menu-open');
|
||
}
|
||
|
||
function openMenu() {
|
||
toggle.setAttribute('aria-expanded', 'true');
|
||
panel.hidden = false;
|
||
document.body.classList.add('menu-open');
|
||
}
|
||
|
||
toggle.addEventListener('click', function () {
|
||
if (toggle.getAttribute('aria-expanded') === 'true') {
|
||
closeMenu();
|
||
return;
|
||
}
|
||
|
||
openMenu();
|
||
});
|
||
|
||
document.addEventListener('click', function (event) {
|
||
if (panel.hidden) {
|
||
return;
|
||
}
|
||
|
||
if (!panel.contains(event.target) && !toggle.contains(event.target)) {
|
||
closeMenu();
|
||
}
|
||
});
|
||
|
||
document.addEventListener('keydown', function (event) {
|
||
if (event.key === 'Escape') {
|
||
closeMenu();
|
||
}
|
||
});
|
||
})();
|
||
</script>
|