Browse Source

Implement wiki links

master
Silberengel 10 months ago
parent
commit
0a54f0106b
  1. 47
      src/lib/utils/markdown/basicMarkdownParser.ts
  2. 8
      src/lib/utils/markdown/markdownTestfile.md

47
src/lib/utils/markdown/basicMarkdownParser.ts

@ -36,12 +36,10 @@ function replaceAlexandriaNostrLinks(text: string): string {
// Regex for 64-char hex // Regex for 64-char hex
const hexPattern = /\b[a-fA-F0-9]{64}\b/; const hexPattern = /\b[a-fA-F0-9]{64}\b/;
// 1. Replace Markdown links ONLY if they match the criteria // 1. Alexandria/localhost Markdown links
text = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, (match, _label, url) => { text = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, (match, _label, url) => {
if (alexandriaPattern.test(url)) { if (alexandriaPattern.test(url)) {
// Ignore d-tag URLs
if (/[?&]d=/.test(url)) return match; if (/[?&]d=/.test(url)) return match;
// Convert hexid in URL to nevent if present
const hexMatch = url.match(hexPattern); const hexMatch = url.match(hexPattern);
if (hexMatch) { if (hexMatch) {
try { try {
@ -51,22 +49,18 @@ function replaceAlexandriaNostrLinks(text: string): string {
return match; return match;
} }
} }
// Or use bech32 if present
const bech32Match = url.match(bech32Pattern); const bech32Match = url.match(bech32Pattern);
if (bech32Match) { if (bech32Match) {
return `nostr:${bech32Match[0]}`; return `nostr:${bech32Match[0]}`;
} }
} }
// For all other links, leave the markdown link untouched
return match; return match;
}); });
// 2. Replace bare Alexandria/localhost URLs only if they contain a Nostr identifier (not d-tag) // 2. Alexandria/localhost bare URLs and non-Alexandria/localhost URLs with Nostr identifiers
text = text.replace(/https?:\/\/[^\s)\]]+/g, (url) => { text = text.replace(/https?:\/\/[^\s)\]]+/g, (url) => {
if (alexandriaPattern.test(url)) { if (alexandriaPattern.test(url)) {
// Ignore d-tag URLs
if (/[?&]d=/.test(url)) return url; if (/[?&]d=/.test(url)) return url;
// Convert hexid in URL to nevent if present
const hexMatch = url.match(hexPattern); const hexMatch = url.match(hexPattern);
if (hexMatch) { if (hexMatch) {
try { try {
@ -76,12 +70,25 @@ function replaceAlexandriaNostrLinks(text: string): string {
return url; return url;
} }
} }
// Or use bech32 if present
const bech32Match = url.match(bech32Pattern); const bech32Match = url.match(bech32Pattern);
if (bech32Match) { if (bech32Match) {
return `nostr:${bech32Match[0]}`; return `nostr:${bech32Match[0]}`;
} }
} }
// For non-Alexandria/localhost URLs, append (View here: nostr:<id>) if a Nostr identifier is present
const hexMatch = url.match(hexPattern);
if (hexMatch) {
try {
const nevent = nip19.neventEncode({ id: hexMatch[0] });
return `${url} (View here: nostr:${nevent})`;
} catch {
return url;
}
}
const bech32Match = url.match(bech32Pattern);
if (bech32Match) {
return `${url} (View here: nostr:${bech32Match[0]})`;
}
return url; return url;
}); });
@ -124,6 +131,25 @@ function stripTrackingParams(url: string): string {
} }
} }
function normalizeDTag(input: string): string {
return input
.toLowerCase()
.replace(/[^\p{L}\p{N}]/gu, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
}
function replaceWikilinks(text: string): string {
// [[target page]] or [[target page|display text]]
return text.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, (_match, target, label) => {
const normalized = normalizeDTag(target.trim());
const display = (label || target).trim();
const url = `https://next-alexandria.gitcitadel.eu/publication?d=${normalized}`;
// Output as a clickable <a> with the [[display]] format
return `<a class="wikilink" data-dtag="${normalized}" data-url="${url}" href="${url}">[[${display}]]</a>`;
});
}
function processBasicFormatting(content: string): string { function processBasicFormatting(content: string): string {
if (!content) return ''; if (!content) return '';
@ -292,6 +318,9 @@ export async function parseBasicMarkdown(text: string): Promise<string> {
// Process Nostr identifiers last // Process Nostr identifiers last
processedText = await processNostrIdentifiers(processedText); processedText = await processNostrIdentifiers(processedText);
// Replace wikilinks
processedText = replaceWikilinks(processedText);
return processedText; return processedText;
} catch (error) { } catch (error) {
console.error('Error in parseBasicMarkdown:', error); console.error('Error in parseBasicMarkdown:', error);

8
src/lib/utils/markdown/markdownTestfile.md

@ -14,6 +14,8 @@ It is _only_ a test, for __sure__. I just wanted to see if the markdown renders
This file is full of ~errors~ opportunities to ~~mess up the formatting~~ check your markdown parser. This file is full of ~errors~ opportunities to ~~mess up the formatting~~ check your markdown parser.
You can even learn about [[mirepoix]], [[nkbip-03]], or [[roman catholic church|catholics]]
npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z wrote this. That's the same person as this one with a nostr prefix nostr:npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z and nprofile1qydhwumn8ghj7argv4nx7un9wd6zumn0wd68yvfwvdhk6tcpr3mhxue69uhkx6rjd9ehgurfd3kzumn0wd68yvfwvdhk6tcqyr7jprhgeregx7q2j4fgjmjgy0xfm34l63pqvwyf2acsd9q0mynuzp4qva3. That is a different person from npub1s3ht77dq4zqnya8vjun5jp3p44pr794ru36d0ltxu65chljw8xjqd975wz. npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z wrote this. That's the same person as this one with a nostr prefix nostr:npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z and nprofile1qydhwumn8ghj7argv4nx7un9wd6zumn0wd68yvfwvdhk6tcpr3mhxue69uhkx6rjd9ehgurfd3kzumn0wd68yvfwvdhk6tcqyr7jprhgeregx7q2j4fgjmjgy0xfm34l63pqvwyf2acsd9q0mynuzp4qva3. That is a different person from npub1s3ht77dq4zqnya8vjun5jp3p44pr794ru36d0ltxu65chljw8xjqd975wz.
> This is important information > This is important information
@ -85,12 +87,14 @@ And a nonsense one with a prefix:
nostr:naddrwhatever nostr:naddrwhatever
And some Nostr addresses that should be ignored: And some Nostr addresses that should be preserved and have a internal link appended:
https://lumina.rocks/note/note1sd0hkhxr49jsetkcrjkvf2uls5m8frkue6f5huj8uv4964p2d8fs8dn68z https://lumina.rocks/note/note1sd0hkhxr49jsetkcrjkvf2uls5m8frkue6f5huj8uv4964p2d8fs8dn68z
https://primal.net/e/nevent1qqsqum7j25p9z8vcyn93dsd7edx34w07eqav50qnde3vrfs466q558gdd02yr https://primal.net/e/nevent1qqsqum7j25p9z8vcyn93dsd7edx34w07eqav50qnde3vrfs466q558gdd02yr
https://primal.net/p/nprofile1qqs06gywary09qmcp2249ztwfq3ue8wxhl2yyp3c39thzp55plvj0sgjn9mdk
URL with a tracking parameter, no Markdown: URL with a tracking parameter, no Markdown:
https://example.com?utm_source=newsletter1&utm_medium=email&utm_campaign=sale https://example.com?utm_source=newsletter1&utm_medium=email&utm_campaign=sale
@ -109,6 +113,8 @@ And within a Markdown tag: [Markdown link title](http://alexandria.gitcitadel.co
And to localhost: http://localhost:4173/publication?id=c36b54991e459221f444612d88ea94ef5bb4a1b93863ef89b1328996746f6d25 And to localhost: http://localhost:4173/publication?id=c36b54991e459221f444612d88ea94ef5bb4a1b93863ef89b1328996746f6d25
http://localhost:4173/profile?id=nprofile1qqs99d9qw67th0wr5xh05de4s9k0wjvnkxudkgptq8yg83vtulad30gxyk5sf
You can even include code inline, like `<div class="leather min-h-full w-full flex flex-col items-center">` or You can even include code inline, like `<div class="leather min-h-full w-full flex flex-col items-center">` or
``` ```

Loading…
Cancel
Save