forked from MapComplete/MapComplete
A11y: various improvements
This commit is contained in:
parent
0d4f2c9c36
commit
5fa2ddd9c1
23 changed files with 327 additions and 98 deletions
39
src/UI/BigComponents/FilterPanel.svelte
Normal file
39
src/UI/BigComponents/FilterPanel.svelte
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<script lang="ts">
|
||||
/**
|
||||
* THe panel containing all filter- and layerselection options
|
||||
*/
|
||||
|
||||
import OverlayToggle from "./OverlayToggle.svelte"
|
||||
import Filterview from "./Filterview.svelte"
|
||||
import ThemeViewState from "../../Models/ThemeViewState"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import Filter from "../../assets/svg/Filter.svelte"
|
||||
|
||||
export let state: ThemeViewState
|
||||
let layout = state.layout
|
||||
</script>
|
||||
|
||||
<div class="m-2 flex flex-col">
|
||||
|
||||
<h2 class="flex items-center">
|
||||
<Filter class="h-6 w-6 pr-2" />
|
||||
<Tr t={Translations.t.general.menu.filter} />
|
||||
</h2>
|
||||
|
||||
{#each layout.layers as layer}
|
||||
<Filterview
|
||||
zoomlevel={state.mapProperties.zoom}
|
||||
filteredLayer={state.layerState.filteredLayers.get(layer.id)}
|
||||
highlightedLayer={state.guistate.highlightedLayerInFilters}
|
||||
/>
|
||||
{/each}
|
||||
{#each layout.tileLayerSources as tilesource}
|
||||
<OverlayToggle
|
||||
layerproperties={tilesource}
|
||||
state={state.overlayLayerStates.get(tilesource.id)}
|
||||
highlightedLayer={state.guistate.highlightedLayerInFilters}
|
||||
zoomlevel={state.mapProperties.zoom}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { ImmutableStore, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import type { Feature } from "geojson"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import Svg from "../../Svg.js"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import Hotkeys from "../Base/Hotkeys"
|
||||
|
|
@ -23,7 +21,7 @@
|
|||
onDestroy(
|
||||
triggerSearch.addCallback((_) => {
|
||||
performSearch()
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
let isRunning: boolean = false
|
||||
|
|
@ -31,15 +29,17 @@
|
|||
let inputElement: HTMLInputElement
|
||||
|
||||
let feedback: string = undefined
|
||||
|
||||
|
||||
|
||||
|
||||
function focusOnSearch() {
|
||||
requestAnimationFrame(() => {
|
||||
inputElement?.focus()
|
||||
inputElement?.select()
|
||||
})
|
||||
}
|
||||
|
||||
Hotkeys.RegisterHotkey({ ctrl: "F" }, Translations.t.hotkeyDocumentation.selectSearch, () => {
|
||||
feedback = undefined
|
||||
requestAnimationFrame(() => {
|
||||
inputElement?.focus()
|
||||
inputElement?.select()
|
||||
})
|
||||
focusOnSearch()
|
||||
})
|
||||
|
||||
const dispatch = createEventDispatcher<{ searchCompleted; searchIsValid: boolean }>()
|
||||
|
|
@ -62,6 +62,7 @@
|
|||
const result = await Geocoding.Search(searchContents, bounds.data)
|
||||
if (result.length == 0) {
|
||||
feedback = Translations.t.general.search.nothing.txt
|
||||
focusOnSearch()
|
||||
return
|
||||
}
|
||||
const poi = result[0]
|
||||
|
|
@ -70,7 +71,7 @@
|
|||
new BBox([
|
||||
[lon0, lat0],
|
||||
[lon1, lat1],
|
||||
]).pad(0.01)
|
||||
]).pad(0.01),
|
||||
)
|
||||
if (perLayer !== undefined) {
|
||||
const id = poi.osm_type + "/" + poi.osm_id
|
||||
|
|
@ -78,11 +79,11 @@
|
|||
for (const layer of layers) {
|
||||
const found = layer.features.data.find((f) => f.properties.id === id)
|
||||
if (found === undefined) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
selectedElement?.setData(found);
|
||||
console.log("Found an element that probably matches:", selectedElement?.data);
|
||||
break;
|
||||
selectedElement?.setData(found)
|
||||
console.log("Found an element that probably matches:", selectedElement?.data)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (clearAfterView) {
|
||||
|
|
@ -93,6 +94,7 @@
|
|||
} catch (e) {
|
||||
console.error(e)
|
||||
feedback = Translations.t.general.search.error.txt
|
||||
focusOnSearch()
|
||||
} finally {
|
||||
isRunning = false
|
||||
}
|
||||
|
|
@ -100,23 +102,25 @@
|
|||
</script>
|
||||
|
||||
<div class="normal-background flex justify-between rounded-full pl-2">
|
||||
<form class="w-full">
|
||||
<form class="w-full flex flex-wrap">
|
||||
{#if isRunning}
|
||||
<Loading>{Translations.t.general.search.searching}</Loading>
|
||||
{:else if feedback !== undefined}
|
||||
<div class="alert" on:click={() => (feedback = undefined)}>
|
||||
{feedback}
|
||||
</div>
|
||||
{:else}
|
||||
<input
|
||||
type="search"
|
||||
class="w-full"
|
||||
bind:this={inputElement}
|
||||
on:keypress={(keypr) => (keypr.key === "Enter" ? performSearch() : undefined)}
|
||||
on:keypress={(keypr) =>{ feedback = undefined; return (keypr.key === "Enter" ? performSearch() : undefined); }}
|
||||
bind:value={searchContents}
|
||||
use:placeholder={Translations.t.general.search.search}
|
||||
/>
|
||||
{#if feedback !== undefined}
|
||||
<!-- The feedback is _always_ shown for screenreaders and to make sure that the searchfield can still be selected by tabbing-->
|
||||
<div class="alert " role="alert" aria-live="assertive">
|
||||
{feedback}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</form>
|
||||
<SearchIcon class="h-6 w-6 self-end" aria-hidden="true" on:click={performSearch}/>
|
||||
<SearchIcon aria-hidden="true" class="h-6 w-6 self-end" on:click={performSearch} />
|
||||
</div>
|
||||
|
|
|
|||
45
src/UI/BigComponents/ReverseGeocoding.svelte
Normal file
45
src/UI/BigComponents/ReverseGeocoding.svelte
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<script lang="ts">/**
|
||||
* Shows the current address when shaken
|
||||
**/
|
||||
import Motion from "../../Sensors/Motion"
|
||||
import { Geocoding } from "../../Logic/Osm/Geocoding"
|
||||
import type { MapProperties } from "../../Models/MapProperties"
|
||||
|
||||
export let mapProperties: MapProperties
|
||||
let lastDisplayed: Date = undefined
|
||||
let currentLocation: string = undefined
|
||||
|
||||
async function displayLocation() {
|
||||
lastDisplayed = new Date()
|
||||
let result = await Geocoding.reverse(
|
||||
mapProperties.location.data,
|
||||
mapProperties.zoom.data,
|
||||
)
|
||||
console.log("Got result", result)
|
||||
let properties = result.features[0].properties
|
||||
currentLocation = properties.display_name
|
||||
window.setTimeout(() => {
|
||||
currentLocation = undefined
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
Motion.singleton.lastShakeEvent.addCallbackD(shaken => {
|
||||
console.log("Got a shaken event")
|
||||
if (shaken.getTime() - lastDisplayed.getTime() < 1000) {
|
||||
console.log("To soon:",shaken.getTime() - lastDisplayed.getTime())
|
||||
// return
|
||||
}
|
||||
displayLocation()
|
||||
})
|
||||
|
||||
Motion.singleton.startListening()
|
||||
mapProperties.location.stabilized(500).addCallbackAndRun(loc => {
|
||||
displayLocation()
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if currentLocation}
|
||||
<div role="alert" aria-live="assertive" class="normal-background">
|
||||
{currentLocation}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -30,10 +30,12 @@
|
|||
)
|
||||
</script>
|
||||
|
||||
<button class="cursor-pointer small flex" on:click={() => select()}>
|
||||
<div class="cursor-pointer small flex" on:click={() => select()}>
|
||||
<span class="flex">
|
||||
{#if i !== undefined}
|
||||
<span class="font-bold">{i + 1}.</span>
|
||||
{/if}
|
||||
<TagRenderingAnswer config={layer.title} {layer} selectedElement={feature} {state} {tags} />
|
||||
<span class="flex">{$bearingAndDist.dist}m {$bearingAndDist.bearing}°</span>
|
||||
</button>
|
||||
<TagRenderingAnswer config={layer.title} {layer} selectedElement={feature} {state} {tags} />
|
||||
{$bearingAndDist.dist}m {$bearingAndDist.bearing}°
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
})
|
||||
lastAction.stabilized(750).addCallbackAndRunD(_ => lastAction.setData(undefined))
|
||||
</script>
|
||||
<div aria-live="assertive" class=" interactive p-1" role="alert">
|
||||
<div aria-live="assertive" class="p-1" role="alert">
|
||||
|
||||
{#if $lastAction !== undefined}
|
||||
<Tr t={Translations.t.general.visualFeedback[$lastAction.key]} />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue