@@ -11,12 +11,13 @@ import { DonationBanner } from '@/components/board/donation-banner';
1111import { BoardJsonLd } from '@/components/board/board-jsonld' ;
1212import { BoardImage as BoardImageWithFallback } from '@/components/board/board-image' ;
1313import { Link } from '@/i18n/navigation' ;
14- import type { Image as BoardImage } from '@armbian/schemas' ;
14+ import type { BoardSummary , Image as BoardImage } from '@armbian/schemas' ;
1515import { Download , BookOpen , Code , ArrowRight , ArrowLeft } from 'lucide-react' ;
1616import { SiGithub } from '@icons-pack/react-simple-icons' ;
1717import type { Metadata } from 'next' ;
1818import { BoardPageDownloads } from '@/components/board/board-page-downloads' ;
1919import { FlashGuideModal } from '@/components/board/flash-guide-modal' ;
20+ import { SiblingBoardsCarousel } from '@/components/board/sibling-boards-carousel' ;
2021import { getPayload } from 'payload' ;
2122import config from '@payload-config' ;
2223import { sanitizeCmsHtml } from '@/lib/sanitize' ;
@@ -170,19 +171,39 @@ export default async function BoardPage({ params }: Props) {
170171 throw err ;
171172 }
172173
173- // Fetch flash guide from Payload CMS. Payload native localization
174- // handles the EN fallback via `fallbackLocale` — no manual two-step.
174+ // Sibling boards (for the "More from X" carousel) and the Payload flash
175+ // guide both depend only on `board` and are independent — fire them in
176+ // parallel to save a round trip on every page render.
177+ const [ siblingResult , flashGuideResult ] = await Promise . allSettled ( [
178+ api . getBoards ( {
179+ vendor : board . vendor_slug ,
180+ sort : 'popularity' ,
181+ // 13 = 12 siblings the carousel can show + room to filter out the
182+ // current board if it appears in the popularity ordering.
183+ limit : 13 ,
184+ } ) ,
185+ ( async ( ) => {
186+ const payload = await getPayload ( { config } ) ;
187+ return payload . find ( {
188+ collection : 'flash-guides' ,
189+ where : { boardSlug : { equals : slug } } ,
190+ locale : locale as 'en' | 'it' ,
191+ fallbackLocale : 'en' ,
192+ limit : 1 ,
193+ } ) ;
194+ } ) ( ) ,
195+ ] ) ;
196+
197+ let siblingBoards : BoardSummary [ ] = [ ] ;
198+ let vendorBoardCount = 0 ;
199+ if ( siblingResult . status === 'fulfilled' ) {
200+ vendorBoardCount = siblingResult . value . meta . total ?? 0 ;
201+ siblingBoards = siblingResult . value . data . filter ( ( b ) => b . slug !== board . slug ) . slice ( 0 , 12 ) ;
202+ }
203+
175204 let flashGuide : { title : string ; content : string ; prerequisites : string [ ] } | null = null ;
176- try {
177- const payload = await getPayload ( { config } ) ;
178- const result = await payload . find ( {
179- collection : 'flash-guides' ,
180- where : { boardSlug : { equals : slug } } ,
181- locale : locale as 'en' | 'it' ,
182- fallbackLocale : 'en' ,
183- limit : 1 ,
184- } ) ;
185- const doc = result . docs [ 0 ] ;
205+ if ( flashGuideResult . status === 'fulfilled' ) {
206+ const doc = flashGuideResult . value . docs [ 0 ] ;
186207 if ( doc ) {
187208 const prereqs = Array . isArray ( doc . prerequisites )
188209 ? doc . prerequisites . map ( ( p : { item ?: string } ) => p . item ?? '' )
@@ -202,8 +223,6 @@ export default async function BoardPage({ params }: Props) {
202223 prerequisites : prereqs . filter ( Boolean ) ,
203224 } ;
204225 }
205- } catch {
206- /* Payload not available — skip flash guide */
207226 }
208227
209228 const isTrunk = ( img : BoardImage ) => img . release . toLowerCase ( ) . includes ( 'trunk' ) ;
@@ -284,9 +303,12 @@ export default async function BoardPage({ params }: Props) {
284303 </ div >
285304
286305 < div className = "flex-1 min-w-0" >
287- < span className = "text-[11px] text-[rgb(var(--brand))] font-mono font-bold uppercase tracking-widest mb-2 block" >
306+ < Link
307+ href = { `/vendors/${ board . vendor_slug } ` }
308+ className = "text-[11px] text-[rgb(var(--brand))] font-mono font-bold uppercase tracking-widest mb-2 inline-block hover:underline"
309+ >
288310 { board . vendor_name }
289- </ span >
311+ </ Link >
290312 < div className = "flex flex-wrap items-center gap-3 mb-3" >
291313 < h1 className = "text-fluid-2xl font-black tracking-tight" > { board . name } </ h1 >
292314 < SupportBadge tier = { board . support_tier } />
@@ -426,6 +448,19 @@ export default async function BoardPage({ params }: Props) {
426448 </ section >
427449 </ ScrollReveal >
428450
451+ { siblingBoards . length > 0 && (
452+ < ScrollReveal >
453+ < section className = "mb-20" >
454+ < SiblingBoardsCarousel
455+ boards = { siblingBoards }
456+ vendorName = { board . vendor_name }
457+ vendorSlug = { board . vendor_slug }
458+ vendorBoardCount = { vendorBoardCount }
459+ />
460+ </ section >
461+ </ ScrollReveal >
462+ ) }
463+
429464 < DonationBanner />
430465 </ div >
431466 </ div >
0 commit comments