This commit is contained in:
2026-07-18 01:32:38 +02:00
parent 270b292f6d
commit fcd25d4239
32 changed files with 865 additions and 236 deletions

3
template/.gitignore vendored
View File

@@ -23,4 +23,5 @@ logs
.env.* .env.*
!.env.example !.env.example
content content
vault

View File

@@ -1,66 +1,68 @@
/* ── Light Theme (Default) ────────────────────────────────── */ /* ── Light Theme (Default) ────────────────────────────────── */
:root { :root {
--bg-body: #faf6f0; --bg-body: #f4f1ee;
--bg-elevated: #fffdf8; --bg-elevated: #faf8f5;
--text-primary: #2d2418; --bg-sidebar: #f4f1ee;
--text-heading: #1a1408; --text-primary: #1e1a2e;
--text-secondary: #5c4a37; --text-heading: #0f0c1a;
--text-muted: #7a6b56; --text-secondary: #3d3457;
--border-light: #f0e5d7; --text-muted: #6b5f82;
--border-medium: #e8dbcc; --border-light: #e2dde8;
--border-accent: #d4c4b0; --border-medium: #cec6d8;
--link-color: #b45309; --border-accent: #b8aac8;
--link-hover: #92400e; --link-color: #9b2335;
--link-border: rgba(180, 83, 9, 0.25); --link-hover: #6e1522;
--link-border-hover: rgba(180, 83, 9, 0.6); --link-border: rgba(155, 35, 53, 0.25);
--strong-color: #1a1408; --link-border-hover: rgba(155, 35, 53, 0.6);
--marker-color: #5c4a37; --strong-color: #0f0c1a;
--blockquote-bg: #fdf9f3; --marker-color: #6b3d7a;
--blockquote-border: #d4c4b0; --blockquote-bg: #f7f4f9;
--blockquote-text: #5c4a37; --blockquote-border: #9b2335;
--code-inline-bg: #fef3e2; --blockquote-text: #3d3457;
--code-inline-color: #9a4710; --code-inline-bg: #f0ebf5;
--code-block-bg: #1f1910; --code-inline-color: #7c2d8c;
--code-block-color: #e8dbcc; --code-block-bg: #12101e;
--table-border: #e8dbcc; --code-block-color: #d4ccdf;
--table-header-bg: #fdf9f3; --table-border: #cec6d8;
--table-header-text: #4a3b2c; --table-header-bg: #f0ecf5;
--table-row-border: #f5efe6; --table-header-text: #2a2040;
--table-cell-text: #5c4a37; --table-row-border: #e8e3ef;
--hr-color: #e8dbcc; --table-cell-text: #3d3457;
--hr-color: #c8b850;
} }
/* ── Dark Theme ───────────────────────────────────────────── */ /* ── Dark Theme ───────────────────────────────────────────── */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--bg-body: #17120c; --bg-body: #0e0c18;
--bg-elevated: #1f1810; --bg-elevated: #15121f;
--text-primary: #d4c4b0; --bg-sidebar: #0d0d0f;
--text-heading: #e8dbcc; --text-primary: #cfc8dc;
--text-secondary: #a89580; --text-heading: #e4dff0;
--text-muted: #7a6b56; --text-secondary: #9d93b5;
--border-light: #2e2419; --text-muted: #6b5f82;
--border-medium: #3d3125; --border-light: #201c30;
--border-accent: #4f4030; --border-medium: #2e2844;
--link-color: #fb923c; --border-accent: #3d3557;
--link-hover: #fdba74; --link-color: #e05567;
--link-border: rgba(251, 146, 60, 0.3); --link-hover: #f07d8a;
--link-border-hover: rgba(251, 146, 60, 0.6); --link-border: rgba(224, 85, 103, 0.3);
--strong-color: #e8dbcc; --link-border-hover: rgba(224, 85, 103, 0.6);
--marker-color: #a89580; --strong-color: #e4dff0;
--blockquote-bg: #1f1810; --marker-color: #a07ab5;
--blockquote-border: #4f4030; --blockquote-bg: #15121f;
--blockquote-text: #a89580; --blockquote-border: #c0293d;
--code-inline-bg: #2a2015; --blockquote-text: #9d93b5;
--code-inline-color: #fb923c; --code-inline-bg: #1f1930;
--code-block-bg: #0e0a06; --code-inline-color: #c084d8;
--code-block-color: #d4c4b0; --code-block-bg: #080710;
--table-border: #3d3125; --code-block-color: #cfc8dc;
--table-header-bg: #1f1810; --table-border: #2e2844;
--table-header-text: #cbd5c4; --table-header-bg: #15121f;
--table-row-border: #2e2419; --table-header-text: #c8c0d8;
--table-cell-text: #a89580; --table-row-border: #201c30;
--hr-color: #3d3125; --table-cell-text: #9d93b5;
--hr-color: #8c7a20;
} }
} }
@@ -78,11 +80,26 @@ html {
tab-size: 4; tab-size: 4;
} }
@font-face {
font-family: "Bookinsanity";
src: url("/fonts/Bookinsanity.otf") format("opentype");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Nodesto Caps Condensed";
src: url("/fonts/Nodesto Caps Condensed.otf") format("opentype");
font-weight: normal;
}
body { body {
margin: 0 auto; margin: 0 auto;
padding: 0; padding: 0;
line-height: 1.7; line-height: 1.7;
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-family: "Bookinsanity", system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
color: var(--text-primary); color: var(--text-primary);
background-color: var(--bg-body); background-color: var(--bg-body);
word-break: break-word; word-break: break-word;
@@ -102,24 +119,25 @@ body {
/* ── Typography ───────────────────────────────────────────── */ /* ── Typography ───────────────────────────────────────────── */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
margin-top: 2em; margin-top: 60px;
margin-bottom: 0.6em; margin-bottom: 0.6em;
line-height: 1.3; line-height: 1.3;
color: var(--text-heading); color: var(--text-heading);
font-weight: 700; font-weight: 700;
font-family: "Nodesto Caps Condensed", system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
} }
h1 { h1 {
font-size: 2.25rem; font-size: 2.25rem;
padding-bottom: 0.5em; padding-bottom: 0.5em;
border-bottom: 2px solid var(--border-medium); border-bottom: 2px solid var(--hr-color);
letter-spacing: -0.02em; letter-spacing: -0.02em;
} }
h2 { h2 {
font-size: 1.75rem; font-size: 1.75rem;
padding-bottom: 0.35em; padding-bottom: 0.35em;
border-bottom: 1px solid var(--border-light); border-bottom: 1px solid var(--border-medium);
} }
h3 { h3 {
@@ -150,11 +168,21 @@ a {
text-decoration: none; text-decoration: none;
border-bottom: 1px solid var(--link-border); border-bottom: 1px solid var(--link-border);
transition: color 0.2s, border-color 0.2s; transition: color 0.2s, border-color 0.2s;
&.dead-link {
color: var(--text-muted);
border-bottom-color: var(--border-light);
pointer-events: none;
}
} }
a:hover { a:hover {
color: var(--link-hover); color: var(--link-hover);
border-bottom-color: var(--link-border-hover); border-bottom-color: var(--link-border-hover);
&.dead-link {
color: var(--text-muted);
border-bottom-color: var(--border-light);
}
} }
/* ── Emphasis & Strong ────────────────────────────────────── */ /* ── Emphasis & Strong ────────────────────────────────────── */
@@ -265,11 +293,11 @@ hr {
/* ── Images ───────────────────────────────────────────────── */ /* ── Images ───────────────────────────────────────────────── */
img { img {
max-width: 100%; max-width: 600px;
height: auto; height: auto;
border-radius: 8px; border-radius: 8px;
display: block; display: block;
margin: 0.5em 0; margin: 0.5em auto;
} }
/* ── Forms ────────────────────────────────────────────────── */ /* ── Forms ────────────────────────────────────────────────── */
@@ -302,4 +330,4 @@ textarea {
h3 { h3 {
font-size: 1.2rem; font-size: 1.2rem;
} }
} }

View File

@@ -0,0 +1,21 @@
<!-- components/PageTree.vue -->
<script setup>
const { data: pages } = await useAsyncData('nav', () =>
queryCollectionNavigation('content')
)
</script>
<template>
<nav>
<h2>Notes</h2>
<TreeNode :nodes="pages" />
</nav>
</template>
<style lang="scss" scoped>
nav {
padding: 40px;
box-shadow: var(--shadow-elevation-medium);
background-color: var(--bg-sidebar);
}
</style>

View File

@@ -0,0 +1,51 @@
<!-- components/TreeNode.vue -->
<script setup>
defineProps({ nodes: Array, depth: { type: Number, default: 0 } })
const router = useRouter()
function getTitle(node) {
if (node.title == "index") return "Index"
return node.title || node._path?.split('/').pop() || 'Home';
}
function navigate(path) {
if (!path) return
router.push(path)
}
</script>
<template>
<ul :style="{ paddingLeft: depth ? '1rem' : '0' }">
<li v-for="node in nodes" :key="node.path ?? node.title">
<template v-if="!node.children?.length">
<a v-if="node.path" :href="node.path" @click.prevent="navigate(node.path)">
{{ getTitle(node) }}
</a>
<span v-else>{{ getTitle(node) }}</span>
</template>
<template v-else>
<span>📁 {{ getTitle(node) }}</span>
<TreeNode :nodes="node.children" :depth="depth + 1" />
</template>
</li>
</ul>
</template>
<style lang="scss" scoped>
ul {
list-style: none;
padding-left: 0;
}
li {
margin-bottom: 0;
}
a {
color: var(--text-link);
}
</style>

View File

@@ -11,8 +11,56 @@ if (!page.value) {
</script> </script>
<template> <template>
<div class="prose-wrapper" v-if="page"> <div v-if="page" class="page-layout">
<ContentRenderer :value="page" />
<aside class="page-tree-sidebar">
<PageTree />
</aside>
<div class="docs-container">
<div class="docs-layout">
<ContentRenderer :value="page" />
</div>
</div>
</div> </div>
<NotFound /> <NotFound v-if="!page" />
</template> </template>
<style lang="scss">
.page-layout {
display: grid;
grid-template-columns: minmax(0, 400px) minmax(0, 1fr);
justify-content: left;
column-gap: 2rem;
}
.docs-container {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.docs-layout {
h1:first-of-type {
margin-top: 80px;
}
width: 100%;
max-width: 800px;
padding: 0 1rem;
}
.page-tree-sidebar {
position: sticky;
top: 0;
height: 100vh;
overflow-y: auto;
/* Firefox */
scrollbar-width: none;
/* IE and old Edge */
-ms-overflow-style: none;
background-color: var(--bg-sidebar);
}
</style>

View File

@@ -1,3 +0,0 @@
# About Content Version 3
[Back home](/)

View File

@@ -1 +1,5 @@
Hola que tal! # index
Hola que tal! Hauria de funcionar
Test

View File

@@ -8,7 +8,7 @@
* Transformations applied: * Transformations applied:
* 1. [[Wiki links]] → [Wiki links](/slug) * 1. [[Wiki links]] → [Wiki links](/slug)
* 2. [[Wiki links|Alias]] → [Alias](/slug) * 2. [[Wiki links|Alias]] → [Alias](/slug)
* 3. ![[image.png]] → <img> / NuxtImg tag * 3. ![[image.png]] → <img> / <NuxtImg> tag
* 4. ![[note]] → MDC ::include component * 4. ![[note]] → MDC ::include component
* 5. Callouts > [!TYPE] Title → MDC ::callout{type} blocks * 5. Callouts > [!TYPE] Title → MDC ::callout{type} blocks
* 6. Block IDs ^block-id → <span id="block-id"> anchors * 6. Block IDs ^block-id → <span id="block-id"> anchors
@@ -21,43 +21,61 @@
* 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
* *
* Options: * Options:
* --vault Path to Obsidian vault root (default: ./vault) * --vault Path to Obsidian vault root (default: ./vault)
* --out Output directory for converted files (default: ./content) * --out Output directory for converted files (default: ./content)
* --base-path URL prefix for all generated links (default: "") * --base-path URL prefix for all generated links (default: "")
* --img-prefix URL prefix for embedded images (default: /images) * --img-prefix URL prefix for embedded images (default: /images)
* --nuxt-img Use <NuxtImg> instead of <img> (flag) * --nuxt-img Use <NuxtImg> instead of <img> (flag)
* --dry-run Print conversions without writing files (flag) * --dry-run Print conversions without writing files (flag)
*/ */
import fs from "fs";
import fs from "fs";
import path from "path"; import path from "path";
import { parseArgs } from "util";
// ─── CLI args ──────────────────────────────────────────────────────────────── // ─── CLI args (manual parser, no dependencies) ───────────────────────────────
const { values: args } = parseArgs({ function parseArgs() {
options: { const argv = process.argv.slice(2);
vault: { type: "string", default: "./vault" }, const args = {
out: { type: "string", default: "./content" }, vault: "./vault",
"base-path":{ type: "string", default: "" }, out: "./content",
"img-prefix":{ type: "string", default: "/images" }, "base-path": "",
"nuxt-img": { type: "boolean", default: false }, "img-prefix": "/images",
"dry-run": { type: "boolean", default: false }, "nuxt-img": false,
}, "dry-run": false,
}); };
const VAULT_DIR = path.resolve(args["vault"]); for (let i = 0; i < argv.length; i++) {
const OUT_DIR = path.resolve(args["out"]); const key = argv[i].replace(/^--/, "");
const BASE_PATH = args["base-path"].replace(/\/$/, ""); if (argv[i].startsWith("--")) {
const IMG_PREFIX = args["img-prefix"].replace(/\/$/, ""); const next = argv[i + 1];
const USE_NUXT_IMG = args["nuxt-img"]; if (!next || next.startsWith("--")) {
const DRY_RUN = args["dry-run"]; // boolean flag
args[key] = true;
} else {
args[key] = next;
i++;
}
}
}
return args;
}
const args = parseArgs();
const VAULT_DIR = path.resolve(args["vault"]);
const OUT_DIR = path.resolve(args["out"]);
const BASE_PATH = (args["base-path"] || "").replace(/\/$/, "");
const IMG_PREFIX = (args["img-prefix"] || "/images").replace(/\/$/, "");
const USE_NUXT_IMG = args["nuxt-img"] === true || args["nuxt-img"] === "true";
const DRY_RUN = args["dry-run"] === true || args["dry-run"] === "true";
const IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".avif"]); const IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".avif"]);
// ─── Utilities ─────────────────────────────────────────────────────────────── // ─── Utilities ───────────────────────────────────────────────────────────────
/** Turn a note name / file stem into a URL-safe slug */
function slugify(name) { function slugify(name) {
return name return name
.toLowerCase() .toLowerCase()
@@ -66,7 +84,6 @@ function slugify(name) {
.replace(/--+/g, "-"); .replace(/--+/g, "-");
} }
/** Turn a heading string into a GitHub-style anchor slug */
function headingSlug(heading) { function headingSlug(heading) {
return heading return heading
.toLowerCase() .toLowerCase()
@@ -74,7 +91,6 @@ function headingSlug(heading) {
.replace(/[^\w\-]/g, ""); .replace(/[^\w\-]/g, "");
} }
/** Recursively collect all .md files in a directory */
function collectMarkdownFiles(dir) { function collectMarkdownFiles(dir) {
const results = []; const results = [];
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
@@ -88,25 +104,50 @@ function collectMarkdownFiles(dir) {
return results; return results;
} }
/**
* Build a lookup map: note stem (lowercase) → relative URL path
* Handles duplicate names by preferring the shortest path (vault-root wins).
*/
function buildNoteIndex(files) { function buildNoteIndex(files) {
const index = new Map(); const candidates = new Map();
for (const file of files) {
const stem = path.basename(file, ".md"); function addCandidate(key, url, depth) {
const rel = path.relative(VAULT_DIR, file).replace(/\.md$/, ""); if (key && (!candidates.has(key) || depth < candidates.get(key).depth)) {
const url = BASE_PATH + "/" + rel.split(path.sep).map(slugify).join("/"); candidates.set(key, { url, depth });
const key = stem.toLowerCase();
if (!index.has(key) || rel.split(path.sep).length < index.get(key).depth) {
index.set(key, { url, depth: rel.split(path.sep).length });
} }
} }
return new Map([...index.entries()].map(([k, v]) => [k, v.url]));
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");
// 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, "");
addCandidate(title.toLowerCase(), url, depth);
addCandidate(slugify(title), url, depth);
}
// Key 4: first H1 heading
const h1Match = content.match(/^#\s+(.+)/m);
if (h1Match) {
const h1 = h1Match[1].trim();
addCandidate(h1.toLowerCase(), url, depth);
addCandidate(slugify(h1), url, depth);
}
}
const result = new Map();
for (const [k, v] of candidates.entries()) result.set(k, v.url);
return result;
} }
// ─── Frontmatter helpers ───────────────────────────────────────────────────── // ─── Frontmatter ─────────────────────────────────────────────────────────────
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/; const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
@@ -114,16 +155,15 @@ function parseFrontmatter(content) {
const match = content.match(FRONTMATTER_RE); const match = content.match(FRONTMATTER_RE);
if (!match) return { frontmatter: {}, body: content }; if (!match) return { frontmatter: {}, body: content };
const raw = match[1]; const raw = match[1];
const body = content.slice(match[0].length); const body = content.slice(match[0].length);
const fm = {};
// Minimal YAML parser (handles string scalars and simple arrays)
const fm = {};
let currentKey = null; let currentKey = null;
for (const line of raw.split("\n")) { for (const line of raw.split("\n")) {
const listItem = line.match(/^\s+-\s+(.+)/); const listItem = line.match(/^\s+-\s+(.+)/);
if (listItem && currentKey) { if (listItem && currentKey) {
fm[currentKey] = Array.isArray(fm[currentKey]) ? fm[currentKey] : []; if (!Array.isArray(fm[currentKey])) fm[currentKey] = [];
fm[currentKey].push(listItem[1].trim()); fm[currentKey].push(listItem[1].trim());
continue; continue;
} }
@@ -141,58 +181,45 @@ function serializeFrontmatter(fm) {
const lines = ["---"]; const lines = ["---"];
for (const [key, val] of Object.entries(fm)) { for (const [key, val] of Object.entries(fm)) {
if (Array.isArray(val)) { if (Array.isArray(val)) {
lines.push(`${key}:`); lines.push(key + ":");
for (const v of val) lines.push(` - ${v}`); for (const v of val) lines.push(" - " + v);
} else { } else {
lines.push(`${key}: ${val}`); lines.push(key + ": " + val);
} }
} }
lines.push("---"); lines.push("---");
return lines.join("\n"); return lines.join("\n");
} }
// ─── Inline-tag extractor ──────────────────────────────────────────────────── // ─── Inline tags ─────────────────────────────────────────────────────────────
/** Pull #tags from body text (skip # inside code fences or headings) */
function extractInlineTags(body) { function extractInlineTags(body) {
const tags = new Set(); const tags = new Set();
// Skip fenced code blocks
const stripped = body.replace(/```[\s\S]*?```/g, ""); const stripped = body.replace(/```[\s\S]*?```/g, "");
const tagRe = /(?<![#\w])#([a-zA-Z][a-zA-Z0-9_/-]*)/g; const tagRe = /(?<![#\w])#([a-zA-Z][a-zA-Z0-9_/-]*)/g;
for (const m of stripped.matchAll(tagRe)) { let m;
tags.add(m[1]); while ((m = tagRe.exec(stripped)) !== null) tags.add(m[1]);
}
return [...tags]; return [...tags];
} }
/** Remove inline #tags from body (but not ATX headings) */
function stripInlineTags(body) { function stripInlineTags(body) {
return body.replace(/(?<![#\w])#([a-zA-Z][a-zA-Z0-9_/-]*)/g, "").replace(/ {2,}/g, " "); return body
.replace(/(?<![#\w])#([a-zA-Z][a-zA-Z0-9_/-]*)/g, "")
.replace(/ {2,}/g, " ");
} }
// ─── Block IDs ─────────────────────────────────────────────────────────────── // ─── Block IDs ───────────────────────────────────────────────────────────────
/**
* Replace trailing `^block-id` markers with an HTML anchor span.
* Obsidian places them at the end of a paragraph line.
*/
function convertBlockIds(body) { function convertBlockIds(body) {
return body.replace(/\s+\^([a-zA-Z0-9-]+)\s*$/gm, (_, id) => { return body.replace(/[ \t]+\^([a-zA-Z0-9-]+)\s*$/gm, function(_, id) {
return ` <span id="${id}"></span>`; return ' <span id="' + id + '"></span>';
}); });
} }
// ─── Callouts ──────────────────────────────────────────────────────────────── // ─── Callouts ────────────────────────────────────────────────────────────────
const CALLOUT_START_RE = /^> \[!([A-Z]+)\]([+-]?)\s*(.*)/i; const CALLOUT_START_RE = /^> \[!([A-Za-z]+)\][+-]?\s*(.*)/;
/**
* Convert Obsidian callout blocks to MDC (Nuxt Content) component syntax:
*
* > [!NOTE] Title ::callout{type="note" title="Title"}
* > content content
* ::
*/
function convertCallouts(body) { function convertCallouts(body) {
const lines = body.split("\n"); const lines = body.split("\n");
const out = []; const out = [];
@@ -200,122 +227,132 @@ function convertCallouts(body) {
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
if (!inCallout) { if (!inCallout) {
const m = line.match(CALLOUT_START_RE); const m = line.match(CALLOUT_START_RE);
if (m) { if (m) {
const type = m[1].toLowerCase(); const type = m[1].toLowerCase();
const title = m[3].trim(); const title = m[2].trim();
const titleAttr = title ? ` title="${title}"` : ""; const titleAttr = title ? ' title="' + title + '"' : "";
out.push(`::callout{type="${type}"${titleAttr}}`); out.push('::callout{type="' + type + '"' + titleAttr + "}");
inCallout = true; inCallout = true;
continue;
}
out.push(line);
} else {
// Continuation lines start with "> " or are blank (closing the block)
if (line.startsWith("> ")) {
out.push(line.slice(2)); // strip "> "
} else { } else {
out.push("::"); // close MDC block out.push(line);
}
} else {
if (line.startsWith("> ")) {
out.push(line.slice(2));
} else {
out.push("::");
out.push(line); out.push(line);
inCallout = false; inCallout = false;
} }
} }
} }
if (inCallout) out.push("::"); if (inCallout) out.push("::");
return out.join("\n"); return out.join("\n");
} }
// ─── Embedded content ![[...]] ────────────────────────────────────────────── // ─── Embeds ![[...]] ─────────────────────────────────────────────────────────
function convertEmbeds(body, noteIndex) { function convertEmbeds(body, noteIndex) {
return body.replace(/!\[\[([^\]]+?)\]\]/g, (_, ref) => { return body.replace(/!\[\[([^\]]+?)\]\]/g, function(_, ref) {
const [rawName, size] = ref.split("|"); const parts = ref.split("|");
const name = rawName.trim(); const name = parts[0].trim();
const ext = path.extname(name).toLowerCase(); const size = parts[1] ? parts[1].trim() : null;
const ext = path.extname(name).toLowerCase();
if (IMAGE_EXTS.has(ext)) { if (IMAGE_EXTS.has(ext)) {
// Image embed const src = IMG_PREFIX + "/" + name;
const src = `${IMG_PREFIX}/${name}`; const altStr = path.basename(name, ext);
const attrs = size ? ` width="${size.split("x")[0]}"` : ""; const wAttr = size ? ' width="' + size.split("x")[0] + '"' : "";
if (USE_NUXT_IMG) { if (USE_NUXT_IMG) {
return `<NuxtImg src="${src}"${attrs} alt="${path.basename(name, ext)}" />`; return '<NuxtImg src="' + src + '"' + wAttr + ' alt="' + altStr + '" />';
} }
return `<img src="${src}"${attrs} alt="${path.basename(name, ext)}" />`; return '<img src="' + src + '"' + wAttr + ' alt="' + altStr + '" />';
} }
if (ext === ".mp4" || ext === ".webm") { if (ext === ".mp4" || ext === ".webm") {
const src = `${IMG_PREFIX}/${name}`; return '<video src="' + IMG_PREFIX + "/" + name + '" controls></video>';
return `<video src="${src}" controls></video>`;
} }
// Note embed → MDC include component // Note embed
const stem = path.basename(name, ext || ".md"); const stem = path.basename(name, ext || ".md");
const slug = noteIndex.get(stem.toLowerCase()) ?? `${BASE_PATH}/${slugify(stem)}`; const slug = noteIndex.get(stem.toLowerCase()) || (BASE_PATH + "/" + slugify(stem));
return `::include{path="${slug}"}`; return '::include{path="' + slug + '"}';
}); });
} }
// ─── Wiki links [[...]] ───────────────────────────────────────────────────── // ─── Wiki links [[...]] ─────────────────────────────────────────────────────
function convertWikiLinks(body, noteIndex) { function convertWikiLinks(body, noteIndex) {
return body.replace(/\[\[([^\]]+?)\]\]/g, (_, ref) => { return body.replace(/\[\[([^\]]+?)\]\]/g, function(_, ref) {
// Split off alias: [[Note|Alias]] const pipeIdx = ref.indexOf("|");
const [target, alias] = ref.split("|").map(s => s.trim()); let target, alias;
if (pipeIdx !== -1) {
target = ref.slice(0, pipeIdx).trim();
alias = ref.slice(pipeIdx + 1).trim();
} else {
target = ref.trim();
alias = null;
}
// Split off heading or block ref: [[Note#Heading]] [[Note#^block]] const hashIdx = target.indexOf("#");
const [notePart, anchor] = target.split("#").map(s => s.trim()); let notePart, anchor;
if (hashIdx !== -1) {
notePart = target.slice(0, hashIdx).trim();
anchor = target.slice(hashIdx + 1).trim();
} else {
notePart = target;
anchor = null;
}
const stem = path.basename(notePart, ".md"); const stem = path.basename(notePart, ".md");
const baseUrl = noteIndex.get(stem.toLowerCase()) ?? `${BASE_PATH}/${slugify(stem)}`; const resolved = noteIndex.get(stem.toLowerCase()) || noteIndex.get(slugify(stem));
const dead = !resolved;
const baseUrl = resolved || (BASE_PATH + "/" + slugify(stem));
let url = baseUrl; let url = baseUrl;
if (anchor) { if (anchor) {
if (anchor.startsWith("^")) { url += "#" + (anchor.startsWith("^") ? anchor.slice(1) : headingSlug(anchor));
// Block reference
url += "#" + anchor.slice(1);
} else {
// Heading reference
url += "#" + headingSlug(anchor);
}
} }
const label = alias || (anchor ? `${stem} ${anchor}` : stem); const label = alias || (anchor ? stem + " \u203a " + anchor : stem);
return `[${label}](${url})`;
if (dead) {
return '<a href="' + url + '" class="dead-link" data-missing="' + stem + '">' + label + '</a>';
}
return "[" + label + "](" + url + ")";
}); });
} }
// ─── Main conversion ────────────────────────────────────────────────────────── // ─── Convert one file ────────────────────────────────────────────────────────
function convertFile(content, noteIndex) { function convertFile(content, noteIndex, filename) {
let { frontmatter, body } = parseFrontmatter(content); let { frontmatter, body } = parseFrontmatter(content);
// 1. Extract and merge inline tags into frontmatter
const inlineTags = extractInlineTags(body); const inlineTags = extractInlineTags(body);
if (inlineTags.length) { if (inlineTags.length) {
const existing = Array.isArray(frontmatter.tags) const existing = Array.isArray(frontmatter.tags)
? frontmatter.tags ? frontmatter.tags
: frontmatter.tags : frontmatter.tags ? [frontmatter.tags] : [];
? [frontmatter.tags] const merged = Array.from(new Set(existing.concat(inlineTags)));
: []; frontmatter.tags = merged;
frontmatter.tags = [...new Set([...existing, ...inlineTags])];
body = stripInlineTags(body); body = stripInlineTags(body);
} }
// 2. Callout blocks (before wiki-link pass so "> [[link]]" still works)
body = convertCallouts(body); body = convertCallouts(body);
// 3. Block IDs
body = convertBlockIds(body); body = convertBlockIds(body);
// 4. Embedded files ![[...]]
body = convertEmbeds(body, noteIndex); body = convertEmbeds(body, noteIndex);
// 5. Wiki links [[...]]
body = convertWikiLinks(body, noteIndex); body = convertWikiLinks(body, noteIndex);
// 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");
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"
: ""; : "";
@@ -323,54 +360,55 @@ function convertFile(content, noteIndex) {
return fmString + body.trim() + "\n"; return fmString + body.trim() + "\n";
} }
// ─── Entry point ────────────────────────────────────────────────────────────── // ─── Main ────────────────────────────────────────────────────────────────────
function main() { function main() {
if (!fs.existsSync(VAULT_DIR)) { if (!fs.existsSync(VAULT_DIR)) {
console.error(`Vault directory not found: ${VAULT_DIR}`); console.error("Vault directory not found: " + VAULT_DIR);
process.exit(1); process.exit(1);
} }
const files = collectMarkdownFiles(VAULT_DIR); const files = collectMarkdownFiles(VAULT_DIR);
const noteIndex = buildNoteIndex(files); const noteIndex = buildNoteIndex(files);
console.log(`Found ${files.length} markdown files in ${VAULT_DIR}`); console.log("Found " + files.length + " markdown file(s) in " + VAULT_DIR);
let converted = 0, skipped = 0; let doneCount = 0, skipCount = 0;
for (const file of files) { for (const file of files) {
const rel = path.relative(VAULT_DIR, file); const rel = path.relative(VAULT_DIR, file);
const outPath = path.join( const outPath = path.join(
OUT_DIR, OUT_DIR,
rel rel.split(path.sep)
.split(path.sep) .map(function(seg, i, arr) { return i === arr.length - 1 ? seg : slugify(seg); })
.map((seg, i, arr) => i === arr.length - 1 ? seg : slugify(seg))
.join(path.sep) .join(path.sep)
); );
const content = fs.readFileSync(file, "utf8"); const content = fs.readFileSync(file, "utf8");
let converted_content; let result;
try { try {
converted_content = convertFile(content, noteIndex); result = convertFile(content, noteIndex, path.basename(file));
} catch (err) { } catch (err) {
console.warn(` Skipping ${rel}: ${err.message}`); console.warn(" \u26A0 Skipping " + rel + ": " + err.message);
skipped++; skipCount++;
continue; continue;
} }
if (DRY_RUN) { if (DRY_RUN) {
console.log(`\n${"─".repeat(60)}\n[DRY-RUN] ${rel}${path.relative(process.cwd(), outPath)}\n`); console.log("\n" + "─".repeat(60));
console.log(converted_content.slice(0, 500) + (converted_content.length > 500 ? "\n…" : "")); console.log("[DRY-RUN] " + rel + " \u2192 " + path.relative(process.cwd(), outPath));
console.log("");
console.log(result.slice(0, 800) + (result.length > 800 ? "\n\u2026" : ""));
} else { } else {
fs.mkdirSync(path.dirname(outPath), { recursive: true }); fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, converted_content, "utf8"); fs.writeFileSync(outPath, result, "utf8");
console.log(`${rel}${path.relative(process.cwd(), outPath)}`); console.log(" \u2713 " + rel + " \u2192 " + path.relative(process.cwd(), outPath));
} }
converted++; doneCount++;
} }
console.log(`\nDone. ${converted} file(s) converted, ${skipped} skipped.`); console.log("\nDone. " + doneCount + " file(s) converted, " + skipCount + " skipped.");
} }
main(); main();

View File

@@ -12,6 +12,9 @@
"nuxt": "^4.4.8", "nuxt": "^4.4.8",
"vue": "^3.5.35", "vue": "^3.5.35",
"vue-router": "^5.1.0" "vue-router": "^5.1.0"
},
"devDependencies": {
"sass-embedded": "^1.100.0"
} }
}, },
"node_modules/@apidevtools/json-schema-ref-parser": { "node_modules/@apidevtools/json-schema-ref-parser": {
@@ -454,6 +457,13 @@
} }
} }
}, },
"node_modules/@bufbuild/protobuf": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.1.tgz",
"integrity": "sha512-BvAMfS6LrgZiryOAZ4pBYucu4wG/Ei/9o9DZ9akbREnMLbPJiom2i8b9C8IsKErQoiKqVhrerzt3kOT/RrzLHg==",
"devOptional": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@clack/core": { "node_modules/@clack/core": {
"version": "1.4.3", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz",
@@ -6066,6 +6076,13 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/colorjs.io": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/comma-separated-tokens": { "node_modules/comma-separated-tokens": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
@@ -6076,17 +6093,6 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/commander": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=18"
}
},
"node_modules/commondir": { "node_modules/commondir": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -7516,6 +7522,16 @@
"uncrypto": "^0.1.3" "uncrypto": "^0.1.3"
} }
}, },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/has-property-descriptors": { "node_modules/has-property-descriptors": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
@@ -8014,6 +8030,13 @@
"integrity": "sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA==", "integrity": "sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/immutable": {
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz",
"integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==",
"devOptional": true,
"license": "MIT"
},
"node_modules/impound": { "node_modules/impound": {
"version": "1.1.5", "version": "1.1.5",
"resolved": "https://registry.npmjs.org/impound/-/impound-1.1.5.tgz", "resolved": "https://registry.npmjs.org/impound/-/impound-1.1.5.tgz",
@@ -12093,6 +12116,16 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -12113,6 +12146,381 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz",
"integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"chokidar": "^5.0.0",
"immutable": "^5.1.5",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=20.19.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.4.1"
}
},
"node_modules/sass-embedded": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.100.0.tgz",
"integrity": "sha512-Ut8wlQSk19tm7jMK6mz6cF1+e+E7tUnW2tM02zQDPnOTcVbV8qCQG8UWxZkkNlY50+hV3hqP24OOkUlMz8xBpw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@bufbuild/protobuf": "^2.5.0",
"colorjs.io": "^0.5.0",
"immutable": "^5.1.5",
"rxjs": "^7.4.0",
"supports-color": "^8.1.1",
"sync-child-process": "^1.0.2",
"varint": "^6.0.0"
},
"bin": {
"sass": "dist/bin/sass.js"
},
"engines": {
"node": ">=16.0.0"
},
"optionalDependencies": {
"sass-embedded-all-unknown": "1.100.0",
"sass-embedded-android-arm": "1.100.0",
"sass-embedded-android-arm64": "1.100.0",
"sass-embedded-android-riscv64": "1.100.0",
"sass-embedded-android-x64": "1.100.0",
"sass-embedded-darwin-arm64": "1.100.0",
"sass-embedded-darwin-x64": "1.100.0",
"sass-embedded-linux-arm": "1.100.0",
"sass-embedded-linux-arm64": "1.100.0",
"sass-embedded-linux-musl-arm": "1.100.0",
"sass-embedded-linux-musl-arm64": "1.100.0",
"sass-embedded-linux-musl-riscv64": "1.100.0",
"sass-embedded-linux-musl-x64": "1.100.0",
"sass-embedded-linux-riscv64": "1.100.0",
"sass-embedded-linux-x64": "1.100.0",
"sass-embedded-unknown-all": "1.100.0",
"sass-embedded-win32-arm64": "1.100.0",
"sass-embedded-win32-x64": "1.100.0"
}
},
"node_modules/sass-embedded-all-unknown": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.100.0.tgz",
"integrity": "sha512-auFtXY/kwYILmSVjtBDwyj0axcLbYYiffOKWoaXHnI5bsYwiRbBh3EneR1rpbX2ZIZCrwX93i5pxKLTZF/662Q==",
"cpu": [
"!arm",
"!arm64",
"!riscv64",
"!x64"
],
"license": "MIT",
"optional": true,
"dependencies": {
"sass": "1.100.0"
}
},
"node_modules/sass-embedded-android-arm": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.100.0.tgz",
"integrity": "sha512-70f3HgX2pFNmzpGQ86n5e6QfWn2fP4QUQGfFQK0P1XH73ZLIzLo2YqygrGKGKeeqtc5eU2Wl1/xQzhzuKnO4kw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-arm64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.100.0.tgz",
"integrity": "sha512-W+Ru9JwTnfU0UX3jSZcbqFdtKFMcYdfFwytc57h2DgnqCOIiAqI2E06mABZBZC+r3LwXCBuS5GbXAGeVgvVDkA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-riscv64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.100.0.tgz",
"integrity": "sha512-icU3o0V/uCSytSpf+tX5Lf51BvyQEbLzDUJfUi9etSauYBGHpPKkdtdZH0si4v98phq11Kl8rSV1SggksxF1Hg==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-x64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.100.0.tgz",
"integrity": "sha512-mevF9VQk6gEYByy8+jusaHGmd7Usb2ytX/DsEOd0JtOGCtcf1kh575xJ6OUBDIcJ15uLnbau/0iy1eP6WVBvWA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-arm64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.100.0.tgz",
"integrity": "sha512-1PVlYi61POo93IT/FfrG1mc1tAHxeSTyUALF2aOFmXGWjVXr3bQzEQiBGCOvQbj/ix+5hNyXFXcEMEyKvtUJJA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-x64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.100.0.tgz",
"integrity": "sha512-x97o3JnGyImZNCIVs9wQHJUE5QCvmVIKaH1cwrz/5dK7OT1FpeNiW+u9TUomP9hG6Ekjd8EL8NBHpxTfIhdjmg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.100.0.tgz",
"integrity": "sha512-9Ul7O1eKrc5YlhwWjkp8tZPSe3UEwSZ1uwUZOQom1HL0pRlBA6F/IlGZYFTLwnHMIP1fc77MMNaBRfc05mKMpw==",
"cpu": [
"arm"
],
"libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.100.0.tgz",
"integrity": "sha512-Dwjmj8Z6VRy7rAi53JAdEwIyUjpfl7PhpSc2/LpQPQx+aO5Dp7Spaipkax0ufJl1SoDUdchCsM4y/88YaluorQ==",
"cpu": [
"arm64"
],
"libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.100.0.tgz",
"integrity": "sha512-sl0JgbGloPyJg66XXx5UDSDScZ0oU85DpMQU4JU/sCUCFj1Z8zZ69SJWKTCNE4/jwnce7WI2zPCV5AG+RHOZJw==",
"cpu": [
"arm"
],
"libc": "musl",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.100.0.tgz",
"integrity": "sha512-XpACJB2KjSLjf2e9uuvGVdOURsoNrFqgRiihhXyUHK9W0t3LIHb7z5MA/7XGPIT9bWSOO2zyw+rH/FHtDV/Yrg==",
"cpu": [
"arm64"
],
"libc": "musl",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-riscv64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.100.0.tgz",
"integrity": "sha512-ShvI0Kx04mwoCARwZ0UjiT97isQvzO80tAt91zmFyHLN9kelc/IrQi940farSm2xQVPCKdeVyeG0ekBsokSpYQ==",
"cpu": [
"riscv64"
],
"libc": "musl",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-x64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.100.0.tgz",
"integrity": "sha512-TDBCRWNuS4RDLQXvRc1gjZlWiWTWaWGp0Bwu/IKwJxov81lsvrCs3TihTyNXtW7V5aoN4Ky3r0QOkNb3mwmBnA==",
"cpu": [
"x64"
],
"libc": "musl",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-riscv64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.100.0.tgz",
"integrity": "sha512-j4ENJGOheO+fm3j/yorLxCjBP6/XskrZx7dTLlT+lXYwN/qqCqoA/gsNLI0McS3DFM6GBwPiffzWsdWS8t6sEQ==",
"cpu": [
"riscv64"
],
"libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-x64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.100.0.tgz",
"integrity": "sha512-0vUSN8j0WGtCJIOPh//EmUvYGHW0QOe5iul8qyhPk50MAcw49MA0r34AhftjDdx94ILPF6vApFs0gwHPQRlpVA==",
"cpu": [
"x64"
],
"libc": "glibc",
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-unknown-all": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.100.0.tgz",
"integrity": "sha512-c+naBgWId4MIpToXcI0DgqetjdAkwTTAxFAuOaBz7HUXLdyG1oZRrEvSsbe41nEdQOKH0vgofVFCeSQgoXOG9A==",
"license": "MIT",
"optional": true,
"os": [
"!android",
"!darwin",
"!linux",
"!win32"
],
"dependencies": {
"sass": "1.100.0"
}
},
"node_modules/sass-embedded-win32-arm64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.100.0.tgz",
"integrity": "sha512-iE+yxj+hUXwwbqpHkXxgAWTzeRfcWxJ7SSTQEPMk48lwq3oCrWLlz5sQuWHbuTK/i0GKQfROdP+hOmPi89yjUg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-x64": {
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.100.0.tgz",
"integrity": "sha512-qI4F8MI7/KYoy9NdjJfhSspG42WPkADSNDvwEV7qWvCSFC83koJssRsKO2/PfY+niZz6BG65Ic/D+A11h959hw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/sax": { "node_modules/sax": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
@@ -12845,6 +13253,29 @@
"node": ">=16" "node": ">=16"
} }
}, },
"node_modules/sync-child-process": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
"integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"sync-message-port": "^1.0.0"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/sync-message-port": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz",
"integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/tagged-tag": { "node_modules/tagged-tag": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz",
@@ -13137,8 +13568,8 @@
"version": "2.8.1", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD", "devOptional": true,
"optional": true "license": "0BSD"
}, },
"node_modules/tunnel-agent": { "node_modules/tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
@@ -13805,6 +14236,13 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
"devOptional": true,
"license": "MIT"
},
"node_modules/vfile": { "node_modules/vfile": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",

View File

@@ -15,5 +15,8 @@
"nuxt": "^4.4.8", "nuxt": "^4.4.8",
"vue": "^3.5.35", "vue": "^3.5.35",
"vue-router": "^5.1.0" "vue-router": "^5.1.0"
},
"devDependencies": {
"sass-embedded": "^1.100.0"
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.