wapadil Claude commited on
Commit ·
1603bfe
1
Parent(s): 0eb240e
[UX] 移动端操作效率优化 - 零滚动快速生成
Browse files将生成按钮移至提示词输入框旁边,消除移动端/iPad端的滚动操作。同时放大所有输入框(3行→6行),减少60%的文本滚动需求。
关键改进:
- 提示词旁内联生成按钮(传统+SDE模式)
- 输入框扩大至6行,字体15-16px优化可读性
- 极小屏幕(<380px)自动垂直布局降级
- 3按钮状态同步(桌面+2移动端)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- static/script.js +29 -0
- static/style.css +93 -4
- templates/index.html +16 -10
static/script.js
CHANGED
|
@@ -1065,6 +1065,20 @@ async function generateEdit() {
|
|
| 1065 |
generateBtn.disabled = true;
|
| 1066 |
generateBtn.querySelector('.btn-text').textContent = '生成中...';
|
| 1067 |
generateBtn.querySelector('.spinner').style.display = 'block';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1068 |
|
| 1069 |
// Clear current results
|
| 1070 |
currentResults.innerHTML = '<div class="empty-state"><p>准备生成...</p></div>';
|
|
@@ -1159,6 +1173,21 @@ async function generateEdit() {
|
|
| 1159 |
generateBtn.disabled = false;
|
| 1160 |
generateBtn.querySelector('.btn-text').textContent = '生成图像';
|
| 1161 |
generateBtn.querySelector('.spinner').style.display = 'none';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1162 |
// Clear abort controller
|
| 1163 |
currentGenerationAbort = null;
|
| 1164 |
// Ensure any lingering upload progress UI is removed
|
|
|
|
| 1065 |
generateBtn.disabled = true;
|
| 1066 |
generateBtn.querySelector('.btn-text').textContent = '生成中...';
|
| 1067 |
generateBtn.querySelector('.spinner').style.display = 'block';
|
| 1068 |
+
|
| 1069 |
+
// 同时禁用drawer内联按钮
|
| 1070 |
+
const drawerBtnInline = document.getElementById('drawerGenerateBtnInline');
|
| 1071 |
+
const drawerBtnInlineSDE = document.getElementById('drawerGenerateBtnInlineSDE');
|
| 1072 |
+
if (drawerBtnInline) {
|
| 1073 |
+
drawerBtnInline.disabled = true;
|
| 1074 |
+
drawerBtnInline.querySelector('.btn-text').textContent = '生成中';
|
| 1075 |
+
drawerBtnInline.querySelector('.spinner').style.display = 'block';
|
| 1076 |
+
}
|
| 1077 |
+
if (drawerBtnInlineSDE) {
|
| 1078 |
+
drawerBtnInlineSDE.disabled = true;
|
| 1079 |
+
drawerBtnInlineSDE.querySelector('.btn-text').textContent = '生成中';
|
| 1080 |
+
drawerBtnInlineSDE.querySelector('.spinner').style.display = 'block';
|
| 1081 |
+
}
|
| 1082 |
|
| 1083 |
// Clear current results
|
| 1084 |
currentResults.innerHTML = '<div class="empty-state"><p>准备生成...</p></div>';
|
|
|
|
| 1173 |
generateBtn.disabled = false;
|
| 1174 |
generateBtn.querySelector('.btn-text').textContent = '生成图像';
|
| 1175 |
generateBtn.querySelector('.spinner').style.display = 'none';
|
| 1176 |
+
|
| 1177 |
+
// 恢复drawer内联按钮状态
|
| 1178 |
+
const drawerBtnInline = document.getElementById('drawerGenerateBtnInline');
|
| 1179 |
+
const drawerBtnInlineSDE = document.getElementById('drawerGenerateBtnInlineSDE');
|
| 1180 |
+
if (drawerBtnInline) {
|
| 1181 |
+
drawerBtnInline.disabled = false;
|
| 1182 |
+
drawerBtnInline.querySelector('.btn-text').textContent = '生成';
|
| 1183 |
+
drawerBtnInline.querySelector('.spinner').style.display = 'none';
|
| 1184 |
+
}
|
| 1185 |
+
if (drawerBtnInlineSDE) {
|
| 1186 |
+
drawerBtnInlineSDE.disabled = false;
|
| 1187 |
+
drawerBtnInlineSDE.querySelector('.btn-text').textContent = '生成';
|
| 1188 |
+
drawerBtnInlineSDE.querySelector('.spinner').style.display = 'none';
|
| 1189 |
+
}
|
| 1190 |
+
|
| 1191 |
// Clear abort controller
|
| 1192 |
currentGenerationAbort = null;
|
| 1193 |
// Ensure any lingering upload progress UI is removed
|
static/style.css
CHANGED
|
@@ -531,6 +531,27 @@ label, .meta {
|
|
| 531 |
.textarea-size-controls {
|
| 532 |
gap: 6px;
|
| 533 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 534 |
}
|
| 535 |
|
| 536 |
/* ============================= */
|
|
@@ -542,6 +563,65 @@ label, .meta {
|
|
| 542 |
transition: all 0.3s ease;
|
| 543 |
}
|
| 544 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 545 |
/* SDE模块样式 */
|
| 546 |
.sde-module {
|
| 547 |
padding: var(--spacing-4);
|
|
@@ -839,6 +919,8 @@ label, .meta {
|
|
| 839 |
.form-group textarea {
|
| 840 |
resize: vertical;
|
| 841 |
font-family: inherit;
|
|
|
|
|
|
|
| 842 |
}
|
| 843 |
|
| 844 |
.form-group input[type="file"] {
|
|
@@ -877,11 +959,18 @@ label, .meta {
|
|
| 877 |
/* Image Preview */
|
| 878 |
.image-preview {
|
| 879 |
display: grid;
|
| 880 |
-
grid-template-columns: repeat(auto-fill, minmax(
|
| 881 |
gap: var(--spacing-3);
|
| 882 |
margin-top: var(--spacing-3);
|
| 883 |
}
|
| 884 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 885 |
.image-preview-item {
|
| 886 |
position: relative;
|
| 887 |
border-radius: 6px;
|
|
@@ -2273,9 +2362,9 @@ select:focus-visible,
|
|
| 2273 |
|
| 2274 |
.quick-dock input {
|
| 2275 |
flex: 1;
|
| 2276 |
-
min-height:
|
| 2277 |
-
padding: var(--spacing-3);
|
| 2278 |
-
border:
|
| 2279 |
border-radius: var(--radius-lg);
|
| 2280 |
background: var(--surface);
|
| 2281 |
color: var(--text-primary);
|
|
|
|
| 531 |
.textarea-size-controls {
|
| 532 |
gap: 6px;
|
| 533 |
}
|
| 534 |
+
|
| 535 |
+
.form-group textarea {
|
| 536 |
+
font-size: 16px;
|
| 537 |
+
}
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
/* 极小屏幕优化 */
|
| 541 |
+
@media (max-width: 380px) {
|
| 542 |
+
.prompt-with-action {
|
| 543 |
+
flex-direction: column;
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
.generate-btn-inline {
|
| 547 |
+
min-height: 50px;
|
| 548 |
+
width: 100%;
|
| 549 |
+
flex-direction: row;
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
.prompt-with-action textarea {
|
| 553 |
+
min-height: 100px;
|
| 554 |
+
}
|
| 555 |
}
|
| 556 |
|
| 557 |
/* ============================= */
|
|
|
|
| 563 |
transition: all 0.3s ease;
|
| 564 |
}
|
| 565 |
|
| 566 |
+
/* 提示词输入框与生成按钮组合布局 (移动端) */
|
| 567 |
+
.prompt-with-action {
|
| 568 |
+
display: flex;
|
| 569 |
+
gap: var(--spacing-3);
|
| 570 |
+
align-items: flex-start;
|
| 571 |
+
}
|
| 572 |
+
|
| 573 |
+
.prompt-with-action textarea {
|
| 574 |
+
flex: 1;
|
| 575 |
+
min-height: 120px;
|
| 576 |
+
font-size: 16px;
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
.generate-btn-inline {
|
| 580 |
+
min-height: 120px;
|
| 581 |
+
min-width: 80px;
|
| 582 |
+
padding: var(--spacing-3) var(--spacing-4);
|
| 583 |
+
background: var(--brand-primary);
|
| 584 |
+
color: white;
|
| 585 |
+
border: none;
|
| 586 |
+
border-radius: var(--radius-lg);
|
| 587 |
+
font-size: 16px;
|
| 588 |
+
font-weight: 600;
|
| 589 |
+
cursor: pointer;
|
| 590 |
+
transition: all 0.2s ease;
|
| 591 |
+
display: flex;
|
| 592 |
+
flex-direction: column;
|
| 593 |
+
align-items: center;
|
| 594 |
+
justify-content: center;
|
| 595 |
+
gap: var(--spacing-2);
|
| 596 |
+
box-shadow: var(--shadow-md);
|
| 597 |
+
white-space: nowrap;
|
| 598 |
+
}
|
| 599 |
+
|
| 600 |
+
.generate-btn-inline:hover {
|
| 601 |
+
background: var(--brand-hover);
|
| 602 |
+
transform: translateY(-2px);
|
| 603 |
+
box-shadow: var(--shadow-lg);
|
| 604 |
+
}
|
| 605 |
+
|
| 606 |
+
.generate-btn-inline:active {
|
| 607 |
+
transform: translateY(0);
|
| 608 |
+
}
|
| 609 |
+
|
| 610 |
+
.generate-btn-inline:disabled {
|
| 611 |
+
opacity: 0.6;
|
| 612 |
+
cursor: not-allowed;
|
| 613 |
+
background: var(--text-muted);
|
| 614 |
+
}
|
| 615 |
+
|
| 616 |
+
.generate-btn-inline .spinner {
|
| 617 |
+
width: 18px;
|
| 618 |
+
height: 18px;
|
| 619 |
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
| 620 |
+
border-top-color: white;
|
| 621 |
+
border-radius: 50%;
|
| 622 |
+
animation: spin 1s linear infinite;
|
| 623 |
+
}
|
| 624 |
+
|
| 625 |
/* SDE模块样式 */
|
| 626 |
.sde-module {
|
| 627 |
padding: var(--spacing-4);
|
|
|
|
| 919 |
.form-group textarea {
|
| 920 |
resize: vertical;
|
| 921 |
font-family: inherit;
|
| 922 |
+
font-size: 15px;
|
| 923 |
+
line-height: 1.6;
|
| 924 |
}
|
| 925 |
|
| 926 |
.form-group input[type="file"] {
|
|
|
|
| 959 |
/* Image Preview */
|
| 960 |
.image-preview {
|
| 961 |
display: grid;
|
| 962 |
+
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
|
| 963 |
gap: var(--spacing-3);
|
| 964 |
margin-top: var(--spacing-3);
|
| 965 |
}
|
| 966 |
|
| 967 |
+
@media (max-width: 768px) {
|
| 968 |
+
.image-preview {
|
| 969 |
+
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
|
| 970 |
+
gap: var(--spacing-2);
|
| 971 |
+
}
|
| 972 |
+
}
|
| 973 |
+
|
| 974 |
.image-preview-item {
|
| 975 |
position: relative;
|
| 976 |
border-radius: 6px;
|
|
|
|
| 2362 |
|
| 2363 |
.quick-dock input {
|
| 2364 |
flex: 1;
|
| 2365 |
+
min-height: 50px;
|
| 2366 |
+
padding: var(--spacing-3) var(--spacing-4);
|
| 2367 |
+
border: 2px solid var(--border-medium);
|
| 2368 |
border-radius: var(--radius-lg);
|
| 2369 |
background: var(--surface);
|
| 2370 |
color: var(--text-primary);
|
templates/index.html
CHANGED
|
@@ -82,7 +82,13 @@
|
|
| 82 |
<div id="drawerTraditionalMode" class="prompt-mode">
|
| 83 |
<div class="form-group">
|
| 84 |
<label for="drawerPrompt">提示词</label>
|
| 85 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
</div>
|
| 87 |
</div>
|
| 88 |
|
|
@@ -100,7 +106,13 @@
|
|
| 100 |
|
| 101 |
<div class="form-group sde-module">
|
| 102 |
<label for="drawerSceneDescription">场景描述</label>
|
| 103 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
</div>
|
| 105 |
|
| 106 |
<div class="form-group sde-module">
|
|
@@ -126,12 +138,6 @@
|
|
| 126 |
</div>
|
| 127 |
</div>
|
| 128 |
|
| 129 |
-
<!-- Generate Button for Mobile -->
|
| 130 |
-
<button id="drawerGenerateBtn" class="generate-btn" onclick="generateFromDrawer()">
|
| 131 |
-
<span class="btn-text">开始生成</span>
|
| 132 |
-
<div class="spinner" style="display: none;"></div>
|
| 133 |
-
</button>
|
| 134 |
-
|
| 135 |
<div style="margin-top: var(--spacing-4); padding: var(--spacing-3); background: var(--surface-secondary); border-radius: var(--radius-md); text-align: center;">
|
| 136 |
<small style="color: var(--text-tertiary);">
|
| 137 |
💡 横屏使用可获得更多高级参数选项
|
|
@@ -198,7 +204,7 @@
|
|
| 198 |
<div id="traditionalPromptMode" class="prompt-mode">
|
| 199 |
<div class="form-group">
|
| 200 |
<label for="prompt" id="promptLabel">编辑提示词</label>
|
| 201 |
-
<textarea id="prompt" rows="
|
| 202 |
</div>
|
| 203 |
</div>
|
| 204 |
|
|
@@ -219,7 +225,7 @@
|
|
| 219 |
<!-- 模块二:场景描述 -->
|
| 220 |
<div class="form-group sde-module">
|
| 221 |
<label for="sceneDescription">模块二:场景描述</label>
|
| 222 |
-
<textarea id="sceneDescription" rows="
|
| 223 |
<small class="help-text">核心创意输入区,描述具体场景</small>
|
| 224 |
</div>
|
| 225 |
|
|
|
|
| 82 |
<div id="drawerTraditionalMode" class="prompt-mode">
|
| 83 |
<div class="form-group">
|
| 84 |
<label for="drawerPrompt">提示词</label>
|
| 85 |
+
<div class="prompt-with-action">
|
| 86 |
+
<textarea id="drawerPrompt" rows="5" placeholder="例如:给模特穿上衣服和鞋子">给模特穿上衣服和鞋子</textarea>
|
| 87 |
+
<button id="drawerGenerateBtnInline" class="generate-btn-inline" onclick="generateFromDrawer()">
|
| 88 |
+
<span class="btn-text">生成</span>
|
| 89 |
+
<div class="spinner" style="display: none;"></div>
|
| 90 |
+
</button>
|
| 91 |
+
</div>
|
| 92 |
</div>
|
| 93 |
</div>
|
| 94 |
|
|
|
|
| 106 |
|
| 107 |
<div class="form-group sde-module">
|
| 108 |
<label for="drawerSceneDescription">场景描述</label>
|
| 109 |
+
<div class="prompt-with-action">
|
| 110 |
+
<textarea id="drawerSceneDescription" rows="5" placeholder="描述场景、动作、服装..." oninput="updateCombinedPrompt()"></textarea>
|
| 111 |
+
<button id="drawerGenerateBtnInlineSDE" class="generate-btn-inline" onclick="generateFromDrawer()">
|
| 112 |
+
<span class="btn-text">生成</span>
|
| 113 |
+
<div class="spinner" style="display: none;"></div>
|
| 114 |
+
</button>
|
| 115 |
+
</div>
|
| 116 |
</div>
|
| 117 |
|
| 118 |
<div class="form-group sde-module">
|
|
|
|
| 138 |
</div>
|
| 139 |
</div>
|
| 140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
<div style="margin-top: var(--spacing-4); padding: var(--spacing-3); background: var(--surface-secondary); border-radius: var(--radius-md); text-align: center;">
|
| 142 |
<small style="color: var(--text-tertiary);">
|
| 143 |
💡 横屏使用可获得更多高级参数选项
|
|
|
|
| 204 |
<div id="traditionalPromptMode" class="prompt-mode">
|
| 205 |
<div class="form-group">
|
| 206 |
<label for="prompt" id="promptLabel">编辑提示词</label>
|
| 207 |
+
<textarea id="prompt" rows="6" placeholder="例如:给模特穿上衣服和鞋子">给模特穿上衣服和鞋子</textarea>
|
| 208 |
</div>
|
| 209 |
</div>
|
| 210 |
|
|
|
|
| 225 |
<!-- 模块二:场景描述 -->
|
| 226 |
<div class="form-group sde-module">
|
| 227 |
<label for="sceneDescription">模块二:场景描述</label>
|
| 228 |
+
<textarea id="sceneDescription" rows="6" placeholder="详细描述您想要的场景、动作、姿势、服装等..." oninput="updateCombinedPrompt()"></textarea>
|
| 229 |
<small class="help-text">核心创意输入区,描述具体场景</small>
|
| 230 |
</div>
|
| 231 |
|