Diagrams working
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/kit": "next",
|
||||
"@types/mermaid": "^8.2.5",
|
||||
"@typescript-eslint/eslint-plugin": "^4.19.0",
|
||||
"@typescript-eslint/parser": "^4.19.0",
|
||||
"autoprefixer": "^10.2.5",
|
||||
@@ -31,6 +32,7 @@
|
||||
"dependencies": {
|
||||
"@fontsource/fira-mono": "^4.2.2",
|
||||
"@lukeed/uuid": "^2.0.0",
|
||||
"@tailwindcss/forms": "^0.3.2",
|
||||
"cookie": "^0.4.1",
|
||||
"js-base64": "^3.6.0",
|
||||
"mermaid": "^8.9.3",
|
||||
|
||||
@@ -6,15 +6,22 @@
|
||||
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
|
||||
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
|
||||
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
|
||||
import { initEditor } from './util';
|
||||
|
||||
let divEl: HTMLDivElement = null;
|
||||
let editor: monaco.editor.IStandaloneCodeEditor;
|
||||
let Monaco;
|
||||
|
||||
export let text: string;
|
||||
export let language: string;
|
||||
export let editorOptions: monaco.editor.IStandaloneEditorConstructionOptions = {
|
||||
value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
|
||||
language: 'javascript'
|
||||
// automaticLayout: true
|
||||
value: text,
|
||||
language: language
|
||||
};
|
||||
|
||||
$: Monaco?.editor.setModelLanguage(editor.getModel(), language);
|
||||
$: editor?.setValue(text);
|
||||
|
||||
const dispatch = createEventDispatcher<EditorEvents>();
|
||||
|
||||
onMount(async () => {
|
||||
@@ -37,6 +44,8 @@
|
||||
}
|
||||
};
|
||||
Monaco = await import('monaco-editor');
|
||||
initEditor(Monaco);
|
||||
|
||||
// divEl = document.getElementById('editor') as HTMLDivElement;
|
||||
editor = Monaco.editor.create(divEl, editorOptions);
|
||||
editor.onDidChangeModelContent(async () => {
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
export const initEditor = (monaco) => {
|
||||
monaco.languages.register({ id: 'mermaid' });
|
||||
|
||||
// Register a tokens provider for the language
|
||||
monaco.languages.setMonarchTokensProvider('mermaid', {
|
||||
typeKeywords: [
|
||||
'graph',
|
||||
'stateDiagram',
|
||||
'sequenceDiagram',
|
||||
'classDiagram',
|
||||
'pie',
|
||||
'flowchart',
|
||||
'gantt'
|
||||
],
|
||||
keywords: ['patricipant', 'as'],
|
||||
arrows: ['---', '===', '-->', '==>'],
|
||||
|
||||
tokenizer: {
|
||||
root: [
|
||||
[/[{}]/, 'delimiter.bracket'],
|
||||
[/[a-z_$][\w$]*/, { cases: { '@typeKeywords': 'keyword', '@keywords': 'keyword' } }],
|
||||
[/[-=>ox]+/, { cases: { '@arrows': 'transition' } }],
|
||||
[/[\[\{\(}]+.+?[\)\]\}]+/, 'string'],
|
||||
[/\".*\"/, 'string']
|
||||
]
|
||||
},
|
||||
whitespace: [
|
||||
[/[ \t\r\n]+/, 'white'],
|
||||
[/\%\%.*$/, 'comment']
|
||||
]
|
||||
});
|
||||
|
||||
monaco.editor.defineTheme('myCoolTheme', {
|
||||
base: 'vs',
|
||||
inherit: false,
|
||||
rules: [
|
||||
{ token: 'keyword', foreground: '880000', fontStyle: 'bold' },
|
||||
{ token: 'custom-error', foreground: 'ff0000', fontStyle: 'bold' },
|
||||
{ token: 'string', foreground: 'AA8500' },
|
||||
{ token: 'transition', foreground: '008800', fontStyle: 'bold' },
|
||||
{ token: 'delimiter.bracket', foreground: '000000', fontStyle: 'bold' }
|
||||
]
|
||||
});
|
||||
|
||||
// Register a completion item provider for the new language
|
||||
monaco.languages.registerCompletionItemProvider('mermaid', {
|
||||
provideCompletionItems: () => {
|
||||
var suggestions = [
|
||||
{
|
||||
label: 'simpleText',
|
||||
kind: monaco.languages.CompletionItemKind.Text,
|
||||
insertText: 'simpleText'
|
||||
},
|
||||
{
|
||||
label: 'testing',
|
||||
kind: monaco.languages.CompletionItemKind.Keyword,
|
||||
insertText: 'testing(${1:condition})',
|
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
|
||||
},
|
||||
{
|
||||
label: 'ifelse',
|
||||
kind: monaco.languages.CompletionItemKind.Snippet,
|
||||
insertText: ['if (${1:condition}) {', '\t$0', '} else {', '\t', '}'].join('\n'),
|
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||
documentation: 'If-Else Statement'
|
||||
}
|
||||
];
|
||||
return { suggestions: suggestions };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const getResizeHandler = (editor) => {
|
||||
return (node) => editor && editor.layout();
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const errorStore = writable(undefined);
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Mermaid } from 'mermaid';
|
||||
|
||||
let mer: Mermaid;
|
||||
export const getMermaid = async (): Promise<Mermaid> => {
|
||||
if (!mer) {
|
||||
mer = await import('mermaid');
|
||||
}
|
||||
return mer;
|
||||
};
|
||||
@@ -9,7 +9,9 @@ const defaultState: State = {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
mermaid: 'default',
|
||||
mermaid: JSON.stringify({
|
||||
theme: 'default'
|
||||
}),
|
||||
updateEditor: false
|
||||
};
|
||||
|
||||
@@ -17,6 +19,7 @@ export const codeStore = writable(defaultState);
|
||||
|
||||
export const loadState = (data: string): void => {
|
||||
let state: State;
|
||||
// debugger;
|
||||
try {
|
||||
const stateStr = decode(data);
|
||||
console.log('state from url', stateStr);
|
||||
@@ -38,7 +41,7 @@ export const updateCode = (code: string, updateEditor: boolean): void => {
|
||||
});
|
||||
};
|
||||
|
||||
export const updateConfig = (config: any, updateEditor: boolean): void => {
|
||||
export const updateConfig = (config: string, updateEditor: boolean): void => {
|
||||
codeStore.update((state) => {
|
||||
return { ...state, mermaid: config, updateEditor };
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { loadState } from './state';
|
||||
|
||||
export const loadStateFromURL = (): void => {
|
||||
debugger;
|
||||
loadState(window.location.hash);
|
||||
loadState(window.location.hash.slice(1));
|
||||
};
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<script lang="ts">
|
||||
import { errorStore } from '$lib/Util/error';
|
||||
import { getMermaid } from '$lib/Util/mermaid';
|
||||
|
||||
import { codeStore } from '$lib/Util/state';
|
||||
import { onMount } from 'svelte';
|
||||
let container;
|
||||
|
||||
export let code = '';
|
||||
export let errorClass = '';
|
||||
onMount(async () => {
|
||||
const mermaid = await getMermaid();
|
||||
codeStore.subscribe((state) => {
|
||||
try {
|
||||
if (container && state) {
|
||||
// Replacing special characters '<' and '>' with encoded '<' and '>'
|
||||
code = state.code; //.replace(/</g, '<').replace(/>/g, '>');
|
||||
|
||||
container.innerHTML = code;
|
||||
delete container.dataset.processed;
|
||||
mermaid.initialize(Object.assign({}, state.mermaid));
|
||||
mermaid.init(undefined, container);
|
||||
mermaid.render('graph-div', code, insertSvg);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('view fail', e);
|
||||
errorClass = 'error';
|
||||
}
|
||||
});
|
||||
errorStore.subscribe((error) => {
|
||||
if (typeof error === 'undefined') {
|
||||
errorClass = '';
|
||||
} else {
|
||||
errorClass = 'error';
|
||||
console.log('Error: ', error);
|
||||
}
|
||||
});
|
||||
});
|
||||
let insertSvg = function (svgCode, bindFunctions) {};
|
||||
</script>
|
||||
|
||||
<div id="view" class={`p-4 ${errorClass}`}>
|
||||
<div bind:this={container} class="flex-grow overflow-auto" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#view {
|
||||
border: 1px solor darkred;
|
||||
flex: 1;
|
||||
}
|
||||
.error {
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
+76
-17
@@ -1,17 +1,38 @@
|
||||
<script context="module">
|
||||
export const ssr = false;
|
||||
// import mermaid from 'mermaid';
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import Editor from '$lib/Editor/index.svelte';
|
||||
import View from '$lib/View/index.svelte';
|
||||
import Card from '$lib/Card/index.svelte';
|
||||
import Tabs from '$lib/Tabs/index.svelte';
|
||||
import { initURLSubscription, updateCode } from '$lib/Util/state';
|
||||
import { initURLSubscription, updateCode, updateConfig, codeStore } from '$lib/Util/state';
|
||||
import { loadStateFromURL } from '$lib/Util/util';
|
||||
import { errorStore } from '$lib/Util/error';
|
||||
|
||||
let selectedTab = 'code';
|
||||
let selectedMode = 'code';
|
||||
let autoSync = true;
|
||||
const languageMap = {
|
||||
code: 'mermaid',
|
||||
config: 'json'
|
||||
};
|
||||
let text: string = '';
|
||||
let language: 'mermaid' | 'json' = 'mermaid';
|
||||
$: language = languageMap[selectedMode];
|
||||
$: {
|
||||
if ($codeStore.updateEditor) {
|
||||
if (selectedMode === 'code') {
|
||||
text = $codeStore.code;
|
||||
} else {
|
||||
text = $codeStore.mermaid;
|
||||
}
|
||||
}
|
||||
}
|
||||
const tabSelectHandler = (message: CustomEvent<Tab>) => {
|
||||
selectedTab = message.detail.id;
|
||||
$codeStore.updateEditor = true;
|
||||
selectedMode = message.detail.id;
|
||||
};
|
||||
const tabs: Tab[] = [
|
||||
{
|
||||
@@ -24,10 +45,33 @@
|
||||
}
|
||||
];
|
||||
|
||||
const updateHandler = async (message: CustomEvent<EditorUpdateEvent>) => {
|
||||
updateCode(message.detail.text, false);
|
||||
const handleCodeUpdate = (code: string): void => {
|
||||
updateCode(code, false);
|
||||
};
|
||||
|
||||
const handleConfigUpdate = (config: string): void => {
|
||||
updateConfig(config, false);
|
||||
};
|
||||
|
||||
let editorText: string = '';
|
||||
const syncDiagram = () => {
|
||||
try {
|
||||
if (selectedMode === 'code') {
|
||||
handleCodeUpdate(editorText);
|
||||
} else {
|
||||
handleConfigUpdate(editorText);
|
||||
}
|
||||
} catch (e) {
|
||||
errorStore.set(e);
|
||||
}
|
||||
};
|
||||
|
||||
const updateHandler = (message: CustomEvent<EditorUpdateEvent>) => {
|
||||
editorText = message.detail.text;
|
||||
if (autoSync) {
|
||||
syncDiagram();
|
||||
}
|
||||
};
|
||||
loadStateFromURL();
|
||||
initURLSubscription();
|
||||
</script>
|
||||
@@ -36,18 +80,33 @@
|
||||
<title>Edit</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="w-2/5 h-screen flex flex-col gap-6">
|
||||
<Card class="h-1/2">
|
||||
<div slot="title">
|
||||
<Tabs on:select={tabSelectHandler} {tabs} />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="w-2/5 h-screen flex flex-col gap-6">
|
||||
<Card class="h-1/2">
|
||||
<div slot="title">
|
||||
<div class="flex">
|
||||
<div class="flex"><Tabs on:select={tabSelectHandler} {tabs} /></div>
|
||||
<div class="flex-grow" />
|
||||
<div class="flex gap-x-4 text-white">
|
||||
{#if !autoSync}
|
||||
<button on:click={syncDiagram}>↻ Sync</button>
|
||||
{/if}
|
||||
<label for="autoSync">
|
||||
<input type="checkbox" name="autoSync" bind:checked={autoSync} />
|
||||
Auto
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if selectedTab == 'code'}
|
||||
<Editor on:update={updateHandler} />
|
||||
{:else}
|
||||
<Editor on:update={updateHandler} />
|
||||
{/if}
|
||||
</Card>
|
||||
<Editor on:update={updateHandler} {language} {text} />
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card class="h-1/3" />
|
||||
<div class="w-3/5 h-screen">
|
||||
<Card class="h-full">
|
||||
<div slot="title" class="text-white">Diagram</div>
|
||||
<View /></Card
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+10
-2
@@ -7,12 +7,20 @@ const config = {
|
||||
preprocess: [
|
||||
preprocess({
|
||||
postcss: true
|
||||
}),
|
||||
})
|
||||
],
|
||||
|
||||
kit: {
|
||||
// hydrate the <div id="svelte"> element in src/app.html
|
||||
target: '#svelte'
|
||||
target: '#svelte',
|
||||
vite: {
|
||||
// ssr: {
|
||||
// noExternal: []
|
||||
// },
|
||||
optimizeDeps: {
|
||||
include: ['mermaid']
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+11
-11
@@ -1,26 +1,26 @@
|
||||
const { tailwindExtractor } = require("tailwindcss/lib/lib/purgeUnusedStyles");
|
||||
const { tailwindExtractor } = require('tailwindcss/lib/lib/purgeUnusedStyles');
|
||||
|
||||
module.exports = {
|
||||
mode: "aot",
|
||||
mode: 'aot',
|
||||
purge: {
|
||||
content: [
|
||||
"./src/**/*.{html,js,svelte,ts}",
|
||||
],
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
options: {
|
||||
defaultExtractor: (content) => [
|
||||
// If this stops working, please open an issue at https://github.com/svelte-add/tailwindcss/issues rather than bothering Tailwind Labs about it
|
||||
...tailwindExtractor(content),
|
||||
// Match Svelte class: directives (https://github.com/tailwindlabs/tailwindcss/discussions/1731)
|
||||
...[...content.matchAll(/(?:class:)*([\w\d-/:%.]+)/gm)].map(([_match, group, ..._rest]) => group),
|
||||
],
|
||||
...[...content.matchAll(/(?:class:)*([\w\d-/:%.]+)/gm)].map(
|
||||
([_match, group, ..._rest]) => group
|
||||
)
|
||||
]
|
||||
},
|
||||
safelist: [/^svelte-[\d\w]+$/],
|
||||
safelist: [/^svelte-[\d\w]+$/]
|
||||
},
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {}
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
extend: {}
|
||||
},
|
||||
plugins: [],
|
||||
plugins: [require('@tailwindcss/forms')]
|
||||
};
|
||||
|
||||
@@ -127,6 +127,13 @@
|
||||
source-map "^0.7.3"
|
||||
svelte-hmr "^0.14.2"
|
||||
|
||||
"@tailwindcss/forms@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.3.2.tgz#e28c4514a53e69f725416a5a2a6d0f221683f069"
|
||||
integrity sha512-aj2/rJsGb2whAZ/BQWHWWQRSbhH0r/l1ozOByiv+ZNjBD84GMvb5dhAyfpeasFky+EJrAwX5eaqft8NQMZFWvA==
|
||||
dependencies:
|
||||
mini-svg-data-uri "^1.2.3"
|
||||
|
||||
"@trysound/sax@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
|
||||
@@ -137,6 +144,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
|
||||
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
|
||||
|
||||
"@types/mermaid@^8.2.5":
|
||||
version "8.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/mermaid/-/mermaid-8.2.5.tgz#85ef5be8a1532c0f596a920972a6242f009a6ce8"
|
||||
integrity sha512-sVKakt9BN2T2qaEHsmQPtV77QAyu5kZh0CErCEaUW4ThBn4VJ47xYuLuvJttmeuSeKfdP/ACi5h184H4gWt4gA==
|
||||
|
||||
"@types/node@*":
|
||||
version "15.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.2.tgz#51e9c0920d1b45936ea04341aa3e2e58d339fb67"
|
||||
@@ -1765,6 +1777,11 @@ min-indent@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||
|
||||
mini-svg-data-uri@^1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.2.3.tgz#e16baa92ad55ddaa1c2c135759129f41910bc39f"
|
||||
integrity sha512-zd6KCAyXgmq6FV1mR10oKXYtvmA9vRoB6xPSTUJTbFApCtkefDnYueVR1gkof3KcdLZo1Y8mjF2DFmQMIxsHNQ==
|
||||
|
||||
minify@^4.1.1:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/minify/-/minify-4.1.3.tgz#58467922d14303f55a3a28fa79641371955b8fbd"
|
||||
|
||||
Reference in New Issue
Block a user