an app to share curated trails sidetrail.app
1

Configure Feed

Select the types of activity you want to include in your feed.

1import type { TrailCardData } from "../data/queries"; 2import { TrailCard } from "./TrailCard"; 3import { HomeEmptyState } from "./HomeEmptyState"; 4import "./HomeTrailsList.css"; 5 6type Props = { 7 trails: TrailCardData[]; 8}; 9 10// Reorder items for CSS columns masonry: [1,2,3,4,5,6] -> [1,3,5,2,4,6] 11// CSS columns fills top-to-bottom, so left column gets first half of DOM. 12// We put odd-ranked items first (left col), then even-ranked (right col). 13// Visual order reads left-to-right: 1,2 / 3,4 / 5,6 14// Tab order follows DOM: 1 -> 3 -> 5 -> 2 -> 4 -> 6 (column-wise) 15// On mobile, CSS order property restores original ranking. 16function interleaveForMasonry<T>(items: T[]): { item: T; originalIndex: number }[] { 17 const result: { item: T; originalIndex: number }[] = []; 18 for (let i = 0; i < items.length; i += 2) { 19 result.push({ item: items[i], originalIndex: i }); 20 } 21 for (let i = 1; i < items.length; i += 2) { 22 result.push({ item: items[i], originalIndex: i }); 23 } 24 return result; 25} 26 27export function HomeTrailsList({ trails }: Props) { 28 if (trails.length === 0) { 29 return ( 30 <HomeEmptyState message="no trails are trending right now" buttonText="start a new trail" /> 31 ); 32 } 33 34 const reordered = interleaveForMasonry(trails); 35 36 return ( 37 <div className="HomeTrailsList-grid"> 38 {reordered.map(({ item: trail, originalIndex }) => ( 39 <div key={trail.uri} style={{ "--original-index": originalIndex } as React.CSSProperties}> 40 <TrailCard 41 uri={trail.uri} 42 rkey={trail.rkey} 43 creatorHandle={trail.creatorHandle} 44 title={trail.title} 45 description={trail.description} 46 accentColor={trail.accentColor} 47 backgroundColor={trail.backgroundColor} 48 creator={trail.creator} 49 stopsCount={trail.stopsCount} 50 /> 51 </div> 52 ))} 53 </div> 54 ); 55}