This commit is contained in:
Philipp Dormann 2025-05-20 01:18:56 +02:00
parent 286bd61497
commit 1386b80d0c
Signed by: philipp
GPG Key ID: 3BB9ADD52DCA4314
2 changed files with 36 additions and 150 deletions

View File

@ -7,113 +7,8 @@
} from "@odit/lfk-client-js";
import Select from "svelte-select";
import toast from "svelte-french-toast";
import { onMount } from "svelte";
import VirtualSelect from "./VirtualSelect.svelte";
//
let options = [
{ label: "Bulbasaur", value: { id: 456 } },
{ label: "Ivysaur", value: { id: 456 } },
{ label: "Venusaur", value: { id: 456 } },
{ label: "Charmander", value: { id: 456 } },
{ label: "Charmeleon", value: { id: 456 } },
{ label: "Charizard", value: { id: 456 } },
{ label: "Squirtle", value: { id: 456 } },
{ label: "Wartortle", value: { id: 456 } },
{ label: "Blastoise", value: { id: 456 } },
{ label: "Caterpie", value: { id: 456 } },
{ label: "Metapod", value: { id: 456 } },
{ label: "Butterfree", value: { id: 456 } },
{ label: "Weedle", value: { id: 456 } },
{ label: "Kakuna", value: { id: 456 } },
{ label: "Beedrill", value: { id: 456 } },
{ label: "Pidgey", value: { id: 456 } },
{ label: "Pidgeotto", value: { id: 456 } },
{ label: "Pidgeot", value: { id: 456 } },
{ label: "Rattata", value: { id: 456 } },
{ label: "Raticate", value: { id: 456 } },
{ label: "Spearow", value: { id: 456 } },
{ label: "Fearow", value: { id: 456 } },
{ label: "Ekans", value: { id: 456 } },
{ label: "Arbok", value: { id: 456 } },
{ label: "Pikachu", value: { id: 456 } },
{ label: "Raichu", value: { id: 456 } },
{ label: "Sandshrew", value: { id: 456 } },
{ label: "Sandslash", value: { id: 456 } },
{ label: "Nidoran♀", value: { id: 456 } },
{ label: "Nidorina", value: { id: 456 } },
{ label: "Nidoqueen", value: { id: 456 } },
{ label: "Nidoran♂", value: { id: 456 } },
{ label: "Nidorino", value: { id: 456 } },
{ label: "Nidoking", value: { id: 456 } },
{ label: "Clefairy", value: { id: 456 } },
{ label: "Clefable", value: { id: 456 } },
{ label: "Vulpix", value: { id: 456 } },
{ label: "Ninetales", value: { id: 456 } },
{ label: "Jigglypuff", value: { id: 456 } },
{ label: "Wigglytuff", value: { id: 456 } },
{ label: "Zubat", value: { id: 456 } },
{ label: "Golbat", value: { id: 456 } },
{ label: "Oddish", value: { id: 456 } },
{ label: "Gloom", value: { id: 456 } },
{ label: "Vileplume", value: { id: 456 } },
{ label: "Paras", value: { id: 456 } },
{ label: "Parasect", value: { id: 456 } },
{ label: "Venonat", value: { id: 456 } },
{ label: "Venomoth", value: { id: 456 } },
{ label: "Diglett", value: { id: 456 } },
{ label: "Dugtrio", value: { id: 456 } },
{ label: "Meowth", value: { id: 456 } },
{ label: "Persian", value: { id: 456 } },
{ label: "Psyduck", value: { id: 456 } },
{ label: "Golduck", value: { id: 456 } },
{ label: "Mankey", value: { id: 456 } },
{ label: "Primeape", value: { id: 456 } },
{ label: "Growlithe", value: { id: 456 } },
{ label: "Arcanine", value: { id: 456 } },
{ label: "Poliwag", value: { id: 456 } },
{ label: "Poliwhirl", value: { id: 456 } },
{ label: "Poliwrath", value: { id: 456 } },
{ label: "Abra", value: { id: 456 } },
{ label: "Kadabra", value: { id: 456 } },
{ label: "Alakazam", value: { id: 456 } },
{ label: "Machop", value: { id: 456 } },
{ label: "Machoke", value: { id: 456 } },
{ label: "Machamp", value: { id: 456 } },
{ label: "Bellsprout", value: { id: 456 } },
{ label: "Weepinbell", value: { id: 456 } },
{ label: "Victreebel", value: { id: 456 } },
{ label: "Tentacool", value: { id: 456 } },
{ label: "Tentacruel", value: { id: 456 } },
{ label: "Geodude", value: { id: 456 } },
{ label: "Graveler", value: { id: 456 } },
{ label: "Golem", value: { id: 456 } },
{ label: "Ponyta", value: { id: 456 } },
{ label: "Rapidash", value: { id: 456 } },
{ label: "Slowpoke", value: { id: 456 } },
{ label: "Slowbro", value: { id: 456 } },
{ label: "Magnemite", value: { id: 456 } },
{ label: "Magneton", value: { id: 456 } },
{ label: "Farfetch'd", value: { id: 456 } },
{ label: "Doduo", value: { id: 456 } },
{ label: "Dodrio", value: { id: 456 } },
{ label: "Seel", value: { id: 456 } },
{ label: "Dewgong", value: { id: 456 } },
{ label: "Grimer", value: { id: 456 } },
{ label: "Muk", value: { id: 456 } },
{ label: "Shellder", value: { id: 456 } },
{ label: "Cloyster", value: { id: 456 } },
{ label: "Gastly", value: { id: 456 } },
{ label: "Haunter", value: { id: 456 } },
];
let selectedOption;
function handleSelect(event) {
selectedOption = event.detail;
console.log("Selected:", selectedOption);
}
//
let runners = [];
let donors = [];
let runnerinfo = { id: 0, firstname: "", lastname: "" };
@ -157,15 +52,16 @@
}
loadDonors();
const getRunnerLabel = (option) =>
option.firstname +
" " +
(option.middlename || "") +
" " +
option.lastname +
" [#" +
option.id +
"]";
const getRunnerLabel = (option) => {
return (
[option.firstname, option.middlename, option.lastname]
.join(" ")
.replace(" ", " ") +
" [#" +
option.id +
"]"
);
};
const filterRunners = (label, filterText, option) => {
if (filterText.startsWith("#")) {
@ -188,10 +84,6 @@
c.click();
});
}
onMount(() => {
document.querySelector("#wrapper_runner_select input").focus();
});
</script>
<div class="p-4">
@ -211,40 +103,27 @@
{/if}
<!-- -->
<h4 class="text-xl font-semibold">{$_("runner")}</h4>
<VirtualSelect
{options}
filterFn={(option, searchTerm) => {
// Example: Match if option starts with search term (case-insensitive)
return option.label.toLowerCase().startsWith(searchTerm.toLowerCase());
autofocus={true}
on:onClear={() => {
console.log("Cleared selection");
}}
bind:selected={selectedOption}
options={runners}
filterFn={(option, searchTerm) => {
return option.label.toLowerCase().includes(searchTerm.toLowerCase());
}}
bind:selected={runnerinfo}
inputAriaLabel={$_("search-for-runner-by-name-or-id")}
inputPlaceholder={$_("search-for-runner-by-name-or-id")}
noOptionsText={$_("no-runners-found")}
on:select={handleSelect}
noOptionsText={$_("no-runners-found")}
on:onSelected={() => {
document.querySelector("#donation_amount_eur").focus();
}}
/>
{#if selectedOption}
<p class="mt-4 text-lg">Selected: {JSON.stringify(selectedOption)}</p>
{/if}
<!-- -->
<!-- Runner Selection -->
<div id="wrapper_runner_select">
<h4 class="text-xl font-semibold">{$_("runner")}</h4>
<Select
containerClasses="rounded-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterRunners(label, filterText, option)}
items={runners}
showChevron={true}
placeholder={$_("search-for-runner-by-name-or-id")}
noOptionsMessage={$_("no-runners-found")}
on:select={(selectedValue) => {
runnerinfo = selectedValue.detail.value;
document.querySelector("#donation_amount_eur").focus();
}}
on:clear={() => (runnerinfo = { id: 0, firstname: "", lastname: "" })}
/>
</div>
<!-- {#if runnerinfo}
<p class="mt-4 text-lg">Selected: {JSON.stringify(runnerinfo)}</p>
{/if} -->
<!-- Amount Input -->
<div>

View File

@ -10,6 +10,7 @@
export let toggleAriaLabel = "Toggle dropdown";
export let clearAriaLabel = "Clear selection";
export let filterFn = null; // Custom filter function
export let autofocus = false; // Autofocus input
// Internal state
let searchTerm = "";
@ -21,6 +22,7 @@
let itemHeight = 40; // Fixed height for each option (in pixels)
let visibleCount = 10; // Default number of items to render
let focusedIndex = -1; // Track the focused option index (-1 means no focus)
let inputElement; // Reference to input element
const dispatch = createEventDispatcher();
@ -69,7 +71,7 @@
function selectOption(option) {
selected = option.value;
isOpen = false;
searchTerm = "";
searchTerm = option.label;
focusedIndex = -1;
dispatch("onSelected", option.value);
}
@ -80,6 +82,7 @@
searchTerm = "";
focusedIndex = -1;
dispatch("onSelected", null);
dispatch("onClear");
}
// Toggle dropdown
@ -157,11 +160,14 @@
updateVisibleItems();
}
// Initialize container size observer
// Initialize container size observer and autofocus
onMount(() => {
if (container) {
const resizeObserver = new ResizeObserver(updateVisibleCount);
resizeObserver.observe(container);
if (autofocus && inputElement) {
inputElement.focus();
}
return () => resizeObserver.disconnect();
}
});
@ -186,6 +192,7 @@
<input
type="text"
bind:value={searchTerm}
bind:this={inputElement}
placeholder={getDisplayText()}
class="w-full bg-transparent focus:outline-none {selected
? 'text-black'