style: refine agent generation workspace dark ui
This commit is contained in:
parent
d6411076fa
commit
55774ef43e
@ -168,6 +168,33 @@
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.agent-dark-scrollbar {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(255, 255, 255, 0.18) rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.agent-dark-scrollbar::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.agent-dark-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.agent-dark-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
border: 2px solid rgba(0, 0, 0, 0);
|
||||
background-clip: padding-box;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.agent-dark-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.26);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
.step {
|
||||
counter-increment: step;
|
||||
}
|
||||
|
||||
@ -550,29 +550,18 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
{/* Main Content */}
|
||||
<main className="flex-1 overflow-y-auto overscroll-contain pt-16 lg:overflow-hidden">
|
||||
<div className="mx-auto flex min-h-full max-w-[1480px] flex-col px-6 py-6 lg:h-full lg:px-8 xl:px-10">
|
||||
{/* 步骤指示器 */}
|
||||
<motion.div
|
||||
className="mb-6 flex items-center justify-center gap-2 text-sm"
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
>
|
||||
<span className="text-white/40">第一步:风格选择</span>
|
||||
<span className="text-white/20">→</span>
|
||||
<span className="text-emerald-400 font-medium">第二步:生图模式</span>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid min-h-0 flex-1 grid-cols-1 gap-6 lg:grid-cols-[400px_minmax(0,1fr)]">
|
||||
{/* Left Panel - Controls */}
|
||||
<div className="min-h-0 space-y-4 lg:h-full lg:overflow-y-auto lg:pr-2">
|
||||
<div className="agent-dark-scrollbar min-h-0 space-y-4 lg:h-full lg:overflow-y-auto lg:pr-2">
|
||||
{/* 嵌入的智能体选择面板 */}
|
||||
{!selectedAgentPreset && presetPanel && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="rounded-2xl border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
className="rounded-[28px] border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
>
|
||||
<h3 className="mb-3 text-sm font-semibold text-white">选择生图模式</h3>
|
||||
<div className="max-h-[480px] overflow-y-auto pr-1">
|
||||
<div className="agent-dark-scrollbar max-h-[480px] overflow-y-auto pr-1">
|
||||
{presetPanel}
|
||||
</div>
|
||||
</motion.div>
|
||||
@ -581,7 +570,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
{/* 已选智能体信息 */}
|
||||
{selectedAgentPreset && (
|
||||
<motion.div
|
||||
className="rounded-2xl border border-white/12 bg-white/[0.05] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
className="rounded-[28px] border border-white/12 bg-white/[0.05] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
>
|
||||
@ -591,10 +580,10 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
<img
|
||||
src={selectedAgentPreset.avatarUrl}
|
||||
alt={selectedAgentPreset.name}
|
||||
className="h-10 w-10 rounded-lg object-cover"
|
||||
className="h-10 w-10 rounded-xl object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-emerald-500/18">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-emerald-500/18">
|
||||
<Wand2 className="h-5 w-5 text-emerald-300" />
|
||||
</div>
|
||||
)}
|
||||
@ -636,7 +625,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
|
||||
{/* Image Slots */}
|
||||
<motion.section
|
||||
className="rounded-2xl border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
className="rounded-[28px] border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.1 }}
|
||||
@ -655,7 +644,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
whileHover={{ scale: 1.03 }}
|
||||
whileTap={{ scale: 0.97 }}
|
||||
className={cn(
|
||||
"group relative aspect-square overflow-hidden rounded-xl transition-all",
|
||||
"group relative aspect-square overflow-hidden rounded-[24px] transition-all",
|
||||
attachments[index]
|
||||
? "ring-2 ring-emerald-400/45"
|
||||
: "border-2 border-dashed border-white/15 bg-black/25 hover:border-emerald-400/35"
|
||||
@ -707,7 +696,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex min-h-[132px] flex-col items-center justify-center rounded-2xl border border-dashed border-white/12 bg-black/20 px-4 text-center text-sm text-white/45">
|
||||
<div className="flex min-h-[132px] flex-col items-center justify-center rounded-[24px] border border-dashed border-white/12 bg-black/20 px-4 text-center text-sm text-white/45">
|
||||
<ImagePlus className="mb-2 h-5 w-5 opacity-60" />
|
||||
先选择一个生图模式,系统会自动展示产品图1、产品图2和模特图槽位。
|
||||
</div>
|
||||
@ -716,7 +705,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
|
||||
{/* Prompt Input */}
|
||||
<motion.section
|
||||
className="rounded-2xl border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
className="rounded-[28px] border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
@ -729,13 +718,13 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="描述你想要的风格、氛围、构图..."
|
||||
className="min-h-[100px] resize-none rounded-lg border-white/12 bg-black text-sm text-white placeholder:text-white/20 focus:border-emerald-400/30"
|
||||
className="min-h-[100px] resize-none rounded-[24px] border-white/12 bg-black text-sm text-white placeholder:text-white/20 focus:border-emerald-400/30"
|
||||
/>
|
||||
</motion.section>
|
||||
|
||||
{/* Settings */}
|
||||
<motion.section
|
||||
className="rounded-2xl border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
className="rounded-[28px] border border-white/12 bg-white/[0.04] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
@ -746,7 +735,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
</h3>
|
||||
<div className="space-y-3">
|
||||
<Select value={selectedModelId} onValueChange={setSelectedModelId}>
|
||||
<SelectTrigger className="h-10 rounded-lg border-white/12 bg-black text-white">
|
||||
<SelectTrigger className="h-10 rounded-[24px] border-white/12 bg-black text-white">
|
||||
<SelectValue placeholder="选择模型" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="border-white/10 bg-zinc-900">
|
||||
@ -763,6 +752,8 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
initialParams={imageParams}
|
||||
onParamsChange={setImageParams}
|
||||
inline
|
||||
inlineTheme="dark"
|
||||
showInlineDivider={false}
|
||||
providerType={currentModel?.providerType}
|
||||
imageGenConfig={currentModel?.imageGenConfig || undefined}
|
||||
/>
|
||||
@ -771,7 +762,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
onClick={handleSend}
|
||||
disabled={isGenerating || !selectedAgentPresetId}
|
||||
className={cn(
|
||||
"h-11 w-full gap-2 rounded-lg",
|
||||
"h-11 w-full gap-2 rounded-[24px]",
|
||||
"bg-gradient-to-r from-emerald-500 to-teal-500",
|
||||
"text-white font-medium",
|
||||
"hover:from-emerald-400 hover:to-teal-400",
|
||||
@ -810,11 +801,18 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
生成完成后会同步回到画布,并在这里保留预览与切换。
|
||||
</div>
|
||||
</div>
|
||||
{allGeneratedImages.length > 0 ? (
|
||||
<div className="rounded-full bg-white/8 px-3 py-1 text-xs text-white/60">
|
||||
共 {allGeneratedImages.length} 张
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-full border border-white/10 bg-white/[0.03] px-3 py-1 text-xs text-white/58">
|
||||
第一步:风格选择
|
||||
<span className="mx-1.5 text-white/22">→</span>
|
||||
<span className="font-medium text-emerald-300">第二步:生图模式</span>
|
||||
</div>
|
||||
) : null}
|
||||
{allGeneratedImages.length > 0 ? (
|
||||
<div className="rounded-full bg-white/8 px-3 py-1 text-xs text-white/60">
|
||||
共 {allGeneratedImages.length} 张
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AnimatePresence mode="wait">
|
||||
@ -845,7 +843,7 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
<img
|
||||
src={buildPreviewImageUrl(displayedResultUrl, 1400)}
|
||||
alt="生成结果"
|
||||
className="max-h-full max-w-full cursor-zoom-in rounded-lg object-contain"
|
||||
className="max-h-full max-w-full cursor-zoom-in rounded-[24px] object-contain"
|
||||
onClick={() => setFullscreenPreview(displayedResultUrl)}
|
||||
/>
|
||||
<button
|
||||
@ -891,9 +889,9 @@ export function AgentGenerationWorkspaceDarkV2({
|
||||
{allGeneratedImages.map((url) => (
|
||||
<button
|
||||
key={url}
|
||||
onClick={() => setSelectedResultUrl(url)}
|
||||
className={cn(
|
||||
"relative flex-shrink-0 overflow-hidden rounded-xl transition-all",
|
||||
onClick={() => setSelectedResultUrl(url)}
|
||||
className={cn(
|
||||
"relative flex-shrink-0 overflow-hidden rounded-[24px] transition-all",
|
||||
displayedResultUrl === url
|
||||
? "ring-2 ring-emerald-400"
|
||||
: "ring-1 ring-white/12 hover:ring-white/30"
|
||||
|
||||
@ -47,7 +47,7 @@ export function AgentWorkflowBrandModelPicker({
|
||||
return (
|
||||
<section
|
||||
className={cn(
|
||||
"space-y-3 rounded-2xl border p-4",
|
||||
"space-y-3 rounded-[28px] border p-4",
|
||||
isDark ? "border-white/12 bg-white/[0.04]" : "border-[#dbe3ff] bg-[#f8faff]"
|
||||
)}
|
||||
>
|
||||
@ -74,7 +74,7 @@ export function AgentWorkflowBrandModelPicker({
|
||||
{!normalizedBrand ? (
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-h-[124px] flex-col items-center justify-center rounded-2xl border border-dashed px-4 text-center text-sm",
|
||||
"flex min-h-[124px] flex-col items-center justify-center rounded-[24px] border border-dashed px-4 text-center text-sm",
|
||||
isDark
|
||||
? "border-white/12 bg-black/20 text-white/45"
|
||||
: "bg-background/60 text-muted-foreground"
|
||||
@ -146,7 +146,7 @@ export function AgentWorkflowBrandModelPicker({
|
||||
)
|
||||
}
|
||||
className={cn(
|
||||
"group overflow-hidden rounded-2xl border bg-background text-left transition-all",
|
||||
"group overflow-hidden rounded-[24px] border bg-background text-left transition-all",
|
||||
selected
|
||||
? isDark
|
||||
? "border-emerald-400/70 bg-white/[0.03] shadow-[0_0_0_1px_rgba(52,211,153,0.2)]"
|
||||
@ -206,7 +206,7 @@ export function AgentWorkflowBrandModelPicker({
|
||||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-h-[124px] flex-col items-center justify-center rounded-2xl border border-dashed px-4 text-center text-sm",
|
||||
"flex min-h-[124px] flex-col items-center justify-center rounded-[24px] border border-dashed px-4 text-center text-sm",
|
||||
isDark
|
||||
? "border-white/12 bg-black/20 text-white/45"
|
||||
: "bg-background/60 text-muted-foreground"
|
||||
|
||||
@ -70,7 +70,7 @@ export function AgentWorkflowMaterialPicker({
|
||||
return (
|
||||
<section
|
||||
className={cn(
|
||||
"space-y-3 rounded-2xl border p-4",
|
||||
"space-y-3 rounded-[24px] border p-4",
|
||||
isDark ? "border-white/12 bg-black/20" : "bg-muted/20"
|
||||
)}
|
||||
>
|
||||
@ -122,7 +122,7 @@ export function AgentWorkflowMaterialPicker({
|
||||
{disabled && disabledHint ? (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-xl border px-3 py-2 text-xs",
|
||||
"rounded-[20px] border px-3 py-2 text-xs",
|
||||
isDark
|
||||
? "border-amber-500/20 bg-amber-500/10 text-amber-100"
|
||||
: "border-amber-200 bg-amber-50 text-amber-800"
|
||||
@ -133,7 +133,7 @@ export function AgentWorkflowMaterialPicker({
|
||||
) : null}
|
||||
|
||||
{!disabled && errorText ? (
|
||||
<div className="rounded-xl border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs text-destructive">
|
||||
<div className="rounded-[20px] border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs text-destructive">
|
||||
{errorText}
|
||||
</div>
|
||||
) : null}
|
||||
@ -208,7 +208,7 @@ export function AgentWorkflowMaterialPicker({
|
||||
type="button"
|
||||
onClick={() => handleToggleImage(image.id)}
|
||||
className={cn(
|
||||
"group overflow-hidden rounded-2xl border bg-background text-left transition-all",
|
||||
"group overflow-hidden rounded-[24px] border bg-background text-left transition-all",
|
||||
selected
|
||||
? isDark
|
||||
? "border-emerald-400/70 bg-white/[0.03] shadow-[0_0_0_1px_rgba(52,211,153,0.2)]"
|
||||
@ -271,7 +271,7 @@ export function AgentWorkflowMaterialPicker({
|
||||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-h-[124px] flex-col items-center justify-center rounded-2xl border border-dashed px-4 text-center text-sm",
|
||||
"flex min-h-[124px] flex-col items-center justify-center rounded-[24px] border border-dashed px-4 text-center text-sm",
|
||||
isDark
|
||||
? "border-white/12 bg-white/[0.03] text-white/42"
|
||||
: "bg-background/60 text-muted-foreground"
|
||||
@ -299,7 +299,7 @@ export function AgentWorkflowMaterialPicker({
|
||||
{result?.images?.length ? (
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-start gap-2 rounded-xl px-3 py-2 text-xs",
|
||||
"flex items-start gap-2 rounded-[20px] px-3 py-2 text-xs",
|
||||
isDark ? "bg-white/[0.04] text-white/45" : "bg-background text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
|
||||
@ -116,7 +116,7 @@ export function AgentWorkflowMaterialSelectionPanel({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"space-y-3 rounded-2xl border p-4",
|
||||
"space-y-3 rounded-[28px] border p-4",
|
||||
isDark ? "border-white/12 bg-white/[0.04]" : "border-[#dbe3ff] bg-[#f8faff]"
|
||||
)}
|
||||
>
|
||||
|
||||
@ -31,7 +31,7 @@ export function AgentWorkflowShowcaseBanner({
|
||||
const resolvedActionLabel = actionLabel || resolved.actionText;
|
||||
|
||||
return (
|
||||
<div className={cn("space-y-8", className)}>
|
||||
<div className={cn("space-y-12 pt-6 md:space-y-14 md:pt-8", className)}>
|
||||
<motion.div
|
||||
className="text-center"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@ -39,7 +39,7 @@ export function AgentWorkflowShowcaseBanner({
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<h1 className="mb-3 text-3xl font-bold text-white md:text-4xl">{resolved.title}</h1>
|
||||
<p className="mb-6 text-base text-white/50">{resolved.subtitle}</p>
|
||||
<p className="mb-8 text-base text-white/50 md:mb-9">{resolved.subtitle}</p>
|
||||
{resolvedActionLabel || secondaryActionLabel ? (
|
||||
<div className="flex flex-col items-center justify-center gap-4 sm:flex-row">
|
||||
{resolvedActionLabel ? (
|
||||
@ -64,7 +64,7 @@ export function AgentWorkflowShowcaseBanner({
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={onSecondaryActionClick}
|
||||
className="h-12 rounded-2xl border-white/20 bg-transparent px-12 text-base font-medium text-white hover:border-emerald-400/50 hover:bg-white/[0.04]"
|
||||
className="h-12 rounded-full border-white/20 bg-transparent px-12 text-base font-medium text-white hover:border-emerald-400/50 hover:bg-white/[0.04]"
|
||||
>
|
||||
{secondaryActionLabel}
|
||||
</Button>
|
||||
|
||||
@ -33,6 +33,8 @@ interface ImageParamsBarProps {
|
||||
providerType?: string; // 模型类型:gemini, volcano-vision, alibaba-image, ruxa-image 等
|
||||
hideImageCount?: boolean; // 隐藏图片数量按钮(仅个别页面需要)
|
||||
hideAdvancedOptions?: boolean; // 隐藏高级设置按钮
|
||||
inlineTheme?: "light" | "dark";
|
||||
showInlineDivider?: boolean;
|
||||
// 🆕 图片生成模型特性配置(从模型配置中读取)
|
||||
imageGenConfig?: {
|
||||
maxImages?: number;
|
||||
@ -83,6 +85,8 @@ export function ImageParamsBar({
|
||||
providerType = "gemini", // 默认 gemini
|
||||
hideImageCount = false,
|
||||
hideAdvancedOptions = false,
|
||||
inlineTheme = "light",
|
||||
showInlineDivider = true,
|
||||
imageGenConfig,
|
||||
}: ImageParamsBarProps) {
|
||||
const getImageCountOptions = () => {
|
||||
@ -255,24 +259,41 @@ export function ImageParamsBar({
|
||||
|
||||
// 内联模式:只返回参数按钮,嵌入工具栏
|
||||
if (inline) {
|
||||
const isDarkInline = inlineTheme === "dark";
|
||||
const ratioLabel = params.aspectRatio === "auto" ? "智能比例" : params.aspectRatio;
|
||||
const sizeLabel = params.imageSize;
|
||||
const outputSize = getComputedOutputSize(params.aspectRatio, params.imageSize);
|
||||
|
||||
return (
|
||||
<div className="ml-1 flex items-center gap-1 border-l border-border/50 pl-1">
|
||||
<div
|
||||
className={cn(
|
||||
"ml-1 flex items-center gap-1 pl-1",
|
||||
showInlineDivider &&
|
||||
(isDarkInline ? "border-l border-white/10" : "border-l border-border/50")
|
||||
)}
|
||||
>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 max-w-[168px] shrink rounded-[12px] border border-[#d6dbe2] bg-[#f3f4f6]/90 px-2 text-[11px] font-semibold text-[#2f3b48] hover:bg-[#edeff2]/90"
|
||||
className={cn(
|
||||
"h-8 max-w-[168px] shrink rounded-[12px] px-2 text-[11px] font-semibold",
|
||||
isDarkInline
|
||||
? "border border-white/12 bg-white/[0.06] text-white hover:bg-white/[0.1]"
|
||||
: "border border-[#d6dbe2] bg-[#f3f4f6]/90 text-[#2f3b48] hover:bg-[#edeff2]/90"
|
||||
)}
|
||||
title={`比例:${params.aspectRatio},分辨率:${params.imageSize}`}
|
||||
>
|
||||
<span className="mr-1 flex h-3.5 w-3.5 items-center justify-center text-[#20262f]">
|
||||
<span
|
||||
className={cn(
|
||||
"mr-1 flex h-3.5 w-3.5 items-center justify-center",
|
||||
isDarkInline ? "text-white/80" : "text-[#20262f]"
|
||||
)}
|
||||
>
|
||||
{renderRatioGlyph(params.aspectRatio)}
|
||||
</span>
|
||||
<span className="truncate">{ratioLabel}</span>
|
||||
<span className="mx-1.5 h-3 w-px bg-[#cfd5de]" />
|
||||
<span className={cn("mx-1.5 h-3 w-px", isDarkInline ? "bg-white/12" : "bg-[#cfd5de]")} />
|
||||
<span className="inline-flex min-w-0 items-center gap-0.5 truncate">
|
||||
{sizeLabel}
|
||||
</span>
|
||||
@ -282,21 +303,35 @@ export function ImageParamsBar({
|
||||
align="center"
|
||||
side="top"
|
||||
sideOffset={10}
|
||||
className="w-[312px] max-w-[calc(100vw-24px)] rounded-[14px] border border-[#d8dde4] bg-[#f3f4f6]/90 p-2 shadow-[0_10px_24px_rgba(15,23,42,0.14)]"
|
||||
className={cn(
|
||||
"w-[312px] max-w-[calc(100vw-24px)] rounded-[14px] p-2 shadow-[0_10px_24px_rgba(15,23,42,0.14)]",
|
||||
isDarkInline
|
||||
? "border border-white/12 bg-[#0d1013]/98 text-white backdrop-blur-xl"
|
||||
: "border border-[#d8dde4] bg-[#f3f4f6]/90"
|
||||
)}
|
||||
>
|
||||
<div className="space-y-2.5">
|
||||
<div>
|
||||
<p className="text-[11px] font-medium text-[#8a94a3]">选择比例</p>
|
||||
<div className="mt-1.5 grid grid-cols-4 gap-1.5 rounded-[12px] bg-[#eceff2]/90 p-1.5 md:grid-cols-5">
|
||||
<p className={cn("text-[11px] font-medium", isDarkInline ? "text-white/45" : "text-[#8a94a3]")}>选择比例</p>
|
||||
<div
|
||||
className={cn(
|
||||
"mt-1.5 grid grid-cols-4 gap-1.5 rounded-[12px] p-1.5 md:grid-cols-5",
|
||||
isDarkInline ? "bg-white/[0.04]" : "bg-[#eceff2]/90"
|
||||
)}
|
||||
>
|
||||
{ASPECT_RATIO_OPTIONS.map((option) => (
|
||||
<button
|
||||
key={option.value}
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex h-[46px] flex-col items-center justify-center rounded-[10px] border text-[#5f6b7a] transition",
|
||||
"flex h-[46px] flex-col items-center justify-center rounded-[10px] border transition",
|
||||
params.aspectRatio === option.value
|
||||
? "border-white bg-white text-[#1f2937] shadow-[0_1px_5px_rgba(15,23,42,0.08)]"
|
||||
: "border-transparent hover:bg-white/70"
|
||||
? isDarkInline
|
||||
? "border-emerald-400/50 bg-emerald-500/12 text-emerald-200 shadow-[0_1px_5px_rgba(15,23,42,0.18)]"
|
||||
: "border-white bg-white text-[#1f2937] shadow-[0_1px_5px_rgba(15,23,42,0.08)]"
|
||||
: isDarkInline
|
||||
? "border-transparent text-white/62 hover:bg-white/[0.06]"
|
||||
: "border-transparent text-[#5f6b7a] hover:bg-white/70"
|
||||
)}
|
||||
onClick={() => updateParam("aspectRatio", option.value)}
|
||||
>
|
||||
@ -312,8 +347,13 @@ export function ImageParamsBar({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-[11px] font-medium text-[#8a94a3]">选择分辨率</p>
|
||||
<div className="mt-1.5 grid grid-cols-2 gap-1.5 rounded-[12px] bg-[#eceff2]/90 p-1">
|
||||
<p className={cn("text-[11px] font-medium", isDarkInline ? "text-white/45" : "text-[#8a94a3]")}>选择分辨率</p>
|
||||
<div
|
||||
className={cn(
|
||||
"mt-1.5 grid grid-cols-2 gap-1.5 rounded-[12px] p-1",
|
||||
isDarkInline ? "bg-white/[0.04]" : "bg-[#eceff2]/90"
|
||||
)}
|
||||
>
|
||||
{availableSizeOptions.map((option) => (
|
||||
<button
|
||||
key={option.value}
|
||||
@ -321,8 +361,12 @@ export function ImageParamsBar({
|
||||
className={cn(
|
||||
"h-8 rounded-[9px] text-[12px] font-semibold transition",
|
||||
params.imageSize === option.value
|
||||
? "bg-white text-[#111827] shadow-[0_1px_5px_rgba(15,23,42,0.08)]"
|
||||
: "bg-transparent text-[#5f6b7a] hover:bg-white/70"
|
||||
? isDarkInline
|
||||
? "bg-emerald-500/12 text-emerald-200 shadow-[0_1px_5px_rgba(15,23,42,0.18)]"
|
||||
: "bg-white text-[#111827] shadow-[0_1px_5px_rgba(15,23,42,0.08)]"
|
||||
: isDarkInline
|
||||
? "bg-transparent text-white/62 hover:bg-white/[0.06]"
|
||||
: "bg-transparent text-[#5f6b7a] hover:bg-white/70"
|
||||
)}
|
||||
onClick={() => updateParam("imageSize", option.value)}
|
||||
>
|
||||
@ -335,22 +379,22 @@ export function ImageParamsBar({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-[11px] font-medium text-[#8a94a3]">尺寸</p>
|
||||
<p className={cn("text-[11px] font-medium", isDarkInline ? "text-white/45" : "text-[#8a94a3]")}>尺寸</p>
|
||||
<div className="mt-1.5 grid grid-cols-[1fr_auto_1fr_auto] items-center gap-1.5">
|
||||
<div className="h-7 rounded-[9px] border border-[#dce1e8] bg-[#eef1f4]/90 px-2 text-[#b0b8c4]">
|
||||
<div className={cn("h-7 rounded-[9px] px-2", isDarkInline ? "border border-white/10 bg-white/[0.04] text-white/68" : "border border-[#dce1e8] bg-[#eef1f4]/90 text-[#b0b8c4]")}>
|
||||
<div className="flex h-full items-center justify-between gap-1.5">
|
||||
<span className="text-[10px] font-semibold">W</span>
|
||||
<span className="text-[12px] font-semibold">{outputSize.width}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Link2 className="h-3 w-3 text-[#adb6c3]" />
|
||||
<div className="h-7 rounded-[9px] border border-[#dce1e8] bg-[#eef1f4]/90 px-2 text-[#b0b8c4]">
|
||||
<Link2 className={cn("h-3 w-3", isDarkInline ? "text-white/35" : "text-[#adb6c3]")} />
|
||||
<div className={cn("h-7 rounded-[9px] px-2", isDarkInline ? "border border-white/10 bg-white/[0.04] text-white/68" : "border border-[#dce1e8] bg-[#eef1f4]/90 text-[#b0b8c4]")}>
|
||||
<div className="flex h-full items-center justify-between gap-1.5">
|
||||
<span className="text-[10px] font-semibold">H</span>
|
||||
<span className="text-[12px] font-semibold">{outputSize.height}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-[11px] font-semibold text-[#8a94a3]">PX</span>
|
||||
<span className={cn("text-[11px] font-semibold", isDarkInline ? "text-white/45" : "text-[#8a94a3]")}>PX</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -362,23 +406,34 @@ export function ImageParamsBar({
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 min-w-[56px] rounded-[12px] border border-[#d6dbe2] bg-[#f3f4f6]/90 px-2.5 text-[12px] font-semibold text-[#2f3b48] hover:bg-[#edeff2]/90 focus-visible:ring-0 focus-visible:ring-offset-0"
|
||||
className={cn(
|
||||
"h-8 min-w-[56px] rounded-[12px] px-2.5 text-[12px] font-semibold focus-visible:ring-0 focus-visible:ring-offset-0",
|
||||
isDarkInline
|
||||
? "border border-white/12 bg-white/[0.06] text-white hover:bg-white/[0.1]"
|
||||
: "border border-[#d6dbe2] bg-[#f3f4f6]/90 text-[#2f3b48] hover:bg-[#edeff2]/90"
|
||||
)}
|
||||
title={`数量:${params.imageCount || 1}张`}
|
||||
>
|
||||
<Sparkles className="mr-1 h-3.5 w-3.5 text-[#6b7280]" />
|
||||
<Sparkles className={cn("mr-1 h-3.5 w-3.5", isDarkInline ? "text-emerald-300" : "text-[#6b7280]")} />
|
||||
{params.imageCount || 1}张
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="center"
|
||||
side="top"
|
||||
sideOffset={10}
|
||||
className="w-auto min-w-[120px] rounded-[14px] border border-[#d8dde4] bg-[#f3f4f6]/95 p-2 shadow-[0_10px_24px_rgba(15,23,42,0.14)]"
|
||||
>
|
||||
side="top"
|
||||
sideOffset={10}
|
||||
className={cn(
|
||||
"w-auto min-w-[120px] rounded-[14px] p-2 shadow-[0_10px_24px_rgba(15,23,42,0.14)]",
|
||||
isDarkInline
|
||||
? "border border-white/12 bg-[#0d1013]/98 text-white backdrop-blur-xl"
|
||||
: "border border-[#d8dde4] bg-[#f3f4f6]/95"
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<p className="text-[11px] font-medium text-[#8a94a3]">生成数量</p>
|
||||
<p className={cn("text-[11px] font-medium", isDarkInline ? "text-white/45" : "text-[#8a94a3]")}>生成数量</p>
|
||||
<div className={cn(
|
||||
"mt-1.5 grid gap-1.5 rounded-[12px] bg-[#eceff2]/90 p-1.5",
|
||||
"mt-1.5 grid gap-1.5 rounded-[12px] p-1.5",
|
||||
isDarkInline ? "bg-white/[0.04]" : "bg-[#eceff2]/90",
|
||||
imageCountOptions.length <= 3 ? "grid-cols-3" : "grid-cols-3"
|
||||
)}>
|
||||
{imageCountOptions.map((count) => (
|
||||
@ -388,8 +443,12 @@ export function ImageParamsBar({
|
||||
className={cn(
|
||||
"flex h-8 min-w-[36px] items-center justify-center rounded-[9px] border text-[12px] font-semibold transition",
|
||||
(params.imageCount || 1) === count
|
||||
? "border-white bg-white text-[#1f2937] shadow-[0_1px_5px_rgba(15,23,42,0.08)]"
|
||||
: "border-transparent text-[#5f6b7a] hover:bg-white/70"
|
||||
? isDarkInline
|
||||
? "border-emerald-400/50 bg-emerald-500/12 text-emerald-200 shadow-[0_1px_5px_rgba(15,23,42,0.18)]"
|
||||
: "border-white bg-white text-[#1f2937] shadow-[0_1px_5px_rgba(15,23,42,0.08)]"
|
||||
: isDarkInline
|
||||
? "border-transparent text-white/62 hover:bg-white/[0.06]"
|
||||
: "border-transparent text-[#5f6b7a] hover:bg-white/70"
|
||||
)}
|
||||
onClick={() => updateParam("imageCount", count)}
|
||||
>
|
||||
@ -409,8 +468,11 @@ export function ImageParamsBar({
|
||||
<Button
|
||||
variant="ghost"
|
||||
className={cn(
|
||||
"h-8 w-8 shrink-0 rounded-[12px] border border-[#d6dbe2] bg-[#f3f4f6]/90 p-0 text-[#5f6b7a] hover:bg-[#edeff2]/90 focus-visible:ring-0 focus-visible:ring-offset-0",
|
||||
(params.promptExtend || params.negativePrompt) && "text-primary"
|
||||
"h-8 w-8 shrink-0 rounded-[12px] p-0 focus-visible:ring-0 focus-visible:ring-offset-0",
|
||||
isDarkInline
|
||||
? "border border-white/12 bg-white/[0.06] text-white/70 hover:bg-white/[0.1]"
|
||||
: "border border-[#d6dbe2] bg-[#f3f4f6]/90 text-[#5f6b7a] hover:bg-[#edeff2]/90",
|
||||
(params.promptExtend || params.negativePrompt) && (isDarkInline ? "text-emerald-300" : "text-primary")
|
||||
)}
|
||||
title="高级设置"
|
||||
>
|
||||
@ -420,17 +482,22 @@ export function ImageParamsBar({
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="end"
|
||||
side="top"
|
||||
sideOffset={10}
|
||||
className="w-[280px] max-w-[calc(100vw-24px)] rounded-[14px] border border-[#d8dde4] bg-[#f3f4f6]/95 p-2 shadow-[0_10px_24px_rgba(15,23,42,0.14)]"
|
||||
>
|
||||
side="top"
|
||||
sideOffset={10}
|
||||
className={cn(
|
||||
"w-[280px] max-w-[calc(100vw-24px)] rounded-[14px] p-2 shadow-[0_10px_24px_rgba(15,23,42,0.14)]",
|
||||
isDarkInline
|
||||
? "border border-white/12 bg-[#0d1013]/98 text-white backdrop-blur-xl"
|
||||
: "border border-[#d8dde4] bg-[#f3f4f6]/95"
|
||||
)}
|
||||
>
|
||||
<div className="space-y-2.5">
|
||||
{/* 提示词智能优化 */}
|
||||
{showPromptExtend && (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-0.5">
|
||||
<span className="text-[12px] font-semibold text-[#2f3b48]">提示词优化</span>
|
||||
<p className="text-[11px] text-[#8a94a3]">AI 自动优化您的描述</p>
|
||||
<span className={cn("text-[12px] font-semibold", isDarkInline ? "text-white/88" : "text-[#2f3b48]")}>提示词优化</span>
|
||||
<p className={cn("text-[11px]", isDarkInline ? "text-white/45" : "text-[#8a94a3]")}>AI 自动优化您的描述</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={params.promptExtend ?? true}
|
||||
@ -442,12 +509,17 @@ export function ImageParamsBar({
|
||||
{/* 反向提示词 */}
|
||||
{showNegativePrompt && (
|
||||
<div className="space-y-1">
|
||||
<span className="text-[12px] font-semibold text-[#2f3b48]">反向提示词</span>
|
||||
<span className={cn("text-[12px] font-semibold", isDarkInline ? "text-white/88" : "text-[#2f3b48]")}>反向提示词</span>
|
||||
<Input
|
||||
placeholder="不希望出现的内容,如:低质量、模糊..."
|
||||
value={params.negativePrompt || ""}
|
||||
onChange={(e) => updateParam("negativePrompt", e.target.value)}
|
||||
className="h-7 rounded-[8px] border-[#dce1e8] bg-[#eef1f4]/90 text-[12px] text-[#2f3b48] placeholder:text-[#b0b8c4]"
|
||||
className={cn(
|
||||
"h-7 rounded-[8px] text-[12px]",
|
||||
isDarkInline
|
||||
? "border-white/12 bg-white/[0.04] text-white placeholder:text-white/28"
|
||||
: "border-[#dce1e8] bg-[#eef1f4]/90 text-[#2f3b48] placeholder:text-[#b0b8c4]"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user