Align PSD template pool layout
This commit is contained in:
parent
d58b706799
commit
c843661da3
@ -41,7 +41,6 @@ import {
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Slider } from "@/components/ui/slider";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
@ -3039,6 +3038,94 @@ export function AgentPsdTemplateEditorDialog({
|
||||
setSelectedTemplateId(nextTemplates[0].id);
|
||||
}
|
||||
|
||||
function renderTemplatePoolSection({
|
||||
mode,
|
||||
templates: poolTemplates,
|
||||
}: {
|
||||
mode: AgentPsdTemplateMode;
|
||||
templates: AgentPsdTemplate[];
|
||||
}) {
|
||||
const isSkuMode = mode === "sku";
|
||||
const title = isSkuMode ? "SKU图模式模板" : "主图模式模板";
|
||||
const description = selectedCategorySummaryText
|
||||
? `当前按品类“${selectedCategorySummaryText}”筛选,同时保留“适合所有”的模板。`
|
||||
: normalizedBrandName
|
||||
? `这里集中展示当前品牌下的${isSkuMode ? " SKU 图" : "主图"}模式模板。`
|
||||
: `当前未选择品牌,这里展示全部品牌下的${isSkuMode ? " SKU 图" : "主图"}模式模板。`;
|
||||
const emptyMessage = selectedCategorySummaryText
|
||||
? `当前品类“${selectedCategorySummaryText}”下暂无${isSkuMode ? " SKU 图" : "主图"}模式模板`
|
||||
: normalizedBrandName
|
||||
? `当前品牌“${normalizedBrandName}”下暂无${isSkuMode ? " SKU 图" : "主图"}模式模板`
|
||||
: `当前暂无可用的${isSkuMode ? " SKU 图" : "主图"}模式模板,请先去后台配置。`;
|
||||
const loadingMessage = `正在加载${isSkuMode ? " SKU 图" : "主图"}模式模板...`;
|
||||
const isCurrentResultMode = normalizedTemplateMode === mode;
|
||||
|
||||
return (
|
||||
<section className="flex min-h-[560px] min-w-0 flex-col overflow-hidden rounded-2xl border border-white/[0.08] bg-[#141416] p-5 shadow-[inset_0_1px_0_rgba(255,255,255,0.04),0_18px_45px_rgba(0,0,0,0.22)]">
|
||||
<div className="flex items-start justify-between gap-4 border-white/[0.07] border-b pb-4">
|
||||
<div className="min-w-0">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<h3 className="font-semibold text-base text-white">{title}</h3>
|
||||
{isCurrentResultMode ? (
|
||||
<span className="rounded-full border border-emerald-400/20 bg-emerald-400/10 px-2 py-0.5 font-medium text-[11px] text-emerald-300">
|
||||
当前模式
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<p className="mt-2 text-white/50 text-xs leading-relaxed">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
<div className="shrink-0 rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 font-medium text-white/70 text-xs">
|
||||
{poolTemplates.length} 个模板
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 min-h-0 flex-1 overflow-y-auto pr-1">
|
||||
{isLoading ? (
|
||||
<div className="grid gap-3">
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<div
|
||||
className="rounded-xl border border-white/10 border-dashed bg-white/[0.02] px-4 py-5 text-center text-sm text-white/50 shadow-inner"
|
||||
key={`${mode}-template-loading-${index}`}
|
||||
>
|
||||
{loadingMessage}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : poolTemplates.length > 0 ? (
|
||||
<div className="grid gap-3 [grid-template-columns:repeat(auto-fit,minmax(260px,1fr))]">
|
||||
{poolTemplates.map((template, index) => (
|
||||
<button
|
||||
className={`rounded-xl border p-3 text-left transition-all duration-200 ${
|
||||
selectedTemplateId === template.id
|
||||
? "border-emerald-500/50 bg-emerald-500/10 shadow-[0_0_15px_rgba(16,185,129,0.1)]"
|
||||
: "border-white/[0.08] bg-white/[0.02] hover:border-white/[0.15] hover:bg-white/[0.04]"
|
||||
}`}
|
||||
key={template.id}
|
||||
onClick={() => setSelectedTemplateId(template.id)}
|
||||
type="button"
|
||||
>
|
||||
{renderTemplatePickerCardContent(template, {
|
||||
showSecondaryCategory:
|
||||
shouldGroupTemplatesBySecondaryCategory,
|
||||
showBrand: shouldShowTemplateBrand,
|
||||
emphasize: true,
|
||||
eager: index < 4,
|
||||
})}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex min-h-[260px] flex-1 flex-col items-center justify-center rounded-xl border border-white/10 border-dashed bg-white/[0.02] px-6 py-10 text-center text-sm text-white/50 shadow-inner">
|
||||
{emptyMessage}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<style
|
||||
@ -3135,11 +3222,17 @@ export function AgentPsdTemplateEditorDialog({
|
||||
</div>
|
||||
|
||||
<div className="grid min-h-0 flex-1 grid-cols-1 overflow-hidden xl:grid-cols-[320px_minmax(0,1fr)_380px]">
|
||||
<div className="min-h-0 border-white/12 border-b bg-[#0a0a0a] p-5 xl:border-r xl:border-b-0">
|
||||
<ScrollArea className="h-full pr-4">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
{selectedTemplate ? (
|
||||
<div
|
||||
className={`min-h-0 border-white/12 border-b bg-[#0a0a0a] xl:border-r xl:border-b-0 ${
|
||||
selectedTemplate ? "p-5" : "p-5 xl:col-span-2 xl:p-6"
|
||||
}`}
|
||||
>
|
||||
<ScrollArea
|
||||
className={selectedTemplate ? "h-full pr-4" : "h-full pr-3"}
|
||||
>
|
||||
{selectedTemplate ? (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<div className="mb-4 flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<div className="font-semibold text-base text-white">
|
||||
@ -3147,62 +3240,48 @@ export function AgentPsdTemplateEditorDialog({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mb-4 flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<div className="font-semibold text-base text-white">
|
||||
主图模式模板
|
||||
|
||||
{selectedCategorySummaryText ? (
|
||||
<div className="rounded-lg border border-white/10 bg-white/[0.02] px-3 py-2 text-white/50 text-xs shadow-inner">
|
||||
{`当前按品类“${selectedCategorySummaryText}”筛选模板,同时保留“适合所有”的模板。`}
|
||||
</div>
|
||||
) : null}
|
||||
{hasTemplateOptions ? (
|
||||
<div className="space-y-2.5">
|
||||
<div className="inline-flex rounded-[14px] bg-white/5 p-1 shadow-inner ring-1 ring-white/10">
|
||||
<button
|
||||
className={`rounded-xl px-4 py-1.5 font-medium text-xs transition-all duration-200 ${
|
||||
selectedTemplateMode === "main"
|
||||
? "bg-emerald-500 text-white shadow-[0_2px_10px_rgba(16,185,129,0.3)] ring-1 ring-emerald-500/50"
|
||||
: "text-white/60 hover:bg-white/5 hover:text-white"
|
||||
}`}
|
||||
onClick={() =>
|
||||
handleSwitchSelectedTemplateMode("main")
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
主图模式
|
||||
</button>
|
||||
<button
|
||||
className={`rounded-xl px-4 py-1.5 font-medium text-xs transition-all duration-200 ${
|
||||
selectedTemplateMode === "sku"
|
||||
? "bg-emerald-500 text-white shadow-[0_2px_10px_rgba(16,185,129,0.3)] ring-1 ring-emerald-500/50"
|
||||
: "text-white/60 hover:bg-white/5 hover:text-white"
|
||||
}`}
|
||||
onClick={() =>
|
||||
handleSwitchSelectedTemplateMode("sku")
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
SKU图模式
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink-0 rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 font-medium text-white/70 text-xs">
|
||||
{mainModeTemplates.length} 个模板
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedCategorySummaryText ? (
|
||||
<div className="rounded-lg border border-white/10 bg-white/[0.02] px-3 py-2 text-white/50 text-xs shadow-inner">
|
||||
当前按品类“{selectedCategorySummaryText}
|
||||
”筛选模板,同时保留“适合所有”的模板。
|
||||
</div>
|
||||
) : null}
|
||||
{selectedTemplate && hasTemplateOptions ? (
|
||||
<div className="space-y-2.5">
|
||||
<div className="inline-flex rounded-[14px] bg-white/5 p-1 shadow-inner ring-1 ring-white/10">
|
||||
<button
|
||||
className={`rounded-xl px-4 py-1.5 font-medium text-xs transition-all duration-200 ${
|
||||
selectedTemplateMode === "main"
|
||||
? "bg-emerald-500 text-white shadow-[0_2px_10px_rgba(16,185,129,0.3)] ring-1 ring-emerald-500/50"
|
||||
: "text-white/60 hover:bg-white/5 hover:text-white"
|
||||
}`}
|
||||
onClick={() =>
|
||||
handleSwitchSelectedTemplateMode("main")
|
||||
}
|
||||
type="button"
|
||||
<Select
|
||||
onValueChange={setSelectedTemplateId}
|
||||
value={selectedTemplateSelectValue}
|
||||
>
|
||||
主图模式
|
||||
</button>
|
||||
<button
|
||||
className={`rounded-xl px-4 py-1.5 font-medium text-xs transition-all duration-200 ${
|
||||
selectedTemplateMode === "sku"
|
||||
? "bg-emerald-500 text-white shadow-[0_2px_10px_rgba(16,185,129,0.3)] ring-1 ring-emerald-500/50"
|
||||
: "text-white/60 hover:bg-white/5 hover:text-white"
|
||||
}`}
|
||||
onClick={() =>
|
||||
handleSwitchSelectedTemplateMode("sku")
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
SKU图模式
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Select
|
||||
onValueChange={setSelectedTemplateId}
|
||||
value={selectedTemplateSelectValue}
|
||||
>
|
||||
<SelectTrigger className="h-auto min-h-[58px] items-center rounded-xl border border-white/10 bg-white/[0.02] px-3 py-2 text-white/90 shadow-inner transition-colors hover:border-white/20 hover:bg-white/[0.04] focus:ring-1 focus:ring-emerald-500/50 data-[state=open]:border-emerald-500/50 [&>span]:contents">
|
||||
{selectedTemplate ? (
|
||||
<SelectTrigger className="h-auto min-h-[58px] items-center rounded-xl border border-white/10 bg-white/[0.02] px-3 py-2 text-white/90 shadow-inner transition-colors hover:border-white/20 hover:bg-white/[0.04] focus:ring-1 focus:ring-emerald-500/50 data-[state=open]:border-emerald-500/50 [&>span]:contents">
|
||||
<div className="min-w-0 flex-1 pr-3">
|
||||
{renderTemplateSelectContent(selectedTemplate, {
|
||||
showSecondaryCategory:
|
||||
@ -3210,152 +3289,105 @@ export function AgentPsdTemplateEditorDialog({
|
||||
showBrand: shouldShowTemplateBrand,
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<SelectValue
|
||||
placeholder={
|
||||
isLoading ? "加载模板中..." : "请选择模板"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</SelectTrigger>
|
||||
<SelectContent
|
||||
className="border-white/10 bg-[#141416] text-white shadow-2xl"
|
||||
style={{
|
||||
backgroundColor: "#141416",
|
||||
color: "#ffffff",
|
||||
}}
|
||||
>
|
||||
{shouldGroupTemplatesBySecondaryCategory
|
||||
? groupedSelectedModeTemplates.map((group) => (
|
||||
<SelectGroup
|
||||
key={`psd-template-group-${group.label}`}
|
||||
>
|
||||
<SelectLabel className="text-white/50">
|
||||
{group.label}
|
||||
</SelectLabel>
|
||||
{group.templates.map((template) => (
|
||||
<SelectItem
|
||||
className="py-2.5 pr-3 text-white focus:bg-white/10 focus:text-white data-[state=checked]:bg-white/10 data-[state=checked]:text-white"
|
||||
key={template.id}
|
||||
value={template.id}
|
||||
>
|
||||
{renderTemplateSelectContent(template, {
|
||||
showSecondaryCategory:
|
||||
shouldGroupTemplatesBySecondaryCategory,
|
||||
showBrand: shouldShowTemplateBrand,
|
||||
compact: true,
|
||||
})}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
))
|
||||
: selectedModeTemplates.map((template) => (
|
||||
<SelectItem
|
||||
className="py-2.5 pr-3 text-white focus:bg-white/10 focus:text-white data-[state=checked]:bg-white/10 data-[state=checked]:text-white"
|
||||
key={template.id}
|
||||
value={template.id}
|
||||
>
|
||||
{renderTemplateSelectContent(template, {
|
||||
showBrand: shouldShowTemplateBrand,
|
||||
compact: true,
|
||||
})}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{isLoading ? (
|
||||
<>
|
||||
{Array.from({ length: 2 }).map((_, index) => (
|
||||
<div
|
||||
className="rounded-2xl border border-white/10 border-dashed bg-white/[0.02] px-4 py-5 text-center text-sm text-white/50 shadow-inner"
|
||||
key={`main-template-loading-${index}`}
|
||||
>
|
||||
正在加载主图模式模板...
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
) : mainModeTemplates.length > 0 ? (
|
||||
mainModeTemplates.map((template, index) => (
|
||||
<button
|
||||
className={`w-full rounded-2xl border p-3 text-left transition-all duration-200 ${
|
||||
selectedTemplateId === template.id
|
||||
? "border-emerald-500/50 bg-emerald-500/10 shadow-[0_0_15px_rgba(16,185,129,0.1)]"
|
||||
: "border-white/[0.08] bg-white/[0.02] hover:border-white/[0.15] hover:bg-white/[0.04]"
|
||||
}`}
|
||||
key={template.id}
|
||||
onClick={() => setSelectedTemplateId(template.id)}
|
||||
type="button"
|
||||
</SelectTrigger>
|
||||
<SelectContent
|
||||
className="border-white/10 bg-[#141416] text-white shadow-2xl"
|
||||
style={{
|
||||
backgroundColor: "#141416",
|
||||
color: "#ffffff",
|
||||
}}
|
||||
>
|
||||
{renderTemplatePickerCardContent(template, {
|
||||
showSecondaryCategory:
|
||||
shouldGroupTemplatesBySecondaryCategory,
|
||||
showBrand: shouldShowTemplateBrand,
|
||||
emphasize: true,
|
||||
eager: index < 2,
|
||||
})}
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center rounded-2xl border border-white/10 border-dashed bg-white/[0.02] p-8 text-center text-sm text-white/50 shadow-inner">
|
||||
{selectedCategorySummaryText
|
||||
? `当前品类“${selectedCategorySummaryText}”下暂无主图模式模板`
|
||||
: normalizedBrandName
|
||||
? `当前品牌“${normalizedBrandName}”下暂无主图模式模板`
|
||||
: "当前暂无可用的主图模式模板,请先去后台配置。"}
|
||||
</div>
|
||||
)}
|
||||
{shouldGroupTemplatesBySecondaryCategory
|
||||
? groupedSelectedModeTemplates.map((group) => (
|
||||
<SelectGroup
|
||||
key={`psd-template-group-${group.label}`}
|
||||
>
|
||||
<SelectLabel className="text-white/50">
|
||||
{group.label}
|
||||
</SelectLabel>
|
||||
{group.templates.map((template) => (
|
||||
<SelectItem
|
||||
className="py-2.5 pr-3 text-white focus:bg-white/10 focus:text-white data-[state=checked]:bg-white/10 data-[state=checked]:text-white"
|
||||
key={template.id}
|
||||
value={template.id}
|
||||
>
|
||||
{renderTemplateSelectContent(
|
||||
template,
|
||||
{
|
||||
showSecondaryCategory:
|
||||
shouldGroupTemplatesBySecondaryCategory,
|
||||
showBrand:
|
||||
shouldShowTemplateBrand,
|
||||
compact: true,
|
||||
}
|
||||
)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
))
|
||||
: selectedModeTemplates.map((template) => (
|
||||
<SelectItem
|
||||
className="py-2.5 pr-3 text-white focus:bg-white/10 focus:text-white data-[state=checked]:bg-white/10 data-[state=checked]:text-white"
|
||||
key={template.id}
|
||||
value={template.id}
|
||||
>
|
||||
{renderTemplateSelectContent(template, {
|
||||
showBrand: shouldShowTemplateBrand,
|
||||
compact: true,
|
||||
})}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="mx-auto w-full max-w-[220px] overflow-hidden rounded-2xl border border-white/10 bg-white/5 shadow-inner">
|
||||
<div
|
||||
style={{
|
||||
aspectRatio: `${Math.max(1, selectedTemplate.width)} / ${Math.max(1, selectedTemplate.height)}`,
|
||||
}}
|
||||
>
|
||||
<TemplatePreviewImage
|
||||
className="h-full w-full object-contain"
|
||||
loading="eager"
|
||||
quality={78}
|
||||
template={selectedTemplate}
|
||||
width={440}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{sourceImageUrl ? null : (
|
||||
<div className="rounded-xl border border-white/10 border-dashed bg-white/[0.02] px-4 py-3 text-white/50 text-xs leading-relaxed shadow-inner">
|
||||
当前未从生图结果带入图片。请先在下方图片图层中点击“上传替换图片”,再开始套用
|
||||
PSD 模板。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{selectedTemplate ? (
|
||||
<>
|
||||
<div className="mx-auto w-full max-w-[220px] overflow-hidden rounded-2xl border border-white/10 bg-white/5 shadow-inner">
|
||||
<div
|
||||
style={{
|
||||
aspectRatio: `${Math.max(1, selectedTemplate.width)} / ${Math.max(1, selectedTemplate.height)}`,
|
||||
}}
|
||||
>
|
||||
<TemplatePreviewImage
|
||||
className="h-full w-full object-contain"
|
||||
loading="eager"
|
||||
quality={78}
|
||||
template={selectedTemplate}
|
||||
width={440}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{sourceImageUrl ? null : (
|
||||
<div className="rounded-xl border border-white/10 border-dashed bg-white/[0.02] px-4 py-3 text-white/50 text-xs leading-relaxed shadow-inner">
|
||||
当前未从生图结果带入图片。请先在下方图片图层中点击“上传替换图片”,再开始套用
|
||||
PSD 模板。
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center rounded-2xl border border-white/10 border-dashed bg-white/[0.02] p-8 text-center text-sm text-white/50 shadow-inner">
|
||||
{isLoading
|
||||
? "正在加载可用模板..."
|
||||
: hasTemplateOptions
|
||||
? "请从左侧主图模式模板或右侧 SKU 图模式模板中选择一个模板开始编辑。"
|
||||
: selectedCategorySummaryText && normalizedBrandName
|
||||
? `当前品牌“${normalizedBrandName}”下没有命中品类“${selectedCategorySummaryText}”的 PSD 模板,请先去后台配置。`
|
||||
: selectedCategorySummaryText
|
||||
? `当前品类“${selectedCategorySummaryText}”下还没有可用 PSD 模板,请先去后台配置。`
|
||||
: normalizedBrandName
|
||||
? `当前品牌“${normalizedBrandName}”下还没有可用 PSD 模板,请先去后台配置。`
|
||||
: "当前还没有启用的 PSD 模板,请先去后台配置。"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid min-h-[640px] gap-5 xl:grid-cols-2">
|
||||
{renderTemplatePoolSection({
|
||||
mode: "main",
|
||||
templates: mainModeTemplates,
|
||||
})}
|
||||
{renderTemplatePoolSection({
|
||||
mode: "sku",
|
||||
templates: skuModeTemplates,
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</ScrollArea>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-0 flex-col border-white/12 border-b bg-[#0a0a0a] p-6 xl:border-r xl:border-b-0">
|
||||
<div
|
||||
className={
|
||||
selectedTemplate
|
||||
? "flex min-h-0 flex-col border-white/12 border-b bg-[#0a0a0a] p-6 xl:border-r xl:border-b-0"
|
||||
: "hidden"
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="psd-preview-viewport relative flex min-h-0 flex-1 items-center justify-center overflow-auto rounded-[28px] border border-white/[0.08] bg-[#141416] p-4 shadow-[inset_0_2px_20px_rgba(0,0,0,0.4)]"
|
||||
ref={previewViewportRef}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user