Commit d9c28a9f authored by edy's avatar edy

feat(ui): optimize douyin expert empty state

parent f2b000fe
Pipeline #18452 failed
......@@ -143,35 +143,59 @@ export function ExpertEmptyState({
if (activeExpertKey === "douyin") {
return (
<div className="empty-state expert-empty-state expert-empty-state-douyin">
<div className="expert-guide-heading">
<span className="empty-state-kicker">{activeExpertName}</span>
<div className="douyin-brief-card">
<span className="douyin-brief-logo" aria-hidden="true"></span>
<div className="douyin-brief-copy">
<strong>{activeExpertGuide.greeting}</strong>
{activeExpertGuide.intro ? <p>{activeExpertGuide.intro}</p> : null}
<p>{activeExpertGuide.summary}</p>
</div>
{activeExpertGuide.requirementChecklist?.length ? (
</div>
<div className="douyin-guide-grid">
<section className="douyin-video-preview-card" aria-label="短视频预览">
<div className="douyin-video-frame">
<div className="douyin-video-topbar">
<span>Brief 预览</span>
<span>9:16</span>
</div>
<div className="douyin-video-play" aria-hidden="true" />
<div className="douyin-video-caption">
<span>开场钩子</span>
<strong>3 秒抓住注意力</strong>
</div>
<div className="douyin-video-progress">
<span />
</div>
</div>
<div className="douyin-shot-strip" aria-hidden="true">
<span />
<span />
<span />
<span />
</div>
</section>
<section className="douyin-guide-card">
<span className="douyin-guide-label">建议先告诉我这些</span>
<span className="douyin-guide-label">开始前补全信息</span>
{activeExpertGuide.intro ? <p className="douyin-guide-intro">{activeExpertGuide.intro}</p> : null}
{activeExpertGuide.requirementChecklist?.length ? (
<div className="douyin-guide-chip-list">
{activeExpertGuide.requirementChecklist.map((item) => (
<span key={item} className="douyin-guide-chip">{item}</span>
))}
</div>
</section>
) : null}
{activeExpertGuide.routeOptions?.length ? (
<div className="douyin-guide-grid">
<div className="douyin-route-list">
{activeExpertGuide.routeOptions.map((item) => (
<section key={item.title} className={"douyin-guide-card douyin-guide-route-card " + item.accent}>
<span className="douyin-guide-route-badge">{item.accent === "host" ? "有人出镜" : "纯画面"}</span>
<strong className="douyin-guide-route-title">{item.title}</strong>
<div key={item.title} className={"douyin-guide-route-card " + item.accent}>
<span className="douyin-guide-route-badge">{item.accent === "host" ? "数字人口播" : "纯画面展示"}</span>
<p className="douyin-guide-route-detail">{item.detail}</p>
</section>
</div>
))}
</div>
) : null}
{activeExpertGuide.workflowSteps?.length ? (
<section className="douyin-guide-card douyin-guide-card-wide">
<span className="douyin-guide-label">生成流程</span>
<div className="douyin-guide-step-list">
{activeExpertGuide.workflowSteps.map((item, index) => (
<div key={item} className="douyin-guide-step">
......@@ -180,14 +204,24 @@ export function ExpertEmptyState({
</div>
))}
</div>
) : null}
{activeExpertGuide.continueHint ? <p className="douyin-guide-continue">{activeExpertGuide.continueHint}</p> : null}
</section>
) : null}
</div>
<div className="douyin-guide-footer">
<p>{starterQuestionsHint}</p>
<span className="douyin-guide-label">{starterQuestionsHint}</span>
<div className="starter-prompt-list">
{activeExpertGuide.prompts.map((item) => (
<button key={item} type="button" className="starter-prompt" onClick={() => onStarterPrompt(item)}>{item}</button>
<button
key={item}
type="button"
className="starter-prompt douyin-starter-prompt"
onClick={() => onStarterPrompt(item)}
>
<span className="starter-prompt-title">立即套用脚本 brief</span>
<span className="starter-prompt-desc">{item}</span>
</button>
))}
</div>
</div>
......
......@@ -171,34 +171,34 @@ export function getExpertGuideContent(project: ExpertProject | undefined): Exper
}
return {
greeting: " 先把这条抖音视频的条件说清楚,我会先帮你整理需求并给出预览。",
summary: "适合抖音视频需求补全、文案与分镜预览、数字人口播和纯画面路线判断。",
intro: "最好一次说明主题、给谁看、想达到什么目标、风格、时长、做数字人还是纯画面,以及现在有没有图片或音频。",
greeting: "先给我一个视频目标,我来生成文案和分镜预览。",
summary: "抖音视频 brief、脚本、分镜和生成路线会先在这里对齐。",
intro: "补齐这些信息后,我会先出预览,不会直接开跑视频。",
requirementChecklist: [
"主题:产品、话题、门店活动或要讲的内容",
"给谁看:目标人群、行业或使用场景",
"目标:卖货、种草、科普、活动引流",
"风格:精致广告感、真实手机拍摄感、氛围感、剧情感",
"时长:数字人口播尽量控制在 65 秒内,纯画面请直接给秒数",
"视频类型:有人出镜讲解,还是纯画面展示",
"素材:有没有人物图片、现成音频,或准备走系统配音"
"主题",
"人群",
"目标",
"风格",
"时长",
"视频类型",
"素材"
],
routeOptions: [
{
title: " 有人出镜讲解",
detail: "适合数字人口播、知识讲解、产品说明。继续生成前通常要确认人物图片,以及现成音频或男声/女声配音。",
title: "数字人口播",
detail: "适合讲解、产品说明和知识类内容。继续前确认人物图片和配音方式。",
accent: "host"
},
{
title: " 纯画面展示",
detail: "适合氛围片、空镜、场景展示、画面加旁白。先把视频秒数说清楚,再出文案和分镜预览。",
title: "纯画面展示",
detail: "适合氛围片、空镜、场景展示和旁白视频。先确认秒数和画面风格。",
accent: "visual"
}
],
workflowSteps: [
" 先生成文案和分镜预览,不直接开跑视频。",
" 你确认预览后,再继续生成数字人或纯画面视频。",
" 如果当前路线缺素材,再按需要补图片、音频或配音要求。"
"补全 brief",
"生成预览",
"确认后开跑视频"
],
// continueHint: "看完预览后,你可以直接回复:继续生成;如果要改,直接回复:修改第几镜 + 你的修改意见。",
placeholder: "例如:做一个讲天气预报的抖音视频,给职场人看,目标是科普,男声数字人口播,10 秒,氛围感,我会上传人物照片,先给我文案和分镜预览。",
......
......@@ -665,6 +665,17 @@
padding: 32px;
}
.conversation-shell.conversation-shell-experts .expert-empty-state-douyin {
align-content: start;
overflow-y: auto;
padding: 16px;
border-style: solid;
background:
radial-gradient(circle at 18% 10%, rgba(61, 220, 255, 0.16), transparent 28%),
radial-gradient(circle at 88% 8%, rgba(255, 77, 141, 0.12), transparent 26%),
linear-gradient(180deg, #f8fbff 0%, #eef5fb 100%);
}
@media (max-width: 1440px), (max-height: 820px) {
.shell,
.conversation-shell {
......
......@@ -806,6 +806,349 @@
padding: 10px 12px;
}
.expert-empty-state-douyin {
gap: 12px;
padding: 16px;
background:
radial-gradient(circle at 18% 10%, rgba(61, 220, 255, 0.16), transparent 28%),
radial-gradient(circle at 88% 8%, rgba(255, 77, 141, 0.12), transparent 26%),
linear-gradient(180deg, #f8fbff 0%, #eef5fb 100%);
}
.expert-empty-state-douyin .douyin-brief-card {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 12px;
align-items: center;
padding: 14px;
border-radius: 16px;
border: 1px solid rgba(207, 221, 235, 0.9);
background: rgba(255, 255, 255, 0.94);
box-shadow: 0 16px 34px rgba(23, 31, 46, 0.08);
}
.expert-empty-state-douyin .douyin-brief-logo {
width: 42px;
height: 42px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 12px;
background:
linear-gradient(135deg, rgba(61, 220, 255, 0.95), rgba(61, 220, 255, 0) 44%),
linear-gradient(315deg, rgba(255, 77, 141, 0.95), rgba(255, 77, 141, 0) 48%),
#111827;
color: #ffffff;
font-size: 18px;
font-weight: 800;
line-height: 1;
}
.expert-empty-state-douyin .douyin-brief-copy {
min-width: 0;
display: grid;
gap: 4px;
}
.expert-empty-state-douyin .douyin-brief-copy strong {
color: #101827;
font-size: 18px;
line-height: 1.35;
}
.expert-empty-state-douyin .douyin-guide-grid {
display: grid;
grid-template-columns: minmax(180px, 0.64fr) minmax(0, 1fr);
gap: 12px;
align-items: stretch;
}
.expert-empty-state-douyin .douyin-video-preview-card,
.expert-empty-state-douyin .douyin-guide-card,
.expert-empty-state-douyin .douyin-guide-footer {
border-radius: 16px;
border: 1px solid rgba(207, 221, 235, 0.9);
background: rgba(255, 255, 255, 0.94);
box-shadow: 0 16px 34px rgba(23, 31, 46, 0.07);
}
.expert-empty-state-douyin .douyin-video-preview-card {
display: grid;
gap: 10px;
justify-items: center;
padding: 12px;
}
.expert-empty-state-douyin .douyin-video-frame {
position: relative;
width: min(100%, 210px);
aspect-ratio: 9 / 16;
overflow: hidden;
border-radius: 18px;
background:
linear-gradient(155deg, rgba(61, 220, 255, 0.2), transparent 30%),
linear-gradient(325deg, rgba(255, 77, 141, 0.28), transparent 36%),
linear-gradient(180deg, #101827, #1d2939);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.expert-empty-state-douyin .douyin-video-topbar,
.expert-empty-state-douyin .douyin-video-caption,
.expert-empty-state-douyin .douyin-video-progress {
position: absolute;
left: 12px;
right: 12px;
}
.expert-empty-state-douyin .douyin-video-topbar {
top: 12px;
display: flex;
justify-content: space-between;
gap: 8px;
color: rgba(255, 255, 255, 0.84);
font-size: 11px;
line-height: 1.4;
}
.expert-empty-state-douyin .douyin-video-play {
position: absolute;
inset: 0;
width: 48px;
height: 48px;
margin: auto;
border-radius: 999px;
background: rgba(255, 255, 255, 0.92);
box-shadow:
-6px 0 0 rgba(61, 220, 255, 0.5),
6px 0 0 rgba(255, 77, 141, 0.45);
}
.expert-empty-state-douyin .douyin-video-play::after {
content: "";
position: absolute;
top: 14px;
left: 19px;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 15px solid #101827;
}
.expert-empty-state-douyin .douyin-video-caption {
bottom: 32px;
display: grid;
gap: 3px;
padding: 10px;
border-radius: 12px;
background: rgba(15, 23, 42, 0.72);
}
.expert-empty-state-douyin .douyin-video-caption span {
color: #3ddcff;
font-size: 11px;
line-height: 1.4;
}
.expert-empty-state-douyin .douyin-video-caption strong {
color: #ffffff;
font-size: 13px;
line-height: 1.35;
}
.expert-empty-state-douyin .douyin-video-progress {
bottom: 14px;
height: 4px;
overflow: hidden;
border-radius: 999px;
background: rgba(255, 255, 255, 0.22);
}
.expert-empty-state-douyin .douyin-video-progress span {
display: block;
width: 58%;
height: 100%;
border-radius: inherit;
background: linear-gradient(90deg, #3ddcff, #ff4d8d);
}
.expert-empty-state-douyin .douyin-shot-strip {
width: min(100%, 210px);
display: grid;
grid-template-columns: 1.1fr 0.8fr 1.3fr 0.9fr;
gap: 5px;
}
.expert-empty-state-douyin .douyin-shot-strip span {
height: 8px;
border-radius: 999px;
background: rgba(16, 24, 39, 0.14);
}
.expert-empty-state-douyin .douyin-shot-strip span:nth-child(2) {
background: rgba(61, 220, 255, 0.58);
}
.expert-empty-state-douyin .douyin-shot-strip span:nth-child(4) {
background: rgba(255, 77, 141, 0.5);
}
.expert-empty-state-douyin .douyin-guide-card {
display: grid;
gap: 10px;
align-content: start;
padding: 14px;
}
.expert-empty-state-douyin .douyin-guide-label {
color: #101827;
font-size: 12px;
font-weight: 700;
line-height: 1.4;
}
.expert-empty-state-douyin .douyin-guide-intro {
margin: 0;
}
.expert-empty-state-douyin .douyin-guide-chip-list {
display: flex;
flex-wrap: wrap;
gap: 7px;
}
.expert-empty-state-douyin .douyin-guide-chip {
min-height: 28px;
display: inline-flex;
align-items: center;
padding: 5px 10px;
border-radius: 999px;
border: 1px solid rgba(16, 24, 39, 0.08);
background: #f8fafc;
color: #243247;
font-size: 12px;
font-weight: 600;
line-height: 1.4;
}
.expert-empty-state-douyin .douyin-route-list {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.expert-empty-state-douyin .douyin-guide-route-card {
display: grid;
gap: 5px;
padding: 10px;
border-radius: 14px;
border: 1px solid rgba(16, 24, 39, 0.08);
background: #fbfdff;
}
.expert-empty-state-douyin .douyin-guide-route-card.host {
border-color: rgba(61, 220, 255, 0.38);
}
.expert-empty-state-douyin .douyin-guide-route-card.visual {
border-color: rgba(255, 77, 141, 0.32);
}
.expert-empty-state-douyin .douyin-guide-route-badge {
width: fit-content;
padding: 3px 7px;
border-radius: 999px;
background: rgba(16, 24, 39, 0.06);
color: #334155;
font-size: 11px;
font-weight: 700;
line-height: 1.4;
}
.expert-empty-state-douyin .douyin-guide-route-title {
color: #101827;
font-size: 13px;
line-height: 1.35;
}
.expert-empty-state-douyin .douyin-guide-route-detail {
margin: 0;
}
.expert-empty-state-douyin .douyin-guide-step-list {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
}
.expert-empty-state-douyin .douyin-guide-step {
min-width: 0;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: 7px;
align-items: center;
padding: 8px;
border-radius: 12px;
background: #f8fafc;
}
.expert-empty-state-douyin .douyin-guide-step-index {
width: 22px;
height: 22px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 999px;
background: #101827;
color: #ffffff;
font-size: 11px;
font-weight: 800;
line-height: 1;
}
.expert-empty-state-douyin .douyin-guide-step-copy {
min-width: 0;
color: #243247;
font-size: 12px;
font-weight: 600;
line-height: 1.4;
}
.expert-empty-state-douyin .douyin-guide-continue {
margin: 0;
}
.expert-empty-state-douyin .douyin-guide-footer {
display: grid;
gap: 10px;
padding: 12px;
}
.expert-empty-state-douyin .starter-prompt-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.expert-empty-state-douyin .douyin-starter-prompt {
display: grid;
gap: 5px;
min-height: 74px;
border-color: rgba(16, 24, 39, 0.1);
background:
linear-gradient(90deg, rgba(61, 220, 255, 0.1), rgba(255, 77, 141, 0.1)),
#ffffff;
}
.expert-empty-state-douyin .starter-prompt-title {
color: #101827;
font-size: 12px;
font-weight: 800;
line-height: 1.35;
}
.expert-empty-state-douyin .starter-prompt-desc {
color: #4b5f7a;
font-size: 12px;
line-height: 1.5;
}
.message-card {
padding: 14px;
}
......@@ -863,6 +1206,15 @@
.chat-header-actions {
justify-content: flex-start;
}
.expert-empty-state-douyin .douyin-guide-grid {
grid-template-columns: 1fr;
}
.expert-empty-state-douyin .douyin-video-frame,
.expert-empty-state-douyin .douyin-shot-strip {
width: min(100%, 180px);
}
}
@media (max-width: 720px) {
......@@ -870,6 +1222,16 @@
display: none;
}
.expert-empty-state-douyin .douyin-brief-card {
grid-template-columns: 1fr;
}
.expert-empty-state-douyin .douyin-route-list,
.expert-empty-state-douyin .douyin-guide-step-list,
.expert-empty-state-douyin .starter-prompt-list {
grid-template-columns: 1fr;
}
.composer-submit {
width: 100%;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment