MapComplete/src/UI/BigComponents/SearchResult.svelte

106 lines
4.1 KiB
Svelte

<script lang="ts">
import type { GeoCodeResult } from "../../Logic/Geocoding/GeocodingProvider"
import { GeocodingUtils } from "../../Logic/Geocoding/GeocodingProvider"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import ToSvelte from "../Base/ToSvelte.svelte"
import { GeoOperations } from "../../Logic/GeoOperations"
import { createEventDispatcher } from "svelte"
import Icon from "../Map/Icon.svelte"
import { BBox } from "../../Logic/BBox"
import TagRenderingAnswer from "../Popup/TagRendering/TagRenderingAnswer.svelte"
import { UIEventSource } from "../../Logic/UIEventSource"
import ArrowUp from "@babeard/svelte-heroicons/mini/ArrowUp"
import { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
import Tr from "../Base/Tr.svelte"
import { Translation } from "../i18n/Translation"
import MoreScreen from "./MoreScreen"
export let entry: GeoCodeResult
export let state: SpecialVisualizationState
let layer: LayerConfig
let tags: UIEventSource<Record<string, string>>
if (entry.feature?.properties?.id) {
layer = state.layout.getMatchingLayer(entry.feature.properties)
tags = state.featureProperties.getStore(entry.feature.properties.id)
}
let dispatch = createEventDispatcher<{ select }>()
let distance = state.mapProperties.location.mapD(l => GeoOperations.distanceBetween([l.lon, l.lat], [entry.lon, entry.lat]))
let bearing = state.mapProperties.location.mapD(l => GeoOperations.bearing([l.lon, l.lat], [entry.lon, entry.lat]))
let mapRotation = state.mapProperties.rotation
let inView = state.mapProperties.bounds.mapD(bounds => bounds.contains([entry.lon, entry.lat]))
let otherTheme: MinimalLayoutInformation | undefined = <MinimalLayoutInformation>entry.payload
function select() {
console.log("Selected search entry", entry)
if (entry.boundingbox) {
const [lat0, lat1, lon0, lon1] = entry.boundingbox
state.mapProperties.bounds.set(
new BBox([
[lon0, lat0],
[lon1, lat1]
]).pad(0.01)
)
} else {
state.mapProperties.flyTo(entry.lon, entry.lat, GeocodingUtils.categoryToZoomLevel[entry.category] ?? 17)
}
if (entry.feature?.properties?.id) {
state.selectedElement.set(entry.feature)
}
state.recentlySearched.addSelected(entry)
dispatch("select")
}
</script>
{#if otherTheme}
<a href={ MoreScreen.createUrlFor(otherTheme, false)} class="flex items-center p-2 w-full gap-y-2 rounded-xl" >
<Icon icon={otherTheme.icon} clss="w-6 h-6 m-1" />
<div class="flex flex-col">
<b>
<Tr t={new Translation(otherTheme.title)} />
</b>
<!--<Tr t={new Translation(otherTheme.shortDescription)} /> -->
</div>
</a>
{:else}
<button class="unstyled w-full link-no-underline" on:click={() => select() }>
<div class="p-2 flex items-center w-full gap-y-2">
{#if layer}
<ToSvelte construct={() => layer.defaultIcon(entry.feature.properties).SetClass("w-6 h-6")} />
{:else if entry.category}
<Icon icon={GeocodingUtils.categoryToIcon[entry.category]} clss="w-6 h-6 shrink-0" color="#aaa" />
{/if}
<div class="flex flex-col items-start pl-2 w-full">
<div class="flex flex-wrap gap-x-2 justify-between w-full">
<b class="nowrap">
{#if layer && $tags?.id}
<TagRenderingAnswer config={layer.title} selectedElement={entry.feature} {state} {tags} {layer} />
{:else}
{entry.display_name ?? entry.osm_id}
{/if}
</b>
<div class="flex gap-x-1 items-center">
{#if $bearing && !$inView}
<ArrowUp class="w-4 h-4 shrink-0" style={`transform: rotate(${$bearing - $mapRotation}deg)`} />
{/if}
{#if $distance}
{GeoOperations.distanceToHuman($distance)}
{/if}
</div>
</div>
{#if entry.description}
<div class="subtle flex justify-between w-full">
{entry.description}
</div>
{/if}
</div>
</div>
</button>
{/if}