diff --git a/InitUiElements.ts b/InitUiElements.ts index f5a5eb5..7b03dba 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -147,6 +147,8 @@ export class InitUiElements { continue; } + console.log("Creating the featureInfobox"); + let start = new Date() // This layer is the layer that gives the questions const featureBox = new FeatureInfoBox( State.state.allElements.getEventSourceById(data.id), @@ -158,6 +160,8 @@ export class InitUiElements { hashText: feature.properties.id.replace("/", "_"), titleText: featureBox.title }); + let end = new Date(); + console.log("Creating featureInfoBox took", (end.getTime() - start.getTime()) , "ms") break; } } @@ -290,14 +294,15 @@ export class InitUiElements { const fullOptions2 = new FullWelcomePaneWithTabs(); - if (Hash.hash.data === undefined) { + if (Hash.Current() === "") { State.state.fullScreenMessage.setData({content: fullOptions2, hashText: "welcome"}) } + // ?-Button on Mobile, opens full screen layer with close-button at the bottom Svg.help_svg() - .SetClass("open-welcome-button block rounded-3xl overflow-hidden shadow ml-3" ) + .SetClass("open-welcome-button block rounded-3xl overflow-hidden shadow ml-3") .onClick(() => { State.state.fullScreenMessage.setData({content: fullOptions2, hashText: "welcome"}) }).AttachTo("help-button-mobile"); @@ -407,12 +412,17 @@ export class InitUiElements { source.features.addCallbackAndRun((featuresFreshness: { feature: any, freshness: Date }[]) => { - if(featuresFreshness === undefined){ + if (featuresFreshness === undefined) { return; } let features = featuresFreshness.map(ff => ff.feature); features.forEach(feature => { State.state.allElements.addElement(feature); + + if(Hash.hash.data === feature.properties.id.replace("/","_")){ + State.state.selectedElement.setData(feature); + } + }) MetaTagging.addMetatags(features); }) diff --git a/Logic/Actors/HistoryHandling.ts b/Logic/Actors/HistoryHandling.ts index 6b317a2..6d1c55d 100644 --- a/Logic/Actors/HistoryHandling.ts +++ b/Logic/Actors/HistoryHandling.ts @@ -9,11 +9,11 @@ export default class HistoryHandling { fullscreenMessage.setData(undefined); } }) - + fullscreenMessage.addCallback(fs => { hash.setData(fs?.hashText); }) - + } } \ No newline at end of file diff --git a/State.ts b/State.ts index 8d3f354..3b79259 100644 --- a/State.ts +++ b/State.ts @@ -81,6 +81,7 @@ export default class State { The latest element that was selected - used to generate the right UI at the right place */ public readonly selectedElement = new UIEventSource(undefined) + publ public readonly featureSwitchUserbadge: UIEventSource; public readonly featureSwitchSearch: UIEventSource; @@ -209,7 +210,7 @@ export default class State { if (selected === undefined) { h.setData(""); } else { - h.setData(selected.id) + h.setData(selected.id.replace("/","_")) } } ) diff --git a/UI/Base/Combine.ts b/UI/Base/Combine.ts index 827e30e..4f5adb7 100644 --- a/UI/Base/Combine.ts +++ b/UI/Base/Combine.ts @@ -25,7 +25,11 @@ export default class Combine extends UIElement { console.error("Not a UI-element", ui); return ""; } - return ui.Render(); + let rendered = ui.Render(); + if(ui.IsEmpty()){ + return ""; + } + return rendered; }).join(""); } diff --git a/UI/Base/Img.ts b/UI/Base/Img.ts index 34b238d..6a019ca 100644 --- a/UI/Base/Img.ts +++ b/UI/Base/Img.ts @@ -12,7 +12,7 @@ export default class Img { return `data:image/svg+xml;base64,${(btoa(source))}`; } - static AsImageElement(source: string, css_class: string): string{ + static AsImageElement(source: string, css_class: string = ""): string{ return ``; } } diff --git a/UI/Base/ScrollableFullScreen.ts b/UI/Base/ScrollableFullScreen.ts index 7369c63..bf966ad 100644 --- a/UI/Base/ScrollableFullScreen.ts +++ b/UI/Base/ScrollableFullScreen.ts @@ -8,25 +8,27 @@ import Ornament from "./Ornament"; * Wraps some contents into a panel that scrolls the content _under_ the title */ export default class ScrollableFullScreen extends UIElement { - private _component: Combine; + private _component: UIElement; constructor(title: UIElement, content: UIElement) { super(); - const returnToTheMap = Svg.back_svg().onClick(() => { + const returnToTheMap = Svg.back_ui().onClick(() => { State.state.fullScreenMessage.setData(undefined); State.state.selectedElement.setData(undefined); - }).SetClass("featureinfobox-back-to-the-map only-on-mobile mb-2") + }).SetClass("block sm:hidden mb-2 bg-blue-50 rounded-full w-12 h-12 p-1.5") + title.SetClass("block w-full") - const ornament = new Combine([new Ornament().SetStyle("height:5em;")]).SetClass("only-on-mobile") + + const ornament = new Combine([new Ornament().SetStyle("height:5em;")]).SetClass("sm:hidden") this._component = new Combine([ - new Combine([returnToTheMap, title]).SetClass("border-b-2 border-black shadow sm:shadow-none fixed sm:relative top-0 left-0 right-0 z-50 bg-white p-2 pb-0 sm:p-0 flex overflow-hidden"), + new Combine([returnToTheMap, title]) + .AddClass("border-b-2 border-black shadow sm:shadow-none z-50 bg-white p-2 pb-0 sm:p-0 flex overflow-x-hidden flex-shrink-0 max-h-20vh"), new Combine(["", content, "", ornament]) - .SetClass("block relative pt-16 sm:pt-4 w-full max-h-screen sm:max-h-65vh landscape:max-h-screen overflow-y-auto overflow-x-hidden"), + .SetClass("block p-2 sm:pt-4 w-full max-h-screen landscape:max-h-screen overflow-y-auto overflow-x-hidden"), // We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide - ]) - this.SetClass("block flex flex-col"); + ]).SetClass("block flex flex-col fixed max-h-screen sm:max-h-65vh sm:relative top-0 left-0 right-0"); } diff --git a/UI/BigComponents/SearchAndGo.ts b/UI/BigComponents/SearchAndGo.ts index 9d945a6..ece0897 100644 --- a/UI/BigComponents/SearchAndGo.ts +++ b/UI/BigComponents/SearchAndGo.ts @@ -22,7 +22,7 @@ export default class SearchAndGo extends UIElement { ); private _foundEntries = new UIEventSource([]); - private _goButton = Svg.search_ui().SetClass('search-go'); + private _goButton = Svg.search_ui().AddClass('w-8 h-8 full-rounded border-black float-right'); constructor() { super(undefined); diff --git a/UI/BigComponents/UserBadge.ts b/UI/BigComponents/UserBadge.ts index 18207e8..f2abd8c 100644 --- a/UI/BigComponents/UserBadge.ts +++ b/UI/BigComponents/UserBadge.ts @@ -50,7 +50,7 @@ export default class UserBadge extends UIElement { this._homeButton = new VariableUiElement( this._userDetails.map((userinfo) => { if (userinfo.home) { - return Svg.home; + return Svg.home_svg().Render(); } return ""; }) diff --git a/UI/FullScreenMessageBoxHandler.ts b/UI/FullScreenMessageBoxHandler.ts index 8a8c7eb..0533be3 100644 --- a/UI/FullScreenMessageBoxHandler.ts +++ b/UI/FullScreenMessageBoxHandler.ts @@ -20,7 +20,8 @@ export default class FullScreenMessageBox extends UIElement { return ""; } this._content = State.state.fullScreenMessage.data.content; - return new Combine([this._content]).SetClass("block max-h-screen h-screen overflow-x-hidden overflow-y-auto bg-white p-2").Render(); + return new Combine([this._content]) + .SetClass("block max-h-screen h-screen overflow-x-hidden overflow-y-auto bg-white p-0").Render(); } protected InnerUpdate(htmlElement: HTMLElement) { diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index f203948..91fbc5d 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -25,11 +25,12 @@ export default class FeatureInfoBox extends UIElement { const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined)) - .SetClass("text-2xl break-words font-bold p-2"); + .AddClass("text-2xl break-words font-bold p-2"); this.title = title; const titleIcons = new Combine( - layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon))) - .SetClass("h-8 w-8 pt-2 box-content"); + layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon) + .AddClass("block w-8 h-8 align-baseline box-content p-0.5"))) + .AddClass("flex flex-row flex-wrap pt-1 items-center mr-2"); let questionBox: UIElement = undefined; if (State.state.featureSwitchUserbadge.data) { diff --git a/UI/Popup/TagRenderingAnswer.ts b/UI/Popup/TagRenderingAnswer.ts index f02bcd8..6806b2b 100644 --- a/UI/Popup/TagRenderingAnswer.ts +++ b/UI/Popup/TagRenderingAnswer.ts @@ -21,6 +21,7 @@ export default class TagRenderingAnswer extends UIElement { if (configuration === undefined) { throw "Trying to generate a tagRenderingAnswer without configuration..." } + this.AddClass("flex items-center flex-row text-lg") } InnerRender(): string { @@ -34,11 +35,6 @@ export default class TagRenderingAnswer extends UIElement { if (tags === undefined) { return ""; } - const tr = this._configuration.GetRenderValue(tags); - if (tr !== undefined) { - this._content = new SubstitutedTranslation(tr, this._tags); - return this._content.Render(); - } // The render value doesn't work well with multi-answers (checkboxes), so we have to check for them manually if (this._configuration.multiAnswer) { @@ -65,6 +61,14 @@ export default class TagRenderingAnswer extends UIElement { return this._content.Render(); } } + + const tr = this._configuration.GetRenderValue(tags); + if (tr !== undefined) { + this._content = new SubstitutedTranslation(tr, this._tags); + return this._content.Render(); + } + + return ""; } diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index 181ac28..4f9fe2b 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -69,7 +69,7 @@ export default class ShowDataLayer { action(); } }); - Hash.hash.addCallback(id => { + Hash.hash.addCallbackAndRun(id => { // This is a bit of an edge case: if the hash becomes an id to search, we have to show the corresponding popup if(State.state.selectedElement !== undefined){ return; // Something is already selected, we don't have to apply this fix @@ -130,6 +130,9 @@ export default class ShowDataLayer { "
Rendering
"); popup.setContent(uiElement.Render()); popup.on('remove', () => { + if(!popup.isOpen()){ + return; + } State.state.selectedElement.setData(undefined); }); leafletLayer.bindPopup(popup); diff --git a/UI/UIElement.ts b/UI/UIElement.ts index d531727..b5d2eb5 100644 --- a/UI/UIElement.ts +++ b/UI/UIElement.ts @@ -109,7 +109,7 @@ export abstract class UIElement extends UIEventSource { } - HideOnEmpty(hide: boolean) { + HideOnEmpty(hide: boolean): UIElement { this._hideIfEmpty = hide; this.Update(); return this; diff --git a/assets/layers/bike_parking/bike_parking.json b/assets/layers/bike_parking/bike_parking.json index 02fc72d..2769720 100644 --- a/assets/layers/bike_parking/bike_parking.json +++ b/assets/layers/bike_parking/bike_parking.json @@ -73,68 +73,68 @@ { "if": "bicycle_parking=stands", "then": { - "en": "Staple racks ", - "nl": "Nietjes ", - "fr": "Arceaux ", - "gl": "De roda (Stands) ", - "de": "Fahrradbügel " + "en": "Staple racks ", + "nl": "Nietjes ", + "fr": "Arceaux ", + "gl": "De roda (Stands) ", + "de": "Fahrradbügel " } }, { "if": "bicycle_parking=wall_loops", "then": { - "en": "Wheel rack/loops ", - "nl": "Wielrek/lussen ", - "fr": "Pinces-roues ", - "gl": "Aros ", - "de": "Metallgestänge " + "en": "Wheel rack/loops ", + "nl": "Wielrek/lussen ", + "fr": "Pinces-roues ", + "gl": "Aros ", + "de": "Metallgestänge " } }, { "if": "bicycle_parking=handlebar_holder", "then": { - "en": "Handlebar holder ", - "nl": "Stuurhouder ", - "fr": "Support guidon ", - "gl": "Cadeado para guiador ", - "de": "Halter für Fahrradlenker " + "en": "Handlebar holder ", + "nl": "Stuurhouder ", + "fr": "Support guidon ", + "gl": "Cadeado para guiador ", + "de": "Halter für Fahrradlenker " } }, { "if": "bicycle_parking=rack", "then": { - "en": "Rack ", - "nl": "Rek ", - "fr": "Râtelier ", - "gl": "Cremalleira ", - "de": "Gestell " + "en": "Rack ", + "nl": "Rek ", + "fr": "Râtelier ", + "gl": "Cremalleira ", + "de": "Gestell " } }, { "if": "bicycle_parking=two_tier", "then": { - "en": "Two-tiered ", - "nl": "Dubbel (twee verdiepingen) ", - "fr": "Superposé ", - "gl": "Dobre cremalleira ", - "de": "Zweistufig " + "en": "Two-tiered ", + "nl": "Dubbel (twee verdiepingen) ", + "fr": "Superposé ", + "gl": "Dobre cremalleira ", + "de": "Zweistufig " } }, { "if": "bicycle_parking=shed", "then": { - "en": "Shed ", - "nl": "Schuur ", - "fr": "Abri ", - "gl": "Abeiro ", - "de": "Schuppen " + "en": "Shed ", + "nl": "Schuur ", + "fr": "Abri ", + "gl": "Abeiro ", + "de": "Schuppen " } }, { "if": "bicycle_parking=bollard", "then": { - "en": "Bollard ", - "nl": "Paal met ring " + "en": "Bollard ", + "nl": "Paal met ring " } }, { diff --git a/assets/themes/surveillance_cameras/surveillance_cameras.json b/assets/themes/surveillance_cameras/surveillance_cameras.json index 5495864..58c7cb2 100644 --- a/assets/themes/surveillance_cameras/surveillance_cameras.json +++ b/assets/themes/surveillance_cameras/surveillance_cameras.json @@ -24,7 +24,6 @@ "startZoom": 1, "widenFactor": 0.05, "socialImage": "", - "customCss": "./assets/themes/surveillance_cameras/custom_theme.css", "defaultBackgroundId": "Stadia.AlidadeSmoothDark", "layers": [ "direction", diff --git a/css/tagrendering.css b/css/tagrendering.css index cd07ed5..878579e 100644 --- a/css/tagrendering.css +++ b/css/tagrendering.css @@ -1,24 +1,6 @@ -.featureinfobox-back-to-the-map { - padding: 0.5em; - border-radius: 999em; - margin-right: 0.4em; - width: min-content; - height: min-content; - background: var(--subtle-detail-color); - flex-shrink: 0; -} -.featureinfobox-back-to-the-map svg { - width: 1.75em; - height: 1.75em; - margin-left: 0.15em; - margin-top: 0.15em -} -.featureinfobox-back-to-the-map svg path{ - stroke: var(--subtle-detail-color-contrast) !important; -} @media only screen and (max-height: 600px) and (min-width: 600px) { /* landscape mode: the first tagrendering of the infobox gets a special treatment and is placed on the right*/ diff --git a/css/userbadge.css b/css/userbadge.css index afc7bf0..88c4ab6 100644 --- a/css/userbadge.css +++ b/css/userbadge.css @@ -7,6 +7,7 @@ width: 100%; min-width: 20em; pointer-events: all; + border-radius: 999em; } #userbadge a { @@ -60,6 +61,7 @@ margin: 0; opacity: 0; transition: opacity 500ms linear; + border-radius: 999em; } .usertext { diff --git a/index.css b/index.css index fd9ab2d..bae4121 100644 --- a/index.css +++ b/index.css @@ -7,6 +7,10 @@ .max-h-65vh { max-height: 65vh; } + + .max-h-20vh { + max-height: 20vh; + } } } @@ -40,12 +44,18 @@ html, body { svg, img { box-sizing: content-box; + width: 100%; + height: 100%; } a { color: var(--foreground-color) } + + + + #topleft-tools svg { fill: var(--foreground-color) !important; stroke: var(--foreground-color) !important; @@ -280,16 +290,6 @@ a { color: var(--foreground-color); } -.search-go img { - position: relative; - float: right; - height: 1.2em; - border: 2px solid black; - padding: 0.4em; - margin-left: 0.5em; - margin-right: 0; -} - .add-popup-all-buttons { max-height: 50vh; @@ -481,39 +481,6 @@ a { } -.share-button { - background-color: var(--subtle-detail-color); - border: none; - color: var(--subtle-detail-color-contrast); - text-decoration: none; - display: inline-block; - border-radius: 3em; - height: 2.5em; - width: 2.5em; - box-sizing: border-box; - padding: 0; -} - -.share-button svg { - height: 1.5em; - width: 1.5em; - padding: 0.5em; - padding-left: 0.4em; - fill: var(--subtle-detail-color-contrast) !important; - stroke: var(--subtle-detail-color-contrast) !important; -} - -.share-button svg path { - fill: var(--subtle-detail-color-contrast) !important; - stroke: var(--subtle-detail-color-contrast) !important; -} - -.share-button svg circle { - fill: var(--subtle-detail-color-contrast) !important; - stroke: var(--subtle-detail-color-contrast) !important; -} - - .ornament { padding-top: 1em; padding-bottom: 1em;