Skip to content

Commit

Permalink
Diagrams working
Browse files Browse the repository at this point in the history
  • Loading branch information
sidharthv96 committed May 10, 2021
1 parent f1558d4 commit 1b94a2c
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 37 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
15 changes: 12 additions & 3 deletions src/lib/Editor/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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 () => {
Expand Down
75 changes: 75 additions & 0 deletions src/lib/Editor/util.js
Original file line number Diff line number Diff line change
@@ -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();
};
3 changes: 3 additions & 0 deletions src/lib/Util/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { writable } from 'svelte/store';

export const errorStore = writable(undefined);
9 changes: 9 additions & 0 deletions src/lib/Util/mermaid.ts
Original file line number Diff line number Diff line change
@@ -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;
};
7 changes: 5 additions & 2 deletions src/lib/Util/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ const defaultState: State = {
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
`,
mermaid: 'default',
mermaid: JSON.stringify({
theme: 'default'
}),
updateEditor: false
};

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);
Expand All @@ -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 };
});
Expand Down
3 changes: 1 addition & 2 deletions src/lib/Util/util.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { loadState } from './state';

export const loadStateFromURL = (): void => {
debugger;
loadState(window.location.hash);
loadState(window.location.hash.slice(1));
};
54 changes: 54 additions & 0 deletions src/lib/View/index.svelte
Original file line number Diff line number Diff line change
@@ -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 '&lt;' and '&gt;'
code = state.code; //.replace(/</g, '&lt;').replace(/>/g, '&gt;');
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>
93 changes: 76 additions & 17 deletions src/routes/edit.svelte
Original file line number Diff line number Diff line change
@@ -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[] = [
{
Expand All @@ -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>
Expand All @@ -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>
12 changes: 10 additions & 2 deletions svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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']
}
}
}
};

Expand Down
Loading

0 comments on commit 1b94a2c

Please sign in to comment.