style: run eslint and prettier
This commit is contained in:
@ -7,7 +7,13 @@
|
|||||||
import { Button } from "$lib/components/ui/button/index.js";
|
import { Button } from "$lib/components/ui/button/index.js";
|
||||||
import { cn } from "$lib/utils.js";
|
import { cn } from "$lib/utils.js";
|
||||||
import { m } from "$lang/messages";
|
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 { geocode } from "$lib/saved.svelte";
|
||||||
import { reverseGeocode, search, type Feature } from "$lib/services/Search";
|
import { reverseGeocode, search, type Feature } from "$lib/services/Search";
|
||||||
|
|
||||||
@ -15,26 +21,26 @@
|
|||||||
{
|
{
|
||||||
value: "current",
|
value: "current",
|
||||||
label: m["location-selector.current"](),
|
label: m["location-selector.current"](),
|
||||||
icon: LocateIcon
|
icon: LocateIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "home",
|
value: "home",
|
||||||
label: m["saved.home"](),
|
label: m["saved.home"](),
|
||||||
subtext: geocode("home"),
|
subtext: geocode("home"),
|
||||||
icon: HomeIcon
|
icon: HomeIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "school",
|
value: "school",
|
||||||
label: m["saved.school"](),
|
label: m["saved.school"](),
|
||||||
subtext: geocode("school"),
|
subtext: geocode("school"),
|
||||||
icon: SchoolIcon
|
icon: SchoolIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "work",
|
value: "work",
|
||||||
label: m["saved.work"](),
|
label: m["saved.work"](),
|
||||||
subtext: geocode("work"),
|
subtext: geocode("work"),
|
||||||
icon: BriefcaseIcon
|
icon: BriefcaseIcon,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let open = $state(false);
|
let open = $state(false);
|
||||||
@ -47,14 +53,22 @@
|
|||||||
|
|
||||||
async function getCoordLabel(value: `${number},${number}`) {
|
async function getCoordLabel(value: `${number},${number}`) {
|
||||||
const splitter = value.split(",");
|
const splitter = value.split(",");
|
||||||
const res = await reverseGeocode({ lat: parseFloat(splitter[0]), lon: parseFloat(splitter[1]) })
|
const res = await reverseGeocode({
|
||||||
if(res.length == 0) return "<unknown>";
|
lat: parseFloat(splitter[0]),
|
||||||
|
lon: parseFloat(splitter[1]),
|
||||||
|
});
|
||||||
|
if (res.length == 0) return "<unknown>";
|
||||||
const feature = res[0];
|
const feature = res[0];
|
||||||
return feature.properties.name;
|
return feature.properties.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedValue = $derived(
|
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
|
// We want to refocus the trigger button when the user selects
|
||||||
@ -126,7 +140,7 @@
|
|||||||
</Command.Empty>
|
</Command.Empty>
|
||||||
<Command.Group>
|
<Command.Group>
|
||||||
{#if searchbarText == ""}
|
{#if searchbarText == ""}
|
||||||
{#each locations as location}
|
{#each locations as location, _index (location.value)}
|
||||||
<Command.Item
|
<Command.Item
|
||||||
value={location.value}
|
value={location.value}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
@ -135,17 +149,15 @@
|
|||||||
}}
|
}}
|
||||||
style="flex-direction: column; align-items: start;"
|
style="flex-direction: column; align-items: start;"
|
||||||
>
|
>
|
||||||
<div style="display: flex; align-items: center; gap: 5px; width: 100%;">
|
<div
|
||||||
<location.icon
|
style="display: flex; align-items: center; gap: 5px; width: 100%;"
|
||||||
class={cn(
|
>
|
||||||
"mr-2 size-4"
|
<location.icon class={cn("mr-2 size-4")} />
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{location.label}
|
{location.label}
|
||||||
<CheckIcon
|
<CheckIcon
|
||||||
class={cn(
|
class={cn(
|
||||||
"mr-2 size-4 ml-auto",
|
"mr-2 size-4 ml-auto",
|
||||||
value !== location.value && "text-transparent"
|
value !== location.value && "text-transparent",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -158,8 +170,11 @@
|
|||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#each searchResults as result}
|
{#each searchResults as result, _index (result.properties.osm_id)}
|
||||||
{@const resultValue = result.geometry.coordinates[1] + "," + result.geometry.coordinates[0]}
|
{@const resultValue =
|
||||||
|
result.geometry.coordinates[1] +
|
||||||
|
"," +
|
||||||
|
result.geometry.coordinates[0]}
|
||||||
<Command.Item
|
<Command.Item
|
||||||
value={resultValue}
|
value={resultValue}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
@ -168,21 +183,23 @@
|
|||||||
}}
|
}}
|
||||||
style="flex-direction: column; align-items: start;"
|
style="flex-direction: column; align-items: start;"
|
||||||
>
|
>
|
||||||
<div style="display: flex; align-items: center; gap: 5px; width: 100%;">
|
<div
|
||||||
<MapPinIcon
|
style="display: flex; align-items: center; gap: 5px; width: 100%;"
|
||||||
class={cn(
|
>
|
||||||
"mr-2 size-4"
|
<MapPinIcon class={cn("mr-2 size-4")} />
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{result.properties.name}
|
{result.properties.name}
|
||||||
<CheckIcon
|
<CheckIcon
|
||||||
class={cn(
|
class={cn(
|
||||||
"mr-2 size-4 ml-auto",
|
"mr-2 size-4 ml-auto",
|
||||||
value !== resultValue && "text-transparent"
|
value !== resultValue && "text-transparent",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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>
|
</Command.Item>
|
||||||
{/each}
|
{/each}
|
||||||
</Command.Group>
|
</Command.Group>
|
||||||
|
|||||||
@ -48,7 +48,10 @@
|
|||||||
let CurrentView: Component = $state(LoadingSidebar);
|
let CurrentView: Component = $state(LoadingSidebar);
|
||||||
const modules = import.meta.glob("./sidebar/**/*.svelte");
|
const modules = import.meta.glob("./sidebar/**/*.svelte");
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const path = modules[`./sidebar/${views[view.current.type] || "InvalidSidebar"}.svelte`];
|
const path =
|
||||||
|
modules[
|
||||||
|
`./sidebar/${views[view.current.type] || "InvalidSidebar"}.svelte`
|
||||||
|
];
|
||||||
if (!path) {
|
if (!path) {
|
||||||
// Invalid view
|
// Invalid view
|
||||||
import("./sidebar/InvalidSidebar.svelte").then((m) => {
|
import("./sidebar/InvalidSidebar.svelte").then((m) => {
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Loading...
|
Loading...
|
||||||
|
|||||||
@ -102,13 +102,18 @@
|
|||||||
{#await getSaved() then saved}
|
{#await getSaved() then saved}
|
||||||
{#if saved.length != 0}
|
{#if saved.length != 0}
|
||||||
<div>
|
<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;">
|
<div style="display: flex; flex-direction: column; gap: 10px;">
|
||||||
{#each saved as save}
|
{#each saved as save, _index (save.name)}
|
||||||
<Button variant="secondary" onclick={() => {
|
<Button
|
||||||
view.switch("trip", { route: JSON.parse(save.data) })
|
variant="secondary"
|
||||||
}}>{save.name}</Button>
|
onclick={() => {
|
||||||
|
view.switch("trip", { route: JSON.parse(save.data) });
|
||||||
|
}}>{save.name}</Button
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { CircleArrowDown, CircleDotIcon, StarIcon } from "@lucide/svelte";
|
import { CircleArrowDown, CircleDotIcon, StarIcon } from "@lucide/svelte";
|
||||||
import Input from "$lib/components/ui/input/input.svelte";
|
|
||||||
import SidebarHeader from "./SidebarHeader.svelte";
|
import SidebarHeader from "./SidebarHeader.svelte";
|
||||||
import { Button } from "$lib/components/ui/button";
|
import { Button } from "$lib/components/ui/button";
|
||||||
import { createValhallaRequest } from "$lib/vehicles/ValhallaVehicles";
|
import { createValhallaRequest } from "$lib/vehicles/ValhallaVehicles";
|
||||||
|
|||||||
@ -48,16 +48,19 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<RequiresCapability capability="saved-routes">
|
<RequiresCapability capability="saved-routes">
|
||||||
{#await isSaved($state.snapshot(route)) then saved}
|
{#await isSaved($state.snapshot(route)) then saved}
|
||||||
<Button variant="secondary" onclick={async () => {
|
<Button
|
||||||
if(saved) {
|
variant="secondary"
|
||||||
await deleteSaved(saved);
|
onclick={async () => {
|
||||||
view.back();
|
if (saved) {
|
||||||
} else {
|
await deleteSaved(saved);
|
||||||
const name = prompt("Trip name?");
|
view.back();
|
||||||
if(!name) return;
|
} else {
|
||||||
await putSaved(name, route);
|
const name = prompt("Trip name?");
|
||||||
}
|
if (!name) return;
|
||||||
}}>
|
await putSaved(name, route);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<SaveIcon />
|
<SaveIcon />
|
||||||
{saved ? m.unsave() : m["sidebar.trip.save"]()}
|
{saved ? m.unsave() : m["sidebar.trip.save"]()}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -70,9 +70,11 @@
|
|||||||
</Avatar.Root>
|
</Avatar.Root>
|
||||||
{user.name || user.preferred_username}
|
{user.name || user.preferred_username}
|
||||||
</SidebarHeader>
|
</SidebarHeader>
|
||||||
<button onclick={() => {
|
<button
|
||||||
refreshToken();
|
onclick={() => {
|
||||||
}}>refresh</button>
|
refreshToken();
|
||||||
|
}}>refresh</button
|
||||||
|
>
|
||||||
<pre>{user.sub}</pre>
|
<pre>{user.sub}</pre>
|
||||||
{JSON.stringify(user, null, 2)}
|
{JSON.stringify(user, null, 2)}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@ -10,11 +10,11 @@ export function saveLocations() {
|
|||||||
|
|
||||||
export async function geocode(name: string) {
|
export async function geocode(name: string) {
|
||||||
const loc = saved[name];
|
const loc = saved[name];
|
||||||
if(!loc) return;
|
if (!loc) return;
|
||||||
const geocode = await reverseGeocode(loc);
|
const geocode = await reverseGeocode(loc);
|
||||||
if(geocode.length == 0) {
|
if (geocode.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const feature = geocode[0];
|
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}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
import { LNV_SERVER } from "./hosts";
|
import { LNV_SERVER } from "./hosts";
|
||||||
import type { OIDCUser } from "./oidc";
|
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 capabilities: Capabilities = [];
|
||||||
export let oidcConfig: {
|
export let oidcConfig: {
|
||||||
AUTH_URL: string;
|
AUTH_URL: string;
|
||||||
@ -57,22 +64,22 @@ export async function uploadID() {
|
|||||||
const res = await fetch(LNV_SERVER + "/user", {
|
const res = await fetch(LNV_SERVER + "/user", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
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.");
|
alert("Failed to upload user data.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function refreshToken() {
|
export async function refreshToken() {
|
||||||
const config = await getOIDCConfig();
|
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");
|
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();
|
const params = new URLSearchParams();
|
||||||
params.append("grant_type", "refresh_token");
|
params.append("grant_type", "refresh_token");
|
||||||
params.append("refresh_token", refresh_token);
|
params.append("refresh_token", refresh_token);
|
||||||
@ -80,13 +87,13 @@ export async function refreshToken() {
|
|||||||
const res = await fetch(config.TOKEN_URL, {
|
const res = await fetch(config.TOKEN_URL, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
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;
|
const data = (await res.json()) as OIDCUser;
|
||||||
if(!res.ok) {
|
if (!res.ok) {
|
||||||
console.error("Refreshing token: " + res.status + " " + res.statusText)
|
console.error("Refreshing token: " + res.status + " " + res.statusText);
|
||||||
console.error(data);
|
console.error(data);
|
||||||
}
|
}
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -96,24 +103,27 @@ export async function refreshToken() {
|
|||||||
await uploadID();
|
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, {
|
let res = await fetch(url, {
|
||||||
headers: {
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
await refreshToken();
|
await refreshToken();
|
||||||
res = await fetch(url, {
|
res = await fetch(url, {
|
||||||
headers: {
|
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.");
|
console.error("Server is misconfigured.");
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
@ -188,8 +198,8 @@ export async function ai(query: string, location?: WorldLocation) {
|
|||||||
return await res.text();
|
return await res.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSaved(): Promise<{ name: string; data: string; }[]> {
|
export function getSaved(): Promise<{ name: string; data: string }[]> {
|
||||||
return authFetch(LNV_SERVER + "/saved").then(res => res.json());
|
return authFetch(LNV_SERVER + "/saved").then((res) => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function putSaved(name: string, data: object) {
|
export function putSaved(name: string, data: object) {
|
||||||
@ -197,24 +207,26 @@ export function putSaved(name: string, data: object) {
|
|||||||
method: "PUT",
|
method: "PUT",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name,
|
name,
|
||||||
data: JSON.stringify(data)
|
data: JSON.stringify(data),
|
||||||
})
|
}),
|
||||||
}).then(res => res.json());
|
}).then((res) => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteSaved(name: string) {
|
export function deleteSaved(name: string) {
|
||||||
return authFetch(LNV_SERVER + "/saved", {
|
return authFetch(LNV_SERVER + "/saved", {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name
|
name,
|
||||||
})
|
}),
|
||||||
}).then(res => res.text());
|
}).then((res) => res.text());
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isSaved(data: Trip) {
|
export async function isSaved(data: Trip) {
|
||||||
const res = await getSaved();
|
const res = await getSaved();
|
||||||
console.log(res, data);
|
console.log(res, data);
|
||||||
const filtered = res.filter(s => JSON.parse(s.data).legs[0].shape == data.legs[0].shape);
|
const filtered = res.filter(
|
||||||
if(filtered.length == 0) return false;
|
(s) => JSON.parse(s.data).legs[0].shape == data.legs[0].shape,
|
||||||
|
);
|
||||||
|
if (filtered.length == 0) return false;
|
||||||
return filtered[0].name;
|
return filtered[0].name;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ async function sha256(input: string | undefined): Promise<ArrayBuffer> {
|
|||||||
return await window.crypto.subtle.digest("SHA-256", data);
|
return await window.crypto.subtle.digest("SHA-256", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OIDCUser = {
|
export interface OIDCUser {
|
||||||
access_token: string;
|
access_token: string;
|
||||||
token_type: string;
|
token_type: string;
|
||||||
refresh_token: string;
|
refresh_token: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user