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 ? '正在生成...' : '开始生成'}
-
-
-
-
{isBusy ? '生成中' : '生成流程'}
-
- {generationSteps.map((step) => (
- -
-
- {step.label}
-
- ))}
-
-
-
-
-
{status}
+ {status !== '准备就绪' &&
{status}
}
@@ -393,6 +391,21 @@ function App() {
))}
)}
+
+
+
+
+
{isBusy ? '生成中' : '生成流程'}
+
+ {generationSteps.map((step) => (
+ -
+
+ {step.label}
+
+ ))}
+
+
+
@@ -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 @@
+///