forked from MapComplete/MapComplete
		
	Replace userbadge with panel access to user information, add more information to user profile
This commit is contained in:
		
							parent
							
								
									bc85c9bbe7
								
							
						
					
					
						commit
						6f018a2fd8
					
				
					 19 changed files with 398 additions and 174 deletions
				
			
		|  | @ -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")) | ||||
|  |  | |||
|  | @ -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<boolean> | ||||
|     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() { | ||||
|  |  | |||
|  | @ -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) | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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( | ||||
|  |  | |||
|  | @ -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 | ||||
|         ) | ||||
|  |  | |||
|  | @ -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 | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | @ -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<Loc>, 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<Loc> }) { | ||||
|         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" | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | @ -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") | ||||
|  |  | |||
|  | @ -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);") | ||||
|     } | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ class LoginButton extends SubtleButton { | |||
| 
 | ||||
| export class LoginToggle extends VariableUiElement { | ||||
|     constructor( | ||||
|         el, | ||||
|         el: BaseUIElement, | ||||
|         text: BaseUIElement | string, | ||||
|         state: { | ||||
|             osmConnection: OsmConnection | ||||
|  |  | |||
|  | @ -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", | ||||
|  |  | |||
							
								
								
									
										52
									
								
								assets/svg/login.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								assets/svg/login.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <svg | ||||
|    width="375px" | ||||
|    height="375px" | ||||
|    viewBox="0 0 375 375" | ||||
|    version="1.1" | ||||
|    id="svg11" | ||||
|    sodipodi:docname="login.svg" | ||||
|    inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <defs | ||||
|      id="defs15" /> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview13" | ||||
|      pagecolor="#505050" | ||||
|      bordercolor="#eeeeee" | ||||
|      borderopacity="1" | ||||
|      inkscape:pageshadow="0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      showgrid="false" | ||||
|      inkscape:zoom="1.3821795" | ||||
|      inkscape:cx="194.62016" | ||||
|      inkscape:cy="176.89453" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="995" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="0" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="svg11" /> | ||||
|   <path | ||||
|      style="fill:none;stroke:#000000;stroke-width:39.7328;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | ||||
|      d="m 237.15027,94.152359 c 0,0 -92.37109,68.046801 -92.69922,93.515521 -0.32428,25.46887 92.69922,93.7423 92.69922,93.7423" | ||||
|      id="path2" /> | ||||
|   <path | ||||
|      style="fill:none;stroke:#000000;stroke-width:33.75;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" | ||||
|      d="M 148.99403,187.46096 H 359.47448" | ||||
|      id="path4" /> | ||||
|   <path | ||||
|      style="fill:none;stroke:#000000;stroke-width:31.3235;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | ||||
|      d="m 166.75391,294.40998 0,5.70716 c 0,33.18364 -26.84767,33.62896 -26.84767,33.62896 0,0 -52.734369,0.74551 -85.976555,0.74551 -33.246085,0 -30.578116,-33.03127 -30.578116,-33.03127 l 0.773433,-112.8359" | ||||
|      id="path8" | ||||
|      sodipodi:nodetypes="cscscc" /> | ||||
|   <path | ||||
|      style="fill:none;stroke:#000000;stroke-width:31.3235;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" | ||||
|      d="m 166.75391,82.8389 v -5.70716 c 0,-33.18364 -26.84767,-33.62896 -26.84767,-33.62896 0,0 -52.734369,-0.74551 -85.976555,-0.74551 -33.246085,0 -30.578116,33.03127 -30.578116,33.03127 l 0.773433,112.8359" | ||||
|      id="path1167" | ||||
|      sodipodi:nodetypes="cscscc" /> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										58
									
								
								assets/svg/person.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								assets/svg/person.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    width="100" | ||||
|    height="100" | ||||
|    viewBox="0 0 26.458333 26.458333" | ||||
|    version="1.1" | ||||
|    id="svg5" | ||||
|    inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)" | ||||
|    sodipodi:docname="person.svg" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview7" | ||||
|      pagecolor="#505050" | ||||
|      bordercolor="#eeeeee" | ||||
|      borderopacity="1" | ||||
|      inkscape:pageshadow="0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      inkscape:document-units="mm" | ||||
|      showgrid="false" | ||||
|      inkscape:snap-global="false" | ||||
|      units="px" | ||||
|      inkscape:zoom="3.629" | ||||
|      inkscape:cx="65.858363" | ||||
|      inkscape:cy="51.11601" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="995" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="0" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="layer1" /> | ||||
|   <defs | ||||
|      id="defs2" /> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(-36.012339,-111.57266)"> | ||||
|     <path | ||||
|        style="fill:#000000;stroke-width:0.264583" | ||||
|        id="path928" | ||||
|        d="" /> | ||||
|     <path | ||||
|        style="fill:#000000;stroke-width:0.264583" | ||||
|        id="path890" | ||||
|        d="" /> | ||||
|     <path | ||||
|        id="path3123" | ||||
|        style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.12697;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|        d="m 45.80331,124.75744 0.05184,1.66724 c -10.853713,0.85314 -8.811666,5.58744 -9.743599,11.32685 8.722476,-0.064 17.444809,-0.0283 26.167302,-2e-5 -0.931933,-5.73941 1.110115,-10.47371 -9.743599,-11.32685 l 0.05184,-1.66724 c 1.828852,-2.39569 4.204525,-13.02917 -3.49306,-12.94766 -7.697588,0.0815 -5.10528,10.57071 -3.290715,12.94768 z" | ||||
|        sodipodi:nodetypes="cccccccc" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2 KiB | 
|  | @ -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. | ||||
|  |  | |||
|  | @ -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 { | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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" | ||||
|  |  | |||
							
								
								
									
										48
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										48
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -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", | ||||
|  |  | |||
|  | @ -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", | ||||
|  |  | |||
							
								
								
									
										11
									
								
								theme.html
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								theme.html
									
										
									
									
									
								
							|  | @ -49,14 +49,9 @@ | |||
| 
 | ||||
| <div class="very-small-screen fixed inset-0 block z-above-controls" id="on-small-screen"></div> | ||||
| <div class="fixed inset-0 block z-above-controls hidden hidden-on-very-small-screen md:w-1/3" style="min-width: 28rem" id="fullscreen"></div> | ||||
| <div class="z-index-above-map pointer-events-none" id="topleft-tools"> | ||||
|     <div class="p-3 flex flex-col items-end sm:items-start sm:flex-row sm:flex-wrap w-full sm:justify-between"> | ||||
|         <div class="shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto" | ||||
|              id="searchbox"></div> | ||||
|         <div class="m-1 pointer-events-auto" id="userbadge"></div> | ||||
|     </div> | ||||
|     <div class="rounded-3xl overflow-hidden ml-3" id="messagesbox"></div> | ||||
| </div> | ||||
| 
 | ||||
| <div class="absolute top-3 left-3 rounded-3xl z-above-map" id="top-left"></div> | ||||
| <div class="absolute top-3 right-2 rounded-3xl z-above-map" id="top-right"></div> | ||||
| 
 | ||||
| <div class="absolute bottom-3 left-3 rounded-3xl z-above-map" id="bottom-left"></div> | ||||
| <div class="absolute bottom-3 right-2 rounded-3xl z-above-map" id="bottom-right"></div> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue