| <script lang="ts"> | |
| import { randomSeed } from '../../lib/stores/app-state'; | |
| /** | |
| * The seed lives in the store, not in a binding: `wizard` is a plain object | |
| * read out of a Svelte store, so mutating a nested field on it would not be | |
| * observed. The parent commits the value through setSeed(). | |
| */ | |
| let { | |
| seed, | |
| onSeed, | |
| label = 'Secret seed', | |
| hint = '', | |
| }: { | |
| seed: number | null; | |
| onSeed: (value: number | null) => void; | |
| label?: string; | |
| hint?: string; | |
| } = $props(); | |
| let input: HTMLInputElement | undefined = $state(); | |
| const awaiting = $derived(seed === null); | |
| $effect(() => { | |
| // Put the caret in the box so the pulsing border reads as "type here". | |
| if (awaiting && input) input.focus(); | |
| }); | |
| function onInput(e: Event) { | |
| const v = (e.target as HTMLInputElement).value.trim(); | |
| onSeed(v === '' ? null : Math.abs(Math.trunc(Number(v))) || 0); | |
| } | |
| </script> | |
| <div class="seed"> | |
| <label for="seed-input">{label}</label> | |
| <input | |
| id="seed-input" | |
| bind:this={input} | |
| class="mono" | |
| class:awaiting-input={awaiting} | |
| type="number" | |
| min="0" | |
| inputmode="numeric" | |
| placeholder="type a number…" | |
| value={seed ?? ''} | |
| oninput={onInput} | |
| /> | |
| <button title="random seed" onclick={() => onSeed(randomSeed())}>⚄ random</button> | |
| {#if awaiting} | |
| <span class="dim small">Enter a seed to derive the secret key.</span> | |
| {:else if hint} | |
| <span class="dim small mono">{hint}</span> | |
| {/if} | |
| </div> | |
| <style> | |
| .seed { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| flex-wrap: wrap; | |
| } | |
| label { | |
| font-weight: 550; | |
| } | |
| input { | |
| width: 150px; | |
| } | |
| </style> | |