Compare commits

...
Author SHA1 Message Date
Sidharth Vinod 20348cc97c Track events 2022-08-16 00:50:24 +05:30
Sidharth Vinod d092716a93 Extract handlePanZoom out 2022-08-15 23:47:09 +05:30
Sidharth Vinod ec4afcc184 Add Pan Zoom toggle test 2022-08-15 12:56:59 +05:30
Sidharth Vinod a713f34354 Add toggle for pan & zoom 2022-08-15 11:33:20 +05:30
Sidharth Vinod 285da3f63d Fix specPattern 2022-08-13 13:46:01 +05:30
Sidharth Vinod 16ff107b6e Add test retries 2022-08-13 13:41:20 +05:30
Sidharth Vinod cf4cbc4299 Fix flashes 2022-08-13 13:19:23 +05:30
Sidharth Vinod 856bc1ebe3 Add unit tests 2022-08-13 12:58:56 +05:30
Sidharth Vinod 7a785f59be Fix flashes 2022-08-13 12:58:47 +05:30
Sidharth Vinod 32b8bbd3c3 Support hashchange event 2022-08-13 12:52:20 +05:30
Sidharth Vinod cb89087240 Fix tests 2022-08-13 12:39:57 +05:30
Sidharth Vinod da8cdef241 Fix tests 2022-08-13 12:31:55 +05:30
Sidharth Vinod 8c3e92a535 Update snapshots 2022-08-13 11:30:49 +05:30
Sidharth Vinod 20b97490a4 Merge branch 'sidv/panzoom' of https://github.com/mermaid-js/mermaid-live-editor into sidv/panzoom
* 'sidv/panzoom' of https://github.com/mermaid-js/mermaid-live-editor:
  Update snapshots
