diff --git a/package-lock.json b/package-lock.json index df38ae4be..0b4f787c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "mapcomplete", - "version": "0.36.1", + "version": "0.36.2", "license": "GPL-3.0-or-later", "dependencies": { "@rgossiaux/svelte-headlessui": "^1.0.2", @@ -56,6 +56,7 @@ "svg-path-parser": "^1.1.0", "tailwind-merge": "^1.13.1", "tailwindcss": "^3.1.8", + "trap-focus-svelte": "^1.0.1", "vite-node": "^0.28.3", "vitest": "^0.28.3", "wikibase-sdk": "^7.14.0", @@ -12140,6 +12141,11 @@ "node": ">=14" } }, + "node_modules/trap-focus-svelte": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trap-focus-svelte/-/trap-focus-svelte-1.0.1.tgz", + "integrity": "sha512-qacSd68+c12mudUu9Mo70Ea16263ich2APFh1d0K7k9rLtwNcxlxNqA6l7Wv7xdzhJbC9TASxroiDSkiN2349w==" + }, "node_modules/ts-api-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", @@ -22659,6 +22665,11 @@ "punycode": "^2.3.0" } }, + "trap-focus-svelte": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trap-focus-svelte/-/trap-focus-svelte-1.0.1.tgz", + "integrity": "sha512-qacSd68+c12mudUu9Mo70Ea16263ich2APFh1d0K7k9rLtwNcxlxNqA6l7Wv7xdzhJbC9TASxroiDSkiN2349w==" + }, "ts-api-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", diff --git a/package.json b/package.json index 6d8c77521..695887074 100644 --- a/package.json +++ b/package.json @@ -143,6 +143,7 @@ "svg-path-parser": "^1.1.0", "tailwind-merge": "^1.13.1", "tailwindcss": "^3.1.8", + "trap-focus-svelte": "^1.0.1", "vite-node": "^0.28.3", "vitest": "^0.28.3", "wikibase-sdk": "^7.14.0", diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 6d74eb795..ce87e0e9f 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -1796,14 +1796,14 @@ video { padding: 0.25rem; } -.p-0\.5 { - padding: 0.125rem; -} - .p-0 { padding: 0px; } +.p-0\.5 { + padding: 0.125rem; +} + .p-12 { padding: 3rem; } @@ -2244,7 +2244,6 @@ body { .focusable { /* Not a 'real' class, but rather an indication to FloatOver and ModalRight to, when they open, grab the focus */ - border: 1px solid red } svg, diff --git a/scripts/generateImageAnalysis.ts b/scripts/generateImageAnalysis.ts index c704e8622..55095efc2 100644 --- a/scripts/generateImageAnalysis.ts +++ b/scripts/generateImageAnalysis.ts @@ -190,19 +190,45 @@ export default class GenerateImageAnalysis extends Script { if (!existsSync(viewDir)) { mkdirSync(viewDir) } + const targetpath = datapath + "/views.csv" + const total = allImages.size + let dloaded = 0 + let skipped = 0 + let err = 0 for (const image of Array.from(allImages)) { - const cachedView = viewDir + "/" + image.replace(/\\/g, "_") + const cachedView = viewDir + "/" + image.replace(/\//g, "_") let attribution: LicenseInfo if (existsSync(cachedView)) { attribution = JSON.parse(readFileSync(cachedView, "utf8")) + skipped++ } else { - attribution = await Imgur.singleton.DownloadAttribution(image) - writeFileSync(cachedView, JSON.stringify(attribution)) + try { + attribution = await Imgur.singleton.DownloadAttribution(image) + await ScriptUtils.sleep(500) + writeFileSync(cachedView, JSON.stringify(attribution)) + dloaded++ + } catch (e) { + err++ + continue + } } results.push([image, attribution.views]) + if (dloaded % 50 === 0) { + console.log({ + dloaded, + skipped, + total, + err, + progress: Math.round(dloaded + skipped + err), + }) + } + + if ((dloaded + skipped + err) % 100 === 0) { + console.log("Writing views to", targetpath) + fs.writeFileSync(targetpath, results.map((r) => r.join(",")).join("\n")) + } } - const targetpath = datapath + "/views.csv" console.log("Writing views to", targetpath) fs.writeFileSync(targetpath, results.map((r) => r.join(",")).join("\n")) } @@ -416,8 +442,8 @@ export default class GenerateImageAnalysis extends Script { const imageBackupPath = args[0] await this.downloadData(datapath, cached) - await this.downloadMetadata(datapath) await this.downloadViews(datapath) + await this.downloadMetadata(datapath) await this.downloadAllImages(datapath, imageBackupPath) this.analyze(datapath) } diff --git a/src/Logic/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts index 2fbbdc369..618ca31af 100644 --- a/src/Logic/State/UserRelatedState.ts +++ b/src/Logic/State/UserRelatedState.ts @@ -39,7 +39,7 @@ export default class UserRelatedState { public readonly installedUserThemes: Store public readonly showAllQuestionsAtOnce: UIEventSource public readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full"> - public readonly showCrosshair: UIEventSource<"yes" | undefined> + public readonly showCrosshair: UIEventSource<"yes" | "always" | "no" | undefined> public readonly fixateNorth: UIEventSource public readonly homeLocation: FeatureSource /** diff --git a/src/Models/Denomination.ts b/src/Models/Denomination.ts index 9dcdfc475..04368f733 100644 --- a/src/Models/Denomination.ts +++ b/src/Models/Denomination.ts @@ -1,10 +1,11 @@ import { Translation } from "../UI/i18n/Translation" import { DenominationConfigJson } from "./ThemeConfig/Json/UnitConfigJson" import Translations from "../UI/i18n/Translations" -import { Store } from "../Logic/UIEventSource" -import BaseUIElement from "../UI/BaseUIElement" -import Toggle from "../UI/Input/Toggle" +/** + * A 'denomination' is one way to write a certain quantity. + * For example, 'meter', 'kilometer', 'mile' and 'foot' are all possible ways to quantify 'length' + */ export class Denomination { public readonly canonical: string public readonly _canonicalSingular: string @@ -53,8 +54,8 @@ export class Denomination { /** * Create a representation of the given value - * @param value: the value from OSM - * @param actAsDefault: if set and the value can be parsed as number, will be parsed and trimmed + * @param value the value from OSM + * @param actAsDefault if set and the value can be parsed as number, will be parsed and trimmed * * const unit = new Denomination({ * canonicalDenomination: "m", @@ -82,6 +83,8 @@ export class Denomination { * unit.canonicalValue("42", true) // =>"42" * unit.canonicalValue("42 m", true) // =>"42" * unit.canonicalValue("42 meter", true) // =>"42" + * + * */ public canonicalValue(value: string, actAsDefault: boolean): string { if (value === undefined) { diff --git a/src/UI/Base/FloatOver.svelte b/src/UI/Base/FloatOver.svelte index 4b294ce9f..0ad3a8bc6 100644 --- a/src/UI/Base/FloatOver.svelte +++ b/src/UI/Base/FloatOver.svelte @@ -1,28 +1,35 @@ -
{ + +
{ dispatch("close") - }} + }}> +
+ +
{}}>
@@ -30,21 +37,23 @@
-
dispatch("close")} > -
+
+ + diff --git a/src/UI/Base/LoginToggle.svelte b/src/UI/Base/LoginToggle.svelte index 8684e1de4..dab8f8711 100644 --- a/src/UI/Base/LoginToggle.svelte +++ b/src/UI/Base/LoginToggle.svelte @@ -10,14 +10,14 @@ export let state: { osmConnection: OsmConnection - featureSwitches?: { featureSwitchUserbadge?: UIEventSource } + featureSwitches?: { featureSwitchEnableLogin?: UIEventSource } } /** * If set, 'loading' will act as if we are already logged in. */ export let ignoreLoading: boolean = false let loadingStatus = state?.osmConnection?.loadingStatus ?? new ImmutableStore("logged-in") - let badge = state?.featureSwitches?.featureSwitchUserbadge ?? new ImmutableStore(true) + let badge = state?.featureSwitches?.featureSwitchEnableLogin ?? new ImmutableStore(true) const t = Translations.t.general const offlineModes: Partial> = { offline: t.loginFailedOfflineMode, diff --git a/src/UI/Base/ModalRight.svelte b/src/UI/Base/ModalRight.svelte index 46b8c5121..78bc0e268 100644 --- a/src/UI/Base/ModalRight.svelte +++ b/src/UI/Base/ModalRight.svelte @@ -2,6 +2,7 @@ import { createEventDispatcher, onMount } from "svelte"; import { XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"; import { Utils } from "../../Utils"; + import { trapFocus } from 'trap-focus-svelte' /** * The slotted element will be shown on the right side @@ -13,13 +14,13 @@ onMount(() => { window.setTimeout( () => Utils.focusOnFocusableChild(mainContent), 250 - - ) - }) + ); + });
diff --git a/src/UI/BigComponents/SelectedElementView.svelte b/src/UI/BigComponents/SelectedElementView.svelte index bdec12a79..42ab7639c 100644 --- a/src/UI/BigComponents/SelectedElementView.svelte +++ b/src/UI/BigComponents/SelectedElementView.svelte @@ -14,10 +14,8 @@ export let selectedElement: Feature export let highlightedRendering: UIEventSource = undefined - let tags: UIEventSource> = state.featureProperties.getStore(selectedElement.properties.id) - $: { - tags = state.featureProperties.getStore(selectedElement.properties.id) - } + export let tags: UIEventSource> = state.featureProperties.getStore(selectedElement.properties.id) + let _metatags: Record onDestroy( state.userRelatedState.preferencesAsTags.addCallbackAndRun((tags) => { @@ -28,7 +26,7 @@ let knownTagRenderings: Store = tags.mapD(tgs => layer.tagRenderings.filter( (config) => (config.condition?.matchesProperties(tgs) ?? true) && - config.metacondition?.matchesProperties({ ...tgs, ..._metatags } ?? true) && + (config.metacondition?.matchesProperties({ ...tgs, ..._metatags }) ?? true) && config.IsKnown(tgs) )) @@ -39,7 +37,7 @@ {:else} -
+
{#each $knownTagRenderings as config (config.id)}
-
+
-
+
diff --git a/src/UI/Image/ImagePreview.svelte b/src/UI/Image/ImagePreview.svelte index 22d6c2720..5f7efab1e 100644 --- a/src/UI/Image/ImagePreview.svelte +++ b/src/UI/Image/ImagePreview.svelte @@ -25,4 +25,4 @@ - + diff --git a/src/UI/Image/UploadingImageCounter.svelte b/src/UI/Image/UploadingImageCounter.svelte index 558b8f907..5cd7c80fb 100644 --- a/src/UI/Image/UploadingImageCounter.svelte +++ b/src/UI/Image/UploadingImageCounter.svelte @@ -13,8 +13,11 @@ import Loading from "../Base/Loading.svelte" export let state: SpecialVisualizationState - export let tags: Store - export let featureId = tags.data.id + export let tags: Store = undefined + export let featureId = tags?.data?.id + if(featureId === undefined){ + throw "No tags or featureID given" + } export let showThankYou: boolean = true const { uploadStarted, uploadFinished, retried, failed } = state.imageUploadManager.getCountsFor(featureId) diff --git a/src/UI/SpecialVisualization.ts b/src/UI/SpecialVisualization.ts index 47829a77a..a898ac226 100644 --- a/src/UI/SpecialVisualization.ts +++ b/src/UI/SpecialVisualization.ts @@ -77,7 +77,7 @@ export interface SpecialVisualizationState { readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full"> readonly mangroveIdentity: MangroveIdentity readonly showAllQuestionsAtOnce: UIEventSource - readonly preferencesAsTags: Store> + readonly preferencesAsTags: UIEventSource> readonly language: UIEventSource } readonly lastClickObject: WritableFeatureSource diff --git a/src/UI/SpecialVisualizations.ts b/src/UI/SpecialVisualizations.ts index a6637d18c..0439a3c15 100644 --- a/src/UI/SpecialVisualizations.ts +++ b/src/UI/SpecialVisualizations.ts @@ -40,7 +40,7 @@ import FeatureReviews from "../Logic/Web/MangroveReviews" import Maproulette from "../Logic/Maproulette" import SvelteUIElement from "./Base/SvelteUIElement" import { BBoxFeatureSourceForLayer } from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource" -import { Feature, Point } from "geojson" +import { Feature } from "geojson" import { GeoOperations } from "../Logic/GeoOperations" import CreateNewNote from "./Popup/CreateNewNote.svelte" import AddNewPoint from "./Popup/AddNewPoint/AddNewPoint.svelte" @@ -48,8 +48,7 @@ import UserProfile from "./BigComponents/UserProfile.svelte" import Link from "./Base/Link" import LayerConfig from "../Models/ThemeConfig/LayerConfig" import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig" -import { OsmTags, WayId } from "../Models/OsmFeature" -import MoveWizard from "./Popup/MoveWizard" +import { WayId } from "../Models/OsmFeature" import SplitRoadWizard from "./Popup/SplitRoadWizard" import { ExportAsGpxViz } from "./Popup/ExportAsGpxViz" import WikipediaPanel from "./Wikipedia/WikipediaPanel.svelte" @@ -82,6 +81,8 @@ 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" class NearbyImageVis implements SpecialVisualization { // Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests @@ -515,12 +516,11 @@ export default class SpecialVisualizations { return undefined } - return new MoveWizard( - >feature, - >tagSource, + return new SvelteUIElement(MoveWizard, { state, - layer.allowMove - ) + featureToMove: feature, + layer, + }) }, }, { diff --git a/src/UI/ThemeViewGUI.svelte b/src/UI/ThemeViewGUI.svelte index ee3cb9c0e..0ae437a05 100644 --- a/src/UI/ThemeViewGUI.svelte +++ b/src/UI/ThemeViewGUI.svelte @@ -89,7 +89,7 @@ }) - let selectedLayer: UIEventSource = state.selectedElement.mapD(element => state.layout.getMatchingLayer(element.properties)); + let selectedLayer: Store = state.selectedElement.mapD(element => state.layout.getMatchingLayer(element.properties)); let currentZoom = state.mapProperties.zoom; let showCrosshair = state.userRelatedState.showCrosshair; @@ -125,7 +125,6 @@ bounds={state.mapProperties.bounds} perLayer={state.perLayer} selectedElement={state.selectedElement} - {selectedLayer} />
@@ -144,7 +143,6 @@ {#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()} { - selectedLayer.setData(currentViewLayer) selectedElement.setData(state.currentView.features?.data?.[0]) }} > @@ -269,7 +267,7 @@ >
- + diff --git a/src/Utils.ts b/src/Utils.ts index 905c3f83e..406056be6 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1658,7 +1658,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } const child = childs.item(0) if (child === null) { - console.log("Focussing on child element: no child element found for", el) return undefined } if ( @@ -1668,7 +1667,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be ) { child.setAttribute("tabindex", "-1") } - console.log("Focussing on", child) child?.focus() }) } diff --git a/src/index.css b/src/index.css index cd6af335d..1815e8f2c 100644 --- a/src/index.css +++ b/src/index.css @@ -69,12 +69,11 @@ body { color: var(--foreground-color); font-family: "Helvetica Neue", Arial, sans-serif; } - .focusable { /* Not a 'real' class, but rather an indication to FloatOver and ModalRight to, when they open, grab the focus */ - border: 1px solid red } + svg, img { box-sizing: content-box; diff --git a/theme.html b/theme.html index 88a2c8ccf..1c3e6a70e 100644 --- a/theme.html +++ b/theme.html @@ -40,7 +40,7 @@ -
+