feat(site): structured landing sections with eyebrow headings
Give the home page a clear, professional information hierarchy: - Add eyebrow labels + headings for Features, Live stats and Community sections using reusable, theme-aware .eyebrow / .section-title styles. - Loosen the vertical rhythm (gap-8/10) so each block breathes. - New messages resolve via the existing English fallback for all locales.
This commit is contained in:
1 parent
3265cf1fad
commit
bf5b9918d9
3 files changed
+151
-83
No files matched your search
+116
-82
@@ -139,7 +139,7 @@ export default async function Home() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-6xl flex flex-col gap-6 px-1 sm:px-0 md:gap-8 pb-12 md:pb-16">
|
<div className="mx-auto w-full max-w-6xl flex flex-col gap-8 px-1 sm:px-0 md:gap-10 pb-12 md:pb-16">
|
||||||
{/* ── Top Bar ── */}
|
{/* ── Top Bar ── */}
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div
|
<div
|
||||||
@@ -327,98 +327,132 @@ export default async function Home() {
|
|||||||
|
|
||||||
{/* ── Features ── */}
|
{/* ── Features ── */}
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3 sm:gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
{features.map((f) => (
|
<div>
|
||||||
<SurfaceCard
|
<span className="eyebrow">{tp("sectionFeaturesLabel")}</span>
|
||||||
key={f.title}
|
<h2 className="section-title mt-2 text-xl sm:text-2xl">
|
||||||
className="card-glow relative p-4 sm:p-5 text-center hover:-translate-y-1"
|
{tp("sectionFeaturesTitle")}
|
||||||
>
|
</h2>
|
||||||
<div
|
</div>
|
||||||
className="mx-auto mb-3 flex h-11 w-11 sm:h-12 sm:w-12 items-center justify-center rounded-xl"
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3 sm:gap-4">
|
||||||
style={{
|
{features.map((f) => (
|
||||||
background:
|
<SurfaceCard
|
||||||
"color-mix(in srgb, var(--color-primary) 14%, transparent)",
|
key={f.title}
|
||||||
boxShadow:
|
className="card-glow relative p-4 sm:p-5 text-center hover:-translate-y-1"
|
||||||
"inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 10%, transparent)",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Image src={f.icon} alt="" width={24} height={24} unoptimized />
|
<div
|
||||||
</div>
|
className="mx-auto mb-3 flex h-11 w-11 sm:h-12 sm:w-12 items-center justify-center rounded-xl"
|
||||||
<h3
|
style={{
|
||||||
className="text-sm sm:text-base font-extrabold mb-1"
|
background:
|
||||||
style={{
|
"color-mix(in srgb, var(--color-primary) 14%, transparent)",
|
||||||
color: "var(--color-text-readable)",
|
boxShadow:
|
||||||
fontFamily: "var(--font-nunito)",
|
"inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 10%, transparent)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{f.title}
|
<Image
|
||||||
</h3>
|
src={f.icon}
|
||||||
<p
|
alt=""
|
||||||
className="text-xs sm:text-sm leading-relaxed"
|
width={24}
|
||||||
style={{ color: "var(--color-text-muted)" }}
|
height={24}
|
||||||
>
|
unoptimized
|
||||||
{f.desc}
|
/>
|
||||||
</p>
|
</div>
|
||||||
</SurfaceCard>
|
<h3
|
||||||
))}
|
className="text-sm sm:text-base font-extrabold mb-1"
|
||||||
|
style={{
|
||||||
|
color: "var(--color-text-readable)",
|
||||||
|
fontFamily: "var(--font-nunito)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{f.title}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
className="text-xs sm:text-sm leading-relaxed"
|
||||||
|
style={{ color: "var(--color-text-muted)" }}
|
||||||
|
>
|
||||||
|
{f.desc}
|
||||||
|
</p>
|
||||||
|
</SurfaceCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
{/* ── Stats + Login ── */}
|
{/* ── Stats + Login ── */}
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div className="grid grid-cols-2 gap-3 sm:gap-4 md:grid-cols-4">
|
<div className="flex flex-col gap-4">
|
||||||
{[
|
<div>
|
||||||
{
|
<span className="eyebrow">{tp("sectionStatsLabel")}</span>
|
||||||
value: users,
|
<h2 className="section-title mt-2 text-xl sm:text-2xl">
|
||||||
label: tp("statsCitizens"),
|
{tp("sectionStatsTitle")}
|
||||||
icon: "/assets/images/icons/friends.png",
|
</h2>
|
||||||
live: false,
|
</div>
|
||||||
},
|
<div className="grid grid-cols-2 gap-3 sm:gap-4 md:grid-cols-4">
|
||||||
{
|
{[
|
||||||
value: rooms,
|
{
|
||||||
label: tp("statsRooms"),
|
value: users,
|
||||||
icon: "/assets/images/icons/catalog.png",
|
label: tp("statsCitizens"),
|
||||||
live: false,
|
icon: "/assets/images/icons/friends.png",
|
||||||
},
|
live: false,
|
||||||
{
|
},
|
||||||
value: online,
|
{
|
||||||
label: tp("statsOnline"),
|
value: rooms,
|
||||||
icon: "/assets/images/icons/navigation/me.png",
|
label: tp("statsRooms"),
|
||||||
live: true,
|
icon: "/assets/images/icons/catalog.png",
|
||||||
},
|
live: false,
|
||||||
{
|
},
|
||||||
value: articles?.length ?? null,
|
{
|
||||||
label: tp("statsArticles"),
|
value: online,
|
||||||
icon: "/assets/images/icons/article.gif",
|
label: tp("statsOnline"),
|
||||||
live: false,
|
icon: "/assets/images/icons/navigation/me.png",
|
||||||
},
|
live: true,
|
||||||
].map((s) => (
|
},
|
||||||
<SurfaceCard
|
{
|
||||||
key={s.label}
|
value: articles?.length ?? null,
|
||||||
className="card-glow relative p-3 sm:p-5 text-center hover:-translate-y-1"
|
label: tp("statsArticles"),
|
||||||
>
|
icon: "/assets/images/icons/article.gif",
|
||||||
<div className="mb-0.5 text-2xl sm:text-3xl font-black tracking-tight md:text-4xl">
|
live: false,
|
||||||
{s.value === null ? (
|
},
|
||||||
<span className="text-base">{te("unavailable")}</span>
|
].map((s) => (
|
||||||
) : s.live ? (
|
<SurfaceCard
|
||||||
<LiveOnlineCounter initial={s.value} />
|
key={s.label}
|
||||||
) : (
|
className="card-glow relative p-3 sm:p-5 text-center hover:-translate-y-1"
|
||||||
<AnimatedCounter value={s.value} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-[10px] sm:text-xs font-bold uppercase tracking-widest flex items-center justify-center gap-1 sm:gap-1.5"
|
|
||||||
style={{ color: "var(--color-text-muted)" }}
|
|
||||||
>
|
>
|
||||||
<Image src={s.icon} alt="" width={14} height={14} unoptimized />
|
<div className="mb-0.5 text-2xl sm:text-3xl font-black tracking-tight md:text-4xl">
|
||||||
{s.label}
|
{s.value === null ? (
|
||||||
</div>
|
<span className="text-base">{te("unavailable")}</span>
|
||||||
</SurfaceCard>
|
) : s.live ? (
|
||||||
))}
|
<LiveOnlineCounter initial={s.value} />
|
||||||
|
) : (
|
||||||
|
<AnimatedCounter value={s.value} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="text-[10px] sm:text-xs font-bold uppercase tracking-widest flex items-center justify-center gap-1 sm:gap-1.5"
|
||||||
|
style={{ color: "var(--color-text-muted)" }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={s.icon}
|
||||||
|
alt=""
|
||||||
|
width={14}
|
||||||
|
height={14}
|
||||||
|
unoptimized
|
||||||
|
/>
|
||||||
|
{s.label}
|
||||||
|
</div>
|
||||||
|
</SurfaceCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
{/* ── Login + Online users ── */}
|
{/* ── Login + Online users ── */}
|
||||||
|
<div>
|
||||||
|
<span className="eyebrow">{tp("sectionCommunityLabel")}</span>
|
||||||
|
<h2 className="section-title mt-2 text-xl sm:text-2xl">
|
||||||
|
{tp("sectionCommunityTitle")}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
<div className="flex flex-col gap-4 md:flex-row">
|
<div className="flex flex-col gap-4 md:flex-row">
|
||||||
<Reveal className="flex w-full flex-col gap-4 md:w-1/3 md:flex-shrink-0">
|
<Reveal className="flex w-full flex-col gap-4 md:w-1/3 md:flex-shrink-0">
|
||||||
<SurfaceCard
|
<SurfaceCard
|
||||||
|
|||||||
@@ -2055,3 +2055,31 @@ details[open] > summary .details-open\:rotate-180 {
|
|||||||
background-clip: text;
|
background-clip: text;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Section eyebrow label with a small accent tick. */
|
||||||
|
.eyebrow {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.18em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--color-primary-readable, var(--color-primary));
|
||||||
|
}
|
||||||
|
.eyebrow::before {
|
||||||
|
content: "";
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 2px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: currentColor;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section heading on the public landing pages. */
|
||||||
|
.section-title {
|
||||||
|
color: var(--color-text-readable);
|
||||||
|
font-family: var(--font-nunito);
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
@@ -282,7 +282,13 @@
|
|||||||
"featuresCommunity": "Community",
|
"featuresCommunity": "Community",
|
||||||
"featuresCommunityDesc": "Make friends and chat",
|
"featuresCommunityDesc": "Make friends and chat",
|
||||||
"featuresGames": "Games",
|
"featuresGames": "Games",
|
||||||
"featuresGamesDesc": "Compete and have fun"
|
"featuresGamesDesc": "Compete and have fun",
|
||||||
|
"sectionFeaturesLabel": "Features",
|
||||||
|
"sectionFeaturesTitle": "Everything a great hotel needs",
|
||||||
|
"sectionStatsLabel": "Live stats",
|
||||||
|
"sectionStatsTitle": "A community that keeps growing",
|
||||||
|
"sectionCommunityLabel": "Community",
|
||||||
|
"sectionCommunityTitle": "Make yourself at home"
|
||||||
},
|
},
|
||||||
"news": {
|
"news": {
|
||||||
"title": "News",
|
"title": "News",
|
||||||
|
|||||||
Reference in new issue
Block a user