From fdde0aaeb3d6e1693787b55d73aa46271fc69dde Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 14 Dec 2023 18:25:35 +0100 Subject: [PATCH] A11y: add labels to previously unlabeled buttons, fix order --- assets/layers/food/food.json | 19 ++++++- assets/layers/icons/icons.json | 54 ++++++++++++++++--- langs/layers/en.json | 42 ++++++++++++++- langs/layers/nl.json | 42 +++++++++++++++ public/css/index-tailwind-output.css | 23 ++------ src/Logic/ImageProviders/Mapillary.ts | 12 ++--- src/Logic/ImageProviders/MapillaryIcon.svelte | 21 ++++++++ src/UI/Base/Link.svelte | 12 +++++ src/UI/Base/Link.ts | 1 - src/UI/Base/MapControlButton.svelte | 4 ++ src/UI/Base/ShareButton.svelte | 4 +- .../OpenBackgroundSelectorButton.svelte | 3 +- .../BigComponents/SelectedElementTitle.svelte | 7 ++- src/UI/BigComponents/ThemeButton.svelte | 2 +- src/UI/Image/ImageAttribution.svelte | 2 +- src/UI/InputElement/InputHelper.svelte | 3 ++ src/UI/Popup/MarkAsFavouriteMini.svelte | 41 +++++++------- src/UI/SpecialVisualizations.ts | 38 +++++++------ src/UI/Test.svelte | 8 ++- src/UI/ThemeViewGUI.svelte | 32 +++++++---- src/Utils/ariaLabel.ts | 3 ++ 21 files changed, 287 insertions(+), 86 deletions(-) create mode 100644 src/Logic/ImageProviders/MapillaryIcon.svelte create mode 100644 src/UI/Base/Link.svelte diff --git a/assets/layers/food/food.json b/assets/layers/food/food.json index 138498c46..faa7b2a7e 100644 --- a/assets/layers/food/food.json +++ b/assets/layers/food/food.json @@ -524,7 +524,7 @@ }, { "id": "Reservation", - "condition": "amenity=restaurant", + "condition": "takeaway=only", "question": { "en": "Is a reservation required for this place?", "nl": "Is reserveren verplicht voor deze zaak?", @@ -581,7 +581,8 @@ "cs": "Rezervace na tomto místě není možná" } } - ] + ], + "#condition": "If one can only do takeaway or deliveries, it is nonsensical to ask if a 'reservation' is possible" }, { "question": { @@ -731,6 +732,13 @@ "pl": "Wszystkie dania są wegetariańskie", "cs": "Všechna jídla jsou vegetariánská" } + }, + { + "if": "diet:vegetarian=on_demand", + "then": { + "en": "Some dishes might be adapted to a vegetarian version, but this should be demanded", + "nl": "Sommige gerechten kunnen op vraag vegetarisch gemaakt worden" + } } ], "condition": "cuisine!=friture", @@ -798,6 +806,13 @@ "pl": "Wszystkie dania są wegańskie", "cs": "Všechna jídla jsou veganská" } + }, + { + "if": "diet:vegan=on_demand", + "then": { + "en": "Some dishes might be adapted to a vegan version if asked for", + "nl": "Op vraag kan een veganistische variant van een gerecht gemaakt worden" + } } ], "condition": "cuisine!=friture", diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json index 289172380..8d796b500 100644 --- a/assets/layers/icons/icons.json +++ b/assets/layers/icons/icons.json @@ -28,7 +28,7 @@ { "#": "ignore-image-in-then", "if": "wikipedia=", - "then": "WD" + "then": "Wikidata" } ] }, @@ -119,12 +119,32 @@ "defaults", "in_favourite" ], - "render": "phone", + "render": { + "special": { + "type": "link", + "href": "tel:{phone}", + "text": "phone", + "arialabel": { + "en": "phone", + "nl": "Telefoneer" + } + } + }, "mappings": [ { "#": "ignore-image-in-then", "if": "contact:phone~*", - "then": "phone" + "then": { + "special": { + "type": "link", + "href": "tel:{contact:phone}", + "text": "phone", + "arialabel": { + "en": "phone", + "nl": "Telefoneer" + } + } + } } ], "condition": { @@ -174,12 +194,12 @@ { "#": "ignore-image-in-then", "if": "smoking=no", - "then": "no-smoking" + "then": "no smoking" }, { "#": "ignore-image-in-then", "if": "smoking=yes", - "then": "smoking-allowed" + "then": "smoking allowed" } ] }, @@ -206,7 +226,17 @@ "labels": [ "defaults" ], - "render": "on osm", + "render": { + "special": { + "type": "link", + "text": "on osm", + "href": "https://openstreetmap.org/{id}", + "arialabel": { + "en": "Open on openstreetmap.org", + "nl": "Bekijk op openstreetmap.org" + } + } + }, "mappings": [ { "if": "id~.*/-.*", @@ -215,7 +245,17 @@ { "#": "ignore-image-in-then", "if": "_backend~*", - "then": "" + "then": { + "special": { + "type": "link", + "text": "on osm", + "href": "{_backend}/{id}", + "arialabel": { + "en": "Open on openstreetmap.org", + "nl": "Bekijk op openstreetmap.org" + } + } + } } ], "condition": "id~(node|way|relation)/[0-9]*" diff --git a/langs/layers/en.json b/langs/layers/en.json index 5b3b1584a..2c24b45eb 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -4721,6 +4721,9 @@ }, "3": { "then": "All dishes are vegan" + }, + "4": { + "then": "Some dishes might be adapted to a vegan version if asked for" } }, "question": "Does this business serve vegan meals?" @@ -4738,6 +4741,9 @@ }, "3": { "then": "All dishes are vegetarian" + }, + "4": { + "then": "Some dishes might be adapted to a vegetarian version, but this should be demanded" } }, "question": "Does this restaurant have a vegetarian option?" @@ -5252,7 +5258,41 @@ } }, "icons": { - "description": "A layer acting as library for icon-tagrenderings, especially to show as badge next to a POI" + "description": "A layer acting as library for icon-tagrenderings, especially to show as badge next to a POI", + "tagRenderings": { + "osmlink": { + "mappings": { + "1": { + "then": { + "special": { + "arialabel": "Open on openstreetmap.org" + } + } + } + }, + "render": { + "special": { + "arialabel": "Open on openstreetmap.org" + } + } + }, + "phonelink": { + "mappings": { + "0": { + "then": { + "special": { + "arialabel": "phone" + } + } + } + }, + "render": { + "special": { + "arialabel": "phone" + } + } + } + } }, "indoors": { "description": "Basic indoor mapping: shows room outlines", diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 1c70aaae9..0fad0cecf 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -4190,6 +4190,9 @@ }, "3": { "then": "Enkel veganistische opties zijn beschikbaar" + }, + "4": { + "then": "Op vraag kan een veganistische variant van een gerecht gemaakt worden" } }, "question": "Heeft deze eetgelegenheid een veganistische optie?" @@ -4207,6 +4210,9 @@ }, "3": { "then": "Enkel vegetarische opties zijn beschikbaar" + }, + "4": { + "then": "Sommige gerechten kunnen op vraag vegetarisch gemaakt worden" } }, "question": "Heeft deze eetgelegenheid een vegetarische optie?" @@ -4654,6 +4660,42 @@ } } }, + "icons": { + "tagRenderings": { + "osmlink": { + "mappings": { + "1": { + "then": { + "special": { + "arialabel": "Bekijk op openstreetmap.org" + } + } + } + }, + "render": { + "special": { + "arialabel": "Bekijk op openstreetmap.org" + } + } + }, + "phonelink": { + "mappings": { + "0": { + "then": { + "special": { + "arialabel": "Telefoneer" + } + } + } + }, + "render": { + "special": { + "arialabel": "Telefoneer" + } + } + } + } + }, "indoors": { "description": "Een basis voor indoor-navigatie: toont binnenruimtes", "name": "Binnenruimtes", diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 4c85fba79b..ee3b5cd6f 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -886,16 +886,6 @@ video { margin-right: 0.25rem; } -.mx-10 { - margin-left: 2.5rem; - margin-right: 2.5rem; -} - -.my-3 { - margin-top: 0.75rem; - margin-bottom: 0.75rem; -} - .mx-12 { margin-left: 3rem; margin-right: 3rem; @@ -969,10 +959,6 @@ video { margin-left: 1rem; } -.mb-10 { - margin-bottom: 2.5rem; -} - .mt-8 { margin-top: 2rem; } @@ -1529,10 +1515,6 @@ video { justify-self: end; } -.justify-self-center { - justify-self: center; -} - .overflow-auto { overflow: auto; } @@ -1935,6 +1917,11 @@ video { line-height: 2.5rem; } +.text-5xl { + font-size: 3rem; + line-height: 1; +} + .font-extrabold { font-weight: 800; } diff --git a/src/Logic/ImageProviders/Mapillary.ts b/src/Logic/ImageProviders/Mapillary.ts index f08a05246..8f7e1c97a 100644 --- a/src/Logic/ImageProviders/Mapillary.ts +++ b/src/Logic/ImageProviders/Mapillary.ts @@ -1,10 +1,10 @@ import ImageProvider, { ProvidedImage } from "./ImageProvider" import BaseUIElement from "../../UI/BaseUIElement" -import Svg from "../../Svg" import { Utils } from "../../Utils" import { LicenseInfo } from "./LicenseInfo" import Constants from "../../Models/Constants" -import Link from "../../UI/Base/Link" +import SvelteUIElement from "../../UI/Base/SvelteUIElement" +import MapillaryIcon from "./MapillaryIcon.svelte" export class Mapillary extends ImageProvider { public static readonly singleton = new Mapillary() @@ -112,11 +112,11 @@ export class Mapillary extends ImageProvider { lat: number } ): BaseUIElement { - const icon = Svg.mapillary_svg() - if (!id) { - return icon + let url: string = undefined + if (id) { + url = Mapillary.createLink(location, 16, "" + id) } - return new Link(icon, Mapillary.createLink(location, 16, "" + id), true) + return new SvelteUIElement(MapillaryIcon, { url }) } async ExtractUrls(key: string, value: string): Promise[]> { diff --git a/src/Logic/ImageProviders/MapillaryIcon.svelte b/src/Logic/ImageProviders/MapillaryIcon.svelte new file mode 100644 index 000000000..44a3d1bf1 --- /dev/null +++ b/src/Logic/ImageProviders/MapillaryIcon.svelte @@ -0,0 +1,21 @@ + + +{#if url} + + + +{:else} + +{/if} diff --git a/src/UI/Base/Link.svelte b/src/UI/Base/Link.svelte new file mode 100644 index 000000000..88fb55ee3 --- /dev/null +++ b/src/UI/Base/Link.svelte @@ -0,0 +1,12 @@ + + + + {@html text} diff --git a/src/UI/Base/Link.ts b/src/UI/Base/Link.ts index f3474f27f..4a600fea0 100644 --- a/src/UI/Base/Link.ts +++ b/src/UI/Base/Link.ts @@ -1,7 +1,6 @@ import Translations from "../i18n/Translations" import BaseUIElement from "../BaseUIElement" import { Store } from "../../Logic/UIEventSource" -import { Utils } from "../../Utils" export default class Link extends BaseUIElement { private readonly _href: string | Store diff --git a/src/UI/Base/MapControlButton.svelte b/src/UI/Base/MapControlButton.svelte index 4bc4bf0d3..64f8a575a 100644 --- a/src/UI/Base/MapControlButton.svelte +++ b/src/UI/Base/MapControlButton.svelte @@ -1,17 +1,21 @@ {/if} diff --git a/src/UI/BigComponents/ThemeButton.svelte b/src/UI/BigComponents/ThemeButton.svelte index 9a29a5d2f..c5bea027f 100644 --- a/src/UI/BigComponents/ThemeButton.svelte +++ b/src/UI/BigComponents/ThemeButton.svelte @@ -92,7 +92,7 @@ {#if selected} - + {/if} diff --git a/src/UI/Image/ImageAttribution.svelte b/src/UI/Image/ImageAttribution.svelte index b9022f8a2..0fad16aff 100644 --- a/src/UI/Image/ImageAttribution.svelte +++ b/src/UI/Image/ImageAttribution.svelte @@ -26,7 +26,7 @@
{#if $license.title} {#if $license.informationLocation} - {$license.title} + {$license.title} {:else} $license.title {/if} diff --git a/src/UI/InputElement/InputHelper.svelte b/src/UI/InputElement/InputHelper.svelte index 27bc2bfdf..154149b49 100644 --- a/src/UI/InputElement/InputHelper.svelte +++ b/src/UI/InputElement/InputHelper.svelte @@ -18,6 +18,7 @@ import DateInput from "./Helpers/DateInput.svelte" import ColorInput from "./Helpers/ColorInput.svelte" import OpeningHoursInput from "./Helpers/OpeningHoursInput.svelte" + import SlopeInput from "./Helpers/SlopeInput.svelte" export let type: ValidatorType export let value: UIEventSource @@ -47,6 +48,8 @@ {:else if type === "opening_hours"} +{:else if type === "slope"} + {:else if type === "wikidata"} InputHelpers.constructWikidataHelper(value, properties)} /> {/if} diff --git a/src/UI/Popup/MarkAsFavouriteMini.svelte b/src/UI/Popup/MarkAsFavouriteMini.svelte index b8d242aac..1f880690e 100644 --- a/src/UI/Popup/MarkAsFavouriteMini.svelte +++ b/src/UI/Popup/MarkAsFavouriteMini.svelte @@ -1,36 +1,39 @@ {#if $isFavourite} - {:else} - {/if} diff --git a/src/UI/SpecialVisualizations.ts b/src/UI/SpecialVisualizations.ts index 1cf93abd0..45afaf86d 100644 --- a/src/UI/SpecialVisualizations.ts +++ b/src/UI/SpecialVisualizations.ts @@ -45,7 +45,6 @@ import { GeoOperations } from "../Logic/GeoOperations" import CreateNewNote from "./Popup/CreateNewNote.svelte" import AddNewPoint from "./Popup/AddNewPoint/AddNewPoint.svelte" import UserProfile from "./BigComponents/UserProfile.svelte" -import Link from "./Base/Link" import LayerConfig from "../Models/ThemeConfig/LayerConfig" import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig" import { WayId } from "../Models/OsmFeature" @@ -81,9 +80,9 @@ import MarkAsFavouriteMini from "./Popup/MarkAsFavouriteMini.svelte" import NextChangeViz from "./OpeningHours/NextChangeViz.svelte" import NearbyImages from "./Image/NearbyImages.svelte" import NearbyImagesCollapsed from "./Image/NearbyImagesCollapsed.svelte" -import { svelte } from "@sveltejs/vite-plugin-svelte" import MoveWizard from "./Popup/MoveWizard.svelte" import { Unit } from "../Models/Unit" +import Link from "./Base/Link.svelte" class NearbyImageVis implements SpecialVisualization { // Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests @@ -1288,6 +1287,10 @@ export default class SpecialVisualizations { name: "download", doc: "If set, this link will act as a download-button. The contents of `href` will be offered for download; this parameter will act as the proposed filename", }, + { + name: "arialabel", + doc: "If set, this text will be used as aria-label", + }, ], needsUrls: [], constr( @@ -1295,15 +1298,19 @@ export default class SpecialVisualizations { tagSource: UIEventSource>, args: string[] ): BaseUIElement { - const [text, href, classnames, download] = args + const [text, href, classnames, download, ariaLabel] = args + const newTab = download === undefined && !href.startsWith("#") return new VariableUiElement( - tagSource.map((tags) => - new Link( - Utils.SubstituteKeys(text, tags), - Utils.SubstituteKeys(href, tags), - download === undefined && !href.startsWith("#"), - Utils.SubstituteKeys(download, tags) - ).SetClass(classnames) + tagSource.map( + (tags) => + new SvelteUIElement(Link, { + text: Utils.SubstituteKeys(text, tags), + href: Utils.SubstituteKeys(href, tags), + classnames, + download: Utils.SubstituteKeys(download, tags), + ariaLabel: Utils.SubstituteKeys(ariaLabel, tags), + newTab, + }) ) ) }, @@ -1422,12 +1429,11 @@ export default class SpecialVisualizations { const [_, username, host] = fediAccount.match( FediverseValidator.usernameAtServer ) - - return new Link( - fediAccount, - "https://" + host + "/@" + username, - true - ) + return new SvelteUIElement(Link, { + text: fediAccount, + url: "https://" + host + "/@" + username, + newTab: true, + }) }) ) }, diff --git a/src/UI/Test.svelte b/src/UI/Test.svelte index ac4f5dde9..8d1c7b4d9 100644 --- a/src/UI/Test.svelte +++ b/src/UI/Test.svelte @@ -1,5 +1,11 @@ -
No tests
+
+
Value: {$value}
+
+ diff --git a/src/UI/ThemeViewGUI.svelte b/src/UI/ThemeViewGUI.svelte index 1ffaf0e24..5f3318018 100644 --- a/src/UI/ThemeViewGUI.svelte +++ b/src/UI/ThemeViewGUI.svelte @@ -64,10 +64,10 @@ import Share from "../assets/svg/Share.svelte" import Favourites from "./Favourites/Favourites.svelte" import ImageOperations from "./Image/ImageOperations.svelte" + import { ariaLabel } from "../Utils/ariaLabel" export let state: ThemeViewState let layout = state.layout - let maplibremap: UIEventSource = state.map let selectedElement: UIEventSource = new UIEventSource(undefined) @@ -142,7 +142,8 @@
- state.guistate.themeIsOpened.setData(true)} on:keydown={forwardEventToMap}> + state.guistate.themeIsOpened.setData(true)} + on:keydown={forwardEventToMap}>
@@ -150,15 +151,19 @@
- state.guistate.menuIsOpened.setData(true)} on:keydown={forwardEventToMap}> + state.guistate.menuIsOpened.setData(true)} + on:keydown={forwardEventToMap} + arialabel={Translations.t.general.labels.menu} + > {#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()} { selectedElement.setData(state.currentView.features?.data?.[0]) - }} on:keydown={forwardEventToMap} - + }} + on:keydown={forwardEventToMap} > currentViewLayer.defaultIcon().SetClass("w-8 h-8 cursor-pointer")} @@ -206,7 +211,9 @@
- state.guistate.openFilterView()} on:keydown={forwardEventToMap}> + state.guistate.openFilterView()} on:keydown={forwardEventToMap} + arialabel={Translations.t.general.labels.filter} + > @@ -246,14 +253,21 @@ />
- mapproperties.zoom.update((z) => z + 1)} on:keydown={forwardEventToMap}> + mapproperties.zoom.update((z) => z + 1)} + on:keydown={forwardEventToMap} + arialabel={Translations.t.general.labels.zoomIn} + > - mapproperties.zoom.update((z) => z - 1)} on:keydown={forwardEventToMap}> + mapproperties.zoom.update((z) => z - 1)} on:keydown={forwardEventToMap} + arialabel={Translations.t.general.labels.zoomOut} + > - geolocationControl.handleClick()}> + geolocationControl.handleClick()} + arialabel={Translations.t.general.labels.jumpToLocation} + > diff --git a/src/Utils/ariaLabel.ts b/src/Utils/ariaLabel.ts index 360f0e4ea..2b355e740 100644 --- a/src/Utils/ariaLabel.ts +++ b/src/Utils/ariaLabel.ts @@ -1,6 +1,9 @@ import { Translation } from "../UI/i18n/Translation" export function ariaLabel(htmlElement: Element, t: Translation) { + if (!t) { + return + } let destroy: () => void = undefined t.current.map(