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