fix: compact enhance pro workspace layout
This commit is contained in:
parent
5c2ece9fb6
commit
9c8228b697
@ -89,6 +89,10 @@ const FALLBACK_CONFIG: EnhanceProClientConfig = {
|
|||||||
presets: defaultEnhanceProPresets(),
|
presets: defaultEnhanceProPresets(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SOLID_PANEL_FIELD_CLASS = "border-white/10 bg-[#1a1b22] text-white";
|
||||||
|
const SOLID_PANEL_CARD_CLASS = "rounded-2xl border border-white/10 bg-[#17181f]";
|
||||||
|
const SOLID_PANEL_CHIP_CLASS = "rounded-full border border-white/10 bg-[#1b1c24]";
|
||||||
|
|
||||||
function clampNumber(value: number, min: number, max: number) {
|
function clampNumber(value: number, min: number, max: number) {
|
||||||
return Math.min(max, Math.max(min, value));
|
return Math.min(max, Math.max(min, value));
|
||||||
}
|
}
|
||||||
@ -486,7 +490,7 @@ export function EnhanceProWorkspace({
|
|||||||
className="max-h-full max-w-full object-contain"
|
className="max-h-full max-w-full object-contain"
|
||||||
src={getDisplayImageUrl(activePreviewUrl, 1800)}
|
src={getDisplayImageUrl(activePreviewUrl, 1800)}
|
||||||
/>
|
/>
|
||||||
<div className="pointer-events-none absolute top-6 left-6 flex items-center gap-2 rounded-full border border-white/10 bg-black/45 px-3 py-1.5 text-white/80 text-xs backdrop-blur-md">
|
<div className="pointer-events-none absolute top-6 left-6 flex items-center gap-2 rounded-full border border-white/10 bg-[#101114] px-3 py-1.5 text-white/80 text-xs">
|
||||||
<ImageIcon className="h-3.5 w-3.5" />
|
<ImageIcon className="h-3.5 w-3.5" />
|
||||||
<span>{activePreviewLabel}</span>
|
<span>{activePreviewLabel}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -506,7 +510,7 @@ export function EnhanceProWorkspace({
|
|||||||
|
|
||||||
{sidePreviewItems.length > 0 ? (
|
{sidePreviewItems.length > 0 ? (
|
||||||
<div className="absolute right-6 bottom-6 left-6 flex items-center justify-center">
|
<div className="absolute right-6 bottom-6 left-6 flex items-center justify-center">
|
||||||
<div className="flex max-w-[min(720px,calc(100vw-5rem))] items-center gap-2 rounded-[24px] border border-white/10 bg-black/45 px-3 py-3 shadow-2xl backdrop-blur-xl">
|
<div className="flex max-w-[min(720px,calc(100vw-5rem))] items-center gap-2 rounded-[24px] border border-white/10 bg-[#101114] px-3 py-3 shadow-2xl">
|
||||||
{sidePreviewItems.map((item, index) => {
|
{sidePreviewItems.map((item, index) => {
|
||||||
const isActive = item.isSource
|
const isActive = item.isSource
|
||||||
? selectedResultIndex < 0
|
? selectedResultIndex < 0
|
||||||
@ -539,50 +543,29 @@ export function EnhanceProWorkspace({
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-[360px] shrink-0 flex-col border-white/10 border-l bg-[#111217]/95">
|
<div className="flex h-full w-[420px] max-w-[42vw] shrink-0 flex-col border-white/10 border-l bg-[#111217]">
|
||||||
<div className="border-white/10 border-b px-5 py-5">
|
<div className="border-white/10 border-b px-4 py-4 pr-24">
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2 font-semibold text-base text-white">
|
<div className="flex items-center gap-2 font-semibold text-base text-white">
|
||||||
<Wand2 className="h-4.5 w-4.5 text-sky-300" />
|
<Wand2 className="h-4.5 w-4.5 text-sky-300" />
|
||||||
图像增强模式
|
图像增强模式
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-white/55 text-xs leading-5">
|
|
||||||
使用 {config.providerName}{" "}
|
|
||||||
对单张图片进行更可控的增强、修复和细节重建。
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-full border border-white/10 bg-white/5 px-2.5 py-1 text-[11px] text-white/65">
|
<div
|
||||||
|
className={cn(
|
||||||
|
SOLID_PANEL_CHIP_CLASS,
|
||||||
|
"px-2.5 py-1 text-[11px] text-white/70"
|
||||||
|
)}
|
||||||
|
>
|
||||||
{selectedPreset?.model || config.defaultModel}
|
{selectedPreset?.model || config.defaultModel}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-4 overflow-hidden rounded-2xl border border-white/10 bg-black/30">
|
|
||||||
{sourceImageUrl ? (
|
|
||||||
<img
|
|
||||||
alt="增强源图"
|
|
||||||
className="h-[128px] w-full object-cover"
|
|
||||||
src={getDisplayImageUrl(sourceImageUrl, 420)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div className="flex h-[128px] items-center justify-center text-sm text-white/40">
|
|
||||||
暂无源图
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="mt-3 flex flex-wrap gap-2 text-[11px] text-white/50">
|
|
||||||
<span className="rounded-full border border-white/10 bg-white/5 px-2 py-1">
|
|
||||||
原图 {naturalSize.width} x {naturalSize.height}
|
|
||||||
</span>
|
|
||||||
<span className="rounded-full border border-white/10 bg-white/5 px-2 py-1">
|
|
||||||
最大输出长边 {config.maxOutputEdge}px
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-h-0 flex-1 space-y-5 overflow-y-auto px-5 py-5">
|
<div className="min-h-0 flex-1 space-y-4 overflow-y-auto px-4 py-4">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center gap-2 rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-white/60">
|
<div className={cn(SOLID_PANEL_CARD_CLASS, "flex items-center gap-2 px-4 py-3 text-sm text-white/60")}>
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
正在加载增强配置...
|
正在加载增强配置...
|
||||||
</div>
|
</div>
|
||||||
@ -602,9 +585,11 @@ export function EnhanceProWorkspace({
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-white/80">增强预设</Label>
|
<Label className="text-[11px] uppercase tracking-[0.08em] text-white/65">
|
||||||
|
增强预设
|
||||||
|
</Label>
|
||||||
<Select onValueChange={handleSelectPreset} value={selectedPresetId}>
|
<Select onValueChange={handleSelectPreset} value={selectedPresetId}>
|
||||||
<SelectTrigger className="border-white/10 bg-white/5 text-white">
|
<SelectTrigger className={`${SOLID_PANEL_FIELD_CLASS} h-10`}>
|
||||||
<SelectValue placeholder="选择一个增强预设" />
|
<SelectValue placeholder="选择一个增强预设" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@ -616,7 +601,7 @@ export function EnhanceProWorkspace({
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
{selectedPreset ? (
|
{selectedPreset ? (
|
||||||
<div className="text-white/45 text-xs leading-5">
|
<div className="line-clamp-2 text-[11px] leading-5 text-white/45">
|
||||||
{selectedPreset.description ||
|
{selectedPreset.description ||
|
||||||
`${selectedPreset.model} · ${getSubjectDetectionLabel(selectedPreset.subjectDetection)}`}
|
`${selectedPreset.model} · ${getSubjectDetectionLabel(selectedPreset.subjectDetection)}`}
|
||||||
</div>
|
</div>
|
||||||
@ -624,11 +609,14 @@ export function EnhanceProWorkspace({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-white/80" htmlFor="enhance-workspace-prompt">
|
<Label
|
||||||
|
className="text-[11px] uppercase tracking-[0.08em] text-white/65"
|
||||||
|
htmlFor="enhance-workspace-prompt"
|
||||||
|
>
|
||||||
增强提示词
|
增强提示词
|
||||||
</Label>
|
</Label>
|
||||||
<Textarea
|
<Textarea
|
||||||
className="border-white/10 bg-white/5 text-white placeholder:text-white/30"
|
className={`${SOLID_PANEL_FIELD_CLASS} min-h-[82px] resize-none placeholder:text-white/30`}
|
||||||
id="enhance-workspace-prompt"
|
id="enhance-workspace-prompt"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setFormState((prev) => ({
|
setFormState((prev) => ({
|
||||||
@ -637,221 +625,251 @@ export function EnhanceProWorkspace({
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
placeholder="例如:保持主体不变,提升画质层次、纹理和局部细节,让结果更高级。"
|
placeholder="例如:保持主体不变,提升画质层次、纹理和局部细节,让结果更高级。"
|
||||||
rows={4}
|
rows={3}
|
||||||
value={formState.prompt}
|
value={formState.prompt}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="space-y-2">
|
||||||
<div className="space-y-2">
|
<div className="text-[11px] uppercase tracking-[0.08em] text-white/65">
|
||||||
<Label
|
基础参数
|
||||||
className="text-white/80"
|
|
||||||
htmlFor="enhance-workspace-width"
|
|
||||||
>
|
|
||||||
输出宽度
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
className="border-white/10 bg-white/5 text-white"
|
|
||||||
id="enhance-workspace-width"
|
|
||||||
max={config.maxOutputEdge}
|
|
||||||
min="1"
|
|
||||||
onChange={(event) =>
|
|
||||||
handleNumericField(
|
|
||||||
"width",
|
|
||||||
clampNumber(
|
|
||||||
Number.parseInt(event.target.value, 10) || 1,
|
|
||||||
1,
|
|
||||||
config.maxOutputEdge
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
type="number"
|
|
||||||
value={formState.width}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="grid grid-cols-3 gap-3">
|
||||||
<Label
|
<div className="space-y-1.5">
|
||||||
className="text-white/80"
|
<Label
|
||||||
htmlFor="enhance-workspace-height"
|
className="text-xs text-white/70"
|
||||||
>
|
htmlFor="enhance-workspace-width"
|
||||||
输出高度
|
>
|
||||||
</Label>
|
宽度
|
||||||
<Input
|
</Label>
|
||||||
className="border-white/10 bg-white/5 text-white"
|
<Input
|
||||||
id="enhance-workspace-height"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max={config.maxOutputEdge}
|
id="enhance-workspace-width"
|
||||||
min="1"
|
max={config.maxOutputEdge}
|
||||||
onChange={(event) =>
|
min="1"
|
||||||
handleNumericField(
|
onChange={(event) =>
|
||||||
"height",
|
|
||||||
clampNumber(
|
|
||||||
Number.parseInt(event.target.value, 10) || 1,
|
|
||||||
1,
|
|
||||||
config.maxOutputEdge
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
type="number"
|
|
||||||
value={formState.height}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-3 gap-3">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label className="text-white/80">增强模式</Label>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) =>
|
|
||||||
setFormState((prev) => ({
|
|
||||||
...prev,
|
|
||||||
model: value as FormState["model"],
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
value={formState.model}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="border-white/10 bg-white/5 text-white">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="Redefine">Redefine</SelectItem>
|
|
||||||
<SelectItem value="Recovery">Recovery</SelectItem>
|
|
||||||
<SelectItem value="Recovery V2">Recovery V2</SelectItem>
|
|
||||||
<SelectItem value="Reimagine">Reimagine</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label className="text-white/80">输出格式</Label>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) =>
|
|
||||||
setFormState((prev) => ({
|
|
||||||
...prev,
|
|
||||||
output_format: value as FormState["output_format"],
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
value={formState.output_format}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="border-white/10 bg-white/5 text-white">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="jpg">JPG</SelectItem>
|
|
||||||
<SelectItem value="png">PNG</SelectItem>
|
|
||||||
<SelectItem value="webp">WEBP</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label className="text-white/80">作用区域</Label>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) =>
|
|
||||||
setFormState((prev) => ({
|
|
||||||
...prev,
|
|
||||||
subject_detection: value as FormState["subject_detection"],
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
value={formState.subject_detection}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="border-white/10 bg-white/5 text-white">
|
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="All">全部</SelectItem>
|
|
||||||
<SelectItem value="Foreground">前景</SelectItem>
|
|
||||||
<SelectItem value="Background">背景</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-3 gap-3">
|
|
||||||
{config.allowBatchSize ? (
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label className="text-white/80">候选结果</Label>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) =>
|
|
||||||
handleNumericField(
|
handleNumericField(
|
||||||
"batchSize",
|
"width",
|
||||||
clampNumber(
|
clampNumber(
|
||||||
Number.parseInt(value, 10) || 1,
|
Number.parseInt(event.target.value, 10) || 1,
|
||||||
1,
|
1,
|
||||||
config.maxBatchSize
|
config.maxOutputEdge
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
value={String(formState.batchSize)}
|
type="number"
|
||||||
|
value={formState.width}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label
|
||||||
|
className="text-xs text-white/70"
|
||||||
|
htmlFor="enhance-workspace-height"
|
||||||
>
|
>
|
||||||
<SelectTrigger className="border-white/10 bg-white/5 text-white">
|
高度
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
|
id="enhance-workspace-height"
|
||||||
|
max={config.maxOutputEdge}
|
||||||
|
min="1"
|
||||||
|
onChange={(event) =>
|
||||||
|
handleNumericField(
|
||||||
|
"height",
|
||||||
|
clampNumber(
|
||||||
|
Number.parseInt(event.target.value, 10) || 1,
|
||||||
|
1,
|
||||||
|
config.maxOutputEdge
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
type="number"
|
||||||
|
value={formState.height}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{config.allowBatchSize ? (
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className="text-xs text-white/70">候选</Label>
|
||||||
|
<Select
|
||||||
|
onValueChange={(value) =>
|
||||||
|
handleNumericField(
|
||||||
|
"batchSize",
|
||||||
|
clampNumber(
|
||||||
|
Number.parseInt(value, 10) || 1,
|
||||||
|
1,
|
||||||
|
config.maxBatchSize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
value={String(formState.batchSize)}
|
||||||
|
>
|
||||||
|
<SelectTrigger
|
||||||
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
|
>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{Array.from(
|
||||||
|
{ length: config.maxBatchSize },
|
||||||
|
(_, index) => index + 1
|
||||||
|
).map((item) => (
|
||||||
|
<SelectItem key={item} value={String(item)}>
|
||||||
|
{item} 张
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label
|
||||||
|
className="text-xs text-white/70"
|
||||||
|
htmlFor="enhance-workspace-seed"
|
||||||
|
>
|
||||||
|
Seed
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
|
id="enhance-workspace-seed"
|
||||||
|
onChange={(event) =>
|
||||||
|
handleNumericField(
|
||||||
|
"seed",
|
||||||
|
Number.parseInt(event.target.value, 10) || 1337
|
||||||
|
)
|
||||||
|
}
|
||||||
|
type="number"
|
||||||
|
value={formState.seed}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className="text-xs text-white/70">模式</Label>
|
||||||
|
<Select
|
||||||
|
onValueChange={(value) =>
|
||||||
|
setFormState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
model: value as FormState["model"],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
value={formState.model}
|
||||||
|
>
|
||||||
|
<SelectTrigger className={`${SOLID_PANEL_FIELD_CLASS} h-10`}>
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{Array.from(
|
<SelectItem value="Redefine">Redefine</SelectItem>
|
||||||
{ length: config.maxBatchSize },
|
<SelectItem value="Recovery">Recovery</SelectItem>
|
||||||
(_, index) => index + 1
|
<SelectItem value="Recovery V2">Recovery V2</SelectItem>
|
||||||
).map((item) => (
|
<SelectItem value="Reimagine">Reimagine</SelectItem>
|
||||||
<SelectItem key={item} value={String(item)}>
|
|
||||||
{item} 张
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
<div className="space-y-1.5">
|
||||||
<div className="space-y-2">
|
<Label className="text-xs text-white/70">格式</Label>
|
||||||
<Label className="text-white/80" htmlFor="enhance-workspace-seed">
|
<Select
|
||||||
Seed
|
onValueChange={(value) =>
|
||||||
</Label>
|
setFormState((prev) => ({
|
||||||
<Input
|
...prev,
|
||||||
className="border-white/10 bg-white/5 text-white"
|
output_format: value as FormState["output_format"],
|
||||||
id="enhance-workspace-seed"
|
}))
|
||||||
onChange={(event) =>
|
}
|
||||||
handleNumericField(
|
value={formState.output_format}
|
||||||
"seed",
|
>
|
||||||
Number.parseInt(event.target.value, 10) || 1337
|
<SelectTrigger className={`${SOLID_PANEL_FIELD_CLASS} h-10`}>
|
||||||
)
|
<SelectValue />
|
||||||
}
|
</SelectTrigger>
|
||||||
type="number"
|
<SelectContent>
|
||||||
value={formState.seed}
|
<SelectItem value="jpg">JPG</SelectItem>
|
||||||
/>
|
<SelectItem value="png">PNG</SelectItem>
|
||||||
</div>
|
<SelectItem value="webp">WEBP</SelectItem>
|
||||||
<div className="space-y-2">
|
</SelectContent>
|
||||||
<Label
|
</Select>
|
||||||
className="text-white/80"
|
</div>
|
||||||
htmlFor="enhance-workspace-scale"
|
<div className="space-y-1.5">
|
||||||
>
|
<Label className="text-xs text-white/70">区域</Label>
|
||||||
放大倍数
|
<Select
|
||||||
</Label>
|
onValueChange={(value) =>
|
||||||
<Input
|
setFormState((prev) => ({
|
||||||
className="border-white/10 bg-white/5 text-white"
|
...prev,
|
||||||
id="enhance-workspace-scale"
|
subject_detection: value as FormState["subject_detection"],
|
||||||
max="32"
|
}))
|
||||||
min="1"
|
}
|
||||||
onChange={(event) =>
|
value={formState.subject_detection}
|
||||||
handleNumericField(
|
>
|
||||||
"image_scaling_factor",
|
<SelectTrigger className={`${SOLID_PANEL_FIELD_CLASS} h-10`}>
|
||||||
clampNumber(
|
<SelectValue />
|
||||||
Number.parseFloat(event.target.value) || 1,
|
</SelectTrigger>
|
||||||
1,
|
<SelectContent>
|
||||||
32
|
<SelectItem value="All">全部</SelectItem>
|
||||||
|
<SelectItem value="Foreground">前景</SelectItem>
|
||||||
|
<SelectItem value="Background">背景</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
{config.allowBatchSize ? (
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label
|
||||||
|
className="text-xs text-white/70"
|
||||||
|
htmlFor="enhance-workspace-seed"
|
||||||
|
>
|
||||||
|
Seed
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
|
id="enhance-workspace-seed"
|
||||||
|
onChange={(event) =>
|
||||||
|
handleNumericField(
|
||||||
|
"seed",
|
||||||
|
Number.parseInt(event.target.value, 10) || 1337
|
||||||
|
)
|
||||||
|
}
|
||||||
|
type="number"
|
||||||
|
value={formState.seed}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label
|
||||||
|
className="text-xs text-white/70"
|
||||||
|
htmlFor="enhance-workspace-scale"
|
||||||
|
>
|
||||||
|
放大
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
|
id="enhance-workspace-scale"
|
||||||
|
max="32"
|
||||||
|
min="1"
|
||||||
|
onChange={(event) =>
|
||||||
|
handleNumericField(
|
||||||
|
"image_scaling_factor",
|
||||||
|
clampNumber(
|
||||||
|
Number.parseFloat(event.target.value) || 1,
|
||||||
|
1,
|
||||||
|
32
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
step="0.5"
|
||||||
step="0.5"
|
type="number"
|
||||||
type="number"
|
value={formState.image_scaling_factor}
|
||||||
value={formState.image_scaling_factor}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-3 gap-3">
|
<div className="space-y-2">
|
||||||
<div className="rounded-2xl border border-white/10 bg-white/5 p-3">
|
<div className="text-[11px] uppercase tracking-[0.08em] text-white/65">
|
||||||
<div className="flex items-center justify-between gap-3">
|
增强开关
|
||||||
<div>
|
</div>
|
||||||
<div className="font-medium text-sm text-white">人脸增强</div>
|
<div className="grid grid-cols-3 gap-3">
|
||||||
<div className="mt-1 text-[11px] text-white/45 leading-4">
|
<div
|
||||||
适合人像和模特图修复
|
className={cn(
|
||||||
</div>
|
SOLID_PANEL_CARD_CLASS,
|
||||||
</div>
|
"flex items-center justify-between gap-3 px-3 py-3"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="text-sm text-white">人脸增强</span>
|
||||||
<Switch
|
<Switch
|
||||||
checked={formState.face_enhancement}
|
checked={formState.face_enhancement}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
@ -862,15 +880,13 @@ export function EnhanceProWorkspace({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<div className="rounded-2xl border border-white/10 bg-white/5 p-3">
|
className={cn(
|
||||||
<div className="flex items-center justify-between gap-3">
|
SOLID_PANEL_CARD_CLASS,
|
||||||
<div>
|
"flex items-center justify-between gap-3 px-3 py-3"
|
||||||
<div className="font-medium text-sm text-white">启用放大</div>
|
)}
|
||||||
<div className="mt-1 text-[11px] text-white/45 leading-4">
|
>
|
||||||
强化增强时的上采样
|
<span className="text-sm text-white">启用放大</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Switch
|
<Switch
|
||||||
checked={formState.upscaling_activated}
|
checked={formState.upscaling_activated}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
@ -881,15 +897,13 @@ export function EnhanceProWorkspace({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<div className="rounded-2xl border border-white/10 bg-white/5 p-3">
|
className={cn(
|
||||||
<div className="flex items-center justify-between gap-3">
|
SOLID_PANEL_CARD_CLASS,
|
||||||
<div>
|
"flex items-center justify-between gap-3 px-3 py-3"
|
||||||
<div className="font-medium text-sm text-white">裁剪铺满</div>
|
)}
|
||||||
<div className="mt-1 text-[11px] text-white/45 leading-4">
|
>
|
||||||
尺寸比例不同时裁切填充
|
<span className="text-sm text-white">裁剪铺满</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Switch
|
<Switch
|
||||||
checked={formState.crop_to_fill}
|
checked={formState.crop_to_fill}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
@ -903,13 +917,15 @@ export function EnhanceProWorkspace({
|
|||||||
{config.enableAdvancedControls ? (
|
{config.enableAdvancedControls ? (
|
||||||
<>
|
<>
|
||||||
<Separator className="bg-white/10" />
|
<Separator className="bg-white/10" />
|
||||||
<div className="space-y-3">
|
<div className="space-y-2">
|
||||||
<div className="font-medium text-sm text-white">高级调节</div>
|
<div className="text-[11px] uppercase tracking-[0.08em] text-white/65">
|
||||||
<div className="grid grid-cols-2 gap-3">
|
高级调节
|
||||||
<div className="space-y-2">
|
</div>
|
||||||
<Label className="text-white/80">Creativity (1-6)</Label>
|
<div className="grid grid-cols-3 gap-3">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className="text-xs text-white/70">创造力</Label>
|
||||||
<Input
|
<Input
|
||||||
className="border-white/10 bg-white/5 text-white"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max="6"
|
max="6"
|
||||||
min="1"
|
min="1"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -926,10 +942,10 @@ export function EnhanceProWorkspace({
|
|||||||
value={formState.creativity}
|
value={formState.creativity}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-1.5">
|
||||||
<Label className="text-white/80">Texture (1-5)</Label>
|
<Label className="text-xs text-white/70">纹理</Label>
|
||||||
<Input
|
<Input
|
||||||
className="border-white/10 bg-white/5 text-white"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max="5"
|
max="5"
|
||||||
min="1"
|
min="1"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -946,10 +962,10 @@ export function EnhanceProWorkspace({
|
|||||||
value={formState.texture}
|
value={formState.texture}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-1.5">
|
||||||
<Label className="text-white/80">Detail (0-1)</Label>
|
<Label className="text-xs text-white/70">细节</Label>
|
||||||
<Input
|
<Input
|
||||||
className="border-white/10 bg-white/5 text-white"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max="1"
|
max="1"
|
||||||
min="0"
|
min="0"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -967,10 +983,10 @@ export function EnhanceProWorkspace({
|
|||||||
value={formState.detail}
|
value={formState.detail}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-1.5">
|
||||||
<Label className="text-white/80">Sharpen (0-1)</Label>
|
<Label className="text-xs text-white/70">锐化</Label>
|
||||||
<Input
|
<Input
|
||||||
className="border-white/10 bg-white/5 text-white"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max="1"
|
max="1"
|
||||||
min="0"
|
min="0"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -988,10 +1004,10 @@ export function EnhanceProWorkspace({
|
|||||||
value={formState.sharpen}
|
value={formState.sharpen}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-1.5">
|
||||||
<Label className="text-white/80">Denoise (0-1)</Label>
|
<Label className="text-xs text-white/70">降噪</Label>
|
||||||
<Input
|
<Input
|
||||||
className="border-white/10 bg-white/5 text-white"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max="1"
|
max="1"
|
||||||
min="0"
|
min="0"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -1009,10 +1025,10 @@ export function EnhanceProWorkspace({
|
|||||||
value={formState.denoise}
|
value={formState.denoise}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-1.5">
|
||||||
<Label className="text-white/80">Face Strength (0-1)</Label>
|
<Label className="text-xs text-white/70">脸部力度</Label>
|
||||||
<Input
|
<Input
|
||||||
className="border-white/10 bg-white/5 text-white"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max="1"
|
max="1"
|
||||||
min="0"
|
min="0"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -1030,12 +1046,10 @@ export function EnhanceProWorkspace({
|
|||||||
value={formState.face_enhancement_strength}
|
value={formState.face_enhancement_strength}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-1.5">
|
||||||
<Label className="text-white/80">
|
<Label className="text-xs text-white/70">脸部创意</Label>
|
||||||
Face Creativity (0-1)
|
|
||||||
</Label>
|
|
||||||
<Input
|
<Input
|
||||||
className="border-white/10 bg-white/5 text-white"
|
className={`${SOLID_PANEL_FIELD_CLASS} h-10`}
|
||||||
max="1"
|
max="1"
|
||||||
min="0"
|
min="0"
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
@ -1059,12 +1073,12 @@ export function EnhanceProWorkspace({
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-white/10 border-t px-5 py-4">
|
<div className="border-white/10 border-t px-4 py-3">
|
||||||
<div className="mb-3 flex items-center justify-between text-white/45 text-xs">
|
<div className="mb-3 flex items-center justify-between text-white/45 text-xs">
|
||||||
<span>
|
<span>
|
||||||
{generatedImages.length > 0
|
{generatedImages.length > 0
|
||||||
? `已生成 ${generatedImages.length} 张候选结果`
|
? `已生成 ${generatedImages.length} 张候选结果`
|
||||||
: "结果会在生成后显示并可发送回画布"}
|
: "生成后可直接发送回画布"}
|
||||||
</span>
|
</span>
|
||||||
{selectedGeneratedImage ? (
|
{selectedGeneratedImage ? (
|
||||||
<span className="inline-flex items-center gap-1 text-emerald-300">
|
<span className="inline-flex items-center gap-1 text-emerald-300">
|
||||||
@ -1075,7 +1089,7 @@ export function EnhanceProWorkspace({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
className="h-11 flex-1 rounded-2xl bg-[#0f62fe] text-white hover:bg-[#0a58e0]"
|
className="h-10 flex-1 rounded-2xl bg-[#0f62fe] text-white hover:bg-[#0a58e0]"
|
||||||
disabled={isSubmitting || !sourceImageUrl}
|
disabled={isSubmitting || !sourceImageUrl}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
type="button"
|
type="button"
|
||||||
@ -1088,7 +1102,7 @@ export function EnhanceProWorkspace({
|
|||||||
开始增强 Pro
|
开始增强 Pro
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className="h-11 rounded-2xl border-white/10 bg-white/5 px-4 text-white hover:bg-white/10 hover:text-white"
|
className="h-10 rounded-2xl border-white/10 bg-[#1a1b22] px-4 text-white hover:bg-[#23242c] hover:text-white"
|
||||||
disabled={!selectedGeneratedImage}
|
disabled={!selectedGeneratedImage}
|
||||||
onClick={handleApply}
|
onClick={handleApply}
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -2961,7 +2961,7 @@ export function RealtimeCanvasDialog({
|
|||||||
)}
|
)}
|
||||||
<div className="pointer-events-none absolute top-6 left-6 z-50 flex flex-col gap-3">
|
<div className="pointer-events-none absolute top-6 left-6 z-50 flex flex-col gap-3">
|
||||||
<button
|
<button
|
||||||
className="pointer-events-auto flex items-center gap-3 rounded-full border border-border/40 bg-background/80 px-4 py-2 shadow-sm backdrop-blur-md transition hover:bg-background"
|
className="pointer-events-auto flex items-center gap-3 rounded-full border border-white/10 bg-[#111216] px-4 py-2 text-white shadow-sm transition hover:bg-[#1a1b22]"
|
||||||
onClick={handleGoHome}
|
onClick={handleGoHome}
|
||||||
title="返回首页"
|
title="返回首页"
|
||||||
type="button"
|
type="button"
|
||||||
@ -2981,18 +2981,18 @@ export function RealtimeCanvasDialog({
|
|||||||
<Sparkles className="h-3.5 w-3.5" />
|
<Sparkles className="h-3.5 w-3.5" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<span className="font-semibold text-foreground text-sm">
|
<span className="font-semibold text-sm text-white">
|
||||||
{siteName}
|
{siteName}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div className="pointer-events-auto inline-flex w-fit items-center gap-1 rounded-full border border-border/40 bg-background/85 p-1.5 shadow-sm backdrop-blur-md">
|
<div className="pointer-events-auto inline-flex w-fit items-center gap-1 rounded-full border border-white/10 bg-[#111216] p-1.5 shadow-sm">
|
||||||
<button
|
<button
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center gap-2 rounded-full px-3 py-2 text-sm transition",
|
"inline-flex items-center gap-2 rounded-full px-3 py-2 text-sm transition",
|
||||||
workspaceMode === "realtime"
|
workspaceMode === "realtime"
|
||||||
? "bg-foreground text-background shadow-sm"
|
? "bg-white text-black shadow-sm"
|
||||||
: "text-foreground/70 hover:bg-background hover:text-foreground"
|
: "bg-[#1a1b22] text-white/78 hover:bg-[#23242c] hover:text-white"
|
||||||
)}
|
)}
|
||||||
onClick={() => setWorkspaceMode("realtime")}
|
onClick={() => setWorkspaceMode("realtime")}
|
||||||
type="button"
|
type="button"
|
||||||
@ -3004,8 +3004,8 @@ export function RealtimeCanvasDialog({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center gap-2 rounded-full px-3 py-2 text-sm transition",
|
"inline-flex items-center gap-2 rounded-full px-3 py-2 text-sm transition",
|
||||||
workspaceMode === "enhance-pro"
|
workspaceMode === "enhance-pro"
|
||||||
? "bg-foreground text-background shadow-sm"
|
? "bg-white text-black shadow-sm"
|
||||||
: "text-foreground/70 hover:bg-background hover:text-foreground"
|
: "bg-[#1a1b22] text-white/78 hover:bg-[#23242c] hover:text-white"
|
||||||
)}
|
)}
|
||||||
onClick={() => setWorkspaceMode("enhance-pro")}
|
onClick={() => setWorkspaceMode("enhance-pro")}
|
||||||
type="button"
|
type="button"
|
||||||
@ -3017,9 +3017,9 @@ export function RealtimeCanvasDialog({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="pointer-events-none absolute top-6 right-6 z-50">
|
<div className="pointer-events-none absolute top-6 right-6 z-50">
|
||||||
<div className="pointer-events-auto rounded-full border border-black bg-black p-1 shadow-sm">
|
<div className="pointer-events-auto rounded-full border border-white/10 bg-[#111216] p-1 shadow-sm">
|
||||||
<Button
|
<Button
|
||||||
className="h-7 w-7 rounded-full text-white transition hover:bg-white/10 hover:text-white"
|
className="h-7 w-7 rounded-full bg-[#1a1b22] text-white transition hover:bg-[#23242c] hover:text-white"
|
||||||
onClick={handleCloseRealtime}
|
onClick={handleCloseRealtime}
|
||||||
size="icon"
|
size="icon"
|
||||||
title="关闭"
|
title="关闭"
|
||||||
@ -3290,7 +3290,7 @@ export function RealtimeCanvasDialog({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute top-28 bottom-4 left-4 z-10 flex w-16 max-w-[18vw] flex-col rounded-[24px] border border-border/40 bg-background/80 p-2 shadow-xl backdrop-blur-md">
|
<div className="absolute top-28 bottom-4 left-4 z-10 flex w-16 max-w-[18vw] flex-col rounded-[24px] border border-border/40 bg-[#111216] p-2 shadow-xl">
|
||||||
<div className="flex items-center justify-center border-border/10 border-b pb-3">
|
<div className="flex items-center justify-center border-border/10 border-b pb-3">
|
||||||
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-muted text-foreground">
|
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-muted text-foreground">
|
||||||
<Layers3 className="h-4 w-4" />
|
<Layers3 className="h-4 w-4" />
|
||||||
@ -3433,7 +3433,7 @@ export function RealtimeCanvasDialog({
|
|||||||
/>
|
/>
|
||||||
<div className="-translate-x-1/2 pointer-events-none absolute bottom-4 left-1/2 z-30 flex w-[min(600px,calc(100vw-2rem))] flex-col items-center gap-2.5">
|
<div className="-translate-x-1/2 pointer-events-none absolute bottom-4 left-1/2 z-30 flex w-[min(600px,calc(100vw-2rem))] flex-col items-center gap-2.5">
|
||||||
<TooltipProvider delayDuration={120}>
|
<TooltipProvider delayDuration={120}>
|
||||||
<div className="pointer-events-auto flex flex-wrap items-center justify-center gap-1 rounded-[24px] border border-border/40 bg-background/80 p-1.5 shadow-xl backdrop-blur-md">
|
<div className="pointer-events-auto flex flex-wrap items-center justify-center gap-1 rounded-[24px] border border-border/40 bg-[#111216] p-1.5 shadow-xl">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@ -3760,7 +3760,7 @@ export function RealtimeCanvasDialog({
|
|||||||
</div>
|
</div>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|
||||||
<div className="pointer-events-auto w-full rounded-[24px] border border-border/40 bg-background/80 p-4 shadow-2xl backdrop-blur-md">
|
<div className="pointer-events-auto w-full rounded-[24px] border border-border/40 bg-[#111216] p-4 shadow-2xl">
|
||||||
<Textarea
|
<Textarea
|
||||||
className="min-h-[56px] resize-none border-0 bg-transparent px-1 py-0.5 text-[15px] leading-7 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0"
|
className="min-h-[56px] resize-none border-0 bg-transparent px-1 py-0.5 text-[15px] leading-7 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0"
|
||||||
onBlur={() => scheduleFlush(true, false)}
|
onBlur={() => scheduleFlush(true, false)}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user