From 9e74d13a6233cac5ccb495d61a902079db21b7d4 Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Wed, 9 Sep 2026 03:04:26 +0000 Subject: [PATCH 01/10] fix: show full model card text --- src/components/models/ModelCard.astro | 4 +- src/components/models/ModelCard.astro.test.ts | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/components/models/ModelCard.astro.test.ts diff --git a/src/components/models/ModelCard.astro b/src/components/models/ModelCard.astro index 028eeafea50..53109768246 100644 --- a/src/components/models/ModelCard.astro +++ b/src/components/models/ModelCard.astro @@ -105,7 +105,7 @@ const authorLogo = authorData[model.author]?.logo; }

{model.shortName}

@@ -132,7 +132,7 @@ const authorLogo = authorData[model.author]?.logo;

{model.description}

diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts new file mode 100644 index 00000000000..727a6e37cd4 --- /dev/null +++ b/src/components/models/ModelCard.astro.test.ts @@ -0,0 +1,45 @@ +import { experimental_AstroContainer as AstroContainer } from "astro/container"; +import { parse } from "node-html-parser"; +import { describe, expect, test } from "vitest"; + +import type { ModelCardData } from "~/util/models"; +import ModelCard from "./ModelCard.astro"; + +const model: ModelCardData = { + id: "model-card-fixture", + name: "fixture-author/verylongmodelnamethatmustwrapwithouttruncation", + slug: "fixture-author/verylongmodelnamethatmustwrapwithouttruncation", + displayName: "Very Long Model", + shortName: "verylongmodelnamethatmustwrapwithouttruncation", + author: "fixture-author", + authorName: "Fixture Author", + hosting: "proxied", + dataSource: "catalog", + source: 2, + task: "Text Generation", + description: + "A deliberately long model description that exceeds two lines and must remain fully visible in the model card instead of being clipped by a presentation-only line clamp.", + capabilities: [], + beta: true, + properties: {}, + propertiesList: [], +}; + +describe("ModelCard", () => { + test("does not emit truncation classes for titles and descriptions", async () => { + const container = await AstroContainer.create(); + const html = await container.renderToString(ModelCard, { + props: { model, index: 0, cols: 3 }, + }); + const root = parse(html); + const title = root.querySelector("h3"); + const description = root.querySelector("p"); + + expect(title?.textContent).toBe(model.shortName); + expect(title?.getAttribute("class")).not.toContain("line-clamp-2"); + expect(title?.getAttribute("class")).toContain("min-w-0"); + expect(title?.getAttribute("class")).toContain("break-words"); + expect(description?.textContent).toBe(model.description); + expect(description?.getAttribute("class")).not.toContain("line-clamp-2"); + }); +}); From 17dcb261305eb11c0bb811e513d1413f0524da38 Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 16:42:18 +0000 Subject: [PATCH 02/10] test: broaden model card truncation coverage --- src/components/models/ModelCard.astro.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts index 727a6e37cd4..051969ddb73 100644 --- a/src/components/models/ModelCard.astro.test.ts +++ b/src/components/models/ModelCard.astro.test.ts @@ -25,6 +25,9 @@ const model: ModelCardData = { propertiesList: [], }; +const truncationClass = + /\b(?:line-clamp-\S+|truncate|overflow-hidden|max-h-\S+)\b/; + describe("ModelCard", () => { test("does not emit truncation classes for titles and descriptions", async () => { const container = await AstroContainer.create(); @@ -36,10 +39,10 @@ describe("ModelCard", () => { const description = root.querySelector("p"); expect(title?.textContent).toBe(model.shortName); - expect(title?.getAttribute("class")).not.toContain("line-clamp-2"); + expect(title?.getAttribute("class")).not.toMatch(truncationClass); expect(title?.getAttribute("class")).toContain("min-w-0"); expect(title?.getAttribute("class")).toContain("break-words"); expect(description?.textContent).toBe(model.description); - expect(description?.getAttribute("class")).not.toContain("line-clamp-2"); + expect(description?.getAttribute("class")).not.toMatch(truncationClass); }); }); From 63d4c8ebb5c747db665552c66b15e0d53b23578b Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 16:49:44 +0000 Subject: [PATCH 03/10] test: match truncation utility tokens exactly --- src/components/models/ModelCard.astro.test.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts index 051969ddb73..698ca1a1383 100644 --- a/src/components/models/ModelCard.astro.test.ts +++ b/src/components/models/ModelCard.astro.test.ts @@ -25,8 +25,14 @@ const model: ModelCardData = { propertiesList: [], }; -const truncationClass = - /\b(?:line-clamp-\S+|truncate|overflow-hidden|max-h-\S+)\b/; +const truncationClasses = (className: string | undefined): string[] => + (className ?? "") + .split(/\s+/) + .filter((token) => + /^(?:line-clamp-|truncate$|overflow-(?:hidden|clip)$|max-h-|text-ellipsis$|whitespace-nowrap$)/.test( + token, + ), + ); describe("ModelCard", () => { test("does not emit truncation classes for titles and descriptions", async () => { @@ -39,10 +45,10 @@ describe("ModelCard", () => { const description = root.querySelector("p"); expect(title?.textContent).toBe(model.shortName); - expect(title?.getAttribute("class")).not.toMatch(truncationClass); + expect(truncationClasses(title?.getAttribute("class"))).toEqual([]); expect(title?.getAttribute("class")).toContain("min-w-0"); expect(title?.getAttribute("class")).toContain("break-words"); expect(description?.textContent).toBe(model.description); - expect(description?.getAttribute("class")).not.toMatch(truncationClass); + expect(truncationClasses(description?.getAttribute("class"))).toEqual([]); }); }); From e118a2f10747b958f99bc85a875c15f7103ed876 Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 10:31:38 -0700 Subject: [PATCH 04/10] fix: constrain model card text --- src/components/models/ModelCard.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/models/ModelCard.astro b/src/components/models/ModelCard.astro index 53109768246..702965a122b 100644 --- a/src/components/models/ModelCard.astro +++ b/src/components/models/ModelCard.astro @@ -103,7 +103,7 @@ const authorLogo = authorData[model.author]?.logo; ) } -
+

@@ -132,7 +132,7 @@ const authorLogo = authorData[model.author]?.logo;

{model.description}

From 5430331664a8876d978299c713c6895d82db7562 Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 17:38:55 +0000 Subject: [PATCH 05/10] Revert "fix: constrain model card text" This reverts commit 34beecdd40854d0404a3a63f3089b88d3e6e2546. --- src/components/models/ModelCard.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/models/ModelCard.astro b/src/components/models/ModelCard.astro index 702965a122b..53109768246 100644 --- a/src/components/models/ModelCard.astro +++ b/src/components/models/ModelCard.astro @@ -103,7 +103,7 @@ const authorLogo = authorData[model.author]?.logo; ) } -
+

