Merge pull request #1565 from mermaid-js/sidv/svelte5

Svelte 5
This commit is contained in:
Sidharth Vinod
2024-11-08 22:16:16 +05:30
committed by GitHub
19 changed files with 712 additions and 1091 deletions
+1
View File
@@ -86,6 +86,7 @@ module.exports = {
j: true,
k: true,
param: true,
Props: true,
req: true,
res: true,
str: true,
+5 -6
View File
@@ -17,9 +17,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- uses: actions/cache@v3
- uses: actions/cache@v4
id: yarn-and-build-cache
with:
path: |
@@ -30,21 +30,20 @@ jobs:
restore-keys: |
${{ runner.os }}-node_modules-build-
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: 18
node-version-file: '.node-version'
cache: 'yarn'
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
uses: cypress-io/github-action@v3
uses: cypress-io/github-action@v6
with:
build: yarn build
start: yarn preview
wait-on: 'http://localhost:3000'
record: true
headless: true
parallel: true
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
+12 -11
View File
@@ -26,15 +26,16 @@
"@fortawesome/fontawesome-free": "^6.5.1",
"@sveltejs/adapter-static": "3.0.6",
"@sveltejs/kit": "2.8.0",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@testing-library/svelte": "4.2.3",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/svelte": "^5.2.4",
"@types/dompurify": "^3.0.5",
"@types/lodash-es": "^4.17.12",
"@types/pako": "2.0.3",
"@types/uuid": "9.0.8",
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"@vitest/ui": "^1.1.3",
"@vitest/ui": "^2.1.4",
"autoprefixer": "^10.4.14",
"c8": "7.14.0",
"chai": "^4.3.7",
@@ -47,27 +48,27 @@
"eslint-plugin-es": "^4.1.0",
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-postcss-modules": "^2.0.0",
"eslint-plugin-svelte": "^2.35.1",
"eslint-plugin-svelte": "^2.45.1",
"eslint-plugin-tailwindcss": "^3.13.1",
"eslint-plugin-unicorn": "^50.0.1",
"eslint-plugin-vitest": "^0.5.0",
"esserializer": "^1.3.11",
"husky": "^8.0.3",
"jsdom": "^21.1.2",
"jsdom": "^25.0.1",
"lint-staged": "^15.2.0",
"node-html-parser": "^6.1.5",
"postcss": "^8.4.33",
"postcss-load-config": "5.1.0",
"prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.1.2",
"prettier-plugin-svelte": "^3.2.6",
"prettier-plugin-tailwindcss": "^0.6.0",
"svelte": "^4.2.8",
"svelte-preprocess": "^5.1.3",
"svelte": "^5.0.0",
"svelte-preprocess": "^6.0.0",
"tailwindcss": "^3.4.1",
"tslib": "^2.6.2",
"typescript": "^5.3.3",
"vite": "^5.0.11",
"vitest": "^1.1.3",
"typescript": "^5.5.0",
"vite": "^5.4.4",
"vitest": "^2.1.4",
"vitest-dom": "^0.1.1"
},
"dependencies": {
+21 -21
View File
@@ -6,9 +6,9 @@
import { pakoSerde } from '$lib/util/serde';
import { stateStore } from '$lib/util/state';
import { logEvent } from '$lib/util/stats';
import { version as FAVersion } from '@fortawesome/fontawesome-free/package.json';
import dayjs from 'dayjs';
import { toBase64 } from 'js-base64';
import { version as FAVersion } from '@fortawesome/fontawesome-free/package.json';
const FONT_AWESOME_URL = `https://cdnjs.cloudflare.com/ajax/libs/font-awesome/${FAVersion}/css/all.min.css`;
@@ -149,7 +149,7 @@ ${svgString}`);
logEvent('copyMarkdown');
};
let gistURL = '';
let gistURL = $state('');
stateStore.subscribe(({ loader }) => {
if (loader?.type === 'gist') {
// @ts-expect-error Gist will have url
@@ -165,14 +165,14 @@ ${svgString}`);
logEvent('loadGist');
};
let iUrl: string;
let svgUrl: string;
let krokiUrl: string;
let mdCode: string;
let imagemodeselected = 'auto';
let userimagesize = 1080;
let iUrl: string | undefined = $state();
let svgUrl: string | undefined = $state();
let krokiUrl: string | undefined = $state();
let mdCode: string | undefined = $state();
let imagemodeselected = $state('auto');
let userimagesize = $state(1080);
let isNetlify = false;
let isNetlify = $state(false);
if (browser && ['mermaid.live', 'netlify'].some((path) => window.location.host.includes(path))) {
isNetlify = true;
}
@@ -187,32 +187,32 @@ ${svgString}`);
<Card title="Actions" isOpen={false}>
<div class="m-2 flex flex-wrap gap-2">
{#if isClipboardAvailable()}
<button class="action-btn w-full" on:click={onCopyClipboard}
><i class="far fa-copy mr-2" /> Copy Image to clipboard
<button class="action-btn w-full" onclick={onCopyClipboard}
><i class="far fa-copy mr-2"></i> Copy Image to clipboard
</button>
{/if}
<button id="downloadPNG" class="action-btn flex-grow" on:click={onDownloadPNG}>
<i class="fas fa-download mr-2" /> PNG
<button id="downloadPNG" class="action-btn flex-grow" onclick={onDownloadPNG}>
<i class="fas fa-download mr-2"></i> PNG
</button>
<button id="downloadSVG" class="action-btn flex-grow" on:click={onDownloadSVG}>
<i class="fas fa-download mr-2" /> SVG
<button id="downloadSVG" class="action-btn flex-grow" onclick={onDownloadSVG}>
<i class="fas fa-download mr-2"></i> SVG
</button>
{#if rendererUrl}
<a target="_blank" rel="noreferrer" class="flex-grow" href={iUrl}>
<button class="action-btn w-full">
<i class="fas fa-external-link-alt mr-2" /> PNG
<i class="fas fa-external-link-alt mr-2"></i> PNG
</button>
</a>
<a target="_blank" rel="noreferrer" class="flex-grow" href={svgUrl}>
<button class="action-btn w-full">
<i class="fas fa-external-link-alt mr-2" /> SVG
<i class="fas fa-external-link-alt mr-2"></i> SVG
</button>
</a>
{/if}
{#if krokiRendererUrl}
<a target="_blank" rel="noreferrer" class="flex-grow" href={krokiUrl}>
<button class="action-btn w-full">
<i class="fas fa-external-link-alt mr-2" /> Kroki
<i class="fas fa-external-link-alt mr-2"></i> Kroki
</button>
</a>
{/if}
@@ -244,9 +244,9 @@ ${svgString}`);
{#if rendererUrl}
<div class="flex w-full items-center gap-2">
<input class="input" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
<input class="input" id="markdown" type="text" value={mdCode} onclick={onCopyMarkdown} />
<label for="markdown">
<button class="btn btn-primary btn-md flex-auto" on:click={onCopyMarkdown}>
<button class="btn btn-primary btn-md flex-auto" onclick={onCopyMarkdown}>
Copy Markdown
</button>
</label>
@@ -261,7 +261,7 @@ ${svgString}`);
bind:value={gistURL}
placeholder="Enter Gist URL" />
<label for="gist">
<button class="btn btn-primary btn-md flex-auto" on:click={loadGist}> Load Gist </button>
<button class="btn btn-primary btn-md flex-auto" onclick={loadGist}> Load Gist </button>
</label>
</div>
{#if isNetlify}
+36 -12
View File
@@ -1,14 +1,38 @@
<script lang="ts">
import type { Tab } from '$lib/types';
import type { Snippet } from 'svelte';
import { slide } from 'svelte/transition';
import Tabs from './Tabs.svelte';
export let isCloseable = true;
export let isOpen = true;
export let tabs: Tab[] = [];
export let activeTabID = '';
export let title: string;
$: isOpen = isCloseable ? isOpen : true;
$: isTabsShown = isOpen && tabs.length > 0;
interface Props {
isClosable?: boolean;
isOpen?: boolean;
tabs?: Tab[];
activeTabID?: string;
title: string;
onselect?: (tab: Tab) => void;
actions?: Snippet;
children?: Snippet;
}
let {
isClosable = true,
isOpen = true,
tabs = [],
activeTabID = '',
title,
onselect,
actions,
children
}: Props = $props();
const toggleCardOpen = () => {
if (isClosable) {
isOpen = !isOpen;
}
};
let isTabsShown = $derived(isOpen && tabs.length > 0);
</script>
<div class="card m-2 flex flex-grow flex-col overflow-hidden rounded shadow-2xl">
@@ -16,18 +40,18 @@
role="toolbar"
tabindex="0"
class="bg-primary p-2 {isTabsShown ? 'pb-0' : ''} flex-none cursor-pointer"
on:click={() => (isOpen = !isOpen)}
on:keypress={() => (isOpen = !isOpen)}>
onclick={toggleCardOpen}
onkeypress={toggleCardOpen}>
<div class="flex justify-between">
<Tabs on:select {tabs} bind:isOpen {title} {isCloseable} {activeTabID} />
<Tabs {onselect} {tabs} bind:isOpen {title} {isClosable} {activeTabID} />
<div class="flex items-center gap-x-4 {isTabsShown ? '-mt-2' : ''}">
<slot name="actions" />
{@render actions?.()}
</div>
</div>
</div>
{#if isOpen}
<div class="card-body flex-grow overflow-auto p-0 text-base-content" transition:slide>
<slot />
{@render children?.()}
</div>
{/if}
</div>
+30 -21
View File
@@ -1,34 +1,43 @@
<script lang="ts">
import type { Tab, TabEvents } from '$lib/types';
import { createEventDispatcher } from 'svelte';
import type { Tab } from '$lib/types';
import { fade } from 'svelte/transition';
export let isCloseable = true;
export let tabs: Tab[];
export let title: string;
export let isOpen = false;
export let activeTabID: string;
let {
isClosable = true,
tabs,
title,
isOpen = $bindable(false),
activeTabID = $bindable(),
onselect
}: {
isClosable?: boolean;
tabs: Tab[];
title: string;
isOpen?: boolean;
activeTabID: string;
onselect?: (tab: Tab) => void;
} = $props();
if (!activeTabID && tabs.length > 0) {
activeTabID = tabs[0].id;
}
const dispatch = createEventDispatcher<TabEvents>();
const toggleTabs = (tab: Tab) => {
return (event: Event) => {
event.stopPropagation();
activeTabID = tab.id;
dispatch('select', tab);
onselect?.(tab);
};
};
</script>
<div class="flex cursor-default">
<span
role="menubar"
tabindex="0"
class="mr-2 font-semibold"
on:click|stopPropagation={() => (isOpen = !isOpen)}
on:keypress|stopPropagation={() => (isOpen = !isOpen)}>
{#if isCloseable}
<i class="fas fa-chevron-right icon" class:isOpen />
<span role="menubar" tabindex="0" class="mr-2 font-semibold">
{#if isClosable}
<i class="fas fa-chevron-right icon mr-1" class:isOpen></i>
{/if}
{title}</span>
{title}
</span>
{#if isOpen && tabs}
<ul class="tabs" transition:fade>
{#each tabs as tab}
@@ -36,9 +45,9 @@
role="tab"
tabindex="0"
class="tab tab-lifted {activeTabID === tab.id ? 'tab-active' : 'text-primary-content'}"
on:click|stopPropagation={() => toggleTabs(tab)}
on:keypress|stopPropagation={() => toggleTabs(tab)}>
<i class="mr-1 {tab.icon}" />
onclick={toggleTabs(tab)}
onkeypress={toggleTabs(tab)}>
<i class="mr-1 {tab.icon}"></i>
{tab.title}
</div>
{/each}
+1 -1
View File
@@ -1,5 +1,5 @@
import { cleanup, render } from '@testing-library/svelte';
import { describe, expect, it, afterEach } from 'vitest';
import { afterEach, describe, expect, it } from 'vitest';
import Card from './Card.svelte';
describe('card.svelte', () => {
+4 -4
View File
@@ -1,4 +1,4 @@
<script lang="ts" context="module">
<script lang="ts" module>
declare global {
interface Window {
Cypress: boolean;
@@ -20,7 +20,7 @@
import monacoJsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import { onDestroy, onMount } from 'svelte';
let divElement: HTMLDivElement | undefined;
let divElement: HTMLDivElement | undefined = $state();
let editor: monaco.editor.IStandaloneCodeEditor | undefined;
let editorOptions: monaco.editor.IStandaloneEditorConstructionOptions = {
minimap: {
@@ -133,11 +133,11 @@
</script>
<div class="flex h-full flex-col">
<div bind:this={divElement} id="editor" class="h-full flex-grow overflow-hidden" />
<div bind:this={divElement} id="editor" class="h-full flex-grow overflow-hidden"></div>
{#if $stateStore.error instanceof Error}
<div class="flex flex-col text-sm text-neutral-100">
<div class="flex items-center gap-2 bg-red-700 p-2">
<i class="fa fa-exclamation-circle w-4" aria-hidden="true" />
<i class="fa fa-exclamation-circle w-4" aria-hidden="true"></i>
<p>Diagram syntax error</p>
</div>
<div class="max-h-32 overflow-auto bg-red-600 p-2 font-mono">
+35 -29
View File
@@ -1,31 +1,33 @@
<script lang="ts">
import { stopPropagation } from 'svelte/legacy';
import Card from '$lib/components/Card/Card.svelte';
import { inputStateStore, getStateString } from '$lib/util/state';
import type { HistoryEntry, HistoryType, State, Tab } from '$lib/types';
import { notify, prompt } from '$lib/util/notify';
import { getStateString, inputStateStore } from '$lib/util/state';
import { logEvent } from '$lib/util/stats';
import dayjs from 'dayjs';
import dayjsRelativeTime from 'dayjs/plugin/relativeTime';
import { onMount } from 'svelte';
import { get } from 'svelte/store';
import {
addHistoryEntry,
historyModeStore,
clearHistoryData,
getPreviousState,
historyModeStore,
historyStore,
loaderHistoryStore,
restoreHistory
} from './history';
import { notify, prompt } from '$lib/util/notify';
import { onMount } from 'svelte';
import { get } from 'svelte/store';
import dayjs from 'dayjs';
import dayjsRelativeTime from 'dayjs/plugin/relativeTime';
import type { HistoryEntry, HistoryType, State, Tab } from '$lib/types';
import { logEvent } from '$lib/util/stats';
dayjs.extend(dayjsRelativeTime);
const HISTORY_SAVE_INTERVAL = 60_000;
const tabSelectHandler = (message: CustomEvent<Tab>) => {
historyModeStore.set(message.detail.id as HistoryType);
const tabSelectHandler = (tab: Tab) => {
historyModeStore.set(tab.id as HistoryType);
};
let tabs: Tab[] = [
let tabs: Tab[] = $state([
{
id: 'manual',
title: 'Saved',
@@ -36,7 +38,7 @@
title: 'Timeline',
icon: 'fas fa-history'
}
];
]);
const downloadHistory = () => {
const data = get(historyStore);
@@ -117,38 +119,42 @@
historyModeStore.set('loader');
}
});
let isOpen = false;
</script>
<Card on:select={tabSelectHandler} bind:isOpen {tabs} title="History">
<div slot="actions">
<Card onselect={tabSelectHandler} isOpen={false} {tabs} title="History">
{#snippet actions()}
<div>
<button
id="uploadHistory"
class="btn btn-secondary btn-xs w-12"
on:click|stopPropagation={() => uploadHistory()}
title="Upload history"><i class="fa fa-upload" /></button>
onclick={stopPropagation(() => uploadHistory())}
title="Upload history"
aria-label="Upload history"><i class="fa fa-upload"></i></button>
{#if $historyStore.length > 0}
<button
id="downloadHistory"
class="btn btn-secondary btn-xs w-12"
on:click|stopPropagation={() => downloadHistory()}
title="Download history"><i class="fa fa-download" /></button>
onclick={stopPropagation(() => downloadHistory())}
title="Download history"
aria-label="Download history"><i class="fa fa-download"></i></button>
{/if}
|
<button
id="saveHistory"
class="btn btn-success btn-xs w-12"
on:click|stopPropagation={() => saveHistory()}
title="Save current state"><i class="far fa-save" /></button>
onclick={stopPropagation(() => saveHistory())}
title="Save current state"
aria-label="Save current state"><i class="far fa-save"></i></button>
{#if $historyModeStore !== 'loader'}
<button
id="clearHistory"
class="btn btn-error btn-xs w-12"
on:click|stopPropagation={() => clearHistory()}
title="Delete all saved states"><i class="fas fa-trash-alt" /></button>
onclick={stopPropagation(() => clearHistory())}
title="Delete all saved states"
aria-label="Delete all saved states"><i class="fas fa-trash-alt"></i></button>
{/if}
</div>
{/snippet}
<ul class="h-56 space-y-2 overflow-auto p-2" id="historyList">
{#if $historyStore.length > 0}
{#each $historyStore as { id, state, time, name, url, type }}
@@ -169,11 +175,11 @@
</div>
</div>
<div class="flex content-center gap-2">
<button class="btn btn-success" on:click={() => restoreHistoryItem(state)}
><i class="fas fa-undo mr-1" />Restore</button>
<button class="btn btn-success" onclick={() => restoreHistoryItem(state)}
><i class="fas fa-undo mr-1"></i>Restore</button>
{#if type !== 'loader'}
<button class="btn btn-error" on:click={() => clearHistory(id)}
><i class="fas fa-trash-alt mr-1" />Delete</button>
<button class="btn btn-error" onclick={() => clearHistory(id)}
><i class="fas fa-trash-alt mr-1"></i>Delete</button>
{/if}
</div>
</div>
+13 -12
View File
@@ -1,6 +1,6 @@
<script context="module" lang="ts">
import { version } from 'mermaid/package.json';
<script module lang="ts">
import { logEvent, plausible } from '$lib/util/stats';
import { version } from 'mermaid/package.json';
void logEvent('version', {
mermaidVersion: version
});
@@ -8,13 +8,13 @@
<script lang="ts">
import { env } from '$lib/util/env';
import Theme from './Theme.svelte';
import { dismissPromotion, getActivePromotion } from '$lib/util/promos/promo';
import Privacy from './Privacy.svelte';
import Theme from './Theme.svelte';
const { isEnabledMermaidChartLinks } = env;
let isMenuOpen = false;
let isMenuOpen = $state(false);
function toggleMenu() {
isMenuOpen = !isMenuOpen;
@@ -57,7 +57,7 @@
});
}
let activePromotion = getActivePromotion();
let activePromotion = $state(getActivePromotion());
const trackBannerClick = () => {
if (!plausible || !activePromotion) {
@@ -76,18 +76,19 @@
class="flex flex-grow"
role="button"
tabindex="0"
on:click={trackBannerClick}
on:keypress={trackBannerClick}>
<svelte:component this={activePromotion.component} />
onclick={trackBannerClick}
onkeypress={trackBannerClick}>
<activePromotion.component />
</div>
<button
class="rounded hover:text-black"
title="Dismiss banner"
on:click={() => {
aria-label="Dismiss banner"
onclick={() => {
dismissPromotion(activePromotion?.id);
activePromotion = undefined;
}}>
<i class="fa fa-close px-2" />
<i class="fa fa-close px-2"></i>
</button>
</div>
{/if}
@@ -136,7 +137,7 @@
type="checkbox"
id="menu-toggle"
bind:checked={isMenuOpen}
on:click={toggleMenu} />
onclick={toggleMenu} />
<div class="hidden w-full lg:flex lg:w-auto lg:items-center" id="menu">
<Theme />
@@ -148,7 +149,7 @@
<li>
<a class="btn btn-ghost" target="_blank" {href}>
{#if icon}
<i class={icon} />
<i class={icon}></i>
{:else if img}
<img src={img} alt={title} />
{/if}
+2 -2
View File
@@ -225,10 +225,10 @@ packet-beta
{#each diagramOrder as sample}
<button
class="btn btn-primary btn-sm w-fit min-w-20 flex-grow normal-case"
on:click={() => loadSampleDiagram(sample)}>
onclick={() => loadSampleDiagram(sample)}>
{sample}
{#if newDiagrams.includes(sample)}
<span class="fa fa-heart ml-2" />
<span class="fa fa-heart ml-2"></span>
{/if}
</button>
{/each}
+4 -4
View File
@@ -27,7 +27,7 @@
</script>
<div class="dropdown hidden lg:block">
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<div tabindex="0" class="btn btn-ghost">
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -49,7 +49,7 @@
</div>
<div
class="dropdown-content top-px mt-14 h-96 w-56 overflow-y-auto bg-base-200 text-base-content shadow-2xl">
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<ul tabindex="0" class="menu compact p-4">
{#each themes as theme}
<li class:bordered={$themeStore.theme !== undefined && theme.includes($themeStore.theme)}>
@@ -57,8 +57,8 @@
role="menuitem"
tabindex="0"
class="btn btn-ghost justify-start"
on:click={() => setTheme(theme)}
on:keypress={() => setTheme(theme)}>{theme}</span>
onclick={() => setTheme(theme)}
onkeypress={() => setTheme(theme)}>{theme}</span>
</li>
{/each}
</ul>
+9 -9
View File
@@ -12,12 +12,12 @@
let code = '';
let config = '';
let container: HTMLDivElement;
let container: HTMLDivElement | undefined = $state();
let rough: boolean;
let view: HTMLDivElement;
let error = false;
let outOfSync = false;
let hide = false;
let view: HTMLDivElement | undefined = $state();
let error = $state(false);
let outOfSync = $state(false);
let hide = $state(false);
let manualUpdate = true;
let panZoomEnabled = $stateStore.panZoom;
let pzoom: typeof panzoom | undefined;
@@ -93,7 +93,7 @@
config = state.mermaid;
panZoomEnabled = state.panZoom;
rough = state.rough;
const scroll = view.parentElement?.scrollTop;
const scroll = view?.parentElement?.scrollTop;
delete container.dataset.processed;
const { svg, bindFunctions } = await renderDiagram(
Object.assign({}, JSON.parse(state.mermaid)) as MermaidConfig,
@@ -131,7 +131,7 @@
}
}
}
if (view.parentElement && scroll) {
if (view?.parentElement && scroll) {
view.parentElement.scrollTop = scroll;
}
error = false;
@@ -171,13 +171,13 @@
{#if $stateStore.autoSync}
It will be updated automatically.
{:else}
Press <i class="fas fa-sync" /> (Sync button) or <kbd>{cmdKey} + Enter</kbd> to sync.
Press <i class="fas fa-sync"></i> (Sync button) or <kbd>{cmdKey} + Enter</kbd> to sync.
{/if}
</div>
{/if}
<div id="view" bind:this={view} class="h-full p-2" class:error class:outOfSync>
<div id="container" bind:this={container} class="h-full overflow-auto" class:hide />
<div id="container" bind:this={container} class="h-full overflow-auto" class:hide></div>
</div>
<style>
+1 -1
View File
@@ -23,7 +23,7 @@
];
let index = Math.floor(Math.random() * taglines.length);
let currentTagline = taglines[index];
let currentTagline = $state(taglines[index]);
const interval = setInterval(() => {
index = (index + 1) % taglines.length;
+11 -5
View File
@@ -1,11 +1,17 @@
<script lang="ts">
import '../app.postcss';
import { base } from '$app/paths';
import { onMount } from 'svelte';
import { loadingStateStore } from '$lib/util/loading';
import { setTheme, themeStore } from '$lib/util/theme';
import { toggleDarkTheme } from '$lib/util/state';
import { setTheme, themeStore } from '$lib/util/theme';
import { initHandler } from '$lib/util/util';
import { onMount, type Snippet } from 'svelte';
import '../app.postcss';
interface Props {
children?: Snippet;
}
let { children }: Props = $props();
// 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.
@@ -42,14 +48,14 @@
</script>
<main class="h-screen text-primary-content">
<slot />
{@render children?.()}
</main>
{#if $loadingStateStore.loading}
<div
class="absolute left-0 top-0 z-50 flex h-screen w-screen justify-center bg-gray-600 align-middle opacity-50">
<div class="my-auto text-4xl font-bold text-indigo-100">
<div class="loader mx-auto" />
<div class="loader mx-auto"></div>
<div>{$loadingStateStore.message}</div>
</div>
</div>
+21 -15
View File
@@ -84,9 +84,9 @@
config: '/syntax/xyChart.html#chart-configurations'
}
};
let docURL = docURLBase;
let activeTabID = 'code';
let docKey = '';
let docURL = $state(docURLBase);
let activeTabID = $state('code');
let docKey = $state('');
stateStore.subscribe(({ code, editorMode }: ValidatedState) => {
activeTabID = editorMode;
const codeTypeMatch = /(\S+)\s/.exec(code);
@@ -97,8 +97,8 @@
}
});
const tabSelectHandler = (message: CustomEvent<Tab>) => {
const editorMode: EditorMode = message.detail.id === 'code' ? 'code' : 'config';
const tabSelectHandler = (tab: Tab) => {
const editorMode: EditorMode = tab.id === 'code' ? 'code' : 'config';
updateCodeStore({ editorMode });
};
@@ -145,8 +145,9 @@
<Navbar />
<div class="flex flex-1 overflow-hidden">
<div class="hidden flex-col md:flex" id="editorPane" style="width: 40%">
<Card on:select={tabSelectHandler} {tabs} isCloseable={false} {activeTabID} title="Mermaid">
<div slot="actions" class="flex flex-row items-center">
<Card onselect={tabSelectHandler} {tabs} isClosable={false} {activeTabID} title="Mermaid">
{#snippet actions()}
<div class="flex flex-row items-center">
<div class="form-control flex-row items-center">
<label class="label cursor-pointer" for="autoSync">
<span> Auto sync</span>
@@ -162,18 +163,20 @@
<button
class="btn btn-secondary btn-xs mr-1"
title="Sync Diagram ({cmdKey} + Enter)"
aria-label="Sync Diagram"
data-cy="sync"
on:click={syncDiagram}><i class="fas fa-sync" /></button>
onclick={syncDiagram}><i class="fas fa-sync"></i></button>
{/if}
<button
class="btn btn-secondary btn-xs"
title="View documentation for {docKey.replace('Diagram', '')} diagram">
<a target="_blank" href={docURL} data-cy="docs">
<i class="fas fa-book mr-1" />Docs
<i class="fas fa-book mr-1"></i>Docs
</a>
</button>
</div>
{/snippet}
<Editor />
</Card>
@@ -184,10 +187,11 @@
<Actions />
</div>
</div>
<div id="resizeHandler" class="hidden md:block" />
<div id="resizeHandler" class="hidden md:block"></div>
<div class="flex flex-1 flex-col overflow-hidden">
<Card title="Diagram" isCloseable={false}>
<div slot="actions" class="flex flex-row items-center gap-2">
<Card title="Diagram" isClosable={false}>
{#snippet actions()}
<div class="flex flex-row items-center gap-2">
<label
class="label flex cursor-pointer gap-1 py-0"
title="Rough mode is in beta. Features like clickable nodes, Pan & Zoom, will be disabled."
@@ -215,17 +219,19 @@
href={`${base}/view#${$stateStore.serialized}`}
target="_blank"
class="btn btn-secondary btn-xs gap-1"
title="View diagram in new page"><i class="fas fa-external-link-alt" />Full screen</a>
title="View diagram in new page"
><i class="fas fa-external-link-alt"></i>Full screen</a>
{#if env.isEnabledMermaidChartLinks}
<a
href={`${MCBaseURL}/app/plugin/save?state=${$stateStore.serialized}`}
target="_blank"
class="btn btn-secondary btn-xs gap-1 bg-[#FF3570]"
title="Save diagram in Mermaid Chart"
><img src="./mermaidchart-logo.svg" class="h-5 w-5" alt="Mermaid chart logo" />Save to
Mermaid Chart</a>
><img src="./mermaidchart-logo.svg" class="h-5 w-5" alt="Mermaid chart logo" />Save
to Mermaid Chart</a>
{/if}
</div>
{/snippet}
<div class="flex-1 overflow-auto">
<View />
+2 -1
View File
@@ -1,5 +1,6 @@
import 'vitest-dom/extend-expect';
import '@testing-library/jest-dom/vitest';
import { beforeAll, vi } from 'vitest';
import 'vitest-dom/extend-expect';
// TODO: Remove once https://github.com/sveltejs/kit/issues/6259 is closed.
beforeAll(() => {
+2 -1
View File
@@ -1,8 +1,9 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { svelteTesting } from '@testing-library/svelte/vite';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [sveltekit()],
plugins: [sveltekit(), svelteTesting()],
envPrefix: 'MERMAID_',
optimizeDeps: { include: ['mermaid'] },
server: {
+430 -864
View File
File diff suppressed because it is too large Load Diff