···
58
58
target="_blank"
59
59
rel="noopener noreferrer"
60
60
className="FloatingAvatar-link"
61
61
+
tabIndex={-1}
61
62
>
62
63
<img
63
64
src={src}
···
1
1
.HomeTrailsList-grid {
2
2
max-width: 800px;
3
3
margin: 0 auto;
4
4
-
display: grid;
5
5
-
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
6
6
-
gap: 1.5rem;
4
4
+
column-count: 2;
5
5
+
column-gap: 1.5rem;
7
6
padding: 0 1rem;
8
7
min-height: 1px;
9
8
}
10
9
10
10
+
.HomeTrailsList-grid > * {
11
11
+
break-inside: avoid;
12
12
+
margin-bottom: 1.5rem;
13
13
+
}
14
14
+
11
15
@media (max-width: 768px) {
12
16
.HomeTrailsList-grid {
13
13
-
grid-template-columns: 1fr;
17
17
+
column-count: 1;
14
18
}
15
19
}
···
7
7
trails: TrailCardData[];
8
8
};
9
9
10
10
+
// Reorder items for CSS columns masonry: [1,2,3,4,5,6] -> [1,3,5,2,4,6]
11
11
+
// CSS columns fills top-to-bottom, so left column gets first half of DOM.
12
12
+
// We put odd-ranked items first (left col), then even-ranked (right col).
13
13
+
// Visual order reads left-to-right: 1,2 / 3,4 / 5,6
14
14
+
// Tab order follows DOM: 1 -> 3 -> 5 -> 2 -> 4 -> 6 (column-wise)
15
15
+
function interleaveForMasonry<T>(items: T[]): T[] {
16
16
+
const result: T[] = [];
17
17
+
for (let i = 0; i < items.length; i += 2) {
18
18
+
result.push(items[i]);
19
19
+
}
20
20
+
for (let i = 1; i < items.length; i += 2) {
21
21
+
result.push(items[i]);
22
22
+
}
23
23
+
return result;
24
24
+
}
25
25
+
10
26
export function HomeTrailsList({ trails }: Props) {
11
27
if (trails.length === 0) {
12
28
return (
···
14
30
);
15
31
}
16
32
33
33
+
const reordered = interleaveForMasonry(trails);
34
34
+
17
35
return (
18
36
<div className="HomeTrailsList-grid">
19
19
-
{trails.map((trail) => (
37
37
+
{reordered.map((trail) => (
20
38
<TrailCard
21
39
key={trail.uri}
22
40
uri={trail.uri}