├── .vscode └── settings.json ├── mermaid.plug.yaml ├── deno.jsonc ├── PLUG.md ├── mermaid.ts ├── README.md ├── mermaid.plug.js └── deno.lock /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "editor.formatOnSave": false, 4 | "deno.config": "deno.jsonc", 5 | "[markdown]": { 6 | "editor.formatOnSave": false 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /mermaid.plug.yaml: -------------------------------------------------------------------------------- 1 | name: mermaid 2 | version: 0.1 3 | imports: 4 | - https://get.silverbullet.md/global.plug.json 5 | functions: 6 | mermaidWidget: 7 | path: ./mermaid.ts:widget 8 | codeWidget: mermaid 9 | -------------------------------------------------------------------------------- /deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "build": "deno run -A https://github.com/silverbulletmd/silverbullet/releases/download/edge/plug-compile.js -c deno.jsonc mermaid.plug.yaml" 4 | }, 5 | "imports": { 6 | "@silverbulletmd/silverbullet": "jsr:@silverbulletmd/silverbullet@2.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /PLUG.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Library/silverbullet-mermaid" 3 | tags: meta/library 4 | files: 5 | - mermaid.plug.js 6 | --- 7 | This plug adds basic [Mermaid](https://mermaid.js.org/) support to Silver Bullet. 8 | 9 | For example: 10 | 11 | ```mermaid 12 | flowchart LR 13 | 14 | A[Hard] -->|Text| B(Round) 15 | B --> C{Decision} 16 | C -->|One| D[Result 1] 17 | C -->|Two| E[Result 2] 18 | ``` 19 | 20 | **Note:** The Mermaid library itself is not bundled with this plug, it pulls the JavaScript from the JSDelivr CDN. This means _this plug will not work without an Internet connection_. The reason for this is primarily plug size (bundling the library would amount to 1.1MB). This way Mermaid is only loaded on pages with actual Mermaid diagrams rather than on every SB load. 21 | 22 | ## Configuration 23 | You can use the `mermaid` config to tweak a few things: 24 | 25 | ```space-lua 26 | config.set("mermaid", { 27 | version = "11.4.0", 28 | integrity = "new integrity hash", 29 | -- or disable integrity checking 30 | integrity_disabled = true 31 | -- optional: register icon packs 32 | icon_packs = { 33 | { 34 | name = "logos", 35 | url = "https://unpkg.com/@iconify-json/logos@1/icons.json", 36 | }, 37 | }, 38 | }) 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /mermaid.ts: -------------------------------------------------------------------------------- 1 | import { system } from "@silverbulletmd/silverbullet/syscalls"; 2 | import { CodeWidgetContent } from "@silverbulletmd/silverbullet/type/client"; 3 | 4 | export async function widget( 5 | bodyText: string, 6 | ): Promise { 7 | const config = await system.getConfig("mermaid", {version: "11.10.1"}) 8 | const mermaidVersion = config?.version; 9 | let mermaidHash : string | undefined = config?.integrity ? `"${config.integrity}"` : `"sha256-BmQmdWDS8X2OTbrwELWK366LV6escyWhHHe0XCTU/Hk="` 10 | if (config?.integrity_disabled) { 11 | mermaidHash = undefined; 12 | } 13 | 14 | let packs: string = ""; 15 | if (config?.icon_packs) { 16 | for (const pack of config?.icon_packs) { 17 | packs += `{ 18 | name: "${pack.name}", 19 | loader: () => fetch("${pack.url}").then(r => r.json()), 20 | },`; 21 | } 22 | } 23 | 24 | return { 25 | html: `
${bodyText.replaceAll("<", "<")}
`, 26 | script: ` 27 | loadJsByUrl("https://cdn.jsdelivr.net/npm/mermaid@${mermaidVersion}/dist/mermaid.min.js", ${mermaidHash}).then(() => { 28 | mermaid.init().then(updateHeight); 29 | mermaid.registerIconPacks([${packs}]); 30 | }); 31 | document.addEventListener("click", () => { 32 | api({type: "blur"}); 33 | }); 34 | `, 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: "Mermaid support for SilverBullet" 3 | tags: meta/library 4 | files: 5 | - mermaid.plug.js 6 | --- 7 | # Silver Bullet plug for Mermaid diagrams 8 | This plug adds basic [Mermaid](https://mermaid.js.org/) support to Silver Bullet. 9 | 10 | For example: 11 | 12 | ```mermaid 13 | flowchart LR 14 | 15 | A[Hard] -->|Text| B(Round) 16 | B --> C{Decision} 17 | C -->|One| D[Result 1] 18 | C -->|Two| E[Result 2] 19 | ``` 20 | 21 | **Note:** this plug is compatible with SilverBulet v2. 22 | 23 | **Note:** The Mermaid library itself is not bundled with this plug, it pulls the JavaScript from the JSDelivr CDN. This means _this plug will not work without an Internet connection_. The reason for this is primarily plug size (bundling the library would amount to 1.1MB). This way Mermaid is only loaded on pages with actual Mermaid diagrams rather than on every SB load. 24 | 25 | ## Installation 26 | In your CONFIG page, add the mermaid plug, e.g.: 27 | 28 | ```space-lua 29 | config.set { 30 | plugs = { 31 | "github:silverbulletmd/silverbullet-mermaid/mermaid.plug.js" 32 | } 33 | } 34 | ``` 35 | 36 | Then run the `Plugs: Update` command. 37 | 38 | 39 | ## Use 40 | 41 | Put a mermaid block in your markdown: 42 | 43 | ```mermaid 44 | flowchart TD 45 | Start --> Stop 46 | ``` 47 | 48 | And move your cursor outside of the block to live preview it! 49 | 50 | ## Configuration 51 | 52 | You can use the `mermaid` config to tweak a few things: 53 | 54 | ```space-lua 55 | config.set("mermaid", { 56 | version = "11.4.0", 57 | integrity = "new integrity hash", 58 | -- or disable integrity checking 59 | integrity_disabled = true 60 | -- optional: register icon packs 61 | icon_packs = { 62 | { 63 | name = "logos", 64 | url = "https://unpkg.com/@iconify-json/logos@1/icons.json", 65 | }, 66 | }, 67 | }) 68 | ``` 69 | 70 | -------------------------------------------------------------------------------- /mermaid.plug.js: -------------------------------------------------------------------------------- 1 | var h=Object.defineProperty;var v=(t,e)=>{for(var i in e)h(t,i,{get:e[i],enumerable:!0})};function f(t){let e=atob(t),i=e.length,o=new Uint8Array(i);for(let n=0;n{throw new Error("Not initialized yet")},p=typeof window>"u"&&typeof globalThis.WebSocketPair>"u";typeof Deno>"u"&&(self.Deno={args:[],build:{arch:"x86_64"},env:{get(){}}});var l=new Map,m=0;p&&(globalThis.syscall=async(t,...e)=>await new Promise((i,o)=>{m++,l.set(m,{resolve:i,reject:o}),u({type:"sys",id:m,name:t,args:e})}));function g(t,e,i){p&&(u=i,self.addEventListener("message",o=>{(async()=>{let n=o.data;switch(n.type){case"inv":{let s=t[n.name];if(!s)throw new Error(`Function not loaded: ${n.name}`);try{let a=await Promise.resolve(s(...n.args||[]));u({type:"invr",id:n.id,result:a})}catch(a){console.error("An exception was thrown as a result of invoking function",n.name,"error:",a.message),u({type:"invr",id:n.id,error:a.message})}}break;case"sysr":{let s=n.id,a=l.get(s);if(!a)throw Error("Invalid request id");l.delete(s),n.error?a.reject(new Error(n.error)):a.resolve(n.result)}break}})().catch(console.error)}),u({type:"manifest",manifest:e}))}async function b(t,e){if(typeof t!="string"){let i=new Uint8Array(await t.arrayBuffer()),o=i.length>0?d(i):void 0;e={method:t.method,headers:Object.fromEntries(t.headers.entries()),base64Body:o},t=t.url}return syscall("sandboxFetch.fetch",t,e)}globalThis.nativeFetch=globalThis.fetch;function w(){globalThis.fetch=async function(t,e){let i=e&&e.body?d(new Uint8Array(await new Response(e.body).arrayBuffer())):void 0,o=await b(t,e&&{method:e.method,headers:e.headers,base64Body:i});return new Response(o.base64Body?f(o.base64Body):null,{status:o.status,headers:o.headers})}}p&&w();typeof self>"u"&&(self={syscall:()=>{throw new Error("Not implemented here")}});function r(t,...e){return globalThis.syscall(t,...e)}var c={};v(c,{getConfig:()=>L,getMode:()=>E,getVersion:()=>U,invokeCommand:()=>A,invokeFunction:()=>F,listCommands:()=>T,listSyscalls:()=>k,reloadPlugs:()=>D,wipeClient:()=>R});function F(t,...e){return r("system.invokeFunction",t,...e)}function A(t,e){return r("system.invokeCommand",t,e)}function T(){return r("system.listCommands")}function k(){return r("system.listSyscalls")}function D(){return r("system.reloadPlugs")}function E(){return r("system.getMode")}function U(){return r("system.getVersion")}function L(t,e=void 0){return r("system.getConfig",t,e)}function R(t=!1){return r("system.wipeClient",t)}async function y(t){let e=await c.getConfig("mermaid",{version:"11.10.1"}),i=e?.version,o=e?.integrity?`"${e.integrity}"`:'"sha256-BmQmdWDS8X2OTbrwELWK366LV6escyWhHHe0XCTU/Hk="';e?.integrity_disabled&&(o=void 0);let n="";if(e?.icon_packs)for(let s of e?.icon_packs)n+=`{ 2 | name: "${s.name}", 3 | loader: () => fetch("${s.url}").then(r => r.json()), 4 | },`;return{html:`
${t.replaceAll("<","<")}
`,script:` 5 | loadJsByUrl("https://cdn.jsdelivr.net/npm/mermaid@${i}/dist/mermaid.min.js", ${o}).then(() => { 6 | mermaid.init().then(updateHeight); 7 | mermaid.registerIconPacks([${n}]); 8 | }); 9 | document.addEventListener("click", () => { 10 | api({type: "blur"}); 11 | }); 12 | `}}var x={mermaidWidget:y},P={name:"mermaid",version:.1,imports:["https://get.silverbullet.md/global.plug.json"],functions:{mermaidWidget:{path:"./mermaid.ts:widget",codeWidget:"mermaid"}},assets:{}},Se={manifest:P,functionMapping:x};g(x,P,self.postMessage);export{Se as plug}; 13 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "specifiers": { 4 | "jsr:@silverbulletmd/silverbullet@2.0.0": "2.0.0" 5 | }, 6 | "jsr": { 7 | "@silverbulletmd/silverbullet@2.0.0": { 8 | "integrity": "6da4dfdf9b7ab83812dc6d0f0aeb6c55561e031a11f53a98e0a9602c499a52e8" 9 | } 10 | }, 11 | "redirects": { 12 | "https://esm.sh/handlebars": "https://esm.sh/handlebars@4.7.8" 13 | }, 14 | "remote": { 15 | "https://deno.land/x/silverbullet@0.10.1/lib/asset_bundle/bundle.ts": "5cebb61d5ec523c9d2d8b222516ed3593d40601834c3c7d2aa2b48dad00986b1", 16 | "https://deno.land/x/silverbullet@0.10.1/lib/command.ts": "1b131c5da91f0bdb8c58eb3058befc4f5861827a38d9196a08026206f51379b1", 17 | "https://deno.land/x/silverbullet@0.10.1/lib/crypto.ts": "62a2fa4fa5656de53856fcaf70f8e1ec561fc949d26d34168372d7963a727886", 18 | "https://deno.land/x/silverbullet@0.10.1/lib/data/kv_primitives.ts": "98d7367dbcd1303defd728ef6764b32765600c18ec3359964cc2758e29bb2f26", 19 | "https://deno.land/x/silverbullet@0.10.1/lib/manifest.ts": "a6a89a1ab5ef3671d3e37a574c66fca32939247ed9fff4a8b20cccf9da45b754", 20 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/event.ts": "da055088f3d1d93f31aadd7e16a97061033fdba5807609f3838280352dbbc15e", 21 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/manifest_cache.ts": "c6eaed062ade506ed98a0fa3686f161f58ff839e939f0aa536a371dabd43ca8f", 22 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/namespace.ts": "0a870e11ffefcf9c5fe9e8d11d5ed07dcd19bdd28c4289f96f8bcf95ec44baf2", 23 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/plug.ts": "d3470c6b2040c7e94576f8685a37ca1553ab5ad95760d9566f3c336cb97eee9d", 24 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/protocol.ts": "953341d218c74d662b549e328551033e303ae196a6b27f464b5b394fa7fb1940", 25 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/sandboxes/sandbox.ts": "b1ce8da12cb7658482c74888693a8d7ecc02e772d4ac245fbf9935a191ebf5a2", 26 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/system.ts": "9543bc8bf0e000f7ab647ebc9bd3132f4b8aa3755980c72ea8f291948f27d4dd", 27 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/types.ts": "bb8d220c152304961c815edc8f71bcb843c761c7a789893f579cf57d088a5333", 28 | "https://deno.land/x/silverbullet@0.10.1/lib/plugos/worker_runtime.ts": "8b147806f210e95f8879cc5a81e4022bcd2454675076f1a3a259169189ee6f20", 29 | "https://deno.land/x/silverbullet@0.10.1/lib/proxy_fetch.ts": "8091713df105d4d92ee1f7d7aabc9af1ed667944c79d001b1ff86ae068fa0f9e", 30 | "https://deno.land/x/silverbullet@0.10.1/plug-api/lib/tree.ts": "c6bcdba7e38f4e9cb1bce5206b0916603b7e57926f942663c03fb7b45d482261", 31 | "https://deno.land/x/silverbullet@0.10.1/plug-api/types.ts": "2656ea5e261ba2d7bf685580c823c2bc87142a0139b655ff794c3b89ffd7cf62", 32 | "https://deno.land/x/silverbullet@0.10.1/web/change.ts": "bc3204e4f34f86edd11b0fcf3fdfc1e8599cb08ca4eebe7f22451195b74440ef", 33 | "https://deno.land/x/silverbullet@2.0.0/lib/asset_bundle/bundle.ts": "5cebb61d5ec523c9d2d8b222516ed3593d40601834c3c7d2aa2b48dad00986b1", 34 | "https://deno.land/x/silverbullet@2.0.0/lib/crypto.ts": "b7485dfcc231cf03af0e5271b89970ba1f7ab6cb43ebfe555de0c48996313250", 35 | "https://deno.land/x/silverbullet@2.0.0/lib/data/kv_primitives.ts": "d8e5759d241321885134ce4132bc61b33f0ba3bfe6ce271633a4bcc2f4e12270", 36 | "https://deno.land/x/silverbullet@2.0.0/lib/manifest.ts": "2628716fffdff63e3aa8462c3b68928b70f686e2bbe8ff5bd41d057773875e63", 37 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/event.ts": "da055088f3d1d93f31aadd7e16a97061033fdba5807609f3838280352dbbc15e", 38 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/manifest_cache.ts": "c6eaed062ade506ed98a0fa3686f161f58ff839e939f0aa536a371dabd43ca8f", 39 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/namespace.ts": "0a870e11ffefcf9c5fe9e8d11d5ed07dcd19bdd28c4289f96f8bcf95ec44baf2", 40 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/plug.ts": "7cbcac21c865b69d678374eda936d5e1ac9422408c8115b84c16f9aef80671be", 41 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/protocol.ts": "953341d218c74d662b549e328551033e303ae196a6b27f464b5b394fa7fb1940", 42 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/sandboxes/sandbox.ts": "cc46432492871bf96279050449455b32cf435bef1abc0a1fccc1d87f34143e8e", 43 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/system.ts": "5b99c8b793edc4de0039dbc8c0532119ec346150a8e129b1fe229361246d59a2", 44 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/types.ts": "e4decd11d40797161b4fed67cc432f370ceb159b4680c57dde97e6300ea0abfb", 45 | "https://deno.land/x/silverbullet@2.0.0/lib/plugos/worker_runtime.ts": "6f16899c0a3d2525c4bf3f881463bce2d7f2b8b55f072fd74ae0f621ba74fea0", 46 | "https://deno.land/x/silverbullet@2.0.0/lib/proxy_fetch.ts": "831d98cf7f9ada653fc958f52ad367d8511e2634400c29e1fe9d6babd230c0bf", 47 | "https://deno.land/x/silverbullet@2.0.0/type/datastore.ts": "43ac83561844fc5224bd2d5c6c2a92a2cdda6688d29b798c624e3c90bca7ab9d", 48 | "https://esm.sh/handlebars@4.7.8": "216fcab7c7eed350aff771ac741f7ded527bc1c5a88adf3e6970975cbd1f49e8", 49 | "https://esm.sh/v135/handlebars@4.7.8/denonext/handlebars.mjs": "f8a53ecdbb0a189a94479519d25f7a97b19220be7ddf53d94b2937cbb2f5dc0b", 50 | "https://esm.sh/v135/source-map@0.6.1/denonext/source-map.mjs": "ccff3bb06dea7c01a2c83cf12113697592e418fd06b55ae2bb4cb0a4e51a98b8" 51 | }, 52 | "workspace": { 53 | "dependencies": [ 54 | "jsr:@silverbulletmd/silverbullet@2.0.0" 55 | ] 56 | } 57 | } 58 | --------------------------------------------------------------------------------