Compare commits

..

6 Commits

Author SHA1 Message Date
Knut Sveidqvist
7f91ed32bc Adding dev tool for simplified development 2025-12-22 09:28:04 +01:00
Sidharth Vinod
d5bc07dc0c fix: Remove unnecessary changeset 2025-12-19 16:50:52 +05:30
Knut Sveidqvist
80a686be03 Merge pull request #7245 from mermaid-js/canonicals-to-mermaid-ai
setting canonicals to mermaid.ai/open-source
2025-12-19 10:12:44 +00:00
autofix-ci[bot]
d26f2c6043 [autofix.ci] apply automated fixes 2025-12-15 14:42:00 +00:00
Knut Sveidqvist
8ca7a28bf3 Update canonicals in big-trees-walk.md
Set canonicals for Mermaid documentation to mermaid.ai/open-source.
2025-12-15 15:32:33 +01:00
Knut Sveidqvist
6b77c9c4c7 setting canonicals to mermaid.ai/open-source 2025-12-15 15:17:56 +01:00
70 changed files with 3612 additions and 358 deletions

View File

@@ -0,0 +1,53 @@
# Dev Explorer frontend: architecture + debugging notes
## Root cause of the “CSS changes do nothing” problem
The page loads `/dev/styles.css`, but **document-level CSS does not apply through a shadow DOM boundary**.
Historically, `dev-explorer-app` was a `LitElement` using Lits default `shadowRoot`, while the rest of the UI used light DOM. That meant:
- The browser showed the _right classes_ (`card`, `card-folder`, `card-file`) in Elements panel.
- `/dev/styles.css` was clearly being served/updated.
- Yet computed styles for `.card` looked like UA defaults because the selector never matched across the shadow root.
Fix: make `dev-explorer-app` light DOM too (`createRenderRoot() { return this; }`), so `/dev/styles.css` reliably styles the whole UI.
## Debugging traps (and fast detection)
- **Shadow DOM trap**
- Symptom: “CSS is loaded but doesnt apply”, especially for simple class selectors.
- Fast check:
- DevTools console: `document.querySelector('dev-explorer-app')?.shadowRoot`
- If non-null, global CSS wont style inside it.
- Or: right-click an element you expect styled → “Reveal in Elements” → see if its under `#shadow-root`.
- **“Light DOM child inside shadow DOM parent” trap**
- Even if a child component uses `createRenderRoot() { return this; }`,
if its _rendered inside the parents shadow root_, its still effectively in shadow for document styles.
- **Dev loop trap (CSS-only changes dont trigger reload)**
- The server watches TypeScript bundle inputs + `.mmd` files; static `/dev/styles.css` previously didnt emit SSE reload events.
- That makes CSS changes look flaky unless you manually refresh.
- Fix: watch `.esbuild/dev-explorer/public/**/*` and emit SSE on changes.
- **Caching trap (less common here, but real)**
- If a query param is constant (`?v=3`) and you dont reload, the browser can keep a cached stylesheet.
- Fast check: DevTools → Network → disable cache + hard reload; or check “(from disk cache)” on the CSS request.
## Styling strategy recommendation (pragmatic)
For a dev-only explorer, keep it simple:
- **Light DOM everywhere**
- **One stylesheet**: `.esbuild/dev-explorer/public/styles.css` served as `/dev/styles.css`
- **Scoped selectors** under `dev-explorer-app` to avoid generic class collisions (`.header`, `.content`, etc.)
If you later _want_ Shadow DOM isolation, do it deliberately:
- Put UI styles in Lit `static styles` or adopt a `CSSStyleSheet` into `this.renderRoot.adoptedStyleSheets`.
- Avoid relying on document CSS selectors for component internals.
## Shoelace integration notes
- Current setup is correct for dev: `setBasePath('/dev/vendor/shoelace')` and `registerIconLibrary(...)`.
- Prefer theming via CSS variables (Shoelace tokens) rather than overriding internal parts everywhere.

View File

@@ -0,0 +1,187 @@
import { LitElement, html } from 'lit';
import '@shoelace-style/shoelace/dist/components/input/input.js';
export type LogLevel = 'info' | 'warn' | 'error';
export type LogEntry = {
ts: number;
level: LogLevel;
message: string;
};
function formatTs(ts: number) {
const d = new Date(ts);
return (
d.toLocaleTimeString(undefined, { hour12: false }) +
'.' +
String(d.getMilliseconds()).padStart(3, '0')
);
}
function levelVariant(level: LogLevel) {
switch (level) {
case 'error':
return 'danger';
case 'warn':
return 'warning';
default:
return 'neutral';
}
}
type DisplayLevel = 'debug' | LogLevel;
function displayLevel(entry: LogEntry): DisplayLevel {
// Mermaid often emits debug lines through console.log/info with a marker.
if (entry.message.includes(': DEBUG :')) return 'debug';
return entry.level;
}
function displayVariant(level: DisplayLevel) {
switch (level) {
case 'error':
return 'danger';
case 'warn':
return 'warning';
case 'debug':
return 'success';
default:
return 'neutral';
}
}
export class DevConsolePanel extends LitElement {
static properties = {
logs: { state: true },
showInfo: { state: true },
showWarn: { state: true },
showError: { state: true },
showDebug: { state: true },
filterText: { state: true },
};
declare logs: LogEntry[];
declare showInfo: boolean;
declare showWarn: boolean;
declare showError: boolean;
declare showDebug: boolean;
declare filterText: string;
constructor() {
super();
this.logs = [];
this.showInfo = true;
this.showWarn = true;
this.showError = true;
this.showDebug = true;
this.filterText = '';
}
createRenderRoot() {
return this;
}
clear() {
this.logs = [];
}
append(entry: LogEntry) {
this.logs = [...this.logs, entry];
}
async copyVisible() {
const visible = this.filteredLogs();
const text = visible
.map((l) => `[${formatTs(l.ts)}] ${l.level.toUpperCase()} ${l.message}`)
.join('\n');
await navigator.clipboard.writeText(text);
}
filteredLogs() {
const q = this.filterText.trim().toLowerCase();
return this.logs.filter((l) => {
const isDebugLine = l.message.includes(': DEBUG :');
// Treat debug-marked lines as their own independent toggle, since Mermaid often routes them through
// console.log/info with a marker rather than a distinct "debug" level.
if (isDebugLine && !this.showDebug) return false;
if (!isDebugLine) {
const levelOk =
l.level === 'info' ? this.showInfo : l.level === 'warn' ? this.showWarn : this.showError;
if (!levelOk) return false;
}
if (!q) return true;
return l.message.toLowerCase().includes(q);
});
}
render() {
const visible = this.filteredLogs();
return html`
<div class="console">
<div class="console-toolbar">
<div class="spacer"></div>
<sl-input
size="small"
placeholder="filter…"
clearable
value=${this.filterText}
@sl-input=${(e: any) => (this.filterText = e.target.value ?? '')}
></sl-input>
<sl-checkbox
size="small"
?checked=${this.showDebug}
@sl-change=${(e: any) => (this.showDebug = e.target.checked)}
>debug</sl-checkbox
>
<sl-checkbox
size="small"
?checked=${this.showInfo}
@sl-change=${(e: any) => (this.showInfo = e.target.checked)}
>info</sl-checkbox
>
<sl-checkbox
size="small"
?checked=${this.showWarn}
@sl-change=${(e: any) => (this.showWarn = e.target.checked)}
>warn</sl-checkbox
>
<sl-checkbox
size="small"
?checked=${this.showError}
@sl-change=${(e: any) => (this.showError = e.target.checked)}
>error</sl-checkbox
>
<sl-button size="small" variant="default" @click=${() => void this.copyVisible()}>
<sl-icon slot="prefix" name="clipboard"></sl-icon>
Copy
</sl-button>
<sl-button size="small" variant="default" @click=${() => this.clear()}>
<sl-icon slot="prefix" name="trash"></sl-icon>
Clear
</sl-button>
</div>
<div class="console-body">
${visible.length === 0
? html`<div class="empty">No logs yet.</div>`
: visible.map((l) => {
const lvl = displayLevel(l);
return html`
<div class="logline">
<div class="logmeta">
<sl-badge variant=${displayVariant(lvl)}>${lvl}</sl-badge>
<span class="path">${formatTs(l.ts)}</span>
</div>
<div>${l.message}</div>
</div>
`;
})}
</div>
</div>
`;
}
}
customElements.define('dev-console-panel', DevConsolePanel);

View File

