diff --git a/src/app/(site)/page.tsx b/src/app/(site)/page.tsx index ab3a058e..93327483 100644 --- a/src/app/(site)/page.tsx +++ b/src/app/(site)/page.tsx @@ -4,8 +4,27 @@ import { headers } from "next/headers"; import Image from "next/image"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; +import type { CSSProperties, ReactNode } from "react"; +import { AnimatedCounter } from "@/components/animated-counter"; +import { HomeLoginForm } from "@/components/auth/home-login-form"; +import { Clock } from "@/components/clock"; +import { LanguageSwitcher } from "@/components/language-switcher"; +import Link from "@/components/link"; +import { LiveOnlineCounter } from "@/components/live-online-counter"; +import { Reveal } from "@/components/motion-reveal"; import { PublicLoadError } from "@/components/public/load-error"; +import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail"; +import { ThemeSwitcher } from "@/components/theme-switcher"; +import { TypewriterText } from "@/components/typewriter-text"; +import { auth } from "@/lib/auth"; +import { cached } from "@/lib/cache"; +import { CameraWeb, db, Rooms, User } from "@/lib/db"; +import { formatDate } from "@/lib/format-date"; +import { resolveHotelName } from "@/lib/hotel-name"; +import { captchaConfig } from "@/lib/services/captcha"; +import { getNewsList } from "@/lib/services/news-list"; import { publicReadFailure } from "@/lib/services/public-read"; +import { siteSettings } from "@/lib/services/site-settings"; import { ICON_ARTICLE, ICON_CAMERA, @@ -28,26 +47,117 @@ export const metadata: Metadata = { }, }; -import { AmbientOrbs } from "@/components/ambient-orbs"; -import { AnimatedCounter } from "@/components/animated-counter"; -import { HomeLoginForm } from "@/components/auth/home-login-form"; -import { Clock } from "@/components/clock"; -import { LanguageSwitcher } from "@/components/language-switcher"; -import Link from "@/components/link"; -import { LiveOnlineCounter } from "@/components/live-online-counter"; -import { Reveal } from "@/components/motion-reveal"; -import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail"; -import { SurfaceCard } from "@/components/surface-card"; -import { ThemeSwitcher } from "@/components/theme-switcher"; -import { TypewriterText } from "@/components/typewriter-text"; -import { auth } from "@/lib/auth"; -import { cached } from "@/lib/cache"; -import { CameraWeb, db, Rooms, User } from "@/lib/db"; -import { formatDate } from "@/lib/format-date"; -import { resolveHotelName } from "@/lib/hotel-name"; -import { captchaConfig } from "@/lib/services/captcha"; -import { getNewsList } from "@/lib/services/news-list"; -import { siteSettings } from "@/lib/services/site-settings"; +// ── Local visual language (theme-aware, no big white blocks) ────────── +const PANEL_BG = + "linear-gradient(160deg, color-mix(in srgb, var(--color-primary) 12%, transparent) 0%, color-mix(in srgb, var(--color-surface) 58%, transparent) 52%, color-mix(in srgb, var(--color-accent) 9%, transparent) 100%)"; + +const PANEL_STYLE: CSSProperties = { + background: PANEL_BG, + backdropFilter: "blur(18px)", + WebkitBackdropFilter: "blur(18px)", + borderColor: "color-mix(in srgb, var(--color-text-muted) 12%, transparent)", + boxShadow: + "0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 6%, transparent), 0 24px 60px -30px color-mix(in srgb, #000 28%, transparent)", +}; + +const DARK_BAND = + "linear-gradient(120deg, color-mix(in srgb, var(--color-primary) 30%, #0a0e1e) 0%, color-mix(in srgb, var(--color-accent) 26%, #0a0e1e) 52%, color-mix(in srgb, var(--color-primary) 20%, #0a0e1e) 100%)"; + +const GLASS_TILE_BG = + "linear-gradient(155deg, color-mix(in srgb, var(--color-surface) 60%, transparent) 0%, color-mix(in srgb, var(--color-surface) 44%, transparent) 60%, color-mix(in srgb, var(--color-accent) 6%, transparent) 100%)"; + +interface GlassPanelProps { + children: ReactNode; + title?: string; + icon?: string; + actionHref?: string; + actionLabel?: string; + bodyClassName?: string; + className?: string; +} + +function GlassPanel({ + children, + title, + icon, + actionHref, + actionLabel, + bodyClassName, + className, +}: GlassPanelProps) { + const hasHeader = Boolean(title || icon); + + return ( +
+ {hasHeader && ( +
+
+ {icon && ( +
+ +
+ )} + {title && ( +

+ {title} +

+ )} +
+ {actionHref && actionLabel && ( + + {actionLabel} + + )} +
+ )} + {hasHeader ? ( +
{children}
+ ) : ( + children + )} +
+ ); +} async function getHotelData() { const [hotelName, logo] = await Promise.all([ @@ -168,26 +278,26 @@ export default async function Home() { -
+
{a.title} -
- → +
+ →
)}

@@ -219,7 +329,7 @@ export default async function Home() {

{formatDate(a.createdAt, "date", "")}

@@ -228,19 +338,47 @@ export default async function Home() { ); + const exploreLinks = [ + { href: "/community", label: tn("community") }, + { href: "/news", label: tn("articles") }, + { href: "/photos", label: tn("photos") }, + { href: "/radio", label: tn("radio") }, + { href: "/shop", label: tn("shop") }, + { href: "/rankings", label: tn("rankings") }, + ]; + + const statChips = [ + { value: users, label: tp("statsCitizens"), color: "var(--color-primary)" }, + { value: rooms, label: tp("statsRooms"), color: "var(--color-accent)" }, + { + value: totalPhotos, + label: tp("statsPhotos"), + color: "var(--color-primary)", + }, + { + value: articles?.length ?? null, + label: tp("statsArticles"), + color: "var(--color-accent)", + }, + ].filter((s) => s.value !== null) as Array<{ + value: number; + label: string; + color: string; + }>; + return ( -
- {/* ── Top Bar ── */} - +
+ {/* ── Top bar ── */} +
) : ( - {hotelName} +
+ +
)} {hotelName}
- {/* ── Hero ── */} - -
+ {/* ── Cinematic hero ── */} + +
-
- -