fix(frontend): restore login & auth-loading styles with Tailwind

提交 6b77018 把 frontend/app/app.css 从 112 行砍到 91 行,
删除了 .login-* 与 .auth-loading 选择器,但 login.tsx /
AuthContext.tsx 的类名没同步迁移,导致:

  - /login 页面无样式(背景渐变、卡片阴影、输入框焦点环全部失效)
  - AuthContext 初次加载时的旋转 spinner 无样式

两处都用 Tailwind 任意值 [..] 语法精确复刻原 CSS,精确到
原始色值(#1677ff、#eef5fb 等),不引入新的 CSS 文件,
不修改 app.css、路由配置或依赖。

Spinner 用 Tailwind 内置 animate-spin(1s)替代原 0.8s
keyframes auth-spin,视觉差异肉眼不可见,如需精确复刻可在
app.css @theme 加 --animate-auth-spin。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
tao.chen
2026-08-25 10:35:27 +08:00
co-authored by Claude Fable 5
parent 97c8fe212b
commit 80c92f7fd4
2 changed files with 37 additions and 13 deletions
+2 -2
View File
@@ -198,8 +198,8 @@ export function AuthProvider({ children }: { children: ReactNode }) {
if (loading) {
return (
<div className="auth-loading" role="status">
<span />
<div className="flex min-h-screen items-center justify-center gap-3 text-[#61758a]" role="status">
<span className="h-5 w-5 animate-spin rounded-full border-2 border-[#bfd5e9] border-t-[#1677ff]" />
</div>
);
+35 -11
View File
@@ -35,14 +35,28 @@ export default function LoginRoute() {
};
return (
<main className="login-page">
<section className="login-card" aria-labelledby="login-title">
<div className="login-brand" aria-hidden="true"></div>
<p className="login-kicker">MODEL EXPERIMENT PLATFORM</p>
<h1 id="login-title"></h1>
<p className="login-description">使 Workspace</p>
<form onSubmit={(event) => void submit(event)}>
<label>
<main className="flex min-h-screen items-center justify-center bg-[radial-gradient(circle_at_20%_15%,rgba(22,119,255,0.12),transparent_34%),linear-gradient(145deg,#eef5fb,#f8fafc_55%,#edf3f8)] p-12">
<section
aria-labelledby="login-title"
className="w-[420px] rounded-[18px] border border-[#dbe6ef] bg-white/[0.96] p-[42px] shadow-[0_22px_60px_rgba(37,63,88,0.14)]"
>
<div
aria-hidden="true"
className="grid h-[46px] w-[46px] place-items-center rounded-[13px] bg-[linear-gradient(145deg,#1177e8,#25a1f2)] text-white"
>
</div>
<p className="mb-[8px] mt-[26px] text-[11px] font-[750] tracking-[0.14em] text-[#1677ff]">
MODEL EXPERIMENT PLATFORM
</p>
<h1 id="login-title" className="m-0 text-[27px]">
</h1>
<p className="mb-[28px] mt-[10px] text-[#728398]">
使 Workspace
</p>
<form onSubmit={(event) => void submit(event)} className="grid gap-[18px]">
<label className="grid gap-2 text-[13px] text-[#465b70]">
<span></span>
<input
autoComplete="username"
@@ -51,9 +65,10 @@ export default function LoginRoute() {
onChange={(event) => setUsername(event.target.value)}
placeholder="请输入用户名"
disabled={busy}
className="w-full rounded-[9px] border border-[#cad8e5] bg-white px-[14px] py-[12px] text-[#18334f] outline-none placeholder:text-[#728398] focus:border-[#1677ff] focus:shadow-[0_0_0_3px_rgba(22,119,255,0.12)] disabled:opacity-65 disabled:cursor-not-allowed"
/>
</label>
<label>
<label className="grid gap-2 text-[13px] text-[#465b70]">
<span></span>
<input
type="password"
@@ -62,10 +77,19 @@ export default function LoginRoute() {
onChange={(event) => setPassword(event.target.value)}
placeholder="请输入密码"
disabled={busy}
className="w-full rounded-[9px] border border-[#cad8e5] bg-white px-[14px] py-[12px] text-[#18334f] outline-none placeholder:text-[#728398] focus:border-[#1677ff] focus:shadow-[0_0_0_3px_rgba(22,119,255,0.12)] disabled:opacity-65 disabled:cursor-not-allowed"
/>
</label>
{error && <p className="login-error" role="alert">{error}</p>}
<button type="submit" disabled={busy}>
{error && (
<p role="alert" className="-mt-1 mb-0 text-[13px] text-[#d4380d]">
{error}
</p>
)}
<button
type="submit"
disabled={busy}
className="min-h-[44px] cursor-pointer rounded-[9px] border-0 bg-[#1677ff] text-white disabled:cursor-wait disabled:opacity-65"
>
{busy ? "正在登录…" : "登录"}
</button>
</form>