Geizkragen/header.php

264 lines
11 KiB
PHP

<?php
/**
* @file header.php
* @brief Globale Header-Datei für die Geizkragen-Anwendung.
*
* Diese Datei bildet den initialen HTML-Kopf (Head) der Anwendung und enthält
* alle grundlegenden Meta-Tags, Stylesheets und Favicon-Definitionen.
* Zudem definiert sie die globale Navigationsleiste, inklusive Desktop- und
* Mobile-Layouts, einer globalen Produktsuche sowie dem Overlay-Menü.
*
* @details
* Folgende Kernkomponenten sind hier implementiert:
* - Einbindung aller relevanten CSS-Dateien (@see style.css, @see login.css, etc.).
* - Setup für Viewport und Mobile-Geräte (Safe Areas für Notch-Geräte).
* - Eine reaktionsfähige Navigationsleiste mit Links zu Home, Vergleich, Wunschliste und Account.
* - Ein Mobile-Menü (Off-Canvas), das per JavaScript geöffnet und geschlossen wird.
* - Suchformulare, die Benutzeranfragen per GET an die index.php übermitteln.
*
* @note Diese Datei wird üblicherweise in anderen Seiten inkludiert. Sie enthält KEINEN
* eigenständigen PHP-Logikbereich am Anfang, um direkt die HTML-Struktur zu rendern.
*/
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="assets/css/login.css">
<link rel="stylesheet" href="assets/css/catbar.css">
<link rel="stylesheet" href="assets/css/compcard.css">
<link rel="stylesheet" href="assets/css/productpage.css">
<link rel="stylesheet" href="assets/css/productAdder.css">
<link rel="stylesheet" href="assets/css/compare.css">
<!-- Favicon (zentral) -->
<link rel="icon" href="assets/images/favicon.ico" sizes="any">
<link rel="shortcut icon" href="assets/images/favicon.ico">
<title>Geizkragen</title>
<style>
/**
* @brief Standard-UI Anpassungen für mobile Geräte.
* Verhindert den blauen Tap-Highlight auf iOS und mobilen Browsern.
*/
* { -webkit-tap-highlight-color: transparent; }
/**
* @brief Safe Areas für Notch-Geräte (z.B. iPhone).
* Sorgt dafür, dass der Header nicht in abgerundete Ecken oder die Kameraaussparung ragt.
*/
.header { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
/**
* @brief Safe Area für den Footer.
*/
.footer { padding-bottom: env(safe-area-inset-bottom); }
/**
* @brief Definiert das Overlay (Hintergrund-Verdunkelung/Blur) für das Mobile-Menü.
* Es wird unsichtbar gerendert und erst sichtbar, wenn die Klasse `is-visible` hinzugefügt wird.
*/
.nav__overlay {
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.55);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
visibility: hidden;
opacity: 0;
transition: opacity 300ms ease, visibility 0s 300ms;
}
/**
* @brief Aktiver Zustand des Overlays. Wichtig für fließende Fade-in Übergänge.
*/
.nav__overlay.is-visible {
visibility: visible;
opacity: 1;
transition: opacity 300ms ease, visibility 0s 0s;
}
</style>
</head>
<body>
<!--
@brief Overlay-Container
Dient der Verdunkelung des Bildschirms beim Öffnen des mobilen Menüs.
Ein Klick auf dieses Element schließt das Menü.
-->
<div class="nav__overlay" id="nav-overlay"></div>
<header class="header" id="header">
<nav class="nav" aria-label="Hauptnavigation">
<a class="nav__logoLink" href="index.php">
<img class="nav__logo" src="assets/images/logoText.png" alt="Geizkragen" width="150">
</a>
<!-- Desktop-Suche (zentriert, wird auf ≤900px per CSS ausgeblendet) -->
<form class="nav__searchForm" action="index.php" method="GET" autocomplete="off">
<div class="nav__searchField">
<input class="nav__searchInput" type="text" id="search" name="search"
placeholder="Produkte suchen…" inputmode="text">
</div>
</form>
<div class="nav__inner container">
<!-- ═══ Slide-In-Menü (wird auf Mobile per JS getoggelt) ═══ -->
<div class="nav__menu" id="nav-menu">
<ul class="nav__list">
<li class="nav__item nav__item--mobile">
<a href="index.php" class="nav__link">Home</a>
</li>
<li class="nav__item nav__item--mobile">
<a href="wunschliste.php" class="nav__link">Wunschliste</a>
</li>
<li class="nav__item nav__item--mobile">
<a href="compare.php" class="nav__link">Vergleich</a>
</li>
<li class="nav__item nav__item--mobile">
<a href="account.php" class="nav__link">Account</a>
</li>
</ul>
<!-- Schließen-Button -->
<button class="nav__close" id="nav-close" type="button" aria-label="Menü schließen">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</div>
<!-- ═══ /Slide-In-Menü ═══ -->
<div class="nav__actions">
<a class="nav__login" href="index.php" aria-label="Home">
<svg class="icon icon-user" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
<span class="nav__btn-text">Home</span>
</a>
<a class="nav__login" href="compare.php" aria-label="Vergleich">
<svg class="icon icon-user" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
<span class="nav__btn-text">Vergleich</span>
</a>
<a class="nav__login" href="wunschliste.php" aria-label="Wunschliste">
<svg class="icon icon-user" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
</svg>
<span class="nav__btn-text">Wunschliste</span>
</a>
<a class="nav__login" href="account.php" aria-label="Account">
<svg class="icon icon-user" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
<span class="nav__btn-text">Account</span>
</a>
<!-- Hamburger-Toggle -->
<button class="nav__toggle" id="nav-toggle" type="button" aria-label="Menü öffnen">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round">
<line x1="3" y1="6" x2="21" y2="6"/>
<line x1="3" y1="12" x2="21" y2="12"/>
<line x1="3" y1="18" x2="21" y2="18"/>
</svg>
</button>
</div>
</div>
</nav>
<!--
@brief Mobile-Suchleiste
Wird unterhalb der Nav-Zeile platziert und ist per CSS in der Regel nur
auf Bildschirmen mit einer Breite von <=900px sichtbar.
-->
<form class="nav__searchBar" action="index.php" method="GET" autocomplete="off">
<div class="nav__searchField">
<input class="nav__searchInput" type="text" name="search"
placeholder="Produkte suchen…" inputmode="text">
</div>
</form>
</header>
<script>
/**
* @brief Kapselung der gesamten JavaScript-Logik für die Navigation.
*
* Verwendet eine IIFE (Immediately Invoked Function Expression), um globale Scope-Verschmutzung zu vermeiden.
* Handhabt das Öffnen, Schließen und die Event-Bindungen des Slide-In/Mobile-Menüs.
*/
(function () {
// DOM Elemente für die Mobile-Menü-Steuerung
var toggle = document.getElementById('nav-toggle'); /**< Button zum Öffnen des Menüs */
var closeBtn = document.getElementById('nav-close'); /**< Button zum Schließen des Menüs */
var menu = document.getElementById('nav-menu'); /**< Container des Slide-In-Menüs */
var overlay = document.getElementById('nav-overlay'); /**< Das verdunkelnde Desktop-Overlay */
// Abbruch, falls eines der essentiellen Elemente fehlt
if (!toggle || !closeBtn || !menu || !overlay) return;
/**
* @brief Öffnet das Mobile-Menü.
*
* Fügt dem Menü und dem Overlay die notwendigen Styling-Klassen hinzu,
* um diese sichtbar zu machen. Blockiert zudem das Scrollen der aktuellen Seite.
*/
function open() {
menu.classList.add('show-menu');
overlay.classList.add('is-visible');
document.body.style.overflow = 'hidden';
}
/**
* @brief Schließt das Mobile-Menü.
*
* Entfernt die aktiven Zustands-Klassen und stellt das gewöhnliche
* Scroll-Verhalten (overflow) wieder her.
*/
function close() {
menu.classList.remove('show-menu');
overlay.classList.remove('is-visible');
document.body.style.overflow = '';
}
// Event-Listener für das Öffnen der Navigation
toggle.addEventListener('click', open);
// Event-Listener für das Schließen der Navigation über den X-Button oder Overlay-Klick
closeBtn.addEventListener('click', close);
overlay.addEventListener('click', close);
/**
* @brief Accessibility: Schließt das Menü via Escape-Taste.
*/
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') close();
});
/**
* @brief Automatisches Schließen des Menüs bei Link-Klick.
*
* Iteriert über alle im Menü vorhandenen Anchor ('a') Tags. Sobald ein Link
* angeklickt wird, wird das Menü geschlossen.
*/
var links = menu.querySelectorAll('a');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', close);
}
})();
</script>