From 2fa56839cf8159ec3c829170d6ed6b3a73b94796 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 26 Feb 2024 19:37:31 +0500 Subject: [PATCH] feat: interactive examples --- .../mermaid/src/docs/.vitepress/config.ts | 7 ++ .../docs/.vitepress/mermaid-markdown-all.ts | 3 +- .../src/docs/.vitepress/theme/MermaidRun.vue | 9 +++ .../src/docs/.vitepress/theme/codapi.css | 69 +++++++++++++++++++ .../src/docs/.vitepress/theme/codapi.ts | 50 ++++++++++++++ .../src/docs/.vitepress/theme/index.ts | 4 ++ packages/mermaid/src/docs/package.json | 1 + pnpm-lock.yaml | 7 ++ 8 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 packages/mermaid/src/docs/.vitepress/theme/MermaidRun.vue create mode 100644 packages/mermaid/src/docs/.vitepress/theme/codapi.css create mode 100644 packages/mermaid/src/docs/.vitepress/theme/codapi.ts diff --git a/packages/mermaid/src/docs/.vitepress/config.ts b/packages/mermaid/src/docs/.vitepress/config.ts index 401130518b..1005b2a28b 100644 --- a/packages/mermaid/src/docs/.vitepress/config.ts +++ b/packages/mermaid/src/docs/.vitepress/config.ts @@ -66,6 +66,13 @@ export default defineConfig({ }, ], }, + vue: { + template: { + compilerOptions: { + isCustomElement: (tag) => tag.includes('-'), + }, + }, + }, }); // Top (across the page) menu diff --git a/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts b/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts index 30f044d988..ff1746e8dc 100644 --- a/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts +++ b/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts @@ -31,7 +31,8 @@ const MermaidExample = async (md: MarkdownRenderer) => { // (it also adds `v-pre` to ignore Vue template syntax) md.options.highlight(token.content, 'mermaid', langAttrs) } - `; + + `; } else if (token.info.trim() === 'mermaid') { const key = index; return ` diff --git a/packages/mermaid/src/docs/.vitepress/theme/MermaidRun.vue b/packages/mermaid/src/docs/.vitepress/theme/MermaidRun.vue new file mode 100644 index 0000000000..1f37418fd6 --- /dev/null +++ b/packages/mermaid/src/docs/.vitepress/theme/MermaidRun.vue @@ -0,0 +1,9 @@ + diff --git a/packages/mermaid/src/docs/.vitepress/theme/codapi.css b/packages/mermaid/src/docs/.vitepress/theme/codapi.css new file mode 100644 index 0000000000..aae11ccd51 --- /dev/null +++ b/packages/mermaid/src/docs/.vitepress/theme/codapi.css @@ -0,0 +1,69 @@ +/* editor styles */ +.vp-doc .language-mermaid pre { + padding: 0; +} + +.vp-doc .language-mermaid code { + border-radius: 8px; + padding: 20px 24px; +} + +.vp-doc .language-mermaid code:focus::after { + position: absolute; + bottom: 2px; + right: 8px; + content: 'Ctrl+Enter to run'; + color: var(--vp-code-lang-color); + font-family: var(--vp-font-family-base); + font-size: 12px; + font-weight: 500; +} + +/* widget styles */ +codapi-snippet { + display: block; +} + +codapi-toolbar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 1em; + margin-bottom: 1em; +} +codapi-toolbar button { + font-size: 1em; + font-weight: 500; + color: var(--vp-c-brand-1); + text-decoration: none; + text-underline-offset: 2px; + transition: color 0.25s, opacity 0.25s; +} +codapi-toolbar button::after { + content: ' ▶'; +} +.vp-doc codapi-toolbar a { + text-decoration: none; +} + +codapi-status { + display: block; + white-space: nowrap; +} + +.vp-doc codapi-ref a { + color: var(--vp-c-text-1); + font-weight: 400; + text-decoration: underline; +} + +codapi-output { + position: relative; + display: block; +} +codapi-output[hidden] { + display: none; +} +codapi-output a[href='#close'] { + display: none; +} diff --git a/packages/mermaid/src/docs/.vitepress/theme/codapi.ts b/packages/mermaid/src/docs/.vitepress/theme/codapi.ts new file mode 100644 index 0000000000..cb407f1ebd --- /dev/null +++ b/packages/mermaid/src/docs/.vitepress/theme/codapi.ts @@ -0,0 +1,50 @@ +// Codapi execution engine for Mermaid. + +import mermaid from 'mermaid'; + +// exec executes a mermaid code snippet. +const exec = async (req) => { + try { + const start = new Date().valueOf(); + const res = await render(req.files['']); + const elapsed = new Date().valueOf() - start; + return { + ok: true, + duration: elapsed, + stdout: res, + stderr: '', + }; + } catch (exc) { + return { + ok: false, + duration: 0, + stdout: '', + stderr: exc.toString(), + }; + } +}; + +// render renders a mermaid diagram according to the spec. +const render = async (spec) => { + const id = 'mermaid-' + hashCode(spec); + const { svg } = await mermaid.render(id, spec); + return svg; +}; + +// hashCode calculates a hashcode for a string. +const hashCode = (s) => { + return s.split('').reduce(function (a, b) { + a = (a << 5) - a + b.charCodeAt(0); + return a & a; + }, 0); +}; + +if (!import.meta.env.SSR) { + // register mermaid execution engine in codapi (client-only). + import('@antonz/codapi/dist/snippet.mjs'); + window.codapi = window.codapi ?? {}; + window.codapi.engines = { + ...window.codapi.engines, + ...{ mermaid: { init: () => {}, exec } }, + }; +} diff --git a/packages/mermaid/src/docs/.vitepress/theme/index.ts b/packages/mermaid/src/docs/.vitepress/theme/index.ts index 3ebb7614a1..d84db4707d 100644 --- a/packages/mermaid/src/docs/.vitepress/theme/index.ts +++ b/packages/mermaid/src/docs/.vitepress/theme/index.ts @@ -2,6 +2,7 @@ import DefaultTheme from 'vitepress/theme'; import './custom.css'; // @ts-ignore import Mermaid from './Mermaid.vue'; +import MermaidRun from './MermaidRun.vue'; // @ts-ignore import Contributors from '../components/Contributors.vue'; // @ts-ignore @@ -14,6 +15,8 @@ import Theme from 'vitepress/theme'; import '../style/main.css'; import 'uno.css'; import type { EnhanceAppContext } from 'vitepress'; +import './codapi.css'; +import './codapi.js'; export default { ...DefaultTheme, @@ -27,6 +30,7 @@ export default { enhanceApp({ app, router }: EnhanceAppContext) { // register global components app.component('Mermaid', Mermaid); + app.component('MermaidRun', MermaidRun); app.component('Contributors', Contributors); router.onBeforeRouteChange = (to) => { try { diff --git a/packages/mermaid/src/docs/package.json b/packages/mermaid/src/docs/package.json index 4719f53c29..1531ade431 100644 --- a/packages/mermaid/src/docs/package.json +++ b/packages/mermaid/src/docs/package.json @@ -15,6 +15,7 @@ "fetch-contributors": "tsx .vitepress/scripts/fetch-contributors.ts" }, "dependencies": { + "@antonz/codapi": "^0.16.0", "@vueuse/core": "^10.1.0", "jiti": "^1.18.2", "vue": "^3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd01f183f1..c4aa873762 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -421,6 +421,9 @@ importers: packages/mermaid/src/docs: dependencies: + '@antonz/codapi': + specifier: ^0.16.0 + version: 0.16.0 '@vueuse/core': specifier: ^10.1.0 version: 10.1.0(vue@3.3.4) @@ -695,6 +698,10 @@ packages: resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==} dev: true + /@antonz/codapi@0.16.0: + resolution: {integrity: sha512-H6OxJhtMJ9yPXb4YQNG5NIM8+fPzHhtai3s3IfseDL16AfaU4dkd7KL0ToVIKVez3FW63nxJ1EsvIayTxinE+Q==} + dev: false + /@apideck/better-ajv-errors@0.3.6(ajv@8.12.0): resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} engines: {node: '>=10'}