diff --git a/hifi-src/src/assets/leistungen/hero-highlight.webp b/hifi-src/src/assets/leistungen/hero-highlight.webp
new file mode 100644
index 0000000..08c32b0
Binary files /dev/null and b/hifi-src/src/assets/leistungen/hero-highlight.webp differ
diff --git a/hifi-src/src/assets/photos/gallery-amp-purple.webp b/hifi-src/src/assets/photos/gallery-amp-purple.webp
new file mode 100644
index 0000000..0335f0a
Binary files /dev/null and b/hifi-src/src/assets/photos/gallery-amp-purple.webp differ
diff --git a/hifi-src/src/assets/photos/gallery-dash.webp b/hifi-src/src/assets/photos/gallery-dash.webp
new file mode 100644
index 0000000..696d41a
Binary files /dev/null and b/hifi-src/src/assets/photos/gallery-dash.webp differ
diff --git a/hifi-src/src/assets/photos/gallery-dash2.webp b/hifi-src/src/assets/photos/gallery-dash2.webp
new file mode 100644
index 0000000..8a85301
Binary files /dev/null and b/hifi-src/src/assets/photos/gallery-dash2.webp differ
diff --git a/hifi-src/src/assets/photos/gallery-rear.webp b/hifi-src/src/assets/photos/gallery-rear.webp
new file mode 100644
index 0000000..fb4a10c
Binary files /dev/null and b/hifi-src/src/assets/photos/gallery-rear.webp differ
diff --git a/hifi-src/src/assets/photos/gallery-speaker.webp b/hifi-src/src/assets/photos/gallery-speaker.webp
new file mode 100644
index 0000000..33ed1ea
Binary files /dev/null and b/hifi-src/src/assets/photos/gallery-speaker.webp differ
diff --git a/hifi-src/src/assets/photos/gallery-subs.webp b/hifi-src/src/assets/photos/gallery-subs.webp
new file mode 100644
index 0000000..8241c9d
Binary files /dev/null and b/hifi-src/src/assets/photos/gallery-subs.webp differ
diff --git a/hifi-src/src/assets/photos/hero-trunk.webp b/hifi-src/src/assets/photos/hero-trunk.webp
new file mode 100644
index 0000000..c07a723
Binary files /dev/null and b/hifi-src/src/assets/photos/hero-trunk.webp differ
diff --git a/hifi-src/src/components/Footer.jsx b/hifi-src/src/components/Footer.jsx
index 57bc03d..88f6eca 100644
--- a/hifi-src/src/components/Footer.jsx
+++ b/hifi-src/src/components/Footer.jsx
@@ -66,10 +66,10 @@ export default function Footer() {
{t('contactPage.hours')}
diff --git a/hifi-src/src/pages/public/Home.jsx b/hifi-src/src/pages/public/Home.jsx
index 3800495..2845435 100644
--- a/hifi-src/src/pages/public/Home.jsx
+++ b/hifi-src/src/pages/public/Home.jsx
@@ -8,14 +8,14 @@ import StarRating from '../../components/StarRating.jsx';
import TestimonialSlider from '../../components/TestimonialSlider.jsx';
import { useSiteSettings } from '../../context/SiteSettingsContext.jsx';
import { useLanguage } from '../../context/LanguageContext.jsx';
-import defaultHeroImage from '../../assets/photos/gallery-dash2.jpg';
-import galleryAmp from '../../assets/photos/gallery-amp-purple.jpg';
-import gallerySpeaker from '../../assets/photos/gallery-speaker.jpg';
-import gallerySubs from '../../assets/photos/gallery-subs.jpg';
-import galleryDash from '../../assets/photos/gallery-dash.jpg';
-import galleryTrunk from '../../assets/photos/hero-trunk.jpg';
-import galleryRear from '../../assets/photos/gallery-rear.jpg';
-import heroHighlight from '../../assets/leistungen/hero-highlight.jpg';
+import defaultHeroImage from '../../assets/photos/gallery-dash2.webp';
+import galleryAmp from '../../assets/photos/gallery-amp-purple.webp';
+import gallerySpeaker from '../../assets/photos/gallery-speaker.webp';
+import gallerySubs from '../../assets/photos/gallery-subs.webp';
+import galleryDash from '../../assets/photos/gallery-dash.webp';
+import galleryTrunk from '../../assets/photos/hero-trunk.webp';
+import galleryRear from '../../assets/photos/gallery-rear.webp';
+import heroHighlight from '../../assets/leistungen/hero-highlight.webp';
import youtubeVideo from '../../assets/videos/youtube-hintergrund.mp4';
const YOUTUBE_URL = 'https://www.youtube.com/@hifiplanet2812';
@@ -23,7 +23,18 @@ const YOUTUBE_VIDEO_ID = 'ostj2mKDVUc';
const brands = ['Focal', 'Helix', 'Ground Zero', 'Mosconi', 'Hifonics', 'Audison'];
-const galleryImages = [gallerySubs, galleryAmp, gallerySpeaker, galleryDash, galleryRear, galleryTrunk];
+// Native Pixelmasse der Bilder unten - nur fuer die width/height-Attribute auf
![]()
,
+// damit der Browser vor dem Laden Platz reserviert (verhindert Layout-Sprung). Die
+// tatsaechliche Anzeigegroesse wird weiterhin komplett per CSS (aspect-square etc.)
+// bestimmt, diese Werte muessen also nicht exakt zum gerenderten Seitenverhaeltnis passen.
+const galleryImages = [
+ { src: gallerySubs, width: 900, height: 600 },
+ { src: galleryAmp, width: 900, height: 600 },
+ { src: gallerySpeaker, width: 900, height: 1200 },
+ { src: galleryDash, width: 900, height: 814 },
+ { src: galleryRear, width: 900, height: 1200 },
+ { src: galleryTrunk, width: 1920, height: 1280 },
+];
export default function Home() {
const { hero_image_path: heroImagePath } = useSiteSettings();
@@ -33,7 +44,7 @@ export default function Home() {
const stats = t('home.stats');
const steps = t('home.steps');
const galleryAlts = t('home.galleryAlts');
- const gallery = galleryImages.map((src, i) => ({ src, alt: galleryAlts[i] }));
+ const gallery = galleryImages.map((img, i) => ({ ...img, alt: galleryAlts[i] }));
const testimonials = t('home.testimonials');
const faqs = t('home.faqs');
@@ -221,7 +232,14 @@ export default function Home() {
@@ -257,7 +282,14 @@ export default function Home() {
{gallery.map((img, i) => (
-
+
))}
@@ -289,7 +321,14 @@ export default function Home() {
-
+
{t('home.moreTitle')}
diff --git a/hifi/.htaccess b/hifi/.htaccess
index 4efb384..52d6f9c 100644
--- a/hifi/.htaccess
+++ b/hifi/.htaccess
@@ -1,6 +1,20 @@
RewriteEngine On
RewriteBase /
+# Lang-lebiger Cache fuer gehashte Build-Assets (Vite haengt bei jeder Aenderung einen
+# neuen Hash an den Dateinamen) und hochgeladene Bilder (bekommen beim Upload einen
+# zufaelligen Dateinamen) - beide aendern sich unter derselben URL nie, "immutable" ist
+# hier also sicher. Ueber mod_headers statt mod_expires, da Letzteres nicht ueberall
+# aktiviert ist.
+
+
+ Header set Cache-Control "public, max-age=31536000, immutable"
+
+
+ Header set Cache-Control "public, max-age=31536000, immutable"
+
+
+
# Ohne dies leitet Apache (mod_dir) Anfragen an /api/uploads mit einem 301 auf
# /api/uploads/ um, bevor mod_rewrite greifen kann - weil api/uploads/ als
# echtes Verzeichnis existiert. Bei einem POST mit Datei-Upload geht dabei der
diff --git a/hifi/api/src/Controllers/AuthController.php b/hifi/api/src/Controllers/AuthController.php
index a28b72a..8eb294e 100644
--- a/hifi/api/src/Controllers/AuthController.php
+++ b/hifi/api/src/Controllers/AuthController.php
@@ -154,8 +154,12 @@ class AuthController
public static function me(): void
{
+ // Bewusst kein 401 hier: /auth/me wird auf JEDER oeffentlichen Seite aufgerufen,
+ // um den Login-Status zu pruefen - "nicht angemeldet" ist der Normalfall fuer
+ // Besucher, kein Fehler. Ein 401 erzeugt in der Browser-Konsole/DevTools trotz
+ // JS-seitigem catch() einen sichtbaren Netzwerk-Fehler (bemaengelt u.a. Lighthouse).
if (empty($_SESSION['admin_id'])) {
- Http::error('Nicht angemeldet', 401);
+ Http::send(['authenticated' => false]);
}
Http::send(self::userPayload((int) $_SESSION['admin_id'], $_SESSION['admin_username']));
}