diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js index d549c4f..ae82120 100644 --- a/web/storyforge-web-v4/assets/app.js +++ b/web/storyforge-web-v4/assets/app.js @@ -3927,7 +3927,7 @@ function renderProjectsScreen() {

项目状态

真实项目列表
-
+
${projects.map((project) => { const stats = getProjectStats(project.id); return ` diff --git a/web/storyforge-web-v4/assets/styles.css b/web/storyforge-web-v4/assets/styles.css index b925b47..960e1e1 100644 --- a/web/storyforge-web-v4/assets/styles.css +++ b/web/storyforge-web-v4/assets/styles.css @@ -784,6 +784,16 @@ select { min-width: 0; } +.entity-card { + display: grid; + gap: 10px; + min-height: 100%; +} + +.entity-card.pad { + padding: 15px; +} + .task-item, .queue-card, .review-card { @@ -1276,6 +1286,13 @@ select { gap: 16px; } +.project-status-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 12px; + align-items: stretch; +} + .table-wrap { overflow: auto; -webkit-overflow-scrolling: touch; @@ -1327,12 +1344,14 @@ tbody tr:hover { .cell-title { font-weight: 600; margin-bottom: 4px; + overflow-wrap: anywhere; } .cell-desc { font-size: 12px; color: var(--muted); line-height: 1.5; + overflow-wrap: anywhere; } .kpi-inline { diff --git a/web/storyforge-web-v4/tests/workbench-pages.test.mjs b/web/storyforge-web-v4/tests/workbench-pages.test.mjs index 0bc169f..d4c0373 100644 --- a/web/storyforge-web-v4/tests/workbench-pages.test.mjs +++ b/web/storyforge-web-v4/tests/workbench-pages.test.mjs @@ -6,6 +6,7 @@ import path from "node:path"; const ROOT = path.resolve(process.cwd(), "web/storyforge-web-v4"); const HTML = fs.readFileSync(path.join(ROOT, "index.html"), "utf8"); const APP = fs.readFileSync(path.join(ROOT, "assets/app.js"), "utf8"); +const CSS = fs.readFileSync(path.join(ROOT, "assets/styles.css"), "utf8"); function extractBetween(source, startToken, endToken) { const start = source.indexOf(startToken); @@ -47,3 +48,10 @@ test("discovery, production, and admin screens use page tabs for heavy content", assert.match(production, /renderDetailTabs\("productionDetailTab"/); assert.match(admin, /renderDetailTabs\("adminWorkbenchTab"/); }); + +test("projects screen uses an adaptive project grid instead of a fixed three-column squeeze", () => { + const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab("); + assert.match(projects, /project-status-grid/); + assert.match(CSS, /\.project-status-grid\s*\{[\s\S]*repeat\(auto-fit,\s*minmax\(260px,\s*1fr\)\)/); + assert.match(CSS, /\.entity-card\.pad\s*\{[\s\S]*padding:\s*15px/); +});