More work on A11y

This commit is contained in:
Pieter Vander Vennet 2023-12-21 17:36:43 +01:00
parent 87aee9e2b7
commit 6da72b80ef
28 changed files with 398 additions and 209 deletions

View file

@ -0,0 +1,36 @@
<script lang="ts">
import { Store } from "../../Logic/UIEventSource"
import { GeoOperations } from "../../Logic/GeoOperations"
import ThemeViewState from "../../Models/ThemeViewState"
import Tr from "../Base/Tr.svelte"
import Translations from "../i18n/Translations"
/**
* Indicates how far away the viewport center is from the current user location
*/
export let state: ThemeViewState
const t = Translations.t.general.visualFeedback
let map = state.mapProperties
let currentLocation = state.geolocation.geolocationState.currentGPSLocation
let distanceToCurrentLocation: Store<{ distance: string, distanceInMeters: number, bearing: number }> = map.location.mapD(({ lon, lat }) => {
const current = currentLocation.data
if (!current) {
return undefined
}
const gps: [number, number] = [current.longitude, current.latitude]
const mapCenter: [number, number] = [lon, lat]
const distanceInMeters = Math.round(GeoOperations.distanceBetween(gps, mapCenter))
const distance = GeoOperations.distanceToHuman(distanceInMeters)
const bearing = Math.round(GeoOperations.bearing(gps, mapCenter))
return { distance, bearing, distanceInMeters }
}, [currentLocation])
</script>
{#if $currentLocation !== undefined}
{#if $distanceToCurrentLocation.distanceInMeters < 20}
<Tr t={t.viewportCenterCloseToGps} />
{:else}
<Tr t={t.viewportCenterDetails.Subs($distanceToCurrentLocation)} />
{/if}
{/if}

View file

@ -8,8 +8,11 @@
import Hotkeys from "../Base/Hotkeys"
import Translations from "../i18n/Translations"
import Locale from "../i18n/Locale"
import MapCenterDetails from "./MapCenterDetails.svelte"
import ThemeViewState from "../../Models/ThemeViewState"
export let mapProperties: MapProperties
export let state: ThemeViewState
let mapProperties = state.mapProperties
let lastDisplayed: Date = undefined
let currentLocation: string = undefined
@ -51,8 +54,9 @@
<div
role="alert"
aria-live="assertive"
class="normal-background border-interactive rounded-full px-2"
class="normal-background border-interactive rounded-full px-2 flex flex-col items-center"
>
{currentLocation}
<MapCenterDetails {state}/>
</div>
{/if}

View file

@ -31,8 +31,11 @@
<div class="flex flex-col">
<!-- Title element-->
<h3>
<a href={`#${$tags.id}`}>
<TagRenderingAnswer config={layer.title} {selectedElement} {state} {tags} {layer} />
</a>
</h3>
<div
class="no-weblate title-icons links-as-button mr-2 flex flex-row flex-wrap items-center gap-x-0.5 p-1 pt-0.5 sm:pt-1"
>

View file

@ -3,8 +3,7 @@
import type { SpecialVisualizationState } from "../SpecialVisualization"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import TagRenderingAnswer from "../Popup/TagRendering/TagRenderingAnswer.svelte"
import { GeoOperations } from "../../Logic/GeoOperations"
import { Store } from "../../Logic/UIEventSource"
import DirectionIndicator from "../Base/DirectionIndicator.svelte"
export let state: SpecialVisualizationState
export let feature: Feature
@ -13,30 +12,13 @@
let tags = state.featureProperties.getStore(id)
let layer: LayerConfig = state.layout.getMatchingLayer(tags.data)
function select() {
state.selectedElement.setData(undefined)
state.selectedLayer.setData(layer)
state.selectedElement.setData(feature)
}
let bearingAndDist: Store<{ bearing: number; dist: number }> = state.mapProperties.location.map(
(l) => {
let fcenter = GeoOperations.centerpointCoordinates(feature)
let mapCenter = [l.lon, l.lat]
let bearing = Math.round(GeoOperations.bearing(fcenter, mapCenter))
let dist = Math.round(GeoOperations.distanceBetween(fcenter, mapCenter))
return { bearing, dist }
}
)
</script>
<div class="small flex cursor-pointer" 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} />
{$bearingAndDist.dist}m {$bearingAndDist.bearing}°
</span>
</div>
<a class="small flex space-x-1 cursor-pointer w-fit" href={`#${feature.properties.id}`}>
{#if i !== undefined}
<span class="font-bold">{i + 1} &nbsp; </span>
{/if}
<TagRenderingAnswer config={layer.title} extraClasses="inline-flex w-fit" {layer} selectedElement={feature} {state}
{tags} />
<DirectionIndicator {feature} {state} />
</a>

View file

@ -7,18 +7,24 @@
import ThemeViewState from "../../Models/ThemeViewState"
import Summary from "./Summary.svelte"
import Tr from "../Base/Tr.svelte"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { UIEventSource } from "../../Logic/UIEventSource"
import type { KeyNavigationEvent } from "../../Models/MapProperties"
import type { Feature } from "geojson"
import MapCenterDetails from "./MapCenterDetails.svelte"
export let state: ThemeViewState
export let featuresInViewPort: Store<Feature[]>
console.log("Visual feedback panel:", featuresInViewPort)
const t = Translations.t.general.visualFeedback
let map = state.mapProperties
let centerFeatures = state.closestFeatures.features
let translationWithLength = centerFeatures.mapD(cf => cf.length).mapD(n => {
if (n === 1) {
return t.oneFeatureInView
}
return t.closestFeaturesAre.Subs({ n })
})
let lastAction: UIEventSource<KeyNavigationEvent> = new UIEventSource<KeyNavigationEvent>(
undefined
undefined,
)
state.mapProperties.onKeyNavigationEvent((event) => {
lastAction.setData(event)
@ -26,17 +32,23 @@
lastAction.stabilized(750).addCallbackAndRunD((_) => lastAction.setData(undefined))
</script>
<div aria-live="assertive" class="p-1" role="alert">
{#if $lastAction !== undefined}
<div aria-live="assertive" class="p-1 interactive" role="alert">
{#if $lastAction?.key === "out"}
<Tr t={t.out.Subs({z: map.zoom.data - 1})} />
{:else if $lastAction?.key === "in"}
<Tr t={t.out.Subs({z: map.zoom.data + 1})} />
{:else if $lastAction !== undefined}
<Tr t={t[$lastAction.key]} />
{:else if $centerFeatures.length === 0}
{:else if $centerFeatures?.length === 0}
<Tr t={t.noCloseFeatures} />
{:else}
<MapCenterDetails {state} />
{:else if $centerFeatures !== undefined}
<div class="pointer-events-auto">
<Tr t={t.closestFeaturesAre.Subs({ n: $featuresInViewPort?.length })} />
<ol class="list-none">
{#each $centerFeatures as feat, i (feat.properties.id)}
<li class="flex">
<Tr t={$translationWithLength} />
<MapCenterDetails {state} />
<ol>
{#each $centerFeatures.slice(0, 9) as feat, i (feat.properties.id)}
<li>
<Summary {state} feature={feat} {i} />
</li>
{/each}