Compare commits

...
Author SHA1 Message Date
Sidharth Vinod 2922ae71db chore: Update favicon 2022-10-18 10:33:52 +05:30
Sidharth Vinod 1f3c74ae19 Merge branch 'sidv/mindmap' of https://github.com/mermaid-js/mermaid-live-editor into sidv/mindmap
* 'sidv/mindmap' of https://github.com/mermaid-js/mermaid-live-editor:
  Update Browserslist
2022-10-17 14:11:35 +05:30
Sidharth Vinod 433fd4d045 chore: ENV types, mindmap rc4 2022-10-17 14:11:26 +05:30
sidharthv96 814ce1aee3 Update Browserslist 2022-10-17 07:00:59 +00:00
Sidharth Vinod ce0517b782 Merge branch 'develop' into sidv/mindmap
* develop:
  Update Browserslist
  Fix an issue where the image is jpg format on mermaid.ink
2022-10-17 12:29:46 +05:30
Sidharth VinodandGitHub 019542d1e8 Merge pull request #1061 from jihchi/patch-2
Fix an issue where the image is jpg format on mermaid.ink
2022-10-17 12:28:05 +05:30
sidharthv96 260d4970ae Update Browserslist 2022-10-17 06:31:20 +00:00
Sidharth Vinod 7f22aea3eb Async statestore, Update mermaid version 2022-10-17 12:00:02 +05:30
jihchi 988eba06d9 Update Browserslist 2022-10-15 08:55:19 +00:00
Jihchi Lee f3ab245ef1 Fix an issue where the image is jpg format on mermaid.ink 2022-10-15 11:54:10 +03:00
Sidharth Vinod b90cf45eff 9.2.0-rc5 2022-10-12 13:08:58 +05:30
Sidharth Vinod 020075da92 feat: lazy load 2022-10-12 12:26:04 +05:30
Sidharth Vinod de41008284 feat: Add lazyload 2022-10-11 13:49:20 +05:30
Sidharth VinodandGitHub 1ea94189d1 Merge pull request #1058 from mermaid-js/renovate/all-minor-patch
chore(deps): update all non-major dependencies (minor)
2022-10-10 20:48:03 +08:00
renovate[bot]andGitHub 68e5d1e53c chore(deps): update all non-major dependencies 2022-10-10 12:32:28 +00:00
Sidharth VinodandGitHub a7ee019c5d Merge pull request #1057 from mermaid-js/renovate/patch-all-minor-patch
chore(deps): update all non-major dependencies (patch)
2022-10-10 20:31:21 +08:00
renovate[bot]andGitHub 2c26f2dfd5 chore(deps): update all non-major dependencies 2022-10-10 10:39:06 +00:00
Sidharth VinodandGitHub 8c562d18f2 Merge branch 'master' into develop 2022-10-07 19:07:54 +08:00
Sidharth VinodandGitHub 7a372eaf6b Merge pull request #1053 from mermaid-js/renovate/all-minor-patch
chore(deps): update all non-major dependencies (minor)
2022-10-07 19:07:17 +08:00
Sidharth Vinod dbfcd13fc5 chore: Remove stability days from renovate 2022-10-07 19:04:05 +08:00
renovate[bot] 0325b5a99c Update Browserslist 2022-10-07 11:01:17 +00:00
renovate[bot]andGitHub d44d591601 chore(deps): update all non-major dependencies 2022-10-07 11:00:13 +00:00
Sidharth VinodandGitHub f3792a39da Merge pull request #1052 from mermaid-js/renovate/patch-all-minor-patch
chore(deps): update all non-major dependencies (patch)
2022-10-03 11:01:09 +08:00
renovate[bot] 86bed95297 Update Browserslist 2022-09-26 00:10:23 +00:00
renovate[bot]andGitHub 211af0b8ae chore(deps): update all non-major dependencies 2022-09-26 00:09:00 +00:00
Sidharth VinodandGitHub ecca96d26a Merge pull request #1048 from mermaid-js/renovate/all-minor-patch
chore(deps): update all non-major dependencies (minor)
2022-09-21 16:49:58 +05:30
renovate[bot] 9c98144b71 Update Browserslist 2022-09-21 10:27:34 +00:00
renovate[bot]andGitHub 24070d9415 chore(deps): update all non-major dependencies 2022-09-21 10:26:31 +00:00
Sidharth VinodandGitHub 6f2df5e088 Merge pull request #1051 from mermaid-js/develop
Release
2022-09-20 13:32:30 +05:30
Sidharth VinodandGitHub 5fd3f32d6a Merge branch 'master' into develop 2022-09-20 13:25:41 +05:30
Sidharth VinodandGitHub 44f700e588 Merge pull request #1050 from mermaid-js/sidv/syncMessage
feat: Add out of sync message
2022-09-20 13:24:33 +05:30
sidharthv96 b74e63fa1d Update Browserslist 2022-09-20 07:16:54 +00:00
Sidharth Vinod 85ed4187e8 feat: Add out of sync message 2022-09-20 12:45:38 +05:30
Sidharth Vinod 3f3086dae5 chore(vscode): Ignore develop PRs 2022-09-20 12:20:23 +05:30
Sidharth VinodandGitHub b7140fb2aa Merge pull request #1045 from mermaid-js/renovate/patch-all-minor-patch
chore(deps): update all non-major dependencies (patch)
2022-09-18 21:20:56 +05:30
renovate[bot]andGitHub 5cb868f68e chore(deps): update all non-major dependencies 2022-09-18 10:12:16 +00:00
Sidharth VinodandGitHub 6d428c8734 Merge pull request #1047 from mermaid-js/sidv/browserList
Update Browserlist workflow
2022-09-18 15:40:55 +05:30
Sidharth VinodandGitHub e5bc61a294 Merge branch 'develop' into sidv/browserList 2022-09-18 10:00:40 +05:30
sidharthv96 ef73a1f24f Update Browserslist 2022-09-18 04:28:07 +00:00
Sidharth Vinod 4f1b54b2ab Update Browserlist 2022-09-18 09:56:58 +05:30
Sidharth VinodandGitHub e90c77efc1 Merge pull request #1046 from mermaid-js/renovate/all-minor-patch
chore(deps): update all non-major dependencies (minor)
2022-09-18 09:55:56 +05:30
Sidharth VinodandGitHub 58516c0947 Merge pull request #1044 from mermaid-js/renovate/mermaid-9.x
chore(deps): update dependency @types/mermaid to v9
2022-09-18 09:55:30 +05:30
Sidharth VinodandGitHub 743c3f118d Merge pull request #1043 from mermaid-js/develop
Release
2022-09-18 09:54:58 +05:30
Sidharth Vinod 927e291bf5 Update Browserlist 2022-09-18 09:54:00 +05:30
renovate[bot]andGitHub a88e365f6d chore(deps): update all non-major dependencies 2022-09-18 04:19:00 +00:00
renovate[bot]andGitHub 9620888b08 chore(deps): update dependency @types/mermaid to v9 2022-09-18 04:17:42 +00:00
Sidharth VinodandGitHub 342b29c704 Merge branch 'master' into develop 2022-09-18 09:45:48 +05:30
Sidharth VinodandGitHub 53feec5701 Merge pull request #1041 from aloisklink/chore/update-to-mermaid-v9.1.7
chore(deps): bump mermaid from 9.1.6 to 9.1.7
2022-09-18 09:45:13 +05:30
Sidharth VinodandGitHub cb73944f12 Merge branch 'develop' into chore/update-to-mermaid-v9.1.7 2022-09-18 09:34:03 +05:30
Alois Klink 96cfb4755c chore(deps): bump mermaid from 9.1.6 to 9.1.7
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 9.1.6 to 9.1.7.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Commits](mermaid-js/mermaid@v9.1.6...v9.1.7)
2022-09-17 22:51:20 +01:00
Sidharth VinodandGitHub a7f99c641a Merge pull request #1040 from mermaid-js/develop
Release
2022-09-15 12:50:41 +05:30
Sidharth VinodandGitHub b86b229aff Merge branch 'master' into develop 2022-09-15 12:15:06 +05:30
Sidharth VinodandGitHub a9b50f462b Merge pull request #1039 from mermaid-js/sidv/removeGA
Reduce analytics calls
2022-09-15 12:14:22 +05:30
Sidharth Vinod 5f3b8ddba0 Merge branch 'sidv/removeGA' of https://github.com/mermaid-js/mermaid-live-editor into sidv/removeGA
* 'sidv/removeGA' of https://github.com/mermaid-js/mermaid-live-editor:
2022-09-15 12:11:55 +05:30
Sidharth Vinod 3bef3ba7fd Only log valid diagrams 2022-09-15 12:11:49 +05:30
Sidharth VinodandGitHub 3328e35cfa Merge branch 'develop' into sidv/removeGA 2022-09-15 12:09:19 +05:30
Sidharth Vinod 1b1ed01156 Reduce analytics calls 2022-09-15 12:04:46 +05:30
Sidharth VinodandGitHub ca41deab2a Merge pull request #989 from mermaid-js/sidv/removeGA
Remove Google Analytics
2022-09-14 14:40:56 +05:30
Sidharth Vinod bff3c95c7c Merge branch 'develop' into sidv/removeGA
* develop: (58 commits)
  chore(deps): update all non-major dependencies
  chore(deps): update all non-major dependencies
  chore(deps): update all non-major dependencies to v0.23.2
  chore: Remove commented code
  Apply suggestions from code review
  fix: Error marker bug
  Simplify debounce handling
  chore: Slight CSS spacing adjustments
  chore(deps): update all non-major dependencies
  chore(deps): update dependency node-html-parser to v6
  chore(deps): update dependency font-awesome to v6
  chore(deps): update actions/setup-node action to v3
  fix(deps): pin dependency analytics-plugin-plausible to 0.0.6
  chore(deps): update all non-major dependencies
  chore(deps): update dependency @types/pako to v2
  Disable dependabot for renovate
  chore: Update deps
  Update Browserslist
  chore: Update svelte
  Update svelte
  ...
