From 124e816abe4e2ec460a5549dab79399f4a249fd6 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 29 Aug 2024 02:46:51 +0200 Subject: [PATCH 1/9] UX+Refactoring: use side-drawer for menu, reorder menu structure --- public/css/index-tailwind-output.css | 94 +++--- src/Logic/Web/ThemeViewStateHashActor.ts | 157 ++++----- src/Models/MenuState.ts | 176 +++------- src/Models/ThemeViewState.ts | 99 +++--- src/UI/Base/CloseAnimation.svelte | 48 --- src/UI/Base/DrawerLeft.svelte | 20 ++ src/UI/Base/MapControlButton.svelte | 7 +- src/UI/Base/Page.svelte | 38 +++ src/UI/Base/TabbedGroup.svelte | 197 ----------- src/UI/Base/TitledPanel.svelte | 3 + src/UI/BigComponents/AboutMapComplete.svelte | 103 ------ src/UI/BigComponents/CopyrightAllIcons.svelte | 22 ++ src/UI/BigComponents/CopyrightPanel.svelte | 22 +- ...anel.svelte => CopyrightSingleIcon.svelte} | 0 .../{FilterPanel.svelte => FilterPage.svelte} | 10 +- src/UI/BigComponents/HotkeyTable.svelte | 5 - src/UI/BigComponents/MenuDrawer.svelte | 296 +++++++++++++++++ .../OpenBackgroundSelectorButton.svelte | 2 +- src/UI/BigComponents/ThemeIntroPanel.svelte | 30 +- src/UI/DownloadFlow/DownloadPanel.svelte | 4 - src/UI/Map/MapLibreAdaptor.ts | 1 - src/UI/Map/RasterLayerOverview.svelte | 45 +-- src/UI/Map/RasterLayerPicker.svelte | 10 +- src/UI/ThemeViewGUI.svelte | 311 ++---------------- src/index.css | 4 + 25 files changed, 645 insertions(+), 1059 deletions(-) delete mode 100644 src/UI/Base/CloseAnimation.svelte create mode 100644 src/UI/Base/DrawerLeft.svelte create mode 100644 src/UI/Base/Page.svelte delete mode 100644 src/UI/Base/TabbedGroup.svelte delete mode 100644 src/UI/BigComponents/AboutMapComplete.svelte create mode 100644 src/UI/BigComponents/CopyrightAllIcons.svelte rename src/UI/BigComponents/{IconCopyrightPanel.svelte => CopyrightSingleIcon.svelte} (100%) rename src/UI/BigComponents/{FilterPanel.svelte => FilterPage.svelte} (93%) create mode 100644 src/UI/BigComponents/MenuDrawer.svelte diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index d31b30538..89a5008ca 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -811,14 +811,14 @@ video { z-index: -10; } -.z-10 { - z-index: 10; -} - .z-50 { z-index: 50; } +.z-10 { + z-index: 10; +} + .z-30 { z-index: 30; } @@ -943,6 +943,11 @@ video { margin-right: 0.25rem; } +.mx-auto { + margin-left: auto; + margin-right: auto; +} + .my-4 { margin-top: 1rem; margin-bottom: 1rem; @@ -963,11 +968,6 @@ video { margin-bottom: -0.25rem; } -.mx-auto { - margin-left: auto; - margin-right: auto; -} - .-mx-1\.5 { margin-left: -0.375rem; margin-right: -0.375rem; @@ -1037,6 +1037,10 @@ video { margin-left: 0.5rem; } +.mb-2 { + margin-bottom: 0.5rem; +} + .mr-10 { margin-right: 2.5rem; } @@ -1053,10 +1057,6 @@ video { margin-left: 1rem; } -.mb-2 { - margin-bottom: 0.5rem; -} - .mt-2 { margin-top: 0.5rem; } @@ -1999,14 +1999,14 @@ video { gap: 1rem; } -.gap-2 { - gap: 0.5rem; -} - .gap-3 { gap: 0.75rem; } +.gap-2 { + gap: 0.5rem; +} + .gap-8 { gap: 2rem; } @@ -2043,6 +2043,12 @@ video { row-gap: 2rem; } +.space-y-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); +} + .space-x-0\.5 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.125rem * var(--tw-space-x-reverse)); @@ -2091,12 +2097,6 @@ video { margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); } -.space-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); -} - .-space-x-px > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(-1px * var(--tw-space-x-reverse)); @@ -2702,6 +2702,11 @@ video { border-color: inherit; } +.border-t-gray-300 { + --tw-border-opacity: 1; + border-top-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + .border-opacity-50 { --tw-border-opacity: 0.5; } @@ -3344,11 +3349,6 @@ video { padding-right: 0.25rem; } -.py-8 { - padding-top: 2rem; - padding-bottom: 2rem; -} - .px-3 { padding-left: 0.75rem; padding-right: 0.75rem; @@ -4084,6 +4084,12 @@ video { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.shadow-md { + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + .shadow-sm { --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); @@ -4108,12 +4114,6 @@ video { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-md { - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - .shadow-gray-300 { --tw-shadow-color: #d1d5db; --tw-shadow: var(--tw-shadow-colored); @@ -4249,13 +4249,13 @@ video { filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } -.drop-shadow-md { - --tw-drop-shadow: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06)); +.drop-shadow-2xl { + --tw-drop-shadow: drop-shadow(0 25px 25px rgb(0 0 0 / 0.15)); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } -.drop-shadow-2xl { - --tw-drop-shadow: drop-shadow(0 25px 25px rgb(0 0 0 / 0.15)); +.drop-shadow-md { + --tw-drop-shadow: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06)); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } @@ -4806,6 +4806,10 @@ code { color: var(--background-color); } +.h-full-child > div { + height: 100%; +} + .bg-black-transparent { background-color: #00000088; } @@ -5964,16 +5968,16 @@ svg.apply-fill path { display: none; } - .dark\:divide-gray-600 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(75 85 99 / var(--tw-divide-opacity)); - } - .dark\:divide-gray-700 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(55 65 81 / var(--tw-divide-opacity)); } + .dark\:divide-gray-600 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(75 85 99 / var(--tw-divide-opacity)); + } + .dark\:divide-gray-800 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(31 41 55 / var(--tw-divide-opacity)); @@ -7248,6 +7252,10 @@ svg.apply-fill path { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .sm\:flex-row { + flex-direction: row; + } + .sm\:flex-nowrap { flex-wrap: nowrap; } diff --git a/src/Logic/Web/ThemeViewStateHashActor.ts b/src/Logic/Web/ThemeViewStateHashActor.ts index 84aa80868..d4c75296a 100644 --- a/src/Logic/Web/ThemeViewStateHashActor.ts +++ b/src/Logic/Web/ThemeViewStateHashActor.ts @@ -1,6 +1,7 @@ import ThemeViewState from "../../Models/ThemeViewState" import Hash from "./Hash" import { MenuState } from "../../Models/MenuState" +import hash from "svelte/types/compiler/compile/utils/hash" export default class ThemeViewStateHashActor { private readonly _state: ThemeViewState @@ -10,18 +11,16 @@ export default class ThemeViewStateHashActor { "", "- The id of the currently selected object, e.g. `node/1234`", "- The currently opened menu view", - "- The base64-encoded JSON-file specifying a custom theme (only when loading)", "", "### Possible hashes to open a menu", "", "The possible hashes are:", "", - MenuState._menuviewTabs.map((tab) => "`menu:" + tab + "`").join(","), - MenuState._themeviewTabs.map((tab) => "`theme-menu:" + tab + "`").join(","), + MenuState.pageNames.map((tab) => "`" + tab + "`").join(",") ] /** - * Converts the hash to the appropriate themeview state and, vice versa, sets the hash. + * Converts the hash to the appropriate theme-view state and, vice versa, sets the hash. * * As the navigator-back-button changes the hash first, this class thus also handles the 'back'-button events. * @@ -33,46 +32,38 @@ export default class ThemeViewStateHashActor { constructor(state: ThemeViewState) { this._state = state + const hashOnLoad = Hash.hash.data + const containsMenu = this.loadStateFromHash(hashOnLoad) // First of all, try to recover the selected element - if (Hash.hash.data) { - const hash = Hash.hash.data - this.loadStateFromHash(hash) - Hash.hash.setData(hash) // reapply the previous hash - state.indexedFeatures.featuresById.addCallbackAndRunD((_) => { - let unregister = this.loadSelectedElementFromHash(hash) + if (!containsMenu && hashOnLoad.length > 0) { + state.indexedFeatures.featuresById.addCallbackAndRunD(() => { // once that we have found a matching element, we can be sure the indexedFeaturesource was popuplated and that the job is done - return unregister + return this.loadSelectedElementFromHash(hashOnLoad) }) } - // Register a hash change listener to correctly handle the back button - Hash.hash.addCallback((hash) => { - if (!!hash) { - // There is still a hash - // We _only_ have to (at most) close the overlays in this case - if (state.previewedImage.data) { - state.previewedImage.setData(undefined) - return - } - - const parts = hash.split(";") - if (parts.indexOf("background") < 0) { - state.guistate.backgroundLayerSelectionIsOpened.setData(false) - } - this.loadSelectedElementFromHash(hash) - } else { - this.back() - } - }) // At last, register callbacks on the state to update the hash when they change. // Note: these should use 'addCallback', not 'addCallbackAndRun' - state.selectedElement.addCallback((_) => this.setHash()) - state.guistate.allToggles.forEach(({ toggle, submenu }) => { - submenu?.addCallback((_) => this.setHash()) - toggle.addCallback((_) => this.setHash()) + state.selectedElement.addCallback(() => this.setHash()) + + // Register a hash change listener to correctly handle the back button + Hash.hash.addCallback((hash) => { + console.trace("Going back with hash", hash) + if (!hash) { + this.back() + }else{ + if(!this.loadStateFromHash(hash)){ + this.loadSelectedElementFromHash(hash) + } + } }) + for (const key in state.guistate.pageStates) { + const toggle = state.guistate.pageStates[key] + toggle.addCallback(() => this.setHash()) + } + // When all is done, set the hash. This must happen last to give the code above correct info this.setHash() } @@ -80,15 +71,10 @@ export default class ThemeViewStateHashActor { /** * Selects the appropriate element * Returns true if this method can be unregistered for the first run - * @param hash - * @private */ private loadSelectedElementFromHash(hash: string): boolean { const state = this._state const selectedElement = state.selectedElement - // state.indexedFeatures.featuresById.stabilized(250) - - hash = hash.split(";")[0] // The 'selectedElement' is always the _first_ item in the hash (if any) // Set the hash based on the selected element... // ... search and select an element based on the hash @@ -101,7 +87,7 @@ export default class ThemeViewStateHashActor { if (!found) { return false } - if (found.properties.id === "last_click") { + if (found.properties.id.startsWith("last_click")) { return true } console.log( @@ -114,82 +100,53 @@ export default class ThemeViewStateHashActor { return true } - private loadStateFromHash(hash: string) { - const state = this._state - for (const superpart of hash.split(";")) { - const parts = superpart.at(-1)?.split(":") ?? [] - - outer: for (const { toggle, name, submenu } of state.guistate.allToggles) { - for (const part of parts) { - if (part.indexOf(":") < 0) { - if (part === name) { - toggle.setData(true) - continue outer - } - continue - } - const [main, submenuValue] = part.split(":") - if (part !== main) { - continue - } - toggle.setData(true) - submenu?.setData(submenuValue) - continue outer - } - - // If we arrive here, the loop above has not found any match - toggle.setData(false) + private loadStateFromHash(hash: string): boolean { + for (const page in this._state.guistate.pageStates) { + if (page === hash) { + const toggle = this._state.guistate.pageStates[page] + toggle.set(true) + console.log("Loading menu view from hash:", page) + return true } } + return false } - private setHash() { - const s = this._state - let h = "" - - for (const { toggle, showOverOthers, name, submenu } of s.guistate.allToggles) { - if (showOverOthers || !toggle.data) { - continue - } - h = name - if (submenu?.data) { - h += ":" + submenu.data + /** + * Sets the hash based on: + * + * 1. Selected element ID + * 2. A selected 'page' from the menu + * + * returns 'true' if a hash was set + */ + private setHash(): boolean { + const selectedElement = this._state.selectedElement.data + if(selectedElement){ + Hash.hash.set(selectedElement.properties.id) + return true + } + for (const page in this._state.guistate.pageStates) { + const toggle = this._state.guistate.pageStates[page] + if (toggle.data) { + Hash.hash.set(page) + return true } } - - if (s.selectedElement.data !== undefined) { - h = s.selectedElement.data.properties.id - } - - for (const { toggle, showOverOthers, name, submenu } of s.guistate.allToggles) { - if (!showOverOthers || !toggle.data) { - continue - } - if (h) { - h += ";" + name - } else { - h = name - } - if (submenu?.data) { - h += ":" + submenu.data - } - } - Hash.hash.setData(h) + Hash.hash.set(undefined) + return false } private back() { const state = this._state + console.log("Got a 'back' event") if (state.previewedImage.data) { state.previewedImage.setData(undefined) return } - // history.pushState(null, null, window.location.pathname); - if (state.selectedElement.data) { - state.selectedElement.setData(undefined) - return - } if (state.guistate.closeAll()) { return } + state.selectedElement.setData(undefined) } } diff --git a/src/Models/MenuState.ts b/src/Models/MenuState.ts index ae48ae6fe..7bd5af0d7 100644 --- a/src/Models/MenuState.ts +++ b/src/Models/MenuState.ts @@ -2,11 +2,10 @@ import LayerConfig from "./ThemeConfig/LayerConfig" import { UIEventSource } from "../Logic/UIEventSource" import UserRelatedState from "../Logic/State/UserRelatedState" import { Utils } from "../Utils" -import { LocalStorageSource } from "../Logic/Web/LocalStorageSource" import Zoomcontrol from "../UI/Zoomcontrol" +import { LocalStorageSource } from "../Logic/Web/LocalStorageSource" -export type ThemeViewTabStates = (typeof MenuState._themeviewTabs)[number] -export type MenuViewTabStates = (typeof MenuState._menuviewTabs)[number] +export type PageType = (typeof MenuState.pageNames)[number] /** * Indicates if a menu is open, and if so, which tab is selected; @@ -15,141 +14,44 @@ export type MenuViewTabStates = (typeof MenuState._menuviewTabs)[number] * Some convenience methods are provided for this as well */ export class MenuState { - public static readonly _themeviewTabs = ["intro", "download", "copyright", "share"] as const - public static readonly _menuviewTabs = [ - "about", - "settings", - "favourites", - "community", - "privacy", - "advanced", + + + public static readonly pageNames = [ + "copyright", "copyright_icons", "community_index", "hotkeys", + "privacy", "filter", "background", "about_theme", "download", "favourites", + "usersettings", "share" ] as const - public readonly themeIsOpened: UIEventSource - public readonly themeViewTabIndex: UIEventSource - public readonly themeViewTab: UIEventSource - public readonly menuIsOpened: UIEventSource - public readonly menuViewTabIndex: UIEventSource - public readonly menuViewTab: UIEventSource - public readonly backgroundLayerSelectionIsOpened: UIEventSource = - new UIEventSource(false) - - public readonly filtersPanelIsOpened: UIEventSource = new UIEventSource(false) - public readonly privacyPanelIsOpened: UIEventSource = new UIEventSource(false) - /** - * Standalone copyright panel - */ - public readonly copyrightPanelIsOpened: UIEventSource = new UIEventSource( - false - ) - - public readonly communityIndexPanelIsOpened: UIEventSource = new UIEventSource(false) - public readonly allToggles: { - toggle: UIEventSource - name: string - submenu?: UIEventSource - showOverOthers?: boolean - }[] + public readonly menuIsOpened = new UIEventSource(false) + public readonly pageStates: Record> public readonly highlightedLayerInFilters: UIEventSource = new UIEventSource( undefined ) public highlightedUserSetting: UIEventSource = new UIEventSource(undefined) - constructor(shouldOpenWelcomeMessage: boolean, themeid: string = "") { + constructor(shouldShowWelcomeMessage: boolean, themeid: string) { // Note: this class is _not_ responsible to update the Hash, @see ThemeViewStateHashActor for this - if (themeid) { - themeid += "-" - } - this.themeIsOpened = LocalStorageSource.GetParsed( - themeid + "thememenuisopened", - shouldOpenWelcomeMessage - ) - this.themeViewTabIndex = LocalStorageSource.GetParsed(themeid + "themeviewtabindex", 0) - this.themeViewTab = this.themeViewTabIndex.sync( - (i) => MenuState._themeviewTabs[i], - [], - (str) => MenuState._themeviewTabs.indexOf(str) - ) + const states = {} + for (const pageName of MenuState.pageNames) { + const toggle = new UIEventSource(false) + states[pageName] = toggle - this.menuIsOpened = LocalStorageSource.GetParsed(themeid + "menuisopened", false) - this.menuViewTabIndex = LocalStorageSource.GetParsed(themeid + "menuviewtabindex", 0) - this.menuViewTab = this.menuViewTabIndex.sync( - (i) => MenuState._menuviewTabs[i], - [], - (str) => MenuState._menuviewTabs.indexOf(str) - ) - this.menuIsOpened.addCallbackAndRun((isOpen) => { - if (!isOpen) { - this.highlightedUserSetting.setData(undefined) - } - }) - this.menuViewTab.addCallbackD((tab) => { - if (tab !== "settings") { - this.highlightedUserSetting.setData(undefined) - } - }) - this.filtersPanelIsOpened.addCallbackAndRun((isOpen) => { - if (!isOpen) { - this.highlightedLayerInFilters.setData(undefined) - } - }) - - this.menuIsOpened.addCallbackAndRunD((opened) => { - if (opened) { - this.themeIsOpened.setData(false) - } - }) - this.themeIsOpened.addCallbackAndRunD((opened) => { - if (opened) { - this.menuIsOpened.setData(false) - } - }) - - this.allToggles = [ - { - toggle: this.privacyPanelIsOpened, - name: "privacy", - showOverOthers: true, - }, - { - toggle: this.copyrightPanelIsOpened, - name: "copyright", - showOverOthers: true, - }, - { - toggle: this.communityIndexPanelIsOpened, - name: "community", - showOverOthers: true, - }, - { - toggle: this.filtersPanelIsOpened, - name: "filters", - showOverOthers: true, - }, - { - toggle: this.menuIsOpened, - name: "menu", - submenu: this.menuViewTab, - }, - { - toggle: this.themeIsOpened, - name: "theme-menu", - submenu: this.themeViewTab, - }, - { - toggle: this.backgroundLayerSelectionIsOpened, - name: "background", - showOverOthers: true, - }, - ] - for (const toggle of this.allToggles) { - toggle.toggle.addCallback((isOpen) => { - if (!isOpen) { - this.resetZoomIfAllClosed() + toggle.addCallback(enabled => { + if (enabled) { + this.menuIsOpened.set(false) } }) } + this.pageStates = >>states + + const visitedBefore = LocalStorageSource.GetParsed( + themeid + "thememenuisopened", false + ) + if (!visitedBefore.data && shouldShowWelcomeMessage) { + this.pageStates.about_theme.set(true) + visitedBefore.set(true) + } } private resetZoomIfAllClosed() { @@ -160,7 +62,7 @@ export class MenuState { } public openFilterView(highlightLayer?: LayerConfig | string) { - this.filtersPanelIsOpened.setData(true) + this.pageStates.filter.setData(true) if (highlightLayer) { if (typeof highlightLayer !== "string") { highlightLayer = highlightLayer.id @@ -170,8 +72,6 @@ export class MenuState { } public openUsersettings(highlightTagRendering?: string) { - this.menuIsOpened.setData(true) - this.menuViewTab.setData("settings") if ( highlightTagRendering !== undefined && !UserRelatedState.availableUserSettingsIds.some((tr) => tr === highlightTagRendering) @@ -189,7 +89,7 @@ export class MenuState { } public isSomethingOpen(): boolean { - return this.allToggles.some((t) => t.toggle.data) + return Object.values(this.pageStates).some((t) => t.data) } /** @@ -197,14 +97,18 @@ export class MenuState { * Returns 'true' if at least one menu was opened */ public closeAll(): boolean { - let somethingWasOpen = false - for (const t of this.allToggles) { - somethingWasOpen = t.toggle.data - t.toggle.setData(false) - if (somethingWasOpen) { - break + for (const key in this.pageStates) { + const toggle = this.pageStates[key] + const wasOpen = toggle.data + toggle.setData(false) + if (wasOpen) { + return true } } - return somethingWasOpen + if (this.menuIsOpened.data) { + this.menuIsOpened.set(false) + return true + } } + } diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index fd502f51b..6c6dcbde3 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -5,7 +5,7 @@ import { Store, UIEventSource } from "../Logic/UIEventSource" import { FeatureSource, IndexedFeatureSource, - WritableFeatureSource, + WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource" import { OsmConnection } from "../Logic/Osm/OsmConnection" import { ExportableMap, MapProperties } from "./MapProperties" @@ -51,7 +51,7 @@ import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveF import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource" import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor" import NoElementsInViewDetector, { - FeatureViewState, + FeatureViewState } from "../Logic/Actors/NoElementsInViewDetector" import FilteredLayer from "./FilteredLayer" import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector" @@ -64,7 +64,7 @@ import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl" import Zoomcontrol from "../UI/Zoomcontrol" import { SummaryTileSource, - SummaryTileSourceRewriter, + SummaryTileSourceRewriter } from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource" import summaryLayer from "../assets/generated/layers/summary.json" import last_click_layerconfig from "../assets/generated/layers/last_click.json" @@ -178,7 +178,7 @@ export default class ThemeViewState implements SpecialVisualizationState { "oauth_token", undefined, "Used to complete the login" - ), + ) }) this.userRelatedState = new UserRelatedState( this.osmConnection, @@ -257,8 +257,8 @@ export default class ThemeViewState implements SpecialVisualizationState { bbox.asGeoJson({ zoom: this.mapProperties.zoom.data, ...this.mapProperties.location.data, - id: "current_view_" + currentViewIndex, - }), + id: "current_view_" + currentViewIndex + }) ] }) ) @@ -275,10 +275,10 @@ export default class ThemeViewState implements SpecialVisualizationState { featurePropertiesStore: this.featureProperties, osmConnection: this.osmConnection, historicalUserLocations: this.geolocation.historicalUserLocations, - featureSwitches: this.featureSwitches, + featureSwitches: this.featureSwitches }, layout?.isLeftRightSensitive() ?? false, - (e, extraMsg) => this.reportError(e, extraMsg), + (e, extraMsg) => this.reportError(e, extraMsg) ) this.historicalUserLocations = this.geolocation.historicalUserLocations this.newFeatures = new NewGeometryFromChangesFeatureSource( @@ -303,7 +303,7 @@ export default class ThemeViewState implements SpecialVisualizationState { "leftover features, such as", features[0].properties ) - }, + } } ) this.perLayer = perLayer.perLayer @@ -359,7 +359,7 @@ export default class ThemeViewState implements SpecialVisualizationState { { currentZoom: this.mapProperties.zoom, layerState: this.layerState, - bounds: this.visualFeedbackViewportBounds, + bounds: this.visualFeedbackViewportBounds } ) this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView @@ -391,7 +391,6 @@ export default class ThemeViewState implements SpecialVisualizationState { public focusOnMap() { if (this.map.data) { this.map.data.getCanvas().focus() - console.log("Focused on map") return } this.map.addCallbackAndRunD((map) => { @@ -454,7 +453,7 @@ export default class ThemeViewState implements SpecialVisualizationState { doShowLayer, metaTags: this.userRelatedState.preferencesAsTags, selectedElement: this.selectedElement, - fetchStore: (id) => this.featureProperties.getStore(id), + fetchStore: (id) => this.featureProperties.getStore(id) }) }) return filteringFeatureSource @@ -481,7 +480,7 @@ export default class ThemeViewState implements SpecialVisualizationState { doShowLayer: flayerGps.isDisplayed, layer: flayerGps.layerDef, metaTags: this.userRelatedState.preferencesAsTags, - selectedElement: this.selectedElement, + selectedElement: this.selectedElement }) } @@ -527,8 +526,6 @@ export default class ThemeViewState implements SpecialVisualizationState { /** * Selects the feature that is 'i' closest to the map center - * @param i - * @private */ private selectClosestAtCenter(i: number = 0) { if (this.userRelatedState.a11y.data !== "never") { @@ -557,23 +554,22 @@ export default class ThemeViewState implements SpecialVisualizationState { this.previewedImage.setData(undefined) return } - this.selectedElement.setData(undefined) - this.guistate.closeAll() - if (!this.guistate.isSomethingOpen()) { - Zoomcontrol.resetzoom() - this.focusOnMap() + if(this.guistate.closeAll()){ + return } + this.selectedElement.setData(undefined) + Zoomcontrol.resetzoom() + this.focusOnMap() }) Hotkeys.RegisterHotkey({ nomod: "f" }, docs.selectFavourites, () => { - this.guistate.menuViewTab.setData("favourites") - this.guistate.menuIsOpened.setData(true) + this.guistate.pageStates.favourites.set(true) }) Hotkeys.RegisterHotkey( { nomod: " ", - onUp: true, + onUp: true }, docs.selectItem, () => { @@ -581,8 +577,7 @@ export default class ThemeViewState implements SpecialVisualizationState { return false } if ( - this.guistate.menuIsOpened.data || - this.guistate.themeIsOpened.data || + this.guistate.isSomethingOpen() || this.previewedImage.data !== undefined ) { return @@ -603,7 +598,7 @@ export default class ThemeViewState implements SpecialVisualizationState { Hotkeys.RegisterHotkey( { nomod: "" + i, - onUp: true, + onUp: true }, doc, () => this.selectClosestAtCenter(i - 1) @@ -616,22 +611,21 @@ export default class ThemeViewState implements SpecialVisualizationState { } Hotkeys.RegisterHotkey( { - nomod: "b", + nomod: "b" }, docs.openLayersPanel, () => { if (this.featureSwitches.featureSwitchBackgroundSelection.data) { - this.guistate.backgroundLayerSelectionIsOpened.setData(true) + this.guistate.pageStates.background.setData(true) } } ) Hotkeys.RegisterHotkey( { - nomod: "s", + nomod: "s" }, Translations.t.hotkeyDocumentation.openFilterPanel, () => { - console.log("S pressed") if (this.featureSwitches.featureSwitchFilter.data) { this.guistate.openFilterView() } @@ -650,7 +644,7 @@ export default class ThemeViewState implements SpecialVisualizationState { available, category, current.data, - skipLayers, + skipLayers ) if (!best) { return @@ -706,7 +700,7 @@ export default class ThemeViewState implements SpecialVisualizationState { Hotkeys.RegisterHotkey( { - shift: "T", + shift: "T" }, Translations.t.hotkeyDocumentation.translationMode, () => { @@ -738,7 +732,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) } ) @@ -770,7 +764,7 @@ export default class ThemeViewState implements SpecialVisualizationState { current_view: this.currentView, favourite: this.favourites, summary: this.featureSummary, - last_click: this.lastClickObject, + last_click: this.lastClickObject } this.closestFeatures.registerSource(specialLayers.favourite, "favourite") @@ -825,7 +819,7 @@ export default class ThemeViewState implements SpecialVisualizationState { doShowLayer: flayer.isDisplayed, layer: flayer.layerDef, metaTags: this.userRelatedState.preferencesAsTags, - selectedElement: this.selectedElement, + selectedElement: this.selectedElement }) }) const summaryLayerConfig = new LayerConfig(summaryLayer, "summaryLayer") @@ -833,7 +827,7 @@ export default class ThemeViewState implements SpecialVisualizationState { features: specialLayers.summary, layer: summaryLayerConfig, // doShowLayer: this.mapProperties.zoom.map((z) => z < maxzoom), - selectedElement: this.selectedElement, + selectedElement: this.selectedElement }) const lastClickLayerConfig = new LayerConfig( @@ -844,28 +838,27 @@ export default class ThemeViewState implements SpecialVisualizationState { lastClickLayerConfig.isShown === undefined ? specialLayers.last_click : specialLayers.last_click.features.mapD((fs) => - fs.filter((f) => { - const matches = lastClickLayerConfig.isShown.matchesProperties( - f.properties - ) - console.debug("LastClick ", f, "matches", matches) - return matches - }) - ) + fs.filter((f) => { + const matches = lastClickLayerConfig.isShown.matchesProperties( + f.properties + ) + console.debug("LastClick ", f, "matches", matches) + return matches + }) + ) new ShowDataLayer(this.map, { features: new StaticFeatureSource(lastClickFiltered), layer: lastClickLayerConfig, onClick: (feature) => { - console.log("Last click was clicked", feature) if (this.mapProperties.zoom.data >= Constants.minZoomLevelToAddNewPoint) { this.selectedElement.setData(feature) return } this.map.data.flyTo({ zoom: Constants.minZoomLevelToAddNewPoint, - center: GeoOperations.centerpointCoordinates(feature), + center: GeoOperations.centerpointCoordinates(feature) }) - }, + } }) } @@ -880,10 +873,12 @@ export default class ThemeViewState implements SpecialVisualizationState { this.lastClickObject.clear() } }) - this.guistate.allToggles.forEach((toggle) => { - toggle.toggle.addCallbackD((isOpened) => { + Object.values(this.guistate.pageStates).forEach((toggle) => { + toggle.addCallbackD((isOpened) => { if (!isOpened) { - this.focusOnMap() + if (!this.guistate.isSomethingOpen()) { + this.focusOnMap() + } } }) }) @@ -950,8 +945,8 @@ export default class ThemeViewState implements SpecialVisualizationState { userid: this.osmConnection.userDetails.data?.uid, pendingChanges: this.changes.pendingChanges.data, previousChanges: this.changes.allChanges.data, - changeRewrites: Utils.MapToObj(this.changes._changesetHandler._remappings), - }), + changeRewrites: Utils.MapToObj(this.changes._changesetHandler._remappings) + }) }) } catch (e) { console.error("Could not upload an error report") diff --git a/src/UI/Base/CloseAnimation.svelte b/src/UI/Base/CloseAnimation.svelte deleted file mode 100644 index 64a7f0366..000000000 --- a/src/UI/Base/CloseAnimation.svelte +++ /dev/null @@ -1,48 +0,0 @@ - - -
-
-
- -
- -
diff --git a/src/UI/Base/DrawerLeft.svelte b/src/UI/Base/DrawerLeft.svelte new file mode 100644 index 000000000..44c937a2e --- /dev/null +++ b/src/UI/Base/DrawerLeft.svelte @@ -0,0 +1,20 @@ + + + + + diff --git a/src/UI/Base/MapControlButton.svelte b/src/UI/Base/MapControlButton.svelte index e9349c34a..7fd143454 100644 --- a/src/UI/Base/MapControlButton.svelte +++ b/src/UI/Base/MapControlButton.svelte @@ -14,15 +14,10 @@ export let arialabel: Translation = undefined export let arialabelDynamic: Store = new ImmutableStore(arialabel) let arialabelString = arialabelDynamic.bind((tr) => tr?.current) - export let htmlElem: UIEventSource = undefined - let _htmlElem: HTMLElement - $: { - htmlElem?.setData(_htmlElem) - } + +{/if} diff --git a/src/UI/Base/TabbedGroup.svelte b/src/UI/Base/TabbedGroup.svelte deleted file mode 100644 index 1bef33d5d..000000000 --- a/src/UI/Base/TabbedGroup.svelte +++ /dev/null @@ -1,197 +0,0 @@ - - -
- { - if (e.detail >= 0) { - tab.setData(e.detail) - } - }} - > -
- - {#if $$slots.title0} - twJoin("tab", selected && "primary", !$condition0 && "hidden")} - > -
- Tab 0 -
-
- {/if} - {#if $$slots.title1} - twJoin("tab", selected && "primary", !$condition1 && "hidden")} - > -
- -
-
- {/if} - {#if $$slots.title2} - twJoin("tab", selected && "primary", !$condition2 && "hidden")} - > -
- -
-
- {/if} - {#if $$slots.title3} - twJoin("tab", selected && "primary", !$condition3 && "hidden")} - > -
- -
-
- {/if} - {#if $$slots.title4} - twJoin("tab", selected && "primary", !$condition4 && "hidden")} - > -
- -
-
- {/if} - {#if $$slots.title5} - twJoin("tab", selected && "primary", !$condition5 && "hidden")} - > -
- -
-
- {/if} - {#if $$slots.title6} - twJoin("tab", selected && "primary", !$condition6 && "hidden")} - > -
- -
-
- {/if} -
- -
-
- - - -
Empty
-
-
- - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - -
- -
- - diff --git a/src/UI/Base/TitledPanel.svelte b/src/UI/Base/TitledPanel.svelte index b7ddbcb11..6e68e500e 100644 --- a/src/UI/Base/TitledPanel.svelte +++ b/src/UI/Base/TitledPanel.svelte @@ -6,4 +6,7 @@
+ + +
diff --git a/src/UI/BigComponents/AboutMapComplete.svelte b/src/UI/BigComponents/AboutMapComplete.svelte deleted file mode 100644 index 14dd1a7d3..000000000 --- a/src/UI/BigComponents/AboutMapComplete.svelte +++ /dev/null @@ -1,103 +0,0 @@ - - - diff --git a/src/UI/BigComponents/CopyrightAllIcons.svelte b/src/UI/BigComponents/CopyrightAllIcons.svelte new file mode 100644 index 000000000..f1423db48 --- /dev/null +++ b/src/UI/BigComponents/CopyrightAllIcons.svelte @@ -0,0 +1,22 @@ + + +{#each iconAttributions as iconAttribution} + +{/each} diff --git a/src/UI/BigComponents/CopyrightPanel.svelte b/src/UI/BigComponents/CopyrightPanel.svelte index c370f6714..3fec0de6b 100644 --- a/src/UI/BigComponents/CopyrightPanel.svelte +++ b/src/UI/BigComponents/CopyrightPanel.svelte @@ -4,11 +4,7 @@ import contributors from "../../assets/contributors.json" import translators from "../../assets/translators.json" import { Translation, TypedTranslation } from "../i18n/Translation" - import AccordionSingle from "../Flowbite/AccordionSingle.svelte" import Tr from "../Base/Tr.svelte" - import IconCopyrightPanel from "./IconCopyrightPanel.svelte" - import licenses from "../../assets/generated/license_info.json" - import type SmallLicense from "../../Models/smallLicense" import Constants from "../../Models/Constants" import ContributorCount from "../../Logic/ContributorCount" import BaseUIElement from "../BaseUIElement" @@ -24,7 +20,6 @@ const t = Translations.t.general.attribution const layoutToUse = state.layout - const iconAttributions: string[] = layoutToUse.getUsedImages() let maintainer: Translation = undefined if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") { @@ -53,11 +48,7 @@ return Translations.t.general.attribution.attributionBackgroundLayer.Subs(props) }) - const allLicenses = {} - for (const key in licenses) { - const license: SmallLicense = licenses[key] - allLicenses[license.path] = license - } + function calculateDataContributions(contributions: Map): Translation { if (contributions === undefined) { @@ -121,9 +112,6 @@