feat: 完成短剧项目空间与结构化资产创作闭环 (#38)
* feat(canvas): 短剧项目空间 - 建立项目章节与画布关联 MVP * feat(canvas): 短剧项目空间 - 完善项目资产、镜头与流程闭环 Refs #30 * fix(deploy): 本地部署 - 修复前端构建并忽略本地 PostgreSQL 配置 * feat(*): 短剧项目空间 - 完成项目、章节、资产、角色与画布创作闭环 Refs #30 --------- Co-authored-by: ddCat <ddcat666@88.com>
This commit is contained in:
@@ -51,7 +51,7 @@ export function AuthScene() {
|
||||
return (
|
||||
<main className="h-dvh min-h-0 overflow-y-auto bg-[#08090c] text-white lg:overflow-hidden">
|
||||
<div className="grid min-h-full lg:h-full lg:grid-cols-[minmax(0,1.32fr)_minmax(520px,1fr)]">
|
||||
<section className="relative min-h-[250px] overflow-hidden sm:min-h-[320px] lg:min-h-0" aria-label="无限画布品牌影片">
|
||||
<section className="relative min-h-[250px] overflow-hidden sm:min-h-[320px] lg:min-h-0" aria-label="影策品牌影片">
|
||||
<video
|
||||
className="absolute inset-0 size-full object-cover"
|
||||
src={AUTH_VIDEO_URL}
|
||||
@@ -67,7 +67,7 @@ export function AuthScene() {
|
||||
<div className="absolute inset-x-0 top-0 flex items-center justify-between gap-4 p-5 sm:p-7 lg:p-9">
|
||||
<Link to="/" className="inline-flex items-center gap-2.5 text-sm font-semibold text-white drop-shadow-sm transition-opacity hover:opacity-80">
|
||||
<span className="size-7 bg-current" style={{ mask: "url(/logo.svg) center / contain no-repeat", WebkitMask: "url(/logo.svg) center / contain no-repeat" }} />
|
||||
无限画布
|
||||
影策
|
||||
</Link>
|
||||
<span className="inline-flex items-center gap-2 rounded-full border border-white/16 bg-black/20 px-3 py-1.5 text-[11px] text-white/76 backdrop-blur-xl">
|
||||
<Play className="size-3 fill-current" />
|
||||
@@ -80,8 +80,8 @@ export function AuthScene() {
|
||||
transition={{ duration: aceternityMotion.duration.panel, ease: aceternityMotion.easing.enter }}
|
||||
className="absolute inset-x-0 bottom-0 max-w-2xl p-5 sm:p-7 lg:p-10"
|
||||
>
|
||||
<p className="text-xs font-semibold tracking-[0.18em] text-white/58">INFINITE CANVAS</p>
|
||||
<h1 className="mt-3 max-w-xl text-3xl font-semibold leading-tight sm:text-4xl lg:text-5xl">灵感,自此拥有空间。</h1>
|
||||
<p className="text-xs font-semibold tracking-[0.18em] text-white/58">YINGCE STUDIO</p>
|
||||
<h1 className="mt-3 max-w-xl text-3xl font-semibold leading-tight sm:text-4xl lg:text-5xl">让一个故事,从文字走向银幕。</h1>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
@@ -99,7 +99,7 @@ export function AuthScene() {
|
||||
className="my-auto w-full max-w-[460px]"
|
||||
>
|
||||
<ConfigProvider theme={getAntThemeConfig(true)}>
|
||||
<SpotlightSurface spotlightColor="rgba(103,232,249,.16)" spotlightRadius={300} className="flex h-auto rounded-[26px]">
|
||||
<SpotlightSurface spotlightColor="rgba(96,165,250,.14)" spotlightRadius={300} className="flex h-auto rounded-[26px]">
|
||||
<CometCard
|
||||
rotateDepth={1.8}
|
||||
translateDepth={1.5}
|
||||
@@ -109,7 +109,7 @@ export function AuthScene() {
|
||||
>
|
||||
<section aria-label={copy.title} className="flex min-h-[620px] flex-col sm:min-h-[640px]">
|
||||
<header className="px-6 pb-5 pt-6 sm:px-8 sm:pt-7">
|
||||
<p className="text-xs font-semibold tracking-[0.18em] text-cyan-300/80">{copy.eyebrow}</p>
|
||||
<p className="text-xs font-semibold tracking-[0.18em] text-blue-300/80">{copy.eyebrow}</p>
|
||||
<h2 className="mt-2 text-3xl font-semibold">{copy.title}</h2>
|
||||
<p className="mt-2 text-sm leading-6 text-white/45">{copy.description}</p>
|
||||
</header>
|
||||
|
||||
@@ -53,6 +53,6 @@ function AuthField({ label, children }: { label: string; children: ReactNode })
|
||||
}
|
||||
|
||||
function safeNext(value: string | null) {
|
||||
if (!value || !value.startsWith("/") || value.startsWith("//")) return "/canvas";
|
||||
if (!value || !value.startsWith("/") || value.startsWith("//")) return "/projects";
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function RegisterPage() {
|
||||
|
||||
return (
|
||||
<form onSubmit={submit} className="space-y-4">
|
||||
{settings?.firstUser ? <Notice icon={<Info className="size-3.5" />} tone="cyan">首个账号自动成为管理员,邮箱验证码暂不要求。</Notice> : null}
|
||||
{settings?.firstUser ? <Notice icon={<Info className="size-3.5" />} tone="blue">首个账号自动成为管理员,邮箱验证码暂不要求。</Notice> : null}
|
||||
{registrationClosed ? <Notice icon={<TriangleAlert className="size-3.5" />} tone="amber">当前已关闭普通注册,请联系管理员创建账号。</Notice> : null}
|
||||
{mailUnavailable ? <Notice icon={<TriangleAlert className="size-3.5" />} tone="amber">管理员尚未配置注册邮件,普通邮箱注册暂不可用。</Notice> : null}
|
||||
|
||||
@@ -116,11 +116,11 @@ function AuthField({ label, children }: { label: string; children: ReactNode })
|
||||
return <label className="block space-y-2"><span className="text-xs font-medium text-white/62">{label}</span>{children}</label>;
|
||||
}
|
||||
|
||||
function Notice({ icon, tone, children }: { icon: ReactNode; tone: "cyan" | "amber"; children: ReactNode }) {
|
||||
return <div className={`flex items-start gap-2 rounded-xl border px-3 py-2.5 text-xs leading-5 ${tone === "cyan" ? "border-cyan-300/15 bg-cyan-300/[0.06] text-cyan-100/78" : "border-amber-300/15 bg-amber-300/[0.06] text-amber-100/78"}`}><span className="mt-0.5 shrink-0">{icon}</span>{children}</div>;
|
||||
function Notice({ icon, tone, children }: { icon: ReactNode; tone: "blue" | "amber"; children: ReactNode }) {
|
||||
return <div className={`flex items-start gap-2 rounded-lg border px-3 py-2.5 text-xs leading-5 ${tone === "blue" ? "border-blue-300/15 bg-blue-300/[0.06] text-blue-100/78" : "border-amber-300/15 bg-amber-300/[0.06] text-amber-100/78"}`}><span className="mt-0.5 shrink-0">{icon}</span>{children}</div>;
|
||||
}
|
||||
|
||||
function safeNext(value: string | null) {
|
||||
if (!value || !value.startsWith("/") || value.startsWith("//")) return "/canvas";
|
||||
if (!value || !value.startsWith("/") || value.startsWith("//")) return "/projects";
|
||||
return value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user