diff --git a/InitUiElements.ts b/InitUiElements.ts index 389171d2d..b0e410974 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -10,7 +10,6 @@ import SimpleAddUI from "./UI/BigComponents/SimpleAddUI"; import CenterMessageBox from "./UI/CenterMessageBox"; import UserBadge from "./UI/BigComponents/UserBadge"; import SearchAndGo from "./UI/BigComponents/SearchAndGo"; -import GeoLocationHandler from "./Logic/Actors/GeoLocationHandler"; import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; import {Utils} from "./Utils"; import Svg from "./Svg"; @@ -23,26 +22,22 @@ import UserDetails from "./Logic/Osm/OsmConnection"; import Attribution from "./UI/BigComponents/Attribution"; import LayerResetter from "./Logic/Actors/LayerResetter"; import FullWelcomePaneWithTabs from "./UI/BigComponents/FullWelcomePaneWithTabs"; -import LayerControlPanel from "./UI/BigComponents/LayerControlPanel"; import ShowDataLayer from "./UI/ShowDataLayer"; import Hash from "./Logic/Web/Hash"; import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline"; import ScrollableFullScreen from "./UI/Base/ScrollableFullScreen"; import Translations from "./UI/i18n/Translations"; import MapControlButton from "./UI/MapControlButton"; -import Combine from "./UI/Base/Combine"; import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler"; import LZString from "lz-string"; import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson"; -import AttributionPanel from "./UI/BigComponents/AttributionPanel"; -import ContributorCount from "./Logic/ContributorCount"; import FeatureSource from "./Logic/FeatureSource/FeatureSource"; import AllKnownLayers from "./Customizations/AllKnownLayers"; import LayerConfig from "./Customizations/JSON/LayerConfig"; import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers"; import {TagsFilter} from "./Logic/Tags/TagsFilter"; -import FilterView from "./UI/BigComponents/FilterView"; -import ExportPDF from "./UI/ExportPDF"; +import LeftControls from "./UI/BigComponents/LeftControls"; +import RightControls from "./UI/BigComponents/RightControls"; export class InitUiElements { static InitAll( @@ -191,42 +186,11 @@ export class InitUiElements { marker.addTo(State.state.leafletMap.data); }); - const geolocationButton = new Toggle( - new MapControlButton( - new GeoLocationHandler( - State.state.currentGPSLocation, - State.state.leafletMap, - State.state.layoutToUse - ), { - dontStyle: true - } - ), - undefined, - State.state.featureSwitchGeolocation - ); - - const plus = new MapControlButton( - Svg.plus_zoom_svg() - ).onClick(() => { - State.state.locationControl.data.zoom++; - State.state.locationControl.ping(); - }); - - const min = new MapControlButton( - Svg.min_zoom_svg() - ).onClick(() => { - State.state.locationControl.data.zoom--; - State.state.locationControl.ping(); - }); - - - new Combine([plus, min, geolocationButton].map(el => el.SetClass("m-0.5 md:m-1"))) - .SetClass("flex flex-col") - .AttachTo("bottom-right"); if (layoutToUse.id === personal.id) { updateFavs(); } + InitUiElements.setupAllLayerElements(); if (layoutToUse.id === personal.id) { @@ -331,105 +295,6 @@ export class InitUiElements { ); } - private static InitLayerSelection(featureSource: FeatureSource) { - const copyrightNotice = new ScrollableFullScreen( - () => Translations.t.general.attribution.attributionTitle.Clone(), - () => - new AttributionPanel( - State.state.layoutToUse, - new ContributorCount(featureSource).Contributors - ), - "copyright" - ); - - const copyrightButton = new Toggle( - copyrightNotice, - new MapControlButton(Svg.copyright_svg()), - copyrightNotice.isShown - ) - .ToggleOnClick() - .SetClass("p-0.5"); - - const layerControlPanel = new LayerControlPanel( - State.state.layerControlIsOpened - ).SetClass("block p-1 rounded-full"); - - const layerControlButton = new Toggle( - layerControlPanel, - new MapControlButton(Svg.layers_svg()), - State.state.layerControlIsOpened - ).ToggleOnClick(); - - const layerControl = new Toggle( - layerControlButton, - "", - State.state.featureSwitchLayers - ); - - - const filterView = - new ScrollableFullScreen( - () => Translations.t.general.layerSelection.title.Clone(), - () => - new FilterView(State.state.filteredLayers).SetClass( - "block p-1 rounded-full" - ), - undefined, - State.state.filterIsOpened - ); - - - const filterMapControlButton = new MapControlButton( - Svg.filter_svg() - ); - - const filterButton = new Toggle( - filterView, - filterMapControlButton, - State.state.filterIsOpened - ).ToggleOnClick(); - - const filterControl = new Toggle( - filterButton, - undefined, - State.state.featureSwitchFilter - ); - - const screenshot = - new Toggle( - new MapControlButton( - Svg.download_svg(), - ).onClick(() => { - // Will already export - new ExportPDF( - { - freeDivId: "belowmap", - background: State.state.backgroundLayer, - location: State.state.locationControl, - features: State.state.featurePipeline.features, - layout: State.state.layoutToUse, - } - ); - - }), undefined, State.state.featureSwitchExportAsPdf) - - - new Combine([filterControl, layerControl, screenshot, copyrightButton,]) - .SetClass("flex flex-col") - .AttachTo("bottom-left"); - - State.state.locationControl.addCallback(() => { - // Close the layer selection when the map is moved - layerControlButton.isEnabled.setData(false); - copyrightButton.isEnabled.setData(false); - }); - - State.state.selectedElement.addCallbackAndRunD((_) => { - layerControlButton.isEnabled.setData(false); - copyrightButton.isEnabled.setData(false); - }); - } - private static InitBaseMap() { State.state.availableBackgroundLayers = AvailableBaseLayers.AvailableLayersAt(State.state.locationControl); @@ -561,7 +426,9 @@ export class InitUiElements { // ------------- Setup the layers ------------------------------- const source = InitUiElements.InitLayers(); - InitUiElements.InitLayerSelection(source); + + new LeftControls(source).AttachTo("bottom-left"); + new RightControls().AttachTo("bottom-right"); // ------------------ Setup various other UI elements ------------ diff --git a/State.ts b/State.ts index ac0c4a390..9b7775504 100644 --- a/State.ts +++ b/State.ts @@ -79,7 +79,7 @@ export default class State { public readonly featureSwitchUserbadge: UIEventSource; public readonly featureSwitchSearch: UIEventSource; - public readonly featureSwitchLayers: UIEventSource; + public readonly featureSwitchBackgroundSlection: UIEventSource; public readonly featureSwitchAddNew: UIEventSource; public readonly featureSwitchWelcomeMessage: UIEventSource; public readonly featureSwitchIframe: UIEventSource; @@ -125,11 +125,11 @@ export default class State { public layoutDefinition: string; public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; - public layerControlIsOpened: UIEventSource = + public downloadControlIsOpened: UIEventSource = QueryParameters.GetQueryParameter( - "layer-control-toggle", + "download-control-toggle", "false", - "Whether or not the layer control is shown" + "Whether or not the download panel is shown" ).map( (str) => str !== "false", [], @@ -249,11 +249,12 @@ export default class State { (layoutToUse) => layoutToUse?.enableSearch ?? true, "Disables/Enables the search bar" ); - this.featureSwitchLayers = featSw( - "fs-layers", - (layoutToUse) => layoutToUse?.enableLayers ?? true, - "Disables/Enables the layer control" + this.featureSwitchBackgroundSlection = featSw( + "fs-background", + (layoutToUse) => layoutToUse?.enableBackgroundLayerSelection ?? true, + "Disables/Enables the background layer control" ); + this.featureSwitchFilter = featSw( "fs-filter", (layoutToUse) => layoutToUse?.enableLayers ?? true, diff --git a/UI/BigComponents/AllDownloads.ts b/UI/BigComponents/AllDownloads.ts new file mode 100644 index 000000000..3911ab538 --- /dev/null +++ b/UI/BigComponents/AllDownloads.ts @@ -0,0 +1,53 @@ +import State from "../../State"; +import Combine from "../Base/Combine"; +import ScrollableFullScreen from "../Base/ScrollableFullScreen"; +import Translations from "../i18n/Translations"; +import {UIEventSource} from "../../Logic/UIEventSource"; +import BaseUIElement from "../BaseUIElement"; +import Toggle from "../Input/Toggle"; +import {DownloadPanel} from "./DownloadPanel"; +import {SubtleButton} from "../Base/SubtleButton"; +import Svg from "../../Svg"; +import ExportPDF from "../ExportPDF"; + +export default class AllDownloads extends ScrollableFullScreen { + + constructor(isShown: UIEventSource) { + super(AllDownloads.GenTitle, AllDownloads.GeneratePanel, "layers", isShown); + } + + private static GenTitle(): BaseUIElement { + return Translations.t.general.download.title + .Clone() + .SetClass("text-2xl break-words font-bold p-2"); + } + + private static GeneratePanel(): BaseUIElement { + const generatePdf = () => { + new ExportPDF( + { + freeDivId: "belowmap", + background: State.state.backgroundLayer, + location: State.state.locationControl, + features: State.state.featurePipeline.features, + layout: State.state.layoutToUse, + }) + } + + const pdf = new Toggle( + new SubtleButton(Svg.floppy_ui(), Translations.t.general.download.downloadAsPdf.Clone().SetClass("font-bold"),) + .onClick(generatePdf), + undefined, + + State.state.featureSwitchExportAsPdf + ) + + const exportPanel = new Toggle( + new DownloadPanel(), + undefined, + State.state.featureSwitchEnableExport + ) + + return new Combine([pdf, exportPanel]).SetClass("flex flex-col"); + } +} diff --git a/UI/BigComponents/FilterView.ts b/UI/BigComponents/FilterView.ts index 17318a610..dfa486fd1 100644 --- a/UI/BigComponents/FilterView.ts +++ b/UI/BigComponents/FilterView.ts @@ -15,6 +15,7 @@ import {UIEventSource} from "../../Logic/UIEventSource"; import BaseUIElement from "../BaseUIElement"; import State from "../../State"; import FilteredLayer from "../../Models/FilteredLayer"; +import BackgroundSelector from "./BackgroundSelector"; /** @@ -23,9 +24,14 @@ import FilteredLayer from "../../Models/FilteredLayer"; export default class FilterView extends VariableUiElement { constructor(filteredLayer: UIEventSource) { + const backgroundSelector = new Toggle( + new BackgroundSelector(), + undefined, + State.state.featureSwitchBackgroundSlection + ) super( filteredLayer.map((filteredLayers) => - filteredLayers?.map(l => FilterView.createOneFilteredLayerElement(l)) + filteredLayers?.map(l => FilterView.createOneFilteredLayerElement(l)).concat(backgroundSelector) ) ); } diff --git a/UI/BigComponents/LayerControlPanel.ts b/UI/BigComponents/LayerControlPanel.ts deleted file mode 100644 index 968902ee3..000000000 --- a/UI/BigComponents/LayerControlPanel.ts +++ /dev/null @@ -1,42 +0,0 @@ -import State from "../../State"; -import BackgroundSelector from "./BackgroundSelector"; -import Combine from "../Base/Combine"; -import ScrollableFullScreen from "../Base/ScrollableFullScreen"; -import Translations from "../i18n/Translations"; -import {UIEventSource} from "../../Logic/UIEventSource"; -import BaseUIElement from "../BaseUIElement"; -import Toggle from "../Input/Toggle"; -import {DownloadPanel} from "./DownloadPanel"; - -export default class LayerControlPanel extends ScrollableFullScreen { - - constructor(isShown: UIEventSource) { - super(LayerControlPanel.GenTitle, LayerControlPanel.GeneratePanel, "layers", isShown); - } - - private static GenTitle(): BaseUIElement { - return Translations.t.general.layerSelection.title - .Clone() - .SetClass("text-2xl break-words font-bold p-2"); - } - - private static GeneratePanel(): BaseUIElement { - const elements: BaseUIElement[] = []; - - if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { - const backgroundSelector = new BackgroundSelector(); - backgroundSelector.SetStyle("margin:1em"); - backgroundSelector.onClick(() => { - }); - elements.push(backgroundSelector) - } - - elements.push(new Toggle( - new DownloadPanel(), - undefined, - State.state.featureSwitchEnableExport - )) - - return new Combine(elements).SetClass("flex flex-col"); - } -} diff --git a/UI/BigComponents/LeftControls.ts b/UI/BigComponents/LeftControls.ts new file mode 100644 index 000000000..6f32c57d4 --- /dev/null +++ b/UI/BigComponents/LeftControls.ts @@ -0,0 +1,94 @@ +import Combine from "../Base/Combine"; +import ScrollableFullScreen from "../Base/ScrollableFullScreen"; +import Translations from "../i18n/Translations"; +import AttributionPanel from "./AttributionPanel"; +import State from "../../State"; +import ContributorCount from "../../Logic/ContributorCount"; +import Toggle from "../Input/Toggle"; +import MapControlButton from "../MapControlButton"; +import Svg from "../../Svg"; +import AllDownloads from "./AllDownloads"; +import FilterView from "./FilterView"; +import FeatureSource from "../../Logic/FeatureSource/FeatureSource"; + +export default class LeftControls extends Combine { + + constructor(featureSource: FeatureSource) { + + const toggledCopyright = new ScrollableFullScreen( + () => Translations.t.general.attribution.attributionTitle.Clone(), + () => + new AttributionPanel( + State.state.layoutToUse, + new ContributorCount(featureSource).Contributors + ), + undefined + ); + + const copyrightButton = new Toggle( + toggledCopyright, + new MapControlButton(Svg.copyright_svg()), + toggledCopyright.isShown + ) + .ToggleOnClick() + .SetClass("p-0.5"); + + const toggledDownload = new Toggle( + new AllDownloads( + State.state.downloadControlIsOpened + ).SetClass("block p-1 rounded-full"), + new MapControlButton(Svg.download_svg()), + State.state.downloadControlIsOpened + ).ToggleOnClick(); + + const downloadButtonn = new Toggle( + toggledDownload, + undefined, + State.state.featureSwitchEnableExport.map(downloadEnabled => downloadEnabled || State.state.featureSwitchExportAsPdf.data, + [State.state.featureSwitchExportAsPdf]) + ); + + + const toggledFilter = new Toggle( + new ScrollableFullScreen( + () => Translations.t.general.layerSelection.title.Clone(), + () => + new FilterView(State.state.filteredLayers).SetClass( + "block p-1 rounded-full" + ), + undefined, + State.state.filterIsOpened + ), + new MapControlButton(Svg.filter_svg()), + State.state.filterIsOpened + ).ToggleOnClick(); + + const filterButton = new Toggle( + toggledFilter, + undefined, + State.state.featureSwitchFilter + ); + + + State.state.locationControl.addCallback(() => { + // Close the layer selection when the map is moved + toggledDownload.isEnabled.setData(false); + copyrightButton.isEnabled.setData(false); + toggledFilter.isEnabled.setData(false); + }); + + State.state.selectedElement.addCallbackAndRunD((_) => { + toggledDownload.isEnabled.setData(false); + copyrightButton.isEnabled.setData(false); + toggledFilter.isEnabled.setData(false); + }); + super([filterButton, + downloadButtonn, + copyrightButton]) + + this.SetClass("flex flex-col") + + } + + +} \ No newline at end of file diff --git a/UI/BigComponents/RightControls.ts b/UI/BigComponents/RightControls.ts new file mode 100644 index 000000000..dd4282b35 --- /dev/null +++ b/UI/BigComponents/RightControls.ts @@ -0,0 +1,43 @@ +import Combine from "../Base/Combine"; +import Toggle from "../Input/Toggle"; +import MapControlButton from "../MapControlButton"; +import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"; +import State from "../../State"; +import Svg from "../../Svg"; + +export default class RightControls extends Combine { + + constructor() { + const geolocationButton = new Toggle( + new MapControlButton( + new GeoLocationHandler( + State.state.currentGPSLocation, + State.state.leafletMap, + State.state.layoutToUse + ), { + dontStyle: true + } + ), + undefined, + State.state.featureSwitchGeolocation + ); + + const plus = new MapControlButton( + Svg.plus_zoom_svg() + ).onClick(() => { + State.state.locationControl.data.zoom++; + State.state.locationControl.ping(); + }); + + const min = new MapControlButton( + Svg.min_zoom_svg() + ).onClick(() => { + State.state.locationControl.data.zoom--; + State.state.locationControl.ping(); + }); + + super([plus, min, geolocationButton].map(el => el.SetClass("m-0.5 md:m-1"))) + this.SetClass("flex flex-col") + } + +} \ No newline at end of file diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 62ea506bb..9f2e4272d 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -166,7 +166,7 @@ export default class SimpleAddUI extends Toggle { ]) ) - .onClick(() => State.state.layerControlIsOpened.setData(true)) + .onClick(() => State.state.filterIsOpened.setData(true)) const openLayerOrConfirm = new Toggle( confirmButton, @@ -238,7 +238,13 @@ export default class SimpleAddUI extends Toggle { const allButtons = []; for (const layer of State.state.filteredLayers.data) { - if (layer.isDisplayed.data === false && State.state.featureSwitchLayers) { + if (layer.isDisplayed.data === false && State.state.featureSwitchFilter.data) { + // The layer is not displayed and we cannot enable the layer control -> we skip + continue; + } + + if(layer.layerDef.name === undefined){ + // this is a parlty hidden layer continue; } diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index e7e395b70..7bddff577 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -23,7 +23,7 @@ "startLat": 51, "startLon": 3.75, "startZoom": 11, - "widenFactor": 0.0, + "widenFactor": 0, "socialImage": "./assets/themes/cycle_infra/cycle-infra.svg", "enableDownload": true, "layers": [ diff --git a/langs/en.json b/langs/en.json index f8453d507..5f0887077 100644 --- a/langs/en.json +++ b/langs/en.json @@ -162,6 +162,7 @@ }, "download": { "title": "Download visible data", + "downloadAsPdf": "Download a PDF of the current map", "downloadGeojson": "Download visible data as geojson", "downloadGeoJsonHelper": "Compatible with QGIS, OsmAnd, ArcGIS, ESRI, ...", "downloadCSV": "Download as CSV",