Merge branch 'master' into develop

This commit is contained in:
Pieter Vander Vennet 2024-06-27 03:45:06 +02:00
commit 894b0d45ca
15 changed files with 218 additions and 135 deletions

View file

@ -386,7 +386,7 @@
"retry": "Retry",
"returnToTheMap": "Return to the map",
"save": "Save",
"screenToSmall": "Open {theme} in a new window",
"screenToSmall": "Open <i>{theme}</i> in a new window",
"search": {
"error": "Something went wrong…",
"nothing": "Nothing found…",

View file

@ -3449,14 +3449,14 @@ video {
padding-right: 3rem;
}
.pr-1 {
padding-right: 0.25rem;
}
.pl-2 {
padding-left: 0.5rem;
}
.pr-1 {
padding-right: 0.25rem;
}
.pt-0\.5 {
padding-top: 0.125rem;
}

View file

@ -326,15 +326,12 @@ class GenerateLayouts extends Script {
}
): Promise<string> {
const apiUrls: string[] = [
...Constants.defaultOverpassUrls,
...Constants.allServers,
Constants.countryCoderEndpoint,
Constants.nominatimEndpoint,
"https://www.openstreetmap.org",
"https://api.openstreetmap.org",
"https://pietervdvn.goatcounter.com",
"https://cache.mapcomplete.org",
"https://proxy.mapcomplete.org",
"https://proxy0.mapcomplete.org",
].concat(...(await this.eliUrls()))
SpecialVisualizations.specialVisualizations.forEach((sv) => {

View file

@ -68,6 +68,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
public readonly osmApiTileSize: UIEventSource<number>
public readonly backgroundLayerId: UIEventSource<string>
public readonly featureSwitchMorePrivacy: UIEventSource<boolean>
public readonly featureSwitchLayerDefault: UIEventSource<boolean>
public constructor(layoutToUse?: LayoutConfig) {
super()
@ -234,5 +235,9 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches {
layoutToUse?.defaultBackgroundId,
"The id of the background layer to start with"
)
this.featureSwitchLayerDefault = QueryParameters.GetBooleanQueryParameter("fs-layers-enabled",true,
"If set to false, all layers will be disabled - except the explicitly enabled layers"
)
}
}

View file

@ -1,4 +1,4 @@
import { UIEventSource } from "../UIEventSource"
import { Store, UIEventSource } from "../UIEventSource"
import { GlobalFilter } from "../../Models/GlobalFilter"
import FilteredLayer from "../../Models/FilteredLayer"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
@ -32,15 +32,16 @@ export default class LayerState {
*
* @param osmConnection
* @param layers
* @param context: the context, probably the name of the theme. Used to disambiguate the upstream user preference
* @param context
* @param layersEnabledByDefault
*/
constructor(osmConnection: OsmConnection, layers: LayerConfig[], context: string) {
constructor(osmConnection: OsmConnection, layers: LayerConfig[], context: string, layersEnabledByDefault: Store<boolean>) {
this.osmConnection = osmConnection
const filteredLayers = new Map()
for (const layer of layers) {
filteredLayers.set(
layer.id,
FilteredLayer.initLinkedState(layer, context, this.osmConnection)
FilteredLayer.initLinkedState(layer, context, this.osmConnection, layersEnabledByDefault)
)
}
this.filteredLayers = filteredLayers

View file

@ -206,10 +206,10 @@ export default class FeatureReviews {
this.subjectUri = this.ConstructSubjectUri()
this.subjectUri.addCallbackAndRunD(
this.subjectUri.mapD(
async (sub) => {
const reviews = await MangroveReviews.getReviews({ sub })
console.log("Got reviews for", feature, reviews, sub)
console.debug("Got reviews for", feature, reviews, sub)
this.addReviews(reviews.reviews, this._name.data)
},
[this._name]
@ -221,7 +221,7 @@ export default class FeatureReviews {
async (sub) => {
try {
const reviews = await MangroveReviews.getReviews({ sub })
console.log("Got reviews (no-encode) for", feature, reviews, sub)
console.debug("Got reviews (no-encode) for", feature, reviews, sub)
this.addReviews(reviews.reviews, this._name.data)
} catch (e) {
console.log("Could not fetch reviews for partially incorrect query ", sub)

View file

@ -10,7 +10,7 @@ export default class Constants {
/**
* API key for Maproulette
*
* Currently there is no user-friendly way to get the user's API key.
* There is no user-friendly way to get the user's API key currently.
* See https://github.com/maproulette/maproulette2/issues/476 for more information.
* Using an empty string however does work for most actions, but will attribute all actions to the Superuser.
*/
@ -169,6 +169,8 @@ export default class Constants {
public static readonly maptilerApiKey = "GvoVAJgu46I5rZapJuAy"
public static readonly SummaryServer: string = Constants.config.summary_server
public static allServers: string[] = [Constants.SummaryServer, Constants.VectorTileServer, Constants.GeoIpServer, Constants.ErrorReportServer, Constants.countryCoderEndpoint, Constants.osmAuthConfig.url, Constants.nominatimEndpoint, Constants.linkedDataProxy, ...Constants.defaultOverpassUrls]
private static isRetina(): boolean {
if (Utils.runningFromConsole) {
return false

View file

@ -81,7 +81,8 @@ export default class FilteredLayer {
public static initLinkedState(
layer: LayerConfig,
context: string,
osmConnection: OsmConnection
osmConnection: OsmConnection,
enabledByDefault?: Store<boolean>
) {
let isDisplayed: UIEventSource<boolean>
if (layer.syncSelection === "local") {
@ -102,9 +103,13 @@ export default class FilteredLayer {
layer
)
} else {
let isShown = layer.shownByDefault
if(enabledByDefault !== undefined && enabledByDefault.data === false){
isShown = false
}
isDisplayed = QueryParameters.GetBooleanQueryParameter(
FilteredLayer.queryParameterKey(layer),
layer.shownByDefault,
isShown ,
"Whether or not layer " + layer.id + " is shown"
)
}

View file

@ -36,6 +36,11 @@ export class MenuState {
public readonly filtersPanelIsOpened: UIEventSource<boolean> = new UIEventSource<boolean>(false)
public readonly privacyPanelIsOpened: UIEventSource<boolean> = new UIEventSource<boolean>(false)
/**
* Standalone copyright panel
*/
public readonly copyrightPanelIsOpened: UIEventSource<boolean> = new UIEventSource<boolean>(false)
public readonly communityIndexPanelIsOpened: UIEventSource<boolean> = new UIEventSource(false)
public readonly allToggles: {
toggle: UIEventSource<boolean>
@ -105,6 +110,11 @@ export class MenuState {
name: "privacy",
showOverOthers: true,
},
{
toggle: this.copyrightPanelIsOpened,
name: "copyright",
showOverOthers: true,
},
{
toggle: this.communityIndexPanelIsOpened,
name: "community",

View file

@ -336,14 +336,16 @@ export default class LayoutConfig implements LayoutInformation {
...json,
layers: json.layers.filter((l) => l["id"] !== "favourite"),
}
this.usedImages = Array.from(
const usedImages =
new ExtractImages(this.official, undefined)
.convertStrict(
jsonNoFavourites,
ConversionContext.construct([json.id], ["ExtractImages"])
)
.map((i) => i.path)
).sort()
.flatMap((i) => i.path)
usedImages.sort()
this.usedImages = Utils.Dedup(usedImages)
return this.usedImages
}
}

View file

@ -202,7 +202,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
)
const self = this
this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id)
this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id, this.featureSwitches.featureSwitchLayerDefault)
{
const overlayLayerStates = new Map<string, { isDisplayed: UIEventSource<boolean> }>()
@ -210,7 +210,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
const isDisplayed = QueryParameters.GetBooleanQueryParameter(
"overlay-" + rasterInfo.id,
rasterInfo.defaultState ?? true,
"Wether or not overlayer layer " + rasterInfo.id + " is shown"
"Whether or not overlayer layer " + rasterInfo.id + " is shown"
)
const state = { isDisplayed }
overlayLayerStates.set(rasterInfo.id, state)
@ -220,8 +220,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
}
{
/* Setup the layout source
* A bit tricky, as this is heavily intertwined with the 'changes'-element, which generate a stream of new and changed features too
/* Set up the layout source
* A bit tricky, as this is heavily intertwined with the 'changes'-element, which generates a stream of new and changed features too
*/
if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) {
@ -704,7 +704,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.mapProperties.zoom.map((z) => Math.max(Math.floor(z), 0)),
this.mapProperties,
{
isActive: this.mapProperties.zoom.map((z) => z <= maxzoom),
isActive: this.mapProperties.zoom.map((z) => z < maxzoom),
}
)
return new SummaryTileSourceRewriter(summaryTileSource, this.layerState.filteredLayers)

View file

@ -0,0 +1,102 @@
<script lang="ts">
import Translations from "../i18n/Translations"
import { Utils } from "../../Utils"
import Hotkeys from "../Base/Hotkeys"
import Constants from "../../Models/Constants"
import Tr from "../Base/Tr.svelte"
import Add from "../../assets/svg/Add.svelte"
import Github from "../../assets/svg/Github.svelte"
import DocumentChartBar from "@babeard/svelte-heroicons/outline/DocumentChartBar"
import Mastodon from "../../assets/svg/Mastodon.svelte"
import Liberapay from "../../assets/svg/Liberapay.svelte"
import ToSvelte from "../Base/ToSvelte.svelte"
import { EyeIcon } from "@rgossiaux/svelte-heroicons/solid"
import MapillaryLink from "./MapillaryLink.svelte"
import OpenJosm from "../Base/OpenJosm.svelte"
import OpenIdEditor from "./OpenIdEditor.svelte"
import If from "../Base/If.svelte"
import Community from "../../assets/svg/Community.svelte"
import Bug from "../../assets/svg/Bug.svelte"
import ThemeViewState from "../../Models/ThemeViewState"
export let state: ThemeViewState
let layout = state.layout
let featureSwitches = state.featureSwitches
</script>
<div class="link-underline links-w-full m-2 flex flex-col gap-y-1">
<Tr t={Translations.t.general.aboutMapComplete.intro} />
<a class="flex" href={Utils.HomepageLink()}>
<Add class="h-6 w-6" />
{#if Utils.isIframe}
<Tr t={Translations.t.general.seeIndex} />
{:else}
<Tr t={Translations.t.general.backToIndex} />
{/if}
</a>
<a class="flex" href="https://github.com/pietervdvn/MapComplete/" target="_blank">
<Github class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.gotoSourceCode} />
</a>
<a class="flex" href="https://github.com/pietervdvn/MapComplete/issues" target="_blank">
<Bug class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.openIssueTracker} />
</a>
<a
class="flex"
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
layout.id +
".md"}
target="_blank"
>
<DocumentChartBar class="h-6 w-6" />
<Tr
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
name: layout.title,
})}
/>
</a>
<a class="flex" href="https://en.osm.town/@MapComplete" target="_blank">
<Mastodon class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.followOnMastodon} />
</a>
<a class="flex" href="https://liberapay.com/pietervdvn/" target="_blank">
<Liberapay class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.donate} />
</a>
<button
class="as-link"
on:click={() => state.guistate.communityIndexPanelIsOpened.setData(true)}
>
<Community class="h-6 w-6" />
<Tr t={Translations.t.communityIndex.title} />
</button>
<If condition={featureSwitches.featureSwitchEnableLogin}>
<OpenIdEditor mapProperties={state.mapProperties} />
<OpenJosm {state} />
<MapillaryLink large={false} mapProperties={state.mapProperties} />
</If>
<button
class="as-link"
on:click={() => state.guistate.privacyPanelIsOpened.setData(true)}
>
<EyeIcon class="h-6 w-6 pr-1" />
<Tr t={Translations.t.privacy.title} />
</button>
<div class="subtle">
{Constants.vNumber}
</div>
</div>

View file

@ -40,7 +40,7 @@ export default class CopyrightPanel extends Combine {
const t = Translations.t.general.attribution
const layoutToUse = state.layout
const iconAttributions: BaseUIElement[] = Utils.Dedup(layoutToUse.getUsedImages()).map(
const iconAttributions: BaseUIElement[] =layoutToUse.getUsedImages().map(
CopyrightPanel.IconAttribution
)

View file

@ -51,10 +51,13 @@
<!-- Intro, description, ... -->
<Tr t={layout.description} />
<Tr t={Translations.t.general.welcomeExplanation.general} />
{#if layout.layers.some((l) => l.presets?.length > 0)}
<Tr t={Translations.t.general.welcomeExplanation.addNew} />
{/if}
<If condition={state.featureSwitches.featureSwitchEnableLogin}>
<Tr t={Translations.t.general.welcomeExplanation.general} />
{#if layout.layers.some((l) => l.presets?.length > 0)}
<Tr t={Translations.t.general.welcomeExplanation.addNew} />
{/if}
</If>
<Tr t={layout.descriptionTail} />

View file

@ -31,8 +31,6 @@
import CopyrightPanel from "./BigComponents/CopyrightPanel"
import DownloadPanel from "./DownloadFlow/DownloadPanel.svelte"
import ModalRight from "./Base/ModalRight.svelte"
import { Utils } from "../Utils"
import Hotkeys from "./Base/Hotkeys"
import LevelSelector from "./BigComponents/LevelSelector.svelte"
import SelectedElementTitle from "./BigComponents/SelectedElementTitle.svelte"
import ThemeIntroPanel from "./BigComponents/ThemeIntroPanel.svelte"
@ -41,8 +39,6 @@
import RasterLayerOverview from "./Map/RasterLayerOverview.svelte"
import IfHidden from "./Base/IfHidden.svelte"
import { onDestroy } from "svelte"
import MapillaryLink from "./BigComponents/MapillaryLink.svelte"
import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte"
import OpenBackgroundSelectorButton from "./BigComponents/OpenBackgroundSelectorButton.svelte"
import StateIndicator from "./BigComponents/StateIndicator.svelte"
import ShareScreen from "./BigComponents/ShareScreen.svelte"
@ -50,14 +46,10 @@
import PendingChangesIndicator from "./BigComponents/PendingChangesIndicator.svelte"
import Cross from "../assets/svg/Cross.svelte"
import LanguagePicker from "./InputElement/LanguagePicker.svelte"
import Mastodon from "../assets/svg/Mastodon.svelte"
import Bug from "../assets/svg/Bug.svelte"
import Liberapay from "../assets/svg/Liberapay.svelte"
import OpenJosm from "./Base/OpenJosm.svelte"
import Min from "../assets/svg/Min.svelte"
import Plus from "../assets/svg/Plus.svelte"
import Filter from "../assets/svg/Filter.svelte"
import Add from "../assets/svg/Add.svelte"
import Community from "../assets/svg/Community.svelte"
import Favourites from "./Favourites/Favourites.svelte"
import ImageOperations from "./Image/ImageOperations.svelte"
@ -79,6 +71,9 @@
import ChevronRight from "@babeard/svelte-heroicons/solid/ChevronRight"
import DocumentChartBar from "@babeard/svelte-heroicons/outline/DocumentChartBar"
import Marker from "./Map/Marker.svelte"
import AboutMapComplete from "./BigComponents/AboutMapComplete.svelte"
import IfNot from "./Base/IfNot.svelte"
import Hotkeys from "./Base/Hotkeys"
export let state: ThemeViewState
let layout = state.layout
@ -124,11 +119,11 @@
state.mapProperties.installCustomKeyboardHandler(viewport)
let canZoomIn = mapproperties.maxzoom.map(
(mz) => mapproperties.zoom.data < mz,
[mapproperties.zoom]
[mapproperties.zoom],
)
let canZoomOut = mapproperties.minzoom.map(
(mz) => mapproperties.zoom.data > mz,
[mapproperties.zoom]
[mapproperties.zoom],
)
function updateViewport() {
@ -165,7 +160,7 @@
onDestroy(
rasterLayer.addCallbackAndRunD((l) => {
rasterLayerName = l.properties.name
})
}),
)
let previewedImage = state.previewedImage
@ -196,7 +191,7 @@
let openMapButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(undefined)
let openMenuButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(undefined)
let openCurrentViewLayerButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(
undefined
undefined,
)
let _openNewElementButton: HTMLButtonElement
let openNewElementButton: UIEventSource<HTMLElement> = new UIEventSource<HTMLElement>(undefined)
@ -250,27 +245,30 @@
</If>
</div>
<div class="float-left m-1 flex flex-col sm:mt-2">
<MapControlButton
on:click={() => state.guistate.themeIsOpened.setData(true)}
on:keydown={forwardEventToMap}
htmlElem={openMapButton}
>
<div class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 md:mx-2">
<Marker icons={layout.icon} size="h-4 w-4 md:h-8 md:w-8 mr-0.5 sm:mr-1 md:mr-2" />
<b class="mr-1">
<Tr t={layout.title} />
</b>
<ChevronRight class="h-4 w-4" />
</div>
</MapControlButton>
<MapControlButton
arialabel={Translations.t.general.labels.menu}
on:click={() => state.guistate.menuIsOpened.setData(true)}
on:keydown={forwardEventToMap}
htmlElem={openMenuButton}
>
<MenuIcon class="h-8 w-8 cursor-pointer" />
</MapControlButton>
<If condition={state.featureSwitches.featureSwitchWelcomeMessage}>
<MapControlButton
on:click={() => state.guistate.themeIsOpened.setData(true)}
on:keydown={forwardEventToMap}
htmlElem={openMapButton}
>
<div class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 md:mx-2">
<Marker icons={layout.icon} size="h-4 w-4 md:h-8 md:w-8 mr-0.5 sm:mr-1 md:mr-2" />
<b class="mr-1">
<Tr t={layout.title} />
</b>
<ChevronRight class="h-4 w-4" />
</div>
</MapControlButton>
<MapControlButton
arialabel={Translations.t.general.labels.menu}
on:click={() => state.guistate.menuIsOpened.setData(true)}
on:keydown={forwardEventToMap}
htmlElem={openMenuButton}
>
<MenuIcon class="h-8 w-8 cursor-pointer" />
</MapControlButton>
</If>
{#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()}
<MapControlButton
on:click={() => {
@ -350,8 +348,12 @@
<a
class="bg-black-transparent pointer-events-auto ml-1 h-fit max-h-12 cursor-pointer self-end self-center overflow-hidden rounded-2xl px-1 text-white opacity-50 hover:opacity-100"
on:click={() => {
if(featureSwitches.featureSwitchWelcomeMessage.data){
state.guistate.themeViewTab.setData("copyright")
state.guistate.themeIsOpened.setData(true)
}else{
state.guistate.copyrightPanelIsOpened.setData(true)
}
}}
>
© <span class="hidden sm:inline sm:pr-2">
@ -512,7 +514,10 @@
<Tr t={Translations.t.general.attribution.title} />
</div>
<ToSvelte construct={() => new CopyrightPanel(state)} slot="content2" />
<div slot="content2" class="flex flex-col m-2">
<ToSvelte construct={() => new CopyrightPanel(state)} />
</div>
<div class="flex" slot="title3">
<Share class="h-4 w-4" />
@ -569,78 +574,11 @@
<Tr t={Translations.t.general.menu.aboutMapComplete} />
</div>
<div class="link-underline links-w-full m-2 flex flex-col gap-y-1" slot="content0">
<Tr t={Translations.t.general.aboutMapComplete.intro} />
<a class="flex" href={Utils.HomepageLink()}>
<Add class="h-6 w-6" />
{#if Utils.isIframe}
<Tr t={Translations.t.general.seeIndex} />
{:else}
<Tr t={Translations.t.general.backToIndex} />
{/if}
</a>
<a class="flex" href="https://github.com/pietervdvn/MapComplete/" target="_blank">
<Github class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.gotoSourceCode} />
</a>
<a class="flex" href="https://github.com/pietervdvn/MapComplete/issues" target="_blank">
<Bug class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.openIssueTracker} />
</a>
<a
class="flex"
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
layout.id +
".md"}
target="_blank"
>
<DocumentChartBar class="h-6 w-6" />
<Tr
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
name: layout.title,
})}
/>
</a>
<a class="flex" href="https://en.osm.town/@MapComplete" target="_blank">
<Mastodon class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.followOnMastodon} />
</a>
<a class="flex" href="https://liberapay.com/pietervdvn/" target="_blank">
<Liberapay class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.donate} />
</a>
<button
class="as-link"
on:click={() => state.guistate.communityIndexPanelIsOpened.setData(true)}
>
<Community class="h-6 w-6" />
<Tr t={Translations.t.communityIndex.title} />
</button>
<If condition={featureSwitches.featureSwitchEnableLogin}>
<OpenIdEditor mapProperties={state.mapProperties} />
<OpenJosm {state} />
<MapillaryLink large={false} mapProperties={state.mapProperties} />
</If>
<button
class="as-link"
on:click={() => state.guistate.privacyPanelIsOpened.setData(true)}
>
<EyeIcon class="h-6 w-6 pr-1" />
<Tr t={Translations.t.privacy.title} />
</button>
<div slot="content0" class="flex flex-col">
<AboutMapComplete {state} />
<div class="m-2 flex flex-col">
<ToSvelte construct={Hotkeys.generateDocumentationDynamic} />
</div>
{Constants.vNumber}
</div>
<div class="flex" slot="title1">
@ -702,6 +640,24 @@
</FloatOver>
</If>
<If condition={state.guistate.copyrightPanelIsOpened}>
<FloatOver on:close={() => state.guistate.privacyPanelIsOpened.setData(false)}>
<div class="flex h-full flex-col overflow-hidden">
<h1 class="low-interaction m-0 flex items-center p-4 drop-shadow-md">
<Tr t= {Translations.t.general.attribution.title}/>
</h1>
<div class="overflow-auto p-4">
<h2>
<Tr t={Translations.t.general.menu.aboutMapComplete} />
</h2>
<AboutMapComplete {state} />
<ToSvelte construct={() => new CopyrightPanel(state)} />
</div>
</div>
</FloatOver>
</If>
<If condition={state.guistate.communityIndexPanelIsOpened}>
<FloatOver on:close={() => state.guistate.communityIndexPanelIsOpened.setData(false)}>
<div class="flex h-full flex-col overflow-hidden">