Compare commits

...

3 Commits

Author SHA1 Message Date
ludan 2b65206b84 feat: 电商克隆上传交互升级、视频模型选择器图标
【电商克隆 - 商品图上传交互重构】
- 新增上传预览大图区(clone-ai-upload-preview-wrap),点击缩略图可切换预览
- 选中缩略图增加 is-active 绿色边框高亮
- 预览区显示商品图编号 + 尺寸/比例/格式信息(formatProductImageSpec)
- 上传区到达 7 张上限时显示"已达上限"、阻止拖拽上传、输入框禁用
- 上传图片自动异步读取尺寸(width/height),无需等待上传完成即可展示
- 已上传素材区重构为列表头(标题+计数)+ 缩略图栈式布局
- 缩略图增加序号角标(1-7),删除按钮独立于缩略图下方
- selectedProductImageId 状态自动管理:删除/新增时自动切换到有效图片

【工作台 - 视频模型选择器图标】
- 新增 VIDEO_MODEL_ICON_URLS 映射(HappyHorse/Pixverse/Vidu/Wan/Kling)
- SelectChip 组件在 chipId=video-model 时显示模型品牌图标
- getVideoModelIconUrl 支持中英文模糊匹配

【样式】
- ecommerce.css: 预览区/素材栈/缩略图选中态/上限态完整样式
- dark-green.css: 主题层微调
2026-06-04 17:27:40 +08:00
ludan fb4011bf1f feat: 个人中心视觉重构、画布网点背景、剧本评分色调统一
【个人中心视觉重构】
- 列表卡片新增媒体预览缩略图(图片/视频/项目/资产),支持 image/video 两种媒体类型
- 新增 renderCardPreview 通用预览组件,自动识别视频格式并渲染 <video> 标签
- 新增 formatAssetType 工具函数,资产类型中文化(角色/场景/道具/视频/图像/素材)
- 媒体卡片采用固定高度网格布局(标题行 18px/正文 36px/元信息 18px),保证列表节奏一致
- 卡片预览区左上角显示类型标签徽章(品牌绿边框+半透明背景)
- 删除按钮增加 hover 红色反馈(边框/背景/文字渐变至红色)
- 积分/任务面板从底部区域移至侧边栏头像下方,减少滚动距离
- 新增 account-card 容器包裹积分/任务切换面板
- 侧边栏统计数据改为 3 列网格布局,每项增加独立圆角卡片样式
- 作品/项目/资产/社区发布四个 Tab 改为均分 4 列网格
- 分区标题增加品牌绿圆点前缀装饰
- 响应式断点:960px(侧边栏双列+内容区单列)、640px(全部单列+标签横向滚动)、420px(紧凑间距)

【画布网点背景】
- 移除 ReactFlow <Background> 组件,改用纯 CSS radial-gradient 圆点背景
- 通过 CSS 自定义属性(--canvas-bg-size/--canvas-bg-dot/--canvas-bg-x/--canvas-bg-y)实现缩放/平移时网点同步
- 网点颜色使用半透明灰蓝(rgba(148,163,184,0.34)),随画布缩放动态调整点间距与大小