@@ -0,0 +1,551 @@
import { LitElement, html, nothing } from 'lit';
import '@shoelace-style/shoelace/dist/components/button/button.js';
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
import '@shoelace-style/shoelace/dist/components/select/select.js';
import '@shoelace-style/shoelace/dist/components/option/option.js';
import '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js';
import '@shoelace-style/shoelace/dist/components/split-panel/split-panel.js';
import './console-panel';
import type { LogEntry, LogLevel } from './console-panel';
type MermaidIife = {
initialize: (config: Record<string, unknown>) => void | Promise<void>;
render: (
id: string,
text: string,
container?: Element
) => Promise<{ svg: string; bindFunctions?: (el: Element) => void }>;
};
declare global {
interface Window {
mermaid?: MermaidIife;
mermaidReady?: Promise<MermaidIife>;
}
}
function stringifyArgs(args: unknown[]) {
// Mermaid's internal logger frequently uses console formatting like:
// console.log('%c...message...', 'color: lightgreen', ...)
// For the log panel we want the human text, not the formatting tokens/styles.
let normalized = [...args];
if (typeof normalized[0] === 'string') {
const fmt = normalized[0];
const cssCount = (fmt.match(/%c/g) ?? []).length;
if (cssCount > 0) {
normalized[0] = fmt.replaceAll('%c', '');
// Drop the corresponding CSS args that follow the format string.
normalized.splice(1, cssCount);
}
}
return normalized
.map((a) => {
if (typeof a === 'string') return a;
if (a instanceof Error) return a.stack ?? a.message;
try {
return JSON.stringify(a);
} catch {
return String(a);
}
})
.join(' ')
.replace(/\s+/g, ' ')
.trim();
}
type MermaidTheme = 'default' | 'dark' | 'forest' | 'neutral' | 'base';
type MermaidLayout = 'dagre' | 'elk';
type MermaidLogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
const DEFAULT_THEME: MermaidTheme = 'default';
const DEFAULT_LAYOUT: MermaidLayout = 'dagre';
const DEFAULT_MERMAID_LOG_LEVEL: MermaidLogLevel = 'warn';
function readUrlParam(name: string) {
try {
return new URL(window.location.href).searchParams.get(name);
} catch {
return null;
}
}
function setUrlParams(pairs: Record<string, string | null | undefined>) {
const url = new URL(window.location.href);
for (const [k, v] of Object.entries(pairs)) {
if (!v) url.searchParams.delete(k);
else url.searchParams.set(k, v);
}
history.replaceState(null, '', url);
}
function readStorage(key: string) {
try {
return localStorage.getItem(key);
} catch {
return null;
}
}
function writeStorage(key: string, value: string) {
try {
localStorage.setItem(key, value);
} catch {
// ignore
}
}
function isTheme(v: unknown): v is MermaidTheme {
return v === 'default' || v === 'dark' || v === 'forest' || v === 'neutral' || v === 'base';
}
function isLayout(v: unknown): v is MermaidLayout {
return v === 'dagre' || v === 'elk';
}
function isMermaidLogLevel(v: unknown): v is MermaidLogLevel {
return (
v === 'trace' || v === 'debug' || v === 'info' || v === 'warn' || v === 'error' || v === 'fatal'
);
}
function normalizeLayout(v: unknown): MermaidLayout | null {
// Back-compat:
// - older UI used `renderer=dagre-d3|dagre-wrapper|elk`
// - new UI uses `layout=dagre|elk`
if (v === 'dagre' || v === 'elk') return v;
if (v === 'dagre-d3' || v === 'dagre-wrapper') return 'dagre';
return null;
}
function parseBoolean(v: unknown): boolean | null {
if (typeof v !== 'string') return null;
const s = v.trim().toLowerCase();
if (['1', 'true', 'yes', 'on'].includes(s)) return true;
if (['0', 'false', 'no', 'off'].includes(s)) return false;
return null;
}
export class DevDiagramViewer extends LitElement {
static properties = {
filePath: { type: String },
sseToken: { type: Number },
theme: { state: true },
layout: { state: true },
mermaidLogLevel: { state: true },
useMaxWidth: { state: true },
loading: { state: true },
error: { state: true },
source: { state: true },
svg: { state: true },
};
declare filePath: string;
declare sseToken: number;
declare theme: MermaidTheme;
declare layout: MermaidLayout;
declare mermaidLogLevel: MermaidLogLevel;
declare useMaxWidth: boolean;
declare loading: boolean;
declare error: string;
declare source: string;
declare svg: string;
#renderSeq = 0;
#consolePatched = false;
#originalConsole?: {
log: typeof console.log;
info: typeof console.info;
debug: typeof console.debug;
warn: typeof console.warn;
error: typeof console.error;
};
constructor() {
super();
const themeParam = readUrlParam('theme');
const layoutParam = readUrlParam('layout');
const rendererParam = readUrlParam('renderer'); // legacy
const logParam = readUrlParam('logLevel');
const useMaxWidthParam = readUrlParam('useMaxWidth');
const storedTheme = readStorage('devExplorer.viewer.theme');
const storedLayout = readStorage('devExplorer.viewer.layout');
const storedRenderer = readStorage('devExplorer.viewer.renderer'); // legacy
const storedLog = readStorage('devExplorer.viewer.logLevel');
const storedUseMaxWidth = readStorage('devExplorer.viewer.useMaxWidth');
this.theme = isTheme(themeParam)
? themeParam
: isTheme(storedTheme)
? storedTheme
: DEFAULT_THEME;
this.layout =
normalizeLayout(layoutParam) ??
normalizeLayout(rendererParam) ??
normalizeLayout(storedLayout) ??
normalizeLayout(storedRenderer) ??
DEFAULT_LAYOUT;
this.mermaidLogLevel = isMermaidLogLevel(logParam)
? logParam
: isMermaidLogLevel(storedLog)
? storedLog
: DEFAULT_MERMAID_LOG_LEVEL;
this.useMaxWidth = parseBoolean(useMaxWidthParam) ?? parseBoolean(storedUseMaxWidth) ?? true;
this.filePath = '';
this.sseToken = 0;
this.loading = true;
this.error = '';
this.source = '';
this.svg = '';
}
createRenderRoot() {
return this;
}
connectedCallback() {
super.connectedCallback();
this.#installConsoleCapture();
}
disconnectedCallback() {
super.disconnectedCallback();
this.#restoreConsoleCapture();
}
updated(changed: Map<string, unknown>) {
if (changed.has('filePath')) {
void this.#loadAndRender();
} else if (changed.has('sseToken')) {
// On rebuild events, re-fetch + re-render the currently open diagram.
if (this.filePath) void this.#loadAndRender();
} else if (
changed.has('theme') ||
changed.has('layout') ||
changed.has('mermaidLogLevel') ||
changed.has('useMaxWidth')
) {
// Re-render the currently loaded diagram with the new config without refetching.
if (this.source) void this.#renderCurrentSource();
}
}
#back() {
this.dispatchEvent(new CustomEvent('back', { bubbles: true, composed: true }));
}
#persistSettings() {
writeStorage('devExplorer.viewer.theme', this.theme);
writeStorage('devExplorer.viewer.layout', this.layout);
writeStorage('devExplorer.viewer.logLevel', this.mermaidLogLevel);
writeStorage('devExplorer.viewer.useMaxWidth', String(this.useMaxWidth));
setUrlParams({
theme: this.theme,
layout: this.layout,
renderer: null, // drop legacy param
logLevel: this.mermaidLogLevel,
useMaxWidth: this.useMaxWidth ? '1' : '0',
});
}
#syncConsolePanelFilters() {
const panel = this.querySelector('dev-console-panel') as any;
if (!panel) return;
// This is intentionally opinionated: less noise by default as logLevel increases.
if (
this.mermaidLogLevel === 'trace' ||
this.mermaidLogLevel === 'debug' ||
this.mermaidLogLevel === 'info'
) {
panel.showInfo = true;
panel.showWarn = true;
panel.showError = true;
return;
}
if (this.mermaidLogLevel === 'warn') {
panel.showInfo = false;
panel.showWarn = true;
panel.showError = true;
return;
}
// error / fatal
panel.showInfo = false;
panel.showWarn = false;
panel.showError = true;
}
#appendLog(entry: LogEntry) {
const panel = this.querySelector('dev-console-panel') as any;
panel?.append?.(entry);
}
#installConsoleCapture() {
if (this.#consolePatched) return;
this.#consolePatched = true;
this.#originalConsole = {
log: console.log,
info: console.info,
debug: console.debug,
warn: console.warn,
error: console.error,
};
const capture = (level: LogLevel, args: unknown[]) => {
this.#appendLog({
ts: Date.now(),
level,
message: stringifyArgs(args),
});
};
// Mermaid uses its own logger which routes to console.info/debug/warn/error.
// Capture those too (map debug/info/log -> panel "info").
console.log = (...args) => {
capture('info', args);
this.#originalConsole!.log.apply(console, args as any);
};
console.info = (...args) => {
capture('info', args);
this.#originalConsole!.info.apply(console, args as any);
};
console.debug = (...args) => {
capture('info', args);
this.#originalConsole!.debug.apply(console, args as any);
};
console.warn = (...args) => {
capture('warn', args);
this.#originalConsole!.warn.apply(console, args as any);
};
console.error = (...args) => {
capture('error', args);
this.#originalConsole!.error.apply(console, args as any);
};
}
#restoreConsoleCapture() {
if (!this.#consolePatched) return;
this.#consolePatched = false;
if (!this.#originalConsole) return;
console.log = this.#originalConsole.log;
console.info = this.#originalConsole.info;
console.debug = this.#originalConsole.debug;
console.warn = this.#originalConsole.warn;
console.error = this.#originalConsole.error;
this.#originalConsole = undefined;
}
#clearLogs() {
const panel = this.querySelector('dev-console-panel') as any;
panel?.clear?.();
}
async #fetchSource() {
const url = new URL('/dev/api/file', window.location.origin);
url.searchParams.set('path', this.filePath);
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.text();
}
async #loadAndRender() {
const seq = ++this.#renderSeq;
this.loading = true;
this.error = '';
this.svg = '';
this.#clearLogs();
this.#syncConsolePanelFilters();
try {
const source = await this.#fetchSource();
if (seq !== this.#renderSeq) return;
this.source = source;
await this.#renderMermaid(source);
} catch (e) {
this.error = e instanceof Error ? e.message : String(e);
} finally {
this.loading = false;
}
}
async #renderCurrentSource() {
const seq = ++this.#renderSeq;
this.loading = true;
this.error = '';
this.svg = '';
this.#clearLogs();
this.#syncConsolePanelFilters();
try {
const source = this.source;
if (!source) return;
if (seq !== this.#renderSeq) return;
await this.#renderMermaid(source);
} catch (e) {
this.error = e instanceof Error ? e.message : String(e);
} finally {
this.loading = false;
}
}
async #renderMermaid(text: string) {
const m = (await window.mermaidReady?.catch(() => undefined)) ?? window.mermaid;
if (!m) {
throw new Error(
'window.mermaid is not available (did /mermaid.esm.mjs load and did the bootstrap set window.mermaid?)'
);
}
const initConfig = {
startOnLoad: false,
securityLevel: 'strict',
theme: this.theme,
layout: this.layout,
logLevel: this.mermaidLogLevel,
flowchart: {
useMaxWidth: this.useMaxWidth,
},
};
// Debugging aid: log exactly what we are about to initialize/render with.
// Do it *before* initialize so detector issues can be correlated.
const previewLimit = 4000;
const preview =
text.length > previewLimit
? `${text.slice(0, previewLimit)}\n… (${text.length - previewLimit} more chars)`
: text;
console.log('[dev-explorer] mermaid.initialize config:', initConfig);
console.log('[dev-explorer] diagram source preview:\n' + preview);
// Keep it deterministic-ish between reloads.
await m.initialize(initConfig);
const id = `dev-explorer-${Date.now()}-${Math.random().toString(16).slice(2)}`;
const { svg, bindFunctions } = await m.render(id, text);
this.svg = svg;
// Allow mermaid to attach event handlers (e.g. links).
await this.updateComplete;
// If the page ever ended up scrolled down due to a previous oversized render, snap back to top.
// (We intentionally removed vertical scrollbars in the viewer.)
try {
window.scrollTo(0, 0);
} catch {
// ignore
}
const container = this.querySelector('.diagram-inner');
if (container && bindFunctions) bindFunctions(container);
}
render() {
return html`
<div class="header">
<sl-button size="small" variant="default" @click=${() => this.#back()}>
<sl-icon slot="prefix" name="arrow-left"></sl-icon>
Back
</sl-button>
<div style="min-width: 0;">
<div class="title">Diagram</div>
<div class="path">${this.filePath}</div>
</div>
<div class="spacer"></div>
<div class="viewer-controls">
<div class="control">
<span class="label">Theme</span>
<sl-select
size="small"
value=${this.theme}
@sl-change=${(e: any) => {
const v = e.target?.value;
if (isTheme(v)) {
this.theme = v;
this.#persistSettings();
}
}}
>
<sl-option value="default">default</sl-option>
<sl-option value="dark">dark</sl-option>
<sl-option value="forest">forest</sl-option>
<sl-option value="neutral">neutral</sl-option>
<sl-option value="base">base</sl-option>
</sl-select>
</div>
<div class="control">
<span class="label">Layout</span>
<sl-select
size="small"
value=${this.layout}
@sl-change=${(e: any) => {
const v = e.target?.value;
if (isLayout(v)) {
this.layout = v;
this.#persistSettings();
}
}}
>
<sl-option value="dagre">dagre</sl-option>
<sl-option value="elk">elk</sl-option>
</sl-select>
</div>
<div class="control">
<span class="label">Log</span>
<sl-select
size="small"
value=${this.mermaidLogLevel}
@sl-change=${(e: any) => {
const v = e.target?.value;
if (isMermaidLogLevel(v)) {
this.mermaidLogLevel = v;
this.#persistSettings();
this.#syncConsolePanelFilters();
}
}}
>
<sl-option value="trace">trace</sl-option>
<sl-option value="debug">debug</sl-option>
<sl-option value="info">info</sl-option>
<sl-option value="warn">warn</sl-option>
<sl-option value="error">error</sl-option>
<sl-option value="fatal">fatal</sl-option>
</sl-select>
</div>
<div class="control">
<sl-checkbox
size="small"
?checked=${this.useMaxWidth}
@sl-change=${(e: any) => {
this.useMaxWidth = Boolean(e.target?.checked);
this.#persistSettings();
}}
>useMaxWidth</sl-checkbox
>
</div>
</div>
${this.loading ? html`<div class="subtle">rendering…</div>` : nothing}
</div>
${this.error
? html`<div class="empty">Error: <span class="path">${this.error}</span></div>`
: nothing}
<div class="content">
<sl-split-panel position="75" style="height: 100%;">
<div slot="start" class="diagram">
<div class="diagram-inner" data-theme=${this.theme} .innerHTML=${this.svg}></div>
</div>
<div slot="end" style="height: 100%;">
<dev-console-panel></dev-console-panel>
</div>
</sl-split-panel>
</div>
`;
}
}
customElements.define('dev-diagram-viewer', DevDiagramViewer);

View File

@@ -0,0 +1,143 @@
import { LitElement, html, nothing } from 'lit';
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';
import { registerIconLibrary } from '@shoelace-style/shoelace/dist/utilities/icon-library.js';
import '@shoelace-style/shoelace/dist/components/breadcrumb/breadcrumb.js';
import '@shoelace-style/shoelace/dist/components/breadcrumb-item/breadcrumb-item.js';
import '@shoelace-style/shoelace/dist/components/button/button.js';
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
import '@shoelace-style/shoelace/dist/components/split-panel/split-panel.js';
import '@shoelace-style/shoelace/dist/components/badge/badge.js';
import '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js';
import './file-explorer';
import './diagram-viewer';
type ViewMode = 'explorer' | 'viewer';
function getInitialStateFromUrl() {
const url = new URL(window.location.href);
const dir = url.searchParams.get('path') ?? '';
const file = url.searchParams.get('file') ?? '';
return { dir, file };
}
function setUrlState({ dir, file }: { dir: string; file: string }) {
const url = new URL(window.location.href);
url.searchParams.delete('path');
url.searchParams.delete('file');
if (dir) url.searchParams.set('path', dir);
if (file) url.searchParams.set('file', file);
history.replaceState(null, '', url);
}
export class DevExplorerApp extends LitElement {
static properties = {
mode: { state: true },
dirPath: { state: true },
lastDirPath: { state: true },
filePath: { state: true },
sseToken: { state: true },
};
declare mode: ViewMode;
declare dirPath: string;
declare lastDirPath: string;
declare filePath: string;
declare sseToken: number;
#events?: EventSource;
constructor() {
super();
const { dir, file } = getInitialStateFromUrl();
this.dirPath = dir;
this.lastDirPath = dir;
this.filePath = file;
this.mode = file ? 'viewer' : 'explorer';
this.sseToken = 0;
setBasePath('/dev/vendor/shoelace');
registerIconLibrary('default', {
resolver: (name) => `/dev/vendor/shoelace/assets/icons/${name}.svg`,
});
}
createRenderRoot() {
// Use light DOM so document-level CSS (public/styles.css => /dev/styles.css) applies to the UI.
// Without this, Lit's default shadow root will block global selectors like `.list` / `button.card`.
return this;
}
connectedCallback() {
super.connectedCallback();
this.#events = new EventSource('/events');
this.#events.onmessage = () => {
this.sseToken++;
};
window.addEventListener('popstate', this.#onPopState);
}
disconnectedCallback() {
super.disconnectedCallback();
this.#events?.close();
window.removeEventListener('popstate', this.#onPopState);
}
#onPopState = () => {
const { dir, file } = getInitialStateFromUrl();
this.dirPath = dir;
this.lastDirPath = dir;
this.filePath = file;
this.mode = file ? 'viewer' : 'explorer';
};
#goToDir = (dir: string) => {
this.dirPath = dir;
this.lastDirPath = dir;
this.mode = 'explorer';
this.filePath = '';
setUrlState({ dir, file: '' });
};
#openFile = (filePath: string) => {
this.filePath = filePath;
this.mode = 'viewer';
setUrlState({ dir: this.lastDirPath, file: filePath });
};
#backToExplorer = () => {
this.mode = 'explorer';
this.filePath = '';
setUrlState({ dir: this.lastDirPath, file: '' });
};
render() {
return html`
<div class="app">
${this.mode === 'explorer'
? html`
<dev-file-explorer
.path=${this.dirPath}
.sseToken=${this.sseToken}
@navigate=${(e: CustomEvent<{ path: string }>) => this.#goToDir(e.detail.path)}
@open-file=${(e: CustomEvent<{ path: string }>) => this.#openFile(e.detail.path)}
></dev-file-explorer>
`
: nothing}
${this.mode === 'viewer'
? html`
<dev-diagram-viewer
.filePath=${this.filePath}
.sseToken=${this.sseToken}
@back=${this.#backToExplorer}
></dev-diagram-viewer>
`
: nothing}
</div>
`;
}
}
customElements.define('dev-explorer-app', DevExplorerApp);

View File

@@ -0,0 +1,182 @@
import { LitElement, html, nothing } from 'lit';
type Entry = {
name: string;
kind: 'dir' | 'file';
path: string;
};
type FilesResponse = {
root: string;
path: string;
entries: Entry[];
};
function dirname(posixPath: string) {
const p = posixPath.replaceAll('\\', '/').replace(/\/+$/, '');
if (!p) return '';
const idx = p.lastIndexOf('/');
if (idx <= 0) return '';
return p.slice(0, idx);
}
function pathSegments(posixPath: string) {
const p = posixPath.replaceAll('\\', '/').replace(/^\/+/, '').replace(/\/+$/, '');
if (!p) return [];
return p.split('/').filter(Boolean);
}
export class DevFileExplorer extends LitElement {
static properties = {
path: { type: String },
sseToken: { type: Number },
loading: { state: true },
error: { state: true },
root: { state: true },
entries: { state: true },
};
declare path: string;
declare sseToken: number;
declare loading: boolean;
declare error: string;
declare root: string;
declare entries: Entry[];
constructor() {
super();
this.path = '';
this.sseToken = 0;
this.loading = true;
this.error = '';
this.root = '';
this.entries = [];
}
createRenderRoot() {
// Use light DOM so global CSS in public/styles.css applies.
return this;
}
updated(changed: Map<string, unknown>) {
if (changed.has('path') || changed.has('sseToken')) {
void this.#load();
}
}
async #load() {
this.loading = true;
this.error = '';
try {
const url = new URL('/dev/api/files', window.location.origin);
if (this.path) url.searchParams.set('path', this.path);
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = (await res.json()) as FilesResponse;
this.root = json.root ?? '';
this.entries = json.entries ?? [];
} catch (e) {
this.error = e instanceof Error ? e.message : String(e);
this.entries = [];
} finally {
this.loading = false;
}
}
#emitNavigate(nextPath: string) {
this.dispatchEvent(
new CustomEvent('navigate', { detail: { path: nextPath }, bubbles: true, composed: true })
);
}
#emitOpenFile(filePath: string) {
this.dispatchEvent(
new CustomEvent('open-file', { detail: { path: filePath }, bubbles: true, composed: true })
);
}
#onActivate(kind: Entry['kind'], entryPath: string) {
if (kind === 'dir') {
this.#emitNavigate(entryPath);
} else {
this.#emitOpenFile(entryPath);
}
}
render() {
const segments = pathSegments(this.path);
const itemLabel = this.entries.length === 1 ? 'item' : 'items';
return html`
<div class="header">
<div style="min-width: 0;">
<div class="title">Dev Explorer</div>
<div class="subtle">
root:
<span class="path">${this.root || 'cypress/platform/dev-diagrams'}</span>
</div>
<div style="margin-top: 6px;">
<sl-breadcrumb>
<sl-breadcrumb-item @click=${() => this.#emitNavigate('')}>root</sl-breadcrumb-item>
${segments.map((seg, idx) => {
const to = segments.slice(0, idx + 1).join('/');
return html`<sl-breadcrumb-item @click=${() => this.#emitNavigate(to)}
>${seg}</sl-breadcrumb-item
>`;
})}
</sl-breadcrumb>
</div>
</div>
<div class="spacer"></div>
<div class="subtle">
${this.loading ? 'loading…' : html`<span>${this.entries.length} ${itemLabel}</span>`}
</div>
<sl-button
size="small"
variant="default"
?disabled=${!this.path}
@click=${() => this.#emitNavigate(dirname(this.path))}
>
<sl-icon slot="prefix" name="arrow-left"></sl-icon>
Up
</sl-button>
</div>
<div class="content">
${this.error
? html`<div class="empty">Error: <span class="path">${this.error}</span></div>`
: nothing}
${!this.error && !this.loading && this.entries.length === 0
? html`<div class="empty">No folders or <span class="path">.mmd</span> files here.</div>`
: nothing}
<div class="list">
${this.entries.map((e) => {
const icon = e.kind === 'dir' ? 'folder-fill' : 'file-earmark-code';
const cardClass = e.kind === 'dir' ? 'card card-folder' : 'card card-file';
const click =
e.kind === 'dir'
? () => this.#emitNavigate(e.path)
: () => this.#emitOpenFile(e.path);
const onKeyDown = (ev: KeyboardEvent) => {
if (ev.key === 'Enter' || ev.key === ' ') {
ev.preventDefault();
this.#onActivate(e.kind, e.path);
}
};
return html`
<button class=${cardClass} type="button" @click=${click} @keydown=${onKeyDown}>
<div class="card-inner">
<sl-icon class="card-icon" name=${icon}></sl-icon>
<div class="card-title">${e.name}</div>
</div>
</button>
`;
})}
</div>
</div>
`;
}
}
customElements.define('dev-file-explorer', DevFileExplorer);

