note fallback

<script>
(function () {
    var content = document.getElementById("content");
    if (!content) return;
    var m = document.body.className.match(/type-([\w-]+)/);
    var type = m ? m[1] : "";
    var widgetTypes = ["mermaid", "canvas", "mindMap", "webView", "relationMap", "spreadsheet", "search", "geo"];
    if (widgetTypes.indexOf(type) === -1) return;
    if (content.querySelector("svg, iframe, canvas, .excalidraw, .mindmap, .mermaid")) return;

    var clone = content.cloneNode(true);
    clone.querySelectorAll("script, style, nav, a, .blog-prevnext, .reading-time").forEach(function (el) { el.remove(); });
    var raw = (clone.textContent || "").trim();
    if (!raw) return;

    function makePre(text) {
        var pre = document.createElement("pre");
        pre.className = "note-fallback";
        var code = document.createElement("code");
        code.className = "language-json";
        code.textContent = text;
        pre.appendChild(code);
        applyHighlight(code);
        return pre;
    }

    var hljsLoading = false;
    function applyHighlight(codeEl) {
        if (window.hljs) {
            codeEl.classList.add("hljs");
            try { hljs.highlightElement(codeEl); } catch (e) {}
            if (window.hljs.lineNumbersBlock) {
                try { hljs.lineNumbersBlock(codeEl); } catch (e) {}
            }
            return;
        }
        if (hljsLoading) {
            setTimeout(function () { applyHighlight(codeEl); }, 200);
            return;
        }
        hljsLoading = true;
        var s = document.createElement("script");
        s.src = "api/notes/vuVkfngB4d0j/download";
        s.onload = function () {
            if (window.hljs && window.hljs.lineNumbersBlock) { applyHighlight(codeEl); return; }
            var p = document.createElement("script");
            p.src = "api/notes/eHpLkUWWMEaM/download";
            p.onload = function () { applyHighlight(codeEl); };
            document.head.appendChild(p);
        };
        document.head.appendChild(s);
    }

    if (type === "mermaid") {
        content.querySelectorAll("img, hr").forEach(function (el) { el.remove(); });
        var nativePre = content.querySelector("pre");
        if (!nativePre) return;
        var src = nativePre.textContent;
        if (!src.trim()) return;
        var nativeDetails = nativePre.closest("details");

        var wrapper = document.createElement("div");
        wrapper.className = "mermaid-render";
        var diagram = document.createElement("div");
        diagram.className = "mermaid-diagram";
        var details = document.createElement("details");
        details.className = "mermaid-source";
        var summary = document.createElement("summary");
        summary.textContent = "Source";
        var pre = document.createElement("pre");
        var code = document.createElement("code");
        code.textContent = src;
        pre.appendChild(code);
        addCopyButton(pre, src);
        details.appendChild(summary);
        details.appendChild(pre);
        wrapper.appendChild(diagram);
        wrapper.appendChild(details);
        (nativeDetails || nativePre).replaceWith(wrapper);
        applyHighlight(code);

        var MMD_DARK = {
            background: "transparent",
            textColor: "#ebdbb2",
            titleColor: "#fbf1c7",
            lineColor: "#a89984",
            edgeLabelBackground: "#3c3836",
            nodeTextColor: "#fbf1c7",
            primaryColor: "#458588", primaryTextColor: "#fbf1c7", primaryBorderColor: "#458588",
            secondaryColor: "#b8bb26", secondaryTextColor: "#1d2021", secondaryBorderColor: "#b8bb26",
            tertiaryColor: "#d3869b", tertiaryTextColor: "#1d2021", tertiaryBorderColor: "#d3869b"
        };
        var MMD_LIGHT = {
            background: "transparent",
            textColor: "#3c3836",
            titleColor: "#282828",
            lineColor: "#928374",
            edgeLabelBackground: "#ebdbb2",
            nodeTextColor: "#1d2021",
            primaryColor: "#83a598", primaryTextColor: "#1d2021", primaryBorderColor: "#076678",
            secondaryColor: "#98971a", secondaryTextColor: "#fbf1c7", secondaryBorderColor: "#79740e",
            tertiaryColor: "#b16286", tertiaryTextColor: "#fbf1c7", tertiaryBorderColor: "#8f3f71"
        };
        function mermaidConfig() {
            var light = document.documentElement.classList.contains("theme-light");
            return { startOnLoad: false, theme: "base", themeVariables: light ? MMD_LIGHT : MMD_DARK };
        }
        function renderMermaid() {
            import("/assets/mermaid.core-BUJU3YJZ.js").then(function (mod) {
                var mermaid = mod.default;
                mermaid.initialize(mermaidConfig());
                return mermaid.render("mm-" + Date.now(), src);
            }).then(function (res) {
                diagram.innerHTML = res.svg;
                diagram.querySelectorAll(".node rect, .cluster rect").forEach(function (r) {
                    var rad = Math.min(8, Math.min(parseFloat(r.getAttribute("width") || 50), parseFloat(r.getAttribute("height") || 50)) * 0.15);
                    r.setAttribute("rx", rad);
                    r.setAttribute("ry", rad);
                });
            }).catch(function () {
                diagram.textContent = src;
            });
        }
        renderMermaid();
        var themeInput = document.querySelector(".theme-selection input");
        if (themeInput) {
            themeInput.addEventListener("change", renderMermaid);
        }
        return;
    }

    if (type === "webView") {
        var p = document.createElement("p");
        p.className = "note-fallback note-fallback-link";
        p.innerHTML = "Embedded page: <a href=\"" + raw + "\" target=\"_blank\" rel=\"noopener noreferrer\">" + raw + "</a>";
        content.appendChild(p);
        return;
    }

    var NS = "http://www.w3.org/2000/svg";
    function svgEl(name, attrs) {
        var n = document.createElementNS(NS, name);
        for (var k in attrs) n.setAttribute(k, attrs[k]);
        return n;
    }

    function fallbackCopy(text, done) {
        var ta = document.createElement("textarea");
        ta.value = text;
        ta.style.position = "fixed";
        ta.style.opacity = "0";
        document.body.appendChild(ta);
        ta.select();
        try { document.execCommand("copy"); } catch (e) {}
        document.body.removeChild(ta);
        done();
    }
    function addCopyButton(pre, text) {
        var btn = document.createElement("button");
        btn.className = "code-copy-btn";
        btn.type = "button";
        btn.textContent = "Copy";
        btn.addEventListener("click", function () {
            var done = function () {
                btn.textContent = "Copied";
                setTimeout(function () { btn.textContent = "Copy"; }, 1500);
            };
            if (navigator.clipboard && navigator.clipboard.writeText) {
                navigator.clipboard.writeText(text).then(done, function () { fallbackCopy(text, done); });
            } else {
                fallbackCopy(text, done);
            }
        });
        pre.appendChild(btn);
    }
    function makeSourceDetails(text) {
        var details = document.createElement("details");
        details.className = "mermaid-source";
        var summary = document.createElement("summary");
        summary.textContent = "Source";
        var pre = document.createElement("pre");
        var code = document.createElement("code");
        code.className = "language-json";
        code.textContent = text;
        pre.appendChild(code);
        addCopyButton(pre, text);
        details.appendChild(summary);
        details.appendChild(pre);
        applyHighlight(code);
        return details;
    }

    /* ---------- MindMap (MindElixir data) ---------- */
    var MIND_DARK = [
        { bg: "#458588", bd: "#3a6b70", text: "#fbf1c7" },
        { bg: "#b8bb26", bd: "#98971a", text: "#1d2021" },
        { bg: "#d3869b", bd: "#b16286", text: "#1d2021" },
        { bg: "#8ec07c", bd: "#689d6a", text: "#1d2021" },
        { bg: "#fe8019", bd: "#d65d0e", text: "#1d2021" }
    ];
    var MIND_LIGHT = [
        { bg: "#83a598", bd: "#458588", text: "#1d2021" },
        { bg: "#98971a", bd: "#79740e", text: "#fbf1c7" },
        { bg: "#b16286", bd: "#8f3f71", text: "#fbf1c7" },
        { bg: "#427b58", bd: "#3a6350", text: "#fbf1c7" },
        { bg: "#af3a03", bd: "#8f3003", text: "#fbf1c7" }
    ];
    function mindPalette() {
        return document.documentElement.classList.contains("theme-light") ? MIND_LIGHT : MIND_DARK;
    }
    function mindEdgeColor() {
        return document.documentElement.classList.contains("theme-light") ? "#928374" : "#a89984";
    }
    function mindSize(topic, fontSize) {
        var lines = String(topic || "").split("\n");
        var w = 0;
        for (var i = 0; i < lines.length; i++) w = Math.max(w, lines[i].length * fontSize * 0.62);
        return { w: Math.max(w + 24, 56), h: Math.max(lines.length * (fontSize + 6) + 10, 32) };
    }
    function mindSubHeight(n, depth) {
        n.depth = depth;
        var fs = depth === 0 ? 16 : 14;
        n.box = mindSize(n.topic, fs);
        if (n.children && n.children.length) {
            var sum = 0;
            for (var i = 0; i < n.children.length; i++) sum += mindSubHeight(n.children[i], depth + 1);
            n.childSpan = sum + (n.children.length - 1) * 18;
            n.total = Math.max(n.box.h, n.childSpan);
        } else {
            n.total = n.box.h;
        }
        return n.total;
    }
    function mindPlace(n, x, side, yTop) {
        n.x = x - n.box.w / 2;
        n.y = yTop + (n.total - n.box.h) / 2;
        if (!n.children || !n.children.length) return;
        var cursor = yTop;
        for (var i = 0; i < n.children.length; i++) {
            var c = n.children[i];
            var childSide = side === 0 ? (i % 2 === 0 ? -1 : 1) : side;
            var childX = x + childSide * (n.box.w / 2 + 46 + c.box.w / 2);
            mindPlace(c, childX, childSide, cursor);
            cursor += c.total + 18;
        }
    }
    function renderMindMap(nodeData) {
        var wrap = document.createElement("div");
        wrap.className = "mindmap-render";
        var root = nodeData;
        mindSubHeight(root, 0);
        mindPlace(root, 0, 0, -root.total / 2);
        var minX = 1e9, minY = 1e9, maxX = -1e9, maxY = -1e9;
        (function walk(n) {
            minX = Math.min(minX, n.x); maxX = Math.max(maxX, n.x + n.box.w);
            minY = Math.min(minY, n.y); maxY = Math.max(maxY, n.y + n.box.h);
            if (n.children) n.children.forEach(walk);
        })(root);
        var pad = 34;
        var MIND = mindPalette();
        var EDGE = mindEdgeColor();
        var W = maxX - minX + pad * 2, H = maxY - minY + pad * 2;
        var svg = svgEl("svg", { class: "mindmap-svg", viewBox: (minX - pad) + " " + (minY - pad) + " " + W + " " + H, width: W, height: H });
        function draw(n) {
            var col = MIND[Math.min(n.depth, MIND.length - 1)];
            var g = svgEl("g");
            g.appendChild(svgEl("rect", { x: n.x, y: n.y, width: n.box.w, height: n.box.h, rx: 8, fill: col.bg, stroke: col.bd, "stroke-width": 1.5 }));
            var lines = String(n.topic || "").split("\n");
            var fs = n.depth === 0 ? 16 : 14;
            var lh = fs + 5;
            for (var i = 0; i < lines.length; i++) {
                var t = svgEl("text", { x: n.x + n.box.w / 2, y: n.y + n.box.h / 2 - ((lines.length - 1) * lh) / 2 + i * lh, "text-anchor": "middle", "dominant-baseline": "central", "font-size": fs, fill: col.text, "font-family": "sans-serif" });
                t.textContent = lines[i];
                g.appendChild(t);
            }
            svg.appendChild(g);
            if (n.children) n.children.forEach(function (c) {
                var sy = n.y + n.box.h / 2, ey = c.y + c.box.h / 2;
                var sx = c.x > n.x ? n.x + n.box.w : n.x;
                var ex = c.x > n.x ? c.x : c.x + c.box.w;
                var dir = ex >= sx ? 1 : -1;
                var dx = Math.max(26, Math.min(56, Math.abs(ex - sx) * 0.4));
                var lead = dx * 0.5;
                svg.appendChild(svgEl("path", {
                    d: "M " + sx + " " + sy +
                        " L " + (sx + dir * lead) + " " + sy +
                        " C " + (sx + dir * dx) + " " + sy + " " + (ex - dir * dx) + " " + ey + " " + (ex - dir * lead) + " " + ey +
                        " L " + ex + " " + ey,
                    fill: "none", stroke: EDGE, "stroke-width": 2.5,
                    "stroke-linecap": "round", "stroke-linejoin": "round"
                }));
                draw(c);
            });
        }
        draw(root);
        wrap.appendChild(svg);
        return wrap;
    }

    /* ---------- Canvas (Excalidraw) ---------- */
    function renderExcalidraw(elements) {
        var wrap = document.createElement("div");
        wrap.className = "excalidraw-render";
        var els = elements.filter(function (e) { return e && !e.isDeleted; });
        if (!els.length) { wrap.textContent = "Empty canvas"; return wrap; }
        var pad = 40;
        var minX = 1e9, minY = 1e9, maxX = -1e9, maxY = -1e9;
        els.forEach(function (e) {
            minX = Math.min(minX, e.x); minY = Math.min(minY, e.y);
            maxX = Math.max(maxX, e.x + e.width); maxY = Math.max(maxY, e.y + e.height);
        });
        var W = maxX - minX + pad * 2, H = maxY - minY + pad * 2;
        var svg = svgEl("svg", { class: "excalidraw-svg", viewBox: (minX - pad) + " " + (minY - pad) + " " + W + " " + H, width: W, height: H });
        els.forEach(function (e) {
            var g = svgEl("g");
            if (e.angle) g.setAttribute("transform", "rotate(" + (e.angle * 180 / Math.PI) + " " + (e.x + e.width / 2) + " " + (e.y + e.height / 2) + ")");
            if (typeof e.opacity === "number" && e.opacity < 100) g.setAttribute("opacity", e.opacity / 100);
            var sc = e.strokeColor || "#282828", bg = e.backgroundColor || "transparent", sw = Math.max(1, e.strokeWidth || 2);
            var filled = bg && bg !== "transparent";
            var fillOp = e.fillStyle === "solid" ? 1 : 0.35;
            function strokeShape(shape) {
                if (filled) { shape.setAttribute("fill", bg); shape.setAttribute("fill-opacity", fillOp); }
                else shape.setAttribute("fill", "none");
                shape.setAttribute("stroke", sc); shape.setAttribute("stroke-width", sw);
                g.appendChild(shape);
            }
            if (e.type === "rectangle") {
                strokeShape(svgEl("rect", { x: e.x, y: e.y, width: e.width, height: e.height, rx: Math.min(8, Math.min(e.width, e.height) * 0.08) }));
            } else if (e.type === "ellipse") {
                strokeShape(svgEl("ellipse", { cx: e.x + e.width / 2, cy: e.y + e.height / 2, rx: e.width / 2, ry: e.height / 2 }));
            } else if (e.type === "diamond") {
                var cx = e.x + e.width / 2, cy = e.y + e.height / 2;
                strokeShape(svgEl("polygon", { points: cx + "," + e.y + " " + (e.x + e.width) + "," + cy + " " + cx + "," + (e.y + e.height) + " " + e.x + "," + cy }));
            } else if (e.type === "line" || e.type === "arrow") {
                var pts = e.points || [];
                if (!pts.length) return;
                var coords = pts.map(function (pt) { return (e.x + pt[0]) + "," + (e.y + pt[1]); }).join(" ");
                strokeShape(svgEl("polyline", { points: coords }));
                if (e.type === "arrow" && pts.length > 1) {
                    var last = pts[pts.length - 1], prev = pts[pts.length - 2];
                    var ang = Math.atan2(last[1] - prev[1], last[0] - prev[0]);
                    var ax = e.x + last[0], ay = e.y + last[1], al = 9 + sw;
                    g.appendChild(svgEl("polygon", { points: (ax + Math.cos(ang) * al) + "," + (ay + Math.sin(ang) * al) + " " + (ax + Math.cos(ang + 2.6) * al * 0.6) + "," + (ay + Math.sin(ang + 2.6) * al * 0.6) + " " + (ax + Math.cos(ang - 2.6) * al * 0.6) + "," + (ay + Math.sin(ang - 2.6) * al * 0.6), fill: sc, stroke: sc }));
                }
            } else if (e.type === "freedraw") {
                var fpts = e.points || [];
                if (!fpts.length) return;
                strokeShape(svgEl("path", { d: "M " + fpts.map(function (pt) { return (e.x + pt[0]) + "," + (e.y + pt[1]); }).join(" L "), "stroke-linecap": "round", "stroke-linejoin": "round" }));
            } else if (e.type === "text") {
                var fs = e.fontSize || 20;
                var ff = e.fontFamily === 2 ? "sans-serif" : (e.fontFamily === 3 ? "monospace" : "'Comic Sans MS','Comic Sans',cursive");
                var ta = e.textAlign === "left" ? "start" : (e.textAlign === "right" ? "end" : "middle");
                var x = ta === "middle" ? e.x + e.width / 2 : e.x;
                var y = e.verticalAlign === "top" ? e.y + fs * 0.8 : e.y + e.height / 2 + fs * 0.35;
                var lines = String(e.text || "").split("\n");
                var t = svgEl("text", { x: x, y: y, "font-size": fs, fill: sc, "font-family": ff, "text-anchor": ta });
                for (var li = 0; li < lines.length; li++) {
                    var ts = document.createElementNS(NS, "tspan");
                    ts.setAttribute("x", x);
                    ts.setAttribute("dy", li === 0 ? 0 : fs * 1.2);
                    ts.textContent = lines[li];
                    t.appendChild(ts);
                }
                g.appendChild(t);
            }
            svg.appendChild(g);
        });
        wrap.appendChild(svg);
        return wrap;
    }

    /* content per Download-Endpoint holen */
    var noteId = document.body.getAttribute("data-note-id");
    var box = document.createElement("div");
    var prevnext = content.querySelector(".blog-prevnext");
    if (prevnext) { content.insertBefore(box, prevnext); }
    else { content.appendChild(box); }

    function renderWidget() {
        fetch("api/notes/" + noteId + "/download")
            .then(function (r) { return r.text(); })
            .then(function (text) {
                var pretty = text, data = null;
                try { data = JSON.parse(text); pretty = JSON.stringify(data, null, 2); } catch (e) {}
                box.innerHTML = "";
                var rendered = null;
                if (data && type === "mindMap" && data.nodeData) rendered = renderMindMap(data.nodeData);
                else if (data && type === "canvas" && Array.isArray(data.elements)) rendered = renderExcalidraw(data.elements);
                if (rendered) {
                    rendered.appendChild(makeSourceDetails(pretty));
                    box.appendChild(rendered);
                } else {
                    box.appendChild(makePre(pretty));
                    box.appendChild(makeSourceDetails(pretty));
                }
            })
            .catch(function () {
                box.textContent = "Content not available.";
            });
    }
    renderWidget();
    var widgetThemeInput = document.querySelector(".theme-selection input");
    if (widgetThemeInput) {
        widgetThemeInput.addEventListener("change", renderWidget);
    }
})();
</script>