diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index af91af2d..65ff1269 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -7,17 +7,11 @@ module.exports = {
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:@typescript-eslint/strict',
'plugin:unicorn/recommended',
+ 'plugin:svelte/recommended',
+ 'plugin:svelte/prettier',
'prettier'
],
- plugins: [
- 'svelte3',
- 'tailwindcss',
- '@typescript-eslint',
- 'es',
- 'vitest',
- 'no-only-tests',
- 'unicorn'
- ],
+ plugins: ['tailwindcss', '@typescript-eslint', 'es', 'vitest', 'no-only-tests', 'unicorn'],
ignorePatterns: [
'docs/*',
'*.cjs',
@@ -30,7 +24,13 @@ module.exports = {
'tsconfig.json'
],
overrides: [
- { files: ['*.svelte'], processor: 'svelte3/svelte3' },
+ {
+ files: ['*.svelte'],
+ parser: 'svelte-eslint-parser',
+ parserOptions: {
+ parser: '@typescript-eslint/parser'
+ }
+ },
{
files: ['*.ts'],
extends: [
@@ -42,16 +42,12 @@ module.exports = {
]
}
],
- settings: {
- 'svelte3/typescript': () => require('typescript')
- },
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
tsconfigRootDir: __dirname,
- project: ['./tsconfig.json'],
- extraFileExtensions: ['.svelte'],
- allowAutomaticSingleRunInference: true
+ project: './tsconfig.json',
+ extraFileExtensions: ['.svelte']
},
env: {
browser: true,
@@ -76,6 +72,7 @@ module.exports = {
case: 'camelCase'
}
],
+ 'unicorn/filename-case': 'off',
'unicorn/prevent-abbreviations': [
'error',
{
diff --git a/.node-version b/.node-version
new file mode 100644
index 00000000..25bf17fc
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+18
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
index ab65daf2..e0366fc9 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -3,5 +3,7 @@
"svelteSortOrder": "options-scripts-markup-styles",
"bracketSameLine": true,
"trailingComma": "none",
- "printWidth": 100
+ "printWidth": 100,
+ "tailwindConfig": "./tailwind.config.cjs",
+ "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index e1731904..5d2cb867 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -10,12 +10,15 @@
"daisyui",
"esserializer",
"gantt",
+ "gitgraph",
"KROKI",
"localstorage",
"mermaidchart",
"mindmap",
"Pageview",
"pako",
+ "panzoom",
+ "pzoom",
"Serde",
"serdes",
"tailwindcss",
diff --git a/cypress/e2e/util.ts b/cypress/e2e/util.ts
index 57a9f54b..456ae585 100644
--- a/cypress/e2e/util.ts
+++ b/cypress/e2e/util.ts
@@ -11,7 +11,7 @@ export const typeInEditor = (
) => {
cy.window().should('have.property', 'editorLoaded', true);
cy.get('#editor').click();
- cy.get('#editor').within(($editor) => {
+ cy.get('#editor').within(() => {
if (bottom) {
cy.get('textarea').type('{pageDown}', { force: true });
}
diff --git a/package.json b/package.json
index 37592fa9..044f27a3 100644
--- a/package.json
+++ b/package.json
@@ -9,9 +9,9 @@
"dev:test": "yarn dev",
"build": "vite build",
"preview": "vite preview",
- "lint": "prettier --check --cache --plugin-search-dir=. .;eslint --ignore-path .gitignore .",
- "lint:fix": "prettier --write --cache --plugin-search-dir=. .;eslint --fix --ignore-path .gitignore .",
- "format": "prettier --write --cache --plugin-search-dir=. .",
+ "lint": "prettier --check --cache . && eslint --ignore-path .gitignore .",
+ "lint:fix": "prettier --write --cache . && eslint --fix --ignore-path .gitignore .",
+ "format": "prettier --write --cache .",
"pre-commit": "lint-staged",
"postinstall": "husky install && svelte-kit sync && (git config blame.ignoreRevsFile .git-blame-ignore-revs || true)",
"test:unit": "vitest",
@@ -23,15 +23,15 @@
},
"devDependencies": {
"@cypress/snapshot": "2.1.7",
- "@sveltejs/adapter-static": "2.0.3",
- "@sveltejs/kit": "1.28.0",
- "@testing-library/jest-dom": "5.17.0",
- "@testing-library/svelte": "3.2.2",
+ "@sveltejs/adapter-static": "3.0.1",
+ "@sveltejs/kit": "2.3.0",
+ "@sveltejs/vite-plugin-svelte": "^3.0.1",
+ "@testing-library/svelte": "4.0.5",
"@types/pako": "2.0.3",
"@types/uuid": "9.0.7",
- "@typescript-eslint/eslint-plugin": "5.62.0",
- "@typescript-eslint/parser": "5.62.0",
- "@vitest/ui": "^0.34.0",
+ "@typescript-eslint/eslint-plugin": "6.18.1",
+ "@typescript-eslint/parser": "6.18.1",
+ "@vitest/ui": "^1.1.3",
"autoprefixer": "^10.4.14",
"c8": "7.14.0",
"chai": "^4.3.7",
@@ -39,33 +39,35 @@
"cy-verify-downloads": "0.2.2",
"cypress": "12.17.4",
"cypress-localstorage-commands": "2.2.5",
- "eslint": "8.55.0",
- "eslint-config-prettier": "8.10.0",
+ "eslint": "8.56.0",
+ "eslint-config-prettier": "9.1.0",
"eslint-plugin-cypress": "2.15.1",
- "eslint-plugin-es": "4.1.0",
+ "eslint-plugin-es": "^4.1.0",
"eslint-plugin-no-only-tests": "^3.1.0",
- "eslint-plugin-postcss-modules": "2.0.0",
- "eslint-plugin-svelte3": "4.0.0",
- "eslint-plugin-tailwindcss": "3.13.0",
- "eslint-plugin-unicorn": "^46.0.0",
- "eslint-plugin-vitest": "^0.3.0",
- "esserializer": "1.3.11",
+ "eslint-plugin-postcss-modules": "^2.0.0",
+ "eslint-plugin-svelte": "^2.35.1",
+ "eslint-plugin-tailwindcss": "^3.13.1",
+ "eslint-plugin-unicorn": "^50.0.1",
+ "eslint-plugin-vitest": "^0.3.20",
+ "esserializer": "^1.3.11",
"font-awesome": "^4.7.0",
"husky": "^8.0.3",
- "jsdom": "21.1.2",
- "lint-staged": "13.3.0",
+ "jsdom": "^21.1.2",
+ "lint-staged": "^15.2.0",
"node-html-parser": "^6.1.5",
- "postcss": "^8.4.21",
- "postcss-load-config": "4.0.2",
- "prettier": "2.8.8",
- "prettier-plugin-svelte": "^2.10.0",
- "svelte": "3.59.2",
- "svelte-preprocess": "5.1.1",
- "tailwindcss": "^3.3.1",
- "tslib": "^2.5.0",
- "typescript": "5.3.2",
- "vite": "^4.5.1",
- "vitest": "^0.34.0"
+ "postcss": "^8.4.33",
+ "postcss-load-config": "5.0.2",
+ "prettier": "^3.1.0",
+ "prettier-plugin-svelte": "^3.1.2",
+ "prettier-plugin-tailwindcss": "^0.5.11",
+ "svelte": "^4.2.8",
+ "svelte-preprocess": "^5.1.3",
+ "tailwindcss": "^3.4.1",
+ "tslib": "^2.6.2",
+ "typescript": "^5.3.3",
+ "vite": "^5.0.11",
+ "vitest": "^1.1.3",
+ "vitest-dom": "^0.1.1"
},
"dependencies": {
"daisyui": "2.52.0",
diff --git a/src/app.html b/src/app.html
index e2469685..9b8d5a11 100644
--- a/src/app.html
+++ b/src/app.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/app.postcss b/src/app.postcss
index 888c737e..73ce33f0 100644
--- a/src/app.postcss
+++ b/src/app.postcss
@@ -3,7 +3,7 @@
@tailwind utilities;
.input {
- @apply flex-1 border-primary border-solid border-2 rounded;
+ @apply flex-1 rounded border-2 border-solid border-primary;
}
.action-btn {
@apply btn btn-primary;
diff --git a/src/global.d.ts b/src/global.d.ts
index 95ecd6a0..63908c66 100644
--- a/src/global.d.ts
+++ b/src/global.d.ts
@@ -1,16 +1 @@
-/* eslint-disable @typescript-eslint/no-empty-interface */
-/* eslint-disable @typescript-eslint/ban-types */
-/* eslint-disable @typescript-eslint/no-unused-vars */
-
///
-import type { TestingLibraryMatchers } from '@testing-library/jest-dom/matchers';
-
-declare global {
- namespace jest {
- interface Matchers
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-expect-error
- // eslint-disable-next-line no-undef
- extends TestingLibraryMatchers {}
- }
-}
diff --git a/src/lib/components/Actions.svelte b/src/lib/components/Actions.svelte
index 7b1b9578..9b1fd242 100644
--- a/src/lib/components/Actions.svelte
+++ b/src/lib/components/Actions.svelte
@@ -7,12 +7,12 @@
import { logEvent } from '$lib/util/stats';
import { toBase64 } from 'js-base64';
import dayjs from 'dayjs';
- const { krokiRendererUrl, rendererUrl } = env;
+ const { krokiRendererUrl, rendererUrl } = env;
type Exporter = (context: CanvasRenderingContext2D, image: HTMLImageElement) => () => void;
- const getFileName = (ext: string) =>
- `mermaid-diagram-${dayjs().format('YYYY-MM-DD-HHmmss')}.${ext}`;
+ const getFileName = (extension: string) =>
+ `mermaid-diagram-${dayjs().format('YYYY-MM-DD-HHmmss')}.${extension}`;
const getBase64SVG = (svg?: HTMLElement, width?: number, height?: number): string => {
if (svg) {
@@ -22,7 +22,7 @@
height && svg?.setAttribute('height', `${height}px`);
width && svg?.setAttribute('width', `${width}px`); // Workaround https://stackoverflow.com/questions/28690643/firefox-error-rendering-an-svg-image-to-html5-canvas-with-drawimage
if (!svg) {
- svg = getSvgEl();
+ svg = getSvgElement();
}
const svgString = svg.outerHTML
.replaceAll('
', '
')
@@ -32,7 +32,7 @@
const exportImage = (event: Event, exporter: Exporter) => {
const canvas: HTMLCanvasElement = document.createElement('canvas');
- const svg: HTMLElement | null = document.querySelector('#container svg');
+ const svg = document.querySelector('#container svg');
if (!svg) {
throw new Error('svg not found');
}
@@ -57,28 +57,26 @@
context.fillRect(0, 0, canvas.width, canvas.height);
const image = new Image();
- image.onload = exporter(context, image);
+ image.addEventListener('load', exporter(context, image));
image.src = `data:image/svg+xml;base64,${getBase64SVG(svg, canvas.width, canvas.height)}`;
event.stopPropagation();
event.preventDefault();
};
- const getSvgEl = () => {
- const svgEl: HTMLElement = document
- .querySelector('#container svg')!
- .cloneNode(true) as HTMLElement;
- svgEl.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
- const fontAwesomeCdnUrl = Array.from(document.head.getElementsByTagName('link'))
- .map((l) => l.href)
- .find((h) => h.includes('font-awesome'));
+ const getSvgElement = () => {
+ const svgElement = document.querySelector('#container svg')?.cloneNode(true) as HTMLElement;
+ svgElement.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
+ const fontAwesomeCdnUrl = [...document.head.querySelectorAll('link')]
+ .map((link) => link.href)
+ .find((url) => url.includes('font-awesome'));
if (fontAwesomeCdnUrl == null) {
- return svgEl;
+ return svgElement;
}
- const styleEl = document.createElement('style');
- styleEl.innerText = `@import url("${fontAwesomeCdnUrl}");'`;
- svgEl.prepend(styleEl);
- return svgEl;
+ const styleElement = document.createElement('style');
+ styleElement.textContent = `@import url("${fontAwesomeCdnUrl}");'`;
+ svgElement.prepend(styleElement);
+ return svgElement;
};
const simulateDownload = (download: string, href: string): void => {
@@ -144,7 +142,7 @@
};
const onCopyMarkdown = () => {
- (document.getElementById('markdown') as HTMLInputElement).select();
+ document.querySelector('#markdown')?.select();
document.execCommand('Copy');
logEvent('copyMarkdown');
};
@@ -185,7 +183,7 @@
-
+
{#if isClipboardAvailable()}
-
+
PNG size
-
+
-
+
{#if isNetlify}
-
-
+
diff --git a/src/lib/components/Card/Card.svelte b/src/lib/components/Card/Card.svelte
index 38098eb6..3e107487 100644
--- a/src/lib/components/Card/Card.svelte
+++ b/src/lib/components/Card/Card.svelte
@@ -11,20 +11,22 @@
$: isTabsShown = isOpen && tabs.length > 0;
-
+
(isOpen = !isOpen)}
on:keypress={() => (isOpen = !isOpen)}>
{#if isOpen}
-
+
{/if}
diff --git a/src/lib/components/Card/Tabs.svelte b/src/lib/components/Card/Tabs.svelte
index 3c7c8f9d..17fa57b3 100644
--- a/src/lib/components/Card/Tabs.svelte
+++ b/src/lib/components/Card/Tabs.svelte
@@ -20,6 +20,8 @@
(isOpen = !isOpen)}
on:keypress|stopPropagation={() => (isOpen = !isOpen)}>
@@ -31,6 +33,8 @@
{#each tabs as tab}
toggleTabs(tab)}
on:keypress|stopPropagation={() => toggleTabs(tab)}>
diff --git a/src/lib/components/Editor.svelte b/src/lib/components/Editor.svelte
index 2d5d3cc3..77652eca 100644
--- a/src/lib/components/Editor.svelte
+++ b/src/lib/components/Editor.svelte
@@ -1,3 +1,12 @@
+
+
-
+
diff --git a/src/lib/components/History/History.svelte b/src/lib/components/History/History.svelte
index 5c8aa95a..72c110d4 100644
--- a/src/lib/components/History/History.svelte
+++ b/src/lib/components/History/History.svelte
@@ -20,7 +20,7 @@
dayjs.extend(dayjsRelativeTime);
- const HISTORY_SAVE_INTERVAL = 60000;
+ const HISTORY_SAVE_INTERVAL = 60_000;
const tabSelectHandler = (message: CustomEvent
) => {
historyModeStore.set(message.detail.id as HistoryType);
@@ -56,17 +56,13 @@
const input = document.createElement('input');
input.type = 'file';
input.accept = 'application/json';
- input.addEventListener('change', ({ target }: Event) => {
- const file = (target).files[0];
+ input.addEventListener('change', async ({ target }: Event) => {
+ const file = (target as HTMLInputElement)?.files?.[0];
if (!file) {
return;
}
- const reader = new FileReader();
- reader.onload = (e) => {
- const data: HistoryEntry[] = JSON.parse(e.target.result as string);
- restoreHistory(data);
- };
- reader.readAsText(file);
+ const data: HistoryEntry[] = JSON.parse(await file.text());
+ restoreHistory(data);
});
input.click();
};
@@ -129,34 +125,34 @@
{#if $historyStore.length > 0}
{/if}
|
{#if $historyModeStore !== 'loader'}
{/if}
-
+
{#if $historyStore.length > 0}
{#each $historyStore as { id, state, time, name, url, type }}
- -
+
-
@@ -165,14 +161,14 @@
href={url}
target="_blank"
title="Open revision in new tab"
- class="hover:underline text-blue-500">{name}
+ class="text-blue-500 hover:underline">{name}
{:else}
{name}
{/if}
- {relativeTime(time)}
+ {relativeTime(time)}
-
+
{#if type !== 'loader'}
diff --git a/src/lib/components/Navbar.svelte b/src/lib/components/Navbar.svelte
index fbfe2af0..55fa3ecf 100644
--- a/src/lib/components/Navbar.svelte
+++ b/src/lib/components/Navbar.svelte
@@ -62,8 +62,13 @@
{#if activePromotion}
-
+ class="top-bar z-10 flex h-fit w-full items-center justify-center bg-gradient-to-r from-[#bd34fe] to-[#ff3670] p-1 text-center text-white">
+