feat(fend): sticky right-split for form output
This commit is contained in:
parent
63e8178fb0
commit
bb429d8195
4 changed files with 97 additions and 17 deletions
|
|
@ -10,7 +10,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="flex items-center gap-3 px-4 py-3 border-b" style="border-color: var(--border); background: var(--bg-card);">
|
<header class="sticky top-0 z-20 flex items-center gap-3 px-4 py-3 border-b" style="border-color: var(--border); background: var(--bg-card);">
|
||||||
<h1 class="font-bold whitespace-nowrap">Aurora Records</h1>
|
<h1 class="font-bold whitespace-nowrap">Aurora Records</h1>
|
||||||
|
|
||||||
{#if roster.characters.length > 0}
|
{#if roster.characters.length > 0}
|
||||||
|
|
|
||||||
42
src/lib/components/OutputPanel.svelte
Normal file
42
src/lib/components/OutputPanel.svelte
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Character } from '$lib/types';
|
||||||
|
import { generateRecord } from '$lib/output';
|
||||||
|
import { species } from '$lib/data';
|
||||||
|
import OutputTab from './OutputTab.svelte';
|
||||||
|
|
||||||
|
let { character }: { character: Character } = $props();
|
||||||
|
|
||||||
|
let tabs = $derived(
|
||||||
|
character.template.records.filter((r) => r.type !== 'public')
|
||||||
|
);
|
||||||
|
|
||||||
|
let activeTab = $state('');
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (tabs.length && !tabs.some((t) => t.type === activeTab)) {
|
||||||
|
activeTab = tabs[0].type;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = $derived(
|
||||||
|
activeTab ? generateRecord(character.template, character.data, activeTab, species) : ''
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-col h-full rounded border" style="border-color: var(--border); background: var(--bg-card);">
|
||||||
|
<div class="flex border-b" style="border-color: var(--border);">
|
||||||
|
{#each tabs as tab}
|
||||||
|
<button
|
||||||
|
onclick={() => { activeTab = tab.type; }}
|
||||||
|
class="px-4 py-2 text-sm capitalize"
|
||||||
|
style={activeTab === tab.type
|
||||||
|
? `color: var(--accent); border-bottom: 2px solid var(--accent);`
|
||||||
|
: `color: var(--text-muted); border-bottom: 2px solid transparent;`}
|
||||||
|
>
|
||||||
|
{tab.type}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<OutputTab {output} />
|
||||||
|
</div>
|
||||||
31
src/lib/components/OutputTab.svelte
Normal file
31
src/lib/components/OutputTab.svelte
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Copy, Check } from 'lucide-svelte';
|
||||||
|
|
||||||
|
let { output }: { output: string } = $props();
|
||||||
|
|
||||||
|
let copied = $state(false);
|
||||||
|
|
||||||
|
let wordCount = $derived(
|
||||||
|
output.trim() ? output.trim().split(/\s+/).length : 0
|
||||||
|
);
|
||||||
|
|
||||||
|
async function copy() {
|
||||||
|
await navigator.clipboard.writeText(output);
|
||||||
|
copied = true;
|
||||||
|
setTimeout(() => { copied = false; }, 2000);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-col h-full">
|
||||||
|
<div class="flex items-center justify-between px-3 py-2 text-sm" style="color: var(--text-muted);">
|
||||||
|
<span>{wordCount} words</span>
|
||||||
|
<button onclick={copy} class="flex items-center gap-1 px-2 py-1 rounded border hover:opacity-80" style="border-color: var(--border);">
|
||||||
|
{#if copied}
|
||||||
|
<Check size={14} /> Copied
|
||||||
|
{:else}
|
||||||
|
<Copy size={14} /> Copy
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<pre class="flex-1 overflow-auto px-4 py-3 text-sm whitespace-pre-wrap font-mono" style="background: var(--bg); color: var(--text);">{output}</pre>
|
||||||
|
</div>
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Header from '$lib/components/Header.svelte';
|
import Header from '$lib/components/Header.svelte';
|
||||||
import SchemaForm from '$lib/components/SchemaForm.svelte';
|
import SchemaForm from '$lib/components/SchemaForm.svelte';
|
||||||
|
import OutputPanel from '$lib/components/OutputPanel.svelte';
|
||||||
import { roster } from '$lib/state.svelte';
|
import { roster } from '$lib/state.svelte';
|
||||||
import { presets } from '$lib/presets';
|
import { presets } from '$lib/presets';
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -8,22 +9,28 @@
|
||||||
<div class="min-h-screen flex flex-col">
|
<div class="min-h-screen flex flex-col">
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<main class="flex-1 p-4">
|
{#if roster.active}
|
||||||
{#if roster.active}
|
{@const char = roster.active}
|
||||||
<div class="max-w-xl mx-auto">
|
<main class="flex-1 grid grid-cols-1 lg:grid-cols-[1fr_1fr]">
|
||||||
<SchemaForm character={roster.active} />
|
<div class="p-4">
|
||||||
|
<div class="max-w-xl mx-auto">
|
||||||
|
<SchemaForm character={char} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
<div class="lg:sticky lg:top-[49px] lg:max-h-[calc(100vh-49px)] overflow-y-auto p-4">
|
||||||
<div class="flex flex-col items-center justify-center gap-4 h-full min-h-[60vh]">
|
<OutputPanel character={char} />
|
||||||
<p style="color: var(--text-muted);">No characters yet.</p>
|
|
||||||
<button
|
|
||||||
onclick={() => roster.create(presets[0])}
|
|
||||||
class="px-3 py-1 rounded text-sm border hover:opacity-80"
|
|
||||||
style="border-color: var(--border);"
|
|
||||||
>
|
|
||||||
Get Started
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
</main>
|
||||||
</main>
|
{:else}
|
||||||
|
<main class="flex-1 flex flex-col items-center justify-center gap-4">
|
||||||
|
<p style="color: var(--text-muted);">No characters yet.</p>
|
||||||
|
<button
|
||||||
|
onclick={() => roster.create(presets[0])}
|
||||||
|
class="px-3 py-1 rounded text-sm border hover:opacity-80"
|
||||||
|
style="border-color: var(--border);"
|
||||||
|
>
|
||||||
|
Get Started
|
||||||
|
</button>
|
||||||
|
</main>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue