11import { marked } from 'marked' ;
22
3+ // Bundle markdown and image assets so production does not rely on /src fetch paths.
4+ const markdownLoaders = import . meta. glob ( '/src/assets/markdown/**/*.md' , {
5+ query : '?raw' ,
6+ import : 'default'
7+ } ) ;
8+
9+ const imageAssets = import . meta. glob ( '/src/assets/images/*' , {
10+ eager : true ,
11+ import : 'default'
12+ } ) ;
13+
314// DOM elements
415const pageNavs = document . querySelectorAll ( '.page-nav' ) ;
516const contentBox = document . getElementById ( 'contentBox' ) ;
@@ -15,6 +26,25 @@ const projectSlugs = ['soccer-robots', 'anuran-calls', 'gen-zsl'];
1526// Project data loaded from markdown
1627let projects = [ ] ;
1728
29+ function getMarkdownLoader ( path ) {
30+ return markdownLoaders [ path ] || null ;
31+ }
32+
33+ function resolveImagePath ( path ) {
34+ if ( ! path ) return '' ;
35+ if ( / ^ ( h t t p s ? : ) ? \/ \/ / . test ( path ) ) return path ;
36+ const normalized = path . startsWith ( '/' ) ? path : `/${ path } ` ;
37+ return imageAssets [ normalized ] || path ;
38+ }
39+
40+ async function loadMarkdownFile ( path ) {
41+ const loader = getMarkdownLoader ( path ) ;
42+ if ( ! loader ) {
43+ throw new Error ( `Markdown asset not found: ${ path } ` ) ;
44+ }
45+ return loader ( ) ;
46+ }
47+
1848// Parse frontmatter from markdown
1949function parseFrontmatter ( markdown ) {
2050 const lines = markdown . split ( '\n' ) ;
@@ -36,15 +66,14 @@ function parseFrontmatter(markdown) {
3666// Load all project metadata
3767async function loadProjectMetadata ( ) {
3868 const projectPromises = projectSlugs . map ( slug =>
39- fetch ( `/src/assets/markdown/projects/${ slug } .md` )
40- . then ( response => response . text ( ) )
69+ loadMarkdownFile ( `/src/assets/markdown/projects/${ slug } .md` )
4170 . then ( markdown => {
4271 const frontmatter = parseFrontmatter ( markdown ) ;
4372 return {
4473 slug : slug ,
4574 title : frontmatter . title || slug ,
4675 description : frontmatter . description || '' ,
47- image : frontmatter . image || '' ,
76+ image : resolveImagePath ( frontmatter . image || '' ) ,
4877 attribution : frontmatter . attribution || '' ,
4978 order : parseInt ( frontmatter . order ) || 0
5079 } ;
@@ -89,11 +118,7 @@ function loadMarkdown(page) {
89118 const contentDiv = document . getElementById ( page + '-content' ) ;
90119 if ( ! markdownPaths [ page ] || ! contentDiv ) return ;
91120
92- fetch ( markdownPaths [ page ] )
93- . then ( response => {
94- if ( ! response . ok ) throw new Error ( 'Network response was not ok' ) ;
95- return response . text ( ) ;
96- } )
121+ loadMarkdownFile ( markdownPaths [ page ] )
97122 . then ( md => {
98123 const targetDiv = page === 'cv' ?
99124 contentDiv . querySelector ( '#cv-markdown' ) :
@@ -159,11 +184,7 @@ function loadProjectDetail(slug) {
159184 contentBox . classList . add ( 'expanded' ) ;
160185
161186 // Load project markdown
162- fetch ( `/src/assets/markdown/projects/${ slug } .md` )
163- . then ( response => {
164- if ( ! response . ok ) throw new Error ( 'Network response was not ok' ) ;
165- return response . text ( ) ;
166- } )
187+ loadMarkdownFile ( `/src/assets/markdown/projects/${ slug } .md` )
167188 . then ( markdown => {
168189 // Parse frontmatter and content
169190 const lines = markdown . split ( '\n' ) ;
@@ -186,9 +207,10 @@ function loadProjectDetail(slug) {
186207 const content = lines . slice ( contentStart ) . join ( '\n' ) ;
187208 const project = projects . find ( p => p . slug === slug ) ;
188209
189- const imageHtml = frontmatter . image ? `
210+ const imageUrl = resolveImagePath ( frontmatter . image || project ?. image || '' ) ;
211+ const imageHtml = imageUrl ? `
190212 <div class="project-detail-image-container">
191- <img src="${ frontmatter . image } " alt="${ frontmatter . title || project ?. title || 'Project' } " class="project-detail-image">
213+ <img src="${ imageUrl } " alt="${ frontmatter . title || project ?. title || 'Project' } " class="project-detail-image">
192214 ${ frontmatter . attribution ? `<p class="image-attribution">Image: ${ frontmatter . attribution } </p>` : '' }
193215 </div>
194216 ` : '' ;
0 commit comments