【剧本评分色调统一】
- 变量 Token 体系重定义为电商同款暗色面板色调(--v5-bg: #0d0d0f, --v5-panel: #151719)
- 移除所有 box-shadow 和 depth 阴影,改用 inset 顶部光泽线
- 移除 backdrop-filter 毛玻璃效果,统一为纯色半透明背景
- hover 交互简化为边框+背景色变化,取消 transform 浮起动画
- 上传区移除 ::after 径向光晕伪元素
- 已上传态/选中态仅通过 border-color 和背景色微调区分
2026-06-04 13:16:38 +08:00
ludan b08a7918da feat: 剧本评分左侧面板滚动优化、电商克隆移动端适配、视觉细节精修
【剧本评分左侧面板滚动重构】
- 新增 script-eval-v5-left-main 滚动容器,上传区/AI信息/历史记录统一在容器内滚动
- 底部操作按钮(开始评测/导出报告)独立于滚动区外,始终可见可点击
- 历史评测列表增加 max-height 限制,超出区域内置滚动条
- 自定义窄滚动条(品牌绿半透明 thumb),保持视觉干净
- 短视口(≤760px/820px)压缩上传区和历史列表最小高度

【剧本评分视觉精修】
- 左侧面板增加渐变背景层次与分区微光分割线
- 上传区增加 ::after 伪元素径向光晕,hover 时品牌绿边框增强
- 已上传状态上传区增加绿色边框高亮(is-ready/is-complete)
- 底部操作栏背景层次加深,导出按钮 hover 增加绿色反馈
- 右侧面板增加底部径向渐变,上传引导卡标题提亮
- 顶部状态栏背景加深,模糊效果增强

【电商克隆移动端适配增强】
- 900px/620px/480px 三级断点增加顶部预留空间,避免与导航重叠
- Logo 区域定位从 sticky 改为 static,避免滚动时遮挡内容
- 设置面板在窄屏下调整内边距与边距

【Token 用量页精简】
- 移除指标卡片序号角标,保持卡片视觉简洁
2026-06-04 09:40:28 +08:00
9 changed files with 1886 additions and 223 deletions
+3 -5
View File
@@ -26,7 +26,6 @@
VideoCameraOutlined,
} from "@ant-design/icons";
import {
Background,
ReactFlow,
} from "@xyflow/react";
import { useCallback, useEffect, useMemo, useRef, useState, type ChangeEvent, type CSSProperties, type MouseEvent, type WheelEvent } from "react";
@@ -3542,7 +3541,8 @@ function CanvasPage({
onMouseMove={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handleCanvasMouseMove}
onWheel={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handleCanvasWheel}
style={{
"--canvas-bg-size": `${24 * canvasViewport.zoom}px`,
"--canvas-bg-size": `${34 * canvasViewport.zoom}px`,
"--canvas-bg-dot": `${1.35 * canvasViewport.zoom}px`,
"--canvas-bg-x": `${canvasViewport.x}px`,
"--canvas-bg-y": `${canvasViewport.y}px`,
cursor: canvasPanDrag ? "grabbing" : spacePanning ? "grab" : undefined,
@@ -3727,9 +3727,7 @@ function CanvasPage({
proOptions={{ hideAttribution: true }}
onPaneClick={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handlePaneClick}
onPaneContextMenu={(shouldShowEmptyProjectState || isWaitingForProjects) ? undefined : handlePaneContextMenu}
>
<Background gap={24} color="transparent" className="studio-canvas__background" />
</ReactFlow>
/>
<div className="studio-canvas-zoom-controls" onMouseDown={(e) => e.stopPropagation()}>
<button type="button" title="缩小" onClick={zoomCanvasOut}></button>
<button type="button" className="studio-canvas-zoom-controls__pct" title="重置缩放" onClick={resetCanvasZoom}>
+104 -25
View File
@@ -523,6 +523,12 @@ const formatUploadedImageRatio = (image?: CloneImageItem) => {
if (!image.width || !image.height) return `上传图片\u00a0\u00a0\u00a0原图比例${format}`;
return `上传图片 ${image.width}×${image.height}px\u00a0\u00a0\u00a0${formatAspectRatio(image.width, image.height)}${format}`;
};
const formatProductImageSpec = (image?: CloneImageItem | null) => {
if (!image) return "等待上传";
const format = image.format ? ` · ${image.format}` : "";
if (!image.width || !image.height) return `正在识别尺寸${format}`;
return `${image.width}×${image.height}px · ${formatAspectRatio(image.width, image.height)}${format}`;
};
const defaultMarketLanguageOption = marketLanguageOptions[0]!;
const normalizeMarket = (value: string) =>
marketLanguageOptions.some((option) => option.country === value) ? value : defaultMarketLanguageOption.country;
@@ -778,6 +784,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
const [selectedProductSetPreview, setSelectedProductSetPreview] = useState<{ src: string; label: string } | null>(null);
const [showHostingModal, setShowHostingModal] = useState(false);
const [productImages, setProductImages] = useState<CloneImageItem[]>([]);
const [selectedProductImageId, setSelectedProductImageId] = useState<string | null>(null);
const [isProductUploadDragging, setIsProductUploadDragging] = useState(false);
const [cloneOutput, setCloneOutput] = useState<CloneOutputKey>("detail");
const [openCloneBasicSelect, setOpenCloneBasicSelect] = useState<CloneBasicSelectKey | null>(null);
@@ -862,6 +869,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
const selectedProductSetOutput =
productSetOutputOptions.find((option) => option.key === productSetOutput) ?? productSetOutputOptions[0]!;
const selectedCloneOutput = cloneOutputOptions.find((option) => option.key === cloneOutput) ?? cloneOutputOptions[1]!;
const selectedProductImage = productImages.find((image) => image.id === selectedProductImageId) ?? productImages[0] ?? null;
const selectedProductImageIndex = selectedProductImage
? productImages.findIndex((image) => image.id === selectedProductImage.id)
: -1;
const selectedProductImageLabel = selectedProductImageIndex >= 0 ? `商品图 ${selectedProductImageIndex + 1}` : "商品图";
const selectedProductImageSpec = formatProductImageSpec(selectedProductImage);
const isProductImageLimitReached = productImages.length >= maxCloneProductImages;
const productSetPreviewReady = productSetStatus === "done";
const cloneSetTotal = Object.values(cloneSetCounts).reduce((sum, value) => sum + value, 0);
const canGenerateSet = setImages.length > 0 && productSetStatus !== "generating";
@@ -890,6 +904,30 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
});
};
useEffect(() => {
if (!productImages.length) {
if (selectedProductImageId !== null) setSelectedProductImageId(null);
return;
}
if (!selectedProductImageId || !productImages.some((image) => image.id === selectedProductImageId)) {
setSelectedProductImageId(productImages[0].id);
}
}, [productImages, selectedProductImageId]);
useEffect(() => {
productImages
.filter((item) => !item.width || !item.height)
.forEach((item) => {
readImageDimensions(item.src)
.then(({ width, height }) => {
setProductImages((current) =>
current.map((currentItem) => (currentItem.id === item.id ? { ...currentItem, width, height } : currentItem)),
);
})
.catch(() => undefined);
});
}, [productImages]);
const addSetImages = (files: File[]) => {
if (setImages.length >= 3) return;
const imageFiles = files.filter((file) => file.type.startsWith("image/"));
@@ -945,6 +983,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
const handleProductDrop = (event: DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsProductUploadDragging(false);
if (isProductImageLimitReached) return;
const files = Array.from(event.dataTransfer.files);
if (files.length) addProductImages(files);
};
@@ -1815,6 +1854,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
setSelectedProductSetPreview(null);
setShowHostingModal(false);
setProductImages([]);
setSelectedProductImageId(null);
setIsProductUploadDragging(false);
setCloneOutput("detail");
setRatio((current) => normalizeRatioForPlatform(platform, current, "detail"));
@@ -2061,18 +2101,24 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
</h2>
<div
role="button"
tabIndex={0}
className={`clone-ai-upload-zone${isProductUploadDragging ? " is-dragging" : ""}`}
onClick={() => productInputRef.current?.click()}
tabIndex={isProductImageLimitReached ? -1 : 0}
aria-disabled={isProductImageLimitReached}
className={`clone-ai-upload-zone${isProductUploadDragging ? " is-dragging" : ""}${isProductImageLimitReached ? " is-full" : ""}`}
onClick={() => {
if (isProductImageLimitReached) return;
productInputRef.current?.click();
}}
onKeyDown={(event) => {
if (event.target !== event.currentTarget) return;
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
if (isProductImageLimitReached) return;
productInputRef.current?.click();
}
}}
onDragEnter={(event) => {
event.preventDefault();
if (isProductImageLimitReached) return;
setIsProductUploadDragging(true);
}}
onDragOver={(event) => event.preventDefault()}
@@ -2085,35 +2131,68 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
</span>
<span className="clone-ai-upload-title"></span>
<strong>
<span aria-hidden="true">+</span>
{isProductImageLimitReached ? (
"已达上限"
) : (
<>
<span aria-hidden="true">+</span>
</>
)}
</strong>
<span className="clone-ai-upload-hint"> 7 </span>
</div>
{productImages.length ? (
<div className="clone-ai-uploaded-files" aria-label="已上传商品原图">
{productImages.map((item) => (
<figure key={item.id} className="clone-ai-uploaded-file">
<img src={item.src} alt={item.name} />
<span className="uploaded-image-zoom" aria-hidden="true">
<img src={item.src} alt="" />
</span>
<button
type="button"
onClick={(event) => {
event.stopPropagation();
removeProductImage(item.id);
}}
aria-label={`删除${item.name}`}
>
<CloseOutlined />
</button>
</figure>
))}
<div className="clone-ai-upload-preview-wrap" onClick={(event) => event.stopPropagation()} aria-live="polite">
<div className="clone-ai-upload-preview">
<img src={selectedProductImage?.src ?? productImages[0].src} alt={`当前预览:${selectedProductImageLabel}`} />
</div>
<div className="clone-ai-upload-preview__meta">
<span>
<b>{selectedProductImageLabel}</b>
<em title={selectedProductImage?.name ?? productImages[0].name}>{selectedProductImageSpec}</em>
</span>
</div>
</div>
) : null}
{productImages.length ? (
<div className="clone-ai-uploaded-stack">
<div className="clone-ai-uploaded-head">
<span></span>
<b>{productImages.length}/{maxCloneProductImages}</b>
</div>
<div className="clone-ai-uploaded-files" aria-label="已上传商品原图">
{productImages.map((item, index) => (
<figure key={item.id} className={`clone-ai-uploaded-file${item.id === selectedProductImage?.id ? " is-active" : ""}`}>
<button
type="button"
className="clone-ai-uploaded-file__thumb"
onClick={(event) => {
event.stopPropagation();
setSelectedProductImageId(item.id);
}}
aria-label={`预览商品图 ${index + 1}`}
>
<img src={item.src} alt={`商品图 ${index + 1}`} />
<span>{index + 1}</span>
</button>
<button
type="button"
onClick={(event) => {
event.stopPropagation();
removeProductImage(item.id);
}}
aria-label={`删除商品图 ${index + 1}`}
>
<CloseOutlined />
</button>
</figure>
))}
</div>
</div>
) : null}
</div>
<input ref={productInputRef} type="file" accept="image/*" multiple onChange={handleProductUpload} />
<input ref={productInputRef} type="file" accept="image/*" multiple disabled={isProductImageLimitReached} onChange={handleProductUpload} />
</section>
<section className="clone-ai-card">
+130 -83
View File
@@ -5,10 +5,13 @@ import {
CloseOutlined,
DeleteOutlined,
EditOutlined,
FileImageOutlined,
FolderOpenOutlined,
LockOutlined,
MailOutlined,
MobileOutlined,
PhoneOutlined,
PlayCircleOutlined,
PlusOutlined,
SafetyOutlined,
ShareAltOutlined,
@@ -179,6 +182,19 @@ function formatAssetStatus(status: string | undefined): string {
return status || "资产";
}
function formatAssetType(type: SavedAssetItem["type"]): string {
const labels: Record<string, string> = {
character: "角色",
scene: "场景",
prop: "道具",
video: "视频",
image: "图像",
asset: "资产",
other: "素材",
};
return labels[type] || "素材";
}
function ProfilePage({
session,
usage,
@@ -527,20 +543,48 @@ function ProfilePage({
</div>
);
const renderCardPreview = (
url: string | null | undefined,
type: "image" | "video" | "project" | "asset",
label: string,
) => {
const mediaUrl = typeof url === "string" ? url.trim() : "";
const isVideoPreview = type === "video" || /\.(mp4|webm|mov)(\?|#|$)/i.test(mediaUrl);
const placeholderIcon =
type === "video" ? <PlayCircleOutlined /> : type === "project" ? <FolderOpenOutlined /> : <FileImageOutlined />;
return (
<div className={`profile-page__list-card-preview${mediaUrl ? " has-media" : ""}`} aria-hidden="true">
{mediaUrl ? (
isVideoPreview ? (
<video src={mediaUrl} muted playsInline preload="metadata" />
) : (
<img src={mediaUrl} alt="" loading="lazy" />
)
) : (
<span className="profile-page__list-card-placeholder">{placeholderIcon}</span>
)}
<span className="profile-page__media-badge">{label}</span>
</div>
);
};
const renderActivePanel = () => {
if (activePanel === "works") {
return visibleWorks.length ? (
<div className="profile-page__list-grid motion-stagger">
{visibleWorks.map((task) => (
<article key={task.id} className="profile-page__list-card">
<div className="profile-page__list-card-head">
<strong>{task.title}</strong>
<span>{formatTaskType(task.type)}</span>
</div>
<p>{task.prompt}</p>
<div className="profile-page__list-card-meta">
<span>{formatTaskStatus(task.status)}</span>
<span>{formatProfileDate(task.createdAt)}</span>
<article key={task.id} className="profile-page__list-card profile-page__media-card">
{renderCardPreview(task.outputUrl, task.type === "video" ? "video" : "image", formatTaskType(task.type))}
<div className="profile-page__list-card-body">
<div className="profile-page__list-card-head">
<strong>{task.title}</strong>
</div>
<p>{task.prompt}</p>
<div className="profile-page__list-card-meta">
<span>{formatTaskStatus(task.status)}</span>
<span>{formatProfileDate(task.createdAt)}</span>
</div>
</div>
</article>
))}
@@ -554,25 +598,27 @@ function ProfilePage({
return projects.length ? (
<div className="profile-page__list-grid motion-stagger">
{projects.map((project) => (
<article key={project.id} className="profile-page__list-card">
<div className="profile-page__list-card-head">
<strong>{project.name}</strong>
<span>{formatProfileDate(project.updatedAt)}</span>
{onDeleteProject ? (
<button
type="button"
className="profile-page__delete-project"
aria-label={`删除项目 ${project.name}`}
onClick={() => onDeleteProject(project)}
>
<DeleteOutlined />
</button>
) : null}
</div>
<p>{project.description || "最近更新的项目"}</p>
<div className="profile-page__list-card-meta">
<span>{project.storyboardCount} </span>
<span>{project.imageCount} / {project.videoCount} </span>
<article key={project.id} className="profile-page__list-card profile-page__media-card">
{renderCardPreview(project.thumbnailUrl, "project", "项目")}
<div className="profile-page__list-card-body">
<div className="profile-page__list-card-head">
<strong>{project.name}</strong>
{onDeleteProject ? (
<button
type="button"
className="profile-page__delete-project"
aria-label={`删除项目 ${project.name}`}
onClick={() => onDeleteProject(project)}
>
<DeleteOutlined />
</button>
) : null}
</div>
<p>{project.description || "最近更新的项目"}</p>
<div className="profile-page__list-card-meta">
<span>{project.storyboardCount} </span>
<span>{formatProfileDate(project.updatedAt)}</span>
</div>
</div>
</article>
))}
@@ -586,15 +632,18 @@ function ProfilePage({
return savedAssets.length ? (
<div className="profile-page__list-grid">
{savedAssets.map((asset) => (
<article key={asset.id} className="profile-page__list-card">
<div className="profile-page__list-card-head">
<strong>{asset.name}</strong>
<span>{formatAssetStatus(asset.status)}</span>
</div>
<p>{asset.description}</p>
<div className="profile-page__list-card-meta">
<span>{asset.type}</span>
<span>{formatProfileDate(asset.updatedAt)}</span>
<article key={asset.id} className="profile-page__list-card profile-page__media-card">
{renderCardPreview(asset.imageUrl || asset.url, asset.type === "video" ? "video" : "asset", formatAssetType(asset.type))}
<div className="profile-page__list-card-body">
<div className="profile-page__list-card-head">
<strong>{asset.name}</strong>
<span>{formatAssetStatus(asset.status)}</span>
</div>
<p>{asset.description}</p>
<div className="profile-page__list-card-meta">
<span>{formatAssetType(asset.type)}</span>
<span>{formatProfileDate(asset.updatedAt)}</span>
</div>
</div>
</article>
))}
@@ -708,6 +757,50 @@ function ProfilePage({
</div>
</div>
<div className="profile-page__account-card">
<div className="profile-page__list-tabs">
<button
type="button"
className={accountPanel === "credits" ? "is-active" : ""}
onClick={() => setAccountPanel("credits")}
>
{(totalBalance / 100).toFixed(2)}
</button>
<button
type="button"
className={accountPanel === "tasks" ? "is-active" : ""}
onClick={() => setAccountPanel("tasks")}
>
{tasks.length}
</button>
</div>
<div className="profile-page__upload-card profile-page__upload-card--meta">
{accountPanel === "credits" ? (
<>
<span className="profile-page__meta-item">
<small></small>
<strong>{displayName}</strong>
</span>
<span className="profile-page__meta-item">
<small></small>
<strong>{(usage.balanceCents / 100).toFixed(2)}</strong>
</span>
</>
) : (
<>
<span className="profile-page__meta-item">
<small></small>
<strong>{tasks.length}</strong>
</span>
<span className="profile-page__meta-item">
<small></small>
<strong>{completedTasks.length}</strong>
</span>
</>
)}
</div>
</div>
<button type="button" className="profile-page__share-btn profile-page__share-btn--plan">
<ShareAltOutlined />
{packageLabel}
@@ -755,52 +848,6 @@ function ProfilePage({
</span>
{renderActivePanel()}
</div>
<div className="profile-page__section">
<div className="profile-page__list-bar">
<div className="profile-page__list-tabs">
<button
type="button"
className={accountPanel === "credits" ? "is-active" : ""}
onClick={() => setAccountPanel("credits")}
>
{(totalBalance / 100).toFixed(2)}
</button>
<button
type="button"
className={accountPanel === "tasks" ? "is-active" : ""}
onClick={() => setAccountPanel("tasks")}
>
{tasks.length}
</button>
</div>
</div>
<div className="profile-page__upload-card profile-page__upload-card--meta">
{accountPanel === "credits" ? (
<>
<span className="profile-page__meta-item">
<small></small>
<strong>{displayName}</strong>
</span>
<span className="profile-page__meta-item">
<small></small>
<strong>{(usage.balanceCents / 100).toFixed(2)}</strong>
</span>
</>
) : (
<>
<span className="profile-page__meta-item">
<small></small>
<strong>{tasks.length}</strong>
</span>
<span className="profile-page__meta-item">
<small></small>
<strong>{completedTasks.length}</strong>
</span>
</>
)}
</div>
</div>
</main>
</div>
</section>
+97 -95
View File
@@ -362,109 +362,111 @@ function ScriptTokensPage() {
<div className="script-eval-v5-page">
{/* Left Panel */}
<aside className="script-eval-v5-left">
<div className="script-eval-v5-lp-section">
<div className="script-eval-v5-lp-label"></div>
<div
className="script-eval-v5-upload-zone"
role="button"
tabIndex={0}
onClick={() => fileInputRef.current?.click()}
onKeyDown={uploadKeyDown}
>
{uploadedFile ? (
<div className="script-eval-v5-upload-done is-show">
<CheckCircleFilled />
<span className="script-eval-v5-uf-meta">
<span className="script-eval-v5-uf-name">{uploadedFile.name}</span>
<span className="script-eval-v5-uf-size">{formatFileSize(uploadedFile.size)}</span>
</span>
<span className="script-eval-v5-uf-re" onClick={(e) => { e.stopPropagation(); handleReset(); }}>
</span>
</div>
) : (
<>
<div className="script-eval-v5-upload-icon"><UploadOutlined /></div>
<div className="script-eval-v5-upload-text"></div>
<button type="button" className="script-eval-v5-upload-btn" onClick={(e) => { e.stopPropagation(); fileInputRef.current?.click(); }}>
<UploadOutlined />
</button>
<div className="script-eval-v5-upload-hint">{TEXT_FILE_HINT}</div>
</>
)}
<div className="script-eval-v5-left-main">
<div className="script-eval-v5-lp-section">
<div className="script-eval-v5-lp-label"></div>
<div
className="script-eval-v5-upload-zone"
role="button"
tabIndex={0}
onClick={() => fileInputRef.current?.click()}
onKeyDown={uploadKeyDown}
>
{uploadedFile ? (
<div className="script-eval-v5-upload-done is-show">
<CheckCircleFilled />
<span className="script-eval-v5-uf-meta">
<span className="script-eval-v5-uf-name">{uploadedFile.name}</span>
<span className="script-eval-v5-uf-size">{formatFileSize(uploadedFile.size)}</span>
</span>
<span className="script-eval-v5-uf-re" onClick={(e) => { e.stopPropagation(); handleReset(); }}>
</span>
</div>
) : (
<>
<div className="script-eval-v5-upload-icon"><UploadOutlined /></div>
<div className="script-eval-v5-upload-text"></div>
<button type="button" className="script-eval-v5-upload-btn" onClick={(e) => { e.stopPropagation(); fileInputRef.current?.click(); }}>
<UploadOutlined />
</button>
<div className="script-eval-v5-upload-hint">{TEXT_FILE_HINT}</div>
</>
)}
</div>
<input ref={fileInputRef} type="file" accept={TEXT_FILE_ACCEPT} style={{ display: "none" }} onChange={handleFileUpload} />
</div>
<input ref={fileInputRef} type="file" accept={TEXT_FILE_ACCEPT} style={{ display: "none" }} onChange={handleFileUpload} />
</div>
<div className="script-eval-v5-lp-section">
<div className="script-eval-v5-lp-label">AI </div>
<div className="script-eval-v5-info-grid">
{!result ? (
<div className="script-eval-v5-info-empty"></div>
) : (
<>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val"><span className="script-eval-v5-info-tag">{result.totalScore} · {grade}</span></span>
</div>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val">{script.length} </span>
</div>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val">{new Date().toLocaleDateString("zh-CN")}</span>
</div>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val">{beatPct}%</span>
</div>
</>
)}
<div className="script-eval-v5-lp-section">
<div className="script-eval-v5-lp-label">AI </div>
<div className="script-eval-v5-info-grid">
{!result ? (
<div className="script-eval-v5-info-empty"></div>
) : (
<>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val"><span className="script-eval-v5-info-tag">{result.totalScore} · {grade}</span></span>
</div>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val">{script.length} </span>
</div>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val">{new Date().toLocaleDateString("zh-CN")}</span>
</div>
<div className="script-eval-v5-info-item">
<span className="script-eval-v5-info-key"></span>
<span className="script-eval-v5-info-val">{beatPct}%</span>
</div>
</>
)}
</div>
</div>
</div>
<div className="script-eval-v5-lp-section is-fill">
<div className="script-eval-v5-lp-label"></div>
<div className="script-eval-v5-history-list">
{!session ? (
<div className="script-eval-v5-history-empty"></div>
) : history.length === 0 ? (
<div className="script-eval-v5-history-empty"></div>
) : (
history.map((item, i) => (
<div key={i} className={`script-eval-v5-history-item${i === 0 ? " is-active" : ""}`}>
<div className="script-eval-v5-hi-left">
<div className="script-eval-v5-hi-name">{item.name}</div>
<div className="script-eval-v5-hi-date">{item.date}</div>
<div className="script-eval-v5-hi-bar">
<div className="script-eval-v5-hi-bar-fill" style={{ width: `${Math.min(92, (item.score / 100) * 100)}%` }} />
<div className="script-eval-v5-lp-section is-fill">
<div className="script-eval-v5-lp-label"></div>
<div className="script-eval-v5-history-list">
{!session ? (
<div className="script-eval-v5-history-empty"></div>
) : history.length === 0 ? (
<div className="script-eval-v5-history-empty"></div>
) : (
history.map((item, i) => (
<div key={i} className={`script-eval-v5-history-item${i === 0 ? " is-active" : ""}`}>
<div className="script-eval-v5-hi-left">
<div className="script-eval-v5-hi-name">{item.name}</div>
<div className="script-eval-v5-hi-date">{item.date}</div>
<div className="script-eval-v5-hi-bar">
<div className="script-eval-v5-hi-bar-fill" style={{ width: `${Math.min(92, (item.score / 100) * 100)}%` }} />
</div>
</div>
<div className="script-eval-v5-hi-right">
<div className={`script-eval-v5-hi-score${item.score >= 90 ? " is-green" : ""}`}>{item.score}</div>
<div className="script-eval-v5-hi-grade">{item.grade}</div>
</div>
</div>
<div className="script-eval-v5-hi-right">
<div className={`script-eval-v5-hi-score${item.score >= 90 ? " is-green" : ""}`}>{item.score}</div>
<div className="script-eval-v5-hi-grade">{item.grade}</div>
</div>
</div>
))
)}
))
)}
</div>
</div>
</div>
<div className="script-eval-v5-lp-bottom">
<button
type="button"
className="script-eval-v5-eval-btn"
disabled={loading || !hasContent}
onClick={() => void handleEvaluate()}
>
{loading ? <LoadingOutlined /> : <ThunderboltOutlined />}
<span>{loading ? "评测中..." : "开始评测"}</span>
</button>
<button type="button" className="script-eval-v5-export-btn" disabled={!result} onClick={handleExportMarkdown}>
<DownloadOutlined />
<span></span>
</button>
<div className="script-eval-v5-lp-bottom">
<button
type="button"
className="script-eval-v5-eval-btn"
disabled={loading || !hasContent}
onClick={() => void handleEvaluate()}
>
{loading ? <LoadingOutlined /> : <ThunderboltOutlined />}
<span>{loading ? "评测中..." : "开始评测"}</span>
</button>
<button type="button" className="script-eval-v5-export-btn" disabled={!result} onClick={handleExportMarkdown}>
<DownloadOutlined />
<span></span>
</button>
</div>
</div>
</aside>
@@ -277,9 +277,8 @@ function TokenUsagePage({
) : null}
<section className="management-metric-cards" aria-label="关键指标">
{metricCards.map((card, index) => (
{metricCards.map((card) => (
<article key={card.key} className={`management-metric-card is-${card.tone}`}>
<span className="management-metric-card__index">{String(index + 1).padStart(2, "0")}</span>
<span className="management-metric-card__label">{card.label}</span>
<strong className="management-metric-card__value">{card.value}</strong>
<span className="management-metric-card__hint">{card.hint}</span>
@@ -3,6 +3,24 @@ import type { ReactNode } from "react";
import type { WorkbenchOption, WorkbenchFieldGroup } from "./workbenchConstants";
import { getRatioOptionClassName, getSettingsGridColumnsClassName } from "./workbenchReferenceUtils";
const VIDEO_MODEL_ICON_URLS = {
happyHorse: "https://stringtest.oss-cn-hangzhou.aliyuncs.com/static/model-icons/HappyHorse.svg",
pixverse: "https://stringtest.oss-cn-hangzhou.aliyuncs.com/static/model-icons/Pixverse.svg",
vidu: "https://stringtest.oss-cn-hangzhou.aliyuncs.com/static/model-icons/viduQ3.svg",
wanxiang: "https://stringtest.oss-cn-hangzhou.aliyuncs.com/static/model-icons/wan.svg",
kling: "https://stringtest.oss-cn-hangzhou.aliyuncs.com/static/model-icons/kling.svg",
} as const;
function getVideoModelIconUrl(option: WorkbenchOption): string | null {
const text = `${option.value} ${option.label}`.toLowerCase();
if (text.includes("happyhorse")) return VIDEO_MODEL_ICON_URLS.happyHorse;
if (text.includes("pixverse")) return VIDEO_MODEL_ICON_URLS.pixverse;
if (text.includes("vidu")) return VIDEO_MODEL_ICON_URLS.vidu;
if (text.includes("wan") || text.includes("万相")) return VIDEO_MODEL_ICON_URLS.wanxiang;
if (text.includes("kling") || text.includes("可灵")) return VIDEO_MODEL_ICON_URLS.kling;
return null;
}
export function SelectChip({
chipId,
value,
@@ -56,6 +74,7 @@ export function SelectChip({
>
{options.map((option, index) => {
const active = option.value === value;
const iconUrl = chipId === "video-model" ? getVideoModelIconUrl(option) : null;
return (
<button
key={option.value}
@@ -71,6 +90,11 @@ export function SelectChip({
>
<span className="ai-workbench-select-chip__option-label">
<span className="ai-workbench-select-chip__option-dot" aria-hidden="true" />
{iconUrl ? (
<span className="ai-workbench-select-chip__option-icon" aria-hidden="true">
<img src={iconUrl} alt="" loading="lazy" />
</span>
) : null}
<span className="ai-workbench-select-chip__option-copy">
<span className="ai-workbench-select-chip__option-title">
<span>{option.label}</span>
@@ -261,4 +285,4 @@ export function InlineOptionChip({
) : null}
</div>
);
}
}
+329 -5
View File
@@ -1157,6 +1157,25 @@
background: #202c28;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone.is-full {
cursor: default;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone.is-full strong {
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.08);
color: #aeb8c4;
box-shadow: none;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone.is-full:hover {
border-color: rgba(255, 255, 255, 0.16);
background:
radial-gradient(circle at 50% 0%, rgba(var(--ecm-accent-rgb), 0.09), transparent 58%),
var(--ecm-inset);
transform: none;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:active {
transform: scale(0.98);
}
@@ -1274,6 +1293,27 @@
transform: scale(0.92);
}
.product-clone-page[data-tool="clone"] .clone-ai-card,
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone,
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-files {
position: relative;
overflow: visible;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone {
z-index: 8;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-uploaded-file:hover),
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-uploaded-file:focus-within) {
z-index: 90;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file:hover,
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file:focus-within {
z-index: 95;
}
.product-clone-page[data-tool="clone"] .clone-ai-settings-section {
display: grid;
gap: 8px;
@@ -3096,7 +3136,7 @@
.uploaded-image-zoom {
position: absolute;
z-index: 70;
z-index: 220;
left: 50%;
bottom: calc(100% + 10px);
display: block;
@@ -3117,6 +3157,18 @@
visibility: hidden;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file .uploaded-image-zoom {
left: 0;
bottom: calc(100% + 12px);
width: min(240px, 58vw);
transform: translate(0, 8px) scale(0.96);
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file:hover .uploaded-image-zoom,
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file:focus-within .uploaded-image-zoom {
transform: translate(0, 0) scale(1);
}
.uploaded-image-zoom img {
display: block;
width: 100%;
@@ -3139,6 +3191,233 @@
visibility: visible;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-upload-preview-wrap) {
align-content: start;
justify-items: stretch;
gap: 10px;
min-height: 0;
padding: 12px;
text-align: left;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-upload-preview-wrap) .clone-ai-upload-main {
grid-template-columns: 34px minmax(0, 1fr) auto;
width: 100%;
align-items: center;
justify-items: start;
gap: 4px 9px;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-upload-preview-wrap) .clone-ai-upload-icon {
grid-row: span 2;
width: 34px;
height: 34px;
border-radius: 10px;
font-size: 16px;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-upload-preview-wrap) .clone-ai-upload-title {
min-width: 0;
color: #c9d2dd;
font-size: 12px;
line-height: 1.2;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-upload-preview-wrap) strong {
grid-row: span 2;
min-width: 96px;
height: 34px;
padding: 0 12px;
font-size: 12px;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone:has(.clone-ai-upload-preview-wrap) .clone-ai-upload-hint {
grid-column: 2;
min-width: 0;
font-size: 10px;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview-wrap {
display: grid;
gap: 7px;
min-width: 0;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview {
position: relative;
display: grid;
width: 100%;
min-height: 126px;
overflow: hidden;
border: 1px solid rgba(var(--ecm-accent-rgb), 0.2);
border-radius: 10px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.04), transparent 48%),
rgba(8, 10, 12, 0.56);
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview img {
display: block;
width: 100%;
height: 126px;
object-fit: contain;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview__meta {
display: flex;
min-width: 0;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 0 2px;
color: #eef2f6;
text-align: left;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview__meta span {
display: grid;
min-width: 0;
gap: 1px;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview__meta b,
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview__meta em {
display: block;
overflow: hidden;
max-width: 260px;
text-overflow: ellipsis;
white-space: nowrap;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview__meta b {
color: var(--ecm-accent);
font-size: 10px;
font-style: normal;
font-weight: 900;
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-preview__meta em {
color: #aeb8c4;
font-size: 10px;
font-style: normal;
font-weight: 700;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-files {
display: flex;
flex-wrap: wrap;
gap: 7px;
margin-top: 0;
padding-top: 2px;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-stack {
display: grid;
gap: 7px;
min-width: 0;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-head {
display: flex;
min-width: 0;
align-items: center;
justify-content: space-between;
gap: 8px;
color: #768292;
font-size: 10px;
font-weight: 900;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-head span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-head b {
flex: 0 0 auto;
padding: 2px 7px;
border: 1px solid rgba(var(--ecm-accent-rgb), 0.18);
border-radius: 999px;
background: rgba(var(--ecm-accent-rgb), 0.07);
color: var(--ecm-accent);
font-size: 10px;
line-height: 1.4;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file {
width: 46px;
height: 46px;
overflow: hidden;
border-color: rgba(255, 255, 255, 0.12);
border-radius: 9px;
background: rgba(255, 255, 255, 0.035);
transition:
border-color 160ms ease,
box-shadow 160ms ease,
transform 160ms ease;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file > button:not(.clone-ai-uploaded-file__thumb) {
top: 2px;
right: 2px;
width: 16px;
height: 16px;
background: rgba(8, 10, 12, 0.82);
color: #fff;
font-size: 9px;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file.is-active {
border-color: rgba(var(--ecm-accent-rgb), 0.86);
box-shadow: 0 0 0 2px rgba(var(--ecm-accent-rgb), 0.12);
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file .clone-ai-uploaded-file__thumb {
position: static;
inset: auto;
display: block;
width: 100%;
height: 100%;
padding: 0;
border: 0;
border-radius: inherit;
background: transparent;
color: inherit;
cursor: pointer;
font-size: inherit;
opacity: 1;
transform: none;
transition: none;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file .clone-ai-uploaded-file__thumb img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file__thumb span {
position: absolute;
left: 3px;
bottom: 3px;
min-width: 14px;
height: 14px;
border-radius: 999px;
background: rgba(8, 10, 12, 0.76);
color: #eef2f6;
font-size: 9px;
font-weight: 900;
line-height: 14px;
text-align: center;
}
.product-clone-page[data-tool="clone"] .clone-ai-uploaded-file:hover {
border-color: rgba(var(--ecm-accent-rgb), 0.62);
transform: translateY(-1px);
}
@keyframes image-mention-menu-rise {
from {
opacity: 0;
@@ -8008,9 +8287,8 @@
}
.product-clone-page[data-tool="clone"] .clone-ai-logo {
position: sticky;
top: 0;
z-index: 3;
position: static;
z-index: auto;
margin: -18px -18px 2px;
padding: 16px 18px 14px;
border-bottom-color: var(--ecm-line);
@@ -8158,6 +8436,13 @@
box-shadow: 0 10px 28px rgba(var(--ecm-accent-rgb), 0.18);
}
.product-clone-page[data-tool="clone"] .clone-ai-upload-zone.is-full strong {
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.08);
color: #aeb8c4;
box-shadow: none;
}
.product-clone-page[data-tool="clone"] :is(.clone-ai-generate:hover:not(:disabled), .clone-ai-send-button:hover:not(:disabled)) {
filter: brightness(1.03);
transform: translateY(-1px);
@@ -8513,7 +8798,7 @@
}
.product-clone-page[data-tool="clone"] .clone-ai-logo {
margin: -14px -14px 0;
margin: 0;
padding: 14px 54px 12px 14px;
}
@@ -8792,3 +9077,42 @@
padding-top: 14px;
}
}
/* Mobile clone header alignment: keep the tool title in normal flow, but attach it to the top nav rhythm. */
@media (max-width: 900px) {
.product-clone-page[data-tool="clone"] {
padding-top: 59px;
}
.product-clone-page[data-tool="clone"] > .product-clone-shell {
min-height: calc(100% - 59px);
}
.product-clone-page[data-tool="clone"] .clone-ai-panel {
padding-top: 0;
}
.product-clone-page[data-tool="clone"] .clone-ai-logo {
margin: 0 -18px 2px;
}
}
@media (max-width: 620px) {
.product-clone-page[data-tool="clone"] .clone-ai-panel {
padding: 0 14px 14px;
}
.product-clone-page[data-tool="clone"] .clone-ai-logo {
margin: 0 -14px 0;
}
}
@media (max-width: 480px) {
.product-clone-page[data-tool="clone"] {
padding-top: 59px;
}
.product-clone-page[data-tool="clone"] > .product-clone-shell {
min-height: calc(100% - 59px);
}
}
+508
View File
@@ -3421,3 +3421,511 @@
font-size: 13px;
}
}
/* Script review left panel overflow guard: keep actions available while history remains scrollable. */
.script-eval-v5-left {
overflow: hidden;
}
.script-eval-v5-left-main {
display: flex;
flex: 1 1 auto;
flex-direction: column;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: rgb(0 255 136 / 35%) transparent;
}
.script-eval-v5-left-main::-webkit-scrollbar,
.script-eval-v5-history-list::-webkit-scrollbar {
width: 6px;
}
.script-eval-v5-left-main::-webkit-scrollbar-track,
.script-eval-v5-history-list::-webkit-scrollbar-track {
background: transparent;
}
.script-eval-v5-left-main::-webkit-scrollbar-thumb,
.script-eval-v5-history-list::-webkit-scrollbar-thumb {
border-radius: 999px;
background: rgb(0 255 136 / 28%);
}
.script-eval-v5-left-main .script-eval-v5-lp-section.is-fill {
flex: 0 0 auto;
min-height: 210px;
}
.script-eval-v5-left-main .script-eval-v5-history-list {
min-height: 128px;
max-height: clamp(160px, 28vh, 300px);
overflow-y: auto;
}
.script-eval-v5-lp-bottom {
position: static;
z-index: auto;
flex-shrink: 0;
margin-top: 0;
}
@media (max-height: 820px) and (min-width: 901px) {
.script-eval-v5-left-main .script-eval-v5-lp-section.is-fill {
flex-basis: auto;
min-height: 190px;
}
.script-eval-v5-left-main .script-eval-v5-history-list {
min-height: 118px;
max-height: clamp(142px, 23vh, 220px);
}
}
@media (max-width: 900px) {
.script-eval-v5-left-main {
overscroll-behavior: contain;
}
}
@media (max-width: 680px) {
.script-eval-v5-left {
overflow: visible;
}
.script-eval-v5-left-main {
flex: 0 0 auto;
overflow: visible;
}
.script-eval-v5-left-main .script-eval-v5-lp-section.is-fill {
min-height: 224px;
}
.script-eval-v5-left-main .script-eval-v5-history-list {
min-height: 132px;
max-height: min(260px, 42vh);
}
.script-eval-v5-history-empty {
min-height: 118px;
}
}
/* Final commercial polish for the script scoring workspace. */
.script-eval-v5 {
background:
radial-gradient(circle at 12% 0%, rgb(0 255 136 / 5%), transparent 28%),
linear-gradient(180deg, #0d1010 0%, #090b0b 100%);
}
.script-eval-v5-page {
background:
linear-gradient(90deg, rgb(0 255 136 / 4%), transparent 24%),
linear-gradient(180deg, rgb(255 255 255 / 1.8%), transparent 180px);
}
.script-eval-v5-left {
background:
linear-gradient(180deg, rgb(255 255 255 / 4%), transparent 180px),
linear-gradient(90deg, rgb(0 255 136 / 4%), transparent 32%),
var(--v5-panel);
}
.script-eval-v5-left-main {
scroll-padding-block: 18px;
}
.script-eval-v5-left-main .script-eval-v5-lp-section {
flex-shrink: 0;
padding-inline: 22px;
background:
linear-gradient(180deg, rgb(255 255 255 / 1.8%), transparent 80px);
}
.script-eval-v5-left-main .script-eval-v5-lp-section + .script-eval-v5-lp-section {
box-shadow: inset 0 1px 0 rgb(255 255 255 / 2.5%);
}
.script-eval-v5-lp-label {
color: #91a09b;
}
.script-eval-v5-upload-zone {
display: grid;
place-items: center;
overflow: hidden;
isolation: isolate;
}
.script-eval-v5-upload-zone::after {
content: "";
position: absolute;
inset: 1px;
z-index: -1;
border-radius: inherit;
background:
radial-gradient(circle at 50% 18%, rgb(0 255 136 / 11%), transparent 38%),
linear-gradient(180deg, rgb(255 255 255 / 2%), transparent 60%);
opacity: 0.78;
pointer-events: none;
}
.script-eval-v5-upload-zone:focus-visible {
outline: 2px solid rgb(0 255 136 / 42%);
outline-offset: 3px;
}
.script-eval-v5.is-ready .script-eval-v5-upload-zone,
.script-eval-v5.is-complete .script-eval-v5-upload-zone {
border-color: rgb(0 255 136 / 28%);
background:
linear-gradient(180deg, rgb(0 255 136 / 8%), rgb(255 255 255 / 2.5%)),
rgb(255 255 255 / 2.8%);
}
.script-eval-v5-upload-done {
width: min(100%, 320px);
padding: 14px 14px;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 8%);
}
.script-eval-v5-info-grid {
display: grid;
grid-template-columns: 1fr;
}
.script-eval-v5-info-item {
min-height: 42px;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 3%);
}
.script-eval-v5-info-empty,
.script-eval-v5-history-empty {
color: #82918c;
background:
linear-gradient(180deg, rgb(255 255 255 / 3.2%), rgb(255 255 255 / 1.8%));
}
.script-eval-v5-left-main .script-eval-v5-lp-section.is-fill {
background:
linear-gradient(180deg, rgb(0 255 136 / 3.4%), transparent 92px),
linear-gradient(180deg, rgb(255 255 255 / 1.8%), transparent);
}
.script-eval-v5-history-list {
padding: 2px 8px 2px 0;
}
.script-eval-v5-history-item {
min-height: 68px;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 3%);
}
.script-eval-v5-lp-bottom {
padding: 18px 22px 22px;
background:
linear-gradient(180deg, rgb(255 255 255 / 2.2%), transparent 60px),
#111414;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 3.5%);
}
.script-eval-v5-export-btn {
border-color: rgb(255 255 255 / 7%);
background:
linear-gradient(180deg, rgb(255 255 255 / 3.5%), rgb(255 255 255 / 1.8%)),
#111414;
color: #7f8d88;
}
.script-eval-v5-export-btn:not(:disabled):hover {
border-color: rgb(0 255 136 / 22%);
color: #c7d5d0;
background:
linear-gradient(180deg, rgb(0 255 136 / 8%), rgb(255 255 255 / 2%)),
#111414;
}
.script-eval-v5-eval-btn:disabled,
.script-eval-v5-export-btn:disabled {
opacity: 0.48;
cursor: not-allowed;
}
.script-eval-v5-right-topbar {
backdrop-filter: blur(14px);
background:
linear-gradient(180deg, rgb(18 22 21 / 92%), rgb(12 14 14 / 88%));
}
.script-eval-v5-right-content:not(.is-report) {
background:
radial-gradient(circle at 50% 43%, rgb(0 255 136 / 5%), transparent 32%),
linear-gradient(180deg, transparent, rgb(0 0 0 / 12%));
}
.script-eval-v5-upload-card-title {
color: #f0fff8;
}
.script-eval-v5-upload-card-desc {
max-width: 540px;
color: #96a5a0;
}
.script-eval-v5-statusbar {
background:
linear-gradient(180deg, rgb(17 20 20 / 84%), rgb(10 12 12 / 92%));
}
@media (max-height: 760px) and (min-width: 901px) {
.script-eval-v5-left-main .script-eval-v5-lp-section {
padding-block: 12px;
}
.script-eval-v5-upload-zone {
min-height: 156px;
}
.script-eval-v5-left-main .script-eval-v5-lp-section.is-fill {
min-height: 176px;
}
.script-eval-v5-left-main .script-eval-v5-history-list {
min-height: 110px;
}
}
@media (max-width: 680px) {
.script-eval-v5-left-main .script-eval-v5-lp-section {
padding-inline: 16px;
}
.script-eval-v5-upload-zone {
min-height: 164px;
}
.script-eval-v5-lp-bottom {
padding: 14px 16px 18px;
}
.script-eval-v5-right-content:not(.is-report) {
padding-top: 22px;
}
}
/* Ecommerce-aligned tone pass: restrained dark SaaS surfaces, no depth shadows. */
.script-eval-v5 {
--v5-bg: #0d0d0f;
--v5-bg2: #151719;
--v5-bg3: #181b1d;
--v5-bg4: #1d2022;
--v5-bg5: #222629;
--v5-border: rgba(255, 255, 255, 0.08);
--v5-border2: rgba(255, 255, 255, 0.12);
--v5-panel: #151719;
--v5-panel-2: #181b1d;
--v5-panel-3: #101214;
--v5-line: rgba(255, 255, 255, 0.08);
--v5-line-strong: rgba(0, 255, 136, 0.24);
--v5-green-deep: rgba(0, 255, 136, 0.055);
--v5-green-soft: rgba(0, 255, 136, 0.09);
--v5-green-border: rgba(0, 255, 136, 0.24);
--v5-shadow-soft: none;
--v5-shadow-tight: none;
background:
radial-gradient(circle at 24% 0%, rgba(0, 255, 136, 0.038), transparent 34%),
linear-gradient(180deg, rgba(255, 255, 255, 0.018), transparent 160px),
var(--v5-bg);
}
.script-eval-v5-page {
background:
linear-gradient(90deg, rgba(255, 255, 255, 0.014), transparent 24%, transparent 76%, rgba(255, 255, 255, 0.012)),
transparent;
}
.script-eval-v5-left,
.script-eval-v5-right {
background: var(--v5-panel);
box-shadow: none;
}
.script-eval-v5-left {
border-right-color: var(--v5-line);
}
.script-eval-v5-left-main .script-eval-v5-lp-section,
.script-eval-v5-left-main .script-eval-v5-lp-section.is-fill {
background: transparent;
border-bottom-color: var(--v5-line);
box-shadow: none;
}
.script-eval-v5-lp-label {
color: #a7b3af;
letter-spacing: 0.02em;
}
.script-eval-v5-lp-label::before {
background: var(--v5-green);
box-shadow: none;
opacity: 0.72;
}
.script-eval-v5-upload-zone,
.script-eval-v5-info-empty,
.script-eval-v5-history-empty,
.script-eval-v5-info-item,
.script-eval-v5-history-item,
.script-eval-v5-loading,
.script-eval-v5-illustration-hit,
.script-eval-report__score-block,
.script-eval-report__chart-card,
.script-eval-report__path-card,
.script-eval-report__finding-group p {
border-color: var(--v5-line);
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.032), transparent 58%),
var(--v5-panel-2);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.025);
}
.script-eval-v5-upload-zone {
border-style: dashed;
}
.script-eval-v5-upload-zone::after {
display: none;
}
.script-eval-v5-upload-zone:hover,
.script-eval-v5-upload-zone:focus-visible,
.script-eval-v5.is-ready .script-eval-v5-upload-zone,
.script-eval-v5.is-complete .script-eval-v5-upload-zone {
border-color: var(--v5-green-border);
background:
radial-gradient(circle at 50% 0%, rgba(0, 255, 136, 0.075), transparent 58%),
var(--v5-panel-3);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.028);
}
.script-eval-v5-upload-icon,
.script-eval-v5-upload-card-icon {
border-color: rgba(0, 255, 136, 0.18);
border-radius: 10px;
background: rgba(0, 255, 136, 0.09);
box-shadow: none;
}
.script-eval-v5-upload-btn,
.script-eval-v5-eval-btn {
background: var(--v5-green);
color: #061014;
box-shadow: none;
}
.script-eval-v5-upload-btn:hover,
.script-eval-v5-eval-btn:hover:not(:disabled) {
background: var(--v5-green-dim);
transform: none;
box-shadow: none;
}
.script-eval-v5-upload-done,
.script-eval-v5-history-item.is-active,
.script-eval-v5-error,
.script-eval-report__chart-note,
.script-eval-report__grade {
box-shadow: none;
}
.script-eval-v5-upload-done {
border-color: var(--v5-green-border);
background:
linear-gradient(180deg, rgba(0, 255, 136, 0.085), rgba(0, 255, 136, 0.035)),
var(--v5-panel-2);
}
.script-eval-v5-history-item:hover {
border-color: rgba(255, 255, 255, 0.13);
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.045), transparent 58%),
var(--v5-panel-2);
transform: none;
box-shadow: none;
}
.script-eval-v5-history-item.is-active {
border-color: var(--v5-green-border);
background:
linear-gradient(90deg, rgba(0, 255, 136, 0.08), rgba(0, 255, 136, 0.025)),
var(--v5-panel-2);
}
.script-eval-v5-lp-bottom,
.script-eval-v5-right-topbar,
.script-eval-v5-statusbar {
background: rgba(21, 23, 25, 0.96);
border-color: var(--v5-line);
box-shadow: none;
backdrop-filter: none;
}
.script-eval-v5-export-btn,
.script-eval-v5-action-btn,
.script-eval-v5-retry-btn {
border-color: var(--v5-line);
background: rgba(255, 255, 255, 0.035);
color: #aeb8b1;
box-shadow: none;
}
.script-eval-v5-export-btn:hover:not(:disabled),
.script-eval-v5-action-btn:hover,
.script-eval-v5-retry-btn:hover {
border-color: var(--v5-green-border);
background: rgba(0, 255, 136, 0.07);
color: #d9fff0;
}
.script-eval-v5-right-content:not(.is-report) {
background:
radial-gradient(circle at 50% 0%, rgba(0, 255, 136, 0.034), transparent 44%),
transparent;
}
.script-eval-v5-illustration-hit:hover,
.script-eval-v5-illustration-hit:focus-visible {
background:
linear-gradient(180deg, rgba(0, 255, 136, 0.06), transparent 58%),
var(--v5-panel-2);
box-shadow: none;
}
.script-eval-report {
--report-bg: #0d0d0f;
--report-panel: #151719;
--report-panel-2: #101214;
--report-row: #181b1d;
--report-border: rgba(255, 255, 255, 0.08);
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.018), transparent 180px),
var(--report-bg);
}
.script-eval-report::before,
.script-eval-report::after {
opacity: 0.28;
}
.script-eval-report__bar-fill {
box-shadow: none;
}
.script-eval-v5.is-complete .script-eval-v5-status-dot,
.script-eval-v5.is-ready .script-eval-v5-status-dot {
box-shadow: none;
}
+689 -7
View File
@@ -1485,6 +1485,40 @@
opacity: 1;
}
.web-shell[data-ui-theme="dark-green"] .ai-workbench-select-chip__option-icon {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 24px;
width: 24px;
height: 24px;
margin-top: 0;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.075);
border-radius: 8px;
background: rgba(255, 255, 255, 0.04);
}
.web-shell[data-ui-theme="dark-green"] .ai-workbench-select-chip__option-icon img {
display: block;
width: 16px;
height: 16px;
object-fit: contain;
filter: brightness(0) invert(1);
opacity: 0.86;
}
.web-shell[data-ui-theme="dark-green"] .ai-workbench-select-chip__option:hover .ai-workbench-select-chip__option-icon,
.web-shell[data-ui-theme="dark-green"] .ai-workbench-select-chip__option.is-active .ai-workbench-select-chip__option-icon {
border-color: rgba(var(--accent-rgb), 0.2);
background: rgba(var(--accent-rgb), 0.08);
}
.web-shell[data-ui-theme="dark-green"] .ai-workbench-select-chip__option:hover .ai-workbench-select-chip__option-icon img,
.web-shell[data-ui-theme="dark-green"] .ai-workbench-select-chip__option.is-active .ai-workbench-select-chip__option-icon img {
opacity: 1;
}
.web-shell[data-ui-theme="dark-green"] .ai-workbench-select-chip__option-copy {
display: flex;
flex: 1;
@@ -6849,6 +6883,649 @@
}
}
/* Profile center: responsive workspace refinement. */
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard {
background:
linear-gradient(180deg, rgba(var(--accent-rgb), 0.035), transparent 220px),
var(--dg-page);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__banner {
height: clamp(156px, 18vw, 214px);
background:
linear-gradient(135deg, rgba(var(--accent-rgb), 0.1), transparent 36%),
linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent),
var(--bg-surface);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__banner-overlay {
background:
linear-gradient(180deg, rgba(13, 13, 15, 0.12), rgba(13, 13, 15, 0.72)),
linear-gradient(90deg, rgba(13, 13, 15, 0.68), transparent 42%);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__body {
grid-template-columns: minmax(270px, 300px) minmax(0, 1fr);
gap: clamp(18px, 2.4vw, 30px);
width: min(1180px, calc(100% - 48px));
min-height: auto;
margin-top: -58px;
padding-bottom: clamp(36px, 5vw, 64px);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__sidebar,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__account-card,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__main-tabs,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__section,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__review-item,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__empty-state,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__upload-card {
border-color: rgba(255, 255, 255, 0.075);
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.026), transparent),
rgba(21, 23, 25, 0.96);
box-shadow: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__sidebar {
gap: 16px;
padding: clamp(16px, 2vw, 22px);
border-radius: var(--radius-md);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar-ring::before {
opacity: 0.45;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar-ring .profile-page__avatar,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar {
width: 82px;
height: 82px;
border-width: 3px;
box-shadow: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar-edit {
width: 82px;
height: 82px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar-badge {
box-shadow: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__username {
font-size: clamp(19px, 1.7vw, 22px);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__bio-display,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__bio {
border-color: rgba(255, 255, 255, 0.07);
background: rgba(255, 255, 255, 0.024);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__bio-display span {
text-align: left;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__counts {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
padding: 0;
border: 0;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__count {
min-width: 0;
padding: 12px 8px;
border: 1px solid rgba(255, 255, 255, 0.065);
border-radius: var(--radius-sm);
background: rgba(255, 255, 255, 0.024);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__count strong {
font-size: clamp(18px, 1.5vw, 22px);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__account-card {
display: grid;
gap: 10px;
width: 100%;
padding: 11px;
border: 1px solid rgba(255, 255, 255, 0.075);
border-radius: var(--radius-sm);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__account-card .profile-page__list-tabs {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
width: 100%;
padding: 3px;
border-color: rgba(255, 255, 255, 0.06);
background: rgba(255, 255, 255, 0.02);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__account-card .profile-page__list-tabs button {
min-width: 0;
min-height: 30px;
padding: 0 8px;
overflow: hidden;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__account-card .profile-page__upload-card--meta {
grid-template-columns: 1fr;
gap: 8px;
padding: 0;
border: 0;
background: transparent;
box-shadow: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__account-card .profile-page__meta-item {
min-height: auto;
padding: 10px 11px;
background: rgba(255, 255, 255, 0.022);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__account-card .profile-page__meta-item strong {
font-size: 15px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__share-btn {
min-height: 42px;
border-radius: 10px;
font-size: 13px;
font-weight: 650;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__share-btn:hover {
transform: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__share-btn--primary {
background: var(--accent);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__share-btn--secondary {
border-color: rgba(255, 255, 255, 0.08);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__main {
gap: 16px;
min-width: 0;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__main-tabs {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 6px;
min-height: 50px;
margin: 0;
padding: 5px;
border-radius: var(--radius-md);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__main-tabs button {
min-width: 0;
min-height: 40px;
padding: 0 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__section {
display: grid;
gap: 14px;
padding: clamp(14px, 1.8vw, 18px);
border: 1px solid rgba(255, 255, 255, 0.075);
border-radius: var(--radius-md);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__section-label {
display: flex;
align-items: center;
gap: 8px;
color: var(--fg-body);
font-size: 15px;
font-weight: 700;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__section-label::before {
content: "";
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--accent);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-grid,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__review-list {
gap: 12px;
max-height: none;
overflow: visible;
padding-right: 0;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-grid {
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__review-list {
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card {
min-height: 128px;
padding: 15px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card {
grid-template-columns: 92px minmax(0, 1fr);
align-items: stretch;
gap: 12px;
min-height: 116px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview {
position: relative;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
min-height: 88px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.065);
border-radius: 10px;
background:
linear-gradient(135deg, rgba(var(--accent-rgb), 0.055), transparent 64%),
rgba(255, 255, 255, 0.024);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview:not(.has-media) {
border-color: rgba(255, 255, 255, 0.07);
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.035), transparent),
rgba(255, 255, 255, 0.018);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview img,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview video {
width: 100%;
height: 100%;
min-height: 88px;
object-fit: cover;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-placeholder {
display: inline-flex;
align-items: center;
justify-content: center;
width: 38px;
height: 38px;
border: 1px solid rgba(var(--accent-rgb), 0.18);
border-radius: 12px;
background: rgba(var(--accent-rgb), 0.07);
color: rgba(var(--accent-rgb), 0.92);
font-size: 16px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-badge {
position: absolute;
top: 7px;
right: 7px;
max-width: calc(100% - 14px);
overflow: hidden;
padding: 3px 7px;
border-radius: 999px;
border: 1px solid rgba(var(--accent-rgb), 0.22);
background: rgba(8, 14, 12, 0.76);
color: var(--accent);
font-size: 10px;
font-weight: 700;
line-height: 1;
text-overflow: ellipsis;
white-space: nowrap;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-head {
gap: 8px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-head strong {
min-width: 0;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__delete-project {
flex: 0 0 26px;
width: 26px;
height: 26px;
margin: -3px -2px 0 0;
border: 1px solid rgba(255, 255, 255, 0.075);
border-radius: 8px;
background: rgba(255, 255, 255, 0.026);
color: var(--fg-soft);
opacity: 0.72;
transition: border-color var(--transition-fast), background var(--transition-fast), color var(--transition-fast), opacity var(--transition-fast);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__delete-project:hover,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__delete-project:focus-visible {
border-color: rgba(255, 118, 118, 0.28);
background: rgba(255, 118, 118, 0.08);
color: #ff9a9d;
opacity: 1;
outline: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-body {
display: grid;
align-content: start;
gap: 8px;
min-width: 0;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card:hover,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__review-item:hover {
border-color: rgba(var(--accent-rgb), 0.28);
transform: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__empty-state {
min-height: 240px;
padding: clamp(30px, 4vw, 46px) 24px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-bar {
margin-bottom: 0;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-tabs {
width: fit-content;
max-width: 100%;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-tabs button {
white-space: nowrap;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__upload-card--meta {
grid-template-columns: repeat(2, minmax(0, 1fr));
padding: 12px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__meta-item {
min-height: 78px;
}
@media (max-width: 960px) {
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__body {
grid-template-columns: 1fr;
width: min(760px, calc(100% - 36px));
margin-top: -44px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__sidebar {
display: grid;
grid-template-columns: minmax(0, 1.2fr) minmax(220px, 0.8fr);
align-items: start;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__sidebar-head {
grid-row: span 5;
align-items: flex-start;
text-align: left;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__counts {
align-self: stretch;
}
}
@media (max-width: 640px) {
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__banner {
height: 140px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__body {
width: min(100% - 28px, 560px);
margin-top: -30px;
padding-bottom: 84px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__sidebar {
display: flex;
gap: 12px;
padding: 16px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__sidebar-head {
align-items: center;
text-align: center;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar-ring .profile-page__avatar,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar {
width: 72px;
height: 72px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__avatar-edit {
width: 72px;
height: 72px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__counts {
gap: 6px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__count {
padding: 10px 6px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__main-tabs {
display: flex;
overflow-x: auto;
scrollbar-width: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__main-tabs::-webkit-scrollbar {
display: none;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__main-tabs button {
flex: 0 0 auto;
min-width: 88px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__section {
padding: 14px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-grid,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__review-list {
grid-template-columns: 1fr;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card {
min-height: 118px;
padding: 13px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card {
grid-template-columns: 88px minmax(0, 1fr);
gap: 10px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview img,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview video {
min-height: 82px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-head {
align-items: center;
flex-direction: row;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__upload-card--meta {
grid-template-columns: 1fr;
}
}
@media (max-width: 420px) {
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__body {
width: min(100% - 20px, 420px);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__counts {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__share-btn {
min-height: 40px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card {
grid-template-columns: 78px minmax(0, 1fr);
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview img,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__list-card-preview video {
min-height: 76px;
}
}
/* Profile center: lock media card rhythm for dense libraries. */
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card {
grid-template-columns: 92px minmax(0, 1fr);
height: 126px;
min-height: 126px;
max-height: 126px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview {
width: 92px;
height: 96px;
min-height: 96px;
max-height: 96px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview img,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview video {
height: 96px;
min-height: 96px;
max-height: 96px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-body {
display: grid;
grid-template-rows: 18px 36px 18px;
align-content: space-between;
gap: 8px;
height: 96px;
min-height: 96px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-head {
min-height: 18px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-head strong {
display: block;
width: 100%;
line-height: 1.25;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card p {
min-height: 36px;
max-height: 36px;
line-height: 1.5;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-meta {
align-self: end;
min-height: 18px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-meta span:last-child {
color: var(--fg-soft);
}
@media (max-width: 640px) {
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card {
grid-template-columns: 88px minmax(0, 1fr);
height: 112px;
min-height: 112px;
max-height: 112px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview {
width: 88px;
height: 86px;
min-height: 86px;
max-height: 86px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview img,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview video {
height: 86px;
min-height: 86px;
max-height: 86px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-body {
grid-template-rows: 16px 32px 16px;
gap: 6px;
height: 86px;
min-height: 86px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card p {
min-height: 32px;
max-height: 32px;
line-height: 1.45;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-meta {
min-height: 16px;
}
}
@media (max-width: 420px) {
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card {
grid-template-columns: 78px minmax(0, 1fr);
height: 104px;
min-height: 104px;
max-height: 104px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview {
width: 78px;
height: 78px;
min-height: 78px;
max-height: 78px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview img,
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-preview video {
height: 78px;
min-height: 78px;
max-height: 78px;
}
.web-shell[data-ui-theme="dark-green"] .profile-page--dashboard .profile-page__media-card .profile-page__list-card-body {
height: 78px;
min-height: 78px;
}
}
/* Ecommerce generation page: keep its carousel and composer independent from
the community carousel rules that share class names. */
.web-shell[data-ui-theme="dark-green"] .ecommerce-landing-page {
@@ -8948,18 +9625,23 @@
/* Canvas SaaS polish: refined production-tool surfaces without changing canvas behavior. */
.web-shell[data-ui-theme="dark-green"][data-view="canvas"] .canvas-page .studio-canvas {
background:
background-image:
radial-gradient(circle at 18% 8%, rgba(var(--accent-rgb), 0.055), transparent 30%),
radial-gradient(circle at 72% 88%, rgba(255, 255, 255, 0.035), transparent 28%),
linear-gradient(rgba(255, 255, 255, 0.026) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.026) 1px, transparent 1px),
var(--dg-page);
radial-gradient(
circle,
rgba(148, 163, 184, 0.34) 0 var(--canvas-bg-dot, 1.35px),
transparent calc(var(--canvas-bg-dot, 1.35px) + 0.55px)
);
background-color: var(--dg-page);
background-position:
center,
center,
var(--canvas-bg-x, 0px) var(--canvas-bg-y, 0px);
background-size:
auto,
auto,
24px 24px,
24px 24px,
auto;
var(--canvas-bg-size, 24px) var(--canvas-bg-size, 24px);
color: var(--fg-body);
}