From d4e48c6bb47c95b205cce8d839a2c3e42536e874 Mon Sep 17 00:00:00 2001 From: Aran Roig Date: Sat, 18 Jul 2026 15:36:28 +0200 Subject: [PATCH] djksdkj --- template/app/components/PageTree.vue | 2 +- template/app/pages/[...slug].vue | 1 + template/content/index.md | 4 +- template/convert.js | 78 ++++++++++++++++++++------- template/public/favicon.ico | Bin 4286 -> 15406 bytes 5 files changed, 63 insertions(+), 22 deletions(-) diff --git a/template/app/components/PageTree.vue b/template/app/components/PageTree.vue index 33ae740..9d82a2c 100644 --- a/template/app/components/PageTree.vue +++ b/template/app/components/PageTree.vue @@ -7,7 +7,7 @@ const { data: pages } = await useAsyncData('nav', () => diff --git a/template/app/pages/[...slug].vue b/template/app/pages/[...slug].vue index 99d36e2..18016f4 100644 --- a/template/app/pages/[...slug].vue +++ b/template/app/pages/[...slug].vue @@ -48,6 +48,7 @@ if (!page.value) { width: 100%; max-width: 800px; padding: 0 1rem; + margin-bottom: 300px; } .page-tree-sidebar { diff --git a/template/content/index.md b/template/content/index.md index 08a564b..6b3ccb0 100644 --- a/template/content/index.md +++ b/template/content/index.md @@ -6,4 +6,6 @@ visible: true Hola que tal! Hauria de funcionar -Test +Test + +Razas diff --git a/template/convert.js b/template/convert.js index 64c0985..1462cff 100644 --- a/template/convert.js +++ b/template/convert.js @@ -19,7 +19,9 @@ * * VISIBILITY GATE: * Only notes whose frontmatter contains `visible: true` are converted. - * Any note missing the field, or with `visible: false`, is silently skipped. + * Any note missing the field, or with `visible: false`, is skipped. + * Wiki links that point to a hidden (or missing) note are rendered as dead + * links: instead of a normal link. * * Usage: * node obsidian-to-nuxt.js --vault ./my-vault --out ./content --base-path /notes @@ -108,6 +110,11 @@ function collectMarkdownFiles(dir) { return results; } +/** + * Build a lookup map of stem/title/slug → URL for every **visible** note. + * Hidden notes (visible !== true) are intentionally excluded so that wiki + * links pointing at them resolve to nothing and are rendered as dead links. + */ function buildNoteIndex(files) { const candidates = new Map(); @@ -118,27 +125,31 @@ function buildNoteIndex(files) { } for (const file of files) { - const stem = path.basename(file, ".md"); - const rel = path.relative(VAULT_DIR, file).replace(/\.md$/, ""); - const url = BASE_PATH + "/" + rel.split(path.sep).map(slugify).join("/"); - const depth = rel.split(path.sep).length; const content = fs.readFileSync(file, "utf8"); + // Skip hidden notes — links to them must become dead links. + const { frontmatter, body } = parseFrontmatter(content); + if (!isVisible(frontmatter)) continue; + + const stem = path.basename(file, ".md"); + const rel = path.relative(VAULT_DIR, file).replace(/\.md$/, ""); + const url = BASE_PATH + "/" + rel.split(path.sep).map(slugify).join("/"); + const depth = rel.split(path.sep).length; + // Key 1: exact lowercase filename stem e.g. "note2" addCandidate(stem.toLowerCase(), url, depth); // Key 2: slugified filename stem e.g. "note-two" from "Note Two.md" addCandidate(slugify(stem), url, depth); - // Key 3: frontmatter title - const fmMatch = content.match(/^---[\s\S]*?^title:\s*(.+)/m); - if (fmMatch) { - const title = fmMatch[1].trim().replace(/^["']|["']$/g, ""); + // Key 3: frontmatter title (already parsed above — no second regex needed) + if (frontmatter.title) { + const title = String(frontmatter.title); addCandidate(title.toLowerCase(), url, depth); addCandidate(slugify(title), url, depth); } // Key 4: first H1 heading - const h1Match = content.match(/^#\s+(.+)/m); + const h1Match = body.match(/^#\s+(.+)/m); if (h1Match) { const h1 = h1Match[1].trim(); addCandidate(h1.toLowerCase(), url, depth); @@ -151,6 +162,24 @@ function buildNoteIndex(files) { return result; } +/** + * Collect the lowercase stems (and slugified stems) of every note that exists + * in the vault but is NOT visible. Used to distinguish "hidden" dead links + * from "truly missing" dead links when rendering wiki links. + */ +function buildHiddenStems(files) { + const hidden = new Set(); + for (const file of files) { + const content = fs.readFileSync(file, "utf8"); + const { frontmatter } = parseFrontmatter(content); + if (isVisible(frontmatter)) continue; + const stem = path.basename(file, ".md"); + hidden.add(stem.toLowerCase()); + hidden.add(slugify(stem)); + } + return hidden; +} + // ─── Frontmatter ───────────────────────────────────────────────────────────── const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/; @@ -299,7 +328,12 @@ function convertEmbeds(body, noteIndex) { // ─── Wiki links [[...]] ────────────────────────────────────────────────────── -function convertWikiLinks(body, noteIndex) { +/** + * @param {string} body + * @param {Map} noteIndex - visible notes only (stem/title → url) + * @param {Set} hiddenStems - stems of notes that exist but are not visible + */ +function convertWikiLinks(body, noteIndex, hiddenStems) { return body.replace(/\[\[([^\]]+?)\]\]/g, function(_, ref) { const pipeIdx = ref.indexOf("|"); let target, alias; @@ -334,7 +368,12 @@ function convertWikiLinks(body, noteIndex) { const label = alias || (anchor ? stem + " \u203a " + anchor : stem); if (dead) { - return '' + label + ''; + // Distinguish between a note that is hidden vs one that doesn't exist at all. + const isHidden = hiddenStems.has(stem.toLowerCase()) || hiddenStems.has(slugify(stem)); + const extraAttr = isHidden + ? ' data-hidden="' + stem + '"' + : ' data-missing="' + stem + '"'; + return '' + label + ''; } return "[" + label + "](" + url + ")"; }); @@ -342,7 +381,7 @@ function convertWikiLinks(body, noteIndex) { // ─── Convert one file ──────────────────────────────────────────────────────── -function convertFile(content, noteIndex, filename) { +function convertFile(content, noteIndex, hiddenStems, filename) { let { frontmatter, body } = parseFrontmatter(content); const inlineTags = extractInlineTags(body); @@ -358,16 +397,14 @@ function convertFile(content, noteIndex, filename) { body = convertCallouts(body); body = convertBlockIds(body); body = convertEmbeds(body, noteIndex); - body = convertWikiLinks(body, noteIndex); + body = convertWikiLinks(body, noteIndex, hiddenStems); // Prepend a title if the body doesn't already start with an H1 heading const trimmed = body.trimStart(); const hasTitle = /^#[^#]/.test(trimmed); if (!hasTitle) { const title = frontmatter.title || path.basename(filename, ".md"); - if (title != "index") { - body = "# " + title + "\n\n" + trimmed; - } + body = "# " + title + "\n\n" + trimmed; } const fmString = Object.keys(frontmatter).length @@ -385,8 +422,9 @@ function main() { process.exit(1); } - const files = collectMarkdownFiles(VAULT_DIR); - const noteIndex = buildNoteIndex(files); + const files = collectMarkdownFiles(VAULT_DIR); + const noteIndex = buildNoteIndex(files); + const hiddenStems = buildHiddenStems(files); console.log("Found " + files.length + " markdown file(s) in " + VAULT_DIR); @@ -416,7 +454,7 @@ function main() { let result; try { - result = convertFile(content, noteIndex, path.basename(file)); + result = convertFile(content, noteIndex, hiddenStems, path.basename(file)); } catch (err) { console.warn(" \u26A0 Skipping " + rel + ": " + err.message); skipCount++; diff --git a/template/public/favicon.ico b/template/public/favicon.ico index 18993ad91cfd43e03b074dd0b5cc3f37ab38e49c..f39f2db6f217a518a024f3f767b4e4b1bc086f3f 100644 GIT binary patch literal 15406 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 literal 4286 zcmeHLOKuuL5PjK%MHWVi6lD zOGiREbCw`xmFozJ^aNatJY>w+g ze6a2@u~m#^BZm@8wco9#Crlli0uLb^3E$t2-WIc^#(?t)*@`UpuofJ(Uyh@F>b3Ph z$D^m8Xq~pTkGJ4Q`Q2)te3mgkWYZ^Ijq|hkiP^9`De={bQQ%heZC$QU2UpP(-tbl8 zPWD2abEew;oat@w`uP3J^YpsgT%~jT(Dk%oU}sa$7|n6hBjDj`+I;RX(>)%lm_7N{+B7Mu%H?422lE%MBJH!!YTN2oT7xr>>N-8OF$C&qU^ z>vLsa{$0X%q1fjOe3P1mCv#lN{xQ4_*HCSAZjTb1`}mlc+9rl8$B3OP%VT@mch_~G z7Y+4b{r>9e=M+7vSI;BgB?ryZDY4m>&wcHSn81VH1N~`0gvwH{ z8dv#hG|OK`>1;j7tM#B)Z7zDN?{6=dUal}$e