diff --git a/src/workflow-web-assets.ts b/src/workflow-web-assets.ts index 669b7e2..9a5f6e0 100644 --- a/src/workflow-web-assets.ts +++ b/src/workflow-web-assets.ts @@ -123,8 +123,10 @@ export function getAssetsHtml(): string { .settings-panel { width: min(920px, 100%); - max-height: min(90vh, 900px); - overflow: auto; + max-height: min(calc(100dvh - 40px), 900px); + display: flex; + flex-direction: column; + overflow: hidden; background: var(--bg-sidebar); border: 1px solid var(--border); border-radius: 12px; @@ -138,6 +140,7 @@ export function getAssetsHtml(): string { gap: 16px; padding: 20px 24px; border-bottom: 1px solid var(--border); + flex-shrink: 0; } .settings-header h2 { @@ -154,12 +157,15 @@ export function getAssetsHtml(): string { .settings-body { padding: 20px 24px 8px; - display: flex; - flex-direction: column; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; + min-height: 0; + overflow-y: auto; } .executor-settings-card { + min-width: 0; background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; @@ -218,6 +224,13 @@ export function getAssetsHtml(): string { display: grid; grid-template-columns: 1fr auto; gap: 10px; + min-width: 0; + } + + .settings-field-row .select-input, + .settings-field > .search-input { + width: 100%; + min-width: 0; } .settings-help { @@ -239,6 +252,7 @@ export function getAssetsHtml(): string { gap: 12px; padding: 16px 24px 24px; border-top: 1px solid var(--border); + flex-shrink: 0; } .settings-actions { @@ -709,6 +723,9 @@ export function getAssetsHtml(): string { .settings-field-row { grid-template-columns: 1fr; } + .settings-body { + grid-template-columns: 1fr; + } .settings-footer { flex-direction: column; align-items: stretch; diff --git a/src/workflow-web.test.ts b/src/workflow-web.test.ts index 42aef7b..73931b9 100644 --- a/src/workflow-web.test.ts +++ b/src/workflow-web.test.ts @@ -205,6 +205,14 @@ printf '%s\\n' '{"providers":[{"name":"test-provider","models":["test-model"]}]} expect(res.body).toContain("手动输入模型"); }); + it("uses a responsive grid with body-only scrolling for model settings", async () => { + const res = await makeRequest(`${baseUrl}/`); + expect(res.status).toBe(200); + expect(res.body).toMatch(/\.settings-panel\s*\{[^}]*display: flex;[^}]*flex-direction: column;[^}]*overflow: hidden;/); + expect(res.body).toMatch(/\.settings-body\s*\{[^}]*display: grid;[^}]*grid-template-columns: repeat\(auto-fit, minmax\(260px, 1fr\)\);[^}]*overflow-y: auto;/); + expect(res.body).toMatch(/@media \(max-width: 768px\)[\s\S]*?\.settings-body\s*\{\s*grid-template-columns: 1fr;/); + }); + it("serves model discovery config endpoint", async () => { const res = await makeRequest(`${baseUrl}/api/config/models`); expect(res.status).toBe(200);