Files
Epicnabbo-Catalogus-Updated…/src/components/auth/auth-top-bar.tsx
T
openhands 97454f361b feat(home): rebuild the landing page on a shared panel system
The homepage mixed four different translucent washes (surface 44-60% plus a
backdrop-filter each), rendered the same four counters twice, and showed a
dangling "Welcome to " eyebrow because the localized string expected the hotel
name. A missing theme wallpaper replaced the whole sky gradient with flat
white, and stale CMS image references produced broken images and 404s.

Replace the ad-hoc panels with one opaque, theme-derived `.panel` token set
(surface, border, shadow, header, radius) and a `.panel-float` variant for the
counter strip that straddles the hero edge. The strip is now the single home
of the four headline counters; a failed read renders "unavailable" instead of
silently dropping a cell. Add the fourth feature card (Games) that already had
translated copy, link recent users to their profiles, and fall back to themed
placeholders for news covers and camera photos without an upload.

Add `pages.home.heroEyebrow` to all 25 locales, layer the CMS wallpaper over
`--site-bg-gradient` instead of replacing it, and keep the sky in dark mode.
Add `publicAssetExists` so local uploads that no longer exist are skipped
(wallpaper, help topics) rather than rendered broken. Fix the `/help` topic
icons to use the `/assets/images/help-center/` base the detail page already
used.

Throttle the spotlight glow to one update per animation frame, drop the dead
`.glass-chip` rules, define the missing `.panel-float`, and fix the stat
divider and reduced-motion selectors. Stat labels use the readable text token
so they clear WCAG AA, and the language button's accessible name now contains
its visible label.

Verified: tsc, biome, 3590 unit tests, i18n audit unchanged, axe 0 violations
at 390/768/1024/1280/1440 in light and dark, quality e2e 16/16.
2026-10-22 17:39:30 +02:00

122 lines
3.5 KiB
TypeScript

import Image from "next/image";
import { Clock } from "@/components/clock";
import { LanguageSwitcher } from "@/components/language-switcher";
import { LiveOnlineCount } from "@/components/live-online-count";
import { Reveal } from "@/components/motion-reveal";
import { ThemeSwitcher } from "@/components/theme-switcher";
import { ICON_LIGHTHOUSE } from "@/lib/site-icons";
/**
* Shared frosted-glass top bar for the public pages (index, login, register).
* Shows the hotel logo on the left and the live "online" counter (which carries
* the hotel name), language / clock / theme controls on the right. One
* component so every public page keeps the exact same chrome instead of
* duplicating it.
*/
export function AuthTopBar({
hotelName,
logo,
online,
}: {
hotelName: string;
logo?: string | null;
/** Live online count; omit (or pass null) to hide the indicator. */
online?: number | null;
}) {
return (
<Reveal>
<div
className="panel relative flex items-center justify-between gap-3 rounded-full px-3 py-2.5 sm:px-5"
style={{
background:
"linear-gradient(90deg, var(--panel-surface), color-mix(in srgb, var(--color-primary) 7%, var(--panel-surface)))",
}}
>
<div className="flex min-w-0 items-center gap-2 sm:gap-3">
{logo ? (
<Image
src={logo}
alt={hotelName}
width={100}
height={28}
className="shrink-0 object-contain"
unoptimized
style={{ maxHeight: 26, width: "auto", height: "auto" }}
/>
) : (
<div
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full"
style={{
background:
"linear-gradient(135deg, var(--color-primary), color-mix(in srgb, var(--color-accent) 60%, var(--color-primary)))",
boxShadow:
"0 4px 16px -4px color-mix(in srgb, var(--color-primary) 60%, transparent)",
}}
>
<Image
src={ICON_LIGHTHOUSE}
alt=""
width={18}
height={18}
className="shrink-0"
unoptimized
style={{ filter: "brightness(0) invert(1)" }}
/>
</div>
)}
</div>
<div
className="flex items-center gap-1 sm:gap-1.5 rounded-full px-1.5 py-1 sm:px-2"
style={{
background:
"color-mix(in srgb, var(--color-text-muted) 5%, transparent)",
}}
>
{typeof online === "number" && (
<span
className="flex items-center gap-1.5 px-1"
style={{ color: "var(--color-text-readable)" }}
>
<span className="relative flex h-2 w-2 shrink-0">
<span
className="absolute inline-flex h-full w-full animate-ping rounded-full opacity-70"
style={{ background: "var(--color-primary)" }}
/>
<span
className="relative inline-flex h-2 w-2 rounded-full"
style={{ background: "var(--color-primary)" }}
/>
</span>
<span
className="text-xs font-black tabular-nums"
style={{
color: "var(--color-primary-readable, var(--color-primary))",
}}
>
<LiveOnlineCount initial={online} hotelName={hotelName} />
</span>
</span>
)}
<LanguageSwitcher />
<div
className="hidden sm:block w-px h-5"
style={{
background:
"color-mix(in srgb, var(--color-text-muted) 12%, transparent)",
}}
/>
<Clock />
<div
className="w-px h-5"
style={{
background:
"color-mix(in srgb, var(--color-text-muted) 12%, transparent)",
}}
/>
<ThemeSwitcher />
</div>
</div>
</Reveal>
);
}