home

come funziona questo sito

tags: code

queste informazioni sono leggermente datate. questo sito è stato offline tra luglio 2025 e gennaio 2026 e da quando l’ho ri pubblicato ho fatto varie modifiche a questo workflow

🗳️questo sito è il mio vault obsidian, che viene compilato in html tramite lume.
il mio vault risiede su una repository privata su github, e uno script sulla mia vps droplet digitalocean gira periodicamente per pullare le ultime modifiche e ricompilarle. il sito viene servito con caddy.

todo list per questo sito

preprocessori

lume permette l’utilizzo di preprocessori per modificare il markdown prima che venga compilato in html. ne ho scritti alcuni per adattare il mio vault obsidian al mio caso d’uso:

titolo

in obsidian il titolo di una nota (pagina) è il nome del file, a meno che non sia espressamente specificato. per poter inserire il titolo in cima alla pagina, ce uso la proprietà title nel template

site.preprocess([".md"], pages => {
    for (const page of pages) {
        if (!page.data.title) {
            page.data.title = page.data.basename
        }
    }
})
<header>
    <a href="/">home</a>
    <h1>{{ title }}</h1>
</header>

a capo

in markdown per andare a capo si devono mettere due spazi alla fine di una riga, mentre in obsidian non serve.

site.preprocess([".md"], pages => {
    for (const page of pages) {
        if (typeof page.data.content === "string") {
            page.data.content = addHardLineBreaks(page.data.content);
        }
    }
});

function addHardLineBreaks(content: string): string {
    const lines = content.split("\n");
    let inCodeBlock = false;

    return lines
        .map((line) => {
            const trimmed = line.trimStart();

            if (trimmed.startsWith("```")) {
                inCodeBlock = !inCodeBlock;
                return line;
            }

            if (inCodeBlock || line.endsWith("  ")) return line;

            return line + "  ";
        })
        .join("\n");
}

wikilinks

in markdown i link vengono creati con la sintassi:

![testo link](url)

per i link interni (tra le pagine di un vault) obsidian utilizza gli wiki-style links, fatti così

[[nome nota]] OPPURE [[nome nota|alias da mostrare nel documento]]

per parsarli uso la libreria wikilinks insieme a un preprocessor personalizzato

import wikilinks from "https://deno.land/x/lume_markdown_plugins@v0.9.0/wikilinks.ts";

site.use(wikilinks({ slugify: s => s }));
site.process([".html"], (pages) => {
    for (const page of pages) {
        for (const link of page.document!.querySelectorAll("a[data-wikilink]")) {
            const id = link.getAttribute("data-wikilink");
            link.removeAttribute("data-wikilink");

            let linkName = ''
            let linkLocation = ''

            if (link.textContent?.includes('|')) {
                [linkLocation, linkName] = link.textContent.split('|')
                link.textContent = linkName
            } else {
                [linkName, linkLocation] = [id ?? '', id ?? '']
            }

            // Search a page with this id
            const found = pages.find((p) => p.data.basename === linkLocation);

            if (found) {
                link.setAttribute("href", found.data.url);
            } else {
                link.setAttribute("title", "This page does not exist");
            }
        }
    }
});

immagini e audio

in markdown le immagini si inseriscono con la sintassi

![alt text](url immagine)

obsidian supporta questa sintassi ma preferisce la sua versione:

![[url immagine]]

stessa cosa vale per i file audio: supporta la sintassi html

<audio src="url file audio" controls> </audio>

ma preferisce la sua sintassi.
per accontentire sia lume che obsidian ho scritto una regex per trasformare dall’uno all’altro

const imageExtensions = [".jpg", ".jpeg", ".gif", ".png", ".bmp", ".svg"]
const audioExtensions = [".flac", ".mp3", ".ogg", ".opus", ".wav"]

function wikicontentToRegular(line: string): string {
    const r = /^\!\[\[(.*)\]\]$/
    const match = line.match(r)

    if (!match) {
        // throw new Error('not wiki content')
        return line
    }

    const media = match[1]

    for (const ext of audioExtensions) {
        if (media.endsWith(ext)) {
            return `<audio src="/${media}" controls> </audio>`
        }
    }
  
    for (const ext of imageExtensions) {
        if (media.endsWith(ext)) {
            return `![foto](/${encodeURI(media)})`
        }
    }
}

checklist

per trasformare le checklist da Github Flavored Markdown:

site.process([".html"], pages => {
    for (const page of pages) {
        for (const item of page.document!.querySelectorAll("li")) {
            if (item.firstChild?.nodeType === 3/* Node.TEXT_NODE */) {
                const text = item.firstChild.textContent || '';

                const updatedEmpty = text.replace(/^\[ \]/, emptyMark);
                if (updatedEmpty !== text) {
                    item.firstChild.textContent = updatedEmpty;
                }

                const updatedFull = text.replace(/^\[x\]/, fullMark);
                if (updatedFull !== text) {
                    item.firstChild.textContent = updatedFull;
                }
            }
        }
    }
})