@@ -62,6 +62,7 @@ function GalleryAppPage() {
6262 const [ relatedApps , setRelatedApps ] = useState < App [ ] > ( [ ] ) ;
6363 const [ loading , setLoading ] = useState ( true ) ;
6464 const [ readme , setReadme ] = useState < string | null > ( null ) ;
65+ const [ readmeBaseUrl , setReadmeBaseUrl ] = useState < string | null > ( null ) ;
6566
6667 const slug = location . pathname . split ( "/" ) . filter ( Boolean ) . pop ( ) || "" ;
6768
@@ -225,23 +226,27 @@ function GalleryAppPage() {
225226 ) ;
226227 } ;
227228
229+ const urlParts = app . githubUrl . split ( "/" ) ;
230+ // Handle https://github.com/owner/repo
231+ const ownerIndex = urlParts . indexOf ( "github.com" ) + 1 ;
232+ if ( ownerIndex === 0 || ownerIndex + 1 >= urlParts . length ) return ;
233+
234+ const owner = urlParts [ ownerIndex ] ;
235+ const repo = urlParts [ ownerIndex + 1 ] ;
236+
228237 // 1. CACHE CHECK: Do we have this in local storage?
229238 const cacheKey = `readme-${ app . slug } ` ;
230239 const cached = localStorage . getItem ( cacheKey ) ;
231240 if ( cached ) {
241+ // Default to main branch for cached READMEs
242+ setReadmeBaseUrl (
243+ `https://github.com/${ owner } /${ repo } /blob/main/` ,
244+ ) ;
232245 setReadme ( preprocessReadme ( cached ) ) ;
233246 return ;
234247 }
235248
236249 try {
237- const urlParts = app . githubUrl . split ( "/" ) ;
238- // Handle https://github.com/owner/repo
239- const ownerIndex = urlParts . indexOf ( "github.com" ) + 1 ;
240- if ( ownerIndex === 0 || ownerIndex + 1 >= urlParts . length ) return ;
241-
242- const owner = urlParts [ ownerIndex ] ;
243- const repo = urlParts [ ownerIndex + 1 ] ;
244-
245250 const branches = [ "main" , "master" ] ;
246251 const filenames = [ "README.md" , "readme.md" ] ;
247252
@@ -254,6 +259,10 @@ function GalleryAppPage() {
254259 const text = await res . text ( ) ;
255260 // Save RAW text to cache so we can improve preprocessing later if needed
256261 localStorage . setItem ( cacheKey , text ) ;
262+ // Store the base URL for resolving relative links in the README
263+ setReadmeBaseUrl (
264+ `https://github.com/${ owner } /${ repo } /blob/${ branch } /` ,
265+ ) ;
257266 // Render PROCESSED text
258267 setReadme ( preprocessReadme ( text ) ) ;
259268 return ; // Exit completely once found
@@ -455,6 +464,33 @@ function GalleryAppPage() {
455464 rehypePlugins = { [ rehypeRaw ] }
456465 components = { {
457466 img : ( ) => null , // Explicitly exclude images
467+ a : ( { href, children, ...props } ) => {
468+ let resolvedHref = href || "" ;
469+ // Rewrite relative URLs to point to the GitHub repo
470+ if (
471+ readmeBaseUrl &&
472+ resolvedHref &&
473+ ! resolvedHref . startsWith ( "http://" ) &&
474+ ! resolvedHref . startsWith ( "https://" ) &&
475+ ! resolvedHref . startsWith ( "//" ) &&
476+ ! resolvedHref . startsWith ( "#" ) &&
477+ ! resolvedHref . startsWith ( "mailto:" )
478+ ) {
479+ // Strip leading "./" if present
480+ const cleanPath = resolvedHref . replace ( / ^ \. \/ / , "" ) ;
481+ resolvedHref = `${ readmeBaseUrl } ${ cleanPath } ` ;
482+ }
483+ return (
484+ < a
485+ href = { resolvedHref }
486+ target = "_blank"
487+ rel = "noopener noreferrer"
488+ { ...props }
489+ >
490+ { children }
491+ </ a >
492+ ) ;
493+ } ,
458494 } }
459495 >
460496 { readme }
0 commit comments