feat(home): two-column hero with live status panel, explore nav, featured news
This commit is contained in:
1 parent
d0db352f36
commit
469f69ddd7
4 files changed
+291
-90
No files matched your search
+284
-89
@@ -34,7 +34,6 @@ 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 { LiveOnlineCount } from "@/components/live-online-count";
|
||||
import { LiveOnlineCounter } from "@/components/live-online-counter";
|
||||
import { Reveal } from "@/components/motion-reveal";
|
||||
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
|
||||
@@ -56,8 +55,15 @@ async function getHotelData() {
|
||||
siteSettings.get("cms_logo", ""),
|
||||
]);
|
||||
|
||||
const [online, users, rooms, articles, recentUsers, recentPhotos] =
|
||||
await Promise.all([
|
||||
const [
|
||||
online,
|
||||
users,
|
||||
rooms,
|
||||
totalPhotos,
|
||||
articles,
|
||||
recentUsers,
|
||||
recentPhotos,
|
||||
] = await Promise.all([
|
||||
cached("online_count", 10_000, () =>
|
||||
db
|
||||
.select({ total: count() })
|
||||
@@ -77,6 +83,12 @@ async function getHotelData() {
|
||||
.from(Rooms)
|
||||
.then((rows) => rows[0]?.total ?? 0),
|
||||
).catch(publicReadFailure("home.rooms")),
|
||||
cached("total_photos", 300_000, () =>
|
||||
db
|
||||
.select({ total: count() })
|
||||
.from(CameraWeb)
|
||||
.then((rows) => rows[0]?.total ?? 0),
|
||||
).catch(publicReadFailure("home.photos-count")),
|
||||
getNewsList(4, { throwOnError: true }).catch(
|
||||
publicReadFailure("home.news"),
|
||||
),
|
||||
@@ -101,6 +113,7 @@ async function getHotelData() {
|
||||
online,
|
||||
users,
|
||||
rooms,
|
||||
totalPhotos,
|
||||
articles,
|
||||
recentUsers,
|
||||
recentPhotos,
|
||||
@@ -115,11 +128,13 @@ export default async function Home() {
|
||||
const tp = await getTranslations("pages.home");
|
||||
const te = await getTranslations("publicData");
|
||||
const th = await getTranslations("header");
|
||||
const tn = await getTranslations("nav");
|
||||
const {
|
||||
hotelName,
|
||||
online,
|
||||
users,
|
||||
rooms,
|
||||
totalPhotos,
|
||||
articles,
|
||||
recentUsers,
|
||||
recentPhotos,
|
||||
@@ -147,6 +162,72 @@ export default async function Home() {
|
||||
},
|
||||
];
|
||||
|
||||
type NewsArticle = NonNullable<typeof articles>[number];
|
||||
|
||||
const renderArticleCard = (a: NewsArticle, featured = false) => (
|
||||
<Link
|
||||
key={a.slug}
|
||||
href={`/news/${a.slug}`}
|
||||
className="group relative w-full overflow-hidden rounded-xl transition-all duration-500 hover:-translate-y-1 hover:shadow-xl"
|
||||
style={{
|
||||
height: featured
|
||||
? "clamp(220px, 26vw, 280px)"
|
||||
: "clamp(170px, 18vw, 210px)",
|
||||
backgroundColor: "var(--color-background)",
|
||||
border:
|
||||
"1px solid color-mix(in srgb, var(--color-text-muted) 12%, transparent)",
|
||||
}}
|
||||
>
|
||||
<div className="relative h-full w-full overflow-hidden rounded-xl">
|
||||
<Image
|
||||
src={a.image}
|
||||
alt={a.title}
|
||||
fill
|
||||
sizes={featured ? "100vw" : "(max-width: 640px) 100vw, 33vw"}
|
||||
className="rounded-xl object-cover transition-transform duration-700 ease-out group-hover:scale-108"
|
||||
/>
|
||||
<div className="absolute right-2.5 top-2.5 flex h-8 w-8 translate-x-1 items-center justify-center rounded-full bg-foreground/50 opacity-0 backdrop-blur-sm transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100">
|
||||
<span className="text-sm font-bold text-primary-foreground">→</span>
|
||||
</div>
|
||||
<div
|
||||
className="absolute left-2.5 top-2.5 rounded-full px-2 py-0.5 text-[10px] font-bold backdrop-blur-sm"
|
||||
style={{
|
||||
background: "color-mix(in srgb, #000 45%, transparent)",
|
||||
color: "#fff",
|
||||
}}
|
||||
>
|
||||
{formatDate(a.createdAt, "date", "")}
|
||||
</div>
|
||||
<div
|
||||
className="absolute bottom-0 left-0 w-full p-3 sm:p-4"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.4) 50%, transparent 100%)",
|
||||
}}
|
||||
>
|
||||
{featured && (
|
||||
<p className="mb-1 text-[10px] font-bold uppercase tracking-widest opacity-90">
|
||||
{tp("latestArticle")}
|
||||
</p>
|
||||
)}
|
||||
<h3
|
||||
className={`line-clamp-2 font-bold text-primary-foreground text-shadow-sm ${
|
||||
featured ? "text-base sm:text-2xl" : "text-sm sm:text-base"
|
||||
}`}
|
||||
>
|
||||
{a.title}
|
||||
</h3>
|
||||
<p
|
||||
className="mt-0.5 text-[10px] sm:text-[11px] font-semibold opacity-80"
|
||||
style={{ color: "var(--color-text-muted)" }}
|
||||
>
|
||||
{formatDate(a.createdAt, "date", "")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
||||
return (
|
||||
<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 ── */}
|
||||
@@ -247,6 +328,13 @@ export default async function Home() {
|
||||
"linear-gradient(135deg, color-mix(in srgb, var(--color-surface) 92%, transparent) 0%, color-mix(in srgb, var(--color-surface) 45%, transparent) 50%, color-mix(in srgb, var(--color-surface) 12%, transparent) 100%)",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(to top, color-mix(in srgb, var(--color-surface) 40%, transparent) 0%, transparent 55%)",
|
||||
}}
|
||||
/>
|
||||
<AmbientOrbs />
|
||||
<div className="hero-ring" aria-hidden="true" style={{ zIndex: 3 }} />
|
||||
{/* Floating mascot — decorative, hidden on smaller screens. */}
|
||||
@@ -267,35 +355,16 @@ export default async function Home() {
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="relative flex flex-col items-center gap-5 px-4 py-12 text-center sm:gap-8 sm:px-6 sm:py-14 md:px-12 md:py-24"
|
||||
className="relative mx-auto grid w-full max-w-6xl grid-cols-1 items-center gap-8 px-4 py-12 text-center sm:px-6 sm:py-14 md:px-12 md:py-20 lg:grid-cols-[1.15fr_0.85fr] lg:gap-10 lg:text-left"
|
||||
style={{ zIndex: 2 }}
|
||||
>
|
||||
<div className="relative flex flex-col items-center gap-5 sm:gap-7 lg:items-start lg:text-left">
|
||||
<div
|
||||
className="brand-halo left-1/2 top-4 h-48 w-48 -translate-x-1/2 sm:top-6 sm:h-64 sm:w-64"
|
||||
className="brand-halo left-1/2 top-6 h-48 w-48 -translate-x-1/2 sm:h-64 sm:w-64 lg:left-0 lg:translate-x-0"
|
||||
style={{ zIndex: -1 }}
|
||||
/>
|
||||
<div
|
||||
className="inline-flex items-center gap-2 px-3 py-1 sm:px-4 sm:py-1.5 rounded-full text-[10px] sm:text-xs font-bold uppercase tracking-widest mb-1 border backdrop-blur-sm"
|
||||
style={{
|
||||
background:
|
||||
"color-mix(in srgb, var(--color-primary) 12%, transparent)",
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-primary) 20%, transparent)",
|
||||
color: "var(--color-primary-readable, var(--color-primary))",
|
||||
}}
|
||||
>
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" />
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-primary" />
|
||||
</span>
|
||||
{online === null ? (
|
||||
<span>{te("unavailable")}</span>
|
||||
) : (
|
||||
<LiveOnlineCount initial={online} hotelName={hotelName} />
|
||||
)}
|
||||
</div>
|
||||
<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 sm:text-3xl md:text-5xl lg:text-6xl"
|
||||
style={{
|
||||
fontFamily: "var(--font-nunito)",
|
||||
textShadow:
|
||||
@@ -310,12 +379,12 @@ export default async function Home() {
|
||||
</span>
|
||||
</h1>
|
||||
<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 sm:text-base md:text-lg"
|
||||
style={{ color: "var(--color-text-muted)" }}
|
||||
>
|
||||
{tp("welcomeBody")}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2.5 sm:gap-3 justify-center">
|
||||
<div className="flex flex-wrap justify-center gap-2.5 sm:gap-3 lg:justify-start">
|
||||
<Link
|
||||
href="/register"
|
||||
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-300 ease-out hover:scale-[1.03] active:scale-95 shadow-lg"
|
||||
@@ -350,6 +419,136 @@ export default async function Home() {
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Live status panel ── */}
|
||||
<div className="relative mx-auto w-full max-w-md lg:mx-0 lg:justify-self-end">
|
||||
<div
|
||||
className="card-glow card-hairline relative overflow-hidden rounded-2xl border p-5 text-left sm:p-6"
|
||||
style={{
|
||||
background:
|
||||
"color-mix(in srgb, var(--color-surface) 78%, transparent)",
|
||||
backdropFilter: "blur(12px)",
|
||||
WebkitBackdropFilter: "blur(12px)",
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-primary) 18%, transparent)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="brand-halo left-1/2 top-0 h-40 w-72 max-w-full -translate-x-1/2 -translate-y-1/2"
|
||||
/>
|
||||
<div className="relative flex flex-wrap items-center justify-between gap-2">
|
||||
<span
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-widest border"
|
||||
style={{
|
||||
background:
|
||||
"color-mix(in srgb, var(--color-primary) 12%, transparent)",
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-primary) 20%, transparent)",
|
||||
color:
|
||||
"var(--color-primary-readable, var(--color-primary))",
|
||||
}}
|
||||
>
|
||||
<span className="relative flex h-1.5 w-1.5">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75" />
|
||||
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-primary" />
|
||||
</span>
|
||||
{tp("onlineNow")}
|
||||
</span>
|
||||
<span
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-widest"
|
||||
style={{
|
||||
background:
|
||||
"color-mix(in srgb, var(--color-text-muted) 8%, transparent)",
|
||||
color: "var(--color-text-muted)",
|
||||
}}
|
||||
>
|
||||
{rooms === null ? (
|
||||
<span>{te("unavailable")}</span>
|
||||
) : (
|
||||
<AnimatedCounter value={rooms} />
|
||||
)}
|
||||
{tp("statsRooms")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="relative mt-4">
|
||||
<div className="gradient-text text-5xl font-black tracking-tight leading-none sm:text-6xl">
|
||||
{online === null ? (
|
||||
<span
|
||||
className="text-xl font-bold underline decoration-transparent"
|
||||
style={{
|
||||
color: "var(--color-text-muted)",
|
||||
}}
|
||||
>
|
||||
{te("unavailable")}
|
||||
</span>
|
||||
) : (
|
||||
<LiveOnlineCounter initial={online} />
|
||||
)}
|
||||
</div>
|
||||
<p
|
||||
className="mt-2 text-[11px] font-bold uppercase tracking-widest"
|
||||
style={{ color: "var(--color-text-muted)" }}
|
||||
>
|
||||
{hotelName}
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative mt-5">
|
||||
{recentUsers === null ? (
|
||||
<span
|
||||
className="text-xs"
|
||||
style={{ color: "var(--color-text-muted)" }}
|
||||
>
|
||||
{te("unavailable")}
|
||||
</span>
|
||||
) : recentUsers.length > 0 ? (
|
||||
<div className="flex -space-x-2">
|
||||
{recentUsers.slice(0, 6).map((u) => (
|
||||
<UserAvatarThumbnail
|
||||
key={u.username}
|
||||
figure={u.look}
|
||||
alt={u.username}
|
||||
options={{ direction: 2 }}
|
||||
className="h-9 w-9 rounded-full ring-2 ring-[color-mix(in_srgb,var(--color-surface)_90%,transparent)]"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<span
|
||||
className="text-xs"
|
||||
style={{ color: "var(--color-text-muted)" }}
|
||||
>
|
||||
{tp("noUsers")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="relative mt-5 flex items-center justify-between gap-3 border-t pt-4"
|
||||
style={{
|
||||
borderTopColor:
|
||||
"color-mix(in srgb, var(--color-primary) 14%, transparent)",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className="text-[10px] font-bold uppercase tracking-widest"
|
||||
style={{ color: "var(--color-text-muted)" }}
|
||||
>
|
||||
{tp("liveUpdates")}
|
||||
</span>
|
||||
<Link
|
||||
href="/community"
|
||||
className="inline-flex items-center gap-1 text-xs font-extrabold transition-transform duration-300 hover:translate-x-0.5"
|
||||
style={{
|
||||
color:
|
||||
"var(--color-primary-readable, var(--color-primary))",
|
||||
}}
|
||||
>
|
||||
{tp("allUsers")} →
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
@@ -469,10 +668,10 @@ export default async function Home() {
|
||||
live: false,
|
||||
},
|
||||
{
|
||||
value: online,
|
||||
label: tp("statsOnline"),
|
||||
icon: ICON_NAV_ME,
|
||||
live: true,
|
||||
value: totalPhotos,
|
||||
label: tp("statsPhotos"),
|
||||
icon: ICON_CAMERA,
|
||||
live: false,
|
||||
},
|
||||
{
|
||||
value: articles?.length ?? null,
|
||||
@@ -548,7 +747,49 @@ export default async function Home() {
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
{/* ── Quick explore ── */}
|
||||
<Reveal>
|
||||
<nav
|
||||
aria-label={tp("exploreLabel")}
|
||||
className="grid grid-cols-2 gap-2.5 sm:grid-cols-3 lg:grid-cols-6"
|
||||
>
|
||||
{[
|
||||
{ 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") },
|
||||
].map((l) => (
|
||||
<Link
|
||||
key={l.href}
|
||||
href={l.href}
|
||||
className="card-hairline group inline-flex items-center justify-center gap-1.5 rounded-xl border px-3 py-2.5 text-xs font-bold transition-all duration-300 hover:-translate-y-0.5 sm:text-sm"
|
||||
style={{
|
||||
background:
|
||||
"color-mix(in srgb, var(--color-surface) 55%, transparent)",
|
||||
borderColor:
|
||||
"color-mix(in srgb, var(--color-text-muted) 10%, transparent)",
|
||||
color: "var(--color-text-readable)",
|
||||
}}
|
||||
>
|
||||
{l.label}
|
||||
<span
|
||||
className="text-[10px] transition-transform duration-300 group-hover:translate-x-0.5"
|
||||
style={{
|
||||
color: "var(--color-primary-readable, var(--color-primary))",
|
||||
}}
|
||||
>
|
||||
→
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
</Reveal>
|
||||
|
||||
{/* ── Login + Online users ── */}
|
||||
<Reveal>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<span className="eyebrow">{tp("sectionCommunityLabel")}</span>
|
||||
<h2 className="section-title mt-2 text-xl sm:text-2xl">
|
||||
@@ -613,7 +854,10 @@ export default async function Home() {
|
||||
</Reveal>
|
||||
|
||||
{/* News */}
|
||||
<Reveal delay={0.15} className="flex w-full flex-col gap-4 md:w-2/3">
|
||||
<Reveal
|
||||
delay={0.15}
|
||||
className="flex w-full flex-col gap-4 md:w-2/3"
|
||||
>
|
||||
<SurfaceCard
|
||||
title={tp("latestNews")}
|
||||
icon={ICON_ARTICLE}
|
||||
@@ -623,62 +867,11 @@ export default async function Home() {
|
||||
{articles === null ? (
|
||||
<PublicLoadError href="/" />
|
||||
) : articles.length > 0 ? (
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-4">
|
||||
{articles.slice(0, 4).map((a) => (
|
||||
<Link
|
||||
key={a.slug}
|
||||
href={`/news/${a.slug}`}
|
||||
className="group relative w-full overflow-hidden rounded-xl transition-all duration-500 hover:-translate-y-1 hover:shadow-xl"
|
||||
style={{
|
||||
height: "clamp(180px, 22vw, 220px)",
|
||||
backgroundColor: "var(--color-background)",
|
||||
border:
|
||||
"1px solid color-mix(in srgb, var(--color-text-muted) 12%, transparent)",
|
||||
}}
|
||||
>
|
||||
<div className="relative h-full w-full overflow-hidden rounded-xl">
|
||||
<Image
|
||||
src={a.image}
|
||||
alt={a.title}
|
||||
fill
|
||||
sizes="(max-width: 640px) 100vw, 400px"
|
||||
className="rounded-xl object-cover transition-transform duration-700 ease-out group-hover:scale-108"
|
||||
/>
|
||||
<div className="absolute right-2.5 top-2.5 flex h-8 w-8 translate-x-1 items-center justify-center rounded-full bg-foreground/50 opacity-0 backdrop-blur-sm transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100">
|
||||
<span className="text-sm font-bold text-primary-foreground">
|
||||
→
|
||||
</span>
|
||||
<div className="flex flex-col gap-3 sm:gap-4">
|
||||
{renderArticleCard(articles[0], true)}
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3 sm:gap-4">
|
||||
{articles.slice(1, 4).map((a) => renderArticleCard(a))}
|
||||
</div>
|
||||
<div
|
||||
className="absolute left-2.5 top-2.5 rounded-full px-2 py-0.5 text-[10px] font-bold backdrop-blur-sm"
|
||||
style={{
|
||||
background:
|
||||
"color-mix(in srgb, #000 45%, transparent)",
|
||||
color: "#fff",
|
||||
}}
|
||||
>
|
||||
{formatDate(a.createdAt, "date", "")}
|
||||
</div>
|
||||
<div
|
||||
className="absolute bottom-0 left-0 w-full p-2.5 sm:p-3"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.4) 50%, transparent 100%)",
|
||||
}}
|
||||
>
|
||||
<h3 className="line-clamp-2 text-sm sm:text-base font-bold text-primary-foreground text-shadow-sm">
|
||||
{a.title}
|
||||
</h3>
|
||||
<p
|
||||
className="mt-0.5 text-[10px] sm:text-[11px] font-semibold opacity-80"
|
||||
style={{ color: "var(--color-text-muted)" }}
|
||||
>
|
||||
{formatDate(a.createdAt, "date", "")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p
|
||||
@@ -691,6 +884,8 @@ export default async function Home() {
|
||||
</SurfaceCard>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
{/* ── Recent photos ── */}
|
||||
{recentPhotos === null ? (
|
||||
@@ -701,7 +896,7 @@ export default async function Home() {
|
||||
recentPhotos.length > 0 && (
|
||||
<Reveal>
|
||||
<SurfaceCard title={tp("recentPhotos")} icon={ICON_CAMERA}>
|
||||
<div className="mx-auto grid max-w-xl grid-cols-4 gap-3">
|
||||
<div className="mx-auto grid max-w-xl grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
{recentPhotos.slice(0, 4).map((p) => (
|
||||
<Link
|
||||
key={p.id}
|
||||
|
||||
@@ -10,7 +10,7 @@ const compactCallSites = new Map<string, number>([
|
||||
["src/app/(site)/login/page.tsx", 2],
|
||||
["src/app/(site)/me/page.tsx", 1],
|
||||
["src/app/(site)/messages/page.tsx", 2],
|
||||
["src/app/(site)/page.tsx", 1],
|
||||
["src/app/(site)/page.tsx", 2],
|
||||
["src/app/(site)/radio/leaderboard/page.tsx", 1],
|
||||
["src/app/(site)/radio/shouts/page.tsx", 1],
|
||||
["src/app/(site)/rankings/page.tsx", 1],
|
||||
|
||||
@@ -274,7 +274,10 @@
|
||||
"statsOnline": "Online",
|
||||
"statsCitizens": "Citizens",
|
||||
"statsRooms": "Rooms",
|
||||
"statsPhotos": "Photos",
|
||||
"statsArticles": "Articles",
|
||||
"onlineNow": "Online now",
|
||||
"exploreLabel": "Explore the hotel",
|
||||
"featuresAvatar": "Avatar",
|
||||
"featuresAvatarDesc": "Create your unique look",
|
||||
"featuresFurniture": "Furniture",
|
||||
|
||||
@@ -274,7 +274,10 @@
|
||||
"statsOnline": "Online",
|
||||
"statsCitizens": "Cittadini",
|
||||
"statsRooms": "Stanze",
|
||||
"statsPhotos": "Foto",
|
||||
"statsArticles": "Articoli",
|
||||
"onlineNow": "Online adesso",
|
||||
"exploreLabel": "Esplora l'hotel",
|
||||
"featuresAvatar": "Avatar",
|
||||
"featuresAvatarDesc": "Crea il tuo look unico",
|
||||
"featuresFurniture": "Arredi",
|
||||
|
||||
Reference in new issue
Block a user