Files
mermaid-live-editor/src/lib/components/Editor.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

84 lines
2.8 KiB
Svelte

<script lang="ts">
import DesktopEditor from '$/components/DesktopEditor.svelte';
import McWrapper from '$/components/McWrapper.svelte';
import MermaidChartIcon from '$/components/MermaidChartIcon.svelte';
import MobileEditor from '$/components/MobileEditor.svelte';
import { Button } from '$/components/ui/button';
import { TID } from '$/constants';
import { env } from '$/util/env';
import { updateCode, updateConfig, urls, validatedState } from '$lib/util/state.svelte';
import { logMermaidChartClick } from '$lib/util/stats';
import { debounce } from 'lodash-es';
import ExclamationCircleIcon from '~icons/material-symbols/error-outline-rounded';
const { isMobile } = $props<{ isMobile: boolean }>();
const onUpdate = (text: string) => {
if (validatedState.current.editorMode === 'code') {
updateCode(text);
} else {
updateConfig(text);
}
};
let showError = $state(false);
const showErrorDebounced = debounce(() => {
showError = true;
}, 3000);
$effect(() => {
if (validatedState.current.error) {
showErrorDebounced();
} else {
showErrorDebounced.cancel();
showError = false;
}
return () => {
showErrorDebounced.cancel();
};
});
</script>
<div class="flex h-full flex-col">
{#if isMobile}
<MobileEditor {onUpdate} />
{:else}
<DesktopEditor {onUpdate} />
{/if}
{#if showError && validatedState.current.error instanceof Error}
<div class="flex flex-col text-sm" data-testid={TID.errorContainer}>
<div class="flex items-center justify-between gap-2 bg-slate-900 p-2 text-white">
<div class="flex w-fit items-center gap-2">
<ExclamationCircleIcon class="size-6 text-destructive" aria-hidden="true" />
<div class="flex flex-col">
<p>Syntax error</p>
{#if env.isEnabledMermaidChartLinks && validatedState.current.editorMode === 'code'}
<p class="text-xs text-white/60" data-testid={TID.aiHelpText}>
Create a free account to repair with AI
</p>
{/if}
</div>
</div>
{#if validatedState.current.editorMode === 'code'}
<McWrapper>
<Button
variant="accent"
size="sm"
data-testid={TID.aiRepairButton}
href={urls.current.mermaidChart({ medium: 'ai_repair' }).save}
target="_blank"
onclick={() => logMermaidChartClick('aiRepair')}>
<MermaidChartIcon />
AI Repair
</Button>
</McWrapper>
{/if}
</div>
<output class="max-h-32 overflow-auto bg-muted p-2" name="mermaid-error" for="editor">
<pre>{validatedState.current.error?.toString()}</pre>
</output>
</div>
{/if}
</div>