Initial commit
This commit is contained in:
361
Library/Malys/MarkmapMindmap.md
Normal file
361
Library/Malys/MarkmapMindmap.md
Normal 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
|
||||

|
||||
|
||||
## 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 don’t 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))
|
||||
|
||||
Reference in New Issue
Block a user