Refactor location object into separate module so that it can be used in multiple locations

This commit is contained in:
2026-03-17 19:28:02 +00:00
parent a327582629
commit 3240560a0b
3 changed files with 43 additions and 26 deletions

View File

@@ -4,44 +4,29 @@
import { fade } from 'svelte/transition';
import { goto } from '$app/navigation';
interface LocationRecord {
n: string; // name
t: string; // tiploc
c?: string; // crs
s: string; // search string
}
import { LOCATIONS } from '$lib/locations-object.svelte.ts';
let { value = $bindable() } = $props();
let results = $state<LocationRecord[]>([]);
let locations: LocationRecord[] = [];
let showResults = $state(false);
let selectedIndex = $state(-1);
const MAX_RESULTS = 5;
async function loadLocations() {
const res = await fetch('/api/tiplocs');
locations = await res.json();
}
onMount(loadLocations);
function tokenize(query: string) {
return query.toLowerCase().trim().split(/\s+/).filter(Boolean);
}
function search(query: string) {
if (query.length < 3) {
results = [];
return;
}
let results = $derived.by(() => {
if (value.length < 3) return [];
const tokens = tokenize(query);
const lowerQuery = query.toLowerCase().trim();
const tokens = tokenize(value);
const lowerQuery = value.toLowerCase().trim();
results = locations
return LOCATIONS.data
.filter((r) => tokens.every((t) => r.s.includes(t)))
.sort((a, b) => {
// Check if query matches CRS
@@ -56,11 +41,12 @@
return a.n.localeCompare(b.n);
})
.slice(0, MAX_RESULTS);
}
})
$effect(() => {
search(value);
});
if (results) selectedIndex = -1;
});
// Hide results when click outside of container
$effect(() => {

View File

@@ -0,0 +1,26 @@
interface LocationRecord {
n: string; // name
t: string; // tiploc
c?: string; // crs
s: string; // search string
}
class LocationStore {
data = $state<LocationRecord[]>([]);
loaded = $state(false);
async init() {
if (this.loaded) return;
try {
const res = await fetch('/api/tiplocs');
this.data = await res.json();
this.loaded = true;
} catch (err) {
console.error('Failed to load locations', err);
}
}
}
export const LOCATIONS = new LocationStore();

View File

@@ -1,6 +1,9 @@
<script lang="ts">
import { page } from '$app/state';
import { slide, fade } from 'svelte/transition';
import { onMount } from 'svelte';
import { LOCATIONS } from '$lib/locations-object.svelte.ts';
import '$lib/global.css';
@@ -10,6 +13,8 @@
import { IconHome, IconDialpad, IconSettings, IconHelp, IconDots } from '@tabler/icons-svelte';
onMount(() => LOCATIONS.init());
let { children } = $props();
// Navigation State