Styling: style menu- and theme-menu tabbed interface
This commit is contained in:
parent
a4a3b8a5ad
commit
14927497bd
6 changed files with 181 additions and 125 deletions
|
@ -1,20 +1,33 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import {createEventDispatcher} from "svelte";
|
||||||
import { XCircleIcon } from "@rgossiaux/svelte-heroicons/solid";
|
import {XCircleIcon} from "@rgossiaux/svelte-heroicons/solid";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The slotted element will be shown on top, with a lower-opacity border
|
* The slotted element will be shown on top, with a lower-opacity border
|
||||||
*/
|
*/
|
||||||
const dispatch = createEventDispatcher<{ close }>();
|
const dispatch = createEventDispatcher<{ close }>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="absolute top-0 right-0 w-screen h-screen overflow-auto" style="background-color: #00000088">
|
<div class="absolute top-0 right-0 w-screen h-screen p-4 md:p-6" style="background-color: #00000088">
|
||||||
<div class="flex flex-col m-4 sm:m-6 p-4 sm:p-6 md:m-8 rounded normal-background">
|
<div class="content normal-background">
|
||||||
<slot name="close-button">
|
<div class="rounded-xl">
|
||||||
<div class="w-8 h-8 absolute right-10 top-10 cursor-pointer" on:click={() => dispatch("close")}>
|
<slot></slot>
|
||||||
<XCircleIcon />
|
</div>
|
||||||
</div>
|
<slot name="close-button">
|
||||||
</slot>
|
<!-- The close button is placed _after_ the default slot in order to always paint it on top -->
|
||||||
<slot></slot>
|
<div class="w-8 h-8 absolute right-10 top-10 cursor-pointer" on:click={() => dispatch("close")}>
|
||||||
</div>
|
<XCircleIcon/>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.content {
|
||||||
|
height: calc( 100vh - 2rem );
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
box-shadow: 0 0 1rem #00000088;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,79 +1,121 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/**
|
/**
|
||||||
* Thin wrapper around 'TabGroup' which binds the state
|
* Thin wrapper around 'TabGroup' which binds the state
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui";
|
import {Tab, TabGroup, TabList, TabPanel, TabPanels} from "@rgossiaux/svelte-headlessui";
|
||||||
import { UIEventSource } from "../../Logic/UIEventSource";
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||||
|
|
||||||
export let tab: UIEventSource<number>;
|
export let tab: UIEventSource<number>;
|
||||||
let tabElements: HTMLElement[] = [];
|
let tabElements: HTMLElement[] = [];
|
||||||
$: tabElements[$tab]?.click();
|
$: tabElements[$tab]?.click();
|
||||||
$: {
|
$: {
|
||||||
if (tabElements[tab.data]) {
|
if (tabElements[tab.data]) {
|
||||||
window.setTimeout(() => tabElements[tab.data].click(), 50)
|
window.setTimeout(() => tabElements[tab.data].click(), 50)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<TabGroup defaultIndex={1} on:change={(e) =>{if(e.detail >= 0){tab.setData( e.detail); }} }>
|
<div class="tabbedgroup w-full h-full">
|
||||||
<TabList>
|
<TabGroup class="h-full w-full flex flex-col" defaultIndex={1}
|
||||||
<Tab class={({selected}) => selected ? "tab-selected" : "tab-unselected"}>
|
on:change={(e) =>{if(e.detail >= 0){tab.setData( e.detail); }} }>
|
||||||
<div bind:this={tabElements[0]} class="flex">
|
<div class="flex bg-gray-300 items-center justify-between sticky top-0">
|
||||||
<slot name="title0">
|
<TabList class="flex flex-wrap">
|
||||||
Tab 0
|
{#if $$slots.title1}
|
||||||
</slot>
|
<Tab class={({selected}) => "tab "+(selected ? "tab-selected" : "tab-unselected")}>
|
||||||
</div>
|
<div bind:this={tabElements[0]} class="flex">
|
||||||
</Tab>
|
<slot name="title0">
|
||||||
<Tab class={({selected}) => selected ? "tab-selected" : "tab-unselected"}>
|
Tab 0
|
||||||
<div bind:this={tabElements[1]} class="flex">
|
</slot>
|
||||||
<slot name="title1" />
|
</div>
|
||||||
</div>
|
</Tab>
|
||||||
</Tab>
|
{/if}
|
||||||
<Tab class={({selected}) => selected ? "tab-selected" : "tab-unselected"}>
|
{#if $$slots.title1}
|
||||||
<div bind:this={tabElements[2]} class="flex">
|
<Tab class={({selected}) => "tab "+(selected ? "tab-selected" : "tab-unselected")}>
|
||||||
<slot name="title2" />
|
<div bind:this={tabElements[1]} class="flex">
|
||||||
</div>
|
<slot name="title1"/>
|
||||||
</Tab>
|
</div>
|
||||||
<Tab class={({selected}) => selected ? "tab-selected" : "tab-unselected"}>
|
</Tab>
|
||||||
<div bind:this={tabElements[3]} class="flex">
|
{/if}
|
||||||
<slot name="title3" />
|
{#if $$slots.title2}
|
||||||
</div>
|
<Tab class={({selected}) => "tab "+(selected ? "tab-selected" : "tab-unselected")}>
|
||||||
</Tab>
|
<div bind:this={tabElements[2]} class="flex">
|
||||||
<Tab class={({selected}) => selected ? "tab-selected" : "tab-unselected"}>
|
<slot name="title2"/>
|
||||||
<div bind:this={tabElements[4]} class="flex">
|
</div>
|
||||||
<slot name="title4" />
|
</Tab>
|
||||||
</div>
|
{/if}
|
||||||
</Tab>
|
{#if $$slots.title3}
|
||||||
</TabList>
|
<Tab class={({selected}) => "tab "+(selected ? "tab-selected" : "tab-unselected")}>
|
||||||
<TabPanels defaultIndex={$tab}>
|
<div bind:this={tabElements[3]} class="flex">
|
||||||
<TabPanel>
|
<slot name="title3"/>
|
||||||
<slot name="content0">
|
</div>
|
||||||
<div>Empty</div>
|
</Tab>
|
||||||
</slot>
|
{/if}
|
||||||
</TabPanel>
|
{#if $$slots.title4}
|
||||||
<TabPanel>
|
<Tab class={({selected}) => "tab "+(selected ? "tab-selected" : "tab-unselected")}>
|
||||||
<slot name="content1" />
|
<div bind:this={tabElements[4]} class="flex">
|
||||||
</TabPanel>
|
<slot name="title4"/>
|
||||||
<TabPanel>
|
</div>
|
||||||
<slot name="content2" />
|
</Tab>
|
||||||
</TabPanel>
|
{/if}
|
||||||
<TabPanel>
|
</TabList>
|
||||||
<slot name="content3" />
|
<slot name="post-tablist"/>
|
||||||
</TabPanel>
|
</div>
|
||||||
<TabPanel>
|
<div class="overflow-y-auto normal-background">
|
||||||
<slot name="content4" />
|
|
||||||
</TabPanel>
|
|
||||||
</TabPanels>
|
|
||||||
</TabGroup>
|
|
||||||
|
|
||||||
|
<TabPanels defaultIndex={$tab}>
|
||||||
|
<TabPanel>
|
||||||
|
<slot name="content0">
|
||||||
|
<div>Empty</div>
|
||||||
|
</slot>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel>
|
||||||
|
<slot name="content1"/>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel>
|
||||||
|
<slot name="content2"/>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel>
|
||||||
|
<slot name="content3"/>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel>
|
||||||
|
<slot name="content4"/>
|
||||||
|
</TabPanel>
|
||||||
|
</TabPanels>
|
||||||
|
</div>
|
||||||
|
</TabGroup>
|
||||||
|
</div>
|
||||||
<style>
|
<style>
|
||||||
.tab-selected {
|
.tabbedgroup {
|
||||||
|
max-height: 100vh;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.tab) {
|
||||||
|
margin: 0.25rem;
|
||||||
|
padding: 0.25rem;
|
||||||
|
padding-left: 0.75rem;
|
||||||
|
padding-right: 0.75rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.tab .flex) {
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.tab span|div) {
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.tab-selected) {
|
||||||
background-color: rgb(59 130 246);
|
background-color: rgb(59 130 246);
|
||||||
color: rgb(255 255 255);
|
color: rgb(255 255 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-unselected {
|
:global(.tab-unselected) {
|
||||||
background-color: rgb(255 255 255);
|
background-color: rgb(255 255 255);
|
||||||
color: rgb(0 0 0);
|
color: rgb(0 0 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,15 @@
|
||||||
{:else}
|
{:else}
|
||||||
<UserCircleIcon class="w-12 h-12" />
|
<UserCircleIcon class="w-12 h-12" />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex flex-col relative">
|
<div class="flex flex-col">
|
||||||
<h3>{$userdetails.name}</h3>
|
<h3>{$userdetails.name}</h3>
|
||||||
{#if description}
|
{#if description}
|
||||||
<FromHtml src={description} />
|
<FromHtml src={description} />
|
||||||
<a href={osmConnection.Backend() + "/profile/edit"} target="_blank">
|
<a href={osmConnection.Backend() + "/profile/edit"} target="_blank" class="link-no-underline flex subtle-background items-center w-fit self-end">
|
||||||
<PencilAltIcon class="p-2 w-6 h-6 subtle-background rounded-full absolute right-1 bottom-1" />
|
<PencilAltIcon slot="image" class="p-2 w-8 h-8" />
|
||||||
|
<Tr slot="message" t={Translations.t.userinfo.editDescription} />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{:else}
|
{:else}
|
||||||
<Tr t={Translations.t. userinfo.noDescription} />
|
<Tr t={Translations.t. userinfo.noDescription} />
|
||||||
<a href={osmConnection.Backend() + "/profile/edit"} target="_blank" class="flex subtle-background items-center">
|
<a href={osmConnection.Backend() + "/profile/edit"} target="_blank" class="flex subtle-background items-center">
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
import type {MapProperties} from "../Models/MapProperties";
|
import type {MapProperties} from "../Models/MapProperties";
|
||||||
import Geosearch from "./BigComponents/Geosearch.svelte";
|
import Geosearch from "./BigComponents/Geosearch.svelte";
|
||||||
import Translations from "./i18n/Translations";
|
import Translations from "./i18n/Translations";
|
||||||
import {CogIcon, EyeIcon, MenuIcon} from "@rgossiaux/svelte-heroicons/solid";
|
import {CogIcon, EyeIcon, MenuIcon, XCircleIcon} from "@rgossiaux/svelte-heroicons/solid";
|
||||||
import Tr from "./Base/Tr.svelte";
|
import Tr from "./Base/Tr.svelte";
|
||||||
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte";
|
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte";
|
||||||
import FloatOver from "./Base/FloatOver.svelte";
|
import FloatOver from "./Base/FloatOver.svelte";
|
||||||
|
@ -149,9 +149,12 @@
|
||||||
<If condition={selectedElementView.map(v => v !== undefined && selectedLayer.data !== undefined && !selectedLayer.data.popupInFloatover,[ selectedLayer] )}>
|
<If condition={selectedElementView.map(v => v !== undefined && selectedLayer.data !== undefined && !selectedLayer.data.popupInFloatover,[ selectedLayer] )}>
|
||||||
<ModalRight on:close={() => {selectedElement.setData(undefined)}}>
|
<ModalRight on:close={() => {selectedElement.setData(undefined)}}>
|
||||||
<div class="absolute flex flex-col h-full w-full normal-background">
|
<div class="absolute flex flex-col h-full w-full normal-background">
|
||||||
<ToSvelte construct={new VariableUiElement(selectedElementTitle)}></ToSvelte>
|
<ToSvelte construct={new VariableUiElement(selectedElementTitle)}>
|
||||||
|
<!-- Title -->
|
||||||
<ToSvelte construct={new VariableUiElement(selectedElementView)}></ToSvelte>
|
</ToSvelte>
|
||||||
|
<ToSvelte construct={new VariableUiElement(selectedElementView).SetClass("overflow-auto")}>
|
||||||
|
<!-- Main view -->
|
||||||
|
</ToSvelte>
|
||||||
</div>
|
</div>
|
||||||
</ModalRight>
|
</ModalRight>
|
||||||
</If>
|
</If>
|
||||||
|
@ -163,9 +166,14 @@
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<If condition={state.guistate.themeIsOpened}>
|
<If condition={state.guistate.themeIsOpened}>
|
||||||
<!-- Theme page -->
|
<!-- Theme menu -->
|
||||||
<FloatOver on:close={() => state.guistate.themeIsOpened.setData(false)}>
|
<FloatOver>
|
||||||
|
<span slot="close-button"><!-- Disable the close button --></span>
|
||||||
<TabbedGroup tab={state.guistate.themeViewTabIndex}>
|
<TabbedGroup tab={state.guistate.themeViewTabIndex}>
|
||||||
|
<div slot="post-tablist">
|
||||||
|
<XCircleIcon class="w-8 h-8 mr-2" on:click={() => state.guistate.themeIsOpened.setData(false)}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Tr slot="title0" t={layout.title}/>
|
<Tr slot="title0" t={layout.title}/>
|
||||||
|
|
||||||
<div slot="content0">
|
<div slot="content0">
|
||||||
|
@ -240,8 +248,12 @@
|
||||||
|
|
||||||
<If condition={state.guistate.menuIsOpened}>
|
<If condition={state.guistate.menuIsOpened}>
|
||||||
<!-- Menu page -->
|
<!-- Menu page -->
|
||||||
<FloatOver on:close={() => state.guistate.menuIsOpened.setData(false)}>
|
<FloatOver>
|
||||||
|
<span slot="close-button"><!-- Hide the default close button --></span>
|
||||||
<TabbedGroup tab={state.guistate.menuViewTabIndex}>
|
<TabbedGroup tab={state.guistate.menuViewTabIndex}>
|
||||||
|
<div slot="post-tablist">
|
||||||
|
<XCircleIcon class="w-8 h-8 mr-2" on:click={() => state.guistate.menuIsOpened.setData(false)}/>
|
||||||
|
</div>
|
||||||
<div class="flex" slot="title0">
|
<div class="flex" slot="title0">
|
||||||
<Tr t={Translations.t.general.menu.aboutMapComplete}/>
|
<Tr t={Translations.t.general.menu.aboutMapComplete}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -276,16 +288,13 @@
|
||||||
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({theme: "MapComplete"})}/>
|
<Tr t={Translations.t.general.attribution.openOsmcha.Subs({theme: "MapComplete"})}/>
|
||||||
</a>
|
</a>
|
||||||
{Constants.vNumber}
|
{Constants.vNumber}
|
||||||
<ToSvelte construct={Hotkeys.generateDocumentationDynamic}></ToSvelte>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<If condition={state.osmConnection.isLoggedIn} slot="title1">
|
<div class="flex" slot="title1">
|
||||||
<div class="flex">
|
<CogIcon class="w-6 h-6"/>
|
||||||
<CogIcon class="w-6 h-6"/>
|
<Tr t={UserRelatedState.usersettingsConfig.title.GetRenderValue({})}/>
|
||||||
<Tr t={UserRelatedState.usersettingsConfig.title.GetRenderValue({})}/>
|
</div>
|
||||||
</div>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<div slot="content1">
|
<div slot="content1">
|
||||||
<!-- All shown components are set by 'usersettings.json', which happily uses some special visualisations created specifically for it -->
|
<!-- All shown components are set by 'usersettings.json', which happily uses some special visualisations created specifically for it -->
|
||||||
|
@ -316,6 +325,12 @@
|
||||||
<Tr t={Translations.t.privacy.title}></Tr>
|
<Tr t={Translations.t.privacy.title}></Tr>
|
||||||
</div>
|
</div>
|
||||||
<ToSvelte construct={() => new PrivacyPolicy()} slot="content3"></ToSvelte>
|
<ToSvelte construct={() => new PrivacyPolicy()} slot="content3"></ToSvelte>
|
||||||
|
|
||||||
|
<Tr slot="title4" t={Translations.t.advanced.title}/>
|
||||||
|
<div class="flex flex-col" slot="content4">
|
||||||
|
<ToSvelte construct={Hotkeys.generateDocumentationDynamic}></ToSvelte>
|
||||||
|
|
||||||
|
</div>
|
||||||
</TabbedGroup>
|
</TabbedGroup>
|
||||||
</FloatOver>
|
</FloatOver>
|
||||||
</If>
|
</If>
|
||||||
|
|
|
@ -735,14 +735,6 @@ video {
|
||||||
top: 1rem;
|
top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-1 {
|
|
||||||
right: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom-1 {
|
|
||||||
bottom: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-1\/2 {
|
.left-1\/2 {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
}
|
}
|
||||||
|
@ -905,10 +897,6 @@ video {
|
||||||
margin-bottom: 2.5rem;
|
margin-bottom: 2.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mt-0 {
|
|
||||||
margin-top: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-8 {
|
.mt-8 {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -1464,6 +1452,11 @@ video {
|
||||||
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
|
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-gray-300 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(209 213 219 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-black {
|
.bg-black {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
|
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
|
||||||
|
@ -1479,11 +1472,6 @@ video {
|
||||||
background-color: rgb(224 231 255 / var(--tw-bg-opacity));
|
background-color: rgb(224 231 255 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-gray-300 {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(209 213 219 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-red-500 {
|
.bg-red-500 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
||||||
|
@ -2324,10 +2312,6 @@ input {
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm\:m-6 {
|
|
||||||
margin: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm\:mx-1 {
|
.sm\:mx-1 {
|
||||||
margin-left: 0.25rem;
|
margin-left: 0.25rem;
|
||||||
margin-right: 0.25rem;
|
margin-right: 0.25rem;
|
||||||
|
@ -2382,10 +2366,6 @@ input {
|
||||||
border-width: 4px;
|
border-width: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm\:p-6 {
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sm\:p-1 {
|
.sm\:p-1 {
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
@ -2418,10 +2398,6 @@ input {
|
||||||
margin: 0.25rem;
|
margin: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.md\:m-8 {
|
|
||||||
margin: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md\:m-2 {
|
.md\:m-2 {
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
}
|
}
|
||||||
|
@ -2483,6 +2459,10 @@ input {
|
||||||
border-top-width: 2px;
|
border-top-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:p-6 {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:p-4 {
|
.md\:p-4 {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
|
"advanced": {
|
||||||
|
"title": "Advanced features"
|
||||||
|
},
|
||||||
"centerMessage": {
|
"centerMessage": {
|
||||||
"loadingData": "Loading data…",
|
"loadingData": "Loading data…",
|
||||||
"ready": "Done!",
|
"ready": "Done!",
|
||||||
|
@ -961,6 +964,7 @@
|
||||||
"notImmediate": "Translations are not updated directly. This typically takes a few days"
|
"notImmediate": "Translations are not updated directly. This typically takes a few days"
|
||||||
},
|
},
|
||||||
"userinfo": {
|
"userinfo": {
|
||||||
|
"editDescription": "Edit your profile description",
|
||||||
"gotoInbox": "Open your inbox",
|
"gotoInbox": "Open your inbox",
|
||||||
"gotoSettings": "Go to your settings on OpenStreetMap.org",
|
"gotoSettings": "Go to your settings on OpenStreetMap.org",
|
||||||
"noDescription": "You don't have a description on your profile yet",
|
"noDescription": "You don't have a description on your profile yet",
|
||||||
|
|
Loading…
Reference in a new issue