facilmap/frontend/src/lib/components/search-result-info.vue

147 wiersze
4.4 KiB
Vue
Czysty Zwykły widok Historia

2023-09-12 09:15:28 +00:00
<script setup lang="ts">
import { renderOsmTag } from "facilmap-utils";
2023-11-06 02:22:33 +00:00
import type { FindOnMapResult, Point, SearchResult, Type } from "facilmap-types";
2023-11-01 18:45:16 +00:00
import Icon from "./ui/icon.vue";
2023-11-02 14:14:05 +00:00
import type { FileResult } from "../utils/files";
2023-11-06 02:22:33 +00:00
import { isFileResult, isLineResult, isMarkerResult } from "../utils/search";
import { getZoomDestinationForSearchResult } from "../utils/zoom";
2023-11-01 18:45:16 +00:00
import Coordinates from "./ui/coordinates.vue";
2023-11-06 02:22:33 +00:00
import { computed, toRaw } from "vue";
import DropdownMenu from "./ui/dropdown-menu.vue";
import UseAsDropdown from "./ui/use-as-dropdown.vue";
import ZoomToObjectButton from "./ui/zoom-to-object-button.vue";
import { injectContextRequired, requireClientContext } from "./facil-map-context-provider/facil-map-context-provider.vue";
import type { RouteDestination } from "./facil-map-context-provider/map-context";
2023-11-01 18:45:16 +00:00
const context = injectContextRequired();
2023-11-06 02:22:33 +00:00
const client = requireClientContext(context);
2023-11-01 18:45:16 +00:00
const props = withDefaults(defineProps<{
result: SearchResult | FileResult;
showBackButton?: boolean;
isAdding?: boolean;
2023-11-06 02:22:33 +00:00
/** If specified, will be passed to the route form as suggestions when using the "Use as" menu */
searchResults?: SearchResult[];
/** If specified, will be passed to the route form as suggestions when using the "Use as" menu */
mapResults?: FindOnMapResult[];
2023-11-01 18:45:16 +00:00
}>(), {
showBackButton: false,
isAdding: false
});
2023-11-06 02:22:33 +00:00
const emit = defineEmits<{
back: [];
"add-to-map": [type: Type];
}>();
2023-11-01 18:45:16 +00:00
const isMarker = computed(() => isMarkerResult(props.result));
const isLine = computed(() => isLineResult(props.result));
const types = computed(() => {
// Result can be both marker and line
2023-11-06 02:22:33 +00:00
return Object.values(client.value.types).filter((type) => (isMarker.value && type.type == "marker") || (isLine.value && type.type == "line"));
2023-11-01 18:45:16 +00:00
});
2023-11-06 02:22:33 +00:00
const zoomDestination = computed(() => getZoomDestinationForSearchResult(props.result));
const routeDestination = computed<RouteDestination | undefined>(() => {
if (isFileResult(props.result)) {
if (props.result.lat != null && props.result.lon != null) {
return { query: `${props.result.lat},${props.result.lon}` };
} else if (props.result.geojson?.type === "Point") {
return { query: `${props.result.geojson.coordinates[1]},${props.result.geojson.coordinates[0]}` };
} else {
return undefined;
}
} else {
return {
query: props.result.short_name,
searchSuggestions: (props.searchResults || props.mapResults) ? props.searchResults : [props.result],
mapSuggestions: props.mapResults,
selectedSuggestion: props.result
};
}
});
2023-09-12 09:15:28 +00:00
</script>
<template>
<div class="fm-search-result-info" v-if="result">
<h2>
2023-11-06 02:22:33 +00:00
<a v-if="showBackButton" href="javascript:" @click="emit('back')"><Icon icon="arrow-left"></Icon></a>
2023-09-12 09:15:28 +00:00
{{result.short_name}}
</h2>
<dl class="fm-search-box-collapse-point">
2023-11-01 18:45:16 +00:00
<template v-if="result.type">
<dt>Type</dt>
<dd>{{result.type}}</dd>
</template>
2023-09-12 09:15:28 +00:00
2023-11-01 18:45:16 +00:00
<template v-if="result.address">
<dt>Address</dt>
<dd>{{result.address}}</dd>
</template>
2023-09-12 09:15:28 +00:00
2023-11-01 18:45:16 +00:00
<template v-if="result.type != 'coordinates' && result.lat != null && result.lon != null">
<dt>Coordinates</dt>
<dd><Coordinates :point="result as Point"></Coordinates></dd>
</template>
2023-09-12 09:15:28 +00:00
2023-11-01 18:45:16 +00:00
<template v-if="result.elevation != null">
<dt>Elevation</dt>
2023-11-06 02:22:33 +00:00
<dd>{{result.elevation}}&#x202F;m</dd>
2023-11-01 18:45:16 +00:00
</template>
2023-09-12 09:15:28 +00:00
2023-11-01 18:45:16 +00:00
<template v-for="(value, key) in result.extratags" :key="key">
2023-09-12 09:15:28 +00:00
<dt>{{key}}</dt>
<dd v-html="renderOsmTag(key, value)"></dd>
</template>
2023-09-12 09:15:28 +00:00
</dl>
2023-11-02 14:14:05 +00:00
<div>
2023-11-06 02:22:33 +00:00
<div class="btn-toolbar" role="group">
<ZoomToObjectButton
v-if="zoomDestination"
label="search result"
size="sm"
:destination="zoomDestination"
></ZoomToObjectButton>
<DropdownMenu
v-if="!client.readonly && types.length > 0"
size="sm"
:isBusy="isAdding"
label="Add to map"
2023-11-02 14:14:05 +00:00
>
2023-11-06 02:22:33 +00:00
<template v-for="type in types" :key="type.id">
2023-11-02 14:14:05 +00:00
<li>
<a
href="javascript:"
class="dropdown-item"
2023-11-06 02:22:33 +00:00
@click="emit('add-to-map', type)"
>{{type.name}}</a>
2023-11-02 14:14:05 +00:00
</li>
2023-11-06 02:22:33 +00:00
</template>
</DropdownMenu>
<UseAsDropdown
v-if="isMarker && routeDestination"
size="sm"
:destination="routeDestination"
></UseAsDropdown>
2023-10-24 00:08:47 +00:00
</div>
2023-10-30 00:14:54 +00:00
</div>
2023-09-12 09:15:28 +00:00
</div>
</template>
<style lang="scss">
.fm-search-result-info {
display: flex;
flex-direction: column;
min-height: 0;
.fm-search-box-collapse-point {
min-height: 1.5em;
}
}
</style>