Initial commit

This commit is contained in:
2026-02-05 12:53:43 +00:00
commit 02f363357a
59 changed files with 23130 additions and 0 deletions

View File

@@ -0,0 +1,361 @@
---
author: malys
description: MarkMap mindmap integration.
name: "Library/Malys/MarkmapMindmap"
tags: meta/library
share.uri: "https://github.com/malys/silverbullet-libraries/blob/main/src/MarkmapMindmap.md"
share.hash: 65e1843c
share.mode: pull
---
# Markmap mindmap
This library provides a way to preview your [MarkMap](https://markmap.js.org/) mind map in a panel while you are editing your space.
With MarkMap Preview, you can:
- Preview your slides without leaving the context of your space
- See how your slides look in real-time as you modify your markdown
- Use the MarkMap Preview panel to navigate through your slides and see them in action
![](https://community.silverbullet.md/uploads/default/original/2X/4/493e4db01035bc5d0ef5189f8f502ac7fc449709.gif)
## Disclaimer & Contributions
This code is provided **as-is**, **without any kind of support or warranty**.
I do **not** provide user support, bug-fixing on demand, or feature development.
If you detect a bug, please **actively participate in debugging it** (analysis, proposed fix, or pull request) **before reporting it**. Bug reports without investigation may be ignored.
🚫 **No new features will be added.**
**All types of contributions are welcome**, including bug fixes, refactoring, documentation improvements, and optimizations.
By using or contributing to this project, you acknowledge and accept these conditions.
## Configuration
To easily manage JS code source, we use a dynamic introspection mechanism based on md page path.
If you dont install program to default path `Library/Malys/xxx`,we have to set:
```lua
config.set("markmap.source ","xxxx")
-- ex: config.set("markmap.source ","Library/Malys/MarkmapMindmap")
-- where xxx is the path of MarkmapMindmap md page
```
> **warning** Caution
> **Depends on** [Utilities.md](https://github.com/malys/silverbullet-libraries/blob/main/src/Utilities.md). It will be installed automatically.
## Code
```space-lua
local source=config.get("markmap.source") or "Library/Malys/MarkmapMindmap"
local panelSize=config.get("markmap.panelSize") or 4
if library~=nil and (mls == nil or (mls ~=nil and mls.debug == nil)) then
library.install("https://github.com/malys/silverbullet-libraries/blob/main/src/Utilities.md")
editor.flashNotification("'Utilities' has been installed", "Info")
end
local function isVisible()
local current_panel_id = config.get("markmap.panelPosition") or "rhs"
local iframe = js.window.document.querySelector(".sb-panel."..current_panel_id..".is-expanded iframe")
if iframe and iframe.contentDocument then
local el = iframe.contentDocument.getElementById("mindmap")
if el then
return true
end
return false
end
end
local function show()
local page_content = editor.getText()
local contentBase64=encoding.base64Encode(page_content)
local content1= mls.getCodeBlock(source,"innerHTML","@CONTENT@", contentBase64)
local js = mls.getCodeBlock(source,"jsInject","@CONTENT@",content1)
local panel_html= mls.getCodeBlock(source,"template")
local current_panel_id = config.get("markmap.panelPosition") or "rhs"
editor.showPanel(current_panel_id,panelSize, panel_html, js)
end
local function hide()
local current_panel_id = config.get("markmap.panelPosition") or "rhs"
editor.hidePanel(current_panel_id)
end
local update = function(mode)
if ((not isVisible() and mode) or (not mode and isVisible())) then
show()
else
hide()
end
end
-- Define the command
command.define({
name = "Markmap: Toggle preview",
description = "Toggle Marp slides render in a panel",
run = function(e)
update(true)
end
})
event.listen({
name = "editor:pageSaved",
run = function(e)
update(false)
end
})
```
## JS templates
```js jsInject
const scriptId = "markmap-inject";
// Remove existing script if present
const existingScript = document.getElementById(scriptId);
if (existingScript) {
existingScript.remove();
}
// Create and inject the script again
const script = document.createElement("script");
script.type = "module";
script.id = scriptId;
script.textContent = `@CONTENT@`;
document.documentElement.appendChild(script);
```
```js innerHTML
function b64DecodeUnicode(str) {
return decodeURIComponent(
atob(str)
.split("")
.map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
.join("")
);
}
import { Transformer } from "https://esm.sh/markmap-lib?bundle";
import { Markmap, deriveOptions } from "https://esm.sh/markmap-view?bundle";
import { Toolbar } from "https://esm.sh/markmap-toolbar?bundle";
const transformer = new Transformer();
const { root } = transformer.transform(b64DecodeUnicode("@CONTENT@"));
const svg = document.getElementById("mindmap");
const base = deriveOptions(null) || {};
const options = {
...base,
duration: 0,
autoFit: false
};
svg.innerHTML = "";
window.mm = Markmap.create(
"svg#mindmap",
options,
root
);
const existing = document.getElementsByClassName("mm-toolbar");
if(existing.length==0){
// 👉 Toolbar
const toolbar = new Toolbar();
toolbar.attach(window.mm);
const el = toolbar.render();
el.style.position = "absolute";
el.style.bottom = "20px";
el.style.right = "20px";
document.body.appendChild(el);
}
// 👉 print
window.addEventListener("beforeprint", () => {
window.mm?.fit();
});
```
## HTML template
```html template
<style>
html,
html {
overflow-y: scroll !important;
width: 90% !important;
}
@media print {
.no-print,
.mm-toolbar {
display: none !important;
}
.markmap-toolbar {
display: none !important;
}
.markmap-dark {
background: white !important;
color: black !important;
}
* {
animation: none !important;
transition: none !important;
}
/* Remove default page margins */
@page {
margin: 0;
}
/* 2⃣ Reset layout sizing */
html,
body {
margin: 0 !important;
padding: 0 !important;
height: auto !important;
overflow: visible !important;
}
/* Hide all toolbars */
.no-print,
.markmap-toolbar {
display: none !important;
}
}
body {
overflow: initial !important;
color: var(--top-color);
font-family: georgia, times, serif;
font-size: 13pt;
margin-top: revert;
margin-bottom: revert;
padding-left: 20px;
padding-right: 20px;
}
img {
max-width: 100%;
}
table {
width: 100%;
border-spacing: 0;
}
ul li p {
margin: 0;
}
thead tr {
background-color: var(--editor-table-head-background-color);
color: var(--editor-table-head-color);
}
th,
td {
padding: 8px;
}
tbody tr:nth-of-type(even) {
background-color: var(--editor-table-even-background-color);
}
a[href] {
text-decoration: none;
color: var(--link-color);
}
blockquote {
border-left: 1px solid var(--editor-blockquote-border-color);
margin-left: 2px;
padding-left: 10px;
background-color: var(--editor-blockquote-background-color);
color: var(--editor-blockquote-color);
}
hr {
margin: 1em 0 1em 0;
text-align: center;
border-color: var(--editor-ruler-color);
border-width: 0;
border-style: dotted;
}
hr:after {
content: "···";
letter-spacing: 1em;
}
span.highlight {
background-color: var(--highlight-color);
}
.markmap {
--markmap-a-color: #0097e6;
--markmap-a-hover-color: #00a8ff;
--markmap-highlight-bg: #ffeaa7;
--markmap-code-bg: #fff;
--markmap-code-color: #555;
--markmap-circle-open-bg: #fff;
--markmap-text-color: #333;
}
html[data-theme=dark] {
.markmap {
--markmap-code-bg: #1a1b26;
--markmap-code-color: #ddd;
--markmap-circle-open-bg: #444;
--markmap-text-color: #dddbdb;
}
}
* {
margin: 0;
padding: 0;
}
#mindmap {
display: block;
width: 100vw;
height: 100vh;
}
.mm-toolbar {display:flex;-webkit-user-select:none;-moz-user-select:none;user-select:none;align-items:center;border-width:1px;--un-border-opacity:1;border-color:rgb(212 212 216 / var(--un-border-opacity));border-radius:0.25rem;border-style:solid;--un-bg-opacity:1;background-color:rgb(255 255 255 / var(--un-bg-opacity));padding:0.25rem;line-height:1; }
.mm-toolbar:hover {--un-border-opacity:1;border-color:rgb(161 161 170 / var(--un-border-opacity)); }
.mm-toolbar svg {display:block; }
.mm-toolbar a {display:inline-block;text-decoration:none; }
.mm-toolbar-brand > img {width:1rem;height:1rem;vertical-align:middle; }
.mm-toolbar-brand > span {padding-left:0.25rem;padding-right:0.25rem; }
.mm-toolbar-brand:not(:first-child), .mm-toolbar-item:not(:first-child) {margin-left:0.25rem; }
.mm-toolbar-brand > *, .mm-toolbar-item > * {min-width:1rem;cursor:pointer;text-align:center;font-size:0.75rem;line-height:1rem;--un-text-opacity:1;color:rgb(161 161 170 / var(--un-text-opacity)); }
.mm-toolbar-brand.active,
.mm-toolbar-brand:hover,
.mm-toolbar-item.active,
.mm-toolbar-item:hover {border-radius:0.25rem;--un-bg-opacity:1;background-color:rgb(228 228 231 / var(--un-bg-opacity)); }
.mm-toolbar-brand.active > *, .mm-toolbar-brand:hover > *, .mm-toolbar-item.active > *, .mm-toolbar-item:hover > * {--un-text-opacity:1;color:rgb(39 39 42 / var(--un-text-opacity)); }
.mm-toolbar-brand.active, .mm-toolbar-item.active {--un-bg-opacity:1;background-color:rgb(212 212 216 / var(--un-bg-opacity)); }
.markmap-dark .mm-toolbar {--un-border-opacity:1;border-color:rgb(82 82 91 / var(--un-border-opacity));--un-bg-opacity:1;background-color:rgb(39 39 42 / var(--un-bg-opacity));--un-text-opacity:1;color:rgb(161 161 170 / var(--un-text-opacity)); }
.markmap-dark .mm-toolbar:hover {--un-border-opacity:1;border-color:rgb(113 113 122 / var(--un-border-opacity)); }
.markmap-dark .mm-toolbar > *:hover {--un-bg-opacity:1;background-color:rgb(82 82 91 / var(--un-bg-opacity)); }
.markmap-dark .mm-toolbar > *:hover > * {--un-text-opacity:1;color:rgb(228 228 231 / var(--un-text-opacity)); }
</style>
<div id="root" class="sb-preview">
<div class="sb-mindmap-toolbar no-print">
<button onclick="window.print()" title="Print">
🖨️
</button>
</div>
<svg id="mindmap"></svg>
</div>
```
## Changelog
* 2026-01-13: fix: multiple SVG visible on refresh
* 2025-12-01 fix: html duplicate inserts
## Community
[Silverbullet forum]([https://community.silverbullet.md/t/space-lua-addon-with-missing-git-commands-history-diff-restore/3539](https://community.silverbullet.md/t/mindmap-with-markmap-js/1556))