feat: init school select component

This commit is contained in:
EETagent 2023-01-26 22:20:13 +01:00
parent 8fbefbf9ce
commit 60323b9be5
4 changed files with 177 additions and 36 deletions

View file

@ -1,36 +0,0 @@
<script lang="ts">
import LL from '$i18n/i18n-svelte';
import type { School } from '$lib/stores/candidate';
// TODO
// import AutoComplete from 'simple-svelte-autocomplete';
import { onMount } from 'svelte';
// import schoollistString from '$lib/assets/schoollist.txt';
let schools: string[] = [];
onMount(async () => {
schools = await fetch('/schoollist.txt')
.then((response) => response.text())
.then((text) => text.split(';'));
});
export let selectedSchool: School;
export let schoolName: string = selectedSchool.name;
$: selectedSchool.name = schoolName;
</script>
<div class="flex flex-row">
<div>
<span>
{$LL.input.selectedSchool()}: {selectedSchool.name}
</span>
<!-- TODO -->
<!-- <AutoComplete items={schools} bind:selectedItem={schoolName} /> -->
<input type="text" bind:value={schoolName} />
</div>
<div class="flex">
<span>{$LL.input.fieldOfStudy()}: </span>
<input type="text" bind:value={selectedSchool.field} />
</div>
</div>

View file

@ -0,0 +1,41 @@
<script lang="ts">
export let itemLabel: string;
export let highlighted: boolean;
</script>
<li class="autocomplete-items" class:autocomplete-active={highlighted} on:click on:keydown={null}>
{@html itemLabel}
</li>
<style>
li.autocomplete-items {
list-style: none;
border-bottom: 1px solid #d4d4d4;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
padding: 10px;
cursor: pointer;
background-color: #fff;
}
li.autocomplete-items:hover {
/*when hovering an item:*/
background-color: #81921f;
color: white;
}
li.autocomplete-items:active {
/*when navigating through the items using the arrow keys:*/
background-color: DodgerBlue !important;
color: #ffffff;
}
.autocomplete-active {
/*when navigating through the items using the arrow keys:*/
background-color: DodgerBlue !important;
color: #ffffff;
}
</style>

View file

@ -0,0 +1,136 @@
<script lang="ts">
import schoollistString from '$lib/assets/schoollist.txt?raw';
import School from './School.svelte';
import type { School as SchoolType } from '$lib/stores/candidate';
const schoolList: Array<string> = schoollistString.split(';');
let filteredSchools: Array<string> = [];
const filterSchools = () => {
let storageArr: Array<string> = [];
if (schoolNameInputValue) {
schoolList.forEach((school) => {
if (school.toLowerCase().startsWith(schoolNameInputValue.toLowerCase())) {
storageArr = [...storageArr, makeMatchBold(school)];
}
});
}
filteredSchools = storageArr;
};
let searchInput: HTMLInputElement;
let optionsList: HTMLUListElement;
let schoolNameInputValue = '';
let schoolFieldInputValue = '';
$: if (!schoolNameInputValue) {
filteredSchools = [];
hiLiteIndex = -1;
}
const setInputVal = (schoolName: string) => {
schoolNameInputValue = removeBold(schoolName);
filteredSchools = [];
hiLiteIndex = -1;
searchInput.focus();
};
const makeMatchBold = (str: string) => {
let matched = str.substring(0, schoolNameInputValue.length);
let makeBold = `<strong>${matched}</strong>`;
let boldedMatch = str.replace(matched, makeBold);
return boldedMatch;
};
const removeBold = (str: string) => {
return str.replace(/<(.)*?>/g, '');
};
let hiLiteIndex: number = 0;
const navigateList = (e: KeyboardEvent) => {
if (e.key === 'ArrowDown') {
if (hiLiteIndex < filteredSchools.length - 1) {
hiLiteIndex++;
// scroll optionsList
let option = optionsList.children[hiLiteIndex];
if (option) {
option.scrollIntoView({ block: 'nearest' });
}
}
} else if (e.key === 'ArrowUp') {
if (hiLiteIndex > 0) {
hiLiteIndex--;
}
} else if (e.key === 'Enter') {
if (hiLiteIndex > -1) {
setInputVal(filteredSchools[hiLiteIndex]);
}
}
};
export let selectedSchool: SchoolType;
$: selectedSchool.name = schoolNameInputValue;
$: selectedSchool.field = schoolFieldInputValue;
</script>
<svelte:window on:keydown={navigateList} />
<div class="autocomplete">
<div class="flex">
<input
class="flex-1"
type="text"
bind:this={searchInput}
bind:value={schoolNameInputValue}
on:input={filterSchools}
/>
<input class="ml-2 w-2/5" type="text" bind:value={schoolFieldInputValue} />
</div>
{#if filteredSchools.length > 0}
<ul bind:this={optionsList} class="schoolAutocompleteList">
{#each filteredSchools as country, i}
<School
itemLabel={country}
highlighted={i === hiLiteIndex}
on:click={() => setInputVal(country)}
/>
{/each}
</ul>
{/if}
</div>
<style lang="postcss">
div,
input {
@apply w-full;
}
div {
@apply relative flex items-center justify-center;
}
input {
@apply hover:border-sspsBlue w-full rounded-lg border border-2 bg-[#f8fafb] p-3 text-xl shadow-lg outline-none transition-colors duration-300;
}
div span {
@apply absolute right-0 top-0 bottom-0 my-auto flex bg-transparent p-3;
}
.withIcon {
@apply pr-14;
}
.error {
@apply border-red-700;
}
.autocomplete {
@apply relative;
}
.schoolAutocompleteList {
@apply absolute top-20 z-50;
@apply w-full;
@apply max-h-72 overflow-scroll;
}
</style>