Skip to content

Commit f34da95

Browse files
committed
fix(lab-card): align links across columns via subgrid
Problem: when links grouped by kind sat in side-by-side columns, the second-row link in one column could sit slightly lower than its sibling in the next column. Each column was its own layout context, so rows didn't share heights across siblings — a short label on the left and a long label on the right wouldn't align. Fix: switch .lab-card__column to a CSS subgrid inheriting rows from .lab-card__columns, so heading + each link row share heights across all columns. Compute --lab-card-rows = max(link count per kind) from JSX so the outer grid defines enough tracks. Also flatten the per-column markup: the inner <ul> wrapper around the link list is gone, since each column now lays out via grid rows directly.
1 parent d37c24b commit f34da95

3 files changed

Lines changed: 37 additions & 25 deletions

File tree

src/design/components/lab-card/index.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,30 @@ function groupByKind(links: readonly FeaturedLink[]): Column[] {
2626

2727
export function LabCard({ lab }: { lab: FeaturedLab }) {
2828
const columns = groupByKind(lab.links)
29+
const maxLinks = columns.reduce((n, c) => Math.max(n, c.links.length), 0)
30+
// Expose the grid size so subgrid rows can align across columns.
31+
const style = `--lab-card-rows: ${maxLinks};`
32+
2933
return (
3034
<article class="lab-card">
3135
<div class="lab-card__intro">
3236
<h3 class="lab-card__title">{lab.title}</h3>
3337
<p class="lab-card__tagline">{lab.tagline}</p>
3438
</div>
35-
<ul class="lab-card__columns">
39+
<ul class="lab-card__columns" style={style}>
3640
{columns.map((column) => (
3741
<li class="lab-card__column">
3842
<p class="lab-card__column-heading">{KIND_HEADING[column.kind]}</p>
39-
<ul class="lab-card__column-links">
40-
{column.links.map((link) => (
41-
<li>
42-
<a
43-
class="lab-card__column-link"
44-
href={link.url}
45-
rel="noopener external"
46-
>
47-
<LinkIcon kind={column.kind} />
48-
<span>{link.label}</span>
49-
</a>
50-
</li>
51-
))}
52-
</ul>
43+
{column.links.map((link) => (
44+
<a
45+
class="lab-card__column-link"
46+
href={link.url}
47+
rel="noopener external"
48+
>
49+
<LinkIcon kind={column.kind} />
50+
<span>{link.label}</span>
51+
</a>
52+
))}
5353
</li>
5454
))}
5555
</ul>

src/design/components/lab-card/styles.css

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,6 @@
5858
margin: 0;
5959
}
6060

61-
.lab-card__column-links {
62-
list-style: none;
63-
padding: 0;
64-
margin: 0;
65-
display: flex;
66-
flex-direction: column;
67-
gap: var(--space-2);
68-
}
69-
7061
.lab-card__column-link {
7162
display: inline-flex;
7263
align-items: center;
@@ -95,10 +86,25 @@
9586
color: var(--color-link-hover);
9687
}
9788

98-
/* Wide enough for a multi-column layout — one column per link kind. */
89+
/*
90+
* On wide containers: one column per link kind, and all columns
91+
* share row heights via subgrid so the Nth link in each column
92+
* lines up horizontally — even when one column's label wraps.
93+
*
94+
* Row layout: 1 heading row + N link rows, where N is --lab-card-rows
95+
* (the max link count across kinds, computed in JSX).
96+
*/
9997
@container (min-width: 32rem) {
10098
.lab-card__columns {
10199
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
100+
grid-template-rows: auto repeat(var(--lab-card-rows, 1), auto);
101+
row-gap: var(--space-3);
102+
}
103+
.lab-card__column {
104+
display: grid;
105+
grid-template-rows: subgrid;
106+
grid-row: span calc(var(--lab-card-rows, 1) + 1);
107+
gap: 0;
102108
}
103109
}
104110
}

tests/views/components.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ describe('LabCard', () => {
112112
expect(html.match(/rel="noopener external"/g)?.length).toBe(4)
113113
})
114114

115+
test('exposes --lab-card-rows to size subgrid rows across columns', async () => {
116+
const html = await renderToHtml(<LabCard lab={multiProject} />)
117+
// Two links per column → 2 rows of links
118+
expect(html).toContain('--lab-card-rows: 2')
119+
})
120+
115121
test('column order is Demo, Repository, Case study (only kinds present)', async () => {
116122
const html = await renderToHtml(<LabCard lab={multiProject} />)
117123
const demoIdx = html.indexOf('>Demo<')

0 commit comments

Comments
 (0)