feat(home): clean shared top bar with live online counter
CI / check (push) Successful in 28s
CI / tests-imaging-browsers (push) Successful in 1m34s
CI / tests-integration (push) Successful in 1m57s
CI / tests-unit (push) Successful in 2m1s
CI / tests-quality (push) Successful in 50s
CI / tests-ui (push) Successful in 4m39s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m29s

The homepage duplicated the online count and recent-user avatars (hero plus
community sidebar), and the public pages each kept their own chrome. Put one
AuthTopBar at the top of index, login and register — logo + hotel name plus a
live online indicator and the language/clock/theme controls — and drop the
duplicated hero rows.
This commit is contained in:
openhands committed 2026-10-18 19:38:32 +02:00
1 parent 9cf1eb615c
commit b40293bd06
5 files changed
+45 -83

No files matched your search

File diff suppressed because it is too large. Load diff
+1
View File
@@ -103,6 +103,7 @@ export function AuthLandingView({ data, copy, form }: AuthLandingViewProps) {
<AuthPageFrame <AuthPageFrame
hotelName={data.hotelName} hotelName={data.hotelName}
logo={data.logo} logo={data.logo}
online={data.online}
title={copy.title} title={copy.title}
subtitle={copy.subtitle} subtitle={copy.subtitle}
notice={copy.notice} notice={copy.notice}
+4 -1
View File
@@ -128,6 +128,8 @@ function AvatarGrid({
interface AuthPageFrameProps { interface AuthPageFrameProps {
hotelName: string; hotelName: string;
logo?: string | null; logo?: string | null;
/** Live online count shown in the top bar; omit to hide it. */
online?: number;
/** Title of the form card on the right. */ /** Title of the form card on the right. */
title: string; title: string;
/** One-line intro above the form. */ /** One-line intro above the form. */
@@ -148,6 +150,7 @@ interface AuthPageFrameProps {
export function AuthPageFrame({ export function AuthPageFrame({
hotelName, hotelName,
logo, logo,
online,
title, title,
subtitle, subtitle,
notice, notice,
@@ -158,7 +161,7 @@ export function AuthPageFrame({
<div className="mx-auto w-full max-w-6xl flex flex-col gap-8 pb-16"> <div className="mx-auto w-full max-w-6xl flex flex-col gap-8 pb-16">
<div className="relative"> <div className="relative">
<AuthAurora /> <AuthAurora />
<AuthTopBar hotelName={hotelName} logo={logo} /> <AuthTopBar hotelName={hotelName} logo={logo} online={online} />
</div> </div>
<Reveal> <Reveal>
+37 -7
View File
@@ -1,29 +1,33 @@
import Image from "next/image"; import Image from "next/image";
import { Clock } from "@/components/clock"; import { Clock } from "@/components/clock";
import { LanguageSwitcher } from "@/components/language-switcher"; import { LanguageSwitcher } from "@/components/language-switcher";
import { LiveOnlineCounter } from "@/components/live-online-counter";
import { Reveal } from "@/components/motion-reveal"; import { Reveal } from "@/components/motion-reveal";
import { ThemeSwitcher } from "@/components/theme-switcher"; import { ThemeSwitcher } from "@/components/theme-switcher";
import { ICON_LIGHTHOUSE } from "@/lib/site-icons"; import { ICON_LIGHTHOUSE } from "@/lib/site-icons";
/** /**
* Shared frosted-glass top bar for the public auth pages (login, register, * Shared frosted-glass top bar for the public pages (index, login, register).
* etc.). Shows the hotel logo + name on the left and language / clock / theme * Shows the hotel logo + name on the left and the live online count, language /
* controls on the right. Defaults mirror the homepage top bar so auth pages * clock / theme controls on the right. One component so every public page keeps
* share one consistent look. * the exact same chrome instead of duplicating it.
*/ */
export function AuthTopBar({ export function AuthTopBar({
hotelName, hotelName,
logo, logo,
online,
showHotelName = true, showHotelName = true,
}: { }: {
hotelName: string; hotelName: string;
logo?: string | null; logo?: string | null;
/** Live online count; omit (or pass null) to hide the indicator. */
online?: number | null;
showHotelName?: boolean; showHotelName?: boolean;
}) { }) {
return ( return (
<Reveal> <Reveal>
<div <div
className="relative flex items-center justify-between rounded-full border px-3 py-2.5 sm:px-5" className="relative flex items-center justify-between gap-3 rounded-full border px-3 py-2.5 sm:px-5"
style={{ style={{
background: background:
"linear-gradient(90deg, color-mix(in srgb, var(--color-surface) 62%, transparent), color-mix(in srgb, var(--color-primary) 7%, transparent))", "linear-gradient(90deg, color-mix(in srgb, var(--color-surface) 62%, transparent), color-mix(in srgb, var(--color-primary) 7%, transparent))",
@@ -35,7 +39,7 @@ export function AuthTopBar({
"0 1px 3px rgba(0,0,0,0.04), 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 6%, transparent)", "0 1px 3px rgba(0,0,0,0.04), 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 6%, transparent)",
}} }}
> >
<div className="flex items-center gap-2 sm:gap-3"> <div className="flex min-w-0 items-center gap-2 sm:gap-3">
{logo ? ( {logo ? (
<Image <Image
src={logo} src={logo}
@@ -69,7 +73,7 @@ export function AuthTopBar({
)} )}
{showHotelName ? ( {showHotelName ? (
<span <span
className="hidden text-sm font-extrabold uppercase tracking-wide sm:inline" className="hidden truncate text-sm font-extrabold uppercase tracking-wide sm:inline"
style={{ color: "var(--color-text-readable)" }} style={{ color: "var(--color-text-readable)" }}
> >
{hotelName} {hotelName}
@@ -83,6 +87,32 @@ export function AuthTopBar({
"color-mix(in srgb, var(--color-text-muted) 5%, transparent)", "color-mix(in srgb, var(--color-text-muted) 5%, transparent)",
}} }}
> >
{typeof online === "number" && (
<span
className="flex items-center gap-1.5 px-1"
title={hotelName}
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))",
}}
>
<LiveOnlineCounter initial={online} />
</span>
</span>
)}
<LanguageSwitcher /> <LanguageSwitcher />
<div <div
className="hidden sm:block w-px h-5" className="hidden sm:block w-px h-5"
@@ -11,7 +11,7 @@ const compactCallSites = new Map<string, number>([
["src/app/(site)/leaderboard/page.tsx", 1], ["src/app/(site)/leaderboard/page.tsx", 1],
["src/app/(site)/me/page.tsx", 1], ["src/app/(site)/me/page.tsx", 1],
["src/app/(site)/messages/page.tsx", 2], ["src/app/(site)/messages/page.tsx", 2],
["src/app/(site)/page.tsx", 2], ["src/app/(site)/page.tsx", 1],
["src/app/(site)/radio/leaderboard/page.tsx", 1], ["src/app/(site)/radio/leaderboard/page.tsx", 1],
["src/app/(site)/radio/shouts/page.tsx", 1], ["src/app/(site)/radio/shouts/page.tsx", 1],
["src/app/(site)/rankings/page.tsx", 1], ["src/app/(site)/rankings/page.tsx", 1],