View File

@@ -0,0 +1,39 @@
<!doctype html>
<html lang="en" class="sl-theme-dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Mermaid Dev Explorer</title>
<link rel="stylesheet" href="/dev/vendor/shoelace/themes/dark.css" />
<link rel="stylesheet" href="/dev/styles.css?v=6" />
</head>
<body>
<!-- Mermaid ESM + ELK layout loaders (required for `layout: 'elk'`) -->
<script type="module">
// Expose a single async hook so the app can reliably await Mermaid "activation".
// This avoids races where the UI calls initialize/render before layouts/diagrams are ready.
window.mermaidReady = (async () => {
try {
const [{ default: mermaid }, { default: layouts }] = await Promise.all([
import('/mermaid.esm.mjs'),
import('/mermaid-layout-elk.esm.mjs'),
]);
mermaid.registerLayoutLoaders(layouts);
// Keep the rest of the dev explorer simple: expose mermaid on window for the Lit components.
window.mermaid = mermaid;
return mermaid;
} catch (err) {
console.error('[dev-explorer] Failed to initialize mermaid (ESM + elk loaders).', err);
throw err;
}
})();
</script>
<dev-explorer-app></dev-explorer-app>
<script type="module" src="/dev/assets/explorer-app.js?v=6"></script>
</body>
</html>

View File

