djksdkj
This commit is contained in:
@@ -7,7 +7,7 @@ const { data: pages } = await useAsyncData('nav', () =>
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav>
|
<nav>
|
||||||
<h2>Notas</h2>
|
<h2>Índice</h2>
|
||||||
<TreeNode :nodes="pages" />
|
<TreeNode :nodes="pages" />
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ if (!page.value) {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
|
margin-bottom: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-tree-sidebar {
|
.page-tree-sidebar {
|
||||||
|
|||||||
@@ -7,3 +7,5 @@ visible: true
|
|||||||
Hola que tal! Hauria de funcionar
|
Hola que tal! Hauria de funcionar
|
||||||
|
|
||||||
Test
|
Test
|
||||||
|
|
||||||
|
<a href="/razas" class="dead-link" data-hidden="Razas">Razas</a>
|
||||||
|
|||||||
@@ -19,7 +19,9 @@
|
|||||||
*
|
*
|
||||||
* VISIBILITY GATE:
|
* VISIBILITY GATE:
|
||||||
* Only notes whose frontmatter contains `visible: true` are converted.
|
* 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: <a class="dead-link" data-missing="…"> instead of a normal link.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* node obsidian-to-nuxt.js --vault ./my-vault --out ./content --base-path /notes
|
* node obsidian-to-nuxt.js --vault ./my-vault --out ./content --base-path /notes
|
||||||
@@ -108,6 +110,11 @@ function collectMarkdownFiles(dir) {
|
|||||||
return results;
|
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) {
|
function buildNoteIndex(files) {
|
||||||
const candidates = new Map();
|
const candidates = new Map();
|
||||||
|
|
||||||
@@ -118,27 +125,31 @@ function buildNoteIndex(files) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
|
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 stem = path.basename(file, ".md");
|
||||||
const rel = path.relative(VAULT_DIR, file).replace(/\.md$/, "");
|
const rel = path.relative(VAULT_DIR, file).replace(/\.md$/, "");
|
||||||
const url = BASE_PATH + "/" + rel.split(path.sep).map(slugify).join("/");
|
const url = BASE_PATH + "/" + rel.split(path.sep).map(slugify).join("/");
|
||||||
const depth = rel.split(path.sep).length;
|
const depth = rel.split(path.sep).length;
|
||||||
const content = fs.readFileSync(file, "utf8");
|
|
||||||
|
|
||||||
// Key 1: exact lowercase filename stem e.g. "note2"
|
// Key 1: exact lowercase filename stem e.g. "note2"
|
||||||
addCandidate(stem.toLowerCase(), url, depth);
|
addCandidate(stem.toLowerCase(), url, depth);
|
||||||
// Key 2: slugified filename stem e.g. "note-two" from "Note Two.md"
|
// Key 2: slugified filename stem e.g. "note-two" from "Note Two.md"
|
||||||
addCandidate(slugify(stem), url, depth);
|
addCandidate(slugify(stem), url, depth);
|
||||||
|
|
||||||
// Key 3: frontmatter title
|
// Key 3: frontmatter title (already parsed above — no second regex needed)
|
||||||
const fmMatch = content.match(/^---[\s\S]*?^title:\s*(.+)/m);
|
if (frontmatter.title) {
|
||||||
if (fmMatch) {
|
const title = String(frontmatter.title);
|
||||||
const title = fmMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
||||||
addCandidate(title.toLowerCase(), url, depth);
|
addCandidate(title.toLowerCase(), url, depth);
|
||||||
addCandidate(slugify(title), url, depth);
|
addCandidate(slugify(title), url, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key 4: first H1 heading
|
// Key 4: first H1 heading
|
||||||
const h1Match = content.match(/^#\s+(.+)/m);
|
const h1Match = body.match(/^#\s+(.+)/m);
|
||||||
if (h1Match) {
|
if (h1Match) {
|
||||||
const h1 = h1Match[1].trim();
|
const h1 = h1Match[1].trim();
|
||||||
addCandidate(h1.toLowerCase(), url, depth);
|
addCandidate(h1.toLowerCase(), url, depth);
|
||||||
@@ -151,6 +162,24 @@ function buildNoteIndex(files) {
|
|||||||
return result;
|
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 ─────────────────────────────────────────────────────────────
|
// ─── Frontmatter ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
|
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
|
||||||
@@ -299,7 +328,12 @@ function convertEmbeds(body, noteIndex) {
|
|||||||
|
|
||||||
// ─── Wiki links [[...]] ──────────────────────────────────────────────────────
|
// ─── 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) {
|
return body.replace(/\[\[([^\]]+?)\]\]/g, function(_, ref) {
|
||||||
const pipeIdx = ref.indexOf("|");
|
const pipeIdx = ref.indexOf("|");
|
||||||
let target, alias;
|
let target, alias;
|
||||||
@@ -334,7 +368,12 @@ function convertWikiLinks(body, noteIndex) {
|
|||||||
const label = alias || (anchor ? stem + " \u203a " + anchor : stem);
|
const label = alias || (anchor ? stem + " \u203a " + anchor : stem);
|
||||||
|
|
||||||
if (dead) {
|
if (dead) {
|
||||||
return '<a href="' + url + '" class="dead-link" data-missing="' + stem + '">' + label + '</a>';
|
// 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 '<a href="' + url + '" class="dead-link"' + extraAttr + '>' + label + '</a>';
|
||||||
}
|
}
|
||||||
return "[" + label + "](" + url + ")";
|
return "[" + label + "](" + url + ")";
|
||||||
});
|
});
|
||||||
@@ -342,7 +381,7 @@ function convertWikiLinks(body, noteIndex) {
|
|||||||
|
|
||||||
// ─── Convert one file ────────────────────────────────────────────────────────
|
// ─── Convert one file ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function convertFile(content, noteIndex, filename) {
|
function convertFile(content, noteIndex, hiddenStems, filename) {
|
||||||
let { frontmatter, body } = parseFrontmatter(content);
|
let { frontmatter, body } = parseFrontmatter(content);
|
||||||
|
|
||||||
const inlineTags = extractInlineTags(body);
|
const inlineTags = extractInlineTags(body);
|
||||||
@@ -358,17 +397,15 @@ function convertFile(content, noteIndex, filename) {
|
|||||||
body = convertCallouts(body);
|
body = convertCallouts(body);
|
||||||
body = convertBlockIds(body);
|
body = convertBlockIds(body);
|
||||||
body = convertEmbeds(body, noteIndex);
|
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
|
// Prepend a title if the body doesn't already start with an H1 heading
|
||||||
const trimmed = body.trimStart();
|
const trimmed = body.trimStart();
|
||||||
const hasTitle = /^#[^#]/.test(trimmed);
|
const hasTitle = /^#[^#]/.test(trimmed);
|
||||||
if (!hasTitle) {
|
if (!hasTitle) {
|
||||||
const title = frontmatter.title || path.basename(filename, ".md");
|
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
|
const fmString = Object.keys(frontmatter).length
|
||||||
? serializeFrontmatter(frontmatter) + "\n\n"
|
? serializeFrontmatter(frontmatter) + "\n\n"
|
||||||
@@ -387,6 +424,7 @@ function main() {
|
|||||||
|
|
||||||
const files = collectMarkdownFiles(VAULT_DIR);
|
const files = collectMarkdownFiles(VAULT_DIR);
|
||||||
const noteIndex = buildNoteIndex(files);
|
const noteIndex = buildNoteIndex(files);
|
||||||
|
const hiddenStems = buildHiddenStems(files);
|
||||||
|
|
||||||
console.log("Found " + files.length + " markdown file(s) in " + VAULT_DIR);
|
console.log("Found " + files.length + " markdown file(s) in " + VAULT_DIR);
|
||||||
|
|
||||||
@@ -416,7 +454,7 @@ function main() {
|
|||||||
|
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
result = convertFile(content, noteIndex, path.basename(file));
|
result = convertFile(content, noteIndex, hiddenStems, path.basename(file));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(" \u26A0 Skipping " + rel + ": " + err.message);
|
console.warn(" \u26A0 Skipping " + rel + ": " + err.message);
|
||||||
skipCount++;
|
skipCount++;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user