+
${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/);
+});