feat(site): professional card system and tidy landing layout
Refine the public UI for a cleaner, more professional and scannable landing experience without leaving the classic Habbo style: - SurfaceCard: softer layered shadow, gradient accent hairline on the top edge and a bolder header title across all public cards. - Home: gradient hotel-name in the hero headline, shine effect on the primary CTA, hairline on the top bar. - Login/register: consistent avatar tiles with rounded corners, subtle borders and a gentle hover lift; uniform username sizing. - Add reusable theme-aware .card-hairline and .gradient-text utilities.
This commit is contained in:
1 parent
d755ab7ce1
commit
29b9a4b0dc
5 files changed
+73
-22
No files matched your search
@@ -122,24 +122,26 @@ export default async function LoginPage() {
|
|||||||
bodyClassName="p-4"
|
bodyClassName="p-4"
|
||||||
className="card-glow"
|
className="card-glow"
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-4 gap-1.5">
|
<div className="grid grid-cols-4 gap-1.5 sm:gap-2">
|
||||||
{recentUsers.map((u) => (
|
{recentUsers.map((u) => (
|
||||||
<div
|
<div
|
||||||
key={u.username}
|
key={u.username}
|
||||||
className="flex flex-col items-center gap-0.5 p-1.5 rounded-lg"
|
className="flex flex-col items-center gap-1.5 rounded-xl border px-1 py-2 transition-all duration-200 hover:-translate-y-0.5"
|
||||||
style={{
|
style={{
|
||||||
background:
|
background:
|
||||||
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
||||||
|
borderColor:
|
||||||
|
"color-mix(in srgb, var(--color-primary) 10%, transparent)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<UserAvatarThumbnail
|
<UserAvatarThumbnail
|
||||||
figure={u.look}
|
figure={u.look}
|
||||||
alt=""
|
alt=""
|
||||||
options={{ direction: 2 }}
|
options={{ direction: 2 }}
|
||||||
className="rounded-md"
|
className="rounded-lg"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="text-[8px] font-bold truncate w-full text-center leading-tight"
|
className="w-full truncate text-center text-[9px] font-bold leading-tight"
|
||||||
style={{ color: "var(--color-text-readable)" }}
|
style={{ color: "var(--color-text-readable)" }}
|
||||||
>
|
>
|
||||||
{u.username}
|
{u.username}
|
||||||
@@ -157,24 +159,26 @@ export default async function LoginPage() {
|
|||||||
bodyClassName="p-4"
|
bodyClassName="p-4"
|
||||||
className="card-glow"
|
className="card-glow"
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-4 gap-1.5">
|
<div className="grid grid-cols-4 gap-1.5 sm:gap-2">
|
||||||
{latestUsers.map((u) => (
|
{latestUsers.map((u) => (
|
||||||
<div
|
<div
|
||||||
key={u.username}
|
key={u.username}
|
||||||
className="flex flex-col items-center gap-0.5 p-1.5 rounded-lg"
|
className="flex flex-col items-center gap-1.5 rounded-xl border px-1 py-2 transition-all duration-200 hover:-translate-y-0.5"
|
||||||
style={{
|
style={{
|
||||||
background:
|
background:
|
||||||
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
||||||
|
borderColor:
|
||||||
|
"color-mix(in srgb, var(--color-primary) 10%, transparent)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<UserAvatarThumbnail
|
<UserAvatarThumbnail
|
||||||
figure={u.look}
|
figure={u.look}
|
||||||
alt=""
|
alt=""
|
||||||
options={{ direction: 2 }}
|
options={{ direction: 2 }}
|
||||||
className="rounded-md"
|
className="rounded-lg"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="text-[8px] font-bold truncate w-full text-center leading-tight"
|
className="w-full truncate text-center text-[9px] font-bold leading-tight"
|
||||||
style={{ color: "var(--color-text-readable)" }}
|
style={{ color: "var(--color-text-readable)" }}
|
||||||
>
|
>
|
||||||
{u.username}
|
{u.username}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export default async function Home() {
|
|||||||
{/* ── Top Bar ── */}
|
{/* ── Top Bar ── */}
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div
|
<div
|
||||||
className="relative flex items-center justify-between rounded-xl border px-3 py-2.5 sm:px-5 sm:py-3"
|
className="relative flex items-center justify-between rounded-xl border px-3 py-2.5 sm:px-5 sm:py-3 card-hairline"
|
||||||
style={{
|
style={{
|
||||||
background:
|
background:
|
||||||
"color-mix(in srgb, var(--color-surface) 60%, transparent)",
|
"color-mix(in srgb, var(--color-surface) 60%, transparent)",
|
||||||
@@ -269,11 +269,15 @@ export default async function Home() {
|
|||||||
<h1
|
<h1
|
||||||
className="text-2xl font-black leading-[1.05] tracking-tight mb-2 sm:text-3xl md:text-5xl lg:text-6xl"
|
className="text-2xl font-black leading-[1.05] tracking-tight mb-2 sm:text-3xl md:text-5xl lg:text-6xl"
|
||||||
style={{
|
style={{
|
||||||
color: "var(--color-text-readable)",
|
|
||||||
fontFamily: "var(--font-nunito)",
|
fontFamily: "var(--font-nunito)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TypewriterText text={tp("welcome", { hotelName })} />
|
<span style={{ color: "var(--color-text-readable)" }}>
|
||||||
|
{tp("welcome", { hotelName: "" })}
|
||||||
|
</span>{" "}
|
||||||
|
<span className="gradient-text">
|
||||||
|
<TypewriterText text={hotelName} />
|
||||||
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p
|
<p
|
||||||
className="text-sm leading-relaxed max-w-2xl mb-5 sm:text-base md:text-lg md:mb-8"
|
className="text-sm leading-relaxed max-w-2xl mb-5 sm:text-base md:text-lg md:mb-8"
|
||||||
@@ -284,7 +288,7 @@ export default async function Home() {
|
|||||||
<div className="flex flex-wrap gap-2.5 sm:gap-3 justify-center">
|
<div className="flex flex-wrap gap-2.5 sm:gap-3 justify-center">
|
||||||
<Link
|
<Link
|
||||||
href="/register"
|
href="/register"
|
||||||
className="inline-flex items-center gap-2 sm:gap-2.5 font-extrabold text-xs sm:text-sm px-5 sm:px-8 py-3 sm:py-4 rounded-xl transition-all duration-200 hover:scale-[1.03] active:scale-95 shadow-lg"
|
className="btn-shine inline-flex items-center gap-2 sm:gap-2.5 font-extrabold text-xs sm:text-sm px-5 sm:px-8 py-3 sm:py-4 rounded-xl transition-all duration-200 hover:scale-[1.03] active:scale-95 shadow-lg"
|
||||||
style={{
|
style={{
|
||||||
background: "var(--color-primary)",
|
background: "var(--color-primary)",
|
||||||
color: "var(--color-primary-foreground)",
|
color: "var(--color-primary-foreground)",
|
||||||
|
|||||||
@@ -135,20 +135,22 @@ export default async function RegisterPage() {
|
|||||||
{recentUsers.map((u) => (
|
{recentUsers.map((u) => (
|
||||||
<div
|
<div
|
||||||
key={u.username}
|
key={u.username}
|
||||||
className="flex flex-col items-center gap-0.5 p-1.5 rounded-lg"
|
className="flex flex-col items-center gap-1.5 rounded-xl border px-1 py-2 transition-all duration-200 hover:-translate-y-0.5"
|
||||||
style={{
|
style={{
|
||||||
background:
|
background:
|
||||||
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
||||||
|
borderColor:
|
||||||
|
"color-mix(in srgb, var(--color-primary) 10%, transparent)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<UserAvatarThumbnail
|
<UserAvatarThumbnail
|
||||||
figure={u.look}
|
figure={u.look}
|
||||||
alt=""
|
alt=""
|
||||||
options={{ direction: 2 }}
|
options={{ direction: 2 }}
|
||||||
className="rounded-md"
|
className="rounded-lg"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="text-[8px] font-bold truncate w-full text-center leading-tight"
|
className="w-full truncate text-center text-[9px] font-bold leading-tight"
|
||||||
style={{ color: "var(--color-text-readable)" }}
|
style={{ color: "var(--color-text-readable)" }}
|
||||||
>
|
>
|
||||||
{u.username}
|
{u.username}
|
||||||
@@ -170,20 +172,22 @@ export default async function RegisterPage() {
|
|||||||
{latestUsers.map((u) => (
|
{latestUsers.map((u) => (
|
||||||
<div
|
<div
|
||||||
key={u.username}
|
key={u.username}
|
||||||
className="flex flex-col items-center gap-0.5 p-1.5 rounded-lg"
|
className="flex flex-col items-center gap-1.5 rounded-xl border px-1 py-2 transition-all duration-200 hover:-translate-y-0.5"
|
||||||
style={{
|
style={{
|
||||||
background:
|
background:
|
||||||
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
"color-mix(in srgb, var(--color-primary) 4%, transparent)",
|
||||||
|
borderColor:
|
||||||
|
"color-mix(in srgb, var(--color-primary) 10%, transparent)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<UserAvatarThumbnail
|
<UserAvatarThumbnail
|
||||||
figure={u.look}
|
figure={u.look}
|
||||||
alt=""
|
alt=""
|
||||||
options={{ direction: 2 }}
|
options={{ direction: 2 }}
|
||||||
className="rounded-md"
|
className="rounded-lg"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="text-[10px] font-bold truncate w-full text-center leading-tight"
|
className="w-full truncate text-center text-[9px] font-bold leading-tight"
|
||||||
style={{ color: "var(--color-text-readable)" }}
|
style={{ color: "var(--color-text-readable)" }}
|
||||||
>
|
>
|
||||||
{u.username}
|
{u.username}
|
||||||
|
|||||||
@@ -2018,3 +2018,40 @@ details[open] > summary .details-open\:rotate-180 {
|
|||||||
0 12px 32px -10px color-mix(in srgb, var(--color-primary) 32%, transparent),
|
0 12px 32px -10px color-mix(in srgb, var(--color-primary) 32%, transparent),
|
||||||
0 0 0 1px color-mix(in srgb, var(--color-primary) 22%, transparent);
|
0 0 0 1px color-mix(in srgb, var(--color-primary) 22%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Gradient accent hairline drawn on the top edge of a relative card. */
|
||||||
|
.card-hairline {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.card-hairline::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset-inline: 2%;
|
||||||
|
top: 0;
|
||||||
|
height: 2px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
color-mix(in srgb, var(--color-primary) 75%, transparent) 30%,
|
||||||
|
var(--color-primary) 50%,
|
||||||
|
color-mix(in srgb, var(--color-accent) 70%, transparent) 70%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
opacity: 0.55;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Brand gradient text (primary → accent). */
|
||||||
|
.gradient-text {
|
||||||
|
background: linear-gradient(
|
||||||
|
115deg,
|
||||||
|
var(--color-primary) 10%,
|
||||||
|
color-mix(in srgb, var(--color-primary) 55%, var(--color-accent)) 48%,
|
||||||
|
color-mix(in srgb, var(--color-accent) 92%, var(--color-primary)) 92%
|
||||||
|
);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
@@ -43,13 +43,15 @@ export function SurfaceCard({
|
|||||||
}: SurfaceCardProps) {
|
}: SurfaceCardProps) {
|
||||||
const hasHeader = Boolean(title || icon || (actionHref && actionLabel));
|
const hasHeader = Boolean(title || icon || (actionHref && actionLabel));
|
||||||
|
|
||||||
|
const CARD_SHADOW =
|
||||||
|
"0 1px 2px rgba(0,0,0,0.05), 0 8px 24px -10px color-mix(in srgb, var(--color-text-muted) 22%, transparent), 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 6%, transparent)";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`surface-card overflow-hidden rounded-2xl border bg-[var(--color-surface)] ${className}`}
|
className={`surface-card card-hairline overflow-hidden rounded-2xl border bg-[var(--color-surface)] ${className}`}
|
||||||
style={{
|
style={{
|
||||||
borderColor: CARD_BORDER,
|
borderColor: CARD_BORDER,
|
||||||
boxShadow:
|
boxShadow: CARD_SHADOW,
|
||||||
"0 1px 2px rgba(0,0,0,0.04), 0 2px 8px rgba(0,0,0,0.03), 0 0 0 0.5px color-mix(in srgb, var(--color-text-muted) 6%, transparent)",
|
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -81,7 +83,7 @@ export function SurfaceCard({
|
|||||||
)}
|
)}
|
||||||
{title && (
|
{title && (
|
||||||
<h2
|
<h2
|
||||||
className="text-sm font-bold tracking-tight"
|
className="text-sm font-extrabold tracking-wide"
|
||||||
style={{
|
style={{
|
||||||
fontFamily: "var(--font-nunito)",
|
fontFamily: "var(--font-nunito)",
|
||||||
color: "var(--color-text-readable)",
|
color: "var(--color-text-readable)",
|
||||||
|
|||||||
Reference in new issue
Block a user