2022-08-13 11:20:42 +05:30
Sidharth Vinod 27d664c514 Disable debounce in localstorage 2022-08-13 11:20:34 +05:30
Sidharth Vinod 6b6defb3c8 Update snapshots 2022-08-13 00:20:29 +05:30
Sidharth Vinod 06b430b0b8 Disable debounce for tests 2022-08-13 00:11:30 +05:30
Sidharth Vinod 0602dd2027 Disable debounce for tests 2022-08-13 00:02:55 +05:30
Sidharth Vinod 21c9257b92 Cypress parallel 2022-08-12 23:26:52 +05:30
Sidharth Vinod 1505a5e496 Fix editor binding 2022-08-12 23:20:08 +05:30
Sidharth Vinod 1bc0718901 Persist pan & zoom in state 2022-08-12 22:15:36 +05:30
Sidharth Vinod 4441102c66 Add PanZoom 2022-08-12 20:41:27 +05:30
Sidharth VinodandGitHub 69dff7ea08 Merge pull request #956 from mermaid-js/develop
Develop
2022-08-12 15:25:08 +05:30
Sidharth VinodandGitHub c662b35fb3 Merge pull request #953 from mermaid-js/dependabot/npm_and_yarn/develop/vite-3.0.6
chore(deps-dev): bump vite from 3.0.5 to 3.0.6
2022-08-12 14:43:33 +05:30
Sidharth VinodandGitHub fac0817e27 Merge pull request #952 from mermaid-js/dependabot/npm_and_yarn/develop/node-html-parser-5.4.1
chore(deps-dev): bump node-html-parser from 5.3.3 to 5.4.1
2022-08-12 14:43:26 +05:30
Sidharth VinodandGitHub df9ebea1da Merge pull request #954 from mermaid-js/sidv/renderShortcut
fix #914 Add render diagram keyboard shortcut
2022-08-12 14:43:15 +05:30
dependabot[bot]andGitHub fc1121e287 chore(deps-dev): bump vite from 3.0.5 to 3.0.6
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 3.0.5 to 3.0.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v3.0.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 07:02:27 +00:00
dependabot[bot]andGitHub d554791df4 chore(deps-dev): bump node-html-parser from 5.3.3 to 5.4.1
Bumps [node-html-parser](https://github.com/taoqf/node-fast-html-parser) from 5.3.3 to 5.4.1.
- [Release notes](https://github.com/taoqf/node-fast-html-parser/releases)
- [Changelog](https://github.com/taoqf/node-html-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taoqf/node-fast-html-parser/compare/v5.3.3...v5.4.1)

---
updated-dependencies:
- dependency-name: node-html-parser
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 07:02:12 +00:00
Sidharth VinodandGitHub 2b5ddb9891 Merge pull request #928 from mermaid-js/develop
Develop
2022-08-12 11:49:59 +05:30
21 changed files with 299 additions and 135 deletions
+6 -6
View File
@@ -9,6 +9,11 @@ on:
jobs:
cypress-run:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# run 3 copies of the current job in parallel
containers: [1, 2, 3]
steps:
- name: Checkout
@@ -30,12 +35,6 @@ jobs:
node-version: 16
cache: 'yarn'
- name: Lint & Test
run: |
yarn install
yarn lint
yarn test:unit
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
@@ -46,5 +45,6 @@ jobs:
wait-on: 'http://localhost:3000'
record: true
headless: true
parallel: true
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+36
View File
@@ -0,0 +1,36 @@
name: Unit Tests
on:
pull_request:
branches:
- master
- develop
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions/cache@v3
id: yarn-and-build-cache
with:
path: |
build
node_modules
key: ${{ runner.os }}-node_modules-build-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-build-
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
- name: Lint & Test
run: |
yarn install
yarn lint
yarn test:unit
+5 -1
View File
@@ -8,6 +8,10 @@ export default defineConfig({
snapshotFileName: './cypress/snapshots.js',
defaultCommandTimeout: 16000,
requestTimeout: 16000,
retries: {
runMode: 2,
openMode: 0
},
e2e: {
setupNodeEvents(on, config) {
on('task', {
@@ -26,6 +30,6 @@ export default defineConfig({
});
},
baseUrl: 'http://localhost:3000',
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}'
specPattern: 'cypress/e2e/**/*.spec.ts'
}
});
+3 -2
View File
@@ -1,7 +1,9 @@
import { disableDebounce } from './util';
describe('Check actions', () => {
beforeEach(() => {
cy.clearLocalStorage();
cy.visit('/edit');
disableDebounce();
});
it('should update markdown code', () => {
@@ -24,8 +26,7 @@ describe('Check actions', () => {
});
it('should download png and svg', () => {
const now = new Date(2022, 0, 1).getTime();
cy.clock(now);
cy.clock(new Date(2022, 0, 1).getTime());
const downloadsFolder = Cypress.config('downloadsFolder');
const verifyFileSize = (fileType: string, size: number) => {
+21 -12
View File
@@ -1,16 +1,10 @@
describe('Auto sync tests', () => {
const cmd = Cypress.platform === 'darwin' ? 'meta' : 'ctrl';
const getEditor = ({ bottom = true, newline = false } = {}) =>
cy
.get('#editor textarea:first')
.click()
.focused()
.type(`${bottom ? '{pageDown}' : `{${cmd}}`}`)
.type(`${newline ? '{enter}' : `{${cmd}}`}`);
import { getEditor, cmd, disableDebounce } from './util';
describe('Auto sync tests', () => {
beforeEach(() => {
cy.clearLocalStorage();
cy.visit('/');
disableDebounce();
});
it('should dim diagram when code is edited', () => {
@@ -26,7 +20,7 @@ describe('Auto sync tests', () => {
cy.get('#view').should('not.have.class', 'outOfSync');
getEditor().type(' C --> Test');
cy.get('#view').should('have.class', 'outOfSync');
getEditor().type(`{${cmd}}{enter}`);
getEditor().type(`${cmd}{enter}`);
cy.get('#view').should('not.have.class', 'outOfSync');
});
@@ -52,10 +46,10 @@ describe('Auto sync tests', () => {
});
it('supports commenting code out/in', () => {
getEditor().type(`{uparrow}{${cmd}}/`);
getEditor().type(`{uparrow}${cmd}/`);
cy.get('#view').contains('Car').should('not.exist');
getEditor().type(`{uparrow}{${cmd}}/`);
getEditor().type(`{uparrow}${cmd}/`);
cy.get('#view').contains('Car').should('exist');
});
@@ -73,3 +67,18 @@ describe('Auto sync tests', () => {
.should('exist');
});
});
describe.only('Pan and Zoom', () => {
beforeEach(() => {
cy.clearLocalStorage();
cy.visit('/');
disableDebounce();
});
it('should toggle pan and zoom', () => {
cy.get('#svg-pan-zoom-reset-pan-zoom').should('not.exist');
cy.contains('Pan & Zoom').click();
cy.get('#svg-pan-zoom-reset-pan-zoom').should('exist');
cy.contains('Pan & Zoom').click();
cy.get('#svg-pan-zoom-reset-pan-zoom').should('not.exist');
});
});
+7 -4
View File
@@ -1,8 +1,11 @@
import { getEditor, disableDebounce } from './util';
describe('Save History', () => {
beforeEach(() => {
cy.clock();
cy.clearLocalStorage();
cy.visit('/edit');
disableDebounce();
cy.contains('Actions').click();
cy.contains('History').click();
});
@@ -18,14 +21,14 @@ describe('Save History', () => {
expect(str).to.equal('State already saved.');
});
cy.on('window:confirm', () => true);
cy.get('#editor').type(' C --> HistoryTest');
getEditor().type(' C --> HistoryTest');
cy.get('#saveHistory').click();
cy.get('#historyList').find('li').should('have.length', 2);
});
it('should be able to restore and delete', () => {
cy.get('#saveHistory').click();
cy.get('#editor').type(' C --> HistoryTest');
getEditor().type(' C --> HistoryTest');
cy.get('#historyList').find('No items in History').should('not.exist');
cy.get('#historyList').find('li').should('have.length', 1);
cy.contains('HistoryTest');
@@ -35,7 +38,7 @@ describe('Save History', () => {
cy.get('#historyList').find('li').should('have.length', 0);
cy.get('#historyList').contains('No items in History');
cy.get('#saveHistory').click();
cy.get('#editor').type(' C --> HistoryTest');
getEditor().type(' C --> HistoryTest');
cy.get('#saveHistory').click();
cy.get('#editor').type('ing');
cy.get('#clearHistory').click();
@@ -48,7 +51,7 @@ describe('Save History', () => {
// TODO: Fix #639
xit('should auto save history', () => {
cy.get('#editor').type(' C --> HistoryTest');
getEditor().type(' C --> HistoryTest');
cy.tick(70000);
cy.contains('Timeline').click();
cy.get('#historyList').find('li').should('have.length', 1);
+5 -8
View File
@@ -1,11 +1,13 @@
import { toBase64 } from 'js-base64';
import { disableDebounce } from './util';
describe('Site Loads', () => {
beforeEach(() => {
cy.clearLocalStorage();
cy.visit('/');
disableDebounce();
});
it('Check Home page load', () => {
cy.visit('/');
cy.url().should('include', '/edit');
cy.contains('History').click();
cy.getLocalStorage('codeStore').snapshot();
@@ -15,12 +17,7 @@ describe('Site Loads', () => {
cy.visit(
'/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBBW0NocmlzdG1hc10gLS0-fEdldCBtb25leXwgQihHbyBzaG9wcGluZylcbiAgICBCIC0tPiBDe0xldCBtZSB0aGlua31cbiAgICBDIC0tPnxPbmV8IERbTGFwdG9wXVxuICAgIEMgLS0-fFR3b3wgRVtpUGhvbmVdXG4gICAgQyAtLT58VGhyZWV8IEZbZmE6ZmEtY2FyIENhcl0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ'
);
cy.url().should(
'include',
'/edit#pako:eNpVkM1qw0AMhF9F6NRC_AI-FBo7zSXQQHLz-iC8cnZJ9oe1TAm2373rmkKrk9B8MwyasAuascRbomjgWisPed6byiQ7iKOhhaJ4m48s4ILn5wz7l2OAwYQYrb-9bvx-haCaTivGIMb6-7JJ1Y__0_MMdXOiKCG2f5XrV5jh0NizyfH_FZM4uz6ansqeio4SVJRa3KHj5MjqXHtaDQrFsGOFZV419zQ-RKHyS0bHqEn4oK2EhDnmMfAOaZRwefoOS0kj_0K1pfwFtx2XbzAdW4g'
);
cy.contains('History').click();
cy.getLocalStorage('codeStore').snapshot();
cy.url().should('include', '/edit#pako:eNp');
});
it('should load sample diagrams when clicked', () => {
@@ -91,6 +88,7 @@ describe('Site Loads', () => {
it('should show troubleshooting steps if loading fails', () => {
cy.visit('/#/edit/eyJjb2RlIjoiZ3JhcGggVERcbiAg');
cy.reload(true);
cy.contains('Please Click here to Raise an issue in github.');
});
@@ -117,7 +115,6 @@ describe('Site Loads', () => {
cy.visit(
'/edit#pako:eNptkU1PwzAMhv9K5BOI9Q9EXBDbJA477YYqITcxndV8QD40weh_Jy1rGR0-OY_tV2_sEyivCSQogzGuGduAtnaixINji0bcf1WVWGfVXdMtx8M1faYm4B8sxR27JLClJd6nwK4VLTlN4bI4jMQd2pLe3C4KFhNNcLQ92jv9ADGLNoTdozc-zIV4ZDsNlud7RtVN7_5Sb_jYrFcN3iN_0pPbEqUZK3QbTP_Ojyv4NdR4bwTHlyMbPcOQ3WJ2CliBpWCRdbnLqFJDOpClGmRJNYauhtr1pS-_6bKMjebkA8hXNJFWgDn5_YdTIFPINDWdb3vu6r8BaWOZRQ'
);
cy.reload();
cy.contains('Animal');
});
});
+11
View File
@@ -0,0 +1,11 @@
export const cmd = `{${Cypress.platform === 'darwin' ? 'meta' : 'ctrl'}}`;
export const getEditor = ({ bottom = true, newline = false } = {}) =>
cy
.get('#editor textarea:first')
.click()
.focused()
.type(`${bottom ? '{pageDown}' : cmd}`)
.type(`${newline ? '{enter}' : cmd}`);
export const disableDebounce = () => cy.setLocalStorage('noDebounce', 'true');
+4 -3
View File
@@ -48,7 +48,7 @@
"husky": "8.0.1",
"jsdom": "20.0.0",
"lint-staged": "13.0.3",
"node-html-parser": "5.3.3",
"node-html-parser": "5.4.1",
"postcss": "8.4.16",
"postcss-load-config": "4.0.1",
"prettier": "2.7.1",
@@ -58,7 +58,7 @@
"tailwindcss": "3.1.8",
"tslib": "2.4.0",
"typescript": "4.7.4",
"vite": "3.0.5",
"vite": "3.0.6",
"vitest": "0.21.1",
"vitest-svelte-kit": "0.0.7"
},
@@ -73,7 +73,8 @@
"monaco-editor": "0.34.0",
"monaco-mermaid": "1.0.6",
"pako": "2.0.4",
"random-word-slugs": "0.1.6"
"random-word-slugs": "0.1.6",
"svg-pan-zoom": "^3.6.1"
},
"lint-staged": {
"*.{ts,svelte,js,css,md,json}": [
+6 -1
View File
@@ -1,10 +1,10 @@
<script lang="ts">
import { browser } from '$app/env';
import Card from '$lib/components/card/card.svelte';
import { krokiRendererUrl, rendererUrl } 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';
@@ -115,19 +115,23 @@
const onCopyClipboard = (event: Event) => {
exportImage(event, clipboardCopy);
void logEvent('copyClipboard');
};
const onDownloadPNG = (event: Event) => {
exportImage(event, downloadImage);
void logEvent('downloadPNG');
};
const onDownloadSVG = () => {
simulateDownload(getFileName('svg'), `data:image/svg+xml;base64,${getBase64SVG()}`);
void logEvent('downloadSVG');
};
const onCopyMarkdown = () => {
(document.getElementById('markdown') as HTMLInputElement).select();
document.execCommand('Copy');
void logEvent('copyMarkdown');
};
let gistURL = '';
@@ -143,6 +147,7 @@
alert('Please enter a Gist URL first');
}
window.location.href = `${window.location.pathname}?gist=${gistURL}`;
void logEvent('loadGist');
};
let iUrl: string;
+14 -7
View File
@@ -6,6 +6,7 @@
import type monaco from 'monaco-editor';
import { createEventDispatcher, onMount } from 'svelte';
import initEditor from 'monaco-mermaid';
import { logEvent } from '$lib/util/stats';
let divEl: HTMLDivElement = null;
let editor: monaco.editor.IStandaloneCodeEditor;
@@ -24,15 +25,18 @@
};
let oldText = text;
$: editor && Monaco?.editor.setModelLanguage(editor.getModel(), language);
$: {
if (text !== oldText) {
const handleTextUpdate = (newText: string) => {
if (newText !== oldText) {
if ($stateStore.updateEditor) {
editor?.setValue(text);
editor?.setValue(newText);
}
oldText = text;
oldText = newText;
}
editor && Monaco?.editor.setModelMarkers(editor.getModel(), 'test', $stateStore.errorMarkers);
}
};
$: handleTextUpdate(text);
themeStore.subscribe(({ isDark }) => {
editor && Monaco?.editor.setTheme(isDark ? 'mermaid-dark' : 'mermaid');
@@ -62,9 +66,9 @@
initEditor(Monaco);
editor = Monaco.editor.create(divEl, editorOptions);
editor.onDidChangeModelContent(() => {
text = editor.getValue();
oldText = editor.getValue();
dispatch('update', {
text
text: oldText
});
});
editor.addAction({
@@ -73,6 +77,9 @@
keybindings: [Monaco.KeyMod.CtrlCmd | Monaco.KeyCode.Enter],
run: function () {
syncDiagram();
void logEvent('renderDiagram', {
method: 'keyboadShortcut'
});
}
});
Monaco?.editor.setTheme($themeStore.isDark ? 'mermaid-dark' : 'mermaid');
+4 -1
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import { updateCode } from '$lib/util/state';
import Card from '$lib/components/card/card.svelte';
import { logEvent } from '$lib/util/stats';
const samples = {
'Flow Chart': `graph TD
@@ -97,8 +98,10 @@
const loadSampleDiagram = (diagramType: string): void => {
updateCode(samples[diagramType], {
updateDiagram: true,
updateEditor: true
updateEditor: true,
resetPanZoom: true
});
void logEvent('loadSampleDiagram', { diagramType });
};
</script>
+67 -6
View File
@@ -1,7 +1,10 @@
<script lang="ts">
import { inputStateStore, stateStore } from '$lib/util/state';
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 { logEvent } from '$lib/util/stats';
let code = '';
let config = '';
@@ -9,7 +12,47 @@
let view: HTMLDivElement;
let error = false;
let outOfSync = false;
let hide = false;
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);
};
const handlePanZoom = (state: State) => {
if (!state.panZoom) {
return;
}
hide = true;
pzoom?.destroy();
pzoom = undefined;
Promise.resolve().then(() => {
const graphDiv = document.getElementById('graph-div');
pzoom = panzoom(graphDiv, {
onPan: handlePanZoomChange,
onZoom: handlePanZoomChange,
controlIconsEnabled: true,
fit: true,
center: true
});
const { pan, zoom } = state;
if (pan !== undefined && zoom !== undefined && Number.isFinite(zoom)) {
pzoom.zoom(zoom);
pzoom.pan(pan);
}
hide = false;
});
};
onMount(() => {
stateStore.subscribe((state) => {
if (state.error !== undefined) {
@@ -24,19 +67,23 @@
}
outOfSync = false;
manualUpdate = true;
if (code === state.code && config === state.mermaid) {
// Do not render if there is no change in Code/Config
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) => {
if (svgCode.length > 0) {
console.log(svgCode);
handlePanZoom(state);
container.innerHTML = svgCode;
const graphDiv = document.getElementById('graph-div');
graphDiv.setAttribute('height', '100%');
graphDiv.style.maxWidth = '100%';
}
});
view.parentElement.scrollTop = scroll;
@@ -51,6 +98,11 @@
error = true;
}
});
window.addEventListener('resize', () => {
if ($stateStore.panZoom && pzoom) {
pzoom.resize();
}
});
});
</script>
@@ -58,16 +110,25 @@
<div class="p-2 text-red-600" id="errorContainer">{$stateStore.error}</div>
{/if}
<div id="view" bind:this={view} class="p-2" class:error class:outOfSync>
<div id="container" bind:this={container} class="flex-1 overflow-auto" />
<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>
<style>
#view {
flex: 1;
}
#container {
transition: visibility 0.3s;
}
.error,
.outOfSync {
opacity: 0.5;
}
.hide {
visibility: hidden;
}
</style>
+3
View File
@@ -39,6 +39,9 @@ export interface State {
updateEditor: boolean;
updateDiagram: boolean;
autoSync: boolean;
panZoom?: boolean;
pan?: { x: number; y: number };
zoom?: number;
loader?: LoaderConfig;
}
+10 -2
View File
@@ -79,7 +79,7 @@ export const stateStore: Readable<ValidatedState> = derived([inputStateStore], (
export const loadState = (data: string): void => {
let state: State;
console.log('Loading', data);
console.log(`Loading '${data}'`);
try {
state = deserializeState(data);
const mermaidConfig: { [key: string]: string } =
@@ -114,7 +114,11 @@ export const updateCodeStore = (newState: Partial<State>): void => {
let prompted = false;
export const updateCode = (
code: string,
{ updateEditor, updateDiagram = false }: { updateEditor: boolean; updateDiagram?: boolean }
{
updateEditor,
updateDiagram = false,
resetPanZoom = false
}: { updateEditor: boolean; updateDiagram?: boolean; resetPanZoom?: boolean }
): void => {
saveStatistics(code);
const lines = (code.match(/\n/g) || '').length + 1;
@@ -132,6 +136,10 @@ export const updateCode = (
}
inputStateStore.update((state) => {
if (resetPanZoom) {
state.pan = undefined;
state.zoom = undefined;
}
return { ...state, code, updateEditor, updateDiagram };
});
};
+9 -6
View File
@@ -33,17 +33,20 @@ const detectType = (text: string): string => {
};
// manual debounce
let timeout;
let timeout: number;
export const saveStatistics = (graph: string): void => {
if (analytics) {
clearTimeout(timeout);
// Only save statistics after a 5 sec delay
timeout = setTimeout(function () {
timeout = window.setTimeout(() => {
const graphType = detectType(graph);
console.debug('ga:', 'send', 'event', 'render', graphType);
void analytics.track('render', {
graphType
});
console.debug(`ga: send event: render ${graphType}`);
void logEvent('render', { graphType });
}, 5000);
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const logEvent = async (name: string, data?: any): Promise<void> => {
await analytics?.track(name, data);
};
+2
View File
@@ -1,6 +1,7 @@
import { writable } from 'svelte/store';
import type { Writable } from 'svelte/store';
import { persist, localStorage } from '@macfja/svelte-persistent-store';
import { logEvent } from './stats';
export interface ThemeConfig {
isDark: boolean;
@@ -33,4 +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 });
};
+2
View File
@@ -24,3 +24,5 @@ export const initHandler = async (): Promise<void> => {
export const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
export const cmdKey = isMac ? 'Cmd' : 'Ctrl';
export const debounceEnabled = window.localStorage.getItem('noDebounce') !== 'true';
+4
View File
@@ -5,10 +5,14 @@
import { loadingStateStore } from '$lib/util/loading';
import { setTheme, themeStore } from '$lib/util/theme';
import { toggleDarkTheme } from '$lib/util/state';
import { initHandler } from '$lib/util/util';
// This can be removed once https://github.com/sveltejs/kit/issues/1612 is fixed.
// Then move it into src and vite will bundle it automatically.
onMount(() => {
window.addEventListener('hashchange', async (ev) => {
await initHandler();
});
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register(`${base}/service-worker.js`, {
+61 -41
View File
@@ -7,7 +7,7 @@
import Card from '$lib/components/card/card.svelte';
import History from '$lib/components/history/history.svelte';
import { updateCode, updateConfig, inputStateStore, stateStore } from '$lib/util/state';
import { cmdKey, initHandler, syncDiagram } from '$lib/util/util';
import { cmdKey, debounceEnabled, initHandler, syncDiagram } from '$lib/util/util';
import { onMount } from 'svelte';
import type { EditorUpdateEvent, State, Tab, DocConfig } from '$lib/types';
import { base } from '$app/paths';
@@ -63,14 +63,15 @@
let text = '';
let docURL = docURLBase;
let language: Languages = 'mermaid';
$: language = languageMap[selectedMode];
$: {
if (selectedMode === 'code') {
const handleModeUpdate = (mode: Modes) => {
if (mode === 'code') {
text = $stateStore.code;
} else {
text = $stateStore.mermaid;
}
}
};
$: language = languageMap[selectedMode];
$: handleModeUpdate(selectedMode);
stateStore.subscribe((state: State) => {
if (state.updateEditor) {
@@ -100,14 +101,26 @@
}
];
const updateHandler = (message: CustomEvent<EditorUpdateEvent>) => {
const code = message.detail.text;
const handleUpdate = (text: string) => {
if (selectedMode === 'code') {
updateCode(code, {
updateCode(text, {
updateEditor: false
});
} else {
updateConfig(code, false);
updateConfig(text, false);
}
};
let debounce: { [key: string]: number } = {};
const updateHandler = ({ detail: { text } }: CustomEvent<EditorUpdateEvent>) => {
console.log({ debounceEnabled });
if (debounceEnabled) {
clearTimeout(debounce[selectedMode]);
debounce[selectedMode] = window.setTimeout(() => {
handleUpdate(text);
}, 300);
} else {
handleUpdate(text);
}
};
@@ -138,34 +151,32 @@
<div class="flex-1 flex overflow-hidden">
<div class="hidden md:flex flex-col" id="editorPane" style="width: 40%">
<Card on:select={tabSelectHandler} {tabs} isCloseable={false} title="Mermaid">
<div slot="actions">
<div class="flex flex-row items-center">
<div class="form-control flex-row items-center">
<label class="cursor-pointer label" for="autoSync">
<span> Auto sync</span>
<input
type="checkbox"
class="toggle {$stateStore.autoSync ? 'btn-secondary' : 'toggle-primary'} ml-1"
id="autoSync"
bind:checked={$inputStateStore.autoSync} />
</label>
</div>
{#if !$stateStore.autoSync}
<button
class="btn btn-secondary btn-xs mr-1"
title="Sync Diagram ({cmdKey} + Enter)"
data-cy="sync"
on:click={syncDiagram}><i class="fas fa-sync" /></button>
{/if}
<button class="btn btn-secondary btn-xs" title="View documentation">
<a target="_blank" href={docURL} data-cy="docs"><i class="fas fa-book mr-1" />Docs</a>
</button>
<div slot="actions" class="flex flex-row items-center">
<div class="form-control flex-row items-center">
<label class="cursor-pointer label" for="autoSync">
<span> Auto sync</span>
<input
type="checkbox"
class="toggle {$stateStore.autoSync ? 'btn-secondary' : 'toggle-primary'} ml-1"
id="autoSync"
bind:checked={$inputStateStore.autoSync} />
</label>
</div>
{#if !$stateStore.autoSync}
<button
class="btn btn-secondary btn-xs mr-1"
title="Sync Diagram ({cmdKey} + Enter)"
data-cy="sync"
on:click={syncDiagram}><i class="fas fa-sync" /></button>
{/if}
<button class="btn btn-secondary btn-xs" title="View documentation">
<a target="_blank" href={docURL} data-cy="docs"><i class="fas fa-book mr-1" />Docs</a>
</button>
</div>
<Editor on:update={updateHandler} {language} bind:text />
<Editor on:update={updateHandler} {language} {text} />
</Card>
<div class="-mt-2">
@@ -177,13 +188,22 @@
<div id="resizeHandler" class="hidden md:block" />
<div class="flex-1 flex flex-col overflow-hidden">
<Card title="Diagram" isCloseable={false}>
<a
href={`${base}/view#${$stateStore.serialized}`}
target="_blank"
slot="actions"
class="btn btn-secondary btn-xs"
title="View diagram in new page"
><i class="fas fa-external-link-alt mr-1" />Full screen</a>
<div slot="actions" class="flex flex-row items-center">
<label class="cursor-pointer label py-0" for="panZoom">
<span>Pan & Zoom</span>
<input
type="checkbox"
class="toggle {$stateStore.panZoom ? 'btn-secondary' : 'toggle-primary'} ml-1"
id="panZoom"
bind:checked={$inputStateStore.panZoom} />
</label>
<a
href={`${base}/view#${$stateStore.serialized}`}
target="_blank"
class="btn btn-secondary btn-xs"
title="View diagram in new page"
><i class="fas fa-external-link-alt mr-1" />Full screen</a>
</div>
<div class="flex-1 overflow-auto">
<View />
+19 -35
View File
@@ -3678,10 +3678,10 @@ node-addon-api@^1.7.1:
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz"
integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==
node-html-parser@5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-5.3.3.tgz#2845704f3a7331a610e0e551bf5fa02b266341b6"
integrity sha512-ncg1033CaX9UexbyA7e1N0aAoAYRDiV8jkTvzEnfd1GDvzFdrsXLzR4p4ik8mwLgnaKP/jyUFWDy9q3jvRT2Jw==
node-html-parser@5.4.1:
version "5.4.1"
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-5.4.1.tgz#c9938b9521ef542c2374e4923078f8f2a365f50d"
integrity sha512-xy/O2wOEBJsIRLs4avwa1lVY7tIpXXOoHHUJLa0GvnoPPqMG1hgBVl1tNI3GHOwRktTVZy+Y6rjghk4B9/NLyg==
dependencies:
css-select "^4.2.1"
he "1.2.0"
@@ -4210,7 +4210,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@8.4.16, postcss@^8.4.16:
postcss@8.4.16, postcss@^8.3.0, postcss@^8.4.14, postcss@^8.4.16, postcss@^8.4.4:
version "8.4.16"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
@@ -4219,15 +4219,6 @@ postcss@8.4.16, postcss@^8.4.16:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.3.0, postcss@^8.4.14, postcss@^8.4.4:
version "8.4.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
@@ -4440,10 +4431,10 @@ robust-predicates@^3.0.0:
resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a"
integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==
rollup@^2.75.6:
version "2.77.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.0.tgz#749eaa5ac09b6baa52acc076bc46613eddfd53f4"
integrity sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==
"rollup@>=2.75.6 <2.77.0 || ~2.77.0":
version "2.77.3"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.3.tgz#8f00418d3a2740036e15deb653bed1a90ee0cc12"
integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
optionalDependencies:
fsevents "~2.3.2"
@@ -4816,6 +4807,11 @@ svelte@3.49.0:
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029"
integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==
svg-pan-zoom@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/svg-pan-zoom/-/svg-pan-zoom-3.6.1.tgz#f880a1bb32d18e9c625d7715350bebc269b450cf"
integrity sha512-JaKkGHHfGvRrcMPdJWkssLBeWqM+Isg/a09H7kgNNajT1cX5AztDTNs+C8UzpCxjCTRrG34WbquwaovZbmSk9g==
svgo@^2.7.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
@@ -5086,27 +5082,15 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
vite@3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.5.tgz#56b8d52e00bbbd5f21d02f0868dc613b3246ecc6"
integrity sha512-bRvrt9Tw8EGW4jj64aYFTnVg134E8hgDxyl/eEHnxiGqYk7/pTPss6CWlurqPOUzqvEoZkZ58Ws+Iu8MB87iMA==
vite@3.0.6, "vite@^2.9.12 || ^3.0.0-0":
version "3.0.6"
resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.6.tgz#08e85ebaa34a3b647cb1365c87675b45f3511be0"
integrity sha512-pjfsWIzfUlQME/VAmU6SsjdHkTt6WAHysuqPkHDcjzNu6IGtxDSZ/VfRYOwHaCqX4M3Ivz0kxuSfAPM6gAIX+w==
dependencies:
esbuild "^0.14.47"
postcss "^8.4.16"
resolve "^1.22.1"
rollup "^2.75.6"
optionalDependencies:
fsevents "~2.3.2"
"vite@^2.9.12 || ^3.0.0-0":
version "3.0.4"
resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.4.tgz#c61688d6b97573e96cf5ac25f2d68597b5ce68e8"
integrity sha512-NU304nqnBeOx2MkQnskBQxVsa0pRAH5FphokTGmyy8M3oxbvw7qAXts2GORxs+h/2vKsD+osMhZ7An6yK6F1dA==
dependencies:
esbuild "^0.14.47"
postcss "^8.4.14"
resolve "^1.22.1"
rollup "^2.75.6"
rollup ">=2.75.6 <2.77.0 || ~2.77.0"
optionalDependencies:
fsevents "~2.3.2"