Redesign login, register, me pages with premium layout and i18n
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 2m7s

This commit is contained in:
openhands committed 2026-07-22 14:42:01 +02:00
1 parent 063ac9ec40
commit 1ffd46713a
7 files changed
+621 -279

No files matched your search

File diff suppressed because it is too large. Load diff
+10 -7
View File
@@ -2,11 +2,6 @@
import { useState } from "react";
/**
* Copies the user's referral link to the clipboard. Mirrors AtomCMS's
* copyCode() helper on the /me page, but resolves the link to an absolute URL
* (the server only knows a relative path, so we prepend the current origin).
*/
export default function CopyReferralButton({ value }: { value: string }) {
const [copied, setCopied] = useState(false);
@@ -18,7 +13,6 @@ export default function CopyReferralButton({ value }: { value: string }) {
try {
await navigator.clipboard.writeText(absolute);
} catch {
// Older browsers / insecure contexts: fall back to a hidden textarea.
const ta = document.createElement("textarea");
ta.value = absolute;
ta.style.position = "fixed";
@@ -37,7 +31,16 @@ export default function CopyReferralButton({ value }: { value: string }) {
}
return (
<button type="button" className="btn btn-secondary" onClick={copy}>
<button
type="button"
onClick={copy}
className="rounded-xl font-bold text-sm px-5 py-2.5 transition-all duration-200 hover:scale-[1.02] active:scale-95 shrink-0"
style={{
background: "color-mix(in srgb, var(--color-primary) 12%, transparent)",
color: "var(--color-primary-readable, var(--color-primary))",
border: `2px solid color-mix(in srgb, var(--color-primary) 20%, transparent)`,
}}
>
{copied ? "Copied!" : "Copy link"}
</button>
);
+202 -107
View File
File diff suppressed because it is too large. Load diff
+89 -38
View File
File diff suppressed because it is too large. Load diff
+10 -16
View File
@@ -10,7 +10,8 @@ import { captchaConfig } from "@/lib/services/captcha";
import { siteSettings } from "@/lib/services/site-settings";
export default async function RegisterPage() {
const t = await getTranslations("header");
const th = await getTranslations("header");
const tpr = await getTranslations("pages.register");
const [hotelName, imagerRaw, cfg] = await Promise.all([
siteSettings.get("hotel_name", "Hotel"),
siteSettings.get(
@@ -67,26 +68,19 @@ export default async function RegisterPage() {
}}
>
<span className="w-2 h-2 rounded-full bg-green-500" />
{online.toLocaleString()} online
{tpr("usersOnline", { count: online })}
</div>
<h1
className="text-xl font-black"
style={{ color: "var(--color-text-readable)" }}
>
Join{" "}
<span
style={{
color: "var(--color-primary-readable, var(--color-primary))",
}}
>
{hotelName}
</span>
{tpr("title")} — {hotelName}
</h1>
<p
className="text-xs mt-1 mx-auto max-w-[200px] leading-relaxed"
style={{ color: "var(--color-text-muted)" }}
>
{t("tagline")}
{th("tagline")}
</p>
</div>
@@ -103,7 +97,7 @@ export default async function RegisterPage() {
className="text-xs font-bold uppercase tracking-widest mb-3"
style={{ color: "var(--color-text-muted)" }}
>
Who&apos;s online
{tpr("whoIsOnline")}
</h3>
<div className="grid grid-cols-4 gap-1.5">
{recentUsers.map((u) => (
@@ -143,7 +137,7 @@ export default async function RegisterPage() {
className="text-xs text-center"
style={{ color: "var(--color-text-muted)" }}
>
Already have an account?{" "}
{tpr("alreadyHaveAccountPre")}{" "}
<Link
href="/login"
className="font-extrabold hover:underline"
@@ -151,7 +145,7 @@ export default async function RegisterPage() {
color: "var(--color-primary-readable, var(--color-primary))",
}}
>
Sign in
{tpr("alreadyHaveAccountLink")}
</Link>
</p>
</div>
@@ -163,13 +157,13 @@ export default async function RegisterPage() {
className="text-2xl font-black tracking-tight"
style={{ color: "var(--color-text-readable)" }}
>
Create your account
{tpr("title")}
</h2>
<p
className="text-sm mt-0.5"
style={{ color: "var(--color-text-muted)" }}
>
Free and takes less than a minute
{tpr("subtitle")}
</p>
</div>
<RegisterForm
File diff suppressed because it is too large. Load diff
+18 -1
View File
@@ -234,7 +234,18 @@
"noArticles": "No articles yet.",
"noPhotos": "No photos yet.",
"noUsers": "No users online",
"latestArticle": "Latest Article"
"latestArticle": "Latest Article",
"statsOnline": "Online",
"statsCitizens": "Citizens",
"statsRooms": "Rooms",
"featuresAvatar": "Avatar",
"featuresAvatarDesc": "Create your unique look",
"featuresFurniture": "Furniture",
"featuresFurnitureDesc": "Decorate rooms with items",
"featuresCommunity": "Community",
"featuresCommunityDesc": "Make friends and chat",
"featuresGames": "Games",
"featuresGamesDesc": "Compete and have fun"
},
"news": {
"title": "News",
@@ -894,6 +905,8 @@
"title": "Sign in",
"subtitle": "Welcome back — log in to enter the hotel.",
"subtitle2fa": "Enter the 6-digit code from your authenticator.",
"welcomeBack": "Welcome back",
"welcomeBackSub": "Sign in to continue to {hotelName}",
"usernamePlaceholder": "Username",
"passwordPlaceholder": "Password",
"codePlaceholder": "2FA code",
@@ -927,7 +940,11 @@
"createAccount": "Create account",
"creatingAccount": "Creating account...",
"alreadyHaveAccount": "Already have an account? Login!",
"alreadyHaveAccountPre": "Already have an account?",
"alreadyHaveAccountLink": "Sign in",
"register": "Register",
"whoIsOnline": "Who's online",
"usersOnline": "{count} online",
"termsError": "You must accept the terms & rules to register.",
"usernameError": "Username is required.",
"emailError": "Valid email is required.",