fix: refine landing and auth entry design

This commit is contained in:
2569718930@qq.com
2026-06-06 20:43:31 +08:00
parent 98b69b180a
commit 524ae7c8cf
4 changed files with 81 additions and 18 deletions
+28 -16
View File
@@ -52,8 +52,8 @@ export function LoginClient({ nextPath, initialError, initialMode }: LoginClient
const copy = {
backHome: isEn ? "Back to Home" : "返回首页",
subtitle: isEn
? "Explore weather details from every corner of the world"
: "探索世界每一个角落的气象细节",
? "Enter the live terminal, subscription center, and Telegram entitlement workflow."
: "进入实时终端、订阅中心和 Telegram 权益工作流。",
googleOneClick: isEn
? "Continue with Google"
: "使用 Google 账号一键登录",
@@ -64,9 +64,9 @@ export function LoginClient({ nextPath, initialError, initialMode }: LoginClient
passwordSignupPlaceholder: isEn
? "Set at least 6 characters"
: "设置至少 6 位密码",
loginSubmit: isEn ? "Start your weather decision journey" : "开启气象决策之旅",
loginSubmit: isEn ? "Enter PolyWeather Terminal" : "进入 PolyWeather 终端",
loginSubmitting: isEn ? "Signing in..." : "正在登录...",
signupSubmit: isEn ? "Create account now" : "立即创建账号",
signupSubmit: isEn ? "Create account and start trial" : "创建账号并领取试用",
signupSubmitting: isEn ? "Creating account..." : "正在创建账号...",
googleSubmitting: isEn ? "Connecting Google..." : "正在连接 Google...",
loginHint: isEn
@@ -101,8 +101,8 @@ export function LoginClient({ nextPath, initialError, initialMode }: LoginClient
// New translations for Koyfin-style layouts
workEmail: isEn ? "Work email" : "工作邮箱",
password: isEn ? "Password" : "密码",
welcomeBack: isEn ? "Welcome Back" : "欢迎回来",
signUpTitle: isEn ? "Sign up for your PolyWeather account" : "注册您的 PolyWeather 账",
welcomeBack: isEn ? "Sign in to PolyWeather" : "登录 PolyWeather",
signUpTitle: isEn ? "Create your PolyWeather account" : "创建 PolyWeather 账",
newToPoly: isEn ? "New to PolyWeather?" : "还没有 PolyWeather 账号?",
alreadyHave: isEn ? "Already have an account?" : "已经有账号了?",
termsAgreement: isEn
@@ -264,22 +264,28 @@ export function LoginClient({ nextPath, initialError, initialMode }: LoginClient
<div className="absolute inset-0 bg-[linear-gradient(to_right,rgba(255,255,255,0.015)_1px,transparent_1px),linear-gradient(to_bottom,rgba(255,255,255,0.015)_1px,transparent_1px)] bg-[size:32px_32px] pointer-events-none" />
<div className="relative z-10 flex flex-col gap-14">
<Link href="/" className="flex items-center hover:opacity-90 transition-opacity">
<img src="/logo.png" alt="PolyWeather" className="h-8 w-auto object-contain brightness-0 invert" />
<Link
href="/"
className="inline-flex items-center gap-2 text-lg font-black tracking-tight text-white transition-opacity hover:opacity-90"
>
<span className="grid h-8 w-8 place-items-center rounded-lg border border-white/15 bg-white/10 text-[11px] font-black text-cyan-200">
PW
</span>
<span>PolyWeather</span>
</Link>
<div className="space-y-6">
<h2 className="text-3xl font-black leading-[1.25] tracking-tight text-white animate-fade-up [animation-delay:150ms] opacity-0">
{isEn ? (
<>
Weather intelligence and risk management{" "}
Settlement-source evidence for temperature markets{" "}
<span className="inline-block px-2.5 py-0.5 mt-1 rounded bg-gradient-to-r from-blue-600 to-indigo-500 text-white font-bold text-[0.9em] shadow-lg shadow-blue-600/25 animate-gradient bg-[length:200%_auto]">
simplified.
</span>
</>
) : (
<>
{" "}
{" "}
<span className="inline-block px-2.5 py-0.5 mt-1 rounded bg-gradient-to-r from-blue-600 to-indigo-500 text-white font-bold text-[0.9em] shadow-lg shadow-blue-600/25 animate-gradient bg-[length:200%_auto]">
</span>
@@ -407,12 +413,18 @@ export function LoginClient({ nextPath, initialError, initialMode }: LoginClient
{/* Top Header Switch */}
<div className="relative z-10 flex justify-between lg:justify-end items-center gap-3">
{/* Logo on top-left for mobile only */}
<Link href="/" className="flex items-center hover:opacity-90 transition-opacity lg:hidden">
<img src="/logo.png" alt="PolyWeather" className="h-7 w-auto object-contain" />
<Link
href="/"
className="inline-flex items-center gap-2 text-sm font-black tracking-tight text-slate-950 transition-opacity hover:opacity-90 lg:hidden"
>
<span className="grid h-8 w-8 place-items-center rounded-lg border border-slate-200 bg-white text-[10px] font-black text-sky-700 shadow-sm">
PW
</span>
<span className="hidden min-[360px]:inline">PolyWeather</span>
</Link>
<div className="flex items-center gap-3">
<span className="text-xs text-slate-500">
<span className="hidden text-xs text-slate-500 sm:inline">
{isLogin ? copy.newToPoly : copy.alreadyHave}
</span>
<button
@@ -422,7 +434,7 @@ export function LoginClient({ nextPath, initialError, initialMode }: LoginClient
setInfoText("");
setMode(isLogin ? "signup" : "login");
}}
className="rounded-xl border border-slate-200 bg-white px-4 py-2 text-xs font-bold text-slate-700 shadow-sm transition-all hover:border-slate-300 hover:bg-slate-50 hover:text-slate-900 active:scale-[0.98]"
className="whitespace-nowrap rounded-xl border border-slate-200 bg-white px-4 py-2 text-xs font-bold text-slate-700 shadow-sm transition-all hover:border-slate-300 hover:bg-slate-50 hover:text-slate-900 active:scale-[0.98]"
>
{isLogin ? copy.signup : copy.login}
</button>
@@ -430,8 +442,8 @@ export function LoginClient({ nextPath, initialError, initialMode }: LoginClient
</div>
{/* Center Form Card */}
<div className="relative z-10 flex flex-1 items-center justify-center my-10">
<div className="w-full max-w-[440px] bg-white/90 backdrop-blur-xl border border-slate-200/50 rounded-2xl p-6 sm:p-10 shadow-[0_24px_60px_rgba(8,16,36,0.06)] animate-fade-up [animation-delay:200ms] opacity-0 transition-transform hover:-translate-y-1 hover:shadow-[0_32px_80px_rgba(8,16,36,0.08)] duration-500">
<div className="relative z-10 flex flex-1 items-start justify-center pt-10 sm:pt-12 lg:my-10 lg:items-center lg:pt-0">
<div className="w-full max-w-[440px] bg-white/90 backdrop-blur-xl border border-slate-200/50 rounded-2xl p-6 sm:p-10 shadow-[0_24px_60px_rgba(8,16,36,0.06)] animate-fade-up [animation-delay:200ms] opacity-0">
<div className="mb-6">
<h1 className="text-2xl font-black tracking-tight text-slate-900 mb-2">
{isLogin ? copy.welcomeBack : copy.signUpTitle}
@@ -0,0 +1,42 @@
import fs from "node:fs";
import path from "node:path";
function assert(condition: unknown, message: string) {
if (!condition) throw new Error(message);
}
export function runTests() {
const source = fs.readFileSync(
path.join(process.cwd(), "components", "auth", "LoginClient.tsx"),
"utf8",
);
assert(
source.includes("登录 PolyWeather") &&
source.includes("创建 PolyWeather 账号") &&
source.includes("创建账号并领取试用"),
"auth entry copy must be product-specific and explain the signup trial path",
);
assert(
source.includes("PW") && source.includes("PolyWeather"),
"auth pages must show a readable PolyWeather brand mark",
);
assert(
!source.includes("brightness-0 invert"),
"auth dark panel must not invert the square logo image into a white block",
);
assert(
source.includes("items-start justify-center pt-10") &&
source.includes("lg:items-center lg:pt-0"),
"auth form must sit higher on mobile while staying centered on desktop",
);
assert(
!source.includes("hover:-translate-y-1"),
"auth form card must not shift position on hover",
);
assert(
source.includes("hidden text-xs text-slate-500 sm:inline") &&
source.includes("whitespace-nowrap rounded-xl"),
"auth mode switch prompt must not crowd or wrap the mobile header",
);
}
@@ -249,8 +249,11 @@ function InstitutionalLandingScreen({ locale }: { locale: LandingLocale }) {
<LandingAnalytics />
<header className="sticky top-0 z-30 border-b border-slate-200 bg-[#fbfbfa]/90 backdrop-blur-xl">
<div className="mx-auto flex h-14 max-w-6xl items-center justify-between px-4 sm:px-6">
<Link href="/" className="flex items-center gap-2 transition-opacity hover:opacity-80">
<img src="/logo.png" alt="PolyWeather" className="h-7 w-auto object-contain" />
<Link
href="/"
className="text-base font-black tracking-tight text-slate-950 transition-opacity hover:opacity-80 sm:text-lg"
>
PolyWeather
</Link>
<nav className="hidden items-center gap-7 text-sm font-medium text-slate-500 md:flex">
@@ -49,6 +49,12 @@ export function runTests() {
assert(!source.includes("高频刷新与 API 仍为 Pro 权益"), "landing page must not incorrectly exclude high-frequency refresh or API from trial access");
assert(source.includes("bg-[#fbfbfa]"), "landing page must use a light Notion-style background");
assert(source.includes("WeatherWorkflowIllustration"), "landing page must include a friendly illustration surface");
assert(
/className="text-base font-black tracking-tight text-slate-950[\s\S]*?>\s*PolyWeather\s*<\/Link>/.test(
source,
),
"landing header must expose a readable PolyWeather wordmark instead of a tiny square logo image",
);
assert(!fs.existsSync(publicPngPath), "heavy PNG preview must not remain in public static assets");
assert(fs.existsSync(fixturePngPath), "PNG preview may only remain as a test fixture");
assert(fs.existsSync(webpPath), "landing page must ship a WebP preview image for the LCP product screenshot");