@@ -0,0 +1,359 @@
/* Dev Explorer tokens. Keep on :root so the page background picks them up too. */
:root {
--app-bg: #0b1020;
--app-fg: #e8eefc;
--panel-bg: #0f1733;
--muted: rgba(232, 238, 252, 0.75);
--border: rgba(232, 238, 252, 0.12);
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
monospace;
}
html,
body {
height: 100%;
}
body {
margin: 0;
background: var(--app-bg);
color: var(--app-fg);
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
/* Keep the page from becoming scrollable when components accidentally overflow. */
overflow: hidden;
}
a {
color: inherit;
}
/* Scope app-level layout rules to avoid generic class collisions. */
dev-explorer-app {
display: block;
height: 100%;
}
dev-explorer-app .app {
height: 100vh;
display: flex;
flex-direction: column;
}
/* Let the top-level view components actually fill the available vertical space. */
dev-explorer-app dev-file-explorer,
dev-explorer-app dev-diagram-viewer {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
dev-explorer-app .header {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid var(--border);
background: var(--panel-bg);
}
dev-explorer-app .viewer-controls {
display: inline-flex;
align-items: center;
gap: 10px;
margin-right: 8px;
}
dev-explorer-app .viewer-controls .control {
display: inline-flex;
align-items: center;
gap: 6px;
}
dev-explorer-app .viewer-controls .label {
font-size: 12px;
color: var(--muted);
user-select: none;
}
dev-explorer-app .viewer-controls sl-select {
width: 140px;
}
dev-explorer-app .header .spacer {
flex: 1;
}
dev-explorer-app .title {
font-weight: 600;
letter-spacing: 0.2px;
}
dev-explorer-app .subtle {
color: var(--muted);
font-size: 12px;
}
dev-explorer-app .content {
flex: 1;
min-height: 0;
overflow: auto;
}
/* Diagram view should behave like a full-height canvas; avoid nested scrollbars. */
dev-explorer-app dev-diagram-viewer .content {
overflow: hidden;
}
/* Shoelace split panel: ensure slot content can't overflow and push itself off-screen. */
dev-explorer-app sl-split-panel {
height: 100%;
overflow: hidden;
}
dev-explorer-app sl-split-panel::part(base) {
height: 100%;
overflow: hidden;
}
dev-explorer-app sl-split-panel::part(start),
dev-explorer-app sl-split-panel::part(end) {
overflow: hidden;
min-height: 0;
}
dev-explorer-app .list {
padding: 24px;
display: grid;
gap: 20px;
grid-template-columns: repeat(auto-fill, 260px);
}
/* Card base - use button element */
dev-explorer-app button.card {
all: unset;
box-sizing: border-box;
width: 260px;
height: 200px;
border-radius: 20px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
/* Folder card style */
dev-explorer-app button.card.card-folder {
background: linear-gradient(160deg, #1a3052 0%, #0d1a2d 100%);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.4),
0 2px 8px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
dev-explorer-app button.card.card-folder:hover {
transform: translateY(-6px) scale(1.02);
box-shadow:
0 16px 48px rgba(0, 0, 0, 0.5),
0 4px 12px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
/* File card style */
dev-explorer-app button.card.card-file {
background: linear-gradient(160deg, #1e2d4a 0%, #111827 100%);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.4),
0 2px 8px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
dev-explorer-app button.card.card-file:hover {
transform: translateY(-6px) scale(1.02);
box-shadow:
0 16px 48px rgba(0, 0, 0, 0.5),
0 4px 12px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
dev-explorer-app button.card:focus-visible {
outline: 3px solid rgba(96, 165, 250, 0.7);
outline-offset: 4px;
}
/* Subtle border overlay */
dev-explorer-app button.card::before {
content: '';
position: absolute;
inset: 0;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.08);
pointer-events: none;
}
dev-explorer-app .card-inner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
padding: 24px;
width: 100%;
height: 100%;
box-sizing: border-box;
}
/* Icon styling */
dev-explorer-app .card-icon {
font-size: 56px !important;
width: 56px;
height: 56px;
}
dev-explorer-app button.card.card-folder .card-icon {
color: #f59e0b;
filter: drop-shadow(0 4px 12px rgba(245, 158, 11, 0.4));
}
dev-explorer-app button.card.card-file .card-icon {
color: #3b82f6;
filter: drop-shadow(0 4px 12px rgba(59, 130, 246, 0.35));
}
/* Title styling */
dev-explorer-app .card-title {
font-size: 12px;
font-family: var(--mono);
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 230px;
color: rgba(255, 255, 255, 0.85);
line-height: 1.4;
text-align: center;
}
dev-explorer-app .row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border: 1px solid var(--border);
border-radius: 8px;
background: rgba(255, 255, 255, 0.02);
}
dev-explorer-app .row:hover {
background: rgba(255, 255, 255, 0.04);
}
dev-explorer-app .row sl-icon {
font-size: 16px;
}
dev-explorer-app .path {
font-family: var(--mono);
font-size: 12px;
color: var(--muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
dev-explorer-app .diagram {
height: 100%;
overflow: hidden;
padding: 12px;
box-sizing: border-box;
}
dev-explorer-app .diagram-inner {
/* Canvas background behind the rendered SVG (theme-dependent). */
background: #fff;
color: #111;
border-radius: 10px;
padding: 12px;
display: flex;
align-items: flex-start;
justify-content: flex-start;
width: 100%;
height: 100%;
box-sizing: border-box;
}
/* Fit the rendered SVG within the available pane (no scrollbars). */
dev-explorer-app .diagram-inner > svg {
width: auto;
height: auto;
max-width: 100% !important;
max-height: 100% !important;
}
dev-explorer-app .diagram-inner[data-theme='dark'] {
background: #0b1020;
color: #e8eefc;
}
dev-explorer-app .console {
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
border-left: 1px solid var(--border);
background: var(--panel-bg);
}
dev-explorer-app .spacer {
flex: 1;
}
dev-explorer-app .console-toolbar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid var(--border);
}
dev-explorer-app .console-toolbar sl-input {
width: 260px;
}
dev-explorer-app .console-body {
flex: 1;
min-height: 0;
overflow: auto;
padding: 10px 12px;
}
dev-explorer-app .logline {
font-family: var(--mono);
font-size: 12px;
white-space: pre-wrap;
word-break: break-word;
margin: 0 0 8px 0;
line-height: 1.35;
}
dev-explorer-app .logmeta {
display: inline-flex;
gap: 8px;
align-items: center;
margin-bottom: 4px;
}
dev-explorer-app .empty {
padding: 18px 12px;
color: var(--muted);
font-size: 13px;
}
dev-explorer-app sl-breadcrumb::part(base) {
font-size: 12px;
}

View File

@@ -2,12 +2,17 @@
import chokidar from 'chokidar';
import cors from 'cors';
import { context } from 'esbuild';
import { promises as fs } from 'fs';
import type { Request, Response } from 'express';
import express from 'express';
import path, { resolve } from 'path';
import { fileURLToPath } from 'url';
import { packageOptions } from '../.build/common.js';
import { generateLangium } from '../.build/generateLangium.js';
import { defaultOptions, getBuildConfig } from './util.js';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const configs = Object.values(packageOptions).map(({ packageName }) =>
getBuildConfig({
...defaultOptions,
@@ -18,7 +23,7 @@ const configs = Object.values(packageOptions).map(({ packageName }) =>
);
const mermaidIIFEConfig = getBuildConfig({
...defaultOptions,
minify: false,
minify: true,
core: false,
options: packageOptions.mermaid,
format: 'iife',
@@ -84,6 +89,81 @@ function sendEventsToAll() {
clients.forEach(({ response }) => response.write(`data: ${Date.now()}\n\n`));
}
interface DevExplorerEntry {
name: string;
kind: 'dir' | 'file';
path: string; // posix-style, relative to root
}
const devExplorerRootAbs = resolve(
process.cwd(),
process.env.MERMAID_DEV_EXPLORER_ROOT ?? 'cypress/platform/dev-diagrams'
);
function toPosixPath(p: string) {
return p.split(path.sep).join('/');
}
function resolveWithinDevExplorerRoot(requestedPath: unknown) {
const requested = typeof requestedPath === 'string' ? requestedPath : '';
if (requested.includes('\0')) {
throw new Error('Invalid path');
}
// Normalize slashes and avoid weird absolute-path cases.
const cleaned = requested.replaceAll('\\', '/').replace(/^\/+/, '');
const absPath = resolve(devExplorerRootAbs, cleaned);
const rel = path.relative(devExplorerRootAbs, absPath);
// Prevent traversal above root.
if (rel.startsWith('..') || path.isAbsolute(rel)) {
throw new Error('Path escapes configured root');
}
return { absPath, relPath: toPosixPath(rel) };
}
async function createDevExplorerBundle() {
const devExplorerDir = resolve(__dirname, 'dev-explorer');
const entryPoint = resolve(devExplorerDir, 'explorer-app.ts');
const outDir = resolve(devExplorerDir, 'dist');
try {
const devExplorerCtx = await context({
absWorkingDir: process.cwd(),
entryPoints: [entryPoint],
bundle: true,
format: 'esm',
target: 'es2020',
sourcemap: true,
outdir: outDir,
logLevel: 'info',
plugins: [
{
name: 'dev-explorer-reload',
setup(build) {
build.onEnd(() => {
sendEventsToAll();
});
},
},
],
});
await devExplorerCtx.watch();
await devExplorerCtx.rebuild();
} catch (err) {
console.error(
[
'Dev Explorer bundle build failed.',
'Install dependencies: pnpm add -D lit @shoelace-style/shoelace',
'Then restart the dev server.',
].join('\n')
);
console.error(err);
}
}
async function createServer() {
await generateLangium();
handleFileChange();
@@ -106,8 +186,117 @@ async function createServer() {
handleFileChange();
});
// Rebuild the dev-explorer client bundle on changes (and emit SSE so the browser reloads).
await createDevExplorerBundle();
// Emit SSE when Dev Explorer static assets change (e.g. public/styles.css),
// otherwise CSS-only changes can look "ignored" unless the user manually refreshes.
chokidar
.watch(['.esbuild/dev-explorer/public/**/*'], {
ignoreInitial: true,
ignored: [/node_modules/, /dist/, /docs/, /coverage/],
})
.on('all', (event, changedPath) => {
if (!['add', 'change', 'unlink'].includes(event)) {
return;
}
console.log(`[dev-explorer] ${event}: ${changedPath}`);
sendEventsToAll();
});
// Emit SSE when .mmd files inside the configured explorer root change.
chokidar
.watch('**/*.mmd', {
cwd: devExplorerRootAbs,
ignoreInitial: true,
})
.on('all', (event, changedPath) => {
if (!['add', 'change', 'unlink'].includes(event)) {
return;
}
console.log(`[dev-explorer] ${event}: ${changedPath}`);
sendEventsToAll();
});
app.use(cors());
app.get('/events', eventsHandler);
// --- Dev Explorer API + UI -------------------------------------------------
const devExplorerDir = resolve(__dirname, 'dev-explorer');
const devExplorerPublicDir = resolve(devExplorerDir, 'public');
const devExplorerDistDir = resolve(devExplorerDir, 'dist');
// Shoelace assets (theme css + icons). Safe: only mounted in dev server.
app.use(
'/dev/vendor/shoelace',
express.static(resolve(process.cwd(), 'node_modules/@shoelace-style/shoelace/dist'))
);
app.get('/dev/api/files', async (req, res) => {
try {
const { absPath, relPath } = resolveWithinDevExplorerRoot(req.query.path);
const stats = await fs.stat(absPath);
if (!stats.isDirectory()) {
res.status(400).json({ error: 'Not a directory' });
return;
}
const dirEntries = await fs.readdir(absPath, { withFileTypes: true });
const entries = dirEntries
.filter((d) => d.isDirectory() || (d.isFile() && d.name.endsWith('.mmd')))
.map<DevExplorerEntry>((d) => ({
name: d.name,
kind: d.isDirectory() ? 'dir' : 'file',
path: toPosixPath(path.join(relPath, d.name)),
}))
.sort((a, b) => {
if (a.kind !== b.kind) {
return a.kind === 'dir' ? -1 : 1;
}
return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });
});
res.json({
root: toPosixPath(path.relative(process.cwd(), devExplorerRootAbs)),
path: relPath === '' ? '' : relPath,
entries,
});
} catch (_e) {
res.status(400).json({ error: 'Invalid path' });
}
});
app.get('/dev/api/file', async (req, res) => {
try {
const { absPath, relPath } = resolveWithinDevExplorerRoot(req.query.path);
if (!absPath.endsWith('.mmd')) {
res.status(400).send('Only .mmd files are allowed');
return;
}
const stats = await fs.stat(absPath);
if (!stats.isFile()) {
res.status(400).send('Not a file');
return;
}
const content = await fs.readFile(absPath, 'utf-8');
res.type('text/plain').send(content);
// Optional: include relPath for debugging.
void relPath;
} catch (_e) {
res.status(400).send('Invalid path');
}
});
// Static assets for the dev-explorer UI.
app.use('/dev/assets', express.static(devExplorerDistDir));
// Serve `/dev/` (and `/dev`) from public/, including index.html.
app.use(
'/dev',
express.static(devExplorerPublicDir, {
index: ['index.html'],
})
);
for (const { packageName } of Object.values(packageOptions)) {
app.use(express.static(`./packages/${packageName}/dist`));
}

View File

@@ -0,0 +1,16 @@
sequenceDiagram
actor Alice
participant John@{ "type": "boundary" }
participant P1@{ "type": "control" } as New Control
participant P2@{ "type": "entity" } as New Entity
participant P3@{ "type": "database" } as New Database
Alice->>+John: Hello John, how are you?
John->>P1: new msg
P1->>P2: new msg
P2->>P3: new msg
Alice->>+John: John, can you hear me?
P3->>P2: new msg
P2->>P1: new msg
John-->>-Alice: Hi Alice, I can hear you!
P1->>John: new msg
John-->>-Alice: I feel great!

View File

@@ -0,0 +1,9 @@
treemap
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12

View File

@@ -0,0 +1,11 @@
---
title: "Grades"
---
radar-beta
axis m["Math"], s["Science"], e["English"]
axis h["History"], g["Geography"], a["Art"]
curve a["Alice"]{85, 90, 80, 70, 75, 90}
curve b["Bob"]{70, 75, 85, 80, 90, 85}
max 100
min 0

View File

@@ -0,0 +1,11 @@
flowchart LR
A["A"] e1@==> B["B"]
A L_A_n1_0@--> n1["C"]
B L_B_n2_0@==> n2["D"]
n1 L_n1_n2_0@--> n2
e1@{ animate: true }
L_A_n1_0@{ animation: slow }
L_B_n2_0@{ animation: slow }
L_n1_n2_0@{ animation: fast }

View File

@@ -0,0 +1,3 @@
flowchart LR
A e1@==> B
e1@{ animate: true }

View File

@@ -0,0 +1,18 @@
---
config:
layout: ogdc
---
flowchart-elk TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2

View File

@@ -0,0 +1,17 @@
---
config:
layout: elk
---
flowchart TB
process_C
subgraph container_Alpha
subgraph process_B
pppB
end
subgraph process_A
pppA
end
process_B-->|via_AWSBatch|container_Beta
process_A-->|messages|container_Beta
end

View File

@@ -0,0 +1,18 @@
---
config:
layout: elk
---
flowchart TB
subgraph container_Beta
process_C
end
subgraph container_Alpha
subgraph process_B
pppB
end
subgraph process_A
pppA
end
process_B-->|via_AWSBatch|container_Beta
process_A-->|messages|container_Beta
end

View File

@@ -0,0 +1,10 @@
---
config:
layout: elk
---
flowchart TB
subgraph container_Beta
process_C
end
process_B-->|via_AWSBatch|container_Beta

View File

@@ -0,0 +1,31 @@
---
config:
layout: elk
---
classDiagram
note "I love this diagram!\nDo you love it?"
Class01 <|-- AveryLongClass : Cool
<<interface>> Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
<<service>>
int id
test()
}
note for Class10 "Cool class\nI said it's very cool class!"

View File

@@ -0,0 +1,17 @@
---
config:
layout: elk
---
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
element test_entity {
type: simulation
}
test_entity - satisfies -> test_req

View File

@@ -0,0 +1,21 @@
---
config:
layout: elk
---
flowchart-elk TB
internet
nat
router
compute1
subgraph project
router
nat
subgraph subnet1
compute1
end
end
%% router --> subnet1
subnet1 --> nat
%% nat --> internet

View File

@@ -0,0 +1,27 @@
---
config:
layout: elk
---
flowchart-elk TB
internet
nat
router
lb1
lb2
compute1
compute2
subgraph project
router
nat
subgraph subnet1
compute1
lb1
end
subgraph subnet2
compute2
lb2
end
end
internet --> router
router --> subnet1 & subnet2
subnet1 & subnet2 --> nat --> internet

View File

@@ -0,0 +1,14 @@
---
config:
layout: elk
elk:
mergeEdges: false
forceNodeModelOrder: false
considerModelOrder: NONE
---
flowchart TB
a --> a1 & a2 & a3 & a4
b --> b1 & b2
b2 --> b3
b1 --> b4

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: rounded
---
flowchart LR
I["fa:fa-code Text"] -- Mermaid js --> D["Use<br/>the<br/>editor!"]
I --> D & D
D@{ shape: question}
I@{ shape: question}

View File

@@ -0,0 +1,21 @@
---
config:
layout: tidy-tree
---
mindmap
root((mindmap))
Origins
Long history
::icon(fa fa-book)
Popularisation
British popular psychology author Tony Buzan
Research
On effectiveness<br/>and features
On Automatic creation
Uses
Creative techniques
Strategic planning
Argument mapping
Tools
Pen and paper
Mermaid

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: linear
---
flowchart LR
A[A] --> B[B]
A[A] --- B([C])
A@{ shape: diamond}
%%B@{ shape: diamond}

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: linear
---
flowchart LR
A[A] -- Mermaid js --> B[B]
A[A] -- Mermaid js --- B[B]
A@{ shape: diamond}
B@{ shape: diamond}

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
flowchart:
curve: rounded
---
flowchart LR
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
I --> D & D
D@{ shape: question}
I@{ shape: question}

View File

@@ -0,0 +1,14 @@
---
config:
layout: elk
flowchart:
curve: rounded
elk:
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart LR
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
D --> I & I
a["a"]
D@{ shape: trap-b}
I@{ shape: lean-l}

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
---
flowchart LR
%% subgraph s1["Untitled subgraph"]
C["Evaluate"]
%% end
B --> C

View File

@@ -0,0 +1,10 @@
---
config:
layout: elk
flowchart:
//curve: linear
---
flowchart LR
%% A ==> B
%% A2 --> B2
A{A} --> B((Bo boo)) & B & B & B

View File

@@ -0,0 +1,18 @@
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph s1["APA"]
D{"Use the editor"}
end
subgraph S2["S2"]
s1
I>"fa:fa-code Text"]
E["E"]
end
D -- Mermaid js --> I
D --> I & E
E --> I

View File

@@ -0,0 +1,23 @@
---
config:
layout: elk
---
flowchart LR
a
subgraph s0["APA"]
subgraph s8["APA"]
subgraph s1["APA"]
D{"X"}
E[Q]
end
subgraph s3["BAPA"]
F[Q]
I
end
D --> I
D --> I
D --> I
I{"X"}
end
end

View File

@@ -0,0 +1,11 @@
---
config:
layout: elk
---
flowchart LR
a
D{"Use the editor"}
D -- Mermaid js --> I{"fa:fa-code Text"}
D-->I
D-->I

View File

@@ -0,0 +1,36 @@
---
config:
layout: elk
---
flowchart LR
subgraph s1["Untitled subgraph"]
n1["Evaluate"]
n2["Option 1"]
n3["Option 2"]
n4["fa:fa-car Option 3"]
end
subgraph s2["Untitled subgraph"]
n5["Evaluate"]
n6["Option 1"]
n7["Option 2"]
n8["fa:fa-car Option 3"]
end
A["Start"] -- Some text --> B("Continue")
B --> C{"Evaluate"}
C -- One --> D["Option 1"]
C -- Two --> E["Option 2"]
C -- Three --> F["fa:fa-car Option 3"]
n1 -- One --> n2
n1 -- Two --> n3
n1 -- Three --> n4
n5 -- One --> n6
n5 -- Two --> n7
n5 -- Three --> n8
n1@{ shape: diam}
n2@{ shape: rect}
n3@{ shape: rect}
n4@{ shape: rect}
n5@{ shape: diam}
n6@{ shape: rect}
n7@{ shape: rect}
n8@{ shape: rect}

View File

@@ -0,0 +1,10 @@
---
config:
layout: elk
---
flowchart LR
subgraph s1["Untitled subgraph"]
n1["Evaluate"]
n2["Option 1"]
end
n1 -- One --> n2

View File

@@ -0,0 +1,6 @@
---
config:
layout: elk
---
flowchart LR
A{A} --> B & C

View File

@@ -0,0 +1,9 @@
---
config:
layout: elk
---
flowchart LR
A{A} --> B & C
subgraph "subbe"
A
end

View File

@@ -0,0 +1,14 @@
---
config:
layout: elk
---
flowchart LR
n2@{ shape: rect}
n3@{ shape: rect}
n4@{ shape: rect}
A["Start"] -- Some text --> B("Continue")
B --> C{"Evaluate"}
C -- One --> D["Option 1"]
C -- Two --> E["Option 2"]
C -- Three --> F["fa:fa-car Option 3"]
%% C@{ shape: hexagon}

View File

@@ -0,0 +1,16 @@
---
config:
kanban:
ticketBaseUrl: 'https://github.com/your-repo/issues/#TICKET#'
---
kanban
Backlog
task1[📝 Define project requirements]@{ ticket: a101 }
To Do
task2[🔍 Research technologies]@{ ticket: a102 }
Review
task4[🔍 Code review for login feature]@{ ticket: a104 }
Done
task5[✅ Deploy initial version]@{ ticket: a105 }
In Progress
task3[💻 Develop login feature]@{ ticket: 103 }

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }

View File

@@ -0,0 +1,3 @@
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
style A fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,4 @@
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }

View File

@@ -0,0 +1,3 @@
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
style A fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,4 @@
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }

View File

@@ -0,0 +1,2 @@
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }

View File

@@ -0,0 +1,3 @@
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,4 @@
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,4 @@
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,3 @@
flowchart LR
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px

View File

@@ -0,0 +1,3 @@
kanban
id2[In progress]
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }

View File

@@ -0,0 +1,24 @@
---
config:
kanban:
ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'
# sectionWidth: 300
---
kanban
Todo
[Create Documentation]
docs[Create Blog about the new diagram]
id7[In progress]
id6[Create renderer so that it works in all cases. We also add some extra text here for testing purposes. And some more just for the extra flare.]
id9[Ready for deploy]
id8[Design grammar]@{ assigned: 'knsv' }
id10[Ready for test]
id4[Create parsing tests]@{ ticket: MC-2038, assigned: 'K.Sveidqvist', priority: 'High' }
id66[last item]@{ priority: 'Very Low', assigned: 'knsv' }
id11[Done]
id5[define getData]
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char]@{ ticket: MC-2036, priority: 'Very High'}
id3[Update DB function]@{ ticket: MC-2037, assigned: knsv, priority: 'High' }
id12[Can't reproduce]
id3[Weird flickering in Firefox]

View File

@@ -0,0 +1,9 @@
flowchart TD
B("B: Investigate how SOX2 is implicated in endothelial to mesenchymal transition and how expression affects the migration of GBM cells")
B --> D["D: Investigate and isolate migratory glioblastoma with regards to phenotype"] & E["E: Investigate the effect of SOX2 on EMT in GBM"] & F["F: Investigate the effect of SOX2 downregulation on migratory/invasive phenotype in the in vitro model and the effect on metastasis formation in the in vivo model"]
L("L: Expression of markers for stemness, EMT and invasion pattern")
D -- RNA Sequencing --> L
E -- "Lentiviral-mediated RNA interference" --> J("J:Sox2 Knock-Down")
J --> O("O: Up/downregulation of stemness markers") & P("P: Up/downregulation of EMT markers")
F -- Transwell/Wound Healing Assay --> K("K: In Vitro m")

View File

@@ -105,49 +105,77 @@
</head>
<body>
<pre id="diagram4" class="mermaid">
---
config:
layout: elk
---
mindmap
root((mindmap))
Origins
Long history
::icon(fa fa-book)
Popularisation
British popular psychology author Tony Buzan
Research
On effectiveness&lt;br/>and features
On Automatic creation
Uses
Creative techniques
Strategic planning
Argument mapping
Tools
id)I am a cloud(
id))I am a bang((
Tools
</pre>
<pre id="diagram4" class="mermaid">
---
config:
layout: elk
---
flowchart
aid0
<div class="grid grid-cols-2 gap-4">
<pre id="diagram4" class="mermaid">
sequenceDiagram
actor Alice
participant John@{ "type": "boundary" }
participant P1@{ "type": "control" } as New Control
participant P2@{ "type": "entity" } as New Entity
participant P3@{ "type": "database" } as New Database
Alice->>+John: Hello John, how are you?
John->>P1: new msg
P1->>P2: new msg
P2->>P3: new msg
Alice->>+John: John, can you hear me?
P3->>P2: new msg
P2->>P1: new msg
John-->>-Alice: Hi Alice, I can hear you!
P1->>John: new msg
John-->>-Alice: I feel great!
</pre
>
<pre id="diagram4" class="mermaid">
>
<pre id="diagram4" class="mermaid">
treemap
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
</pre
>
<pre id="diagram4" class="mermaid">
---
config:
layout: elk
---
mindmap
aid0
title: "Grades"
---
radar-beta
axis m["Math"], s["Science"], e["English"]
axis h["History"], g["Geography"], a["Art"]
curve a["Alice"]{85, 90, 80, 70, 75, 90}
curve b["Bob"]{70, 75, 85, 80, 90, 85}
max 100
min 0
</pre
>
<pre id="diagram4" class="mermaid">
flowchart LR
A["A"] e1@==> B["B"]
A L_A_n1_0@--> n1["C"]
B L_B_n2_0@==> n2["D"]
n1 L_n1_n2_0@--> n2
e1@{ animate: true }
L_A_n1_0@{ animation: slow }
L_B_n2_0@{ animation: slow }
L_n1_n2_0@{ animation: fast }
</pre
>
</div>
<pre id="diagram4" class="mermaid2">
flowchart LR
A e1@==> B
e1@{ animate: true }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: ogdc
@@ -169,7 +197,7 @@
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -190,7 +218,7 @@
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -212,7 +240,7 @@
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -227,7 +255,7 @@
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -261,7 +289,7 @@
note for Class10 "Cool class\nI said it's very cool class!"
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -281,7 +309,7 @@
test_entity - satisfies -> test_req
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -305,7 +333,7 @@
%% nat --> internet
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -335,7 +363,7 @@
subnet1 & subnet2 --> nat --> internet
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -351,19 +379,7 @@ config:
b2 --> b3
b1 --> b4</pre
>
<pre id="diagram4" class="mermaid">
treemap
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
</pre>
<pre id="diagram5" class="mermaid">
<pre id="diagram5" class="mermaid2">
---
config:
layout: elk
@@ -377,7 +393,7 @@ treemap
I@{ shape: question}
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: tidy-tree
@@ -401,7 +417,7 @@ treemap
Mermaid
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -415,7 +431,7 @@ treemap
%%B@{ shape: diamond}
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -429,7 +445,7 @@ treemap
B@{ shape: diamond}
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -442,7 +458,7 @@ treemap
D@{ shape: question}
I@{ shape: question}
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -458,7 +474,7 @@ treemap
D@{ shape: trap-b}
I@{ shape: lean-l}
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -471,7 +487,7 @@ flowchart LR
B --> C
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -484,7 +500,7 @@ flowchart LR
A{A} --> B((Bo boo)) & B & B & B
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -504,7 +520,7 @@ A{A} --> B((Bo boo)) & B & B & B
D --> I & E
E --> I
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -529,7 +545,7 @@ config:
end
end
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -542,7 +558,7 @@ config:
D-->I
D-->I
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -581,7 +597,7 @@ flowchart LR
n8@{ shape: rect}
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -597,7 +613,7 @@ flowchart LR
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -606,7 +622,7 @@ flowchart LR
A{A} --> B & C
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -618,7 +634,7 @@ flowchart LR
end
</pre
>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
@@ -636,7 +652,7 @@ flowchart LR
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
kanban:
@@ -655,81 +671,81 @@ kanban
task3[💻 Develop login feature]@{ ticket: 103 }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
kanban
id2[In progress]
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
---
config:
kanban:
@@ -800,7 +816,7 @@ kanban
// look: 'handDrawn',
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
// layout: 'dagre',
layout: 'elk',
layout: 'dagre',
// layout: 'fixed',
// htmlLabels: false,
flowchart: { titleTopMargin: 10 },

818
cypress/platform/knsv4.html Normal file
View File

@@ -0,0 +1,818 @@
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/font-awesome.min.css"
/>
<link
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
rel="stylesheet"
/>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet"
/>
<style>
body {
/* background: rgb(221, 208, 208); */
/* background: #333; */
font-family: 'Arial';
/* color: white; */
/* font-size: 18px !important; */
}
h1 {
color: grey;
}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
/* background-color: #efefef;
background-image: radial-gradient(#fff 51%, transparent 91%),
radial-gradient(#fff 51%, transparent 91%);
background-size: 20px 20px;
background-position:
0 0,
10px 10px;
background-repeat: repeat; */
}
.malware {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
pre {
width: 100%;
}
/* tspan {
font-size: 6px !important;
} */
/* .flowchart-link {
stroke-dasharray: 4, 4 !important;
animation: flow 1s linear infinite;
animation: dashdraw 4.93282s linear infinite;
stroke-width: 2px !important;
} */
@keyframes dashdraw {
from {
stroke-dashoffset: 0;
}
}
/*stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation: 4.932820s linear infinite;*/
/* stroke-width:2;stroke-dasharray:10.000000,9.865639;stroke-dashoffset:-198.656393;animation: dashdraw 4.932820s linear infinite;*/
</style>
</head>
<body>
<pre id="diagram4" class="mermaid">
---
config:
layout: tidy-tree
---
mindmap
[My User Manual ]
)What motivates me?(
a("Impact: Create real change, see outcomes")
People Energy: Connection, fun, joy
)What drives me nuts?(
Inefficiency: Poor execution, no follow-through
Indecision: Limbo > Action, prefer decisive moves
)How can people really impress me?(
Bring energy, ideas, enthusiasm
Execute + follow through!
Make things better, not just maintain
)What qualities do I value?(
Approachable & collaborative
Direct, transparent communication
Ownership with healthy boundaries
Willingness to learn and share
New perspectives & expertise
)What people might misunderstand(
Passion ≠ upset; high energy!
Many ideas ≠ all top priorities
I move fast - let me know if pace is overwhelming
)Real talk: My quirks & weaknesses(
Thrive on momentum, find it hard to slow down
Prefer "real" over "polished"
"Why" is my default question
Action > reflection sometimes
My energy can overshadow quieter voices
Help me pause & amplify all voices!
)Working & Growing Together(
How I like to be coached: Help me see blind spots, push/anchor me
Communication: Slack for quick; docs for updates; calls for nuance
Feedback: Real-time & caring, structured for growth
Receiving feedback: Direct, soon, with impact; ideally 1:1 or positive+constructive together
How I coach: Focus on outcomes, stretch/celebrate, creative growth opportunities, consultative problem-solving
Mistakes: Be quick, transparent, own it, share learnings
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart
aid0
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
mindmap
aid0
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: ogdc
---
flowchart-elk TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart TB
process_C
subgraph container_Alpha
subgraph process_B
pppB
end
subgraph process_A
pppA
end
process_B-->|via_AWSBatch|container_Beta
process_A-->|messages|container_Beta
end
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart TB
subgraph container_Beta
process_C
end
subgraph container_Alpha
subgraph process_B
pppB
end
subgraph process_A
pppA
end
process_B-->|via_AWSBatch|container_Beta
process_A-->|messages|container_Beta
end
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart TB
subgraph container_Beta
process_C
end
process_B-->|via_AWSBatch|container_Beta
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
classDiagram
note "I love this diagram!\nDo you love it?"
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "1" *-- "*" Class04
Class05 "1" o-- "many" Class06
Class07 "1" .. "*" Class08
Class09 "1" --> "*" C2 : Where am i?
Class09 "*" --* "*" C3
Class09 "1" --|> "1" Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
note for Class10 "Cool class\nI said it's very cool class!"
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
element test_entity {
type: simulation
}
test_entity - satisfies -> test_req
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart-elk TB
internet
nat
router
compute1
subgraph project
router
nat
subgraph subnet1
compute1
end
end
%% router --> subnet1
subnet1 --> nat
%% nat --> internet
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart-elk TB
internet
nat
router
lb1
lb2
compute1
compute2
subgraph project
router
nat
subgraph subnet1
compute1
lb1
end
subgraph subnet2
compute2
lb2
end
end
internet --> router
router --> subnet1 & subnet2
subnet1 & subnet2 --> nat --> internet
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
elk:
mergeEdges: false
forceNodeModelOrder: false
considerModelOrder: NONE
---
flowchart TB
a --> a1 & a2 & a3 & a4
b --> b1 & b2
b2 --> b3
b1 --> b4</pre
>
<pre id="diagram4" class="mermaid2">
treemap
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
</pre>
<pre id="diagram5" class="mermaid2">
---
config:
layout: elk
flowchart:
curve: rounded
---
flowchart LR
I["fa:fa-code Text"] -- Mermaid js --> D["Use<br/>the<br/>editor!"]
I --> D & D
D@{ shape: question}
I@{ shape: question}
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: tidy-tree
---
mindmap
root((mindmap))
Origins
Long history
::icon(fa fa-book)
Popularisation
British popular psychology author Tony Buzan
Research
On effectiveness<br/>and features
On Automatic creation
Uses
Creative techniques
Strategic planning
Argument mapping
Tools
Pen and paper
Mermaid
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
flowchart:
curve: linear
---
flowchart LR
A[A] --> B[B]
A[A] --- B([C])
A@{ shape: diamond}
%%B@{ shape: diamond}
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
flowchart:
curve: linear
---
flowchart LR
A[A] -- Mermaid js --> B[B]
A[A] -- Mermaid js --- B[B]
A@{ shape: diamond}
B@{ shape: diamond}
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
flowchart:
curve: rounded
---
flowchart LR
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
I --> D & D
D@{ shape: question}
I@{ shape: question}
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
flowchart:
curve: rounded
elk:
nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart LR
D["Use the editor"] -- Mermaid js --> I["fa:fa-code Text"]
D --> I & I
a["a"]
D@{ shape: trap-b}
I@{ shape: lean-l}
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
%% subgraph s1["Untitled subgraph"]
C["Evaluate"]
%% end
B --> C
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
flowchart:
//curve: linear
---
flowchart LR
%% A ==> B
%% A2 --> B2
A{A} --> B((Bo boo)) & B & B & B
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph s1["APA"]
D{"Use the editor"}
end
subgraph S2["S2"]
s1
I>"fa:fa-code Text"]
E["E"]
end
D -- Mermaid js --> I
D --> I & E
E --> I
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
a
subgraph s0["APA"]
subgraph s8["APA"]
subgraph s1["APA"]
D{"X"}
E[Q]
end
subgraph s3["BAPA"]
F[Q]
I
end
D --> I
D --> I
D --> I
I{"X"}
end
end
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
a
D{"Use the editor"}
D -- Mermaid js --> I{"fa:fa-code Text"}
D-->I
D-->I
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
subgraph s1["Untitled subgraph"]
n1["Evaluate"]
n2["Option 1"]
n3["Option 2"]
n4["fa:fa-car Option 3"]
end
subgraph s2["Untitled subgraph"]
n5["Evaluate"]
n6["Option 1"]
n7["Option 2"]
n8["fa:fa-car Option 3"]
end
A["Start"] -- Some text --> B("Continue")
B --> C{"Evaluate"}
C -- One --> D["Option 1"]
C -- Two --> E["Option 2"]
C -- Three --> F["fa:fa-car Option 3"]
n1 -- One --> n2
n1 -- Two --> n3
n1 -- Three --> n4
n5 -- One --> n6
n5 -- Two --> n7
n5 -- Three --> n8
n1@{ shape: diam}
n2@{ shape: rect}
n3@{ shape: rect}
n4@{ shape: rect}
n5@{ shape: diam}
n6@{ shape: rect}
n7@{ shape: rect}
n8@{ shape: rect}
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
subgraph s1["Untitled subgraph"]
n1["Evaluate"]
n2["Option 1"]
end
n1 -- One --> n2
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
A{A} --> B & C
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
A{A} --> B & C
subgraph "subbe"
A
end
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
layout: elk
---
flowchart LR
n2@{ shape: rect}
n3@{ shape: rect}
n4@{ shape: rect}
A["Start"] -- Some text --> B("Continue")
B --> C{"Evaluate"}
C -- One --> D["Option 1"]
C -- Two --> E["Option 2"]
C -- Three --> F["fa:fa-car Option 3"]
%% C@{ shape: hexagon}
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
kanban:
ticketBaseUrl: 'https://github.com/your-repo/issues/#TICKET#'
---
kanban
Backlog
task1[📝 Define project requirements]@{ ticket: a101 }
To Do
task2[🔍 Research technologies]@{ ticket: a102 }
Review
task4[🔍 Code review for login feature]@{ ticket: a104 }
Done
task5[✅ Deploy initial version]@{ ticket: a105 }
In Progress
task3[💻 Develop login feature]@{ ticket: 103 }
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
A:::AClass
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
style A fill:#f9f,stroke:#333,stroke-width:4px
</pre>
<pre id="diagram4" class="mermaid2">
kanban
id2[In progress]
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
</pre>
<pre id="diagram4" class="mermaid2">
---
config:
kanban:
ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'
# sectionWidth: 300
---
kanban
Todo
[Create Documentation]
docs[Create Blog about the new diagram]
id7[In progress]
id6[Create renderer so that it works in all cases. We also add some extra text here for testing purposes. And some more just for the extra flare.]
id9[Ready for deploy]
id8[Design grammar]@{ assigned: 'knsv' }
id10[Ready for test]
id4[Create parsing tests]@{ ticket: MC-2038, assigned: 'K.Sveidqvist', priority: 'High' }
id66[last item]@{ priority: 'Very Low', assigned: 'knsv' }
id11[Done]
id5[define getData]
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char]@{ ticket: MC-2036, priority: 'Very High'}
id3[Update DB function]@{ ticket: MC-2037, assigned: knsv, priority: 'High' }
id12[Can't reproduce]
id3[Weird flickering in Firefox]
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
import layoutElk from './mermaid-layout-elk.esm.mjs';
import layouts from './mermaid-layout-tidy-tree.esm.mjs';
const staticBellIconPack = {
prefix: 'fa6-regular',
icons: {
bell: {
body: '<path fill="currentColor" d="M224 0c-17.7 0-32 14.3-32 32v19.2C119 66 64 130.6 64 208v25.4c0 45.4-15.5 89.5-43.8 124.9L5.3 377c-5.8 7.2-6.9 17.1-2.9 25.4S14.8 416 24 416h400c9.2 0 17.6-5.3 21.6-13.6s2.9-18.2-2.9-25.4l-14.9-18.6c-28.3-35.5-43.8-79.6-43.8-125V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32m0 96c61.9 0 112 50.1 112 112v25.4c0 47.9 13.9 94.6 39.7 134.6H72.3c25.8-40 39.7-86.7 39.7-134.6V208c0-61.9 50.1-112 112-112m64 352H160c0 17 6.7 33.3 18.7 45.3S207 512 224 512s33.3-6.7 45.3-18.7S288 465 288 448"/>',
width: 448,
},
},
width: 512,
height: 512,
};
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
},
{
name: 'fa',
loader: () => staticBellIconPack,
},
]);
mermaid.registerLayoutLoaders(layouts);
await mermaid.initialize({
logLevel: 0,
securityLevel: 'loose',
callback,
});
mermaid.parseError = function (err, hash) {
console.error('In parse error:');
console.error(err);
};
</script>
</body>
</html>

View File

@@ -10,7 +10,7 @@
# Interface: ParseOptions
Defined in: [packages/mermaid/src/types.ts:90](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L90)
Defined in: [packages/mermaid/src/types.ts:89](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L89)
## Properties
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:90](https://github.com/mermaid-js/mer
> `optional` **suppressErrors**: `boolean`
Defined in: [packages/mermaid/src/types.ts:95](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L95)
Defined in: [packages/mermaid/src/types.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L94)
If `true`, parse will return `false` instead of throwing error when the diagram is invalid.
The `parseError` function will not be called.

View File

@@ -10,7 +10,7 @@
# Interface: ParseResult
Defined in: [packages/mermaid/src/types.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L98)
Defined in: [packages/mermaid/src/types.ts:97](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L97)
## Properties
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:98](https://github.com/mermaid-js/mer
> **config**: [`MermaidConfig`](MermaidConfig.md)
Defined in: [packages/mermaid/src/types.ts:106](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L106)
Defined in: [packages/mermaid/src/types.ts:105](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L105)
The config passed as YAML frontmatter or directives
@@ -28,6 +28,6 @@ The config passed as YAML frontmatter or directives
> **diagramType**: `string`
Defined in: [packages/mermaid/src/types.ts:102](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L102)
Defined in: [packages/mermaid/src/types.ts:101](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L101)
The diagram type, e.g. 'flowchart', 'sequence', etc.

View File

@@ -10,7 +10,7 @@
# Interface: RenderResult
Defined in: [packages/mermaid/src/types.ts:116](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L116)
Defined in: [packages/mermaid/src/types.ts:115](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L115)
## Properties
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:116](https://github.com/mermaid-js/me
> `optional` **bindFunctions**: (`element`) => `void`
Defined in: [packages/mermaid/src/types.ts:134](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L134)
Defined in: [packages/mermaid/src/types.ts:133](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L133)
Bind function to be called after the svg has been inserted into the DOM.
This is necessary for adding event listeners to the elements in the svg.
@@ -45,7 +45,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
> **diagramType**: `string`
Defined in: [packages/mermaid/src/types.ts:124](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L124)
Defined in: [packages/mermaid/src/types.ts:123](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L123)
The diagram type, e.g. 'flowchart', 'sequence', etc.
@@ -55,6 +55,6 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
> **svg**: `string`
Defined in: [packages/mermaid/src/types.ts:120](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L120)
Defined in: [packages/mermaid/src/types.ts:119](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L119)
The svg code for the rendered graph.

View File

@@ -11,7 +11,8 @@ import unicorn from 'eslint-plugin-unicorn';
import globals from 'globals';
import tseslint from 'typescript-eslint';
export default tseslint.config(
/** @type {import('eslint').Linter.FlatConfig[]} */
const config = tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
@@ -23,6 +24,7 @@ export default tseslint.config(
'.git/',
'**/generated/',
'**/coverage/',
'.esbuild/dev-explorer/**',
'packages/mermaid/src/config.type.ts',
'packages/mermaid/src/docs/.vitepress/components.d.ts',
],
@@ -221,3 +223,5 @@ export default tseslint.config(
processor: 'markdown/markdown',
}
);
export default config;

View File

@@ -78,6 +78,7 @@
"@types/lodash": "^4.17.21",
"@types/mdast": "^4.0.4",
"@types/node": "^22.19.1",
"@shoelace-style/shoelace": "^2.20.1",
"@types/rollup-plugin-visualizer": "^5.0.3",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/spy": "^3.2.4",
@@ -105,6 +106,7 @@
"eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-tsdoc": "^0.4.0",
"eslint-plugin-unicorn": "^62.0.0",
"lit": "^3.2.1",
"express": "^5.2.1",
"globals": "^16.4.0",
"globby": "^14.1.0",

View File

@@ -85,17 +85,6 @@ export class FlowDB implements DiagramDB {
return common.sanitizeText(txt, this.config);
}
private sanitizeNodeLabelType(labelType?: string) {
switch (labelType) {
case 'markdown':
case 'string':
case 'text':
return labelType;
default:
return 'markdown';
}
}
/**
* Function to lookup domId from id in the graph definition.
*
@@ -219,7 +208,6 @@ export class FlowDB implements DiagramDB {
if (doc?.label) {
vertex.text = doc?.label;
vertex.labelType = this.sanitizeNodeLabelType(doc?.labelType);
}
if (doc?.icon) {
vertex.icon = doc?.icon;
@@ -279,7 +267,7 @@ export class FlowDB implements DiagramDB {
if (edge.text.startsWith('"') && edge.text.endsWith('"')) {
edge.text = edge.text.substring(1, edge.text.length - 1);
}
edge.labelType = this.sanitizeNodeLabelType(linkTextObj.type);
edge.labelType = linkTextObj.type;
}
if (type !== undefined) {
@@ -714,7 +702,7 @@ You have to call mermaid.initialize.`
title: title.trim(),
classes: [],
dir,
labelType: this.sanitizeNodeLabelType(_title?.type),
labelType: _title.type,
};
log.info('Adding', subGraph.id, subGraph.nodes, subGraph.dir);
@@ -1024,7 +1012,6 @@ You have to call mermaid.initialize.`
const baseNode = {
id: vertex.id,
label: vertex.text,
labelType: vertex.labelType,
labelStyle: '',
parentId,
padding: config.flowchart?.padding || 8,
@@ -1101,7 +1088,6 @@ You have to call mermaid.initialize.`
id: subGraph.id,
label: subGraph.title,
labelStyle: '',
labelType: subGraph.labelType,
parentId: parentDB.get(subGraph.id),
padding: 8,
cssCompiledStyles: this.getCompiledStyles(subGraph.classes),
@@ -1133,7 +1119,6 @@ You have to call mermaid.initialize.`
end: rawEdge.end,
type: rawEdge.type ?? 'normal',
label: rawEdge.text,
labelType: rawEdge.labelType,
labelpos: 'c',
thickness: rawEdge.stroke,
minlen: rawEdge.length,

View File

@@ -29,7 +29,7 @@ export interface FlowVertex {
domId: string;
haveCallback?: boolean;
id: string;
labelType: 'markdown' | 'string' | 'text';
labelType: 'text';
link?: string;
linkTarget?: string;
props?: any;
@@ -62,7 +62,7 @@ export interface FlowEdge {
style?: string[];
length?: number;
text: string;
labelType: 'markdown' | 'string' | 'text';
labelType: 'text';
classes: string[];
id?: string;
animation?: 'fast' | 'slow';

View File

@@ -8,7 +8,7 @@ import type { CanonicalUrlConfig } from './canonical-urls.js';
*/
export const canonicalConfig: CanonicalUrlConfig = {
// Base URL for the Mermaid documentation site
baseUrl: 'https://docs.mermaidchart.com',
baseUrl: 'https://mermaid.ai/open-source',
// Disable automatic generation - only use specificCanonicalUrls
autoGenerate: false,
@@ -57,93 +57,6 @@ export const canonicalConfig: CanonicalUrlConfig = {
},
};
/**
* Pages that should have specific canonical URLs
*
* Since autoGenerate is set to false, ONLY pages listed here will get canonical URLs.
*
* Usage: Add entries to this object where the key is the relative path
* of the markdown file and the value is the desired canonical URL.
*
* Examples:
* - 'intro/index.md': 'https://docs.mermaidchart.com/intro/index.html'
* - 'syntax/flowchart.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/flowchart.html'
* - 'config/configuration.md': 'https://docs.mermaidchart.com/mermaid-oss/config/configuration.html'
*/
export const specificCanonicalUrls: Record<string, string> = {
// Add your specific canonical URLs here
// Example:
// 'syntax/flowchart.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/flowchart.html',
// Intro section
'intro/index.md': 'https://docs.mermaidchart.com/intro/index.html',
'intro/getting-started.md':
'https://docs.mermaidchart.com/mermaid-oss/intro/getting-started.html',
'intro/syntax-reference.md':
'https://docs.mermaidchart.com/mermaid-oss/intro/syntax-reference.html',
// Syntax section
'syntax/flowchart.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/flowchart.html',
'syntax/sequenceDiagram.md':
'https://docs.mermaidchart.com/mermaid-oss/syntax/sequenceDiagram.html',
'syntax/classDiagram.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/classDiagram.html',
'syntax/stateDiagram.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/stateDiagram.html',
'syntax/entityRelationshipDiagram.md':
'https://docs.mermaidchart.com/mermaid-oss/syntax/entityRelationshipDiagram.html',
'syntax/userJourney.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/userJourney.html',
'syntax/gantt.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/gantt.html',
'syntax/pie.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/pie.html',
'syntax/quadrantChart.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/quadrantChart.html',
'syntax/requirementDiagram.md':
'https://docs.mermaidchart.com/mermaid-oss/syntax/requirementDiagram.html',
'syntax/mindmap.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/mindmap.html',
'syntax/timeline.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/timeline.html',
'syntax/gitgraph.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/gitgraph.html',
'syntax/c4.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/c4.html',
'syntax/sankey.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/sankey.html',
'syntax/xyChart.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/xyChart.html',
'syntax/block.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/block.html',
'syntax/packet.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/packet.html',
'syntax/kanban.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/kanban.html',
'syntax/architecture.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/architecture.html',
'syntax/radar.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/radar.html',
'syntax/examples.md': 'https://docs.mermaidchart.com/mermaid-oss/syntax/examples.html',
// Config section
'config/configuration.md': 'https://docs.mermaidchart.com/mermaid-oss/config/configuration.html',
'config/usage.md': 'https://docs.mermaidchart.com/mermaid-oss/config/usage.html',
'config/icons.md': 'https://docs.mermaidchart.com/mermaid-oss/config/icons.html',
'config/directives.md': 'https://docs.mermaidchart.com/mermaid-oss/config/directives.html',
'config/theming.md': 'https://docs.mermaidchart.com/mermaid-oss/config/theming.html',
'config/math.md': 'https://docs.mermaidchart.com/mermaid-oss/config/math.html',
'config/accessibility.md': 'https://docs.mermaidchart.com/mermaid-oss/config/accessibility.html',
'config/mermaidCLI.md': 'https://docs.mermaidchart.com/mermaid-oss/config/mermaidCLI.html',
'config/faq.md': 'https://docs.mermaidchart.com/mermaid-oss/config/faq.html',
// Ecosystem section
'ecosystem/mermaid-chart.md':
'https://docs.mermaidchart.com/mermaid-oss/ecosystem/mermaid-chart.html',
'ecosystem/tutorials.md': 'https://docs.mermaidchart.com/mermaid-oss/ecosystem/tutorials.html',
'ecosystem/integrations-community.md':
'https://docs.mermaidchart.com/mermaid-oss/ecosystem/integrations-community.html',
'ecosystem/integrations-create.md':
'https://docs.mermaidchart.com/mermaid-oss/ecosystem/integrations-create.html',
// Community section
'community/intro.md': 'https://docs.mermaidchart.com/mermaid-oss/community/intro.html',
'community/contributing.md':
'https://docs.mermaidchart.com/mermaid-oss/community/contributing.html',
'community/new-diagram.md':
'https://docs.mermaidchart.com/mermaid-oss/community/new-diagram.html',
'community/questions-and-suggestions.md':
'https://docs.mermaidchart.com/mermaid-oss/community/questions-and-suggestions.html',
'community/security.md': 'https://docs.mermaidchart.com/mermaid-oss/community/security.html',
};
/**
* Helper function to get canonical URL for a specific page
* This can be used in frontmatter or for manual overrides
*/
export function getCanonicalUrl(relativePath: string): string | undefined {
return specificCanonicalUrls[relativePath];
return `https://mermaid.ai/open-source/${relativePath}`;
}

View File

@@ -1,5 +1,5 @@
import type { PageData } from 'vitepress';
import { canonicalConfig, specificCanonicalUrls } from './canonical-config.js';
import { canonicalConfig } from './canonical-config.js';
/**
* Configuration for canonical URL generation
@@ -48,31 +48,15 @@ const defaultConfig: CanonicalUrlConfig = {
},
};
/**
* Check if a path matches any of the exclude patterns
*/
function shouldExcludePath(relativePath: string, excludePatterns: string[] = []): boolean {
return excludePatterns.some((pattern) => {
// Convert glob pattern to regex
const regexPattern = pattern
.replace(/\*\*/g, '.*')
.replace(/\*/g, '[^/]*')
.replace(/\?/g, '.')
.replace(/\./g, '\\.');
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(relativePath);
});
}
/**
* Transform a relative path to a canonical URL path
*/
function transformPath(relativePath: string, config: CanonicalUrlConfig): string {
export function transformPath(relativePath: string, config: CanonicalUrlConfig): string {
let transformedPath = relativePath;
// Apply built-in transformations
if (config.transformations?.removeMarkdownExtension) {
transformedPath = transformedPath.replace(/\.md$/, '');
transformedPath = transformedPath.replace(/\.md$/, '.html');
}
if (config.transformations?.removeIndex) {
@@ -116,45 +100,9 @@ function generateCanonicalUrl(relativePath: string, config: CanonicalUrlConfig):
export function addCanonicalUrls(pageData: PageData): void {
const config = canonicalConfig;
// Check for specific canonical URLs first
const specificUrl = specificCanonicalUrls[pageData.relativePath];
if (specificUrl) {
addCanonicalToHead(pageData, specificUrl);
return;
}
// Skip if canonical URL is already explicitly set in frontmatter
if (pageData.frontmatter.canonical) {
// If it's already a full URL, use as-is
if (pageData.frontmatter.canonical.startsWith('http')) {
addCanonicalToHead(pageData, pageData.frontmatter.canonical);
return;
}
// If it's a relative path, convert to absolute URL
const canonicalUrl = config.baseUrl + pageData.frontmatter.canonical;
addCanonicalToHead(pageData, canonicalUrl);
return;
}
// Skip if canonicalPath is set in frontmatter
if (pageData.frontmatter.canonicalPath) {
const canonicalUrl = config.baseUrl + pageData.frontmatter.canonicalPath;
addCanonicalToHead(pageData, canonicalUrl);
return;
}
// Skip if auto-generation is disabled
if (!config.autoGenerate) {
return;
}
// Skip if path should be excluded
if (shouldExcludePath(pageData.relativePath, config.excludePatterns)) {
return;
}
// Generate canonical URL
const canonicalUrl = generateCanonicalUrl(pageData.relativePath, config);
transformPath(pageData.relativePath, config);
addCanonicalToHead(pageData, canonicalUrl);
}

View File

@@ -13,7 +13,7 @@ export const labelHelper = async <T extends SVGGraphicsElement>(
_classes?: string
) => {
let cssClasses;
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig()?.flowchart?.htmlLabels);
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig()?.htmlLabels);
if (!_classes) {
cssClasses = 'node default';
} else {
@@ -48,7 +48,6 @@ export const labelHelper = async <T extends SVGGraphicsElement>(
style: node.labelStyle,
addSvgBackground: !!node.icon || !!node.img,
});
// Get the size of the label
let bbox = text.getBBox();
const halfPadding = (node?.padding ?? 0) / 2;

View File

@@ -1,7 +1,6 @@
export interface NodeMetaData {
shape?: string;
label?: string;
labelType?: string;
icon?: string;
form?: string;
pos?: 't' | 'b';

501
pnpm-lock.yaml generated
View File

@@ -37,6 +37,9 @@ importers:
'@rollup/plugin-typescript':
specifier: ^12.1.4
version: 12.1.4(rollup@4.52.5)(tslib@2.8.1)(typescript@5.7.3)
'@shoelace-style/shoelace':
specifier: ^2.20.1
version: 2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.2.7)
'@types/cors':
specifier: ^2.8.19
version: 2.8.19
@@ -169,6 +172,9 @@ importers:
lint-staged:
specifier: ^16.1.6
version: 16.1.6
lit:
specifier: ^3.2.1
version: 3.3.1
markdown-table:
specifier: ^3.0.4
version: 3.0.4
@@ -403,10 +409,10 @@ importers:
version: 5.0.0
vitepress:
specifier: ^1.6.4
version: 1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3)
version: 1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3)
vitepress-plugin-search:
specifier: 1.0.4-alpha.22
version: 1.0.4-alpha.22(flexsearch@0.8.212)(vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3))(vue@3.5.21(typescript@5.7.3))
version: 1.0.4-alpha.22(flexsearch@0.8.212)(vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3))(vue@3.5.21(typescript@5.7.3))
packages/mermaid-example-diagram:
dependencies:
@@ -466,7 +472,7 @@ importers:
dependencies:
'@zenuml/core':
specifier: ^3.41.6
version: 3.41.6(@babel/core@7.28.5)(@babel/template@7.27.2)
version: 3.41.6(@babel/core@7.28.5)(@babel/template@7.27.2)(@types/react@19.2.7)
devDependencies:
mermaid:
specifier: workspace:^
@@ -528,7 +534,68 @@ importers:
version: 1.0.3(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0)
vitepress:
specifier: 1.6.4
version: 1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.9.2)
version: 1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.9.2)
workbox-window:
specifier: ^7.3.0
version: 7.3.0
packages/mermaid/src/vitepress:
dependencies:
'@mdi/font':
specifier: ^7.4.47
version: 7.4.47
'@vueuse/core':
specifier: ^12.7.0
version: 12.8.2(typescript@5.9.2)
font-awesome:
specifier: ^4.7.0
version: 4.7.0
jiti:
specifier: ^2.4.2
version: 2.6.1
mermaid:
specifier: workspace:^
version: link:../..
vue:
specifier: ^3.4.38
version: 3.5.25(typescript@5.9.2)
devDependencies:
'@iconify-json/carbon':
specifier: ^1.1.37
version: 1.2.14
'@unocss/reset':
specifier: ^66.0.0
version: 66.5.9
'@vite-pwa/vitepress':
specifier: ^0.5.3
version: 0.5.4(vite-plugin-pwa@0.21.2(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0))
'@vitejs/plugin-vue':
specifier: ^5.0.5
version: 5.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.2))
fast-glob:
specifier: ^3.3.3
version: 3.3.3
https-localhost:
specifier: ^4.7.1
version: 4.7.1
pathe:
specifier: ^2.0.3
version: 2.0.3
unocss:
specifier: ^66.0.0
version: 66.5.9(postcss@8.5.6)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))
unplugin-vue-components:
specifier: ^28.4.0
version: 28.8.0(@babel/parser@7.28.5)(vue@3.5.25(typescript@5.9.2))
vite:
specifier: ^6.1.1
version: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
vite-plugin-pwa:
specifier: ^0.21.1
version: 0.21.2(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0)
vitepress:
specifier: 1.6.3
version: 1.6.3(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.9.2)
workbox-window:
specifier: ^7.3.0
version: 7.3.0
@@ -834,10 +901,6 @@ packages:
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.28.3':
resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.28.5':
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
engines: {node: '>=6.9.0'}
@@ -1766,6 +1829,10 @@ packages:
resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
engines: {node: '>=18'}
'@ctrl/tinycolor@4.2.0':
resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==}
engines: {node: '>=14'}
'@cypress/code-coverage@3.14.7':
resolution: {integrity: sha512-0qk2aNKmrB0AwJtYSyK2+MWl/3NqDgZQ1OBSEh6oFnJwl/H2u3NTatV+FTCap22HTm+uxUS6SarU8gP9gFZ6Tw==}
peerDependencies:
@@ -2547,6 +2614,17 @@ packages:
'@leichtgewicht/ip-codec@2.0.5':
resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==}
'@lit-labs/ssr-dom-shim@1.4.0':
resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==}
'@lit/react@1.0.8':
resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==}
peerDependencies:
'@types/react': 17 || 18 || 19
'@lit/reactive-element@2.1.1':
resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==}
'@manypkg/find-root@1.1.0':
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
@@ -2944,6 +3022,16 @@ packages:
'@shikijs/vscode-textmate@10.0.2':
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
'@shoelace-style/animations@1.2.0':
resolution: {integrity: sha512-avvo1xxkLbv2dgtabdewBbqcJfV0e0zCwFqkPMnHFGbJbBHorRFfMAHh1NG9ymmXn0jW95ibUVH03E1NYXD6Gw==}
'@shoelace-style/localize@3.2.1':
resolution: {integrity: sha512-r4C9C/5kSfMBIr0D9imvpRdCNXtUNgyYThc4YlS6K5Hchv1UyxNQ9mxwj+BTRH2i1Neits260sR3OjKMnplsFA==}
'@shoelace-style/shoelace@2.20.1':
resolution: {integrity: sha512-FSghU95jZPGbwr/mybVvk66qRZYpx5FkXL+vLNpy1Vp8UsdwSxXjIHE3fsvMbKWTKi9UFfewHTkc5e7jAqRYoQ==}
engines: {node: '>=14.17.0'}
'@sinclair/typebox@0.34.41':
resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==}
@@ -3274,6 +3362,9 @@ packages:
'@types/range-parser@1.2.7':
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
'@types/react@19.2.7':
resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==}
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
@@ -3594,6 +3685,15 @@ packages:
cpu: [x64]
os: [win32]
'@vite-pwa/vitepress@0.5.4':
resolution: {integrity: sha512-g57qwG983WTyQNLnOcDVPQEIeN+QDgK/HdqghmygiUFp3a/MzVvmLXC/EVnPAXxWa8W2g9pZ9lE3EiDGs2HjsA==}
peerDependencies:
'@vite-pwa/assets-generator': ^0.2.6
vite-plugin-pwa: '>=0.21.2 <1'
peerDependenciesMeta:
'@vite-pwa/assets-generator':
optional: true
'@vite-pwa/vitepress@1.0.1':
resolution: {integrity: sha512-INBxiNLZpef349KSmQ6zHWB4uqIgZgvJnwzH3bedW/7d/Ej0lK5HP95fiBdIc2wHUtmR3Znnegmt3zLESVWrpA==}
peerDependencies:
@@ -3663,36 +3763,24 @@ packages:
'@vue/compiler-core@3.5.21':
resolution: {integrity: sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==}
'@vue/compiler-core@3.5.24':
resolution: {integrity: sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==}
'@vue/compiler-core@3.5.25':
resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==}
'@vue/compiler-dom@3.5.21':
resolution: {integrity: sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==}
'@vue/compiler-dom@3.5.24':
resolution: {integrity: sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==}
'@vue/compiler-dom@3.5.25':
resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==}
'@vue/compiler-sfc@3.5.21':
resolution: {integrity: sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==}
'@vue/compiler-sfc@3.5.24':
resolution: {integrity: sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g==}
'@vue/compiler-sfc@3.5.25':
resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==}
'@vue/compiler-ssr@3.5.21':
resolution: {integrity: sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==}
'@vue/compiler-ssr@3.5.24':
resolution: {integrity: sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg==}
'@vue/compiler-ssr@3.5.25':
resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==}
@@ -3736,9 +3824,6 @@ packages:
'@vue/shared@3.5.21':
resolution: {integrity: sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==}
'@vue/shared@3.5.24':
resolution: {integrity: sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==}
'@vue/shared@3.5.25':
resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==}
@@ -4701,6 +4786,11 @@ packages:
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
composed-offset-position@0.0.6:
resolution: {integrity: sha512-Q7dLompI6lUwd7LWyIcP66r4WcS9u7AL2h8HaeipiRfCRPLMWqRx8fYsjb4OHi6UQFifO7XtNC2IlEJ1ozIFxw==}
peerDependencies:
'@floating-ui/utils': ^0.2.5
compressible@2.0.18:
resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
engines: {node: '>= 0.6'}
@@ -4888,6 +4978,9 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
cuint@0.2.2:
resolution: {integrity: sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==}
@@ -7134,6 +7227,15 @@ packages:
resolution: {integrity: sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ==}
engines: {node: '>=20.0.0'}
lit-element@4.2.1:
resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==}
lit-html@3.3.1:
resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==}
lit@3.3.1:
resolution: {integrity: sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==}
loader-runner@4.3.0:
resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
engines: {node: '>=6.11.5'}
@@ -8236,6 +8338,9 @@ packages:
pure-rand@7.0.1:
resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==}
qr-creator@1.0.0:
resolution: {integrity: sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==}
qs@6.13.0:
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
engines: {node: '>=0.6'}
@@ -9578,6 +9683,18 @@ packages:
peerDependencies:
vite: '>=4 <=7'
vite-plugin-pwa@0.21.2:
resolution: {integrity: sha512-vFhH6Waw8itNu37hWUJxL50q+CBbNcMVzsKaYHQVrfxTt3ihk3PeLO22SbiP1UNWzcEPaTQv+YVxe4G0KOjAkg==}
engines: {node: '>=16.0.0'}
peerDependencies:
'@vite-pwa/assets-generator': ^0.2.6
vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
workbox-build: ^7.3.0
workbox-window: ^7.3.0
peerDependenciesMeta:
'@vite-pwa/assets-generator':
optional: true
vite-plugin-pwa@1.0.3:
resolution: {integrity: sha512-/OpqIpUldALGxcsEnv/ekQiQ5xHkQ53wcoN5ewX4jiIDNGs3W+eNcI1WYZeyOLmzoEjg09D7aX0O89YGjen1aw==}
engines: {node: '>=16.0.0'}
@@ -9621,6 +9738,46 @@ packages:
terser:
optional: true
vite@6.4.1:
resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
jiti: '>=1.21.0'
less: '*'
lightningcss: ^1.21.0
sass: '*'
sass-embedded: '*'
stylus: '*'
sugarss: '*'
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
peerDependenciesMeta:
'@types/node':
optional: true
jiti:
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
tsx:
optional: true
yaml:
optional: true
vite@7.1.11:
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -9669,6 +9826,18 @@ packages:
vitepress: ^1.0.0-rc.35
vue: '3'
vitepress@1.6.3:
resolution: {integrity: sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw==}
hasBin: true
peerDependencies:
markdown-it-mathjax3: ^4
postcss: ^8
peerDependenciesMeta:
markdown-it-mathjax3:
optional: true
postcss:
optional: true
vitepress@1.6.4:
resolution: {integrity: sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==}
hasBin: true
@@ -10566,14 +10735,14 @@ snapshots:
'@babel/core@7.28.4':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.3
'@babel/generator': 7.28.5
'@babel/helper-compilation-targets': 7.27.2
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4)
'@babel/helpers': 7.28.4
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
'@babel/types': 7.28.4
'@babel/types': 7.28.5
'@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
debug: 4.4.3(supports-color@8.1.1)
@@ -10603,14 +10772,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@babel/generator@7.28.3':
dependencies:
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
'@babel/generator@7.28.5':
dependencies:
'@babel/parser': 7.28.5
@@ -10801,7 +10962,7 @@ snapshots:
'@babel/parser@7.28.4':
dependencies:
'@babel/types': 7.28.4
'@babel/types': 7.28.5
'@babel/parser@7.28.5':
dependencies:
@@ -12295,6 +12456,8 @@ snapshots:
'@csstools/css-tokenizer@3.0.4': {}
'@ctrl/tinycolor@4.2.0': {}
'@cypress/code-coverage@3.14.7(@babel/core@7.28.4)(@babel/preset-env@7.28.5(@babel/core@7.28.4))(babel-loader@10.0.0(@babel/core@7.28.4)(webpack@5.101.3(esbuild@0.25.12)))(cypress@14.5.4)(webpack@5.101.3(esbuild@0.25.12))':
dependencies:
'@babel/core': 7.28.4
@@ -12341,7 +12504,7 @@ snapshots:
'@babel/preset-env': 7.28.5(@babel/core@7.28.4)
babel-loader: 10.0.0(@babel/core@7.28.4)(webpack@5.101.3(esbuild@0.25.12))
bluebird: 3.7.1
debug: 4.4.0
debug: 4.4.3(supports-color@8.1.1)
lodash: 4.17.21
semver: 7.7.3
webpack: 5.101.3(esbuild@0.25.12)
@@ -12364,9 +12527,9 @@ snapshots:
'@docsearch/css@3.8.2': {}
'@docsearch/js@3.8.2(@algolia/client-search@5.37.0)(search-insights@2.17.3)':
'@docsearch/js@3.8.2(@algolia/client-search@5.37.0)(@types/react@19.2.7)(search-insights@2.17.3)':
dependencies:
'@docsearch/react': 3.8.2(@algolia/client-search@5.37.0)(search-insights@2.17.3)
'@docsearch/react': 3.8.2(@algolia/client-search@5.37.0)(@types/react@19.2.7)(search-insights@2.17.3)
preact: 10.27.2
transitivePeerDependencies:
- '@algolia/client-search'
@@ -12375,13 +12538,14 @@ snapshots:
- react-dom
- search-insights
'@docsearch/react@3.8.2(@algolia/client-search@5.37.0)(search-insights@2.17.3)':
'@docsearch/react@3.8.2(@algolia/client-search@5.37.0)(@types/react@19.2.7)(search-insights@2.17.3)':
dependencies:
'@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.37.0)(algoliasearch@5.37.0)(search-insights@2.17.3)
'@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.37.0)(algoliasearch@5.37.0)
'@docsearch/css': 3.8.2
algoliasearch: 5.37.0
optionalDependencies:
'@types/react': 19.2.7
search-insights: 2.17.3
transitivePeerDependencies:
- '@algolia/client-search'
@@ -13062,6 +13226,16 @@ snapshots:
'@leichtgewicht/ip-codec@2.0.5': {}
'@lit-labs/ssr-dom-shim@1.4.0': {}
'@lit/react@1.0.8(@types/react@19.2.7)':
dependencies:
'@types/react': 19.2.7
'@lit/reactive-element@2.1.1':
dependencies:
'@lit-labs/ssr-dom-shim': 1.4.0
'@manypkg/find-root@1.1.0':
dependencies:
'@babel/runtime': 7.28.4
@@ -13424,6 +13598,24 @@ snapshots:
'@shikijs/vscode-textmate@10.0.2': {}
'@shoelace-style/animations@1.2.0': {}
'@shoelace-style/localize@3.2.1': {}
'@shoelace-style/shoelace@2.20.1(@floating-ui/utils@0.2.10)(@types/react@19.2.7)':
dependencies:
'@ctrl/tinycolor': 4.2.0
'@floating-ui/dom': 1.7.4
'@lit/react': 1.0.8(@types/react@19.2.7)
'@shoelace-style/animations': 1.2.0
'@shoelace-style/localize': 3.2.1
composed-offset-position: 0.0.6(@floating-ui/utils@0.2.10)
lit: 3.3.1
qr-creator: 1.0.0
transitivePeerDependencies:
- '@floating-ui/utils'
- '@types/react'
'@sinclair/typebox@0.34.41': {}
'@sindresorhus/base62@1.0.0': {}
@@ -13819,6 +14011,10 @@ snapshots:
'@types/range-parser@1.2.7': {}
'@types/react@19.2.7':
dependencies:
csstype: 3.2.3
'@types/resolve@1.20.2': {}
'@types/responselike@1.0.3':
@@ -13994,6 +14190,14 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
'@unocss/astro@66.5.9(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@unocss/core': 66.5.9
'@unocss/reset': 66.5.9
'@unocss/vite': 66.5.9(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))
optionalDependencies:
vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
'@unocss/astro@66.5.9(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@unocss/core': 66.5.9
@@ -14130,6 +14334,19 @@ snapshots:
dependencies:
'@unocss/core': 66.5.9
'@unocss/vite@66.5.9(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@jridgewell/remapping': 2.3.5
'@unocss/config': 66.5.9
'@unocss/core': 66.5.9
'@unocss/inspector': 66.5.9
chokidar: 3.6.0
magic-string: 0.30.21
pathe: 2.0.3
tinyglobby: 0.2.15
unplugin-utils: 0.3.1
vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
'@unocss/vite@66.5.9(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))':
dependencies:
'@jridgewell/remapping': 2.3.5
@@ -14202,6 +14419,10 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
'@vite-pwa/vitepress@0.5.4(vite-plugin-pwa@0.21.2(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0))':
dependencies:
vite-plugin-pwa: 0.21.2(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0)
'@vite-pwa/vitepress@1.0.1(vite-plugin-pwa@1.0.3(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0))':
dependencies:
vite-plugin-pwa: 1.0.3(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0)
@@ -14216,6 +14437,16 @@ snapshots:
vite: 5.4.20(@types/node@22.19.1)(terser@5.44.1)
vue: 3.5.21(typescript@5.9.2)
'@vitejs/plugin-vue@5.2.4(vite@5.4.20(@types/node@22.19.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.2))':
dependencies:
vite: 5.4.20(@types/node@22.19.1)(terser@5.44.1)
vue: 3.5.25(typescript@5.9.2)
'@vitejs/plugin-vue@5.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.2))':
dependencies:
vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
vue: 3.5.25(typescript@5.9.2)
'@vitejs/plugin-vue@6.0.2(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.2))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.50
@@ -14253,7 +14484,7 @@ snapshots:
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.19
magic-string: 0.30.21
optionalDependencies:
vite: 7.1.11(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
@@ -14270,7 +14501,7 @@ snapshots:
'@vitest/snapshot@3.2.4':
dependencies:
'@vitest/pretty-format': 3.2.4
magic-string: 0.30.19
magic-string: 0.30.21
pathe: 2.0.3
'@vitest/spy@3.2.4':
@@ -14302,14 +14533,6 @@ snapshots:
estree-walker: 2.0.2
source-map-js: 1.2.1
'@vue/compiler-core@3.5.24':
dependencies:
'@babel/parser': 7.28.5
'@vue/shared': 3.5.24
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.1
'@vue/compiler-core@3.5.25':
dependencies:
'@babel/parser': 7.28.5
@@ -14323,11 +14546,6 @@ snapshots:
'@vue/compiler-core': 3.5.21
'@vue/shared': 3.5.21
'@vue/compiler-dom@3.5.24':
dependencies:
'@vue/compiler-core': 3.5.24
'@vue/shared': 3.5.24
'@vue/compiler-dom@3.5.25':
dependencies:
'@vue/compiler-core': 3.5.25
@@ -14335,24 +14553,12 @@ snapshots:
'@vue/compiler-sfc@3.5.21':
dependencies:
'@babel/parser': 7.28.4
'@babel/parser': 7.28.5
'@vue/compiler-core': 3.5.21
'@vue/compiler-dom': 3.5.21
'@vue/compiler-ssr': 3.5.21
'@vue/shared': 3.5.21
estree-walker: 2.0.2
magic-string: 0.30.19
postcss: 8.5.6
source-map-js: 1.2.1
'@vue/compiler-sfc@3.5.24':
dependencies:
'@babel/parser': 7.28.5
'@vue/compiler-core': 3.5.24
'@vue/compiler-dom': 3.5.24
'@vue/compiler-ssr': 3.5.24
'@vue/shared': 3.5.24
estree-walker: 2.0.2
magic-string: 0.30.21
postcss: 8.5.6
source-map-js: 1.2.1
@@ -14374,11 +14580,6 @@ snapshots:
'@vue/compiler-dom': 3.5.21
'@vue/shared': 3.5.21
'@vue/compiler-ssr@3.5.24':
dependencies:
'@vue/compiler-dom': 3.5.24
'@vue/shared': 3.5.24
'@vue/compiler-ssr@3.5.25':
dependencies:
'@vue/compiler-dom': 3.5.25
@@ -14460,8 +14661,6 @@ snapshots:
'@vue/shared@3.5.21': {}
'@vue/shared@3.5.24': {}
'@vue/shared@3.5.25': {}
'@vueuse/core@12.8.2(typescript@5.7.3)':
@@ -14668,7 +14867,7 @@ snapshots:
'@xtuc/long@4.2.2': {}
'@zenuml/core@3.41.6(@babel/core@7.28.5)(@babel/template@7.27.2)':
'@zenuml/core@3.41.6(@babel/core@7.28.5)(@babel/template@7.27.2)(@types/react@19.2.7)':
dependencies:
'@floating-ui/react': 0.27.16(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@headlessui/react': 2.2.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -14681,7 +14880,7 @@ snapshots:
highlight.js: 10.7.3
html-to-image: 1.11.13
immer: 10.1.3
jotai: 2.14.0(@babel/core@7.28.5)(@babel/template@7.27.2)(react@19.1.1)
jotai: 2.14.0(@babel/core@7.28.5)(@babel/template@7.27.2)(@types/react@19.2.7)(react@19.1.1)
lodash: 4.17.21
marked: 4.3.0
pako: 2.1.0
@@ -15528,6 +15727,10 @@ snapshots:
commondir@1.0.1: {}
composed-offset-position@0.0.6(@floating-ui/utils@0.2.10):
dependencies:
'@floating-ui/utils': 0.2.10
compressible@2.0.18:
dependencies:
mime-db: 1.54.0
@@ -15770,6 +15973,8 @@ snapshots:
csstype@3.1.3: {}
csstype@3.2.3: {}
cuint@0.2.2: {}
cypress-image-snapshot@4.0.1(cypress@14.5.4)(jest@30.1.3(@types/node@22.19.1)):
@@ -16243,7 +16448,7 @@ snapshots:
detective-vue2@2.2.0(typescript@5.7.3):
dependencies:
'@dependents/detective-less': 5.0.1
'@vue/compiler-sfc': 3.5.24
'@vue/compiler-sfc': 3.5.25
detective-es6: 5.0.1
detective-sass: 6.0.1
detective-scss: 5.0.1
@@ -17922,7 +18127,7 @@ snapshots:
istanbul-lib-instrument@6.0.3:
dependencies:
'@babel/core': 7.28.4
'@babel/parser': 7.28.4
'@babel/parser': 7.28.5
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 7.7.3
@@ -18237,10 +18442,10 @@ snapshots:
jest-snapshot@30.1.2:
dependencies:
'@babel/core': 7.28.4
'@babel/generator': 7.28.3
'@babel/generator': 7.28.5
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4)
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4)
'@babel/types': 7.28.4
'@babel/types': 7.28.5
'@jest/expect-utils': 30.1.2
'@jest/get-type': 30.1.0
'@jest/snapshot-utils': 30.1.2
@@ -18350,10 +18555,11 @@ snapshots:
'@hapi/topo': 6.0.2
'@standard-schema/spec': 1.0.0
jotai@2.14.0(@babel/core@7.28.5)(@babel/template@7.27.2)(react@19.1.1):
jotai@2.14.0(@babel/core@7.28.5)(@babel/template@7.27.2)(@types/react@19.2.7)(react@19.1.1):
optionalDependencies:
'@babel/core': 7.28.5
'@babel/template': 7.27.2
'@types/react': 19.2.7
react: 19.1.1
jpeg-js@0.4.4: {}
@@ -18590,6 +18796,22 @@ snapshots:
rfdc: 1.4.1
wrap-ansi: 9.0.2
lit-element@4.2.1:
dependencies:
'@lit-labs/ssr-dom-shim': 1.4.0
'@lit/reactive-element': 2.1.1
lit-html: 3.3.1
lit-html@3.3.1:
dependencies:
'@types/trusted-types': 2.0.7
lit@3.3.1:
dependencies:
'@lit/reactive-element': 2.1.1
lit-element: 4.2.1
lit-html: 3.3.1
loader-runner@4.3.0: {}
local-pkg@1.1.2:
@@ -19864,6 +20086,8 @@ snapshots:
pure-rand@7.0.1: {}
qr-creator@1.0.0: {}
qs@6.13.0:
dependencies:
side-channel: 1.1.0
@@ -21323,6 +21547,33 @@ snapshots:
universalify@2.0.1: {}
unocss@66.5.9(postcss@8.5.6)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)):
dependencies:
'@unocss/astro': 66.5.9(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))
'@unocss/cli': 66.5.9
'@unocss/core': 66.5.9
'@unocss/postcss': 66.5.9(postcss@8.5.6)
'@unocss/preset-attributify': 66.5.9
'@unocss/preset-icons': 66.5.9
'@unocss/preset-mini': 66.5.9
'@unocss/preset-tagify': 66.5.9
'@unocss/preset-typography': 66.5.9
'@unocss/preset-uno': 66.5.9
'@unocss/preset-web-fonts': 66.5.9
'@unocss/preset-wind': 66.5.9
'@unocss/preset-wind3': 66.5.9
'@unocss/preset-wind4': 66.5.9
'@unocss/transformer-attributify-jsx': 66.5.9
'@unocss/transformer-compile-class': 66.5.9
'@unocss/transformer-directives': 66.5.9
'@unocss/transformer-variant-group': 66.5.9
'@unocss/vite': 66.5.9(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))
optionalDependencies:
vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
transitivePeerDependencies:
- postcss
- supports-color
unocss@66.5.9(postcss@8.5.6)(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)):
dependencies:
'@unocss/astro': 66.5.9(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))
@@ -21367,7 +21618,7 @@ snapshots:
chokidar: 3.6.0
debug: 4.4.3(supports-color@8.1.1)
local-pkg: 1.1.2
magic-string: 0.30.19
magic-string: 0.30.21
mlly: 1.8.0
tinyglobby: 0.2.15
unplugin: 2.3.10
@@ -21506,6 +21757,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
vite-plugin-pwa@0.21.2(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0):
dependencies:
debug: 4.4.3(supports-color@8.1.1)
pretty-bytes: 6.1.1
tinyglobby: 0.2.15
vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
workbox-build: 7.3.0(@types/babel__core@7.20.5)
workbox-window: 7.3.0
transitivePeerDependencies:
- supports-color
vite-plugin-pwa@1.0.3(vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0):
dependencies:
debug: 4.4.3(supports-color@8.1.1)
@@ -21527,6 +21789,22 @@ snapshots:
fsevents: 2.3.3
terser: 5.44.1
vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
rollup: 4.52.5
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 22.19.1
fsevents: 2.3.3
jiti: 2.6.1
terser: 5.44.1
tsx: 4.20.6
yaml: 2.8.1
vite@7.1.11(@types/node@22.19.1)(jiti@2.5.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1):
dependencies:
esbuild: 0.25.12
@@ -21559,20 +21837,69 @@ snapshots:
tsx: 4.20.6
yaml: 2.8.1
vitepress-plugin-search@1.0.4-alpha.22(flexsearch@0.8.212)(vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3))(vue@3.5.21(typescript@5.7.3)):
vitepress-plugin-search@1.0.4-alpha.22(flexsearch@0.8.212)(vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3))(vue@3.5.21(typescript@5.7.3)):
dependencies:
'@types/flexsearch': 0.7.42
'@types/markdown-it': 12.2.3
flexsearch: 0.8.212
glob-to-regexp: 0.4.1
markdown-it: 13.0.2
vitepress: 1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3)
vitepress: 1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3)
vue: 3.5.21(typescript@5.7.3)
vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3):
vitepress@1.6.3(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.9.2):
dependencies:
'@docsearch/css': 3.8.2
'@docsearch/js': 3.8.2(@algolia/client-search@5.37.0)(search-insights@2.17.3)
'@docsearch/js': 3.8.2(@algolia/client-search@5.37.0)(@types/react@19.2.7)(search-insights@2.17.3)
'@iconify-json/simple-icons': 1.2.52
'@shikijs/core': 2.5.0
'@shikijs/transformers': 2.5.0
'@shikijs/types': 2.5.0
'@types/markdown-it': 14.1.2
'@vitejs/plugin-vue': 5.2.4(vite@5.4.20(@types/node@22.19.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.2))
'@vue/devtools-api': 7.7.7
'@vue/shared': 3.5.25
'@vueuse/core': 12.8.2(typescript@5.9.2)
'@vueuse/integrations': 12.8.2(axios@1.13.2)(change-case@5.4.4)(focus-trap@7.6.5)(typescript@5.9.2)
focus-trap: 7.6.5
mark.js: 8.11.1
minisearch: 7.1.2
shiki: 2.5.0
vite: 5.4.20(@types/node@22.19.1)(terser@5.44.1)
vue: 3.5.25(typescript@5.9.2)
optionalDependencies:
postcss: 8.5.6
transitivePeerDependencies:
- '@algolia/client-search'
- '@types/node'
- '@types/react'
- async-validator
- axios
- change-case
- drauu
- fuse.js
- idb-keyval
- jwt-decode
- less
- lightningcss
- nprogress
- qrcode
- react
- react-dom
- sass
- sass-embedded
- search-insights
- sortablejs
- stylus
- sugarss
- terser
- typescript
- universal-cookie
vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.7.3):
dependencies:
'@docsearch/css': 3.8.2
'@docsearch/js': 3.8.2(@algolia/client-search@5.37.0)(@types/react@19.2.7)(search-insights@2.17.3)
'@iconify-json/simple-icons': 1.2.52
'@shikijs/core': 2.5.0
'@shikijs/transformers': 2.5.0
@@ -21618,10 +21945,10 @@ snapshots:
- typescript
- universal-cookie
vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.9.2):
vitepress@1.6.4(@algolia/client-search@5.37.0)(@types/node@22.19.1)(@types/react@19.2.7)(axios@1.13.2)(change-case@5.4.4)(postcss@8.5.6)(search-insights@2.17.3)(terser@5.44.1)(typescript@5.9.2):
dependencies:
'@docsearch/css': 3.8.2
'@docsearch/js': 3.8.2(@algolia/client-search@5.37.0)(search-insights@2.17.3)
'@docsearch/js': 3.8.2(@algolia/client-search@5.37.0)(@types/react@19.2.7)(search-insights@2.17.3)
'@iconify-json/simple-icons': 1.2.52
'@shikijs/core': 2.5.0
'@shikijs/transformers': 2.5.0

View File

@@ -8,7 +8,7 @@
},
"include": [
"./.build/*.ts",
"./.esbuild/*.ts",
"./.esbuild/**/*.ts",
"./.vite/*.ts",
"./cypress.config.ts",
"./tests",