commit ac27081f01517a2f6227d83e719389d804a0defd
parent 59d8935b670be1047bacd26405863ecdbc440edd
Author: Damian Myrda <damian@prime8.dev>
Date: Sat, 31 Jan 2026 18:58:29 -0600
fix(git): convert relative links to blob URLs for browsing
Links like ./LICENSE now point to git.prime8.dev/-/blob/... instead of
raw file URLs, allowing users to browse files in the Git UI.
Diffstat:
1 file changed, 31 insertions(+), 20 deletions(-)
diff --git a/src/external/git.ts b/src/external/git.ts
@@ -6,6 +6,11 @@ export interface GitMetadata {
dateModified: Date;
}
+interface RepoUrls {
+ web: string;
+ branch: string;
+}
+
export async function fetchGitMetadataForProject(
project: Project,
): Promise<GitMetadata | null> {
@@ -18,10 +23,18 @@ export async function fetchGitMetadataForProject(
const data = await response.json();
- const baseUrl = `${data.web_url.replace("http://", "https://")}/-/raw/${data.default_branch}`;
+ const urls: RepoUrls = {
+ web: data.web_url.replace("http://", "https://"),
+ branch: data.default_branch,
+ };
return {
- readme: await fetchReadme(baseUrl, toRawUrl(data.readme_url)),
+ readme: await fetchReadme(
+ urls,
+ data.readme_url
+ .replace("http://", "https://")
+ .replace("/-/blob/", "/-/raw/"),
+ ),
dateCreated: data.created_at,
dateModified: data.updated_at,
};
@@ -30,39 +43,37 @@ export async function fetchGitMetadataForProject(
}
}
-function toRawUrl(blobUrl: string): string {
- return blobUrl.replace("http://", "https://").replace("/-/blob/", "/-/raw/");
-}
-
async function fetchReadme(
- baseUrl: string,
- url: string,
+ urls: RepoUrls,
+ readmeUrl: string,
): Promise<string | null> {
try {
- const response = await fetch(url, {
+ const response = await fetch(readmeUrl, {
headers: { "User-Agent": "prime8dev-portfolio" },
});
if (!response.ok) return null;
const content = await response.text();
- return fixRelativePaths(baseUrl, content);
+ return fixRelativePaths(urls, content);
} catch {
return null;
}
}
-function fixRelativePaths(baseUrl: string, markdown: string): string {
- // Fix relative image paths:  -> 
- let fixed = markdown.replace(
- /!\[([^\]]*)\]\(\.\/([^)]+)\)/g,
- ``,
+function fixRelativePaths(urls: RepoUrls, markdown: string): string {
+ // blob = file browser URL (for links)
+ const blob = `${urls.web}/-/blob/${urls.branch}`;
+ markdown = markdown.replace(
+ /(?<!!)\[([^\]]+)\]\(\.\/([^)]+)\)/g,
+ `[$1](${blob}/$2)`,
);
- // Fix relative link paths (not images): [text](./path) -> [text](baseUrl/path)
- fixed = fixed.replace(
- /(?<!!)\[([^\]]+)\]\(\.\/([^)]+)\)/g,
- `[$1](${baseUrl}/$2)`,
+ // raw = direct file content URL (for images)
+ const raw = `${urls.web}/-/raw/${urls.branch}`;
+ markdown = markdown.replace(
+ /!\[([^\]]*)\]\(\.\/([^)]+)\)/g,
+ ``,
);
- return fixed;
+ return markdown;
}