feat(stores): location stores
This commit is contained in:
@ -8,7 +8,6 @@
|
||||
routing,
|
||||
} from "$lib/services/navigation/routing.svelte";
|
||||
import { location } from "./location.svelte";
|
||||
import { saved } from "$lib/saved.svelte";
|
||||
import RoutingLayers from "$lib/services/navigation/RoutingLayers.svelte";
|
||||
import {
|
||||
getPMTilesURL,
|
||||
@ -20,6 +19,7 @@
|
||||
import HazardMarker from "./HazardMarker.svelte";
|
||||
import { hazards } from "./hazards.svelte";
|
||||
import RequiresCapability from "./RequiresCapability.svelte";
|
||||
import MapLocationMarkers from "./MapLocationMarkers.svelte";
|
||||
|
||||
onMount(() => {
|
||||
window.addEventListener("resize", map.updateMapPadding);
|
||||
@ -28,9 +28,6 @@
|
||||
|
||||
let locationDot: HTMLDivElement | undefined = $state();
|
||||
let locationAccuracyCircle: HTMLDivElement | undefined = $state();
|
||||
let homeMarker: HTMLImageElement | undefined = $state();
|
||||
let workMarker: HTMLImageElement | undefined = $state();
|
||||
let schoolMarker: HTMLImageElement | undefined = $state();
|
||||
|
||||
const DEBUG_POINTS = false; // Set to true to show debug points on the map
|
||||
</script>
|
||||
@ -137,51 +134,7 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if saved.home}
|
||||
<img
|
||||
src={map.zoom > 9 ? "/img/saved/home.png" : "/img/saved/small.png"}
|
||||
alt="Home Marker"
|
||||
bind:this={homeMarker}
|
||||
style="width: 32px;"
|
||||
/>
|
||||
<Marker
|
||||
lnglat={{
|
||||
lat: saved.home.lat,
|
||||
lng: saved.home.lon,
|
||||
}}
|
||||
element={homeMarker}
|
||||
/>
|
||||
{/if}
|
||||
{#if saved.school}
|
||||
<img
|
||||
src={map.zoom > 9 ? "/img/saved/school.png" : "/img/saved/small.png"}
|
||||
alt="School Marker"
|
||||
bind:this={schoolMarker}
|
||||
style="width: 32px;"
|
||||
/>
|
||||
<Marker
|
||||
lnglat={{
|
||||
lat: saved.school.lat,
|
||||
lng: saved.school.lon,
|
||||
}}
|
||||
element={schoolMarker}
|
||||
/>
|
||||
{/if}
|
||||
{#if saved.work}
|
||||
<img
|
||||
src={map.zoom > 9 ? "/img/saved/work.png" : "/img/saved/small.png"}
|
||||
alt="Work Marker"
|
||||
bind:this={workMarker}
|
||||
style="width: 32px;"
|
||||
/>
|
||||
<Marker
|
||||
lnglat={{
|
||||
lat: saved.work.lat,
|
||||
lng: saved.work.lon,
|
||||
}}
|
||||
element={workMarker}
|
||||
/>
|
||||
{/if}
|
||||
<MapLocationMarkers />
|
||||
|
||||
<RequiresCapability capability="hazards">
|
||||
{#each hazards as hazard (hazard.latitude + "-" + hazard.longitude)}
|
||||
|
||||
22
src/lib/components/lnv/MapLocationMarker.svelte
Normal file
22
src/lib/components/lnv/MapLocationMarker.svelte
Normal file
@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { MAP_ICONS, type Location } from "$lib/saved.svelte";
|
||||
import { Marker } from "svelte-maplibre-gl";
|
||||
import { map } from "./map.svelte";
|
||||
|
||||
let { store }: { store: Location } = $props();
|
||||
|
||||
let marker: HTMLImageElement | undefined = $state();
|
||||
</script>
|
||||
<img
|
||||
src={map.zoom > 9 ? `/img/saved/${MAP_ICONS[store.icon ?? "small.png"]}` : "/img/saved/small.png"}
|
||||
alt="Work Marker"
|
||||
bind:this={marker}
|
||||
style="width: 32px;"
|
||||
/>
|
||||
<Marker
|
||||
lnglat={{
|
||||
lat: store.lat,
|
||||
lng: store.lng,
|
||||
}}
|
||||
element={marker}
|
||||
/>
|
||||
11
src/lib/components/lnv/MapLocationMarkers.svelte
Normal file
11
src/lib/components/lnv/MapLocationMarkers.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import type { Location } from "$lib/saved.svelte";
|
||||
import { stores } from "$lib/services/stores.svelte";
|
||||
import MapLocationMarker from "./MapLocationMarker.svelte";
|
||||
|
||||
const locations = stores<Location>("location");
|
||||
</script>
|
||||
|
||||
{#each locations.current as location (location.data.lat + "-" + location.data.lng)}
|
||||
<MapLocationMarker store={location.data} />
|
||||
{/each}
|
||||
57
src/lib/components/lnv/main/SavedLocations.svelte
Normal file
57
src/lib/components/lnv/main/SavedLocations.svelte
Normal file
@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import { m } from "$lang/messages";
|
||||
import Button from "$lib/components/ui/button/button.svelte";
|
||||
import { circInOut } from "svelte/easing";
|
||||
import { fly } from "svelte/transition";
|
||||
import { map, pin } from "../map.svelte";
|
||||
import { MapPinIcon } from "@lucide/svelte";
|
||||
import { stores } from "$lib/services/stores.svelte";
|
||||
import { ICONS, type Location } from "$lib/saved.svelte";
|
||||
|
||||
const locations = stores<Location>("location");
|
||||
|
||||
function getName(name: string) {
|
||||
if(name == "home") {
|
||||
return m["saved.home"]();
|
||||
} else if(name == "work") {
|
||||
return m["saved.work"]();
|
||||
} else if(name == "school") {
|
||||
return m["saved.school"]();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
</script>
|
||||
<div
|
||||
id="saved"
|
||||
class="mt-2 mb-2"
|
||||
in:fly={{ y: 20, duration: 200, easing: circInOut }}
|
||||
>
|
||||
{#each locations.current as location (location.data.lat + "-" + location.data.lng)}
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="flex-1"
|
||||
onclick={() => {
|
||||
const { lat, lng } = location.data;
|
||||
pin.dropPin(lat, lng);
|
||||
pin.showInfo();
|
||||
map.value?.flyTo({
|
||||
center: [lng, lat],
|
||||
zoom: 19,
|
||||
});
|
||||
}}>
|
||||
{@const Icon = ICONS[location.data.icon ?? "pin"] ?? MapPinIcon}
|
||||
<Icon />
|
||||
{getName(location.data.name)}
|
||||
</Button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#saved {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
/* justify-content: space-evenly; */
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -22,12 +22,12 @@
|
||||
import Reviews from "../info/Reviews.svelte";
|
||||
import MapAi from "../info/MapAI.svelte";
|
||||
import RequiresCapability from "../RequiresCapability.svelte";
|
||||
import { saved, saveLocations } from "$lib/saved.svelte";
|
||||
import { getDeveloperToggle } from "./settings/developer.svelte";
|
||||
import InternetAccess from "../info/InternetAccess.svelte";
|
||||
import RestaurantInfo from "../info/RestaurantInfo.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
import { onMount } from "svelte";
|
||||
import { updateStore } from "$lib/services/stores.svelte";
|
||||
|
||||
// let { feature }: { feature: Feature } = $props();
|
||||
|
||||
@ -185,12 +185,12 @@
|
||||
<Button
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
// localStorage.setItem(
|
||||
// "saved.home",
|
||||
// JSON.stringify({ lat, lon: lng }),
|
||||
// );
|
||||
saved.home = { lat, lon: lng };
|
||||
saveLocations();
|
||||
updateStore({ name: "home", type: "location" }, {
|
||||
lat,
|
||||
lng,
|
||||
name: "home",
|
||||
icon: "home"
|
||||
})
|
||||
}}
|
||||
>
|
||||
<HomeIcon />
|
||||
@ -199,8 +199,12 @@
|
||||
<Button
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
saved.school = { lat, lon: lng };
|
||||
saveLocations();
|
||||
updateStore({ name: "school", type: "location" }, {
|
||||
lat,
|
||||
lng,
|
||||
name: "school",
|
||||
icon: "school"
|
||||
})
|
||||
}}
|
||||
>
|
||||
<SchoolIcon />
|
||||
@ -209,12 +213,12 @@
|
||||
<Button
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
// localStorage.setItem(
|
||||
// "saved.work",
|
||||
// JSON.stringify({ lat, lon: lng }),
|
||||
// );
|
||||
saved.work = { lat, lon: lng };
|
||||
saveLocations();
|
||||
updateStore({ name: "work", type: "location" }, {
|
||||
lat,
|
||||
lng,
|
||||
name: "work",
|
||||
icon: "work"
|
||||
})
|
||||
}}
|
||||
>
|
||||
<BriefcaseIcon />
|
||||
|
||||
@ -1,108 +1,21 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
BriefcaseIcon,
|
||||
DownloadIcon,
|
||||
FuelIcon,
|
||||
HomeIcon,
|
||||
ParkingSquareIcon,
|
||||
SchoolIcon,
|
||||
} from "@lucide/svelte";
|
||||
import { Button } from "../../ui/button";
|
||||
import { fly } from "svelte/transition";
|
||||
import { circInOut } from "svelte/easing";
|
||||
import { map, pin } from "../map.svelte";
|
||||
import VehicleSelector from "../VehicleSelector.svelte";
|
||||
import Post from "../Post.svelte";
|
||||
import RequiresCapability from "../RequiresCapability.svelte";
|
||||
import { saved } from "$lib/saved.svelte";
|
||||
import { m } from "$lang/messages";
|
||||
import { view } from "../view.svelte";
|
||||
import * as Card from "$lib/components/ui/card";
|
||||
import SavedRoutes from "../main/SavedRoutes.svelte";
|
||||
import SavedLocations from "../main/SavedLocations.svelte";
|
||||
</script>
|
||||
|
||||
<div
|
||||
id="saved"
|
||||
class="mt-2 mb-2"
|
||||
in:fly={{ y: 20, duration: 200, easing: circInOut }}
|
||||
>
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="flex-1"
|
||||
onclick={() => {
|
||||
const loc = saved.home;
|
||||
if (!loc) {
|
||||
alert(m["saved.no-location"]({ name: m["saved.home"]() }));
|
||||
return;
|
||||
}
|
||||
const { lat, lon } = loc;
|
||||
if (!lat || !lon) {
|
||||
alert(m["saved.no-location"]({ name: m["saved.home"]() }));
|
||||
return;
|
||||
}
|
||||
pin.dropPin(lat, lon);
|
||||
pin.showInfo();
|
||||
map.value?.flyTo({
|
||||
center: [lon, lat],
|
||||
zoom: 19,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<HomeIcon />
|
||||
{m["saved.home"]()}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="flex-1"
|
||||
onclick={() => {
|
||||
console.log(saved);
|
||||
const loc = saved.school;
|
||||
if (!loc) {
|
||||
alert(m["saved.no-location"]({ name: m["saved.school"]() }));
|
||||
return;
|
||||
}
|
||||
const { lat, lon } = loc;
|
||||
if (!lat || !lon) {
|
||||
alert(m["saved.no-location"]({ name: m["saved.school"]() }));
|
||||
return;
|
||||
}
|
||||
pin.dropPin(lat, lon);
|
||||
pin.showInfo();
|
||||
map.value?.flyTo({
|
||||
center: [lon, lat],
|
||||
zoom: 19,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<SchoolIcon />
|
||||
{m["saved.school"]()}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
class="flex-1"
|
||||
onclick={() => {
|
||||
const loc = saved.work;
|
||||
if (!loc) {
|
||||
alert(m["saved.no-location"]({ name: m["saved.work"]() }));
|
||||
return;
|
||||
}
|
||||
const { lat, lon } = loc;
|
||||
if (!lat || !lon) {
|
||||
alert(m["saved.no-location"]({ name: m["saved.work"]() }));
|
||||
return;
|
||||
}
|
||||
pin.dropPin(lat, lon);
|
||||
pin.showInfo();
|
||||
map.value?.flyTo({
|
||||
center: [lon, lat],
|
||||
zoom: 19,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<BriefcaseIcon />
|
||||
{m["saved.work"]()}
|
||||
</Button>
|
||||
</div>
|
||||
<SavedLocations />
|
||||
|
||||
<VehicleSelector />
|
||||
|
||||
@ -170,13 +83,3 @@
|
||||
<Post />
|
||||
</div>
|
||||
</RequiresCapability>
|
||||
|
||||
<style>
|
||||
#saved {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
/* justify-content: space-evenly; */
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,13 +1,24 @@
|
||||
import type { Component } from "svelte";
|
||||
import { reverseGeocode } from "./services/Search";
|
||||
import { BriefcaseIcon, HomeIcon, MapPinIcon, SchoolIcon, type IconProps } from "@lucide/svelte";
|
||||
|
||||
/**
|
||||
* @deprecated Use stores instead.
|
||||
*/
|
||||
export const saved: Record<string, WorldLocation> = $state(
|
||||
JSON.parse(localStorage.getItem("saved") ?? "{}"),
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated Use stores instead.
|
||||
*/
|
||||
export function saveLocations() {
|
||||
localStorage.setItem("saved", JSON.stringify(saved));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use stores instead.
|
||||
*/
|
||||
export async function geocode(name: string) {
|
||||
const loc = saved[name];
|
||||
if (!loc) return;
|
||||
@ -18,3 +29,23 @@ export async function geocode(name: string) {
|
||||
const feature = geocode[0];
|
||||
return `${feature.properties.street}${feature.properties.housenumber ? " " + feature.properties.housenumber : ""}, ${feature.properties.city}`;
|
||||
}
|
||||
|
||||
export const ICONS: Record<string, Component<IconProps>> = {
|
||||
home: HomeIcon,
|
||||
work: BriefcaseIcon,
|
||||
school: SchoolIcon,
|
||||
pin: MapPinIcon
|
||||
};
|
||||
|
||||
export const MAP_ICONS: Record<string, string> = {
|
||||
home: "home.png",
|
||||
school: "school.png",
|
||||
work: "work.png"
|
||||
}; // TODO: add generic pin icon
|
||||
|
||||
export interface Location {
|
||||
lat: number;
|
||||
lng: number;
|
||||
name: string;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user