feat(site): redesign home, login and register with premium dark gaming theme
Replaced the classic Habbo landing style on the home, login and register pages with a modern premium dark-gaming look: always-dark hero canvas with brand glows, grid overlay and ambient orbs, glass panels, gradient text and floating art. Adds shared LandingTopBar, AuthShell and BrandFrank components plus reusable premium CSS utilities. Build, typecheck and lint pass.
This commit is contained in:
1 parent
4d720ee03c
commit
741f01e897
8 files changed
+694
-657
No files matched your search
@@ -0,0 +1,47 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { AmbientOrbs } from "@/components/ambient-orbs";
|
||||
import { LandingTopBar } from "@/components/landing-top-bar";
|
||||
|
||||
/**
|
||||
* Premium dark-gaming shell shared by the login and register pages.
|
||||
* Renders an always-dark hero canvas (brand glows + grid overlay) with a
|
||||
* hotel header on top, a brand/side column on the left and the auth form
|
||||
* (rendered by the page) on the right in a frosted glass panel.
|
||||
*/
|
||||
export function AuthShell({
|
||||
hotelName,
|
||||
logo,
|
||||
side,
|
||||
footer,
|
||||
children,
|
||||
}: {
|
||||
hotelName: string;
|
||||
logo?: string | null;
|
||||
side: ReactNode;
|
||||
footer?: ReactNode;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<section className="landing-hero w-full overflow-hidden rounded-2xl border border-white/10 sm:rounded-3xl">
|
||||
{/* Ambient glows */}
|
||||
<AmbientOrbs />
|
||||
|
||||
{/* Header */}
|
||||
<LandingTopBar hotelName={hotelName} logo={logo} />
|
||||
|
||||
{/* Body */}
|
||||
<div className="relative z-10 grid gap-8 px-4 pb-8 pt-6 sm:px-7 sm:pb-10 sm:pt-8 lg:grid-cols-[1fr_1.05fr] lg:gap-12">
|
||||
<div className="flex flex-col">{side}</div>
|
||||
<div className="glass-panel relative h-fit w-full rounded-2xl p-5 sm:p-7 lg:sticky lg:top-6">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{footer ? (
|
||||
<div className="relative z-10 border-t border-white/10 px-4 py-4 text-center sm:px-7">
|
||||
{footer}
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import Image from "next/image";
|
||||
|
||||
/**
|
||||
* Floating brand art for the premium auth pages: the welcome character
|
||||
* hovers over a pulsing primary halo with a faint slow-orbiting ring.
|
||||
*/
|
||||
export function BrandFrank({ size = 150 }: { size?: number }) {
|
||||
return (
|
||||
<div className="relative flex items-center justify-center">
|
||||
<style>{`@keyframes spin-slow { to { transform: rotate(360deg); } }`}</style>
|
||||
<span className="hero-halo h-40 w-40 sm:h-48 sm:w-48" />
|
||||
<span
|
||||
className="absolute h-52 w-52 rounded-full border border-dashed sm:h-64 sm:w-64"
|
||||
style={{
|
||||
borderColor: "color-mix(in srgb, #ffffff 16%, transparent)",
|
||||
animation: "spin-slow 28s linear infinite",
|
||||
}}
|
||||
/>
|
||||
<div className="animate-float relative z-10 drop-shadow-[0_20px_30px_rgba(0,0,0,0.45)]">
|
||||
<Image
|
||||
src="/assets/images/FrankwithBag.gif"
|
||||
alt=""
|
||||
width={size}
|
||||
height={Math.round(size * 1.29)}
|
||||
className="object-contain"
|
||||
unoptimized
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -113,52 +113,30 @@ export function RegisterForm({
|
||||
/>
|
||||
) : null}
|
||||
{/* Header Banner */}
|
||||
<div
|
||||
className="relative overflow-hidden bg-center bg-cover rounded-t-xl"
|
||||
style={{
|
||||
backgroundImage: "url(/assets/images/mybobba_banner.png)",
|
||||
height: "160px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="absolute inset-0 z-10"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(180deg, rgba(0,0,0,0.05) 0%, rgba(0,0,0,0.55) 100%)",
|
||||
}}
|
||||
/>
|
||||
<div className="relative flex items-center justify-center w-full h-full z-20">
|
||||
<div
|
||||
className="relative animate-float"
|
||||
style={{ width: "140px", height: "140px" }}
|
||||
<div className="mb-7 flex items-center gap-4">
|
||||
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl border border-white/10 bg-white/5">
|
||||
<Image
|
||||
src="/assets/images/icons/navigation/me.png"
|
||||
alt=""
|
||||
width={22}
|
||||
height={22}
|
||||
unoptimized
|
||||
className="opacity-90"
|
||||
/>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p
|
||||
className="text-[11px] font-extrabold uppercase tracking-widest"
|
||||
style={{ color: "var(--color-primary)" }}
|
||||
>
|
||||
<div
|
||||
className="absolute inset-0 rounded-full overflow-hidden"
|
||||
style={{ zIndex: -1 }}
|
||||
>
|
||||
<div
|
||||
className="w-full h-full"
|
||||
style={{
|
||||
background: "black",
|
||||
filter: "blur(8px)",
|
||||
transform: "scale(1.2)",
|
||||
opacity: 0.6,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Image
|
||||
src="/assets/images/FrankwithBag.gif"
|
||||
alt=""
|
||||
fill
|
||||
className="!static"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
objectPosition: "center",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{t("accountDetails")}
|
||||
</p>
|
||||
<h2 className="m-0 text-2xl font-black tracking-tight text-white">
|
||||
{t("title")}
|
||||
</h2>
|
||||
<p className="mt-0.5 truncate text-sm text-white/55">
|
||||
{t("subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -171,12 +149,7 @@ export function RegisterForm({
|
||||
};
|
||||
formAction(fd);
|
||||
}}
|
||||
className="p-6 flex flex-col gap-6"
|
||||
style={{
|
||||
backgroundColor:
|
||||
"color-mix(in srgb, var(--color-background) 50%, var(--color-surface))",
|
||||
borderRadius: "0 0 12px 12px",
|
||||
}}
|
||||
className="flex flex-col gap-6"
|
||||
>
|
||||
{(error || state.error) && (
|
||||
<div
|
||||
@@ -383,8 +356,7 @@ export function RegisterForm({
|
||||
termsError ? "animate-shake" : ""
|
||||
}`}
|
||||
style={{
|
||||
backgroundColor:
|
||||
"color-mix(in srgb, var(--color-background) 50%, var(--color-surface))",
|
||||
backgroundColor: "var(--color-background)",
|
||||
border: `1px solid ${
|
||||
termsError
|
||||
? "var(--color-danger)"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import Image from "next/image";
|
||||
import { Clock } from "@/components/clock";
|
||||
import { LanguageSwitcher } from "@/components/language-switcher";
|
||||
import { ThemeSwitcher } from "@/components/theme-switcher";
|
||||
|
||||
/**
|
||||
* Frosted top bar shared by the home hero and the premium auth pages.
|
||||
* Dark-styled to sit on the "always-dark" landing canvas.
|
||||
*/
|
||||
export function LandingTopBar({
|
||||
hotelName,
|
||||
logo,
|
||||
}: {
|
||||
hotelName: string;
|
||||
logo?: string | null;
|
||||
}) {
|
||||
return (
|
||||
<div className="relative z-10 flex items-center justify-between gap-3 border-b border-white/10 px-4 py-3 sm:px-7 sm:py-4">
|
||||
<div className="flex min-w-0 items-center gap-2.5 sm:gap-3">
|
||||
{logo ? (
|
||||
<Image
|
||||
src={logo}
|
||||
alt={hotelName}
|
||||
width={110}
|
||||
height={30}
|
||||
className="shrink-0 object-contain"
|
||||
unoptimized
|
||||
style={{ maxHeight: 30, width: "auto", height: "auto" }}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src="/assets/images/icons/lighthouse.png"
|
||||
alt={hotelName}
|
||||
width={30}
|
||||
height={30}
|
||||
className="shrink-0"
|
||||
unoptimized
|
||||
/>
|
||||
)}
|
||||
<span className="hidden truncate text-sm font-extrabold uppercase tracking-widest text-white/85 sm:inline">
|
||||
{hotelName}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1 rounded-xl border border-white/10 bg-white/5 px-1.5 py-1 sm:px-2">
|
||||
<LanguageSwitcher />
|
||||
<div className="hidden h-5 w-px bg-white/15 sm:block" />
|
||||
<Clock />
|
||||
<div className="h-5 w-px bg-white/15" />
|
||||
<ThemeSwitcher />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user