Files
mermaid-live-editor/src/lib/components/EnhancedEditsButton.svelte
T
Sidharth VinodandClaude Fable 5 b3c8bd6c28 refactor: Migrate editor state from svelte/store to runes
Replace the writable+derived store pipeline in state.ts with a
state.svelte.ts module: a deep $state inputState mutated only through
the exported update functions, each of which persists the snapshot and
re-validates it asynchronously into validatedState.current (with
urls.current derived from it). Store subscriptions in components become
$effect blocks, and the rough/grid toggles use function bindings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 00:34:07 +05:30

120 lines
3.0 KiB
Svelte

<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 { validatedState, urls } from '$/util/state.svelte';
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 = validatedState.current.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;
}
const cycleIntervalMs = 30_000;
let currentActionIndex = $state(0);
const availableActions = $derived.by<EnhancedEditAction[]>(() => {
if (!validatedState.current.diagramType) {
return [];
}
const actions: EnhancedEditAction[] = [
{ campaign: 'voice_1', label: 'with voice', medium: 'voice_edit', source: 'voiceEdit' },
{ campaign: 'ai_1', label: 'with AI', medium: 'ai_edit', source: 'aiEdit' }
];
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[currentActionIndex % actions.length];
});
$effect(() => {
const actionCount = availableActions.length;
if (actionCount === 0) {
currentActionIndex = 0;
return;
}
if (currentActionIndex >= actionCount) {
currentActionIndex = 0;
}
if (actionCount <= 1) {
return;
}
const intervalID = setInterval(() => {
currentActionIndex = (currentActionIndex + 1) % actionCount;
}, cycleIntervalMs);
return () => clearInterval(intervalID);
});
</script>
{#if currentAction}
<McWrapper>
<Button
variant="secondary"
size="sm"
href={urls.current.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}