revert(migrate): removes migrate modal in favour of the button we put in

This commit is contained in:
Lewis Wynne 2026-03-23 21:02:22 +00:00
parent a4f8c651a4
commit 8525561522
4 changed files with 111 additions and 150 deletions

View file

@ -1,25 +1,35 @@
<script lang="ts">
import { ChevronDown } from 'lucide-svelte';
import type { Character, Template } from '$lib/types';
import { roster } from '$lib/state.svelte';
import { presets } from '$lib/presets';
import { slugify } from '$lib/utils/slugify';
import { diffTemplates, hasChanges } from '$lib/utils/template-diff';
import RecordCard from './RecordCard.svelte';
import Modal from './Modal.svelte';
let { character }: { character: Character } = $props();
let dismissed = $state<string | null>(null);
let showTemplateSwitcher = $state(false);
let showMigrationModal = $state(false);
let speciesKey = slugify('Species');
let pendingMigration = $derived.by(() => {
if (!character.template.id.startsWith('preset:')) return null;
const preset = presets.find((p) => p.id === character.template.id);
if (!preset) return null;
const diff = diffTemplates(character.template, preset);
if (!hasChanges(diff)) return null;
return { preset, diff };
});
let suggestion = $derived.by((): { template: Template; reason: string } | null => {
const currentSpecies = character.data[speciesKey] as string | undefined;
if (!currentSpecies) return null;
const current = character.template;
// Current template is species-specific but doesn't match selected species
if (current.species?.length && !current.species.includes(currentSpecies)) {
// Find a template that matches, or fall back to a general one
const specific = presets.find((p) =>
p.species?.includes(currentSpecies) && p.id !== current.id
);
@ -34,7 +44,6 @@
return null;
}
// Current template is general, but a species-specific one exists
if (!current.species) {
const specific = presets.find((p) =>
p.species?.includes(currentSpecies) && p.id !== current.id
@ -54,10 +63,55 @@
character.template = $state.snapshot(template);
roster.scheduleSave(character);
dismissed = null;
showTemplateSwitcher = false;
}
async function applyMigration() {
if (!pendingMigration) return;
await roster.migrateToPreset(character, pendingMigration.preset);
}
</script>
<div class="flex flex-col gap-4">
<!-- Template bar -->
<div class="flex items-center gap-2 text-xs">
<span class="relative">
<button
onclick={(e) => { e.stopPropagation(); showTemplateSwitcher = !showTemplateSwitcher; }}
class="hover:underline"
style="color: var(--text-muted);"
>
{character.template.name} template
</button>
{#if showTemplateSwitcher}
<nav class="absolute z-10 mt-1 left-0 w-56 rounded border shadow-lg" style="background: var(--bg-card); border-color: var(--border);">
{#each presets as preset}
<button
onclick={(e) => { e.stopPropagation(); switchTemplate(preset); }}
class="block w-full text-left px-3 py-2 text-sm hover:opacity-80"
style={preset.id === character.template.id ? 'color: var(--accent);' : 'color: var(--text);'}
>
<span class="font-medium">{preset.name}</span>
{#if preset.description}
<span class="block text-xs" style="color: var(--text-muted);">{preset.description}</span>
{/if}
</button>
{/each}
</nav>
{/if}
</span>
{#if pendingMigration}
<button
onclick={() => { showMigrationModal = true; }}
class="hover:underline"
style="color: var(--accent);"
>
update available
</button>
{/if}
</div>
<!-- Species suggestion -->
{#if suggestion}
<div class="rounded border px-4 py-3" style="border-color: var(--accent); background: var(--bg-card);">
<p class="text-sm mb-2">
@ -94,3 +148,50 @@
/>
{/each}
</div>
{#if showMigrationModal && pendingMigration}
<Modal onClose={() => { showMigrationModal = false; }}>
<h2 class="font-semibold mb-3">Template Update</h2>
<p class="text-sm mb-2">The <strong>{pendingMigration.preset.name}</strong> template has been updated:</p>
<ul class="text-sm flex flex-col gap-0.5 mb-3" style="color: var(--text-muted);">
{#each pendingMigration.diff.renamedFields as r}
<li>{r.from}{r.to}</li>
{/each}
{#each pendingMigration.diff.addedRecords as r}
<li>+ New record: {r}</li>
{/each}
{#each pendingMigration.diff.removedRecords as r}
<li>- Removed record: {r}</li>
{/each}
{#each pendingMigration.diff.addedFields as f}
<li>+ New field: {f}</li>
{/each}
{#each pendingMigration.diff.removedFields as f}
<li>- Removed field: {f}</li>
{/each}
</ul>
<p class="text-xs mb-3" style="color: var(--text-muted);">Your existing data will be preserved.</p>
<div class="flex gap-2 justify-end">
<button
onclick={() => { showMigrationModal = false; }}
class="px-3 py-1 rounded text-sm hover:opacity-80"
style="color: var(--text-muted);"
>
Skip
</button>
<button
onclick={async () => { await applyMigration(); showMigrationModal = false; }}
class="px-3 py-1 rounded text-sm border hover:opacity-80"
style="border-color: var(--accent); color: var(--accent);"
>
Update
</button>
</div>
</Modal>
{/if}
<svelte:window onclick={() => {
if (showTemplateSwitcher) {
showTemplateSwitcher = false;
}
}} />