zenno: make character selects searchable

Fixes #20.
This commit is contained in:
2026-06-16 13:37:59 -04:00
parent f8e7bfbec6
commit ad58edbfe1
4 changed files with 212 additions and 42 deletions
+24 -27
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import CharaPick from '$lib/CharaPick.svelte';
import { AFFINITY_RELATION_DESCRIPTIONS, affinityDetail, type AffinityDetail } from '$lib/data/affinity';
import { character, charaNames, type Character } from '$lib/data/character';
import { character, type Character } from '$lib/data/character';
import { onMount } from 'svelte';
import { SvelteSet } from 'svelte/reactivity';
@@ -12,21 +12,21 @@
affs = affinities;
characters = charas.filter((c) => affs.some((d) => d.chara_id === c.chara_id));
});
const names = $derived(charaNames(characters));
let charA: number = $state(1001);
let charB: number = $state(0);
let charC: number = $state(0);
const nameA = $derived(names.get(charA)?.en ?? `Character ${charA}`);
const nameB = $derived(names.get(charB)?.en ?? `Character ${charB}`);
const nameC = $derived(names.get(charC)?.en ?? `Character ${charC}`);
let charA: Character | undefined = $state();
let charB: Character | undefined = $state();
let charC: Character | undefined = $state();
const charaListA = $derived(characters.filter((c) => c.chara_id != charB?.chara_id && c.chara_id != charC?.chara_id));
const charaListB = $derived(characters.filter((c) => c.chara_id != charA?.chara_id && c.chara_id != charC?.chara_id));
const charaListC = $derived(characters.filter((c) => c.chara_id != charA?.chara_id && c.chara_id != charB?.chara_id));
function groupsFor(affs: AffinityDetail[], chara: number): AffinityDetail[] {
return chara !== 0 ? affs.filter((d) => d.chara_id === chara) : [];
}
const groupsA = $derived(groupsFor(affs, charA));
const groupsB = $derived(groupsFor(affs, charB));
const groupsC = $derived(groupsFor(affs, charC));
const groupsA = $derived(groupsFor(affs, charA?.chara_id ?? 0));
const groupsB = $derived(groupsFor(affs, charB?.chara_id ?? 0));
const groupsC = $derived(groupsFor(affs, charC?.chara_id ?? 0));
const allGroups = $derived.by(() => {
const seen = new SvelteSet<number>();
const r = [];
@@ -41,8 +41,7 @@
}
return r;
});
const selCount = $derived(1 + (charB === 0 ? 0 : 1) + (charC === 0 ? 0 : 1));
const duplicate = $derived(charA === charB || charA === charC || (charB !== 0 && charB === charC));
const selCount = $derived(1 + (charB == null ? 0 : 1) + (charC == null ? 0 : 1));
const infos = $derived(
allGroups
.map((d) => ({
@@ -65,21 +64,19 @@
<div class="mx-auto mt-8 flex flex-col rounded-md text-center shadow-md ring md:max-w-2xl md:flex-row">
<div class="m-4 flex-1 md:mt-3">
<label for="charA" class="hidden md:inline">Character 1</label>
<CharaPick id="charA" {characters} class="w-full" bind:value={charA} required />
<CharaPick id="charA" characters={charaListA} class="w-full" bind:value={charA} required />
</div>
<div class="m-4 flex-1 md:mt-3">
<label for="charB" class="hidden md:inline">Character 2</label>
<CharaPick id="charB" {characters} class="w-full" bind:value={charB} />
<CharaPick id="charB" characters={charaListB} class="w-full" bind:value={charB} />
</div>
<div class="m-4 flex-1 md:mt-3">
<label for="charC" class="hidden md:inline">Character 3</label>
<CharaPick id="charC" {characters} class="w-full" bind:value={charC} />
<CharaPick id="charC" characters={charaListC} class="w-full" bind:value={charC} />
</div>
</div>
<svelte:boundary>
{#if duplicate}
<span class="mt-8 block w-full text-center text-lg">Duplicate characters always have zero affinity.</span>
{:else if selCount > 1}
{#if selCount > 1}
<span class="mt-8 block w-full text-center text-lg">Total {selCount === 2 ? 'pair' : 'trio'} affinity: {total}</span>
{/if}
<table class="mx-auto mt-8 table-fixed">
@@ -88,12 +85,12 @@
<th class="w-32 px-2" scope="col">Group ID</th>
<th class="w-96 px-2" scope="col">Description</th>
{#if selCount > 1}
<th class="w-56 px-2" scope="col">{nameA}</th>
{#if charB !== 0}
<th class="w-56 px-2" scope="col">{nameB}</th>
<th class="w-56 px-2" scope="col">{charA!.name}</th>
{#if charB != null}
<th class="w-56 px-2" scope="col">{charB.name}</th>
{/if}
{#if charC !== 0}
<th class="w-56 px-2" scope="col">{nameC}</th>
{#if charC != null}
<th class="w-56 px-2" scope="col">{charC.name}</th>
{/if}
{/if}
<th class="w-32 px-2" scope="col">Affinity</th>
@@ -110,14 +107,14 @@
{/if}
{#if selCount > 1}
<td class="px-4 text-center">{a ? '✓' : ''}</td>
{#if charB !== 0}
{#if charB != null}
<td class="px-4 text-center">{b ? '✓' : ''}</td>
{/if}
{#if charC !== 0}
{#if charC != null}
<td class="px-4 text-center">{c ? '✓' : ''}</td>
{/if}
{/if}
<td class="px-4 text-center">{!duplicate && selCount > 1 && counted === selCount ? '+' : ''}{affinity}</td>
<td class="px-4 text-center">{selCount > 1 && counted === selCount ? '+' : ''}{affinity}</td>
</tr>
{/each}
</tbody>
+3 -3
View File
@@ -17,10 +17,10 @@
characters = charas.filter((c) => convoMap.has(c.chara_id));
});
let charaID = $state(1001);
let chara: Character | undefined = $state();
let convo = $state(1);
const options = $derived(convoMap.get(charaID) ?? []);
const options = $derived(convoMap.get(chara?.chara_id ?? 0) ?? []);
const cur = $derived(options.find((c) => c.number === convo));
const cur1Name = $derived(cur?.chara_1 && names.get(cur.chara_1)?.en);
const cur2Name = $derived(cur?.chara_2 && names.get(cur.chara_2)?.en);
@@ -43,7 +43,7 @@
<div class="mx-auto mt-8 flex flex-col rounded-md text-center shadow-md ring md:max-w-xl md:flex-row">
<div class="m-4 flex-1 md:mt-3">
<label for="chara" class="hidden md:inline">Character</label>
<CharaPick id="chara" {characters} class="w-full" bind:value={charaID} required />
<CharaPick id="chara" {characters} class="w-full" bind:value={chara} required />
</div>
<div class="m-4 flex-1 md:mt-3">
<label for="convo" class="hidden md:inline">Conversation</label>