2022-09-14 14:39:36 +05:30
Sidharth VinodandGitHub 610502502a Merge pull request #1035 from mermaid-js/renovate/all-minor-patch
chore(deps): update all non-major dependencies (minor)
2022-09-13 19:47:07 +05:30
renovate[bot]andGitHub 7c4376b0d0 chore(deps): update all non-major dependencies 2022-09-13 12:18:16 +00:00
Sidharth VinodandGitHub 0ae679ec12 Merge pull request #1034 from mermaid-js/renovate/patch-all-minor-patch
chore(deps): update all non-major dependencies (patch)
2022-09-13 17:47:22 +05:30
renovate[bot]andGitHub e8a3de759d chore(deps): update all non-major dependencies 2022-09-13 07:01:16 +00:00
Sidharth VinodandGitHub ca74cc169b Merge pull request #1032 from mermaid-js/develop
Develop
2022-09-12 10:03:18 +05:30
Sidharth VinodandGitHub 08c27a2500 Merge pull request #1033 from mermaid-js/renovate/patch-all-minor-patch
chore(deps): update all non-major dependencies to v0.23.2 (patch)
2022-09-11 00:40:09 +05:30
renovate[bot]andGitHub 330f02f81b chore(deps): update all non-major dependencies to v0.23.2 2022-09-10 18:52:03 +00:00
Sidharth VinodandGitHub 9f27cb4b65 Merge pull request #1031 from mermaid-js/sidv/optimizeDebounce
Simplify debounce handling
2022-09-11 00:19:53 +05:30
Sidharth Vinod b596c58ca7 chore: Remove commented code 2022-09-10 20:53:34 +05:30
fc533d8e11 Apply suggestions from code review
Co-authored-by: Alois Klink <alois@aloisklink.com>
2022-09-10 20:51:21 +05:30
Sidharth Vinod 01483420c9 Merge branch 'master' into sidv/optimizeDebounce
* master:
  fix: Error marker bug
