diff --git a/assets/layers/questions/questions.json b/assets/layers/questions/questions.json
index 0618c5459..28c768a51 100644
--- a/assets/layers/questions/questions.json
+++ b/assets/layers/questions/questions.json
@@ -189,6 +189,10 @@
"addExtraTags": [
"contact:phone="
]
+ },
+ "editButtonAriaLabel": {
+ "en": "Edit phone number",
+ "nl": "Pas telefoonnummer aan"
}
},
{
@@ -268,6 +272,10 @@
"addExtraTags": [
"contact:email="
]
+ },
+ "editButtonAriaLabel": {
+ "en": "Edit email address",
+ "nl": "Pas emailadres aan"
}
},
{
@@ -318,7 +326,11 @@
"hideInAnswer": true,
"icon": "./assets/layers/icons/website.svg"
}
- ]
+ ],
+ "editButtonAriaLabel": {
+ "en": "Edit website",
+ "nl": "Pas website aan"
+ }
},
{
"id": "wheelchair-access",
@@ -2215,7 +2227,7 @@
}
}
]
- },
+ },
{
"id": "internet-ssid",
"labels": [
diff --git a/langs/en.json b/langs/en.json
index aacb72dad..54d7581ab 100644
--- a/langs/en.json
+++ b/langs/en.json
@@ -306,7 +306,7 @@
"sunday": "On sunday {ranges}",
"thursday": "On thursday {ranges}",
"tuesday": "On tuesday {ranges}",
- "unknown": "The opening hours are unkown",
+ "unknown": "The opening hours are unknown",
"wednesday": "On wednesday {ranges}"
},
"osmLinkTooltip": "Browse this object on OpenStreetMap for history and more editing options",
@@ -398,12 +398,12 @@
"useSearch": "Use the search above to see presets",
"useSearchForMore": "Use the search function to search within {total} more values…",
"visualFeedback": {
- "closestFeaturesAre": "Closest features are:",
+ "closestFeaturesAre": "{n} features within view",
"east": "Moving east",
"in": "Zooming in",
"islocked": "View locked to your GPS-location, moving disabled. Press the geolocation button to unlock.",
"locked": "View is now locked to your GPS-location, moving disabled.",
- "navigation": "Use arrow keys to move the map, press space to select the closest feature",
+ "navigation": "Use arrow keys to move the map, press space to select the closest feature. Press a number to select locations further away.",
"noCloseFeatures": "No features in view",
"north": "Moving north",
"out": "Zooming out",
diff --git a/langs/nl.json b/langs/nl.json
index 178893e8d..ba84f8cc4 100644
--- a/langs/nl.json
+++ b/langs/nl.json
@@ -50,6 +50,12 @@
"panelIntro": "
Jouw persoonlijke thema
Activeer je favorite lagen van alle andere themas",
"reload": "Herlaad de data"
},
+ "favouritePoi": {
+ "button": {
+ "isMarkedShort": "Als favoriet gemarkeerd",
+ "isNotMarkedShort": "Niet als favoriet gemarkeerd"
+ }
+ },
"flyer": {
"aerial": "Deze kaart gebruikt luchtfoto's van het Agentschap Informatie Vlaanderen als achtergrond.\nOok het GRB is beschikbaar als achtergrondlaag.",
"callToAction": "Probeer het uit op mapcomplete.org",
@@ -162,6 +168,7 @@
},
"back": "Vorige",
"backToIndex": "Keer terug naar het overzicht met alle thematische kaarten",
+ "backToMap": "Ga terug naar de kaart",
"backgroundMap": "Selecteer een achtergrondlaag",
"backgroundSwitch": "Verander achtergrond",
"cancel": "Annuleren",
@@ -200,6 +207,14 @@
"histogram": {
"error_loading": "Kan het histogram niet laden"
},
+ "labels": {
+ "background": "Kies achtergrondlaag",
+ "filter": "Filter data",
+ "jumpToLocation": "Ga naar jouw locatie",
+ "menu": "Menu",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom uit"
+ },
"layerSelection": {
"title": "Selecteer lagen",
"zoomInToSeeThisLayer": "Vergroot de kaart om deze laag te zien"
@@ -245,11 +260,17 @@
"openTheMap": "Raadpleeg de kaart",
"openTheMapAtGeolocation": "Ga naar jouw locatie",
"opening_hours": {
+ "all_days_from": "Elke dag geopend {ranges}",
"closed_permanently": "Gesloten voor onbepaalde tijd",
"closed_until": "Gesloten - open op {date}",
+ "error": "Kan de openingsuren niet inlezen",
"error_loading": "Sorry, deze openingsuren kunnen niet getoond worden",
+ "friday": "Op vrijdag {ranges}",
"loadingCountry": "Het land wordt nog bepaald…",
+ "monday": "Op maandag {ranges}",
"not_all_rules_parsed": "De openingsuren zijn ingewikkeld. De volgende regels worden niet getoond bij het ingeven:",
+ "on_weekdays": "Op weekdagen {ranges}",
+ "on_weekends": "In het weekend {ranges}",
"openTill": "tot",
"open_24_7": "Dag en nacht open",
"open_during_ph": "Op een feestdag is dit",
@@ -257,7 +278,15 @@
"ph_closed": "gesloten",
"ph_not_known": " ",
"ph_open": "open",
- "ph_open_as_usual": "geopend zoals gewoonlijk"
+ "ph_open_as_usual": "geopend zoals gewoonlijk",
+ "ranges": "van {starttime} tot {endtime}",
+ "rangescombined": "{range0} en {range1}",
+ "saturday": "Op zaterdag {ranges}",
+ "sunday": "Op zondag {ranges}",
+ "thursday": "Op donderdag {ranges}",
+ "tuesday": "Op dinsdag {ranges}",
+ "unknown": "De openingsuren zijn niet gekend",
+ "wednesday": "Op woensdag {ranges}"
},
"osmLinkTooltip": "Bekijk dit object op OpenStreetMap om de geschiedenis te zien en meer te kunnen aanpassen",
"pdf": {
@@ -300,6 +329,7 @@
"searchShort": "Zoek…",
"searching": "Aan het zoeken…"
},
+ "share": "Deel deze locatie",
"sharescreen": {
"copiedToClipboard": "Link gekopieerd naar klembord",
"embedIntro": "
Plaats dit op je website
Voeg dit kaartje toe op je eigen website. We moedigen dit zelfs aan - je hoeft geen toestemming te vragen. Het is gratis en zal dat altijd blijven. Hoe meer het gebruikt wordt, hoe waardevoller",
@@ -340,6 +370,20 @@
},
"useSearch": "Gebruik de zoekfunctie hierboven om meer opties te zien",
"useSearchForMore": "Gebruik de zoekfunctie om {total} meer waarden te vinden…",
+ "visualFeedback": {
+ "closestFeaturesAre": "{n} object in in beeld",
+ "east": "Naar het oosten",
+ "in": "Aan het inzoomen",
+ "islocked": "Bewegen vergrendeld rond je huidige locatie. Duw op de geolocatie-knop om te ontgrendelen.",
+ "locked": "Bewegen vergrendeld rond jouw huidige locatie.",
+ "navigation": "Gebruik de pijltjestoetsen om te bewegen. Druk op spatie om het meest centrale punt te selecteren. Druk op een cijfertoets om andere items te selecteren.",
+ "noCloseFeatures": "Niet in beeld",
+ "north": "Naar het noorden",
+ "out": "Aan het uitzoomen",
+ "south": "Naar het zuiden",
+ "unlocked": "Bewegen ontgrendeld",
+ "west": "Naar het westen"
+ },
"weekdays": {
"abbreviations": {
"friday": "Vrij",
diff --git a/package.json b/package.json
index 0d6bd5f6b..f60304fc5 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"https://overpass.openstreetmap.ru/cgi/interpreter"
],
"country_coder_host": "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/latlon2country",
- "nominatimEndpoint": "https://nominatim.openstreetmap.org/search?"
+ "nominatimEndpoint": "https://nominatim.openstreetmap.org/"
},
"scripts": {
"start": "npm run generate:layeroverview && npm run strt",
diff --git a/src/Logic/Osm/Geocoding.ts b/src/Logic/Osm/Geocoding.ts
index d3af5d6a5..0818c792f 100644
--- a/src/Logic/Osm/Geocoding.ts
+++ b/src/Logic/Osm/Geocoding.ts
@@ -1,6 +1,7 @@
import { Utils } from "../../Utils"
import { BBox } from "../BBox"
import Constants from "../../Models/Constants"
+import { FeatureCollection } from "geojson"
export interface GeoCodeResult {
display_name: string
@@ -20,12 +21,21 @@ export class Geocoding {
static async Search(query: string, bbox: BBox): Promise {
const b = bbox ?? BBox.global
- const url =
- Geocoding.host +
- "format=json&limit=1&viewbox=" +
- `${b.getEast()},${b.getNorth()},${b.getWest()},${b.getSouth()}` +
- "&accept-language=nl&q=" +
- query
+ const url = `${
+ Geocoding.host
+ }search?format=json&limit=1&viewbox=${b.getEast()},${b.getNorth()},${b.getWest()},${b.getSouth()}&accept-language=nl&q=${query}`
+ return Utils.downloadJson(url)
+ }
+
+ static async reverse(
+ coordinate: { lon: number; lat: number },
+ zoom: number = 18
+ ): Promise {
+ // https://nominatim.org/release-docs/develop/api/Reverse/
+ // IF the zoom is low, it'll only return a country instead of an address
+ const url = `${Geocoding.host}reverse?format=geojson&lat=${coordinate.lat}&lon=${
+ coordinate.lon
+ }&zoom=${Math.round(zoom)}`
return Utils.downloadJson(url)
}
}
diff --git a/src/Models/MapProperties.ts b/src/Models/MapProperties.ts
index 8e905155a..73ec1b413 100644
--- a/src/Models/MapProperties.ts
+++ b/src/Models/MapProperties.ts
@@ -16,6 +16,7 @@ export interface MapProperties {
readonly maxbounds: UIEventSource
readonly allowMoving: UIEventSource
readonly allowRotating: UIEventSource
+ readonly rotation: UIEventSource
readonly lastClickLocation: Store<{ lon: number; lat: number }>
readonly allowZooming: UIEventSource
diff --git a/src/Models/MenuState.ts b/src/Models/MenuState.ts
index a64c05a0a..58c2c356a 100644
--- a/src/Models/MenuState.ts
+++ b/src/Models/MenuState.ts
@@ -14,13 +14,7 @@ export type MenuViewTabStates = (typeof MenuState._menuviewTabs)[number]
* Some convenience methods are provided for this as well
*/
export class MenuState {
- public static readonly _themeviewTabs = [
- "intro",
- "filters",
- "download",
- "copyright",
- "share",
- ] as const
+ public static readonly _themeviewTabs = ["intro", "download", "copyright", "share"] as const
public static readonly _menuviewTabs = [
"about",
"settings",
@@ -39,6 +33,8 @@ export class MenuState {
public readonly backgroundLayerSelectionIsOpened: UIEventSource =
new UIEventSource(false)
+ public readonly filtersPanelIsOpened: UIEventSource = new UIEventSource(false)
+
public readonly allToggles: {
toggle: UIEventSource
name: string
@@ -84,8 +80,8 @@ export class MenuState {
this.highlightedUserSetting.setData(undefined)
}
})
- this.themeViewTab.addCallbackAndRun((tab) => {
- if (tab !== "filters") {
+ this.filtersPanelIsOpened.addCallbackAndRun((isOpen) => {
+ if (!isOpen) {
this.highlightedLayerInFilters.setData(undefined)
}
})
@@ -121,8 +117,7 @@ export class MenuState {
}
public openFilterView(highlightLayer?: LayerConfig | string) {
- this.themeIsOpened.setData(true)
- this.themeViewTab.setData("filters")
+ this.filtersPanelIsOpened.setData(true)
if (highlightLayer) {
if (typeof highlightLayer !== "string") {
highlightLayer = highlightLayer.id
@@ -159,6 +154,7 @@ export class MenuState {
this.menuIsOpened,
this.themeIsOpened,
this.backgroundLayerSelectionIsOpened,
+ this.filtersPanelIsOpened,
]
const somethingIsOpen = toggles.some((t) => t.data)
toggles.forEach((t) => t.setData(false))
diff --git a/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts
index 85eb7c2c3..241d24c67 100644
--- a/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts
+++ b/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts
@@ -279,6 +279,13 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
*/
questionHint?: Translatable
+ /**
+ * When using a screenreader and selecting the 'edit' button, the current rendered value is read aloud in normal circumstances.
+ * In some rare cases, this is not desirable. For example, if the rendered value is a link to a website, this link can be selected (and will be read aloud).
+ * If the user presses _tab_ again, they'll select the button and have the link read aloud a second time.
+ */
+ editButtonAriaLabel?: Translatable
+
/**
* A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer
*/
diff --git a/src/Models/ThemeConfig/TagRenderingConfig.ts b/src/Models/ThemeConfig/TagRenderingConfig.ts
index 17c840489..a7c445706 100644
--- a/src/Models/ThemeConfig/TagRenderingConfig.ts
+++ b/src/Models/ThemeConfig/TagRenderingConfig.ts
@@ -76,6 +76,7 @@ export default class TagRenderingConfig {
public readonly multiAnswer: boolean
public readonly mappings?: Mapping[]
+ public readonly editButtonAriaLabel?: Translation
public readonly labels: string[]
public readonly classes: string[]
@@ -134,6 +135,11 @@ export default class TagRenderingConfig {
this.question = Translations.T(json.question, translationKey + ".question")
this.questionhint = Translations.T(json.questionHint, translationKey + ".questionHint")
this.description = Translations.T(json.description, translationKey + ".description")
+ this.editButtonAriaLabel = Translations.T(
+ json.editButtonAriaLabel,
+ translationKey + ".editButtonAriaLabel"
+ )
+
this.condition = TagUtils.Tag(json.condition ?? { and: [] }, `${context}.condition`)
this.invalidValues = json["invalidValues"]
? TagUtils.Tag(json["invalidValues"], `${context}.invalidValues`)
diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts
index 24e399797..4d757889d 100644
--- a/src/Models/ThemeViewState.ts
+++ b/src/Models/ThemeViewState.ts
@@ -61,6 +61,7 @@ import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSou
import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource"
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
+import { Orientation } from "../Sensors/Orientation"
/**
*
@@ -115,8 +116,6 @@ export default class ThemeViewState implements SpecialVisualizationState {
readonly geolocation: GeoLocationHandler
readonly geolocationControl: GeolocationControlState
- readonly lastGeolocationRequestMoment: UIEventSource = new UIEventSource(undefined)
-
readonly imageUploadManager: ImageUploadManager
readonly previewedImage = new UIEventSource(undefined)
diff --git a/src/Sensors/Motion.ts b/src/Sensors/Motion.ts
new file mode 100644
index 000000000..bedd2dbb4
--- /dev/null
+++ b/src/Sensors/Motion.ts
@@ -0,0 +1,33 @@
+import { UIEventSource } from "../Logic/UIEventSource"
+
+export default class Motion {
+ public static singleton = new Motion()
+ /**
+ * In m/s²
+ */
+ public maxAcc = new UIEventSource(0)
+
+ public lastShakeEvent = new UIEventSource(undefined)
+
+ private isListening = false
+ private constructor() {
+ this.startListening()
+ }
+
+ private onUpdate(eventData: DeviceMotionEvent) {
+ const acc = eventData.acceleration
+ this.maxAcc.setData(Math.max(acc.x, acc.y, acc.z))
+ if (this.maxAcc.data > 22) {
+ this.lastShakeEvent.setData(new Date())
+ }
+ }
+
+ startListening() {
+ if (this.isListening) {
+ return
+ }
+ this.isListening = true
+ console.log("Listening to motion events", this)
+ window.addEventListener("devicemotion", (e) => this.onUpdate(e))
+ }
+}
diff --git a/src/Sensors/Orientation.ts b/src/Sensors/Orientation.ts
index 149fdfeb8..df789a2c8 100644
--- a/src/Sensors/Orientation.ts
+++ b/src/Sensors/Orientation.ts
@@ -30,9 +30,13 @@ export class Orientation {
*/
public arrowDirection: UIEventSource = new UIEventSource(undefined)
private _measurementsStarted = false
+ private _animateFakeMeasurements = false
- constructor() {}
+ constructor() {
+ // this.fakeMeasurements(true)
+ }
+ // noinspection JSUnusedGlobalSymbols
public fakeMeasurements(rotateAlpha: boolean = true) {
console.log("Starting fake measurements of orientation sensors", {
alpha: this.alpha,
@@ -41,10 +45,15 @@ export class Orientation {
absolute: this.absolute,
})
this.alpha.setData(45)
+
if (rotateAlpha) {
- Stores.Chronic(25).addCallback((date) =>
- this.alpha.setData(-(date.getTime() / 10) % 360)
- )
+ this._animateFakeMeasurements = true
+ Stores.Chronic(25).addCallback((date) => {
+ this.alpha.setData((date.getTime() / 100) % 360)
+ if (!this._animateFakeMeasurements) {
+ return true
+ }
+ })
}
this.beta.setData(20)
this.gamma.setData(30)
diff --git a/src/UI/BigComponents/FilterPanel.svelte b/src/UI/BigComponents/FilterPanel.svelte
new file mode 100644
index 000000000..5799d39cb
--- /dev/null
+++ b/src/UI/BigComponents/FilterPanel.svelte
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+ {#each layout.layers as layer}
+
+ {/each}
+ {#each layout.tileLayerSources as tilesource}
+
+ {/each}
+