Compare commits
164
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ace89a4f28 | ||
|
|
aadf4ec8dc | ||
|
|
ffdaaa3c5d | ||
|
|
e4d4feaf65 | ||
|
|
50d1ce03ea | ||
|
|
a1687b7da4 | ||
|
|
7f936e9ab5 | ||
|
|
b28fc87b0e | ||
|
|
2be4c64eaf | ||
|
|
289ad5b969 | ||
|
|
4680245695 | ||
|
|
1d5ce4b2a4 | ||
|
|
1652bcfbe4 | ||
|
|
31ab44718e | ||
|
|
506f0f4133 | ||
|
|
9ff8bb54eb | ||
|
|
7c2cb42861 | ||
|
|
c0fbd2e17b | ||
|
|
4ab170dc8b | ||
|
|
96780c6b38 | ||
|
|
acf8e48336 | ||
|
|
3bba5c0ed1 | ||
|
|
2c567ada01 | ||
|
|
47f8c6aa88 | ||
|
|
314ac81046 | ||
|
|
bb1779b41c | ||
|
|
d1f5ff384c | ||
|
|
b8806bf784 | ||
|
|
ce5927c826 | ||
|
|
05f587f4b1 | ||
|
|
f126c9905b | ||
|
|
472f2f5411 | ||
|
|
abec15bfbb | ||
|
|
871a19a8c6 | ||
|
|
464a728ce4 | ||
|
|
a2084bbf42 | ||
|
|
42805e58d5 | ||
|
|
15ad228b6e | ||
|
|
eecb7ca4aa | ||
|
|
5e7143c88d | ||
|
|
36a759887a | ||
|
|
ec203ab582 | ||
|
|
7110beaca0 | ||
|
|
2314e1a85a | ||
|
|
31803eae7e | ||
|
|
15836ace17 | ||
|
|
a7095febbf | ||
|
|
b23719fbb4 | ||
|
|
c681cf60a2 | ||
|
|
bcad69e2d0 | ||
|
|
167093d64d | ||
|
|
b9fe9f3df1 | ||
|
|
dfe32b93c0 | ||
|
|
f76c89ff1f | ||
|
|
07f28f2baf | ||
|
|
814869d4b6 | ||
|
|
9e2b03c1d8 | ||
|
|
7e1957ca13 | ||
|
|
687ac6428b | ||
|
|
45c5958b56 | ||
|
|
15a90149be | ||
|
|
649bfee23c | ||
|
|
113c50e255 | ||
|
|
4804046d9f | ||
|
|
5a8f28b229 | ||
|
|
0e38b66461 | ||
|
|
5ea4267768 | ||
|
|
30651c41de | ||
|
|
2868870065 | ||
|
|
4ed439b3ad | ||
|
|
d2673d5326 | ||
|
|
a14c9a7e9d | ||
|
|
2ecd56fe8a | ||
|
|
41c1ed8c5d | ||
|
|
efdfba2812 | ||
|
|
eb33a59ac2 | ||
|
|
89c64ae0cb | ||
|
|
e094efabf6 | ||
|
|
2b757cc433 | ||
|
|
b890622543 | ||
|
|
cf3457a983 | ||
|
|
40b21f05de | ||
|
|
91fe1911fb | ||
|
|
6fc2968901 | ||
|
|
61fa0bda71 | ||
|
|
55149fa616 | ||
|
|
0dc8582bd6 | ||
|
|
7517614429 | ||
|
|
1cc55e210a | ||
|
|
1f0e6e7a36 | ||
|
|
548f3206ad | ||
|
|
782cf66274 | ||
|
|
21049c7fff | ||
|
|
6b0183fbe9 | ||
|
|
94c4ea3322 | ||
|
|
9ba0b53a10 | ||
|
|
86be314d2c | ||
|
|
07a2bb8ca1 | ||
|
|
d683a80f40 | ||
|
|
6d47808298 | ||
|
|
f9d1c55f25 | ||
|
|
d9b475a82f | ||
|
|
0b938cefa8 | ||
|
|
2637621671 | ||
|
|
44281abb4e | ||
|
|
007e6f1896 | ||
|
|
479fe86ca5 | ||
|
|
deb449cf4f | ||
|
|
ebd7a9cdb4 | ||
|
|
5e5c869ada | ||
|
|
6532a9a947 | ||
|
|
36c16781b5 | ||
|
|
2c4b8246c8 | ||
|
|
cacf434709 | ||
|
|
fa8a261fed | ||
|
|
dab9761e6e | ||
|
|
c32d5e565d | ||
|
|
2328294f1b | ||
|
|
7abb08cdff | ||
|
|
570c2f4c8b | ||
|
|
8c9e29c3da | ||
|
|
5a806c0d56 | ||
|
|
740c9c827e | ||
|
|
2e8ac60684 | ||
|
|
339c023447 | ||
|
|
ca9d6faaed | ||
|
|
40a0c22d56 | ||
|
|
129c296121 | ||
|
|
7491d8fd99 | ||
|
|
3db6543024 | ||
|
|
26afd28a85 | ||
|
|
fbb93ab813 | ||
|
|
2a24199756 | ||
|
|
52afad3e97 | ||
|
|
1810dad5f9 | ||
|
|
b40506bd9f | ||
|
|
dc9cff4a2d | ||
|
|
b4f3e42da3 | ||
|
|
c7e8e8625f | ||
|
|
8e6898b5d5 | ||
|
|
1e5a516679 | ||
|
|
70ed3a4700 | ||
|
|
0fd98ce271 | ||
|
|
4e37ea9c8f | ||
|
|
47bf6b8867 | ||
|
|
cd42d0dee0 | ||
|
|
dc47b749f2 | ||
|
|
830ecaa8af | ||
|
|
0897aca3b9 | ||
|
|
05bcfb13ca | ||
|
|
4de2c97fbe | ||
|
|
2f7b0973fd | ||
|
|
354ae063d7 | ||
|
|
8d727e5cac | ||
|
|
8957627cfc | ||
|
|
626a600dae | ||
|
|
045ab4df22 | ||
|
|
8956201dab | ||
|
|
19a6190b56 | ||
|
|
ffe260893d | ||
|
|
166d08532b | ||
|
|
2acde71f37 | ||
|
|
73fc573a2d | ||
|
|
d5a433bcdc |
@@ -0,0 +1,5 @@
|
|||||||
|
**/node_modules
|
||||||
|
**/.git
|
||||||
|
**/.svelte-kit
|
||||||
|
**/dist
|
||||||
|
**/docs
|
||||||
+3
-2
@@ -7,7 +7,7 @@ module.exports = {
|
|||||||
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
'prettier'
|
'prettier'
|
||||||
],
|
],
|
||||||
plugins: ['svelte3', 'tailwindcss', '@typescript-eslint'],
|
plugins: ['svelte3', 'tailwindcss', '@typescript-eslint', 'es'],
|
||||||
ignorePatterns: [
|
ignorePatterns: [
|
||||||
'docs/*',
|
'docs/*',
|
||||||
'*.cjs',
|
'*.cjs',
|
||||||
@@ -42,6 +42,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||||
'@typescript-eslint/no-unsafe-assignment': 'off'
|
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||||
|
'es/no-regexp-lookbehind-assertions': 'error'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+17
-5
@@ -1,8 +1,20 @@
|
|||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: 'npm'
|
- package-ecosystem: docker
|
||||||
directory: '/'
|
directory: /
|
||||||
target-branch: 'develop'
|
target-branch: develop
|
||||||
schedule:
|
schedule:
|
||||||
interval: 'weekly'
|
interval: weekly
|
||||||
day: 'friday'
|
day: friday
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: /
|
||||||
|
target-branch: develop
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
day: friday
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: /
|
||||||
|
target-branch: develop
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
day: friday
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
cypress-run:
|
cypress-run:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# Update after https://github.com/cypress-io/cypress-docker-images/issues/487
|
||||||
container: cypress/browsers:node14.16.0-chrome90-ff88
|
container: cypress/browsers:node14.16.0-chrome90-ff88
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- develop
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '16'
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -45,6 +46,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
if: ${{ github.ref == 'refs/heads/master' }}
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./docs
|
publish_dir: ./docs
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v4
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
exempt-issue-labels: 'retained'
|
exempt-issue-labels: 'retained'
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
# Stop : press ctrl + c
|
# Stop : press ctrl + c
|
||||||
# or
|
# or
|
||||||
# docker stop mermaid-live-editor
|
# docker stop mermaid-live-editor
|
||||||
FROM node:14.17.0 as mermaid-live-editor-builder
|
FROM node:16.10.0 as mermaid-live-editor-builder
|
||||||
COPY --chown=node:node . /home
|
COPY --chown=node:node . /home
|
||||||
WORKDIR /home
|
WORKDIR /home
|
||||||
RUN yarn install
|
RUN yarn install
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
FROM node:16
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json .
|
||||||
|
COPY yarn.lock .
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
RUN ls
|
||||||
|
CMD ["yarn", "dev"]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[](https://dashboard.cypress.io/projects/2ckppp/runs) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
|
[](https://dashboard.cypress.io/projects/2ckppp/runs) [](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)[](https://app.netlify.com/sites/mermaidjs/deploys)
|
||||||
|
|
||||||
# Contributors are welcome!
|
# Contributors are welcome!
|
||||||
|
|
||||||
@@ -17,14 +17,27 @@ Edit, preview and share mermaid charts/diagrams.
|
|||||||
|
|
||||||
## Live demo
|
## Live demo
|
||||||
|
|
||||||
You can try out a live version [here](https://mermaid-js.github.io/mermaid-live-editor/).
|
You can try out a live version [here](https://mermaid.live/).
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
|
### Run published image
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --publish 8000:80 ghcr.io/mermaid-js/mermaid-live-editor
|
docker run --publish 8000:80 ghcr.io/mermaid-js/mermaid-live-editor
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### To configure renderer URL
|
||||||
|
|
||||||
|
When building, Set the Environment variable MERMAID_RENDERER_URL to the rendering service.
|
||||||
|
Default is `https://mermaid.ink`
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up --build
|
||||||
|
```
|
||||||
|
|
||||||
Then open http://localhost:8000
|
Then open http://localhost:8000
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
@@ -47,6 +60,7 @@ This app is created with Svelte Kit.
|
|||||||
|
|
||||||
## Release
|
## Release
|
||||||
|
|
||||||
When a PR is created targeting master, it will be built and deployed as a beta in http://mermaid-js.github.io/mermaid-live-editor/beta
|
When a PR is created targeting master, it will be built and deployed by Netlify.
|
||||||
|
The URL will be indicated in a Comment in the PR.
|
||||||
|
|
||||||
Once the PR is merged, it will automatically be released.
|
Once the PR is merged, it will automatically be released.
|
||||||
|
|||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
monacoVersion="$(jq -r '.dependencies."monaco-editor"' package.json)"
|
||||||
|
monacoVersion="${monacoVersion:1}"
|
||||||
|
|
||||||
|
if [[ $(uname) == "Darwin" ]];
|
||||||
|
then
|
||||||
|
sed -i '' -E "s/monaco-editor\/[^/]*/monaco-editor\/$monacoVersion/g" ./src/app.html
|
||||||
|
else
|
||||||
|
sed -i'' -E "s/monaco-editor\/[^/]*/monaco-editor\/$monacoVersion/g" ./src/app.html
|
||||||
|
fi
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ describe('Site Loads', () => {
|
|||||||
cy.contains('securityLevel').should('not.exist');
|
cy.contains('securityLevel').should('not.exist');
|
||||||
cy.get('#view').find('img').should('not.exist');
|
cy.get('#view').find('img').should('not.exist');
|
||||||
cy.get('#view').contains('<img');
|
cy.get('#view').contains('<img');
|
||||||
cy.get('#view').contains('src="https://via.placeholder.com/64"');
|
cy.get('#view').contains(`src='https://via.placeholder.com/64'`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow persisting "securityLevel" using confirm dialogue', () => {
|
it('should allow persisting "securityLevel" using confirm dialogue', () => {
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
describe('Test themes', () => {
|
||||||
|
describe('Test light themes', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clearLocalStorage();
|
||||||
|
cy.visit('/edit', {
|
||||||
|
onBeforeLoad(win) {
|
||||||
|
cy.stub(win, 'matchMedia')
|
||||||
|
.callThrough()
|
||||||
|
.withArgs('(prefers-color-scheme: dark)')
|
||||||
|
.returns({
|
||||||
|
matches: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cy.contains('Change Theme').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set light theme as default', () => {
|
||||||
|
cy.contains('light').parent().should('have.class', 'bordered');
|
||||||
|
cy.contains('dark').parent().should('not.have.class', 'bordered');
|
||||||
|
cy.getLocalStorage('themeStore').snapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change themes when clicked', () => {
|
||||||
|
cy.contains('light').parent().should('have.class', 'bordered');
|
||||||
|
cy.contains('cupcake').click();
|
||||||
|
cy.contains('cupcake').parent().should('have.class', 'bordered');
|
||||||
|
cy.contains('light').parent().should('not.have.class', 'bordered');
|
||||||
|
cy.contains('dark').parent().should('not.have.class', 'bordered');
|
||||||
|
cy.getLocalStorage('themeStore').snapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test dark mode', () => {
|
||||||
|
// eslint-disable-next-line mocha/no-hooks-for-single-case
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.clearLocalStorage();
|
||||||
|
cy.visit('/edit', {
|
||||||
|
onBeforeLoad(win) {
|
||||||
|
cy.stub(win, 'matchMedia')
|
||||||
|
.callThrough()
|
||||||
|
.withArgs('(prefers-color-scheme: dark)')
|
||||||
|
.returns({
|
||||||
|
matches: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cy.contains('Change Theme').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set dark theme as default', () => {
|
||||||
|
cy.contains('light').parent().should('not.have.class', 'bordered');
|
||||||
|
cy.contains('dark').parent().should('have.class', 'bordered');
|
||||||
|
cy.getLocalStorage('themeStore').snapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
+25
-1
@@ -16,7 +16,7 @@ module.exports = {
|
|||||||
"1": "{\"code\":\"graph TD\\n A[Party] -->|Get money| B(Go shopping!!)\\n \",\"mermaid\":\"{\\n \\\"theme\\\": \\\"forest\\\",\\n \\\"test\\\": \\\"hello world\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":true,\"loader\":{\"type\":\"files\",\"config\":{\"codeURL\":\"https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/code.mmd\",\"configURL\":\"https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/config.json\"}}}"
|
"1": "{\"code\":\"graph TD\\n A[Party] -->|Get money| B(Go shopping!!)\\n \",\"mermaid\":\"{\\n \\\"theme\\\": \\\"forest\\\",\\n \\\"test\\\": \\\"hello world\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":true,\"loader\":{\"type\":\"files\",\"config\":{\"codeURL\":\"https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/code.mmd\",\"configURL\":\"https://gist.githubusercontent.com/sidharthv96/6268a23e673a533dcb198f241fd7012a/raw/4eb03887e6a41397e80bdcdbf94017c498f8f1e2/config.json\"}}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"__version": "8.3.1",
|
"__version": "8.4.1",
|
||||||
"Auto sync tests": {
|
"Auto sync tests": {
|
||||||
"should dim diagram when code is edited": {
|
"should dim diagram when code is edited": {
|
||||||
"1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\\n C --> Test\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":false,\"updateDiagram\":false}"
|
"1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\\n C --> Test\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":false,\"updateDiagram\":false}"
|
||||||
@@ -24,5 +24,29 @@ module.exports = {
|
|||||||
"should not dim diagram when code is in sync": {
|
"should not dim diagram when code is in sync": {
|
||||||
"1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\\n C --> Testing\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":false}"
|
"1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\\n C --> Testing\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":false}"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Test themes": {
|
||||||
|
"should set light theme as default": {
|
||||||
|
"1": "{\"theme\":\"light\",\"isDark\":false}"
|
||||||
|
},
|
||||||
|
"should change themes when clicked": {
|
||||||
|
"1": "{\"theme\":\"cupcake\",\"isDark\":false}"
|
||||||
|
},
|
||||||
|
"should set dark theme as default": {
|
||||||
|
"1": "{\"theme\":\"dark\",\"isDark\":true}"
|
||||||
|
},
|
||||||
|
"Test light themes": {
|
||||||
|
"should set light theme as default": {
|
||||||
|
"1": "{\"theme\":\"light\",\"isDark\":false}"
|
||||||
|
},
|
||||||
|
"should change themes when clicked": {
|
||||||
|
"1": "{\"theme\":\"cupcake\",\"isDark\":false}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Test dark mode": {
|
||||||
|
"should set dark theme as default": {
|
||||||
|
"1": "{\"theme\":\"dark\",\"isDark\":true}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
version: '3.7'
|
||||||
|
services:
|
||||||
|
mermaid:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
volumes:
|
||||||
|
- ./src:/app/src
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
- 24678:24678
|
||||||
+22
-19
@@ -2,7 +2,7 @@
|
|||||||
"name": "mermaid-live-editor",
|
"name": "mermaid-live-editor",
|
||||||
"version": "2.0.67",
|
"version": "2.0.67",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "svelte-kit dev",
|
"dev": "svelte-kit dev --host 0.0.0.0",
|
||||||
"build": "svelte-kit build",
|
"build": "svelte-kit build",
|
||||||
"preview": "svelte-kit preview",
|
"preview": "svelte-kit preview",
|
||||||
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
|
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
|
||||||
@@ -15,45 +15,48 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cypress/snapshot": "^2.1.7",
|
"@cypress/snapshot": "^2.1.7",
|
||||||
"@sveltejs/adapter-static": "1.0.0-next.17",
|
"@sveltejs/adapter-static": "1.0.0-next.20",
|
||||||
"@sveltejs/kit": "1.0.0-next.147",
|
"@sveltejs/kit": "1.0.0-next.173",
|
||||||
"@types/mermaid": "^8.2.7",
|
"@types/mermaid": "^8.2.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.30.0",
|
"@typescript-eslint/eslint-plugin": "^4.31.2",
|
||||||
"@typescript-eslint/parser": "^4.30.0",
|
"@typescript-eslint/parser": "^4.31.2",
|
||||||
"autoprefixer": "^10.3.3",
|
"autoprefixer": "^10.3.5",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"cssnano": "^5.0.8",
|
"cssnano": "^5.0.8",
|
||||||
"cypress": "8.3.1",
|
"cypress": "8.4.1",
|
||||||
"cypress-localstorage-commands": "^1.5.0",
|
"cypress-localstorage-commands": "^1.5.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-prettier": "^8.1.0",
|
"eslint-config-prettier": "^8.1.0",
|
||||||
"eslint-plugin-cypress": "^2.11.3",
|
"eslint-plugin-cypress": "^2.12.1",
|
||||||
|
"eslint-plugin-es": "^4.1.0",
|
||||||
"eslint-plugin-mocha": "^9.0.0",
|
"eslint-plugin-mocha": "^9.0.0",
|
||||||
"eslint-plugin-postcss-modules": "^1.2.1",
|
"eslint-plugin-postcss-modules": "^1.2.1",
|
||||||
"eslint-plugin-svelte3": "^3.2.0",
|
"eslint-plugin-svelte3": "^3.2.1",
|
||||||
"eslint-plugin-tailwindcss": "^1.14.3",
|
"eslint-plugin-tailwindcss": "^1.15.0",
|
||||||
"husky": "^7.0.2",
|
"husky": "^7.0.2",
|
||||||
"lint-staged": "^11.1.2",
|
"lint-staged": "^11.1.2",
|
||||||
"mocha": "^9.1.1",
|
"mocha": "^9.1.1",
|
||||||
"postcss": "^8.3.6",
|
"node-html-parser": "^4.1.5",
|
||||||
|
"postcss": "^8.3.8",
|
||||||
"postcss-load-config": "^3.1.0",
|
"postcss-load-config": "^3.1.0",
|
||||||
"prettier": "~2.3.2",
|
"prettier": "~2.4.1",
|
||||||
"prettier-plugin-svelte": "^2.4.0",
|
"prettier-plugin-svelte": "^2.4.0",
|
||||||
"svelte": "^3.42.4",
|
"svelte": "^3.43.0",
|
||||||
"svelte-preprocess": "^4.8.0",
|
"svelte-preprocess": "^4.9.5",
|
||||||
"tailwindcss": "^2.2.9",
|
"tailwindcss": "^2.2.15",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"typescript": "^4.4.2"
|
"typescript": "^4.4.3"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@analytics/google-analytics": "^0.5.3",
|
"@analytics/google-analytics": "^0.5.3",
|
||||||
"@macfja/svelte-persistent-store": "^1.2.0",
|
"@macfja/svelte-persistent-store": "^1.2.0",
|
||||||
"analytics": "^0.7.14",
|
"analytics": "^0.7.14",
|
||||||
"js-base64": "^3.6.1",
|
"daisyui": "^1.14.1",
|
||||||
"mermaid": "^8.12.1",
|
"js-base64": "^3.7.2",
|
||||||
|
"mermaid": "git+https://github.com/sidharthv96/mermaid.git#esm",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"monaco-editor": "^0.27.0",
|
"monaco-editor": "^0.28.1",
|
||||||
"random-word-slugs": "^0.0.5"
|
"random-word-slugs": "^0.0.5"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
|||||||
+6
-6
@@ -8,7 +8,7 @@
|
|||||||
name="og:image"
|
name="og:image"
|
||||||
content="https://github.com/mermaid-js/mermaid/raw/develop/img/header.png"
|
content="https://github.com/mermaid-js/mermaid/raw/develop/img/header.png"
|
||||||
/>
|
/>
|
||||||
<link rel="canonical" href="https://mermaid-js.github.io/mermaid-live-editor/" />
|
<link rel="canonical" href="https://mermaid.live" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Simplify documentation and avoid heavy tools. Open source Visio Alternative. Commonly used for explaining your code! Mermaid is a simple markdown-like script language for generating charts from text via javascript."
|
content="Simplify documentation and avoid heavy tools. Open source Visio Alternative. Commonly used for explaining your code! Mermaid is a simple markdown-like script language for generating charts from text via javascript."
|
||||||
@@ -21,27 +21,27 @@
|
|||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.27.0/min/vs/editor/editor.main.min.css"
|
href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.28.1/min/vs/editor/editor.main.min.css"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
/>
|
/>
|
||||||
<script>
|
<script>
|
||||||
var require = {
|
var require = {
|
||||||
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.27.0/min/vs' }
|
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.28.1/min/vs' }
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script
|
<script
|
||||||
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.27.0/min/vs/loader.min.js"
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.28.1/min/vs/loader.min.js"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
></script>
|
></script>
|
||||||
<script
|
<script
|
||||||
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.27.0/min/vs/editor/editor.main.nls.min.js"
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.28.1/min/vs/editor/editor.main.nls.min.js"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
></script>
|
></script>
|
||||||
<script
|
<script
|
||||||
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.27.0/min/vs/editor/editor.main.js"
|
src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.28.1/min/vs/editor/editor.main.js"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
></script>
|
></script>
|
||||||
|
|||||||
+3
-11
@@ -2,17 +2,9 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
.nav-btn {
|
.input {
|
||||||
@apply lg:p-2 py-3 px-0 block border-b-2 border-transparent hover:border-white;
|
@apply flex-1 border-primary border-solid border-2 rounded;
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
@apply bg-indigo-500 hover:bg-indigo-700 rounded px-4 shadow;
|
|
||||||
}
|
}
|
||||||
.action-btn {
|
.action-btn {
|
||||||
@apply rounded p-2 bg-indigo-400 shadow flex-auto text-white hover:bg-indigo-500;
|
@apply btn btn-primary;
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
|
||||||
@apply flex-1 border-indigo-400 border-solid border-2 rounded;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
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 type { State } from '$lib/types';
|
import { rendererUrl } from '$lib/util/env';
|
||||||
import { codeStore } from '$lib/util/state';
|
import { base64State, codeStore } from '$lib/util/state';
|
||||||
import { toBase64 } from 'js-base64';
|
import { toBase64 } from 'js-base64';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
@@ -137,15 +137,15 @@
|
|||||||
if (browser && ['mermaid.live', 'netlify'].some((path) => window.location.host.includes(path))) {
|
if (browser && ['mermaid.live', 'netlify'].some((path) => window.location.host.includes(path))) {
|
||||||
isNetlify = true;
|
isNetlify = true;
|
||||||
}
|
}
|
||||||
codeStore.subscribe((state: State) => {
|
base64State.subscribe((encodedState: string) => {
|
||||||
const stateCopy = JSON.parse(JSON.stringify(state));
|
const stateCopy = JSON.parse(JSON.stringify($codeStore));
|
||||||
if (typeof stateCopy.mermaid === 'string') {
|
if (typeof stateCopy.mermaid === 'string') {
|
||||||
stateCopy.mermaid = JSON.parse(stateCopy.mermaid);
|
stateCopy.mermaid = JSON.parse(stateCopy.mermaid);
|
||||||
}
|
}
|
||||||
const b64Code = toBase64(JSON.stringify(stateCopy), true);
|
const b64Code = toBase64(JSON.stringify(stateCopy), true);
|
||||||
iUrl = `https://mermaid.ink/img/${b64Code}`;
|
iUrl = `${rendererUrl}/img/${b64Code}`;
|
||||||
svgUrl = `https://mermaid.ink/svg/${b64Code}`;
|
svgUrl = `${rendererUrl}/svg/${b64Code}`;
|
||||||
mdCode = `[](${window.location.protocol}//${window.location.host}${window.location.pathname}#${window.location.hash})`;
|
mdCode = `[](${window.location.protocol}//${window.location.host}${window.location.pathname}#${encodedState})`;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -153,39 +153,53 @@
|
|||||||
<div class="flex flex-wrap gap-2 m-2">
|
<div class="flex flex-wrap gap-2 m-2">
|
||||||
{#if isClipboardAvailable()}
|
{#if isClipboardAvailable()}
|
||||||
<button class="action-btn w-full" on:click={onCopyClipboard}
|
<button class="action-btn w-full" on:click={onCopyClipboard}
|
||||||
><i class="far fa-copy" /> Copy Image to clipboard
|
><i class="far fa-copy mr-2" /> Copy Image to clipboard
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
<button class="action-btn flex-auto" on:click={onDownloadPNG}>
|
<button class="action-btn flex-auto" on:click={onDownloadPNG}>
|
||||||
<i class="fas fa-download" /> PNG
|
<i class="fas fa-download mr-2" /> PNG
|
||||||
</button>
|
</button>
|
||||||
<button class="action-btn flex-auto" on:click={onDownloadSVG}>
|
<button class="action-btn flex-auto" on:click={onDownloadSVG}>
|
||||||
<i class="fas fa-download" /> SVG
|
<i class="fas fa-download mr-2" /> SVG
|
||||||
</button>
|
</button>
|
||||||
<button class="action-btn flex-auto">
|
<button class="action-btn flex-auto">
|
||||||
<a target="_blank" href={iUrl}><i class="fas fa-external-link-alt" /> PNG</a>
|
<a target="_blank" href={iUrl}><i class="fas fa-external-link-alt mr-2" /> PNG</a>
|
||||||
</button>
|
</button>
|
||||||
<button class="action-btn flex-auto">
|
<button class="action-btn flex-auto">
|
||||||
<a target="_blank" href={svgUrl}><i class="fas fa-external-link-alt" /> SVG</a>
|
<a target="_blank" href={svgUrl}><i class="fas fa-external-link-alt mr-2" /> SVG</a>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
PNG size
|
PNG size
|
||||||
<input type="radio" value="auto" id="autosize" bind:group={imagemodeselected} />
|
<label for="autosize">
|
||||||
<label for="autosize">Auto</label>
|
<input type="radio" value="auto" id="autosize" bind:group={imagemodeselected} /> Auto
|
||||||
<input type="radio" value="width" id="width-active" bind:group={imagemodeselected} />
|
</label>
|
||||||
<label for="width">Width</label>
|
|
||||||
<input type="radio" value="height" id="height-active" bind:group={imagemodeselected} />
|
<label for="width">
|
||||||
<label for="height">Height</label>
|
<input type="radio" value="width" id="width" bind:group={imagemodeselected} /> Width
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="height">
|
||||||
|
<input type="radio" value="height" id="height" bind:group={imagemodeselected} /> Height
|
||||||
|
</label>
|
||||||
|
|
||||||
{#if imagemodeselected !== 'auto'}
|
{#if imagemodeselected !== 'auto'}
|
||||||
<input id="height" type="number" min="3" max="10000" bind:value={userimagesize} />
|
<input
|
||||||
|
id="height"
|
||||||
|
class="input"
|
||||||
|
type="number"
|
||||||
|
min="3"
|
||||||
|
max="10000"
|
||||||
|
bind:value={userimagesize} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full flex gap-2 items-center">
|
<div class="w-full flex gap-2 items-center">
|
||||||
<input class="input" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
|
<input class="input" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
|
||||||
<label for="markdown">
|
<label for="markdown">
|
||||||
<button class="btn text-white flex-auto" on:click={onCopyMarkdown}> Copy Markdown </button>
|
<button class="btn btn-primary btn-md flex-auto" on:click={onCopyMarkdown}>
|
||||||
|
Copy Markdown
|
||||||
|
</button>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -197,7 +211,7 @@
|
|||||||
bind:value={gistURL}
|
bind:value={gistURL}
|
||||||
placeholder="Enter Gist URL" />
|
placeholder="Enter Gist URL" />
|
||||||
<label for="gist">
|
<label for="gist">
|
||||||
<button class="btn text-white flex-auto" on:click={loadGist}> Load Gist </button>
|
<button class="btn btn-primary btn-md flex-auto" on:click={loadGist}> Load Gist </button>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{#if isNetlify}
|
{#if isNetlify}
|
||||||
|
|||||||
@@ -7,21 +7,22 @@
|
|||||||
export let tabs: Tab[] = [];
|
export let tabs: Tab[] = [];
|
||||||
export let title: string;
|
export let title: string;
|
||||||
$: isOpen = isCloseable ? isOpen : true;
|
$: isOpen = isCloseable ? isOpen : true;
|
||||||
|
$: isTabsShown = isOpen && tabs.length > 0;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="bg-white rounded overflow-hidden shadow m-2 flex-grow flex flex-col">
|
<div class="card rounded overflow-hidden m-2 flex-grow flex flex-col shadow-2xl">
|
||||||
<div
|
<div
|
||||||
class="bg-indigo-400 border-gray-400 p-2 flex-none cursor-pointer"
|
class="bg-primary p-2 {isTabsShown ? 'pb-0' : ''} flex-none cursor-pointer"
|
||||||
on:click={() => (isOpen = !isOpen)}>
|
on:click={() => (isOpen = !isOpen)}>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<Tabs on:select {tabs} bind:isOpen {title} {isCloseable} />
|
<Tabs on:select {tabs} bind:isOpen {title} {isCloseable} />
|
||||||
<div class="flex gap-x-4 items-center text-white">
|
<div class="flex gap-x-4 items-center {isTabsShown ? '-mt-2' : ''}">
|
||||||
<slot name="actions" />
|
<slot name="actions" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if isOpen}
|
{#if isOpen}
|
||||||
<div class="flex-grow overflow-auto" transition:slide>
|
<div class="card-body p-0 flex-grow overflow-auto text-base-content" transition:slide>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -17,25 +17,20 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex cursor-default">
|
<div class="flex cursor-default">
|
||||||
<span class="text-white mr-2 font-semibold" on:click|stopPropagation={() => (isOpen = !isOpen)}>
|
<span class="mr-2 font-semibold" on:click|stopPropagation={() => (isOpen = !isOpen)}>
|
||||||
{#if isCloseable}
|
{#if isCloseable}
|
||||||
<i class="fas fa-chevron-right icon" class:isOpen />
|
<i class="fas fa-chevron-right icon" class:isOpen />
|
||||||
{/if}
|
{/if}
|
||||||
{title}</span>
|
{title}</span>
|
||||||
{#if isOpen && tabs}
|
{#if isOpen && tabs}
|
||||||
<ul class="flex flex-wrap flex-row" transition:fade>
|
<ul class="tabs" transition:fade>
|
||||||
{#each tabs as tab}
|
{#each tabs as tab}
|
||||||
<li class="mr-2 last:mr-0 w-28 h-6 flex-auto text-center">
|
<div
|
||||||
<div
|
class="tab tab-lifted text-primary-content {activeTabID === tab.id ? 'tab-active' : ''}"
|
||||||
class="text cursor-pointer font-semibold min-w-16 w-auto px-2 py-1 -mb-4 rounded-t flex justify-center items-center leading-normal {activeTabID ===
|
on:click|stopPropagation={() => toggleTabs(tab)}>
|
||||||
tab.id
|
<i class="mr-1 {tab.icon}" />
|
||||||
? 'text-indigo-500 bg-white border-white'
|
{tab.title}
|
||||||
: 'text-white bg-indigo-500 border-indigo-500 hover:bg-indigo-600'}"
|
</div>
|
||||||
on:click|stopPropagation={() => toggleTabs(tab)}>
|
|
||||||
<i class="{tab.icon} mr-1" />
|
|
||||||
{tab.title}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { EditorEvents } from '$lib/types';
|
import type { EditorEvents } from '$lib/types';
|
||||||
import { codeStore } from '$lib/util/state';
|
import { codeStore } from '$lib/util/state';
|
||||||
|
import { themeStore } from '$lib/util/theme';
|
||||||
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 './util';
|
import { initEditor } from './util';
|
||||||
@@ -17,7 +18,7 @@
|
|||||||
minimap: {
|
minimap: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
theme: 'mermaidTheme',
|
theme: 'mermaid',
|
||||||
overviewRulerLanes: 0
|
overviewRulerLanes: 0
|
||||||
};
|
};
|
||||||
export let errorMarkers: monaco.editor.IMarkerData[] = [];
|
export let errorMarkers: monaco.editor.IMarkerData[] = [];
|
||||||
@@ -33,6 +34,10 @@
|
|||||||
editor && Monaco?.editor.setModelMarkers(editor.getModel(), 'test', errorMarkers);
|
editor && Monaco?.editor.setModelMarkers(editor.getModel(), 'test', errorMarkers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
themeStore.subscribe(({ isDark }) => {
|
||||||
|
editor && Monaco?.editor.setTheme(isDark ? 'mermaid-dark' : 'mermaid');
|
||||||
|
});
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<EditorEvents>();
|
const dispatch = createEventDispatcher<EditorEvents>();
|
||||||
const loadMonaco = async () => {
|
const loadMonaco = async () => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
@@ -62,7 +67,7 @@
|
|||||||
text
|
text
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Monaco?.editor.setTheme($themeStore.isDark ? 'mermaid-dark' : 'mermaid');
|
||||||
const resizeObserver = new ResizeObserver((entries) => {
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
editor.layout({
|
editor.layout({
|
||||||
height: entries[0].contentRect.height,
|
height: entries[0].contentRect.height,
|
||||||
|
|||||||
@@ -5,73 +5,546 @@
|
|||||||
export const initEditor = (monacoEditor): void => {
|
export const initEditor = (monacoEditor): void => {
|
||||||
monacoEditor.languages.register({ id: 'mermaid' });
|
monacoEditor.languages.register({ id: 'mermaid' });
|
||||||
|
|
||||||
// Register a tokens provider for the language
|
const requirementDiagrams = [
|
||||||
monacoEditor.languages.setMonarchTokensProvider('mermaid', {
|
'requirement',
|
||||||
typeKeywords: [
|
'functionalRequirement',
|
||||||
'graph',
|
'interfaceRequirement',
|
||||||
'stateDiagram',
|
'performanceRequirement',
|
||||||
'sequenceDiagram',
|
'physicalRequirement',
|
||||||
'classDiagram',
|
'designConstraint'
|
||||||
'pie',
|
];
|
||||||
'erDiagram',
|
|
||||||
'flowchart',
|
const keywords: {
|
||||||
'gantt',
|
[key: string]: {
|
||||||
'gitGraph',
|
typeKeywords: string[];
|
||||||
'journey'
|
blockKeywords: string[];
|
||||||
],
|
keywords: string[];
|
||||||
keywords: ['participant', 'as'],
|
};
|
||||||
arrows: ['---', '===', '-->', '==>', '->>', '->'],
|
} = {
|
||||||
tokenizer: {
|
flowchart: {
|
||||||
root: [
|
typeKeywords: ['flowchart', 'flowchart-v2', 'graph'],
|
||||||
[/[{}]/, 'delimiter.bracket'],
|
blockKeywords: ['subgraph', 'end'],
|
||||||
[/[a-z_$][\w$]*/, { cases: { '@typeKeywords': 'keyword', '@keywords': 'keyword' } }],
|
keywords: [
|
||||||
[/[-=>ox]+/, { cases: { '@arrows': 'transition' } }],
|
'TB',
|
||||||
[/[[{(}]+.+?[)\]}]+/, 'string'],
|
'TD',
|
||||||
[/".*"/, 'string']
|
'BT',
|
||||||
|
'RL',
|
||||||
|
'LR',
|
||||||
|
'click',
|
||||||
|
'call',
|
||||||
|
'href',
|
||||||
|
'_self',
|
||||||
|
'_blank',
|
||||||
|
'_parent',
|
||||||
|
'_top',
|
||||||
|
'linkStyle',
|
||||||
|
'style',
|
||||||
|
'classDef',
|
||||||
|
'class',
|
||||||
|
'direction',
|
||||||
|
'interpolate'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
whitespace: [
|
sequenceDiagram: {
|
||||||
[/[ \t\r\n]+/, 'white'],
|
typeKeywords: ['sequenceDiagram'],
|
||||||
[/%%.*$/, 'comment']
|
blockKeywords: ['alt', 'par', 'and', 'loop', 'else', 'end', 'rect', 'opt', 'alt', 'rect'],
|
||||||
|
keywords: [
|
||||||
|
'participant',
|
||||||
|
'as',
|
||||||
|
'Note',
|
||||||
|
'note',
|
||||||
|
'right of',
|
||||||
|
'left of',
|
||||||
|
'over',
|
||||||
|
'activate',
|
||||||
|
'deactivate',
|
||||||
|
'autonumber',
|
||||||
|
'title',
|
||||||
|
'actor'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
classDiagram: {
|
||||||
|
typeKeywords: ['classDiagram', 'classDiagram-v2'],
|
||||||
|
blockKeywords: ['class'],
|
||||||
|
keywords: [
|
||||||
|
'link',
|
||||||
|
'click',
|
||||||
|
'callback',
|
||||||
|
'call',
|
||||||
|
'href',
|
||||||
|
'cssClass',
|
||||||
|
'direction',
|
||||||
|
'TB',
|
||||||
|
'BT',
|
||||||
|
'RL',
|
||||||
|
'LR'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
stateDiagram: {
|
||||||
|
typeKeywords: ['stateDiagram', 'stateDiagram-v2'],
|
||||||
|
blockKeywords: ['state', 'note', 'end'],
|
||||||
|
keywords: ['state', 'as', 'hide empty description', 'direction', 'TB', 'BT', 'RL', 'LR']
|
||||||
|
},
|
||||||
|
erDiagram: {
|
||||||
|
typeKeywords: ['erDiagram'],
|
||||||
|
blockKeywords: [],
|
||||||
|
keywords: []
|
||||||
|
},
|
||||||
|
journey: {
|
||||||
|
typeKeywords: ['journey'],
|
||||||
|
blockKeywords: ['section'],
|
||||||
|
keywords: ['title']
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
typeKeywords: ['info'],
|
||||||
|
blockKeywords: [],
|
||||||
|
keywords: ['showInfo']
|
||||||
|
},
|
||||||
|
gantt: {
|
||||||
|
typeKeywords: ['gantt'],
|
||||||
|
blockKeywords: [],
|
||||||
|
keywords: [
|
||||||
|
'title',
|
||||||
|
'dateFormat',
|
||||||
|
'axisFormat',
|
||||||
|
'todayMarker',
|
||||||
|
'section',
|
||||||
|
'excludes',
|
||||||
|
'inclusiveEndDates'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
requirementDiagram: {
|
||||||
|
typeKeywords: ['requirement', 'requirementDiagram'],
|
||||||
|
blockKeywords: requirementDiagrams.concat('element'),
|
||||||
|
keywords: []
|
||||||
|
},
|
||||||
|
gitGraph: {
|
||||||
|
typeKeywords: ['gitGraph'],
|
||||||
|
blockKeywords: [],
|
||||||
|
keywords: ['commit', 'branch', 'merge', 'reset', 'checkout', 'LR', 'BT']
|
||||||
|
},
|
||||||
|
pie: {
|
||||||
|
typeKeywords: ['pie'],
|
||||||
|
blockKeywords: [],
|
||||||
|
keywords: ['title', 'showData']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register a tokens provider for the mermaid language
|
||||||
|
monacoEditor.languages.setMonarchTokensProvider('mermaid', {
|
||||||
|
...Object.entries(keywords)
|
||||||
|
.map((entry) =>
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.entries(entry[1]).map((deepEntry) => [
|
||||||
|
entry[0] + deepEntry[0][0].toUpperCase() + deepEntry[0].slice(1),
|
||||||
|
deepEntry[1]
|
||||||
|
])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.reduce((overallKeywords, nextKeyword) => ({ ...overallKeywords, ...nextKeyword }), {}),
|
||||||
|
tokenizer: {
|
||||||
|
root: [
|
||||||
|
[/%%(?=.*%%$)/, { token: 'string', nextEmbedded: 'json' }],
|
||||||
|
[/%%$/, { token: 'string', nextEmbedded: '@pop' }],
|
||||||
|
[/^\s*gitGraph/m, 'typeKeyword', 'gitGraph'],
|
||||||
|
[/^\s*info/m, 'typeKeyword', 'info'],
|
||||||
|
[/^\s*pie/m, 'typeKeyword', 'pie'],
|
||||||
|
[/^\s*(flowchart|flowchart-v2|graph)/m, 'typeKeyword', 'flowchart'],
|
||||||
|
[/^\s*sequenceDiagram/, 'typeKeyword', 'sequenceDiagram'],
|
||||||
|
[/^\s*classDiagram(-v2)?/, 'typeKeyword', 'classDiagram'],
|
||||||
|
[/^\s*journey/, 'typeKeyword', 'journey'],
|
||||||
|
[/^\s*gantt/, 'typeKeyword', 'gantt'],
|
||||||
|
[/^\s*stateDiagram(-v2)?/, 'typeKeyword', 'stateDiagram'],
|
||||||
|
[/^\s*erDiagram/, 'typeKeyword', 'erDiagram'],
|
||||||
|
[/^\s*requirement(Diagram)?/, 'typeKeyword', 'requirementDiagram'],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment']
|
||||||
|
],
|
||||||
|
gitGraph: [
|
||||||
|
[/option(?=s)/, { token: 'typeKeyword', next: 'optionsGitGraph' }],
|
||||||
|
[/(^\s*branch|reset|merge|checkout)(.*$)/, ['keyword', 'variable']],
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@gitGraphBlockKeywords': 'typeKeyword',
|
||||||
|
'@gitGraphKeywords': 'keyword'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment'],
|
||||||
|
[/".*?"/, 'string'],
|
||||||
|
[/\^/, 'delimiter.bracket']
|
||||||
|
],
|
||||||
|
optionsGitGraph: [
|
||||||
|
[/s$/, { token: 'typeKeyword', nextEmbedded: 'json', matchOnlyAtLineStart: false }],
|
||||||
|
['end', { token: 'typeKeyword', next: '@pop', nextEmbedded: '@pop' }]
|
||||||
|
],
|
||||||
|
info: [
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@infoBlockKeywords': 'typeKeyword',
|
||||||
|
'@infoKeywords': 'keyword'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
pie: [
|
||||||
|
[/(title)(.*$)/, ['keyword', 'string']],
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@pieBlockKeywords': 'typeKeyword',
|
||||||
|
'@pieKeywords': 'keyword'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/".*?"/, 'string'],
|
||||||
|
[/\s*\d+/, 'number'],
|
||||||
|
[/:/, 'delimiter.bracket'],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment']
|
||||||
|
],
|
||||||
|
flowchart: [
|
||||||
|
[/[ox]?(--+|==+)[ox]/, 'transition'],
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@flowchartBlockKeywords': 'typeKeyword',
|
||||||
|
'@flowchartKeywords': 'keyword',
|
||||||
|
'@default': 'variable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/\|+.+?\|+/, 'string'],
|
||||||
|
[/\[+(\\.+?[\\/]|\/.+?[/\\])\]+/, 'string'],
|
||||||
|
[/[[>]+[^\]|[]+?\]+/, 'string'],
|
||||||
|
[/{+.+?}+/, 'string'],
|
||||||
|
[/\(+.+?\)+/, 'string'],
|
||||||
|
[/-\.+->?/, 'transition'],
|
||||||
|
[/(-[-.])([^->]+?)(-{3,}|-{2,}>|\.-+>)/, ['transition', 'string', 'transition']],
|
||||||
|
[/(==+)([^=]+?)(={3,}|={2,}>)/, ['transition', 'string', 'transition']],
|
||||||
|
[/<?(--+|==+)>|===+|---+/, 'transition'],
|
||||||
|
[/:::/, 'transition'],
|
||||||
|
[/[;&]/, 'delimiter.bracket'],
|
||||||
|
[/".*?"/, 'string'],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment']
|
||||||
|
],
|
||||||
|
sequenceDiagram: [
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@sequenceDiagramBlockKeywords': 'typeKeyword',
|
||||||
|
'@sequenceDiagramKeywords': 'keyword',
|
||||||
|
'@default': 'variable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/(--?>?>|--?[)x])[+-]?/, 'transition'],
|
||||||
|
[/(:)([^:\n]*?$)/, ['delimiter.bracket', 'string']],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment']
|
||||||
|
],
|
||||||
|
classDiagram: [
|
||||||
|
[/(?!class\s)([a-zA-Z]+)(\s+[a-zA-Z]+)/, ['type', 'variable']],
|
||||||
|
[/(\*|<\|?|o)?(--|\.\.)(\*|\|?>|o)?/, 'transition'],
|
||||||
|
[/^\s*class\s(?!.*\{)/, 'keyword'],
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@classDiagramBlockKeywords': 'typeKeyword',
|
||||||
|
'@classDiagramKeywords': 'keyword',
|
||||||
|
'@default': 'variable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment'],
|
||||||
|
[/(<<)(.+?)(>>)/, ['delimiter.bracket', 'annotation', 'delimiter.bracket']],
|
||||||
|
[/".*?"/, 'string'],
|
||||||
|
[/:::/, 'transition'],
|
||||||
|
[/:|\+|-|#|~|\*\s*$|\$\s*$|\(|\)|{|}/, 'delimiter.bracket']
|
||||||
|
],
|
||||||
|
journey: [
|
||||||
|
[/(title)(.*)/, ['keyword', 'string']],
|
||||||
|
[/(section)(.*)/, ['typeKeyword', 'string']],
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@journeyBlockKeywords': 'typeKeyword',
|
||||||
|
'@journeyKeywords': 'keyword',
|
||||||
|
'@default': 'variable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
/(^\s*.+?)(:)(.*?)(:)(.*?)([,$])/,
|
||||||
|
[
|
||||||
|
'string',
|
||||||
|
'delimiter.bracket',
|
||||||
|
'number',
|
||||||
|
'delimiter.bracket',
|
||||||
|
'variable',
|
||||||
|
'delimiter.bracket'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[/,/, 'delimiter.bracket'],
|
||||||
|
[/(^\s*.+?)(:)([^:]*?)$/, ['string', 'delimiter.bracket', 'variable']],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment']
|
||||||
|
],
|
||||||
|
gantt: [
|
||||||
|
[/(title)(.*)/, ['keyword', 'string']],
|
||||||
|
[/(section)(.*)/, ['typeKeyword', 'string']],
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@ganttBlockKeywords': 'typeKeyword',
|
||||||
|
'@ganttKeywords': 'keyword'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/(^\s*.*?)(:)/, ['string', 'delimiter.bracket']],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment'],
|
||||||
|
[/:/, 'delimiter.bracket']
|
||||||
|
],
|
||||||
|
stateDiagram: [
|
||||||
|
[/note[^:]*$/, { token: 'typeKeyword', next: 'stateDiagramNote' }],
|
||||||
|
['hide empty description', 'keyword'],
|
||||||
|
[/^\s*state\s(?!.*\{)/, 'keyword'],
|
||||||
|
[/(<<)(fork|join|choice)(>>)/, 'annotation'],
|
||||||
|
[/(\[\[)(fork|join|choice)(]])/, ['delimiter.bracket', 'annotation', 'delimiter.bracket']],
|
||||||
|
[
|
||||||
|
/[a-zA-Z][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@stateDiagramBlockKeywords': 'typeKeyword',
|
||||||
|
'@stateDiagramKeywords': 'keyword',
|
||||||
|
'@default': 'variable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/".*?"/, 'string'],
|
||||||
|
[/(:)([^:\n]*?$)/, ['delimiter.bracket', 'string']],
|
||||||
|
[/{|}/, 'delimiter.bracket'],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment'],
|
||||||
|
[/-->/, 'transition'],
|
||||||
|
[/\[.*?]/, 'string']
|
||||||
|
],
|
||||||
|
stateDiagramNote: [
|
||||||
|
[/^\s*end note$/, { token: 'typeKeyword', next: '@pop' }],
|
||||||
|
[/.*/, 'string']
|
||||||
|
],
|
||||||
|
erDiagram: [
|
||||||
|
[/[}|][o|](--|\.\.)[o|][{|]/, 'transition'],
|
||||||
|
[/".*?"/, 'string'],
|
||||||
|
[/(:)(.*?$)/, ['delimiter.bracket', 'string']],
|
||||||
|
[/:|{|}/, 'delimiter.bracket'],
|
||||||
|
[/([a-zA-Z]+)(\s+[a-zA-Z]+)/, ['type', 'variable']],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment'],
|
||||||
|
[/[a-zA-Z_-][\w$]*/, 'variable']
|
||||||
|
],
|
||||||
|
requirementDiagram: [
|
||||||
|
[/->|<-|-/, 'transition'],
|
||||||
|
[/(\d+\.)*\d+/, 'number'],
|
||||||
|
[
|
||||||
|
/[a-zA-Z_-][\w$]*/,
|
||||||
|
{
|
||||||
|
cases: {
|
||||||
|
'@requirementDiagramBlockKeywords': 'typeKeyword',
|
||||||
|
'@default': 'variable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[/:|{|}|\//, 'delimiter.bracket'],
|
||||||
|
[/%%[^$]([^%]*(?!%%$)%?)*$/, 'comment'],
|
||||||
|
[/".*?"/, 'string']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
monacoEditor.editor.defineTheme('mermaid-dark', {
|
||||||
|
base: 'vs-dark',
|
||||||
|
inherit: true,
|
||||||
|
rules: [
|
||||||
|
{ token: 'typeKeyword', foreground: '9650c8', fontStyle: 'bold' },
|
||||||
|
{ token: 'transition', foreground: '008800', fontStyle: 'bold' }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
monacoEditor.editor.defineTheme('mermaidTheme', {
|
monacoEditor.editor.defineTheme('mermaid', {
|
||||||
base: 'vs',
|
base: 'vs',
|
||||||
inherit: false,
|
inherit: true,
|
||||||
rules: [
|
rules: [
|
||||||
{ token: 'keyword', foreground: '880000', fontStyle: 'bold' },
|
{ token: 'typeKeyword', foreground: '9650c8', fontStyle: 'bold' },
|
||||||
|
{ token: 'keyword', foreground: '649696' },
|
||||||
{ token: 'custom-error', foreground: 'ff0000', fontStyle: 'bold' },
|
{ token: 'custom-error', foreground: 'ff0000', fontStyle: 'bold' },
|
||||||
{ token: 'string', foreground: 'AA8500' },
|
{ token: 'string', foreground: 'AA8500' },
|
||||||
{ token: 'transition', foreground: '008800', fontStyle: 'bold' },
|
{ token: 'transition', foreground: '008800', fontStyle: 'bold' },
|
||||||
{ token: 'delimiter.bracket', foreground: '000000', fontStyle: 'bold' }
|
{ token: 'delimiter.bracket', foreground: '000000', fontStyle: 'bold' },
|
||||||
|
{ token: 'annotation', foreground: '4b4b96' },
|
||||||
|
{ token: 'number', foreground: '4b4b96' },
|
||||||
|
{ token: 'comment', foreground: '888c89' },
|
||||||
|
{ token: 'variable', foreground: 'A22889' },
|
||||||
|
{ token: 'type', foreground: '2BDEA8' }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register a completion item provider for the new language
|
// Register a completion item provider for the mermaid language
|
||||||
monacoEditor.languages.registerCompletionItemProvider('mermaid', {
|
monacoEditor.languages.registerCompletionItemProvider('mermaid', {
|
||||||
provideCompletionItems: () => {
|
provideCompletionItems: () => {
|
||||||
const suggestions = [
|
const suggestions = [
|
||||||
{
|
{
|
||||||
label: 'simpleText',
|
label: 'loop',
|
||||||
kind: monacoEditor.languages.CompletionItemKind.Text,
|
|
||||||
insertText: 'simpleText'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'testing',
|
|
||||||
kind: monacoEditor.languages.CompletionItemKind.Keyword,
|
|
||||||
insertText: 'testing(${1:condition})',
|
|
||||||
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'ifelse',
|
|
||||||
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
insertText: ['if (${1:condition}) {', '\t$0', '} else {', '\t', '}'].join('\n'),
|
insertText: ['loop ${1:Loop text}', '\t$0', 'end'].join('\n'),
|
||||||
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
documentation: 'If-Else Statement'
|
documentation: 'Sequence Diagram Loops'
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
label: 'alt',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['alt ${1:Describing text}', '\t$0', 'else', '\t', 'end'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Alternative Path'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'opt',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['opt ${1:Describing text}', '\t$0', 'end'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Optional Path'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'par',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: [
|
||||||
|
'par ${1:[Action 1]}',
|
||||||
|
'\t$0',
|
||||||
|
'and ${2:[Action 2]}',
|
||||||
|
'\t',
|
||||||
|
'and ${3:[Action 3]}',
|
||||||
|
'\t',
|
||||||
|
'end'
|
||||||
|
].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Parallel Actions'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'rect',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['rect ${1:rgb(0, 255, 0)}', '\t$0', 'end'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Background Color'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'subgraph',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['subgraph ${1:title}', '\t$0', 'end'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Subgraph'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'class',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['class ${1:className} {', '\t$0', '}'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Class'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'state',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['state ${1:stateName} {', '\t$0', '}'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'State'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'note',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['note ${1:right of State1}', '\t$0', 'end note'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'State'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'section',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['section ${1:Go to work}', '\t$0'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'User-journey Section'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'element',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['element ${1:test_entity} {', '\t$0', '}'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Requirement Diagram Element'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'options',
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: ['options', '{', ' $0', '}', 'end'].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: 'Git Graph Options'
|
||||||
|
},
|
||||||
|
...requirementDiagrams.map((requirementDiagramType) => ({
|
||||||
|
label: requirementDiagramType,
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Snippet,
|
||||||
|
insertText: [
|
||||||
|
requirementDiagramType + ' ${1:test_req} {',
|
||||||
|
'\tid: 1',
|
||||||
|
'\ttext: the test text.',
|
||||||
|
'\trisk: high',
|
||||||
|
'\tverifyMethod: test',
|
||||||
|
'}'
|
||||||
|
].join('\n'),
|
||||||
|
insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
documentation: requirementDiagramType
|
||||||
|
.split(/(?=[A-Z])/)
|
||||||
|
.map((part) => part[0].toUpperCase() + part.slice(1))
|
||||||
|
.join(' ')
|
||||||
|
})),
|
||||||
|
...[
|
||||||
|
...new Set(
|
||||||
|
Object.values(keywords)
|
||||||
|
.map((diagramKeywords) =>
|
||||||
|
Object.entries(diagramKeywords)
|
||||||
|
.filter((keywordType) => keywordType[0] !== 'annotations')
|
||||||
|
.map((entry) => entry[1])
|
||||||
|
)
|
||||||
|
.flat(2)
|
||||||
|
)
|
||||||
|
].map((keyword) => ({
|
||||||
|
label: keyword,
|
||||||
|
kind: monacoEditor.languages.CompletionItemKind.Keyword,
|
||||||
|
insertText: keyword
|
||||||
|
}))
|
||||||
];
|
];
|
||||||
return { suggestions: suggestions };
|
return { suggestions: suggestions };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
monacoEditor.languages.setLanguageConfiguration('mermaid', {
|
||||||
|
autoClosingPairs: [
|
||||||
|
{
|
||||||
|
open: '(',
|
||||||
|
close: ')'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
open: '{',
|
||||||
|
close: '}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
open: '[',
|
||||||
|
close: ']'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
brackets: [
|
||||||
|
['(', ')'],
|
||||||
|
['{', '}'],
|
||||||
|
['[', ']']
|
||||||
|
]
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -90,13 +90,13 @@
|
|||||||
<div slot="actions">
|
<div slot="actions">
|
||||||
<button
|
<button
|
||||||
id="saveHistory"
|
id="saveHistory"
|
||||||
class="btn"
|
class="btn btn-xs btn-success w-12"
|
||||||
on:click|stopPropagation={() => saveHistory()}
|
on:click|stopPropagation={() => saveHistory()}
|
||||||
title="Save current state"><i class="far fa-save" /></button>
|
title="Save current state"><i class="far fa-save" /></button>
|
||||||
{#if $historyModeStore !== 'loader'}
|
{#if $historyModeStore !== 'loader'}
|
||||||
<button
|
<button
|
||||||
id="clearHistory"
|
id="clearHistory"
|
||||||
class="btn text-red-400"
|
class="btn btn-xs btn-error w-12"
|
||||||
on:click|stopPropagation={() => clearHistory()}
|
on:click|stopPropagation={() => clearHistory()}
|
||||||
title="Delete all saved states"><i class="fas fa-trash-alt" /></button>
|
title="Delete all saved states"><i class="fas fa-trash-alt" /></button>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
<li class="rounded p-2 shadow flex-col">
|
<li class="rounded p-2 shadow flex-col">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col text-base-content">
|
||||||
{#if url}
|
{#if url}
|
||||||
<a
|
<a
|
||||||
href={url}
|
href={url}
|
||||||
@@ -121,20 +121,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2 content-center">
|
<div class="flex gap-2 content-center">
|
||||||
<button
|
<button class="btn btn-success" on:click={() => restoreHistory(state)}
|
||||||
class="rounded px-2 w-24 bg-green-200 hover:bg-green-300"
|
><i class="fas fa-undo mr-1" />Restore</button>
|
||||||
on:click={() => restoreHistory(state)}><i class="fas fa-undo" /> Restore</button>
|
|
||||||
{#if type !== 'loader'}
|
{#if type !== 'loader'}
|
||||||
<button
|
<button class="btn btn-error" on:click={() => clearHistory(time)}
|
||||||
class="rounded px-2 w-24 bg-red-200 hover:bg-red-300"
|
><i class="fas fa-trash-alt mr-1" />Delete</button>
|
||||||
on:click={() => clearHistory(time)}><i class="fas fa-trash-alt" /> Delete</button>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="m-2 text-gray-600">
|
<div class="m-2">
|
||||||
No items in History<br />
|
No items in History<br />
|
||||||
Click the Save button to save current state and restore it later.<br />
|
Click the Save button to save current state and restore it later.<br />
|
||||||
Timeline will automatically be saved every minute.
|
Timeline will automatically be saved every minute.
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Theme from './theme.svelte';
|
||||||
|
|
||||||
interface Link {
|
interface Link {
|
||||||
title: string;
|
title: string;
|
||||||
href: string;
|
href: string;
|
||||||
@@ -37,11 +39,12 @@
|
|||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="p-2 bg-indigo-400 text-white font-bold flex flex-wrap items-center">
|
<div class="navbar mb-2 shadow-lg bg-primary">
|
||||||
<div class="flex-1 flex justify-between items-center">
|
<div class="flex-1 px-2 mx-2">
|
||||||
<a href="/">Mermaid<span class="text-xs font-thin">v{version}</span> Live Editor</a>
|
<span class="text-lg font-bold">
|
||||||
|
<a href="/">Mermaid<span class="text-xs font-thin">v{version}</span> Live Editor</a>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="menu-toggle" class="pointer-cursor lg:hidden block"
|
<label for="menu-toggle" class="pointer-cursor lg:hidden block"
|
||||||
><svg
|
><svg
|
||||||
class="fill-current "
|
class="fill-current "
|
||||||
@@ -53,28 +56,27 @@
|
|||||||
></label>
|
></label>
|
||||||
<input class="hidden" type="checkbox" id="menu-toggle" />
|
<input class="hidden" type="checkbox" id="menu-toggle" />
|
||||||
|
|
||||||
|
<Theme />
|
||||||
<div class="hidden lg:flex lg:items-center lg:w-auto w-full" id="menu">
|
<div class="hidden lg:flex lg:items-center lg:w-auto w-full" id="menu">
|
||||||
<nav>
|
<ul class="lg:flex items-center justify-between text-base pt-4 lg:pt-0">
|
||||||
<ul class="lg:flex items-center justify-between text-base pt-4 lg:pt-0">
|
{#each links as { title, href, icon }}
|
||||||
{#each links as { title, href, icon }}
|
<li>
|
||||||
<li>
|
<a class="btn btn-ghost" target="_blank" {href}>
|
||||||
<a class="nav-btn" target="_blank" {href}>
|
{#if icon}
|
||||||
{#if icon}
|
<i class={icon} />
|
||||||
<i class={icon} />
|
{/if}
|
||||||
{/if}
|
{title}</a>
|
||||||
{title}</a>
|
</li>
|
||||||
</li>
|
{/each}
|
||||||
{/each}
|
</ul>
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#menu-toggle:checked + #menu {
|
#menu-toggle:checked + #menu {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
header {
|
.navbar {
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -108,7 +108,8 @@ merge newbranch
|
|||||||
<Card title="Sample Diagrams" isOpen={false}>
|
<Card title="Sample Diagrams" isOpen={false}>
|
||||||
<div class="flex gap-2 flex-wrap p-2">
|
<div class="flex gap-2 flex-wrap p-2">
|
||||||
{#each Object.keys(samples) as sample}
|
{#each Object.keys(samples) as sample}
|
||||||
<button class="action-btn" on:click={() => loadSampleDiagram(sample)}>{sample}</button>
|
<button class="btn btn-primary normal-case btn-sm" on:click={() => loadSampleDiagram(sample)}
|
||||||
|
>{sample}</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<script>
|
||||||
|
import { setTheme, themeStore } from '$lib/util/theme';
|
||||||
|
|
||||||
|
const themes = [
|
||||||
|
'🌝 light',
|
||||||
|
'🌚 dark',
|
||||||
|
'🧁 cupcake',
|
||||||
|
'🐝 bumblebee',
|
||||||
|
'✳️ emerald',
|
||||||
|
'🏢 corporate',
|
||||||
|
'🌃 synthwave',
|
||||||
|
'👴 retro',
|
||||||
|
'🤖 cyberpunk',
|
||||||
|
'🌸 valentine',
|
||||||
|
'🎃 halloween',
|
||||||
|
'🌷 garden',
|
||||||
|
'🌲 forest',
|
||||||
|
'🐟 aqua',
|
||||||
|
'👓 lofi',
|
||||||
|
'🖍 pastel',
|
||||||
|
'🧚♀️ fantasy',
|
||||||
|
'📝 wireframe',
|
||||||
|
'🏴 black',
|
||||||
|
'💎 luxury',
|
||||||
|
'🧛♂️ dracula'
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hidden lg:block dropdown">
|
||||||
|
<div tabindex="0" class="btn btn-ghost ">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
class="inline-block w-6 h-6 stroke-current md:mr-2"
|
||||||
|
><path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" /></svg>
|
||||||
|
<span class="hidden md:inline"> Change Theme </span>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 1792 1792"
|
||||||
|
class="inline-block w-4 h-4 ml-1 fill-current"
|
||||||
|
><path
|
||||||
|
d="M1395 736q0 13-10 23l-466 466q-10 10-23 10t-23-10l-466-466q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l393 393 393-393q10-10 23-10t23 10l50 50q10 10 10 23z" /></svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-14 overflow-y-auto shadow-2xl top-px dropdown-content h-96 w-56 bg-base-200 text-base-content">
|
||||||
|
<ul tabindex="0" class="p-4 menu compact">
|
||||||
|
{#each themes as theme}
|
||||||
|
<li class={theme.includes($themeStore.theme) ? 'bordered' : ''}>
|
||||||
|
<span class="btn btn-ghost justify-start" on:click={() => setTheme(theme)}>{theme}</span>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
import { codeStore } from '$lib/util/state';
|
import { codeStore } from '$lib/util/state';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import * as mermaid from 'mermaid';
|
import mermaid from 'mermaid';
|
||||||
|
|
||||||
let code = '';
|
let code = '';
|
||||||
let config = '';
|
let config = '';
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
|
let view: HTMLDivElement;
|
||||||
let error = false;
|
let error = false;
|
||||||
let outOfSync = false;
|
let outOfSync = false;
|
||||||
let manualUpdate = true;
|
let manualUpdate = true;
|
||||||
@@ -26,13 +27,13 @@
|
|||||||
}
|
}
|
||||||
code = state.code;
|
code = state.code;
|
||||||
config = state.mermaid;
|
config = state.mermaid;
|
||||||
const scroll = container.parentElement.parentElement.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) => {
|
||||||
container.innerHTML = svgCode;
|
container.innerHTML = svgCode;
|
||||||
});
|
});
|
||||||
container.parentElement.parentElement.parentElement.scrollTop = scroll;
|
view.parentElement.scrollTop = scroll;
|
||||||
error = false;
|
error = false;
|
||||||
} else if (manualUpdate) {
|
} else if (manualUpdate) {
|
||||||
manualUpdate = false;
|
manualUpdate = false;
|
||||||
@@ -55,7 +56,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="view" class="p-2" class:error class:outOfSync>
|
<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="container" bind:this={container} class="flex-1 overflow-auto" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export const rendererUrl = import.meta.env.MERMAID_RENDERER_URL ?? 'https://mermaid.ink';
|
||||||
+17
-5
@@ -1,8 +1,9 @@
|
|||||||
import { writable, get, derived } from 'svelte/store';
|
import { writable, get, derived } from 'svelte/store';
|
||||||
|
import type { Readable } from 'svelte/store';
|
||||||
import { toBase64, fromBase64 } from 'js-base64';
|
import { toBase64, fromBase64 } from 'js-base64';
|
||||||
import { persist, localStorage } from '@macfja/svelte-persistent-store';
|
import { persist, localStorage } from '@macfja/svelte-persistent-store';
|
||||||
import type { State } from '$lib/types';
|
import type { State } from '$lib/types';
|
||||||
import { saveStatistcs } from './stats';
|
import { saveStatistics } from './stats';
|
||||||
|
|
||||||
export const defaultState: State = {
|
export const defaultState: State = {
|
||||||
code: `graph TD
|
code: `graph TD
|
||||||
@@ -25,7 +26,7 @@ export const defaultState: State = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const codeStore = persist(writable(defaultState), localStorage(), 'codeStore');
|
export const codeStore = persist(writable(defaultState), localStorage(), 'codeStore');
|
||||||
export const base64State = derived([codeStore], ([code], set) => {
|
export const base64State: Readable<string> = derived([codeStore], ([code], set) => {
|
||||||
set(toBase64(JSON.stringify(code), true));
|
set(toBase64(JSON.stringify(code), true));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ export const loadState = (data: string): void => {
|
|||||||
let state: State;
|
let state: State;
|
||||||
try {
|
try {
|
||||||
const stateStr = fromBase64(data);
|
const stateStr = fromBase64(data);
|
||||||
console.log(`Tring to load state: ${stateStr}`);
|
console.log(`Trying to load state: ${stateStr}`);
|
||||||
state = JSON.parse(stateStr);
|
state = JSON.parse(stateStr);
|
||||||
const mermaidConfig =
|
const mermaidConfig =
|
||||||
typeof state.mermaid === 'string' ? JSON.parse(state.mermaid) : state.mermaid;
|
typeof state.mermaid === 'string' ? JSON.parse(state.mermaid) : state.mermaid;
|
||||||
@@ -66,12 +67,12 @@ export const updateCodeStore = (newState: State): void => {
|
|||||||
|
|
||||||
let prompted = false;
|
let prompted = false;
|
||||||
export const updateCode = (code: string, updateEditor: boolean, updateDiagram = false): void => {
|
export const updateCode = (code: string, updateEditor: boolean, updateDiagram = false): void => {
|
||||||
saveStatistcs(code);
|
saveStatistics(code);
|
||||||
const lines = (code.match(/\n/g) || '').length + 1;
|
const lines = (code.match(/\n/g) || '').length + 1;
|
||||||
|
|
||||||
if (lines > 50 && !prompted && get(codeStore).autoSync) {
|
if (lines > 50 && !prompted && get(codeStore).autoSync) {
|
||||||
const turnOff = confirm(
|
const turnOff = confirm(
|
||||||
'Long diagram deteced. Turn off Auto Sync? Click the sync logo to manually sync.'
|
'Long diagram detected. Turn off Auto Sync? Click the sync logo to manually sync.'
|
||||||
);
|
);
|
||||||
prompted = true;
|
prompted = true;
|
||||||
if (turnOff) {
|
if (turnOff) {
|
||||||
@@ -92,6 +93,17 @@ export const updateConfig = (config: string, updateEditor: boolean): void => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const toggleDarkTheme = (dark: boolean): void => {
|
||||||
|
codeStore.update((state) => {
|
||||||
|
const config = JSON.parse(state.mermaid);
|
||||||
|
if (!config.theme || ['dark', 'default'].includes(config.theme)) {
|
||||||
|
config.theme = dark ? 'dark' : 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...state, mermaid: JSON.stringify(config, null, 2), updateEditor: true };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const initURLSubscription = (): void => {
|
export const initURLSubscription = (): void => {
|
||||||
base64State.subscribe((state: string) => {
|
base64State.subscribe((state: string) => {
|
||||||
history.replaceState(undefined, undefined, `#${state}`);
|
history.replaceState(undefined, undefined, `#${state}`);
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ const detectType = (text: string): string => {
|
|||||||
|
|
||||||
// manual debounce
|
// manual debounce
|
||||||
let timeout;
|
let timeout;
|
||||||
export const saveStatistcs = (graph: string): void => {
|
export const saveStatistics = (graph: string): void => {
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
// Only save statistcs after a 5 sec delay
|
// Only save statistics after a 5 sec delay
|
||||||
timeout = setTimeout(function () {
|
timeout = setTimeout(function () {
|
||||||
const graphType = detectType(graph);
|
const graphType = detectType(graph);
|
||||||
console.debug('ga:', 'send', 'event', 'render', graphType);
|
console.debug('ga:', 'send', 'event', 'render', graphType);
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import type { Writable } from 'svelte/store';
|
||||||
|
import { persist, localStorage } from '@macfja/svelte-persistent-store';
|
||||||
|
|
||||||
|
export interface ThemeConfig {
|
||||||
|
isDark: boolean;
|
||||||
|
theme?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const themeStore: Writable<ThemeConfig> = persist(
|
||||||
|
writable({
|
||||||
|
isDark: false
|
||||||
|
}),
|
||||||
|
localStorage(),
|
||||||
|
'themeStore'
|
||||||
|
);
|
||||||
|
|
||||||
|
const darkThemes = [
|
||||||
|
'dark',
|
||||||
|
'synthwave',
|
||||||
|
'halloween',
|
||||||
|
'aqua',
|
||||||
|
'forest',
|
||||||
|
'luxury',
|
||||||
|
'black',
|
||||||
|
'dracula'
|
||||||
|
];
|
||||||
|
|
||||||
|
export const setTheme = (theme: string): void => {
|
||||||
|
if (theme.includes(' ')) {
|
||||||
|
theme = theme.split(' ')[1].trim();
|
||||||
|
}
|
||||||
|
const isDark = darkThemes.includes(theme);
|
||||||
|
console.log('Setting theme', theme);
|
||||||
|
themeStore.set({ theme, isDark });
|
||||||
|
};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import { get as manifestGet } from '../manifest.json';
|
||||||
|
export const get = manifestGet;
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
import { base } from '$app/paths';
|
import { base } from '$app/paths';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { loadingStateStore } from '$lib/util/loading';
|
import { loadingStateStore } from '$lib/util/loading';
|
||||||
|
import { setTheme, themeStore } from '$lib/util/theme';
|
||||||
|
import { toggleDarkTheme } from '$lib/util/state';
|
||||||
|
|
||||||
// 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(() => {
|
||||||
@@ -18,10 +21,23 @@
|
|||||||
console.log('Service worker registration failed, error:', error);
|
console.log('Service worker registration failed, error:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
||||||
|
if ($themeStore.theme === undefined) {
|
||||||
|
setTheme(isDarkMode ? 'dark' : 'light');
|
||||||
|
}
|
||||||
|
|
||||||
|
themeStore.subscribe(({ theme, isDark }) => {
|
||||||
|
if (theme) {
|
||||||
|
document.getElementsByTagName('html')[0].setAttribute('data-theme', theme);
|
||||||
|
toggleDarkTheme(isDark);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="h-screen">
|
<main class="h-screen text-primary-content">
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
+30
-27
@@ -10,11 +10,12 @@
|
|||||||
import { initHandler, syncDiagram } from '$lib/util/util';
|
import { initHandler, syncDiagram } from '$lib/util/util';
|
||||||
import { errorStore } from '$lib/util/error';
|
import { errorStore } from '$lib/util/error';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import * as mermaid from 'mermaid';
|
import mermaid from 'mermaid';
|
||||||
import type monaco from 'monaco-editor';
|
import type monaco from 'monaco-editor';
|
||||||
import type { EditorUpdateEvent, State, Tab } from '$lib/types';
|
import type { EditorUpdateEvent, State, Tab } from '$lib/types';
|
||||||
import { base } from '$app/paths';
|
import { base } from '$app/paths';
|
||||||
|
|
||||||
|
base64State; // Weird fix for error > base64State is not defined. Treeshaking?
|
||||||
let selectedMode = 'code';
|
let selectedMode = 'code';
|
||||||
const languageMap = {
|
const languageMap = {
|
||||||
code: 'mermaid',
|
code: 'mermaid',
|
||||||
@@ -120,25 +121,32 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="h-full flex flex-col overflow-hidden bg-gray-100">
|
<div class="h-full flex flex-col overflow-hidden">
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<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">
|
||||||
{#if !$codeStore.autoSync}
|
<div class="flex flex-row items-center">
|
||||||
<button
|
{#if !$codeStore.autoSync}
|
||||||
class="bg-indigo-500 hover:bg-indigo-700 rounded px-4 mx-2"
|
<button
|
||||||
title="Sync Diagram"
|
class="btn btn-secondary btn-xs"
|
||||||
data-cy="sync"
|
title="Sync Diagram"
|
||||||
on:click={syncDiagram}><i class="fas fa-sync" /></button>
|
data-cy="sync"
|
||||||
{/if}
|
on:click={syncDiagram}><i class="fas fa-sync" /></button>
|
||||||
<label
|
{/if}
|
||||||
for="autoSync"
|
|
||||||
style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">
|
<div class="form-control">
|
||||||
<input type="checkbox" id="autoSync" bind:checked={$codeStore.autoSync} />
|
<label class="cursor-pointer label" for="autoSync">
|
||||||
Auto sync
|
<input
|
||||||
</label>
|
type="checkbox"
|
||||||
|
class="toggle toggle-primary mr-1"
|
||||||
|
id="autoSync"
|
||||||
|
bind:checked={$codeStore.autoSync} />
|
||||||
|
<span> Auto sync</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Editor on:update={updateHandler} {language} bind:text {errorMarkers} />
|
<Editor on:update={updateHandler} {language} bind:text {errorMarkers} />
|
||||||
@@ -150,20 +158,20 @@
|
|||||||
<Actions />
|
<Actions />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="resizeHandler" />
|
<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}>
|
||||||
<button
|
<button
|
||||||
slot="actions"
|
slot="actions"
|
||||||
class="btn"
|
class="btn btn-primary btn-xs shadow-lg"
|
||||||
title="View diagram in new page"
|
title="View diagram in new page"
|
||||||
on:click|stopPropagation={() => viewDiagram()}><i class="far fa-eye" /> View</button>
|
on:click|stopPropagation={() => viewDiagram()}><i class="far fa-eye mr-2" /> View</button>
|
||||||
|
|
||||||
<div class="flex-1 overflow-auto">
|
<div class="flex-1 overflow-auto">
|
||||||
<View />
|
<View />
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<div class="md:hidden bg-white rounded shadow p-2 mx-2">
|
<div class="md:hidden rounded shadow p-2 mx-2">
|
||||||
Code editing not supported on mobile. Please use a desktop browser.
|
Code editing not supported on mobile. Please use a desktop browser.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -182,19 +190,14 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: #ccc;
|
background-color: hsla(var(--b3));
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
|
transition-duration: 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#resizeHandler:hover::after {
|
#resizeHandler:hover::after {
|
||||||
margin-left: -2px;
|
margin-left: -2px;
|
||||||
background-color: #818cf8;
|
background-color: hsla(var(--p));
|
||||||
width: 4px;
|
width: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
#resizeHandler {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 47 KiB |
@@ -24,6 +24,7 @@ const config = {
|
|||||||
target: '#svelte',
|
target: '#svelte',
|
||||||
trailingSlash: 'ignore',
|
trailingSlash: 'ignore',
|
||||||
vite: {
|
vite: {
|
||||||
|
envPrefix: 'MERMAID_',
|
||||||
optimizeDeps: { include: ['mermaid'] }
|
optimizeDeps: { include: ['mermaid'] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-17
@@ -1,21 +1,7 @@
|
|||||||
const { tailwindExtractor } = require('tailwindcss/lib/lib/purgeUnusedStyles');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'aot',
|
mode: 'jit',
|
||||||
purge: {
|
plugins: [require('daisyui')],
|
||||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
purge: ['./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
|
|
||||||
)
|
|
||||||
]
|
|
||||||
},
|
|
||||||
safelist: [/^svelte-[\d\w]+$/]
|
|
||||||
},
|
|
||||||
theme: {
|
theme: {
|
||||||
extend: {}
|
extend: {}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user