diff --git a/public/css/style.css b/public/css/style.css index d9630ab..fff8934 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -4465,7 +4465,16 @@ textarea::selection { } .paper-table .cell-anon .anon-sub a { color: var(--ink-muted); border-bottom: 1px dotted var(--border-color); } .paper-table .cell-anon .anon-sub a:hover { color: var(--color); } -.paper-table .cell-conf { font-family: var(--font-mono); font-size: 13px; color: var(--color); } +.paper-table .cell-conf { + font-family: var(--font-mono); + font-size: 13px; + color: var(--color); + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.paper-table .cell-conf span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .paper-table .cell-status { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 8px; font-size: 14px; color: var(--color); } .paper-table .cell-status .status-line { display: inline-flex; align-items: center; gap: 8px; } .paper-table .cell-status .status-sub { flex-basis: 100%; font-size: 11px; line-height: 1.2; color: var(--ink-muted); } @@ -5295,6 +5304,12 @@ textarea::selection { gap: 6px; text-align: left; } + .paper-table .cell-conf { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } .paper-table .cell-views.num { text-align: left; } .paper-table .cell-views::before { content: '\f06e'; diff --git a/public/partials/dashboard.htm b/public/partials/dashboard.htm index 8b3eb3f..00250dc 100644 --- a/public/partials/dashboard.htm +++ b/public/partials/dashboard.htm @@ -195,7 +195,7 @@
- +
diff --git a/test/dashboard-conference-overflow.test.js b/test/dashboard-conference-overflow.test.js new file mode 100644 index 0000000..e3530cb --- /dev/null +++ b/test/dashboard-conference-overflow.test.js @@ -0,0 +1,49 @@ +const { expect } = require("chai"); +const fs = require("fs"); +const path = require("path"); + +/** + * Regression test for the dashboard "Conference" column overflowing into + * the "Status" column. + * + * Root cause: `.cell-conf` is a CSS grid item with the default + * `min-width: auto`, so an unbreakable long string (e.g. a conference URL) + * forces the grid track wider than its `minmax(140px, 1fr)` track size, + * visually bleeding into the next cell instead of being clipped. + */ + +const cssPath = path.join(__dirname, "..", "public", "css", "style.css"); +const htmlPath = path.join(__dirname, "..", "public", "partials", "dashboard.htm"); + +function getRuleBody(css, selector) { + const index = css.indexOf(selector); + expect(index, `selector "${selector}" not found in style.css`).to.be.greaterThan(-1); + const start = css.indexOf("{", index); + const end = css.indexOf("}", start); + return css.slice(start + 1, end); +} + +describe("dashboard .cell-conf overflow fix", function () { + const css = fs.readFileSync(cssPath, "utf8"); + + it("clips overflowing conference text instead of letting it bleed into other cells", function () { + const rule = getRuleBody(css, ".paper-table .cell-conf {"); + expect(rule).to.match(/min-width:\s*0/); + expect(rule).to.match(/overflow:\s*hidden/); + expect(rule).to.match(/text-overflow:\s*ellipsis/); + expect(rule).to.match(/white-space:\s*nowrap/); + }); + + it("keeps the fix in the stacked mobile layout too", function () { + const mobileSectionStart = css.indexOf("@media (max-width: 900px)"); + const mobileRule = getRuleBody(css.slice(mobileSectionStart), ".paper-table .cell-conf {"); + expect(mobileRule).to.match(/overflow:\s*hidden/); + expect(mobileRule).to.match(/text-overflow:\s*ellipsis/); + expect(mobileRule).to.match(/white-space:\s*nowrap/); + }); + + it("exposes the full conference value via a title attribute for truncated text", function () { + const html = fs.readFileSync(htmlPath, "utf8"); + expect(html).to.match(/cell-conf[\s\S]*?title="\{\{item\.conference\}\}"/); + }); +});