auto-save 2026-05-15 19:19 (~4)

This commit is contained in:
2026-05-15 19:19:18 +08:00
parent ea52864732
commit 7d4efa4844
4 changed files with 197 additions and 161 deletions

View File

@@ -365,6 +365,61 @@
-webkit-text-fill-color: #fff;
transition: background-color 9999s ease-in-out 0s;
}
.login-page--source::before,
.login-page--source::after {
display: none;
}
.login-page--source .login-oasis-shade {
background:
radial-gradient(circle at 34% 52%, rgba(230, 245, 120, 0.08), transparent 28%),
linear-gradient(90deg, rgba(0, 0, 0, 0.22), rgba(0, 0, 0, 0.04) 44%, rgba(0, 0, 0, 0.38));
}
.login-source-overlay {
position: relative;
z-index: 10;
display: grid;
min-height: 100vh;
grid-template-columns: minmax(320px, 460px) minmax(280px, 320px);
align-items: center;
justify-content: center;
gap: clamp(28px, 8vw, 120px);
padding: clamp(20px, 4vw, 56px);
}
.login-source-character-panel {
width: min(460px, 36vw);
border: 1px solid rgba(140, 180, 120, 0.14);
border-radius: 16px;
background: rgba(10, 18, 10, 0.28);
padding: 16px;
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.32);
backdrop-filter: blur(12px);
}
.login-source-character-panel .login-character-stage {
min-height: 330px;
border-color: rgba(255, 255, 255, 0.12);
background:
linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px),
linear-gradient(180deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px),
rgba(255, 255, 255, 0.035);
background-size: 28px 28px, 28px 28px, auto;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.login-source-character-panel .login-character-stage::after {
background: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.24));
}
.login-source-character-panel .login-stage-grid {
border-color: rgba(255, 255, 255, 0.11);
}
.login-source-character-panel .login-characters-container {
transform: translateX(-50%) scale(0.78);
}
.login-page--oasis .login-source-auth-panel {
width: min(320px, calc(100vw - 40px));
padding: 22px;
}
.login-page--source .login-auth-icon {
margin-bottom: 0;
}
.login-hero {
isolation: isolate;
color: #282828;
@@ -1089,6 +1144,29 @@
.login-page--oasis .login-auth-panel {
padding: 24px 18px;
}
.login-source-overlay {
min-height: 100vh;
grid-template-columns: 1fr;
align-content: center;
gap: 18px;
padding: 20px;
}
.login-source-character-panel {
width: min(100%, 350px);
justify-self: center;
padding: 12px;
}
.login-source-character-panel .login-character-stage {
min-height: 220px;
}
.login-source-character-panel .login-characters-container {
transform: translateX(-50%) scale(0.48);
}
.login-page--oasis .login-source-auth-panel {
width: min(100%, 330px);
justify-self: center;
padding: 20px;
}
.login-page--oasis .login-wordmark__logo {
font-size: 24px;
}

View File

@@ -9,8 +9,6 @@ import {
Eye,
EyeOff,
LockKeyhole,
ShieldCheck,
Sparkles,
UserRound,
} from "lucide-react"
import { AnimatedLoginCharacters, type LoginCharacterMood } from "@/components/login/animated-login-characters"
@@ -86,162 +84,110 @@ export default function LoginPage() {
}
return (
<main className="login-page login-page--oasis relative min-h-screen overflow-hidden px-5 py-6 text-white sm:px-8 lg:px-10">
<main className="login-page login-page--oasis login-page--source relative min-h-screen overflow-hidden text-white">
<OasisCanvas />
<div className="login-oasis-shade" />
<div className="relative z-10 mx-auto flex min-h-[calc(100vh-3rem)] w-full max-w-7xl items-center">
<div className="grid w-full gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(290px,320px)] lg:items-center">
<section className="login-hero login-oasis-hero order-2 relative min-h-[540px] overflow-hidden p-1 text-white sm:p-2 lg:order-1 lg:min-h-[620px]">
<div className="relative z-10 flex h-full flex-col">
<div className="flex flex-wrap items-center justify-between gap-4">
<div className="login-wordmark">
<span className="login-wordmark__logo">SKG</span>
<span className="login-wordmark__sub">Creative OS</span>
</div>
<div className="login-secure-pill">
<ShieldCheck className="h-4 w-4" />
<span>Internal Access</span>
</div>
</div>
<div className="login-source-overlay">
<section className="login-source-character-panel" aria-hidden="true">
<AnimatedLoginCharacters mood={mood} eyeOffset={eyeOffset} />
</section>
<div className="mt-10 max-w-[620px]">
<p className="login-kicker">CONTENT PRODUCTION SYSTEM</p>
<h1 className="login-premium-title"></h1>
<p className="login-premium-copy"></p>
</div>
<div className="login-creative-stage" aria-label="Creative workflow visual">
<div className="login-creative-caption">
<span>Creative Pipeline</span>
<b>Pipeline ready</b>
</div>
<div className="login-dynamic-dock">
<span className="login-dynamic-dock__label">Live Creative Modules</span>
<AnimatedLoginCharacters mood={mood} eyeOffset={eyeOffset} />
</div>
<div className="login-studio-chip login-studio-chip--visual">
<Sparkles className="h-4 w-4" />
<span>Pipeline Online</span>
</div>
</div>
<div className="login-premium-metrics">
{[
["Frame Lab", "画面"],
["Sound Lab", "声音"],
["Final Cut", "成片"],
].map(([label, value]) => (
<div key={label} className="login-premium-metric">
<span>{label}</span>
<b>{value}</b>
</div>
))}
<section className="login-auth-panel login-source-auth-panel flex items-center rounded-[8px]">
<form className="w-full" onSubmit={onSubmit}>
<div className="mb-4">
<div className="login-auth-icon inline-flex h-9 w-9 items-center justify-center rounded-[8px] text-white">
<LockKeyhole className="h-5 w-5" />
</div>
</div>
</section>
<section className="login-auth-panel order-1 flex items-center rounded-[8px] p-5 sm:p-6 lg:order-2 lg:p-6">
<form className="w-full" onSubmit={onSubmit}>
<div className="mb-5">
<div className="login-auth-icon mb-3 inline-flex h-9 w-9 items-center justify-center rounded-[8px] text-white">
<LockKeyhole className="h-5 w-5" />
</div>
<h2 className="text-xl font-semibold text-white"></h2>
<p className="mt-2 text-sm leading-6 text-white/55"></p>
</div>
<div className="space-y-3">
<label className="block">
<span className="mb-2 block text-sm font-medium text-white/70">访</span>
<span className="flex h-11 items-center gap-3 rounded-[8px] border border-white/10 bg-black/25 px-3 text-white transition focus-within:border-[#d6b36a] focus-within:bg-black/35 focus-within:ring-2 focus-within:ring-[#d6b36a]/25">
<UserRound className="h-4 w-4 text-white/45" />
<input
className="h-full min-w-0 flex-1 bg-transparent text-base text-white outline-none placeholder:text-white/30"
value={username}
disabled={disabled}
autoComplete="username"
placeholder="输入访问账号"
onFocus={() => setActiveField("username")}
onBlur={() => setActiveField(null)}
onChange={(event) => {
setUsername(event.target.value)
if (error) setError("")
}}
/>
</span>
</label>
<label className="block">
<span className="mb-2 block text-sm font-medium text-white/70">访</span>
<span className="flex h-11 items-center gap-3 rounded-[8px] border border-white/10 bg-black/25 px-3 text-white transition focus-within:border-[#d6b36a] focus-within:bg-black/35 focus-within:ring-2 focus-within:ring-[#d6b36a]/25">
<LockKeyhole className="h-4 w-4 text-white/45" />
<input
className="h-full min-w-0 flex-1 bg-transparent text-base text-white outline-none placeholder:text-white/30"
value={password}
disabled={disabled}
type={showPassword ? "text" : "password"}
autoComplete="current-password"
placeholder="输入访问密钥"
onFocus={() => setActiveField("password")}
onBlur={() => setActiveField(null)}
onChange={(event) => {
setPassword(event.target.value)
if (error) setError("")
}}
/>
<button
className="grid h-9 w-9 place-items-center rounded-[8px] text-white/55 transition hover:bg-white/10 hover:text-white focus:outline-none focus:ring-2 focus:ring-[#d6b36a]/45 disabled:opacity-50"
type="button"
disabled={disabled}
aria-label={showPassword ? "隐藏密码" : "显示密码"}
onMouseDown={(event) => event.preventDefault()}
onClick={() => setShowPassword((value) => !value)}
>
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
</span>
</label>
</div>
<div className="mt-3 flex items-center justify-between gap-4">
<label className="flex cursor-pointer items-center gap-2 text-sm text-white/60">
<div className="space-y-3">
<label className="block">
<span className="sr-only">访</span>
<span className="flex h-11 items-center gap-3 rounded-[8px] border border-white/10 bg-black/25 px-3 text-white transition focus-within:border-[#d6b36a] focus-within:bg-black/35 focus-within:ring-2 focus-within:ring-[#d6b36a]/25">
<UserRound className="h-4 w-4 text-white/45" />
<input
className="h-4 w-4 rounded border-white/20 bg-black/30 accent-[#c89b3c]"
type="checkbox"
checked={remember}
className="h-full min-w-0 flex-1 bg-transparent text-base text-white outline-none placeholder:text-white/30"
value={username}
disabled={disabled}
onChange={(event) => setRemember(event.target.checked)}
autoComplete="username"
placeholder="账号"
onFocus={() => setActiveField("username")}
onBlur={() => setActiveField(null)}
onChange={(event) => {
setUsername(event.target.value)
if (error) setError("")
}}
/>
<span></span>
</label>
<span className="text-xs text-white/35">marketing.skg.com</span>
</div>
</span>
</label>
<div className="mt-4 min-h-9" aria-live="polite">
{error ? (
<div className="flex items-start gap-2 rounded-[8px] border border-red-400/30 bg-red-500/10 px-3 py-2 text-sm text-red-100">
<AlertCircle className="mt-0.5 h-4 w-4 shrink-0" />
<span>{error}</span>
</div>
) : status === "success" ? (
<div className="flex items-start gap-2 rounded-[8px] border border-emerald-300/30 bg-emerald-400/10 px-3 py-2 text-sm text-emerald-100">
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0" />
<span></span>
</div>
) : null}
</div>
<label className="block">
<span className="sr-only">访</span>
<span className="flex h-11 items-center gap-3 rounded-[8px] border border-white/10 bg-black/25 px-3 text-white transition focus-within:border-[#d6b36a] focus-within:bg-black/35 focus-within:ring-2 focus-within:ring-[#d6b36a]/25">
<LockKeyhole className="h-4 w-4 text-white/45" />
<input
className="h-full min-w-0 flex-1 bg-transparent text-base text-white outline-none placeholder:text-white/30"
value={password}
disabled={disabled}
type={showPassword ? "text" : "password"}
autoComplete="current-password"
placeholder="密钥"
onFocus={() => setActiveField("password")}
onBlur={() => setActiveField(null)}
onChange={(event) => {
setPassword(event.target.value)
if (error) setError("")
}}
/>
<button
className="grid h-9 w-9 place-items-center rounded-[8px] text-white/55 transition hover:bg-white/10 hover:text-white focus:outline-none focus:ring-2 focus:ring-[#d6b36a]/45 disabled:opacity-50"
type="button"
disabled={disabled}
aria-label={showPassword ? "隐藏密码" : "显示密码"}
onMouseDown={(event) => event.preventDefault()}
onClick={() => setShowPassword((value) => !value)}
>
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
</span>
</label>
</div>
<button
className="mt-1 flex h-11 w-full items-center justify-center gap-2 rounded-[8px] bg-white px-4 text-base font-semibold text-black shadow-xl shadow-black/25 transition hover:bg-[#f5efe3] focus:outline-none focus:ring-2 focus:ring-[#d6b36a]/60 disabled:cursor-wait disabled:opacity-70"
type="submit"
<label className="mt-3 flex cursor-pointer items-center gap-2 text-sm text-white/60">
<input
className="h-4 w-4 rounded border-white/20 bg-black/30 accent-[#c89b3c]"
type="checkbox"
checked={remember}
disabled={disabled}
>
<span>{status === "loading" ? "验证中" : status === "success" ? "已验证" : "打开工作台"}</span>
<ArrowRight className="h-4 w-4" />
</button>
</form>
</section>
</div>
onChange={(event) => setRemember(event.target.checked)}
/>
<span></span>
</label>
<div className="mt-4 min-h-9" aria-live="polite">
{error ? (
<div className="flex items-start gap-2 rounded-[8px] border border-red-400/30 bg-red-500/10 px-3 py-2 text-sm text-red-100">
<AlertCircle className="mt-0.5 h-4 w-4 shrink-0" />
<span>{error}</span>
</div>
) : status === "success" ? (
<div className="flex items-start gap-2 rounded-[8px] border border-emerald-300/30 bg-emerald-400/10 px-3 py-2 text-sm text-emerald-100">
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0" />
<span></span>
</div>
) : null}
</div>
<button
className="mt-1 flex h-11 w-full items-center justify-center gap-2 rounded-[8px] bg-white px-4 text-base font-semibold text-black shadow-xl shadow-black/25 transition hover:bg-[#f5efe3] focus:outline-none focus:ring-2 focus:ring-[#d6b36a]/60 disabled:cursor-wait disabled:opacity-70"
type="submit"
disabled={disabled}
>
<span>{status === "loading" ? "验证中" : status === "success" ? "进入中" : "登录"}</span>
<ArrowRight className="h-4 w-4" />
</button>
</form>
</section>
</div>
</main>
)