@@ -27,6 +27,36 @@ function loadMetadata(metadataPath) {
2727}
2828
2929
30+ // MyST markdown templates — kept separate from logic for readability
31+ const clickableCardMyst = ( link , title , description ) => [
32+ '```{card}' ,
33+ `:link: ${ link } ` ,
34+ `:header: [${ title } →](${ link } )` ,
35+ description ,
36+ '```' ,
37+ ] . join ( '\n' ) ;
38+
39+ const unrecognizedCardMyst = ( filePath ) => [
40+ '```{card}' ,
41+ ':header: ⚠️ _Unrecognised notebook_' ,
42+ `Could not find \`${ filePath } \`` ,
43+ '```' ,
44+ ] . join ( '\n' ) ;
45+
46+ const metadataErrorMyst = ( metadataPath ) => [
47+ `:::{error} \`notebook-gallery\` error` ,
48+ `Could not read metadata from \`${ metadataPath } \`` ,
49+ ':::' ,
50+ ] . join ( '\n' ) ;
51+
52+ const gridOfCardsMyst = ( cards ) => [
53+ '````{grid} 1 2 2 3' ,
54+ ...cards ,
55+ '````' ,
56+ ] . join ( '\n\n' ) ;
57+ // End of MyST markdown templates
58+
59+
3060/**
3161 * MyST directive: notebook-gallery
3262 *
@@ -56,27 +86,35 @@ const notebookGalleryDirective = {
5686 body : { type : String , required : true } ,
5787
5888 run ( data , vfile , ctx ) {
89+ // Resolve the metadata file path relative to the repo root and load it
5990 const metadataPath = path . resolve ( REPO_ROOT , data . arg ) ;
6091 const metadataByFile = loadMetadata ( metadataPath ) ;
6192
6293 if ( ! metadataByFile ) {
63- return ctx . parseMyst ( `:::danger\nnotebook-gallery: could not read \` ${ metadataPath } \`\n:::` ) . children ;
94+ return ctx . parseMyst ( metadataErrorMyst ( metadataPath ) ) . children ;
6495 }
6596
97+ // Links in cards must be relative to the file that contains this directive
6698 const callerDir = path . dirname ( path . resolve ( vfile . path ) ) ;
6799
68- const cards = data . body . split ( '\n' )
100+ // Parse the body: one notebook path per line, skip blank lines and comments
101+ const notebookFilePaths = data . body . split ( '\n' )
69102 . map ( l => l . trim ( ) )
70- . filter ( l => l && ! l . startsWith ( '#' ) )
71- . map ( filePath => {
72- const meta = metadataByFile [ filePath ] ;
73- if ( ! meta ) return `:::warning\nnotebook-gallery: not found in metadata: \`${ filePath } \`\n:::` ;
74- const link = path . relative ( callerDir , path . resolve ( REPO_ROOT , filePath ) ) ;
75- return `\`\`\`{card}\n:link: ${ link } \n:header: [${ meta . title } →](${ link } )\n${ meta . description } \n\`\`\`` ;
76- } ) ;
77-
78- const myst = `\`\`\`\`{grid} 1 2 2 3\n${ cards . join ( '\n\n' ) } \n\`\`\`\`` ;
79- return ctx . parseMyst ( myst ) . children ;
103+ . filter ( l => l && ! l . startsWith ( '#' ) ) ;
104+
105+ // Build a MyST card string for each notebook path
106+ const cards = notebookFilePaths . map ( filePath => {
107+ const meta = metadataByFile [ filePath ] ;
108+ if ( ! meta ) return unrecognizedCardMyst ( filePath ) ;
109+ const link = path . relative ( callerDir , path . resolve ( REPO_ROOT , filePath ) ) ;
110+ const title = meta . title ?? path . basename ( filePath , path . extname ( filePath ) ) ; // fall back to filename
111+ const description = meta . description ?? '' ; // fall back to no description
112+ return clickableCardMyst ( link , title , description ) ;
113+ } ) ;
114+
115+ // Wrap all cards in a grid, parse the combined MyST string, and return the
116+ // resulting AST nodes to be inserted in place of this directive.
117+ return ctx . parseMyst ( gridOfCardsMyst ( cards ) ) . children ;
80118 } ,
81119} ;
82120
0 commit comments