feat: updated help text

This commit is contained in:
lew 2026-03-24 03:38:18 +00:00
parent ed695d136c
commit 79fe404de5
6 changed files with 46 additions and 24 deletions

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { Sun, Moon, Trash2, Plus, Upload } from 'lucide-svelte'; import { Sun, Moon, Trash2, Plus, Upload, CircleHelp } from 'lucide-svelte';
import { theme } from '$lib/theme.svelte'; import { theme } from '$lib/theme.svelte';
import { roster } from '$lib/state.svelte'; import { roster } from '$lib/state.svelte';
import { presets } from '$lib/presets'; import { presets } from '$lib/presets';
@ -8,11 +8,13 @@
import TemplatePicker from './TemplatePicker.svelte'; import TemplatePicker from './TemplatePicker.svelte';
import ShareMenu from './ShareMenu.svelte'; import ShareMenu from './ShareMenu.svelte';
import Modal from './Modal.svelte'; import Modal from './Modal.svelte';
import HelpText from './HelpText.svelte';
let { onImport }: { onImport?: (json: string) => void } = $props(); let { onImport }: { onImport?: (json: string) => void } = $props();
let confirmDelete = $state(false); let confirmDelete = $state(false);
let showPicker = $state(false); let showPicker = $state(false);
let showHelp = $state(false);
let openDropdown = $state<'add' | 'share' | null>(null); let openDropdown = $state<'add' | 'share' | null>(null);
let fileInput: HTMLInputElement; let fileInput: HTMLInputElement;
@ -109,6 +111,10 @@
{#if roster.saveStatus === 'saving'}Saving...{:else if roster.saveStatus === 'saved'}Saved{/if} {#if roster.saveStatus === 'saving'}Saving...{:else if roster.saveStatus === 'saved'}Saved{/if}
</span> </span>
<button onclick={() => { showHelp = true; }} class="flex items-center justify-center w-[30px] h-[30px] rounded hover:opacity-80" title="About">
<CircleHelp size={18} />
</button>
<button onclick={() => theme.toggle()} class="flex items-center justify-center w-[30px] h-[30px] rounded hover:opacity-80" title="Toggle theme"> <button onclick={() => theme.toggle()} class="flex items-center justify-center w-[30px] h-[30px] rounded hover:opacity-80" title="Toggle theme">
{#if theme.dark} {#if theme.dark}
<Sun size={18} /> <Sun size={18} />
@ -147,4 +153,19 @@
</Modal> </Modal>
{/if} {/if}
{#if showHelp}
<Modal onClose={() => { showHelp = false; }}>
<HelpText />
<div class="flex justify-end mt-4">
<button
onclick={() => { showHelp = false; }}
class="px-3 py-1 rounded text-sm border hover:opacity-80"
style="border-color: var(--border); color: var(--text);"
>
Got it
</button>
</div>
</Modal>
{/if}
<svelte:window onclick={() => { openDropdown = null; }} /> <svelte:window onclick={() => { openDropdown = null; }} />

View file

@ -0,0 +1,17 @@
<div class="text-sm flex flex-col gap-4" style="color: var(--text-muted);">
<p>
Pick a template and fill in the form. Each section covers a different record. Blank fields are omitted from the output automatically, so no rush to finish everything.
</p>
<p>
Characters save to your browser. You can also export to a file or generate a share link: the link itself encodes the full set of records, so functionally it's a save file.
</p>
<p>
Share links let the recipient see a preview of your records, with the option to import the character into their own roster.
</p>
<p>
This tool is entirely data-driven in XML, and it's already set up for template sharing. A visual template editor is coming soon, so anybody can create their own templates and share them between one another.
</p>
<p>
Cheers.
</p>
</div>

View file

@ -22,7 +22,7 @@ describe('exportCharacter', () => {
expect(parsed.version).toBe(1); expect(parsed.version).toBe(1);
expect(parsed.templateId).toBe('preset:standard'); expect(parsed.templateId).toBe('preset:standard');
expect(parsed.template).toBeDefined(); expect(parsed.template).toBeDefined();
expect(parsed.template.name).toBe('Standard'); expect(parsed.template.name).toBe('General');
expect(parsed.data).toEqual({ expect(parsed.data).toEqual({
name: 'Yury Zakharov', name: 'Yury Zakharov',
species: 'human', species: 'human',

View file

@ -41,7 +41,7 @@ describe('character URL encoding', () => {
const encoded = encodeCharacterURL(testCharacter); const encoded = encodeCharacterURL(testCharacter);
const decoded = decodeCharacterURL(encoded); const decoded = decodeCharacterURL(encoded);
expect(decoded.data).toEqual(testCharacter.data); expect(decoded.data).toEqual(testCharacter.data);
expect(decoded.template.name).toBe('Standard'); expect(decoded.template.name).toBe('General');
}); });
it('uses short encoding for preset templates', () => { it('uses short encoding for preset templates', () => {

View file

@ -40,8 +40,8 @@ describe('isBlankCharacter', () => {
expect(isBlankCharacter(makeChar({ 'spoken-languages': [] }))).toBe(true); expect(isBlankCharacter(makeChar({ 'spoken-languages': [] }))).toBe(true);
}); });
it('returns true when languages is just the default', () => { it('returns false when languages has any value', () => {
expect(isBlankCharacter(makeChar({ 'spoken-languages': ['Tau Ceti Basic'] }))).toBe(true); expect(isBlankCharacter(makeChar({ 'spoken-languages': ['Tau Ceti Basic'] }))).toBe(false);
}); });
it('returns false when languages has custom values', () => { it('returns false when languages has custom values', () => {

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { FileText, Link2, Users } from 'lucide-svelte';
import Header from '$lib/components/Header.svelte'; import Header from '$lib/components/Header.svelte';
import HelpText from '$lib/components/HelpText.svelte';
import SchemaForm from '$lib/components/SchemaForm.svelte'; import SchemaForm from '$lib/components/SchemaForm.svelte';
import OutputPanel from '$lib/components/OutputPanel.svelte'; import OutputPanel from '$lib/components/OutputPanel.svelte';
import ImportModal from '$lib/components/ImportModal.svelte'; import ImportModal from '$lib/components/ImportModal.svelte';
@ -130,24 +130,8 @@
</main> </main>
{:else} {:else}
<main class="flex-1 flex items-center justify-center p-6"> <main class="flex-1 flex items-center justify-center p-6">
<div class="max-w-md w-full flex flex-col gap-6" style="color: var(--text-muted);"> <div class="max-w-md w-full flex flex-col gap-6">
<div class="text-sm flex flex-col gap-4"> <HelpText />
<p>
Pick a template and fill in the form. Each section covers a different record. Blank fields are omitted from the output automatically, so no rush to finish everything.
</p>
<p>
Characters save to your browser. You can also export to a file or generate a share link: the link itself encodes the full set of records, so functionally it's a save file.
</p>
<p>
Share links let the recipient see a preview of your records, with the option to import the character into their own roster.
</p>
<p>
This tool is entirely data-driven in XML, and it's already set up for template sharing. A visual template editor is coming soon, so anybody can create their own templates and share them between one another.
</p>
<p>
Cheers.
</p>
</div>
<div class="flex gap-3"> <div class="flex gap-3">
<button <button