Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1fd4dc244 | ||
|
|
9436f8ddda |
@@ -5,7 +5,6 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Online FlowChart & Diagrams Editor - Mermaid Live Editor</title>
|
||||
<meta name="og:image" content="%sveltekit.assets%/favicon.svg" />
|
||||
<link rel="canonical" href="https://mermaid.ai/live" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Simplify documentation and avoid heavy tools. Open source Visio Alternative. Commonly used for explaining your code! Mermaid is a simple markdown-like script language for generating charts from text via javascript." />
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<script lang="ts">
|
||||
import McWrapper from '$/components/McWrapper.svelte';
|
||||
import MermaidChartIcon from '$/components/MermaidChartIcon.svelte';
|
||||
import { Button } from '$/components/ui/button';
|
||||
import { standardizeDiagramType } from '$/util/mermaid';
|
||||
import { stateStore, urlsStore } from '$/util/state';
|
||||
import { logMermaidChartClick } from '$/util/stats';
|
||||
import { quintInOut } from 'svelte/easing';
|
||||
import { slide } from 'svelte/transition';
|
||||
|
||||
const visualEditDiagramTypes = new Set([
|
||||
'flowchart',
|
||||
'stateDiagram',
|
||||
'classDiagram',
|
||||
'sequenceDiagram',
|
||||
'er',
|
||||
'requirement',
|
||||
'mindmap'
|
||||
]);
|
||||
|
||||
const diagramType = $derived.by(() => {
|
||||
const dt = $stateStore.diagramType;
|
||||
return dt ? standardizeDiagramType(dt) : undefined;
|
||||
});
|
||||
|
||||
const showVisualEdit = $derived.by(() => {
|
||||
return diagramType ? visualEditDiagramTypes.has(diagramType) : false;
|
||||
});
|
||||
|
||||
interface EnhancedEditAction {
|
||||
campaign: string;
|
||||
label: string;
|
||||
medium: 'ai_edit' | 'visual_edit' | 'voice_edit';
|
||||
source: string;
|
||||
}
|
||||
|
||||
let currentActionMedium = $state<EnhancedEditAction['medium'] | undefined>(undefined);
|
||||
let previousDiagramType = $state<string | undefined>(undefined);
|
||||
|
||||
const availableActions = $derived.by<EnhancedEditAction[]>(() => {
|
||||
if (!$stateStore.diagramType) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const actions: EnhancedEditAction[] = [
|
||||
{ campaign: 'ai_1', label: 'with AI', medium: 'ai_edit', source: 'aiEdit' },
|
||||
{ campaign: 'voice_1', label: 'with Voice', medium: 'voice_edit', source: 'voiceEdit' }
|
||||
];
|
||||
|
||||
if (showVisualEdit) {
|
||||
actions.unshift({
|
||||
campaign: 'visual_1',
|
||||
label: 'Visually',
|
||||
medium: 'visual_edit',
|
||||
source: 'visualEdit'
|
||||
});
|
||||
}
|
||||
|
||||
return actions;
|
||||
});
|
||||
|
||||
const currentAction = $derived.by(() => {
|
||||
const actions = availableActions;
|
||||
if (actions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return actions.find(({ medium }) => medium === currentActionMedium) ?? actions[0];
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const actions = availableActions;
|
||||
|
||||
if (!diagramType || actions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasCurrentAction = actions.some(({ medium }) => medium === currentActionMedium);
|
||||
|
||||
if (diagramType !== previousDiagramType || !hasCurrentAction) {
|
||||
currentActionMedium = actions[Math.floor(Math.random() * actions.length)].medium;
|
||||
previousDiagramType = diagramType;
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (diagramType) {
|
||||
return;
|
||||
}
|
||||
|
||||
previousDiagramType = undefined;
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if currentAction}
|
||||
<McWrapper>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
href={$urlsStore.mermaidChart({
|
||||
medium: currentAction.medium,
|
||||
campaign: currentAction.campaign
|
||||
}).save}
|
||||
target="_blank"
|
||||
onclick={() => logMermaidChartClick(currentAction.source)}>
|
||||
<MermaidChartIcon />
|
||||
Edit
|
||||
{#key currentAction.label}
|
||||
<span
|
||||
class="-ml-1"
|
||||
in:slide={{ axis: 'x', easing: quintInOut, delay: 400 }}
|
||||
out:slide={{ axis: 'x', easing: quintInOut }}>
|
||||
{currentAction.label}
|
||||
</span>
|
||||
{/key}
|
||||
</Button>
|
||||
</McWrapper>
|
||||
{/if}
|
||||
@@ -142,11 +142,13 @@ export const urlsStore = derived([stateStore], ([{ code, serialized }]) => {
|
||||
}: {
|
||||
medium:
|
||||
| 'ai_repair'
|
||||
| 'ai_edit'
|
||||
| 'main_menu'
|
||||
| 'save_diagram'
|
||||
| 'share'
|
||||
| 'vibe_diagramming'
|
||||
| 'visual_edit';
|
||||
| 'visual_edit'
|
||||
| 'voice_edit';
|
||||
campaign?: string;
|
||||
}) => {
|
||||
const utmSource = getUTMSource();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import Card from '$/components/Card/Card.svelte';
|
||||
import DiagramDocButton from '$/components/DiagramDocumentationButton.svelte';
|
||||
import Editor from '$/components/Editor.svelte';
|
||||
import EnhancedEditsButton from '$/components/EnhancedEditsButton.svelte';
|
||||
import History from '$/components/History/History.svelte';
|
||||
import McWrapper from '$/components/McWrapper.svelte';
|
||||
import MermaidChartIcon from '$/components/MermaidChartIcon.svelte';
|
||||
@@ -19,15 +20,12 @@
|
||||
import VersionSecurityToolbar from '$/components/VersionSecurityToolbar.svelte';
|
||||
import View from '$/components/View.svelte';
|
||||
import type { EditorMode, Tab } from '$/types';
|
||||
import { standardizeDiagramType } from '$/util/mermaid';
|
||||
import { shouldShowEditorChooser } from '$/util/migration/domainMigration';
|
||||
import { PanZoomState } from '$/util/panZoom';
|
||||
import { stateStore, updateCodeStore, urlsStore } from '$/util/state';
|
||||
import { logEvent, logMermaidChartClick } from '$/util/stats';
|
||||
import { initHandler } from '$/util/util';
|
||||
import { onMount } from 'svelte';
|
||||
import { quintInOut } from 'svelte/easing';
|
||||
import { slide } from 'svelte/transition';
|
||||
import CodeIcon from '~icons/custom/code';
|
||||
import HistoryIcon from '~icons/material-symbols/history';
|
||||
import GearIcon from '~icons/material-symbols/settings-outline-rounded';
|
||||
@@ -65,20 +63,6 @@
|
||||
});
|
||||
});
|
||||
|
||||
const visualEditDiagramTypes = new Set([
|
||||
'flowchart',
|
||||
'stateDiagram',
|
||||
'classDiagram',
|
||||
'sequenceDiagram',
|
||||
'er',
|
||||
'requirement',
|
||||
'mindmap'
|
||||
]);
|
||||
const showVisualEdit = $derived.by(() => {
|
||||
const dt = $stateStore.diagramType;
|
||||
return dt ? visualEditDiagramTypes.has(standardizeDiagramType(dt)) : false;
|
||||
});
|
||||
|
||||
let isHistoryOpen = $state(false);
|
||||
|
||||
let editorPane: Resizable.Pane | undefined;
|
||||
@@ -153,24 +137,7 @@
|
||||
<Resizable.Handle class="mr-1 hidden opacity-0 sm:block" />
|
||||
<Resizable.Pane minSize={15} class="relative flex h-full flex-1 flex-col overflow-hidden">
|
||||
<View {panZoomState} shouldShowGrid={$stateStore.grid} />
|
||||
{#if showVisualEdit}
|
||||
<div
|
||||
class="absolute top-0 left-5 hidden md:block"
|
||||
transition:slide={{ axis: 'x', easing: quintInOut }}>
|
||||
<McWrapper>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
href={$urlsStore.mermaidChart({ medium: 'visual_edit', campaign: 'visual_1' })
|
||||
.save}
|
||||
target="_blank"
|
||||
onclick={() => logMermaidChartClick('visualEdit')}>
|
||||
<MermaidChartIcon />
|
||||
Edit Visually
|
||||
</Button>
|
||||
</McWrapper>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="absolute top-0 left-5 hidden md:block"><EnhancedEditsButton /></div>
|
||||
<div class="absolute top-0 right-0"><PanZoomToolbar {panZoomState} /></div>
|
||||
<div class="absolute right-0 bottom-0"><VersionSecurityToolbar /></div>
|
||||
<div class="absolute bottom-0 left-0 sm:left-5"><SyncRoughToolbar /></div>
|
||||
|
||||
Reference in New Issue
Block a user