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 (