diff --git a/Logic/Osm/OsmConnection.ts b/Logic/Osm/OsmConnection.ts index 3c79b3023..5d35d2b9c 100644 --- a/Logic/Osm/OsmConnection.ts +++ b/Logic/Osm/OsmConnection.ts @@ -16,9 +16,12 @@ export default class UserDetails { public csCount = 0 public img: string public unreadMessages = 0 - public totalMessages = 0 - home: { lon: number; lat: number } + public totalMessages: number = 0 + public home: { lon: number; lat: number } public backend: string + public account_created: string; + public tracesCount: number = 0; + public description: string; constructor(backend: string) { this.backend = backend @@ -209,16 +212,22 @@ export class OsmConnection { data.loggedIn = true console.log("Login completed, userinfo is ", userInfo) data.name = userInfo.getAttribute("display_name") + data.account_created = userInfo.getAttribute("account_created") data.uid = Number(userInfo.getAttribute("id")) - data.csCount = userInfo.getElementsByTagName("changesets")[0].getAttribute("count") + data.csCount = Number.parseInt( userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? 0) + data.tracesCount = Number.parseInt( userInfo.getElementsByTagName("changesets")[0].getAttribute("count") ?? 0) data.img = undefined const imgEl = userInfo.getElementsByTagName("img") if (imgEl !== undefined && imgEl[0] !== undefined) { data.img = imgEl[0].getAttribute("href") } - data.img = data.img ?? Img.AsData(Svg.osm_logo) + data.img = data.img ?? Img.AsData(Svg.person_img) + const description = userInfo.getElementsByTagName("description") + if (description !== undefined && description[0] !== undefined) { + data.description = description[0]?.innerHTML + } const homeEl = userInfo.getElementsByTagName("home") if (homeEl !== undefined && homeEl[0] !== undefined) { const lat = parseFloat(homeEl[0].getAttribute("lat")) diff --git a/UI/Base/ScrollableFullScreen.ts b/UI/Base/ScrollableFullScreen.ts index da6280ee6..c36894ebd 100644 --- a/UI/Base/ScrollableFullScreen.ts +++ b/UI/Base/ScrollableFullScreen.ts @@ -16,7 +16,7 @@ import Title from "./Title" * */ export default class ScrollableFullScreen { - private static readonly empty = new FixedUiElement("") + private static readonly empty = ScrollableFullScreen.initEmpty() private static _currentlyOpen: ScrollableFullScreen public isShown: UIEventSource private hashToShow: string @@ -61,6 +61,7 @@ export default class ScrollableFullScreen { } }) } + isShown.addCallback((isShown) => { if (isShown) { // We first must set the hash, then activate the panel @@ -68,8 +69,13 @@ export default class ScrollableFullScreen { if (setHash) { Hash.hash.setData(hashToShow) } + ScrollableFullScreen._currentlyOpen = self self.Activate() + } else { + if(self.hashToShow !== undefined){ + Hash.hash.setData(undefined) + } // Some cleanup... ScrollableFullScreen.collapse() @@ -77,6 +83,18 @@ export default class ScrollableFullScreen { }) } + private static initEmpty(): FixedUiElement{ + + document.addEventListener("keyup", function (event) { + if (event.code === "Escape") { + ScrollableFullScreen.collapse() + event.preventDefault() + } + }) + + return new FixedUiElement("") + + } public static collapse(){ const fs = document.getElementById("fullscreen") if (fs !== null) { @@ -84,7 +102,10 @@ export default class ScrollableFullScreen { fs.classList.add("hidden") } - ScrollableFullScreen._currentlyOpen?.isShown?.setData(false) + const opened = ScrollableFullScreen._currentlyOpen + if( opened !== undefined){ + opened?.isShown?.setData(false) + } } Destroy() { diff --git a/UI/BigComponents/ExtraLinkButton.ts b/UI/BigComponents/ExtraLinkButton.ts index 92b5621d6..fcc9fd77d 100644 --- a/UI/BigComponents/ExtraLinkButton.ts +++ b/UI/BigComponents/ExtraLinkButton.ts @@ -42,11 +42,11 @@ export default class ExtraLinkButton extends UIElement { const isIframe = window !== window.top - if (c.requirements.has("iframe") && !isIframe) { + if (c.requirements?.has("iframe") && !isIframe) { return undefined } - if (c.requirements.has("no-iframe") && isIframe) { + if (c.requirements?.has("no-iframe") && isIframe) { return undefined } @@ -82,11 +82,11 @@ export default class ExtraLinkButton extends UIElement { newTab: c.newTab, }) - if (c.requirements.has("no-welcome-message")) { + if (c.requirements?.has("no-welcome-message")) { link = new Toggle(undefined, link, this.state.featureSwitchWelcomeMessage) } - if (c.requirements.has("welcome-message")) { + if (c.requirements?.has("welcome-message")) { link = new Toggle(link, undefined, this.state.featureSwitchWelcomeMessage) } diff --git a/UI/BigComponents/LeftControls.ts b/UI/BigComponents/LeftControls.ts index 6cae112d3..867ba4b8e 100644 --- a/UI/BigComponents/LeftControls.ts +++ b/UI/BigComponents/LeftControls.ts @@ -13,6 +13,7 @@ import { VariableUiElement } from "../Base/VariableUIElement" import FeatureInfoBox from "../Popup/FeatureInfoBox" import CopyrightPanel from "./CopyrightPanel" import FeaturePipelineState from "../../Logic/State/FeaturePipelineState" +import {FixedUiElement} from "../Base/FixedUiElement"; export default class LeftControls extends Combine { constructor( diff --git a/UI/BigComponents/RightControls.ts b/UI/BigComponents/RightControls.ts index c6c4fd7a5..d45bba768 100644 --- a/UI/BigComponents/RightControls.ts +++ b/UI/BigComponents/RightControls.ts @@ -18,7 +18,7 @@ export default class RightControls extends Combine { const geolocationButton = new Toggle( new MapControlButton(geolocatioHandler, { dontStyle: true, - }), + }).SetClass("p-1"), undefined, state.featureSwitchGeolocation ) diff --git a/UI/BigComponents/UserBadge.ts b/UI/BigComponents/UserBadge.ts deleted file mode 100644 index d036b6ec3..000000000 --- a/UI/BigComponents/UserBadge.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { VariableUiElement } from "../Base/VariableUIElement" -import Svg from "../../Svg" -import Combine from "../Base/Combine" -import { FixedUiElement } from "../Base/FixedUiElement" -import LanguagePicker from "../LanguagePicker" -import Translations from "../i18n/Translations" -import Link from "../Base/Link" -import Toggle from "../Input/Toggle" -import Img from "../Base/Img" -import MapState from "../../Logic/State/MapState" -import { LoginToggle } from "../Popup/LoginButton" - -export default class UserBadge extends LoginToggle { - constructor(state: MapState) { - const userDetails = state.osmConnection.userDetails - const logout = Svg.logout_svg().onClick(() => { - state.osmConnection.LogOut() - }) - - const userBadge = new VariableUiElement( - userDetails.map((user) => { - { - const homeButton = new VariableUiElement( - userDetails.map((userinfo) => { - if (userinfo.home) { - return Svg.home_svg() - } - return " " - }) - ).onClick(() => { - const home = state.osmConnection.userDetails.data?.home - if (home === undefined) { - return - } - state.leafletMap.data?.setView([home.lat, home.lon], 16) - }) - - const linkStyle = "flex items-baseline" - const languagePicker = ( - new LanguagePicker(state.layoutToUse.language, "") ?? new FixedUiElement("") - ).SetStyle("width:min-content;") - - let messageSpan = new Link( - new Combine([Svg.envelope, "" + user.totalMessages]).SetClass(linkStyle), - `${user.backend}/messages/inbox`, - true - ) - - const csCount = new Link( - new Combine([Svg.star, "" + user.csCount]).SetClass(linkStyle), - `${user.backend}/user/${user.name}/history`, - true - ) - - if (user.unreadMessages > 0) { - messageSpan = new Link( - new Combine([Svg.envelope, "" + user.unreadMessages]), - `${user.backend}/messages/inbox`, - true - ).SetClass("alert") - } - - let dryrun = new Toggle( - new FixedUiElement("TESTING").SetClass("alert font-xs p-0 max-h-4"), - undefined, - state.featureSwitchIsTesting - ) - - const settings = new Link( - Svg.gear, - `${user.backend}/user/${encodeURIComponent(user.name)}/account`, - true - ) - - const userName = new Link( - new FixedUiElement(user.name), - `${user.backend}/user/${user.name}`, - true - ) - - const userStats = new Combine([ - homeButton, - settings, - messageSpan, - csCount, - languagePicker, - logout, - ]).SetClass("userstats") - - const usertext = new Combine([ - new Combine([userName, dryrun]).SetClass("flex justify-end w-full"), - userStats, - ]).SetClass("flex flex-col sm:w-auto sm:pl-2 overflow-hidden w-0") - const userIcon = ( - user.img === undefined ? Svg.osm_logo_ui() : new Img(user.img) - ) - .SetClass( - "rounded-full opacity-0 m-0 p-0 duration-500 w-16 min-width-16 h16 float-left" - ) - .onClick(() => { - if (usertext.HasClass("w-0")) { - usertext.RemoveClass("w-0") - usertext.SetClass("w-min pl-2") - } else { - usertext.RemoveClass("w-min") - usertext.RemoveClass("pl-2") - usertext.SetClass("w-0") - } - }) - - return new Combine([usertext, userIcon]).SetClass("h-16 flex bg-white") - } - }) - ) - - super( - new Combine([ - userBadge.SetClass("inline-block m-0 w-full").SetStyle("pointer-events: all"), - ]).SetClass("shadow rounded-full h-min overflow-hidden block w-full md:w-max"), - Translations.t.general.loginWithOpenStreetMap, - state - ) - } -} diff --git a/UI/BigComponents/UserInformation.ts b/UI/BigComponents/UserInformation.ts index e69de29bb..d3ffa4324 100644 --- a/UI/BigComponents/UserInformation.ts +++ b/UI/BigComponents/UserInformation.ts @@ -0,0 +1,109 @@ +import ScrollableFullScreen from "../Base/ScrollableFullScreen"; +import Translations from "../i18n/Translations"; +import {OsmConnection} from "../../Logic/Osm/OsmConnection"; +import Combine from "../Base/Combine"; +import {SubtleButton} from "../Base/SubtleButton"; +import Svg from "../../Svg"; +import {VariableUiElement} from "../Base/VariableUIElement"; +import Img from "../Base/Img"; +import {FixedUiElement} from "../Base/FixedUiElement"; +import Link from "../Base/Link"; +import {UIEventSource} from "../../Logic/UIEventSource"; +import Loc from "../../Models/Loc"; +import BaseUIElement from "../BaseUIElement"; +import Showdown from "showdown" +import LanguagePicker from "../LanguagePicker"; +import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"; + +class UserInformationMainPanel extends Combine { + constructor(osmConnection: OsmConnection, locationControl: UIEventSource, layout: LayoutConfig) { + const t = Translations.t.userinfo; + const imgSize = "h-6 w-6" + const ud = osmConnection.userDetails; + super([ + + new VariableUiElement(ud.map(ud => { + + if (!ud?.loggedIn) { + // Not logged in + return new SubtleButton( + Svg.login_svg(), "Login", {imgSize} + ).onClick(osmConnection.AttemptLogin) + } + + let img: Img = Svg.person_svg(); + if (ud.img !== undefined) { + img = new Img(ud.img) + } + img.SetClass("rounded-full h-12 w-12 m-4") + + let description: BaseUIElement = undefined + if (ud.description) { + const editButton = new Link( + Svg.pencil_svg().SetClass("h-4 w-4"), + "https://www.openstreetmap.org/profile/edit", + true + ).SetClass("absolute block bg-subtle rounded-full p-2 bottom-2 right-2 w-min self-end") + + description = new Combine([ + new FixedUiElement(new Showdown.Converter().makeHtml(ud.description)).SetClass("link-underline"), + editButton + ]).SetClass("relative w-full m-2") + + } else { + description = new Combine([ + t.noDescription, new SubtleButton(Svg.pencil_svg(), t.noDescriptionCallToAction, {imgSize}) + ]).SetClass("w-full m-2") + } + + let panToHome: BaseUIElement; + if (ud.home) { + panToHome = new SubtleButton(Svg.home_svg(), t.moveToHome, {imgSize}) + .onClick(() => { + const home = ud?.home + if (home === undefined) { + return + } + locationControl.setData({...home, zoom: 16}) + } + ); + } + + return new Combine([ + new Combine([img, description]).SetClass("flex border border-black rounded-md"), + new LanguagePicker(layout.language, Translations.t.general.pickLanguage.Clone()), + + new SubtleButton(Svg.envelope_svg(), new Combine([t.gotoInbox, + ud.unreadMessages == 0 ? undefined : t.newMessages.SetClass("alert block") + ]), + {imgSize, url: `${ud.backend}/messages/inbox`, newTab: true}), + new SubtleButton(Svg.gear_svg(), t.gotoSettings, + {imgSize, url: `${ud.backend}/user/${encodeURIComponent(ud.name)}/account`, newTab: true}), + panToHome, + new SubtleButton(Svg.logout_svg(), Translations.t.general.logout, {imgSize}).onClick(osmConnection.LogOut) + + ]) + } + )).SetClass("flex flex-col"), + + + ]); + } +} + +export default class UserInformationPanel extends ScrollableFullScreen { + constructor(state: { + layoutToUse: LayoutConfig; + osmConnection: OsmConnection, locationControl: UIEventSource }) { + const t = Translations.t.general; + super( + () => { + return new VariableUiElement(state.osmConnection.userDetails.map(ud => "Welcome " + ud.name)) + }, + () => { + return new UserInformationMainPanel(state.osmConnection, state.locationControl, state.layoutToUse) + }, + "userinfo" + ); + } +} diff --git a/UI/DefaultGUI.ts b/UI/DefaultGUI.ts index 974bbc28c..683519819 100644 --- a/UI/DefaultGUI.ts +++ b/UI/DefaultGUI.ts @@ -6,7 +6,6 @@ import FullWelcomePaneWithTabs from "./BigComponents/FullWelcomePaneWithTabs" import MapControlButton from "./MapControlButton" import Svg from "../Svg" import Toggle from "./Input/Toggle" -import UserBadge from "./BigComponents/UserBadge" import SearchAndGo from "./BigComponents/SearchAndGo" import BaseUIElement from "./BaseUIElement" import LeftControls from "./BigComponents/LeftControls" @@ -25,6 +24,11 @@ import Combine from "./Base/Combine" import AddNewMarker from "./BigComponents/AddNewMarker" import FilteredLayer from "../Models/FilteredLayer" import ExtraLinkButton from "./BigComponents/ExtraLinkButton" +import {VariableUiElement} from "./Base/VariableUIElement"; +import Img from "./Base/Img"; +import UserInformationPanel from "./BigComponents/UserInformation"; +import {LoginToggle} from "./Popup/LoginButton"; +import {FixedUiElement} from "./Base/FixedUiElement"; /** * The default MapComplete GUI initializer @@ -180,14 +184,38 @@ export default class DefaultGUI { const self = this new Combine([ - Toggle.If(state.featureSwitchUserbadge, () => new UserBadge(state)), + Toggle.If(state.featureSwitchUserbadge, () => { + + const userInfo = new UserInformationPanel(state) + + const mapControl = new MapControlButton( + new VariableUiElement(state.osmConnection.userDetails.map(ud => { + if (ud?.img === undefined) { + return Svg.person_ui().SetClass("mt-1 block") + } + return new Img(ud?.img); + })).SetClass("block rounded-full overflow-hidden"), + { + dontStyle: true + } + ).onClick(() => userInfo.Activate()); + + return new LoginToggle( + mapControl, Translations.t.general.loginWithOpenStreetMap, state + ) + + + + }), Toggle.If( state.featureSwitchExtraLinkEnabled, () => new ExtraLinkButton(state, state.layoutToUse.extraLink) ), + Toggle.If(state.featureSwitchWelcomeMessage, () => self.InitWelcomeMessage()), + Toggle.If(state.featureSwitchIsTesting, () => new FixedUiElement("TESTING").SetClass("alert m-2 border-2 border-black")) ]) .SetClass("flex flex-col") - .AttachTo("userbadge") + .AttachTo("top-left") new Combine([ new ExtraLinkButton(state, { @@ -201,11 +229,8 @@ export default class DefaultGUI { .SetClass("flex items-center justify-center normal-background h-full") .AttachTo("on-small-screen") - Toggle.If(state.featureSwitchSearch, () => new SearchAndGo(state)).AttachTo("searchbox") + Toggle.If(state.featureSwitchSearch, () => new SearchAndGo(state).SetClass("shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto")).AttachTo("top-right") - Toggle.If(state.featureSwitchWelcomeMessage, () => self.InitWelcomeMessage()).AttachTo( - "messagesbox" - ) new LeftControls(state, guiState).AttachTo("bottom-left") new RightControls(state).AttachTo("bottom-right") diff --git a/UI/MapControlButton.ts b/UI/MapControlButton.ts index 004aae8ee..684a8d026 100644 --- a/UI/MapControlButton.ts +++ b/UI/MapControlButton.ts @@ -14,9 +14,10 @@ export default class MapControlButton extends Combine { super([contents]) if (!options?.dontStyle) { contents.SetClass("mapcontrol p-1") + this.SetClass("p-1") } this.SetClass( - "relative block rounded-full w-10 h-10 p-1 pointer-events-auto z-above-map subtle-background m-0.5 md:m-1" + "relative block rounded-full w-10 h-10 pointer-events-auto z-above-map subtle-background m-0.5 md:m-1" ) this.SetStyle("box-shadow: 0 0 10px var(--shadow-color);") } diff --git a/UI/Popup/LoginButton.ts b/UI/Popup/LoginButton.ts index d85b89a45..872e143b4 100644 --- a/UI/Popup/LoginButton.ts +++ b/UI/Popup/LoginButton.ts @@ -24,7 +24,7 @@ class LoginButton extends SubtleButton { export class LoginToggle extends VariableUiElement { constructor( - el, + el: BaseUIElement, text: BaseUIElement | string, state: { osmConnection: OsmConnection diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 2e75fd955..9352c1631 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -735,6 +735,14 @@ ], "sources": [] }, + { + "path": "login.svg", + "license": "CC0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] + }, { "path": "logo.svg", "license": "CC0; trivial", @@ -981,6 +989,14 @@ " https://commons.wikimedia.org/wiki/File:Octicons-pencil.svg" ] }, + { + "path": "person.svg", + "license": "CC0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] + }, { "path": "pin.svg", "license": "CC0; trivial", @@ -1293,16 +1309,6 @@ ], "sources": [] }, - { - "path": "twitter.svg", - "license": "Logo - all rights reserved", - "authors": [ - "Twitter Inc." - ], - "sources": [ - "https://about.twitter.com/en/who-we-are/brand-toolkit" - ] - }, { "path": "up.svg", "license": "CC0; trivial", diff --git a/assets/svg/login.svg b/assets/svg/login.svg new file mode 100644 index 000000000..6b7bf28f7 --- /dev/null +++ b/assets/svg/login.svg @@ -0,0 +1,52 @@ + + + + + + + + + diff --git a/assets/svg/person.svg b/assets/svg/person.svg new file mode 100644 index 000000000..61f250de1 --- /dev/null +++ b/assets/svg/person.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + diff --git a/css/index-tailwind-output.css b/css/index-tailwind-output.css index 96ad02a02..3b6b81b32 100644 --- a/css/index-tailwind-output.css +++ b/css/index-tailwind-output.css @@ -648,8 +648,8 @@ video { top: 14rem; } -.bottom-3 { - bottom: 0.75rem; +.top-3 { + top: 0.75rem; } .left-3 { @@ -660,6 +660,10 @@ video { right: 0.5rem; } +.bottom-3 { + bottom: 0.75rem; +} + .top-2 { top: 0.5rem; } @@ -692,6 +696,10 @@ video { left: 0px; } +.bottom-2 { + bottom: 0.5rem; +} + .left-1\/2 { left: 50%; } @@ -775,10 +783,6 @@ video { margin-bottom: 0.75rem; } -.ml-3 { - margin-left: 0.75rem; -} - .mb-4 { margin-bottom: 1rem; } @@ -795,16 +799,20 @@ video { margin-right: 2rem; } +.mt-1 { + margin-top: 0.25rem; +} + .mt-4 { margin-top: 1rem; } -.mr-2 { - margin-right: 0.5rem; +.ml-3 { + margin-left: 0.75rem; } -.mt-1 { - margin-top: 0.25rem; +.mr-2 { + margin-right: 0.5rem; } .ml-4 { @@ -1810,6 +1818,10 @@ video { timeout: 90; } +.\[key\:string\] { + key: string; +} + :root { /* The main colour scheme of mapcomplete is configured here. * For a custom styling, set 'customCss' in your layoutConfig and overwrite some of these. diff --git a/css/mobile.css b/css/mobile.css index 42532a321..dfef43f64 100644 --- a/css/mobile.css +++ b/css/mobile.css @@ -11,7 +11,7 @@ Contains tweaks for small screens } -@media only screen and (min-height: 300px) and (min-width: 225px) { +@media only screen and (min-height: 175px) and (min-width: 175px) { .very-small-screen { display: none !important; } @@ -23,7 +23,7 @@ Contains tweaks for small screens } -@media not screen and (min-height: 300px) and (min-width: 225px) { +@media not screen and (min-height: 175px) and (min-width: 175px) { .very-small-screen { } diff --git a/langs/en.json b/langs/en.json index 38286d530..e3a20f3db 100644 --- a/langs/en.json +++ b/langs/en.json @@ -927,6 +927,15 @@ "missing": "{count} untranslated strings", "notImmediate": "Translations are not updated directly. This typically takes a few days" }, + "userinfo": { + "gotoInbox": "Open your inbox", + "gotoSettings": "Go to your settings on OpenStreetMap.org", + "moveToHome": "Move the map to your home location", + "newMessages": "you have new messages", + "noDescription": "You don't have a description on your profile yet", + "noDescriptionCallToAction": "Add a profile description", + "welcome": "Welcome {user}" + }, "validation": { "color": { "description": "A color or hexcode" diff --git a/package-lock.json b/package-lock.json index 4cadebbf1..51e0e466a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@turf/distance": "^6.5.0", "@turf/length": "^6.5.0", "@turf/turf": "^6.5.0", + "@types/showdown": "^2.0.0", "chart.js": "^3.8.0", "country-language": "^0.1.7", "csv-parse": "^5.1.0", @@ -39,6 +40,7 @@ "osmtogeojson": "^3.0.0-beta.5", "papaparse": "^5.3.1", "prompt-sync": "^4.2.0", + "showdown": "^2.1.0", "svg-path-parser": "^1.1.0", "tailwindcss": "^3.1.8", "togpx": "^0.5.4", @@ -3464,6 +3466,11 @@ "integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==", "optional": true }, + "node_modules/@types/showdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz", + "integrity": "sha512-70xBJoLv+oXjB5PhtA8vo7erjLDp9/qqI63SRHm4REKrwuPOLs8HhXwlZJBJaB4kC18cCZ1UUZ6Fb/PLFW4TCA==" + }, "node_modules/@types/wikidata-sdk": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/wikidata-sdk/-/wikidata-sdk-6.1.0.tgz", @@ -4902,6 +4909,14 @@ "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", "dev": true }, + "node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -13636,6 +13651,21 @@ "node": ">=0.10.0" } }, + "node_modules/showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "dependencies": { + "commander": "^9.0.0" + }, + "bin": { + "showdown": "bin/showdown.js" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.me/tiviesantos" + } + }, "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -19382,6 +19412,11 @@ "integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==", "optional": true }, + "@types/showdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz", + "integrity": "sha512-70xBJoLv+oXjB5PhtA8vo7erjLDp9/qqI63SRHm4REKrwuPOLs8HhXwlZJBJaB4kC18cCZ1UUZ6Fb/PLFW4TCA==" + }, "@types/wikidata-sdk": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/wikidata-sdk/-/wikidata-sdk-6.1.0.tgz", @@ -20552,6 +20587,11 @@ "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", "dev": true }, + "commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -27433,6 +27473,14 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "requires": { + "commander": "^9.0.0" + } + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", diff --git a/package.json b/package.json index 3dddb05ee..4b508d3d0 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "@turf/distance": "^6.5.0", "@turf/length": "^6.5.0", "@turf/turf": "^6.5.0", + "@types/showdown": "^2.0.0", "chart.js": "^3.8.0", "country-language": "^0.1.7", "csv-parse": "^5.1.0", @@ -99,6 +100,7 @@ "osmtogeojson": "^3.0.0-beta.5", "papaparse": "^5.3.1", "prompt-sync": "^4.2.0", + "showdown": "^2.1.0", "svg-path-parser": "^1.1.0", "tailwindcss": "^3.1.8", "togpx": "^0.5.4", diff --git a/theme.html b/theme.html index 88c973bc9..20c18fabd 100644 --- a/theme.html +++ b/theme.html @@ -49,14 +49,9 @@
-
-
- -
-
-
-
+ +
+