style: run eslint and prettier
Some checks failed
TrafficCue CI / check (push) Failing after 39s
TrafficCue CI / build (push) Failing after 38s

This commit is contained in:
2025-08-30 13:13:31 +02:00
parent b5804bc9e0
commit 8af4a623b3
10 changed files with 121 additions and 80 deletions

View File

@ -7,7 +7,13 @@
import { Button } from "$lib/components/ui/button/index.js";
import { cn } from "$lib/utils.js";
import { m } from "$lang/messages";
import { BriefcaseIcon, HomeIcon, LocateIcon, MapPinIcon, SchoolIcon } from "@lucide/svelte";
import {
BriefcaseIcon,
HomeIcon,
LocateIcon,
MapPinIcon,
SchoolIcon,
} from "@lucide/svelte";
import { geocode } from "$lib/saved.svelte";
import { reverseGeocode, search, type Feature } from "$lib/services/Search";
@ -15,26 +21,26 @@
{
value: "current",
label: m["location-selector.current"](),
icon: LocateIcon
icon: LocateIcon,
},
{
value: "home",
label: m["saved.home"](),
subtext: geocode("home"),
icon: HomeIcon
icon: HomeIcon,
},
{
value: "school",
label: m["saved.school"](),
subtext: geocode("school"),
icon: SchoolIcon
icon: SchoolIcon,
},
{
value: "work",
label: m["saved.work"](),
subtext: geocode("work"),
icon: BriefcaseIcon
}
icon: BriefcaseIcon,
},
];
let open = $state(false);
@ -47,14 +53,22 @@
async function getCoordLabel(value: `${number},${number}`) {
const splitter = value.split(",");
const res = await reverseGeocode({ lat: parseFloat(splitter[0]), lon: parseFloat(splitter[1]) })
if(res.length == 0) return "<unknown>";
const res = await reverseGeocode({
lat: parseFloat(splitter[0]),
lon: parseFloat(splitter[1]),
});
if (res.length == 0) return "<unknown>";
const feature = res[0];
return feature.properties.name;
}
const selectedValue = $derived(
new Promise(async r => { r(locations.find((f) => f.value === value)?.label || await getCoordLabel(value)) })
new Promise((r) => {
r(
locations.find((f) => f.value === value)?.label ||
getCoordLabel(value).then((v) => r(v)),
);
}),
);
// We want to refocus the trigger button when the user selects
@ -126,7 +140,7 @@
</Command.Empty>
<Command.Group>
{#if searchbarText == ""}
{#each locations as location}
{#each locations as location, _index (location.value)}
<Command.Item
value={location.value}
onSelect={() => {
@ -135,17 +149,15 @@
}}
style="flex-direction: column; align-items: start;"
>
<div style="display: flex; align-items: center; gap: 5px; width: 100%;">
<location.icon
class={cn(
"mr-2 size-4"
)}
/>
<div
style="display: flex; align-items: center; gap: 5px; width: 100%;"
>
<location.icon class={cn("mr-2 size-4")} />
{location.label}
<CheckIcon
class={cn(
"mr-2 size-4 ml-auto",
value !== location.value && "text-transparent"
value !== location.value && "text-transparent",
)}
/>
</div>
@ -158,8 +170,11 @@
{/each}
{/if}
{#each searchResults as result}
{@const resultValue = result.geometry.coordinates[1] + "," + result.geometry.coordinates[0]}
{#each searchResults as result, _index (result.properties.osm_id)}
{@const resultValue =
result.geometry.coordinates[1] +
"," +
result.geometry.coordinates[0]}
<Command.Item
value={resultValue}
onSelect={() => {
@ -168,21 +183,23 @@
}}
style="flex-direction: column; align-items: start;"
>
<div style="display: flex; align-items: center; gap: 5px; width: 100%;">
<MapPinIcon
class={cn(
"mr-2 size-4"
)}
/>
<div
style="display: flex; align-items: center; gap: 5px; width: 100%;"
>
<MapPinIcon class={cn("mr-2 size-4")} />
{result.properties.name}
<CheckIcon
class={cn(
"mr-2 size-4 ml-auto",
value !== resultValue && "text-transparent"
value !== resultValue && "text-transparent",
)}
/>
</div>
<span>{result.properties.street}{result.properties.housenumber ? " " + result.properties.housenumber : ""}, {result.properties.city}</span>
<span
>{result.properties.street}{result.properties.housenumber
? " " + result.properties.housenumber
: ""}, {result.properties.city}</span
>
</Command.Item>
{/each}
</Command.Group>

View File

@ -48,7 +48,10 @@
let CurrentView: Component = $state(LoadingSidebar);
const modules = import.meta.glob("./sidebar/**/*.svelte");
$effect(() => {
const path = modules[`./sidebar/${views[view.current.type] || "InvalidSidebar"}.svelte`];
const path =
modules[
`./sidebar/${views[view.current.type] || "InvalidSidebar"}.svelte`
];
if (!path) {
// Invalid view
import("./sidebar/InvalidSidebar.svelte").then((m) => {

View File

@ -1 +1 @@
Loading...
Loading...

View File

@ -102,13 +102,18 @@
{#await getSaved() then saved}
{#if saved.length != 0}
<div>
<h2 style="margin: 5px; margin-left: 0; font-size: 1.2em;">Saved Routes</h2>
<h2 style="margin: 5px; margin-left: 0; font-size: 1.2em;">
Saved Routes
</h2>
<div style="display: flex; flex-direction: column; gap: 10px;">
{#each saved as save}
<Button variant="secondary" onclick={() => {
view.switch("trip", { route: JSON.parse(save.data) })
}}>{save.name}</Button>
{#each saved as save, _index (save.name)}
<Button
variant="secondary"
onclick={() => {
view.switch("trip", { route: JSON.parse(save.data) });
}}>{save.name}</Button
>
{/each}
</div>
</div>

View File

@ -1,6 +1,5 @@
<script lang="ts">
import { CircleArrowDown, CircleDotIcon, StarIcon } from "@lucide/svelte";
import Input from "$lib/components/ui/input/input.svelte";
import SidebarHeader from "./SidebarHeader.svelte";
import { Button } from "$lib/components/ui/button";
import { createValhallaRequest } from "$lib/vehicles/ValhallaVehicles";

View File

@ -48,16 +48,19 @@
</Button>
<RequiresCapability capability="saved-routes">
{#await isSaved($state.snapshot(route)) then saved}
<Button variant="secondary" onclick={async () => {
if(saved) {
await deleteSaved(saved);
view.back();
} else {
const name = prompt("Trip name?");
if(!name) return;
await putSaved(name, route);
}
}}>
<Button
variant="secondary"
onclick={async () => {
if (saved) {
await deleteSaved(saved);
view.back();
} else {
const name = prompt("Trip name?");
if (!name) return;
await putSaved(name, route);
}
}}
>
<SaveIcon />
{saved ? m.unsave() : m["sidebar.trip.save"]()}
</Button>

View File

@ -70,9 +70,11 @@
</Avatar.Root>
{user.name || user.preferred_username}
</SidebarHeader>
<button onclick={() => {
refreshToken();
}}>refresh</button>
<button
onclick={() => {
refreshToken();
}}>refresh</button
>
<pre>{user.sub}</pre>
{JSON.stringify(user, null, 2)}
{/if}

View File

@ -10,11 +10,11 @@ export function saveLocations() {
export async function geocode(name: string) {
const loc = saved[name];
if(!loc) return;
if (!loc) return;
const geocode = await reverseGeocode(loc);
if(geocode.length == 0) {
if (geocode.length == 0) {
return;
}
const feature = geocode[0];
return `${feature.properties.street}${feature.properties.housenumber ? (" " + feature.properties.housenumber) : ""}, ${feature.properties.city}`;
return `${feature.properties.street}${feature.properties.housenumber ? " " + feature.properties.housenumber : ""}, ${feature.properties.city}`;
}

View File

@ -1,7 +1,14 @@
import { LNV_SERVER } from "./hosts";
import type { OIDCUser } from "./oidc";
export type Capabilities = ("auth" | "reviews" | "ai" | "fuel" | "post" | "saved-routes")[];
export type Capabilities = (
| "auth"
| "reviews"
| "ai"
| "fuel"
| "post"
| "saved-routes"
)[];
export let capabilities: Capabilities = [];
export let oidcConfig: {
AUTH_URL: string;
@ -57,22 +64,22 @@ export async function uploadID() {
const res = await fetch(LNV_SERVER + "/user", {
method: "POST",
headers: {
"Content-Type": "application/json"
"Content-Type": "application/json",
},
body: JSON.stringify({
token: localStorage.getItem("lnv-id")
})
token: localStorage.getItem("lnv-id"),
}),
});
if(!res.ok) {
if (!res.ok) {
alert("Failed to upload user data.");
}
}
export async function refreshToken() {
const config = await getOIDCConfig();
if(!config) throw new Error("Server does not support OIDC.");
if (!config) throw new Error("Server does not support OIDC.");
const refresh_token = localStorage.getItem("lnv-refresh");
if(!refresh_token) throw new Error("No refresh token.")
if (!refresh_token) throw new Error("No refresh token.");
const params = new URLSearchParams();
params.append("grant_type", "refresh_token");
params.append("refresh_token", refresh_token);
@ -80,13 +87,13 @@ export async function refreshToken() {
const res = await fetch(config.TOKEN_URL, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
"Content-Type": "application/x-www-form-urlencoded",
},
body: params
body: params,
});
const data = (await res.json()) as OIDCUser;
if(!res.ok) {
console.error("Refreshing token: " + res.status + " " + res.statusText)
if (!res.ok) {
console.error("Refreshing token: " + res.status + " " + res.statusText);
console.error(data);
}
console.log(data);
@ -96,24 +103,27 @@ export async function refreshToken() {
await uploadID();
}
export async function authFetch(url: string, params?: RequestInit): ReturnType<typeof fetch> {
export async function authFetch(
url: string,
params?: RequestInit,
): ReturnType<typeof fetch> {
let res = await fetch(url, {
headers: {
"Authorization": "Bearer " + localStorage.getItem("lnv-token")
Authorization: "Bearer " + localStorage.getItem("lnv-token"),
},
...params
...params,
});
if(res.status != 401) {
if (res.status != 401) {
return res;
}
await refreshToken();
res = await fetch(url, {
headers: {
"Authorization": "Bearer " + localStorage.getItem("lnv-token")
Authorization: "Bearer " + localStorage.getItem("lnv-token"),
},
...params
...params,
});
if(res.status == 401) {
if (res.status == 401) {
console.error("Server is misconfigured.");
}
return res;
@ -188,8 +198,8 @@ export async function ai(query: string, location?: WorldLocation) {
return await res.text();
}
export function getSaved(): Promise<{ name: string; data: string; }[]> {
return authFetch(LNV_SERVER + "/saved").then(res => res.json());
export function getSaved(): Promise<{ name: string; data: string }[]> {
return authFetch(LNV_SERVER + "/saved").then((res) => res.json());
}
export function putSaved(name: string, data: object) {
@ -197,24 +207,26 @@ export function putSaved(name: string, data: object) {
method: "PUT",
body: JSON.stringify({
name,
data: JSON.stringify(data)
})
}).then(res => res.json());
data: JSON.stringify(data),
}),
}).then((res) => res.json());
}
export function deleteSaved(name: string) {
return authFetch(LNV_SERVER + "/saved", {
method: "DELETE",
body: JSON.stringify({
name
})
}).then(res => res.text());
name,
}),
}).then((res) => res.text());
}
export async function isSaved(data: Trip) {
const res = await getSaved();
console.log(res, data);
const filtered = res.filter(s => JSON.parse(s.data).legs[0].shape == data.legs[0].shape);
if(filtered.length == 0) return false;
const filtered = res.filter(
(s) => JSON.parse(s.data).legs[0].shape == data.legs[0].shape,
);
if (filtered.length == 0) return false;
return filtered[0].name;
}

View File

@ -60,7 +60,7 @@ async function sha256(input: string | undefined): Promise<ArrayBuffer> {
return await window.crypto.subtle.digest("SHA-256", data);
}
export type OIDCUser = {
export interface OIDCUser {
access_token: string;
token_type: string;
refresh_token: string;