@@ -1297,18 +1297,55 @@ export function latestVideos(limit = LATEST_SLUGS.length): Video[] {
12971297}
12981298
12991299/**
1300- * Homepage hero — the single video featured at the top of the homepage, currently the
1301- * channel's most-viewed video (caption: "most viewed"). DECOUPLED from LATEST_SLUGS on
1302- * purpose: the most-viewed video is not necessarily the newest upload, so it does NOT belong
1303- * in the upload-ordered "Latest videos" list. Update this slug when the featured video changes.
1300+ * Homepage hero — the TWO videos featured side-by-side at the top of the homepage.
1301+ * ORDER IS MEANINGFUL: index 0 = LEFT column (desktop) / TOP (mobile stack), index 1 =
1302+ * RIGHT / BOTTOM. Ordered oldest→newest so the mobile stack reads chronologically.
1303+ *
1304+ * Each pick carries its own editorial `caption` because only ONE of the two is the
1305+ * channel's most-viewed video — a shared "most viewed" label would be inaccurate.
1306+ * Keep captions short (they render on one line under a fixed 16:9 thumbnail).
1307+ *
1308+ * DECOUPLED from LATEST_SLUGS on purpose: an evergreen/most-viewed pick is not
1309+ * necessarily a recent upload, so it does NOT belong in "Latest videos".
1310+ * Update these slugs/captions when the featured picks change.
13041311 */
1305- export const FEATURED_SLUG = 'getting-started-acb-vscode-hello-world' ;
1312+ export interface FeaturedVideo {
1313+ video : Video ;
1314+ /** Editorial caption rendered beneath the thumbnail (may include an emoji). */
1315+ caption : string ;
1316+ }
13061317
1307- /** Homepage hero video (see FEATURED_SLUG). Throws at build if the slug is stale. */
1308- export function featuredVideo ( ) : Video {
1309- const v = getVideo ( FEATURED_SLUG ) ;
1310- if ( ! v ) throw new Error ( `FEATURED_SLUG "${ FEATURED_SLUG } " not found in VIDEOS` ) ;
1311- return v ;
1318+ const FEATURED : { slug : string ; caption : string } [ ] = [
1319+ { slug : 'mulesoft-from-start-mulesoft-overview' , caption : '👑 most viewed' } ,
1320+ { slug : 'getting-started-acb-vscode-hello-world' , caption : '🚀 start with ACB' } ,
1321+ ] ;
1322+
1323+ /**
1324+ * Back-compat literal for scripts/youtube-analytics.mjs, whose parser greps this file for
1325+ * the FEATURED_SLUG assignment below. Keep it a single-quoted string literal (NOT
1326+ * FEATURED[0].slug — the regex needs a literal) AND equal to FEATURED[0].slug, the left /
1327+ * most-viewed pick. The assert below fails the build if the two ever drift. (Don't write the
1328+ * assignment pattern in prose above this line — the regex matches the file's FIRST occurrence.)
1329+ */
1330+ export const FEATURED_SLUG = 'mulesoft-from-start-mulesoft-overview' ;
1331+ if ( FEATURED_SLUG !== FEATURED [ 0 ] . slug ) {
1332+ throw new Error ( 'FEATURED_SLUG must equal FEATURED[0].slug (kept as a literal for the analytics parser).' ) ;
1333+ }
1334+
1335+ /**
1336+ * Homepage hero videos, resolved LEFT→RIGHT (see FEATURED). Throws at build if any slug
1337+ * is stale OR if the count isn't exactly 2, so the two-column layout can't silently degrade.
1338+ */
1339+ export function featuredVideos ( ) : FeaturedVideo [ ] {
1340+ const resolved = FEATURED . map ( ( { slug, caption } ) => {
1341+ const video = getVideo ( slug ) ;
1342+ if ( ! video ) throw new Error ( `FEATURED slug "${ slug } " not found in VIDEOS` ) ;
1343+ return { video, caption } ;
1344+ } ) ;
1345+ if ( resolved . length !== 2 ) {
1346+ throw new Error ( `FEATURED must contain exactly 2 videos (got ${ resolved . length } ); the homepage hero is a two-column layout.` ) ;
1347+ }
1348+ return resolved ;
13121349}
13131350
13141351export function getPlaylist ( id : string ) : Playlist | undefined {
0 commit comments