From 390848bb28e2728b94c39e04b79c777cbd2352e0 Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Fri, 5 Dec 2025 08:29:39 +1100 Subject: [PATCH 1/3] WIP: MarkdownLink --- src/components/MarkdownLink.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/MarkdownLink.tsx b/src/components/MarkdownLink.tsx index 3fca7017e..c8e5fb92d 100644 --- a/src/components/MarkdownLink.tsx +++ b/src/components/MarkdownLink.tsx @@ -17,6 +17,12 @@ export function MarkdownLink({ const [hrefWithoutHash, hash] = hrefProp?.split('#') ?? [] let [to] = hrefWithoutHash?.split('.md') ?? [] + to = to.replaceAll(/\.\.\//gm, '../../') + to = to.replaceAll( + /(?!https?:\/\/|\/\/|\/|\.\/|\.\.\/|#)([^)]+)\)/gm, + (match, p1) => `../${p1})` + ) + return ( Date: Fri, 5 Dec 2025 18:14:26 +1100 Subject: [PATCH 2/3] Tweak MarkdownLink --- src/components/MarkdownLink.tsx | 96 +++++++-------------------------- 1 file changed, 20 insertions(+), 76 deletions(-) diff --git a/src/components/MarkdownLink.tsx b/src/components/MarkdownLink.tsx index c8e5fb92d..235475cb3 100644 --- a/src/components/MarkdownLink.tsx +++ b/src/components/MarkdownLink.tsx @@ -1,99 +1,43 @@ import { Link } from '@tanstack/react-router' import type { HTMLProps } from 'react' +function isRelativeLink(link: string) { + return ( + !link.startsWith(`/`) && + !link.startsWith('http://') && + !link.startsWith('https://') && + !link.startsWith('//') && + !link.startsWith('#') && + !link.startsWith('mailto:') + ) +} + export function MarkdownLink({ href: hrefProp, ...rest }: HTMLProps) { - if ( - hrefProp?.startsWith('http') || - hrefProp?.startsWith('#') || - hrefProp?.startsWith('//') - ) { - // eslint-disable-next-line jsx-a11y/anchor-has-content + if (!isRelativeLink(hrefProp ?? '')) { return } const [hrefWithoutHash, hash] = hrefProp?.split('#') ?? [] - let [to] = hrefWithoutHash?.split('.md') ?? [] + let hrefWithoutMd = hrefWithoutHash.replace('.md', '') - to = to.replaceAll(/\.\.\//gm, '../../') - to = to.replaceAll( - /(?!https?:\/\/|\/\/|\/|\.\/|\.\.\/|#)([^)]+)\)/gm, - (match, p1) => `../${p1})` - ) + // Force relative links to resolve one level higher + if (hrefWithoutMd.startsWith('../')) { + hrefWithoutMd = hrefWithoutMd.replace(/^\.\.\//gm, '../../') + } else if (hrefWithoutMd.startsWith('./')) { + hrefWithoutMd = hrefWithoutMd.replace(/^\.\//gm, '../') + } return ( ) } - -// function resolveRelativePath(routerHref: string, markdownPath: string): string { -// let hash = '' -// let basePath = routerHref -// let relativePath = markdownPath - -// // Check if the relative path starts with a hash -// if (relativePath.startsWith('#')) { -// // If the basePath already has a hash, remove it -// const hashIndex = basePath.indexOf('#') -// if (hashIndex !== -1) { -// basePath = basePath.substring(0, hashIndex) -// } - -// return basePath + relativePath -// } - -// // Remove hash from path if it exists, we'll add it back later -// if (hashIndex !== -1) { -// hash = relativePath.substring(hashIndex) -// relativePath = relativePath.substring(0, hashIndex) -// } - -// // Remove .md extension if it exists -// if (relativePath.endsWith('.md')) { -// relativePath = relativePath.substring(0, relativePath.length - 3) -// } else { -// // If the path doesn't end with .md, return the path as is -// return relativePath + hash -// } - -// const stack = basePath.split('/').filter(Boolean) -// const parts = relativePath.split('/') - -// let firstDoubleDotEncountered = false // Flag to track the first ".." - -// for (let i = 0; i < parts.length; i++) { -// const part = parts[i] -// if (part === '.') { -// continue -// } -// if (part === '..') { -// if (!firstDoubleDotEncountered) { -// // First time encountering ".." -// stack.pop() // First pop -// stack.pop() // Second pop -// firstDoubleDotEncountered = true // Set the flag -// } else { -// // Subsequent ".." -// stack.pop() -// } -// } else { -// stack.push(part) -// } -// } - -// let resolvedPath = '/' + stack.filter(Boolean).join('/') - -// // Add the hash back -// resolvedPath += hash - -// return resolvedPath -// } From fe5e6b2eb2c9fa8d9cbecf54b2b3f91aa496a35a Mon Sep 17 00:00:00 2001 From: Lachlan Collins <1667261+lachlancollins@users.noreply.github.com> Date: Fri, 5 Dec 2025 19:00:31 +1100 Subject: [PATCH 3/3] Handle relative link without ./ --- src/components/MarkdownLink.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/MarkdownLink.tsx b/src/components/MarkdownLink.tsx index 235475cb3..452b147a4 100644 --- a/src/components/MarkdownLink.tsx +++ b/src/components/MarkdownLink.tsx @@ -28,6 +28,8 @@ export function MarkdownLink({ hrefWithoutMd = hrefWithoutMd.replace(/^\.\.\//gm, '../../') } else if (hrefWithoutMd.startsWith('./')) { hrefWithoutMd = hrefWithoutMd.replace(/^\.\//gm, '../') + } else { + hrefWithoutMd = `../${hrefWithoutMd}` } return (