feat(web): polish custom style view layout and UX

Rework custom style view: fixed modal height to match grid view, move
upload and preset-import controls to bottom toolbar alongside cancel/save,
textarea fills remaining space. Add bordered style to cancel button,
improve disabled save button visibility, remove per-card magic-wand
customize button, and add placeholder hint about English prompts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
yuanzonghao
2026-06-06 21:47:10 +08:00
parent 7185f319a2
commit 9a1c292b77
+43 -55
View File
@@ -1025,7 +1025,7 @@ function StyleModal({
<div
onMouseDown={(e) => e.stopPropagation()}
className={
"flex w-[1400px] max-w-[94vw] max-h-[86vh] flex-col overflow-hidden rounded-sm border border-clay-900/15 bg-cream-50 shadow-2xl shadow-clay-900/25 transition-all duration-300 " +
"flex w-[1400px] max-w-[94vw] h-[86vh] flex-col overflow-hidden rounded-sm border border-clay-900/15 bg-cream-50 shadow-2xl shadow-clay-900/25 transition-all duration-300 " +
(shown ? "opacity-100 scale-100" : "opacity-0 scale-95")
}
>
@@ -1073,8 +1073,7 @@ function StyleModal({
</div>
{view === "custom" ? (
<div className="flex flex-col gap-4 overflow-y-auto px-6 py-6 md:px-8">
<div className="flex flex-col gap-2">
<div className="flex flex-1 flex-col gap-4 overflow-y-auto px-6 py-6 md:px-8">
<input
ref={fileInputRef}
type="file"
@@ -1086,24 +1085,29 @@ function StyleModal({
if (fileInputRef.current) fileInputRef.current.value = "";
}}
/>
<textarea
value={draft}
onChange={(e) => setDraft(e.target.value)}
autoFocus
rows={6}
placeholder={"描述你想要的画面风格,例如:\n梦幻水彩风格,柔和的色调,怀旧的氛围\n\n💡 提示:部分绘图模型对英文提示词效果更佳,建议先借助 AI 对话工具生成专业的英文风格描述,再粘贴到这里"}
className="w-full flex-1 resize-y rounded-sm border border-clay-900/15 bg-cream-50 px-3 py-2.5 font-sans text-[13px] leading-relaxed text-clay-900 outline-none transition-colors focus:border-ember-500 placeholder:text-clay-400"
/>
{parseError && (
<span className="font-sans text-[11px] text-rose-500">
<i className="fa-solid fa-circle-exclamation mr-1" />
{parseError}
</span>
)}
<div className="flex items-center gap-2">
{customStyleRefImage ? (
<div className="flex items-center gap-3 rounded-sm border border-clay-900/12 bg-cream-100 px-3 py-2.5">
<div className="flex items-center gap-2">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={customStyleRefImage}
alt="画风参考图"
className="h-14 w-14 shrink-0 rounded-sm border border-clay-900/10 object-cover"
className="h-8 w-8 shrink-0 rounded-sm border border-clay-900/10 object-cover"
/>
<div className="flex min-w-0 flex-1 flex-col">
<span className="font-sans text-[12px] text-clay-900">
<i className="fa-solid fa-check mr-1.5 text-ember-500" />
</span>
<span className="font-sans text-[11px] leading-snug text-clay-500">
AI
</span>
</div>
<div className="flex flex-col items-end gap-1">
<button
type="button"
onClick={() => fileInputRef.current?.click()}
@@ -1120,52 +1124,49 @@ function StyleModal({
</button>
</div>
</div>
) : (
<button
type="button"
onClick={() => fileInputRef.current?.click()}
disabled={parsing}
className={
"flex items-center justify-center gap-2 rounded-sm border border-dashed px-3 py-2.5 font-sans text-[12px] transition-colors " +
"flex items-center gap-1.5 rounded-sm border px-3 py-1.5 font-sans text-[12px] transition-colors " +
(parsing
? "border-clay-900/15 bg-cream-100 text-clay-400 cursor-wait"
: "border-clay-900/25 text-clay-700 hover:border-ember-500 hover:bg-ember-500/5 hover:text-ember-500")
? "border-clay-900/15 text-clay-400 cursor-wait"
: "border-clay-900/15 text-clay-700 hover:border-ember-500 hover:text-ember-500")
}
>
{parsing ? (
<>
<i className="fa-solid fa-circle-notch fa-spin text-[11px]" />
AI
</>
) : (
<>
<i className="fa-regular fa-image text-[13px]" />
· AI
<i className="fa-regular fa-image text-[11px]" />
</>
)}
</button>
)}
{parseError && (
<span className="font-sans text-[11px] text-rose-500">
<i className="fa-solid fa-circle-exclamation mr-1" />
{parseError}
</span>
)}
</div>
<textarea
value={draft}
onChange={(e) => setDraft(e.target.value)}
autoFocus
rows={6}
placeholder={"描述你想要的画面风格,例如:\n梦幻水彩风格,柔和的色调,怀旧的氛围"}
className="w-full resize-y rounded-sm border border-clay-900/15 bg-cream-50 px-3 py-2.5 font-sans text-[13px] leading-relaxed text-clay-900 outline-none transition-colors focus:border-ember-500 placeholder:text-clay-400"
/>
<div className="flex items-center justify-end gap-2">
<select
value=""
onChange={(e) => {
const v = e.target.value;
if (v && STYLE_MAP[v]) setDraft(STYLE_MAP[v]);
}}
className="h-8 w-44 rounded-sm border border-clay-900/15 bg-cream-50 px-2 font-sans text-[12px] text-clay-700 outline-none transition-colors focus:border-ember-500"
>
<option value=""></option>
{Object.keys(STYLE_MAP).map((s) => (
<option key={s} value={s}>{s}</option>
))}
</select>
<div className="flex-1" />
<button
type="button"
onClick={() => setView("grid")}
className="px-3 py-1.5 font-sans text-xs text-clay-500 hover:text-clay-900 transition-colors"
className="rounded-sm border border-clay-900/15 px-4 py-1.5 font-sans text-xs text-clay-700 hover:border-clay-900/30 hover:text-clay-900 transition-colors"
>
</button>
@@ -1174,10 +1175,10 @@ function StyleModal({
disabled={!draft.trim()}
onClick={saveCustom}
className={
"rounded-sm px-4 py-1.5 font-sans text-xs text-cream-50 transition-colors " +
"rounded-sm px-4 py-1.5 font-sans text-xs transition-colors " +
(draft.trim()
? "bg-clay-900 hover:bg-ember-500"
: "bg-clay-300 cursor-not-allowed")
? "bg-clay-900 text-cream-50 hover:bg-ember-500"
: "bg-clay-900/20 text-clay-500 cursor-not-allowed")
}
>
@@ -1189,7 +1190,6 @@ function StyleModal({
{list.map(({ name, i }) => {
const isCustom = name === "自定义风格";
const isAuto = name === "自动";
const hasStyleMap = Boolean(STYLE_MAP[name]);
const thumb = STYLE_THUMB[name];
return (
<div
@@ -1226,18 +1226,6 @@ function StyleModal({
) : (
<div className="absolute inset-0 bg-cream-100" />
)}
{!isAuto && !isCustom && hasStyleMap && (
<span
onClick={(e) => {
e.stopPropagation();
openCustomView(STYLE_MAP[name] ?? "");
}}
title="基于此风格自定义"
className="absolute right-1.5 top-1.5 z-20 flex h-6 w-6 items-center justify-center rounded-sm text-[11px] text-cream-50/70 opacity-0 transition-all group-hover:opacity-100 hover:bg-ember-500/20 hover:text-cream-50"
>
<i className="fa-solid fa-wand-magic-sparkles" />
</span>
)}
</div>
<span className={"block px-2 py-2 text-center font-serif text-sm " + (i === value ? "text-ember-500" : "text-clay-700")}>
{name}