2022-09-10 14:54:31 +05:30
Sidharth VinodandGitHub 8ded1dc1cb Merge pull request #1030 from mermaid-js/develop
chore: Slight CSS spacing adjustments
2022-09-10 14:30:31 +05:30
Sidharth Vinod 62c760fc70 fix: Error marker bug 2022-09-10 14:24:56 +05:30
Sidharth Vinod 90445dbf46 Simplify debounce handling
Previously events were debounced at source of generation.
Now they are debounced only at effected areas where necessary.
2022-09-10 13:53:03 +05:30
Sidharth VinodandGitHub 21f7e25cc1 Merge branch 'master' into develop 2022-09-09 23:30:58 +05:30
Sidharth Vinod ff9f9b7cf9 chore: Slight CSS spacing adjustments 2022-09-09 23:18:39 +05:30
Sidharth Vinod 4116956469 Remove GA 2022-08-26 23:27:15 +05:30
28 changed files with 827 additions and 769 deletions
+2 -1
View File
@@ -44,6 +44,7 @@ module.exports = {
],
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'es/no-regexp-lookbehind-assertions': 'error'
'es/no-regexp-lookbehind-assertions': 'error',
curly: ['error', 'all']
}
};
-1
View File
@@ -48,4 +48,3 @@ jobs:
parallel: true
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
MERMAID_DISABLE_DEBOUNCE: 'true'
+3 -4
View File
@@ -1,10 +1,9 @@
name: Update Browserslist
on:
workflow_dispatch:
push:
branches:
- develop
branches-ignore:
- 'develop'
- 'master'
jobs:
build:
runs-on: ubuntu-latest
+2 -1
View File
@@ -4,5 +4,6 @@
"vitest.commandLine": "yarn test:unit",
"vitest.enable": true,
"testing.autoRun.mode": "rerun",
"svelte.enable-ts-plugin": true
"svelte.enable-ts-plugin": true,
"githubPullRequests.ignoredPullRequestBranches": ["develop"]
}
+1 -1
View File
@@ -6,7 +6,7 @@
# Stop : press ctrl + c
# or
# docker stop mermaid-live-editor
FROM node:18.9.0 as mermaid-live-editor-builder
FROM node:18.10.0 as mermaid-live-editor-builder
COPY --chown=node:node . /home
WORKDIR /home
RUN yarn install
+4
View File
@@ -9,8 +9,10 @@ describe('Auto sync tests', () => {
it('should dim diagram when code is edited', () => {
cy.contains('Auto sync').click();
cy.get('#view').should('not.have.class', 'outOfSync');
cy.get('#view').should('not.contain.text', 'Diagram out of sync.');
getEditor().type(' C --> Test');
cy.get('#view').should('have.class', 'outOfSync');
cy.get('#view').should('contain.text', 'Diagram out of sync.');
cy.getLocalStorage('codeStore').snapshot();
});
@@ -19,7 +21,9 @@ describe('Auto sync tests', () => {
cy.get('#view').should('not.have.class', 'outOfSync');
getEditor().type(' C --> Test');
cy.get('#view').should('have.class', 'outOfSync');
cy.get('#view').should('contain.text', 'Diagram out of sync.');
getEditor().type(`${cmd}{enter}`);
cy.get('#view').should('not.contain.text', 'Diagram out of sync.');
cy.get('#view').should('not.have.class', 'outOfSync');
});
+22 -23
View File
@@ -5,7 +5,8 @@
"license": "MIT",
"scripts": {
"dev": "vite dev",
"dev:test": "MERMAID_DISABLE_DEBOUNCE=true yarn dev",
"dev:force": "MERMAID_LOCAL=true yarn dev --force",
"dev:test": "yarn dev",
"build": "vite build",
"preview": "vite preview",
"lint": "prettier --check --cache --plugin-search-dir=. .;eslint --ignore-path .gitignore .",
@@ -22,55 +23,53 @@
},
"devDependencies": {
"@cypress/snapshot": "2.1.7",
"@sveltejs/adapter-static": "1.0.0-next.42",
"@sveltejs/kit": "1.0.0-next.480",
"@sveltejs/adapter-static": "1.0.0-next.44",
"@sveltejs/kit": "1.0.0-next.511",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/svelte": "3.2.1",
"@types/mermaid": "8.2.9",
"@testing-library/svelte": "3.2.2",
"@types/pako": "2.0.0",
"@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.36.2",
"@typescript-eslint/parser": "5.36.2",
"@vitest/ui": "0.23.1",
"autoprefixer": "10.4.8",
"@typescript-eslint/eslint-plugin": "5.39.0",
"@typescript-eslint/parser": "5.39.0",
"@vitest/ui": "0.24.0",
"autoprefixer": "10.4.12",
"c8": "7.12.0",
"chai": "4.3.6",
"cssnano": "5.1.13",
"cy-verify-downloads": "0.1.8",
"cypress": "10.7.0",
"cy-verify-downloads": "0.1.11",
"cypress": "10.9.0",
"cypress-localstorage-commands": "2.2.1",
"eslint": "8.23.0",
"eslint": "8.25.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-es": "4.1.0",
"eslint-plugin-postcss-modules": "2.0.0",
"eslint-plugin-svelte3": "4.0.0",
"eslint-plugin-tailwindcss": "3.6.1",
"eslint-plugin-tailwindcss": "3.6.2",
"eslint-plugin-vitest": "0.0.8",
"esserializer": "1.3.2",
"husky": "8.0.1",
"jsdom": "20.0.0",
"jsdom": "20.0.1",
"lint-staged": "13.0.3",
"node-html-parser": "6.0.0",
"postcss": "8.4.16",
"node-html-parser": "6.1.1",
"postcss": "8.4.17",
"postcss-load-config": "4.0.1",
"prettier": "2.7.1",
"prettier-plugin-svelte": "2.7.0",
"prettier-plugin-svelte": "2.8.0",
"svelte": "3.50.1",
"svelte-preprocess": "4.10.7",
"tailwindcss": "3.1.8",
"tslib": "2.4.0",
"typescript": "4.8.3",
"vite": "3.1.0",
"vitest": "0.23.1"
"typescript": "4.8.4",
"vite": "3.1.7",
"vitest": "0.24.0"
},
"dependencies": {
"@analytics/google-analytics": "1.0.3",
"analytics": "0.8.1",
"analytics-plugin-plausible": "0.0.6",
"daisyui": "2.25.0",
"daisyui": "2.31.0",
"js-base64": "3.7.2",
"mermaid": "9.1.6",
"mermaid": "9.2.0-rc6",
"moment": "2.29.4",
"monaco-editor": "0.34.0",
"monaco-mermaid": "1.0.6",
-4
View File
@@ -14,10 +14,6 @@
{
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true
},
{
"matchDatasources": ["npm"],
"stabilityDays": 3
}
],
"dependencyDashboard": true,
+5 -3
View File
@@ -11,7 +11,9 @@
<meta
name="description"
content="Simplify documentation and avoid heavy tools. Open source Visio Alternative. Commonly used for explaining your code! Mermaid is a simple markdown-like script language for generating charts from text via javascript." />
<link rel="icon" type="image/png" href="%sveltekit.assets%/favicon.png" />
<link rel="icon" type="image/png" href="%sveltekit.assets%/favicon.svg" />
<link rel="mask-icon" href="%sveltekit.assets%/favicon.svg" color="#000000" />
<meta name="theme-color" content="#6366F1" />
<link rel="manifest" href="%sveltekit.assets%/manifest.json" />
<link
rel="stylesheet"
@@ -28,8 +30,8 @@
<script>
var require = {
paths: {
vs: "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs",
},
vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs'
}
};
</script>
<script
+14
View File
@@ -0,0 +1,14 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly MERMAID_RENDERER_URL: string;
readonly MERMAID_KROKI_RENDERER_URL: string;
readonly MERMAID_CDN_URL: string;
readonly MERMAID_BASE_URL: string;
readonly MERMAID_LOCAL: boolean;
// more env variables...
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
+16 -17
View File
@@ -1,12 +1,13 @@
<script lang="ts">
import { browser } from '$app/environment';
import Card from '$lib/components/card/card.svelte';
import { krokiRendererUrl, rendererUrl } from '$lib/util/env';
import { env } from '$lib/util/env';
import { pakoSerde } from '$lib/util/serde';
import { stateStore } from '$lib/util/state';
import { logEvent } from '$lib/util/stats';
import { toBase64 } from 'js-base64';
import moment from 'moment';
const { krokiRendererUrl, rendererUrl } = env;
type Exporter = (context: CanvasRenderingContext2D, image: HTMLImageElement) => () => void;
@@ -115,19 +116,19 @@
const onCopyClipboard = (event: Event) => {
exportImage(event, clipboardCopy);
void logEvent('copyClipboard');
logEvent('copyClipboard');
};
const onDownloadPNG = (event: Event) => {
exportImage(event, downloadImage);
void logEvent('download', {
logEvent('download', {
type: 'png'
});
};
const onDownloadSVG = () => {
simulateDownload(getFileName('svg'), `data:image/svg+xml;base64,${getBase64SVG()}`);
void logEvent('download', {
logEvent('download', {
type: 'svg'
});
};
@@ -135,7 +136,7 @@
const onCopyMarkdown = () => {
(document.getElementById('markdown') as HTMLInputElement).select();
document.execCommand('Copy');
void logEvent('copyMarkdown');
logEvent('copyMarkdown');
};
let gistURL = '';
@@ -151,7 +152,7 @@
alert('Please enter a Gist URL first');
}
window.location.href = `${window.location.pathname}?gist=${gistURL}`;
void logEvent('loadGist');
logEvent('loadGist');
};
let iUrl: string;
@@ -166,7 +167,7 @@
isNetlify = true;
}
stateStore.subscribe(({ code, serialized }) => {
iUrl = `${rendererUrl}/img/${serialized}`;
iUrl = `${rendererUrl}/img/${serialized}?type=png`;
svgUrl = `${rendererUrl}/svg/${serialized}`;
krokiUrl = `${krokiRendererUrl}/mermaid/svg/${pakoSerde.serialize(code)}`;
mdCode = `[![](${iUrl})](${window.location.protocol}//${window.location.host}${window.location.pathname}#${serialized})`;
@@ -180,26 +181,24 @@
><i class="far fa-copy mr-2" /> Copy Image to clipboard
</button>
{/if}
<button id="downloadPNG" class="action-btn flex-auto" on:click={onDownloadPNG}>
<button id="downloadPNG" class="action-btn flex-grow" on:click={onDownloadPNG}>
<i class="fas fa-download mr-2" /> PNG
</button>
<button id="downloadSVG" class="action-btn flex-auto" on:click={onDownloadSVG}>
<button id="downloadSVG" class="action-btn flex-grow" on:click={onDownloadSVG}>
<i class="fas fa-download mr-2" /> SVG
</button>
<a target="_blank" href={iUrl}>
<button class="action-btn flex-auto">
<a target="_blank" class="flex-grow" href={iUrl}>
<button class="action-btn w-full">
<i class="fas fa-external-link-alt mr-2" /> PNG
</button>
</a>
<a target="_blank" href={svgUrl}>
<button class="action-btn flex-auto">
<a target="_blank" class="flex-grow" href={svgUrl}>
<button class="action-btn w-full">
<i class="fas fa-external-link-alt mr-2" /> SVG
</button>
</a>
<a target="_blank" href={krokiUrl}>
<button class="action-btn flex-auto">
<a target="_blank" class="flex-grow" href={krokiUrl}>
<button class="action-btn w-full">
<i class="fas fa-external-link-alt mr-2" /> Kroki
</button>
</a>
+10 -27
View File
@@ -7,7 +7,6 @@
import { onMount } from 'svelte';
import initEditor from 'monaco-mermaid';
import { logEvent } from '$lib/util/stats';
import { debounceEnabled } from '$lib/util/env';
let divEl: HTMLDivElement = null;
let editor: monaco.editor.IStandaloneCodeEditor;
@@ -37,10 +36,8 @@
Monaco?.editor.setModelLanguage(editor.getModel(), language);
}
// Display errors if present
if (errorMarkers.length > 0) {
Monaco?.editor.setModelMarkers(editor.getModel(), 'test', errorMarkers);
}
// Display/clear errors
Monaco?.editor.setModelMarkers(editor.getModel(), 'mermaid', errorMarkers);
});
themeStore.subscribe(({ isDark }) => {
@@ -55,31 +52,16 @@
}
};
// Debounce state updates to avoid performance issues
let debounce: { [key: string]: number } = {};
const updateHandler = (newText: string) => {
text = newText;
const mode = $stateStore.editorMode;
if (debounceEnabled) {
clearTimeout(debounce[mode]);
debounce[mode] = window.setTimeout(() => {
handleUpdate(text, mode);
}, 300);
} else {
handleUpdate(text, mode);
}
};
const loadMonaco = async () => {
console.log('Loading Monaco...');
let i = 0;
while (i++ < 500) {
try {
// @ts-ignore : This is a hack to handle a svelte-kit error when importing monaco.
Monaco = window.monaco;
// @ts-ignore : This is a hack to handle a svelte-kit error when importing monaco.
Monaco = window.monaco;
if (Monaco !== undefined) {
return;
} catch {
await new Promise((r) => setTimeout(r, 100));
}
await new Promise((r) => setTimeout(r, 100));
}
alert('Loading Monaco Editor failed. Please try refreshing the page.');
};
@@ -89,7 +71,8 @@
initEditor(Monaco);
editor = Monaco.editor.create(divEl, editorOptions);
editor.onDidChangeModelContent(() => {
updateHandler(editor.getValue());
text = editor.getValue();
handleUpdate(text, $stateStore.editorMode);
});
editor.addAction({
id: 'mermaid-render-diagram',
@@ -97,7 +80,7 @@
keybindings: [Monaco.KeyMod.CtrlCmd | Monaco.KeyCode.Enter],
run: function () {
syncDiagram();
void logEvent('renderDiagram', {
logEvent('renderDiagram', {
method: 'keyboadShortcut'
});
}
+1 -1
View File
@@ -39,7 +39,7 @@
];
</script>
<div class="navbar mb-2 shadow-lg bg-primary">
<div class="navbar shadow-lg bg-primary p-0">
<div class="flex-1 px-2 mx-2">
<span class="text-lg font-bold">
<a href="/">Mermaid<span class="text-xs font-thin">v{version}</span> Live Editor</a>
+1 -1
View File
@@ -100,7 +100,7 @@
updateDiagram: true,
resetPanZoom: true
});
void logEvent('loadSampleDiagram', { diagramType });
logEvent('loadSampleDiagram', { diagramType });
};
</script>
+58 -44
View File
@@ -1,10 +1,11 @@
<script lang="ts">
import { inputStateStore, stateStore, updateCodeStore } from '$lib/util/state';
import { onMount } from 'svelte';
import mermaid from 'mermaid';
import panzoom from 'svg-pan-zoom';
import type { State } from '$lib/types';
import type { State, ValidatedState } from '$lib/types';
import { logEvent } from '$lib/util/stats';
import { cmdKey } from '$lib/util/util';
import { render as renderDiagram } from '$lib/util/mermaid';
let code = '';
let config = '';
@@ -16,16 +17,12 @@
let manualUpdate = true;
let panZoomEnabled = $stateStore.panZoom;
let pzoom: SvgPanZoom.Instance;
let debounce: number;
const handlePanZoomChange = () => {
const pan = pzoom.getPan();
const zoom = pzoom.getZoom();
clearTimeout(debounce);
debounce = window.setTimeout(() => {
updateCodeStore({ pan, zoom });
void logEvent('panZoom');
}, 200);
updateCodeStore({ pan, zoom });
logEvent('panZoom');
};
const handlePanZoom = (state: State) => {
@@ -53,50 +50,61 @@
});
};
onMount(() => {
stateStore.subscribe((state) => {
if (state.error !== undefined) {
error = true;
return;
}
error = false;
try {
if (container && state && (state.updateDiagram || state.autoSync)) {
if (!state.autoSync) {
$inputStateStore.updateDiagram = false;
}
outOfSync = false;
manualUpdate = true;
if (code === state.code && config === state.mermaid && panZoomEnabled === state.panZoom) {
// Do not render if there is no change in Code/Config/PanZoom
return;
}
code = state.code;
config = state.mermaid;
panZoomEnabled = state.panZoom;
const scroll = view.parentElement.scrollTop;
delete container.dataset.processed;
mermaid.initialize(Object.assign({}, JSON.parse(state.mermaid)));
mermaid.render('graph-div', code, (svgCode) => {
const handleStateChange = async (state: ValidatedState) => {
if (state.error !== undefined) {
error = true;
return;
}
error = false;
try {
if (container && state && (state.updateDiagram || state.autoSync)) {
if (!state.autoSync) {
$inputStateStore.updateDiagram = false;
}
outOfSync = false;
manualUpdate = true;
if (code === state.code && config === state.mermaid && panZoomEnabled === state.panZoom) {
// Do not render if there is no change in Code/Config/PanZoom
return;
}
code = state.code;
config = state.mermaid;
panZoomEnabled = state.panZoom;
const scroll = view.parentElement.scrollTop;
delete container.dataset.processed;
await renderDiagram(
Object.assign({}, JSON.parse(state.mermaid)),
code,
'graph-div',
(svgCode, bindFunctions) => {
if (svgCode.length > 0) {
handlePanZoom(state);
container.innerHTML = svgCode;
const graphDiv = document.getElementById('graph-div');
graphDiv.setAttribute('height', '100%');
graphDiv.style.maxWidth = '100%';
if (bindFunctions) {
bindFunctions(graphDiv);
}
}
});
view.parentElement.scrollTop = scroll;
error = false;
} else if (manualUpdate) {
manualUpdate = false;
} else if (code !== state.code || config !== state.mermaid) {
outOfSync = true;
}
} catch (e) {
console.error('view fail', e);
error = true;
}
);
view.parentElement.scrollTop = scroll;
error = false;
} else if (manualUpdate) {
manualUpdate = false;
} else if (code !== state.code || config !== state.mermaid) {
outOfSync = true;
}
} catch (e) {
console.error('view fail', e);
error = true;
}
};
onMount(() => {
stateStore.subscribe(async (state) => {
await handleStateChange(state);
});
window.addEventListener('resize', () => {
if ($stateStore.panZoom && pzoom) {
@@ -110,6 +118,12 @@
<div class="p-2 text-red-600" id="errorContainer">{$stateStore.error}</div>
{/if}
{#if outOfSync}
<div class="absolute w-full p-2 z-10 text-yellow-600 bg-base-100 bg-opacity-80 text-center">
Diagram out of sync. <br />
Press <i class="fas fa-sync" /> (Sync button) or <kbd>{cmdKey} + Enter</kbd> to sync.
</div>
{/if}
<div id="view" bind:this={view} class="p-2 h-full" class:error class:outOfSync>
<div id="container" bind:this={container} class="h-full overflow-auto" class:hide />
</div>
+9 -5
View File
@@ -1,5 +1,9 @@
export const rendererUrl: string =
(import.meta.env.MERMAID_RENDERER_URL as string) ?? 'https://mermaid.ink';
export const krokiRendererUrl: string =
(import.meta.env.MERMAID_KROKI_RENDERER_URL as string) ?? 'https://kroki.io';
export const debounceEnabled: boolean = import.meta.env.MERMAID_DISABLE_DEBOUNCE !== 'true';
export const env = {
rendererUrl: import.meta.env.MERMAID_RENDERER_URL ?? 'https://mermaid.ink',
krokiRendererUrl: import.meta.env.MERMAID_KROKI_RENDERER_URL ?? 'https://kroki.io',
mermaidCDNUrl: import.meta.env.MERMAID_CDN_URL ?? 'https://unpkg.com/@mermaid-js',
mermaidBaseURL: import.meta.env.MERMAID_BASE_URL ?? 'http://localhost:9000',
useLocalMermaid: import.meta.env.MERMAID_LOCAL ?? false,
isDev: import.meta.env.DEV,
baseURL: import.meta.env.BASE_URL
};
+47
View File
@@ -0,0 +1,47 @@
import mermaid from 'mermaid';
// We need to export MermaidConfig and all related types from mermaid.
import type { MermaidConfig } from 'mermaid/dist/config.type';
import { env } from './env';
const { mermaidBaseURL, mermaidCDNUrl, useLocalMermaid } = env;
const getDiagramURL = (name: string, version: string): string => {
if (useLocalMermaid) {
return `${mermaidBaseURL}/${name}-detector.esm.mjs`;
}
return `${mermaidCDNUrl}/${name}@${version}/dist/${name}-detector.esm.mjs`;
};
console.log(mermaid);
const initialize = mermaid.initializeAsync({
logLevel: 0,
lazyLoadedDiagrams: [getDiagramURL('mermaid-mindmap', '9.2.0-rc4')],
loadExternalDiagramsAtStartup: true
});
export const init = async () => {
await initialize;
};
export const render = async (
config: MermaidConfig,
code: string,
id: string,
callback: Parameters<typeof mermaid.render>[2]
): Promise<void> => {
await init();
// Should be able to call this multiple times without any issues.
// await mermaid.initialize({
// ...config,
// lazyLoadedDiagrams: [
// // We should make SRI mandatory for all lazy-loaded diagrams.
// 'https://unpkg.com/@mermaid-js/mermaid-mindmap@9.2.0-rc2/dist/mermaid-mindmap-detector.esm.mjs'
// ]
// });
console.log('Rendering', code);
await mermaid.mermaidAPI.renderAsync(id, code, callback);
};
export const parse = async (code: string): Promise<boolean> => {
await init();
return mermaid.parseAsync(code);
};
+53 -35
View File
@@ -1,13 +1,15 @@
import { writable, get, derived } from 'svelte/store';
import { persist, localStorage } from './persist';
import { saveStatistics } from './stats';
import { saveStatistics, countLines } from './stats';
import { serializeState, deserializeState } from './serde';
import { cmdKey } from './util';
import mermaid from 'mermaid';
import { parse, init } from './mermaid';
import type { Readable } from 'svelte/store';
import type { MarkerData, State, ValidatedState } from '$lib/types';
void init();
export const defaultState: State = {
code: `graph TD
A[Christmas] -->|Get money| B(Go shopping)
@@ -42,41 +44,53 @@ const urlParseFailedState = `graph TD
export const inputStateStore = persist(writable(defaultState), localStorage(), 'codeStore');
// All internal reads should be done via stateStore, but it should not be persisted/shared externally.
export const stateStore: Readable<ValidatedState> = derived([inputStateStore], ([state]) => {
const processed: ValidatedState = {
...state,
export const stateStore: Readable<ValidatedState> = derived(
[inputStateStore],
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
async ([state], set) => {
const processed: ValidatedState = {
...state,
serialized: '',
errorMarkers: [],
error: undefined,
editorMode: state.editorMode ?? 'code'
};
// No changes should be done to fields part of `state`.
try {
processed.serialized = serializeState(state);
await parse(state.code);
JSON.parse(state.mermaid);
} catch (e) {
processed.error = e;
console.error(e);
if (e.hash) {
try {
const marker: MarkerData = {
severity: 8, // Error
startLineNumber: e.hash.loc.first_line,
startColumn: e.hash.loc.first_column,
endLineNumber: e.hash.loc.last_line,
endColumn: (e.hash.loc.last_column as number) + 1,
message: e.str
};
processed.errorMarkers = [marker];
} catch (err) {
console.error('Error without line helper', err);
}
}
}
set(processed);
},
{
...get(inputStateStore),
serialized: '',
errorMarkers: [],
error: undefined,
editorMode: state.editorMode ?? 'code'
};
// No changes should be done to fields part of `state`.
try {
processed.serialized = serializeState(state);
mermaid.parse(state.code);
JSON.parse(state.mermaid);
} catch (e) {
processed.error = e;
console.error(e);
if (e.hash) {
try {
const marker: MarkerData = {
severity: 8, // Error
startLineNumber: e.hash.loc.first_line,
startColumn: e.hash.loc.first_column,
endLineNumber: e.hash.loc.last_line,
endColumn: (e.hash.loc.last_column as number) + 1,
message: e.str
};
processed.errorMarkers = [marker];
} catch (err) {
console.error('Error without line helper', err);
}
}
editorMode: get(inputStateStore).editorMode ?? 'code'
}
return processed;
});
);
export const loadState = (data: string): void => {
let state: State;
@@ -121,8 +135,8 @@ export const updateCode = (
resetPanZoom = false
}: { updateDiagram?: boolean; resetPanZoom?: boolean } = {}
): void => {
const lines = countLines(code);
saveStatistics(code);
const lines = (code.match(/\n/g) || '').length + 1;
if (lines > 50 && !prompted && get(stateStore).autoSync) {
const turnOff = confirm(
@@ -162,9 +176,13 @@ export const toggleDarkTheme = (dark: boolean): void => {
});
};
let urlDebounce: number;
export const initURLSubscription = (): void => {
stateStore.subscribe(({ serialized }) => {
history.replaceState(undefined, undefined, `#${serialized}`);
clearTimeout(urlDebounce);
urlDebounce = window.setTimeout(() => {
history.replaceState(undefined, undefined, `#${serialized}`);
}, 250);
});
};
+19
View File
@@ -0,0 +1,19 @@
import { describe, it, expect } from 'vitest';
import { detectType } from './stats';
describe('diagram detection', () => {
it('should detect diagrams correctly', () => {
expect(
detectType(`%%{{
graph`)
).toBe('graph');
expect(detectType(`gitGraph`)).toBe('gitGraph');
expect(
detectType(`%%{{
flowChart
graph`)
).toBe('flowChart');
expect(detectType(`loki -> thor`)).toBe(undefined);
});
});
+64 -28
View File
@@ -1,25 +1,17 @@
import { browser } from '$app/environment';
import type { AnalyticsInstance } from 'analytics';
export let analytics: AnalyticsInstance;
export const initAnalytics = async (): Promise<void> => {
if (browser && !analytics) {
try {
const { Analytics } = await import('analytics');
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const googleAnalytics = (await import('@analytics/google-analytics')).default;
const plausible = (await import('analytics-plugin-plausible')).default;
const [{ Analytics }, { default: plausible }] = await Promise.all([
import('analytics'),
import('analytics-plugin-plausible')
]);
analytics = Analytics({
app: 'mermaid-live-editor',
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
plugins: [
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
googleAnalytics({
measurementIds: ['UA-153180559-1']
}),
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
plausible({
domain: 'mermaid.live',
hashMode: false,
@@ -35,28 +27,72 @@ export const initAnalytics = async (): Promise<void> => {
}
};
const detectType = (text: string): string => {
return text
export const detectType = (text: string): string => {
const possibleDiagramTypes = [
'classDiagram',
'erDiagram',
'flowChart',
'gantt',
'gitGraph',
'graph',
'journey',
'pie',
'stateDiagram'
];
const firstLine = text
.replace(/^\s*%%.*\n/g, '\n')
.trimStart()
.split(' ')[0];
.split(' ')[0]
.toLowerCase();
const detectedDiagram = possibleDiagramTypes.find((d) => firstLine.includes(d.toLowerCase()));
return detectedDiagram;
};
export const countLines = (code: string): number => {
return (code.match(/\n/g) || '').length + 1;
};
// manual debounce
let timeout: number;
export const saveStatistics = (graph: string): void => {
if (analytics) {
clearTimeout(timeout);
// Only save statistics after a 5 sec delay
timeout = window.setTimeout(() => {
const graphType = detectType(graph);
console.debug(`ga: send event: render ${graphType}`);
void logEvent('render', { graphType });
}, 5000);
const graphType = detectType(graph);
if (!graphType) {
return;
}
const length = countLines(graph);
logEvent('render', { graphType, length });
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const logEvent = async (name: string, data?: any): Promise<void> => {
await analytics?.track(name, data);
const minutesToMilliSeconds = (minutes: number): number => {
return minutes * 60_000;
};
const defaultDelay = minutesToMilliSeconds(1);
const delaysPerEvent = {
render: minutesToMilliSeconds(5),
panZoom: minutesToMilliSeconds(10),
copyClipboard: defaultDelay,
download: defaultDelay,
copyMarkdown: defaultDelay,
loadGist: defaultDelay,
loadSampleDiagram: defaultDelay,
renderDiagram: defaultDelay,
history: defaultDelay,
migration: defaultDelay,
themeChange: defaultDelay
};
export type AnalyticsEvent = keyof typeof delaysPerEvent;
const timeouts: Record<string, number> = {};
// manual debounce to reduce the number of events sent to analytics
export const logEvent = (name: AnalyticsEvent, data?: unknown): void => {
if (!analytics) {
return;
}
const key = data ? JSON.stringify({ name, data }) : name;
if (timeouts[key] === undefined) {
void analytics.track(name, data);
} else {
clearTimeout(timeouts[key]);
}
timeouts[key] = window.setTimeout(() => {
delete timeouts[key];
}, delaysPerEvent[name]);
};
+1 -1
View File
@@ -34,5 +34,5 @@ export const setTheme = (theme: string): void => {
const isDark = darkThemes.includes(theme);
console.log('Setting theme', theme);
themeStore.set({ theme, isDark });
void logEvent('themeChange', { theme, isDark });
logEvent('themeChange', { theme, isDark });
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 491 491" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="M490.16,84.61C490.16,37.912 452.248,0 405.55,0L84.61,0C37.912,0 0,37.912 0,84.61L0,405.55C0,452.248 37.912,490.16 84.61,490.16L405.55,490.16C452.248,490.16 490.16,452.248 490.16,405.55L490.16,84.61Z" style="fill:rgb(255,54,112);"/>
<path d="M407.48,111.18C335.587,108.103 269.573,152.338 245.08,220C220.587,152.338 154.573,108.103 82.68,111.18C80.285,168.229 107.577,222.632 154.74,254.82C178.908,271.419 193.35,298.951 193.27,328.27L193.27,379.13L296.9,379.13L296.9,328.27C296.816,298.953 311.255,271.42 335.42,254.82C382.596,222.644 409.892,168.233 407.48,111.18Z" style="fill:white;fill-rule:nonzero;"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

+1 -6
View File
@@ -3,12 +3,7 @@
"name": "Mermaid Live Editor",
"icons": [
{
"src": "/icon-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/icon-512.png",
"src": "/favicon.png",
"type": "image/png",
"sizes": "512x512"
}
+488 -566
View File
File diff suppressed because it is too large Load Diff