@@ -132,7 +132,7 @@ const authorLogo = authorData[model.author]?.logo;

{model.description}

From a51053d7965d92c3d55d7124cab88252b93b2ea0 Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 17:54:11 +0000 Subject: [PATCH 06/10] test: cover title wrapper truncation --- src/components/models/ModelCard.astro.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts index 698ca1a1383..57a42abebd7 100644 --- a/src/components/models/ModelCard.astro.test.ts +++ b/src/components/models/ModelCard.astro.test.ts @@ -42,9 +42,11 @@ describe("ModelCard", () => { }); const root = parse(html); const title = root.querySelector("h3"); + const titleRow = title?.parentNode; const description = root.querySelector("p"); expect(title?.textContent).toBe(model.shortName); + expect(truncationClasses(titleRow?.getAttribute("class"))).toEqual([]); expect(truncationClasses(title?.getAttribute("class"))).toEqual([]); expect(title?.getAttribute("class")).toContain("min-w-0"); expect(title?.getAttribute("class")).toContain("break-words"); From c30de402e5f7188529514f75f8148c61b157e28c Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 18:06:26 +0000 Subject: [PATCH 07/10] test: scope model card description selector --- src/components/models/ModelCard.astro.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts index 57a42abebd7..d0a446323e5 100644 --- a/src/components/models/ModelCard.astro.test.ts +++ b/src/components/models/ModelCard.astro.test.ts @@ -43,7 +43,7 @@ describe("ModelCard", () => { const root = parse(html); const title = root.querySelector("h3"); const titleRow = title?.parentNode; - const description = root.querySelector("p"); + const description = root.querySelector("a > p"); expect(title?.textContent).toBe(model.shortName); expect(truncationClasses(titleRow?.getAttribute("class"))).toEqual([]); From 0bb901a2e6bf73c8d9118c980a9b1f1bbc03c58e Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 18:25:10 +0000 Subject: [PATCH 08/10] test: cover axis-specific overflow utilities --- src/components/models/ModelCard.astro.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts index d0a446323e5..759d9fd4fb4 100644 --- a/src/components/models/ModelCard.astro.test.ts +++ b/src/components/models/ModelCard.astro.test.ts @@ -29,7 +29,7 @@ const truncationClasses = (className: string | undefined): string[] => (className ?? "") .split(/\s+/) .filter((token) => - /^(?:line-clamp-|truncate$|overflow-(?:hidden|clip)$|max-h-|text-ellipsis$|whitespace-nowrap$)/.test( + /^(?:line-clamp-|truncate$|overflow-(?:[xy]-)?(?:hidden|clip|ellipsis)$|max-h-|text-ellipsis$|whitespace-nowrap$)/.test( token, ), ); From 31cb2b5ca1cd29cb613790ff34b983875ef2d234 Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 18:33:11 +0000 Subject: [PATCH 09/10] test: narrow truncation utility matching --- src/components/models/ModelCard.astro.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts index 759d9fd4fb4..3bf560b5162 100644 --- a/src/components/models/ModelCard.astro.test.ts +++ b/src/components/models/ModelCard.astro.test.ts @@ -29,7 +29,7 @@ const truncationClasses = (className: string | undefined): string[] => (className ?? "") .split(/\s+/) .filter((token) => - /^(?:line-clamp-|truncate$|overflow-(?:[xy]-)?(?:hidden|clip|ellipsis)$|max-h-|text-ellipsis$|whitespace-nowrap$)/.test( + /^(?:line-clamp-(?:[1-9]\d*|\[[^\]]+\])|truncate$|overflow-(?:[xy]-)?(?:hidden|clip|ellipsis)$|text-ellipsis$|whitespace-nowrap$)/.test( token, ), ); From d8ec352f5ab66f5a2b35a97e6950d09070eaf515 Mon Sep 17 00:00:00 2001 From: Charlie Gleason Date: Thu, 10 Sep 2026 19:46:28 +0000 Subject: [PATCH 10/10] fix: wrap full model card descriptions --- src/components/models/ModelCard.astro | 2 +- src/components/models/ModelCard.astro.test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/models/ModelCard.astro b/src/components/models/ModelCard.astro index 53109768246..6ca8723a9f7 100644 --- a/src/components/models/ModelCard.astro +++ b/src/components/models/ModelCard.astro @@ -132,7 +132,7 @@ const authorLogo = authorData[model.author]?.logo;

{model.description}

diff --git a/src/components/models/ModelCard.astro.test.ts b/src/components/models/ModelCard.astro.test.ts index 3bf560b5162..e861a780cd6 100644 --- a/src/components/models/ModelCard.astro.test.ts +++ b/src/components/models/ModelCard.astro.test.ts @@ -29,7 +29,7 @@ const truncationClasses = (className: string | undefined): string[] => (className ?? "") .split(/\s+/) .filter((token) => - /^(?:line-clamp-(?:[1-9]\d*|\[[^\]]+\])|truncate$|overflow-(?:[xy]-)?(?:hidden|clip|ellipsis)$|text-ellipsis$|whitespace-nowrap$)/.test( + /^(?:line-clamp-(?:[1-9]\d*|\[[^\]]+\])$|truncate$|overflow-(?:[xy]-)?(?:hidden|clip|ellipsis)$|text-ellipsis$|whitespace-nowrap$)/.test( token, ), ); @@ -52,5 +52,6 @@ describe("ModelCard", () => { expect(title?.getAttribute("class")).toContain("break-words"); expect(description?.textContent).toBe(model.description); expect(truncationClasses(description?.getAttribute("class"))).toEqual([]); + expect(description?.getAttribute("class")).toContain("break-words"); }); });