add stable media support and sync skillhub UI

This commit is contained in:
wtgoku
2026-04-08 23:17:42 +08:00
parent ff4f370763
commit 4b20dc5e37
32 changed files with 6269 additions and 393 deletions
+75 -29
View File
@@ -1,5 +1,8 @@
import Link from "next/link";
import { getDictionary, type Locale } from "@/lib/site-content";
import { LoginForm } from "@/components/login-form";
import { getViewerSession } from "@/lib/popiart-api";
import { getLiveCopy } from "@/lib/live-copy";
import { type Locale } from "@/lib/site-content";
export default async function LoginPage({
params,
@@ -7,39 +10,82 @@ export default async function LoginPage({
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
const dictionary = getDictionary(locale as Locale);
const typedLocale = locale as Locale;
const liveCopy = getLiveCopy(typedLocale);
const session = await getViewerSession();
const isZh = typedLocale === "zh";
const title = isZh ? "使用 PopiNewAPI Key 登录" : "Sign in with your PopiNewAPI key";
const subtitle = isZh
? "页面登录后会换取产品层 session,控制台与 CLI 共用同一条认证链路。"
: "The web app exchanges your key for a product-layer session shared by the console and CLI.";
const cliTitle = isZh ? "CLI 登录指引" : "CLI sign-in guide";
const cliBody = isZh
? "如果你更习惯终端工作流,可以先安装 popiartcli,再用同一个 key 完成登录。"
: "If you prefer terminal-first workflows, install popiartcli and sign in with the same key.";
const installTitle = isZh ? "推荐命令" : "Recommended commands";
const continueCta = isZh ? "进入控制台" : "Open console";
const cliCommands = [
"brew tap wtgoku-create/popi",
"brew install wtgoku-create/popi/popiart",
"popiart auth login --key <your-popinewapi-key>",
"popiart skills list",
].join("\n");
return (
<div className="page-stack">
<section className="login-shell">
<div className="login-panel">
<div className="eyebrow">{dictionary.login.tag}</div>
<h1>{dictionary.login.title}</h1>
<p>{dictionary.login.subtitle}</p>
<div className="login-actions">
<button className="button button-dark" type="button">
{dictionary.login.primaryProvider}
</button>
<button className="button button-light" type="button">
{dictionary.login.secondaryProvider}
</button>
</div>
<p className="legal-copy">
{dictionary.login.termsPrefix}{" "}
<Link href={`/${locale}/pricing`}>{dictionary.login.termsLink}</Link>{" "}
{dictionary.login.and}{" "}
<Link href={`/${locale}/docs`}>{dictionary.login.privacyLink}</Link>
</p>
<section className="login-shell login-shell-focused">
<div className="login-panel login-panel-plain">
<div className="eyebrow">{isZh ? "SIGN IN" : "SIGN IN"}</div>
<h1>{title}</h1>
<p>{subtitle}</p>
{session ? (
<div className="login-form-stack">
<div className="status-banner">
<strong>{session.user.name || session.user.email || session.user.id}</strong>
<span>{liveCopy.login.alreadySignedIn}</span>
</div>
<Link className="button button-dark" href={`/${locale}/console`}>
{continueCta}
</Link>
</div>
) : (
<LoginForm
labels={{
fieldLabel: liveCopy.login.fieldLabel,
fieldHint: liveCopy.login.fieldHint,
submit: liveCopy.login.submit,
submitting: liveCopy.login.submitting,
helperTitle: liveCopy.login.helperTitle,
helperBody: liveCopy.login.helperBody,
commandLabel: liveCopy.login.commandLabel,
invalidKey: liveCopy.login.invalidKey,
}}
locale={typedLocale}
/>
)}
</div>
<div className="login-benefits">
{dictionary.login.benefits.map((benefit) => (
<article className="benefit-card" key={benefit.title}>
<span className="card-kicker">{benefit.kicker}</span>
<h2>{benefit.title}</h2>
<p>{benefit.description}</p>
</article>
))}
<div className="login-guide-panel">
<div className="section-heading compact">
<div className="eyebrow">{isZh ? "CLI" : "CLI"}</div>
<h2>{cliTitle}</h2>
<p>{cliBody}</p>
</div>
<div className="inline-note">
<strong>{installTitle}</strong>
<p>{liveCopy.login.helperBody}</p>
</div>
<div className="code-card login-guide-code">
<span className="card-kicker">{liveCopy.login.commandLabel}</span>
<pre>
<code>{cliCommands}</code>
</pre>
</div>
<Link className="button button-light" href={`/${locale}/docs`}>
{isZh ? "查看文档" : "Read docs"}
</Link>
</div>
</section>
</div>