Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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:
|
||||
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 }}
|
||||
|
||||
@@ -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',
|
||||
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'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
"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}": [
|
||||
|
||||
@@ -24,15 +24,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 +65,9 @@
|
||||
initEditor(Monaco);
|
||||
editor = Monaco.editor.create(divEl, editorOptions);
|
||||
editor.onDidChangeModelContent(() => {
|
||||
text = editor.getValue();
|
||||
oldText = editor.getValue();
|
||||
dispatch('update', {
|
||||
text
|
||||
text: oldText
|
||||
});
|
||||
});
|
||||
editor.addAction({
|
||||
|
||||
@@ -97,7 +97,8 @@
|
||||
const loadSampleDiagram = (diagramType: string): void => {
|
||||
updateCode(samples[diagramType], {
|
||||
updateDiagram: true,
|
||||
updateEditor: true
|
||||
updateEditor: true,
|
||||
resetPanZoom: true
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<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';
|
||||
|
||||
let code = '';
|
||||
let config = '';
|
||||
@@ -9,7 +11,46 @@
|
||||
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 });
|
||||
}, 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 +65,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 +96,11 @@
|
||||
error = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener('resize', () => {
|
||||
if ($stateStore.panZoom && pzoom) {
|
||||
pzoom.resize();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -58,16 +108,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>
|
||||
|
||||
Vendored
+3
@@ -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
@@ -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 };
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
@@ -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 />
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user