From 20bd25e1361ca9d3925d2c6c12ba5743a9704576 Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Mon, 27 Apr 2026 11:15:53 +0800 Subject: [PATCH] fix: polish layout and app branding --- src-tauri/icons/icon.png | Bin 800 -> 15609 bytes src-tauri/src/commands/generation.rs | 2 + src-tauri/tauri.conf.json | 12 +- src/assets/logo.svg | 1 + src/main.tsx | 171 +++++++------- src/styles.css | 329 ++++++++++++++++++--------- src/vite-env.d.ts | 1 + 7 files changed, 311 insertions(+), 205 deletions(-) create mode 100644 src/assets/logo.svg create mode 100644 src/vite-env.d.ts diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png index 673d07b31309fb52674cdc8233f04dede87a7b2c..5c17473310be5941db399d9aa18665ba2646beb0 100644 GIT binary patch literal 15609 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 literal 800 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fgQIQ(qnda-upao=eFt9L6 zF@Q{91Y$czX*k=BQG>7(?pq)aaTa()7Beu2se&-0XOPMVplN3_Ln2Bde0{8v^K1^l#~=$>Fbx5m+O@q>*W`v>l<2HTIw4Z=^Gj80#)c1SLT%@ zR_NvxD?a#8ycOWDy)d+?iUDiLfcJ80syc2lYWR z`i6Q2`f#&>T5Uk0R?hi3`9;A6iOH#UhBjb@$U+EPAgTj0D^hbJTrzW0^NN8kvNJR= zGJ)zsm%^$w61P?)DX3N(eUOKd0ss=aU{PT3+Hu+F!=uWM>)>1KmB84u^mK6yiQs&D z!I782fP=-ctG-;~L9ndqN>00Cwr@tuf9;Ei(c4yki;; \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index af11b83..245d9cd 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom/client'; import { convertFileSrc, invoke } from '@tauri-apps/api/core'; +import appLogo from './assets/logo.svg'; import './styles.css'; type ProviderConfig = { @@ -20,8 +21,8 @@ type ProviderForm = { kind: string; base_url: string; api_key: string; - text_model: string; - image_model: string; + text_model?: string | null; + image_model?: string | null; enabled: boolean; }; @@ -60,8 +61,8 @@ const defaultProviderForm: ProviderForm = { kind: 'openai-compatible', base_url: 'https://api.openai.com/v1', api_key: '', - text_model: 'gpt-5', - image_model: 'gpt-image-2', + text_model: null, + image_model: null, enabled: true, }; @@ -73,10 +74,15 @@ const initialGenerationSteps: GenerationStep[] = [ { label: '更新结果列表', status: 'pending' }, ]; +const imageModelOptions = ['gpt-image-1', 'gpt-image-1.5', 'gpt-image-2']; +const imageSizeOptions = ['1024x1024', '1024x1536', '1536x1024']; +const imageQualityOptions = ['auto', 'high', 'medium', 'low']; + function App() { const [providers, setProviders] = useState([]); const [providerForm, setProviderForm] = useState(defaultProviderForm); const [prompt, setPrompt] = useState('一只赛博朋克风格的橘猫坐在霓虹灯下'); + const [selectedImageModel, setSelectedImageModel] = useState('gpt-image-2'); const [imageSize, setImageSize] = useState('1024x1024'); const [imageQuality, setImageQuality] = useState('auto'); const [status, setStatus] = useState('准备就绪'); @@ -119,8 +125,8 @@ function App() { kind: current.kind, base_url: current.base_url, api_key: current.api_key ?? form.api_key, - text_model: current.text_model ?? defaultProviderForm.text_model, - image_model: current.image_model ?? defaultProviderForm.image_model, + text_model: current.text_model ?? null, + image_model: null, enabled: current.enabled, })); } @@ -130,7 +136,7 @@ function App() { setIsBusy(true); setStatus('正在保存配置...'); try { - await invoke('upsert_provider', { input: providerForm }); + await invoke('upsert_provider', { input: { ...providerForm, image_model: null } }); await refreshProviders(); setStatus('配置已保存'); } catch (error) { @@ -165,8 +171,8 @@ function App() { kind: provider.kind, base_url: provider.base_url, api_key: provider.api_key ?? form.api_key, - text_model: provider.text_model ?? defaultProviderForm.text_model, - image_model: provider.image_model ?? defaultProviderForm.image_model, + text_model: provider.text_model ?? null, + image_model: null, enabled: provider.enabled, })); setStatus('已切换模型配置'); @@ -178,7 +184,7 @@ function App() { setStatus('正在生成图片...'); try { startStep(0); - await invoke('upsert_provider', { input: providerForm }); + await invoke('upsert_provider', { input: { ...providerForm, image_model: null } }); startStep(1); await new Promise((resolve) => window.setTimeout(resolve, 120)); startStep(2); @@ -186,7 +192,7 @@ function App() { input: { provider_id: providerForm.id, prompt, - model: providerForm.image_model, + model: selectedImageModel, size: imageSize, quality: imageQuality, image_paths: materialPaths, @@ -260,7 +266,7 @@ function App() {
-
+ Image Draw AI

Image Draw AI

图片默认保存到应用数据文件夹

@@ -269,7 +275,7 @@ function App() {
当前模型 - {providerForm.image_model} + {selectedImageModel}
@@ -288,25 +294,30 @@ function App() {
-
- - {materialPaths.length > 0 && ( - - )} - {materialPaths.length > 0 ? `${materialPaths.length} 张素材` : '未导入素材'} -
-

支持 PNG / JPG / WEBP,多张素材会使用图像编辑模式

- - {materialPaths.length > 0 && ( -
- {materialPaths.map((path) => ( -
- 素材图片 - -
- ))} +
+
+ 参考图 + {materialPaths.length > 0 ? `${materialPaths.length} 张,图像编辑模式` : '可选,支持多张'}
- )} + {materialPaths.length > 0 && ( + + )} +
+ +
+ + {materialPaths.map((path, index) => ( +
+ 素材图片 + {index + 1} + +
+ ))} +
@@ -314,29 +325,31 @@ function App() { 生成参数 基础
-
- {['1024x1024', '1024x1536', '1536x1024'].map((size) => ( - - ))} -
-
- {['auto', 'high', 'medium', 'low'].map((quality) => ( - - ))} + +
+ +
@@ -344,22 +357,7 @@ function App() { {isBusy ? '正在生成...' : '开始生成'} -
- - -

{status}

+ {status !== '准备就绪' &&

{status}

}
@@ -393,6 +391,21 @@ function App() { ))}
)} + +
+ @@ -452,23 +465,6 @@ function App() { -
-
- 模型 - 默认模型 -
-
- - -
-
-
@@ -489,7 +485,6 @@ function App() {
diff --git a/src/styles.css b/src/styles.css index f4dc02b..237180f 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,6 +1,9 @@ :root { color: #172033; - background: #eef3fb; + background: + radial-gradient(circle at 8% 10%, rgba(255, 221, 77, 0.22), transparent 28%), + radial-gradient(circle at 92% 8%, rgba(96, 239, 154, 0.18), transparent 24%), + linear-gradient(135deg, #f7f9ff 0%, #eef4fb 46%, #f8fbf6 100%); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; } @@ -10,9 +13,10 @@ body { margin: 0; + overflow: hidden; } -button, textarea, input { +button, textarea, input, select { font: inherit; } @@ -54,21 +58,28 @@ button.mini { } .app-shell { - min-height: 100vh; - padding: 22px; + display: grid; + gap: 18px; + grid-template-rows: auto minmax(0, 1fr); + height: 100vh; + min-width: 1120px; + overflow: hidden; + padding: 20px; } .topbar { align-items: center; - background: rgba(255, 255, 255, 0.82); - border: 1px solid rgba(203, 213, 225, 0.8); - border-radius: 24px; - box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08); + backdrop-filter: blur(18px); + background: rgba(255, 255, 255, 0.76); + border: 1px solid rgba(255, 255, 255, 0.86); + border-radius: 28px; + box-shadow: 0 20px 60px rgba(30, 41, 59, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.72); display: flex; justify-content: space-between; - margin: 0 auto 18px; + margin: 0 auto; max-width: 1440px; padding: 16px 18px; + width: 100%; } .brand { @@ -78,15 +89,12 @@ button.mini { } .brand-mark { - align-items: center; - background: linear-gradient(135deg, #2563eb, #7c3aed); + background: linear-gradient(180deg, #ffffff, #f8fafc); border-radius: 18px; - color: #ffffff; - display: grid; - font-size: 24px; - font-weight: 900; + box-shadow: 0 12px 28px rgba(15, 23, 42, 0.12), inset 0 0 0 1px rgba(15, 23, 42, 0.08); height: 52px; - place-items: center; + object-fit: contain; + padding: 6px; width: 52px; } @@ -108,8 +116,8 @@ button.mini { } .current-provider { - background: #f8fafc; - border: 1px solid #e2e8f0; + background: rgba(248, 250, 252, 0.88); + border: 1px solid rgba(226, 232, 240, 0.96); border-radius: 16px; display: grid; gap: 4px; @@ -129,29 +137,56 @@ button.mini { } .workspace { + align-items: stretch; display: grid; gap: 18px; grid-template-columns: minmax(360px, 440px) minmax(0, 1fr); margin: 0 auto; max-width: 1440px; + height: 100%; + min-height: 0; + width: 100%; } .compose-card, .result-card, .settings-drawer { - background: rgba(255, 255, 255, 0.9); - border: 1px solid rgba(203, 213, 225, 0.9); - border-radius: 28px; - box-shadow: 0 24px 70px rgba(15, 23, 42, 0.1); + backdrop-filter: blur(18px); + background: rgba(255, 255, 255, 0.86); + border: 1px solid rgba(255, 255, 255, 0.9); + border-radius: 30px; + box-shadow: 0 28px 80px rgba(30, 41, 59, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.74); } .compose-card { - align-self: start; + display: flex; + flex-direction: column; + gap: 12px; + min-height: 0; + overflow: hidden; + padding: 16px; +} + +.compose-card > .section-heading, +.compose-card > .material-panel, +.compose-card > .params-card, +.compose-card > .generate-button, +.compose-card > .status { + flex: 0 0 auto; +} + +.prompt-field { display: grid; - gap: 18px; - padding: 20px; + grid-template-rows: auto minmax(0, 1fr); + flex: 1 1 auto; + gap: 8px; + min-height: 260px; + overflow: hidden; } .result-card { - min-height: calc(100vh - 132px); + display: flex; + flex-direction: column; + min-height: 0; + overflow: hidden; padding: 20px; } @@ -160,6 +195,7 @@ button.mini { display: flex; justify-content: space-between; gap: 12px; + min-height: 34px; } .heading-actions { @@ -180,25 +216,36 @@ button.mini { font-weight: 800; } -input, textarea { +input, textarea, select { + max-width: 100%; width: 100%; border: 1px solid #dbe4f0; border-radius: 18px; color: #172033; - background: #f8fafc; + background: rgba(248, 250, 252, 0.88); outline: none; padding: 13px 14px; } -input:focus, textarea:focus { +input:focus, textarea:focus, select:focus { background: #ffffff; border-color: #60a5fa; box-shadow: 0 0 0 4px rgba(96, 165, 250, 0.18); } +select { + appearance: none; + background-image: linear-gradient(45deg, transparent 50%, #64748b 50%), linear-gradient(135deg, #64748b 50%, transparent 50%); + background-position: calc(100% - 18px) 52%, calc(100% - 12px) 52%; + background-size: 6px 6px, 6px 6px; + background-repeat: no-repeat; +} + .prompt-field textarea { - min-height: 190px; - resize: vertical; + height: 100%; + min-height: 0; + max-width: 100%; + resize: none; } small { @@ -216,76 +263,154 @@ small { } .material-panel { - background: #f8fafc; - border: 1px dashed #cbd5e1; + background: rgba(248, 250, 252, 0.72); + border: 1px solid rgba(226, 232, 240, 0.92); border-radius: 22px; - padding: 14px; + display: grid; + gap: 12px; + grid-template-rows: auto 120px; + height: 200px; + overflow: hidden; + padding: 12px; } -.material-toolbar { +.material-header { align-items: center; display: flex; - flex-wrap: wrap; - gap: 10px; + justify-content: space-between; + gap: 12px; } -.material-toolbar span { +.material-header div { + display: grid; + gap: 3px; +} + +.material-header strong { + color: #0f172a; +} + +.material-header span { color: #64748b; + font-size: 12px; +} + +.reference-strip { + display: flex; + gap: 10px; + min-height: 120px; + overflow-x: auto; + overflow-y: hidden; + padding: 8px 2px; +} + +.add-reference-card, .reference-card { + border-radius: 18px; + flex: 0 0 104px; + height: 104px; +} + +.add-reference-card { + align-items: center; + background: linear-gradient(180deg, #ffffff, #f8fafc); + border: 1px dashed rgba(37, 99, 235, 0.42); + color: #2563eb; + display: grid; + gap: 2px; + justify-items: center; + padding: 12px; +} + +.add-reference-card:hover:not(:disabled) { + box-shadow: 0 14px 28px rgba(37, 99, 235, 0.14); +} + +.add-reference-card > span { + align-items: center; + background: #eff6ff; + border-radius: 999px; + display: grid; + font-size: 22px; + height: 34px; + place-items: center; + width: 34px; +} + +.add-reference-card strong { font-size: 13px; } -.drop-hint { - color: #94a3b8; - font-size: 12px; - margin: 10px 0 0; +.add-reference-card small { + font-size: 11px; } -.material-grid { - display: grid; - gap: 10px; - grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); - margin-top: 12px; -} - -.material-card { +.reference-card { background: #ffffff; border: 1px solid #e2e8f0; - border-radius: 18px; - display: grid; - gap: 8px; + box-shadow: 0 10px 22px rgba(15, 23, 42, 0.08); overflow: hidden; - padding-bottom: 8px; + position: relative; } -.material-card img { - aspect-ratio: 1; +.reference-card img { background: #e2e8f0; + height: 100%; object-fit: cover; width: 100%; } -.material-card button { - justify-self: center; - padding: 6px 10px; +.reference-card button { + align-items: center; + background: rgba(15, 23, 42, 0.72); + border-radius: 999px; + display: grid; + height: 24px; + padding: 0; + place-items: center; + position: absolute; + right: 7px; + top: 7px; + width: 24px; +} + +.reference-card > span { + align-items: center; + background: rgba(255, 255, 255, 0.88); + border-radius: 999px; + bottom: 7px; + color: #334155; + display: grid; + font-size: 12px; + font-weight: 900; + height: 24px; + left: 7px; + place-items: center; + position: absolute; + width: 24px; } .generate-button { - background: linear-gradient(135deg, #2563eb, #7c3aed); + background: linear-gradient(135deg, #2563eb, #7c3aed 58%, #f97316); border-radius: 18px; + box-shadow: 0 18px 36px rgba(37, 99, 235, 0.28); font-size: 17px; padding: 15px 18px; } .progress-card { align-items: flex-start; - background: #f8fafc; - border: 1px solid #e2e8f0; + background: rgba(248, 250, 252, 0.82); + border: 1px solid rgba(226, 232, 240, 0.92); border-radius: 22px; display: flex; gap: 14px; padding: 15px; } +.result-progress { + margin-top: auto; +} + .spinner { border: 3px solid rgba(148, 163, 184, 0.32); border-top-color: #2563eb; @@ -374,13 +499,21 @@ small { .empty-state { align-items: center; - border: 1px dashed #cbd5e1; + background: linear-gradient(180deg, rgba(248, 250, 252, 0.5), rgba(255, 255, 255, 0.76)); + border: 1px dashed rgba(148, 163, 184, 0.68); border-radius: 26px; color: #64748b; display: grid; + flex: 1; min-height: 420px; place-items: center; text-align: center; + margin-bottom: 16px; +} + +.empty-state > div { + display: grid; + place-items: center; } .empty-state div { @@ -390,17 +523,22 @@ small { margin-bottom: 8px; } +.empty-state p { + margin: 0; +} + .image-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + margin-bottom: 18px; } .image-card { background: #ffffff; - border: 1px solid #e2e8f0; - border-radius: 22px; - box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08); + border: 1px solid rgba(226, 232, 240, 0.9); + border-radius: 24px; + box-shadow: 0 18px 46px rgba(15, 23, 42, 0.1); overflow: hidden; } @@ -487,6 +625,11 @@ small { gap: 10px; } +.drawer-actions button { + border-radius: 12px; + padding: 8px 14px; +} + .saved-providers { border-top: 1px solid #e2e8f0; display: grid; @@ -536,28 +679,11 @@ small { } @media (max-width: 980px) { - .workspace { - grid-template-columns: 1fr; - } - - .result-card { - min-height: 420px; - } + .workspace { grid-template-columns: minmax(360px, 440px) minmax(0, 1fr); } } @media (max-width: 720px) { - .app-shell { - padding: 12px; - } - - .topbar, .topbar-actions { - align-items: stretch; - flex-direction: column; - } - - .grid.two, .provider-item { - grid-template-columns: 1fr; - } + .grid.two, .provider-item { grid-template-columns: 1fr; } } .params-card { @@ -565,37 +691,18 @@ small { border: 1px solid #e2e8f0; border-radius: 22px; display: grid; - gap: 12px; - padding: 14px; + gap: 8px; + padding: 10px; } -.segmented { - background: #eef2f7; - border-radius: 16px; - display: grid; +.compact-field { gap: 6px; - grid-template-columns: repeat(3, 1fr); - padding: 6px; } -.segmented.compact { - grid-template-columns: repeat(4, 1fr); -} - -.segmented button { - background: transparent; - color: #64748b; - padding: 9px 8px; -} - -.segmented button:hover:not(:disabled) { - box-shadow: none; -} - -.segmented button.active { - background: #ffffff; - box-shadow: 0 8px 18px rgba(15, 23, 42, 0.08); - color: #1d4ed8; +.compact-field input, +.compact-field select { + border-radius: 14px; + padding: 10px 12px; } .image-preview-button { diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +///