forked from MapComplete/MapComplete
		
	UX: enable menu drawer on index page, slightly reorder index page
This commit is contained in:
		
							parent
							
								
									b71f07974e
								
							
						
					
					
						commit
						383eebfdca
					
				
					 10 changed files with 280 additions and 263 deletions
				
			
		|  | @ -16,10 +16,9 @@ export default class ContributorCount { | |||
|         perLayer: ReadonlyMap<string, GeoIndexedStore> | ||||
|     }) { | ||||
|         this.perLayer = state.perLayer | ||||
|         const self = this | ||||
|         state.mapProperties.bounds.mapD( | ||||
|             (bbox) => { | ||||
|                 self.update(bbox) | ||||
|                 this.update(bbox) | ||||
|             }, | ||||
|             [state.dataIsLoading] | ||||
|         ) | ||||
|  |  | |||
|  | @ -44,9 +44,9 @@ export class MenuState { | |||
|         undefined | ||||
|     ) | ||||
|     public highlightedUserSetting: UIEventSource<string> = new UIEventSource<string>(undefined) | ||||
|     private readonly _selectedElement: UIEventSource<any> | ||||
|     private readonly _selectedElement: UIEventSource<any> | undefined | ||||
| 
 | ||||
|     constructor(selectedElement: UIEventSource<any>) { | ||||
|     constructor(selectedElement: UIEventSource<any> | undefined) { | ||||
|         this._selectedElement = selectedElement | ||||
|         // Note: this class is _not_ responsible to update the Hash, @see ThemeViewStateHashActor for this
 | ||||
|         const states = {} | ||||
|  | @ -118,7 +118,7 @@ export class MenuState { | |||
|         if (MenuState.previewedImage.data !== undefined) { | ||||
|             return true | ||||
|         } | ||||
|         if (this._selectedElement.data) { | ||||
|         if (this._selectedElement?.data) { | ||||
|             return true | ||||
|         } | ||||
|         return Object.values(this.pageStates).some((t) => t.data) | ||||
|  |  | |||
|  | @ -27,6 +27,11 @@ | |||
|   import { AndroidPolyfill } from "../Logic/Web/AndroidPolyfill" | ||||
|   import Forgejo from "../assets/svg/Forgejo.svelte" | ||||
|   import Locale from "./i18n/Locale" | ||||
|   import DrawerLeft from "./Base/DrawerLeft.svelte" | ||||
|   import MenuDrawer from "./BigComponents/MenuDrawer.svelte" | ||||
|   import { MenuState } from "../Models/MenuState" | ||||
|   import { MenuIcon } from "@rgossiaux/svelte-heroicons/solid" | ||||
|   import AccordionSingle from "./Flowbite/AccordionSingle.svelte" | ||||
| 
 | ||||
|   AndroidPolyfill.init().then(() => console.log("Android polyfill setup completed")) | ||||
|   const featureSwitches = new OsmConnectionFeatureSwitches() | ||||
|  | @ -39,6 +44,13 @@ | |||
|     ) | ||||
|   }) | ||||
|   const state = new UserRelatedState(osmConnection) | ||||
|   const guistate = new MenuState(undefined) | ||||
|   const menuDrawerState = { | ||||
|     guistate, osmConnection, | ||||
|     userRelatedState: state, | ||||
|     featureSwitches: { featureSwitchEnableLogin: new UIEventSource(true) } | ||||
|   } | ||||
| 
 | ||||
|   const t = Translations.t.index | ||||
|   const tu = Translations.t.general | ||||
|   const tr = Translations.t.general.morescreen | ||||
|  | @ -138,20 +150,36 @@ | |||
| </script> | ||||
| 
 | ||||
| <main> | ||||
|   <div class="absolute h-screen w-screen bg-white top-0 left-0" style="z-index: -1;"></div> | ||||
| 
 | ||||
|   <div class="h-full overflow-hidden"> | ||||
|     <DrawerLeft shown={guistate.pageStates.menu}> | ||||
|       <div class="h-screen overflow-y-auto"> | ||||
|         <MenuDrawer onlyLink={true} state={menuDrawerState} /> | ||||
|       </div> | ||||
|     </DrawerLeft> | ||||
|   </div> | ||||
| 
 | ||||
|   <div class="m-4 flex flex-col"> | ||||
|     <LanguagePicker | ||||
|       clss="self-end max-w-full" | ||||
|       assignTo={state.language} | ||||
|       availableLanguages={t.title.SupportedLanguages()} | ||||
|       preferredLanguages={userLanguages} | ||||
|     /> | ||||
|     <div class="w-ful flex justify-between"> | ||||
|       <button on:click={() => guistate.pageStates.menu.set(true)} class="rounded-full m-0 p-2"> | ||||
|         <MenuIcon class="h-6 w-6 cursor-pointer" /> | ||||
|       </button> | ||||
| 
 | ||||
|       <LanguagePicker | ||||
|         clss="self-end max-w-full" | ||||
|         assignTo={state.language} | ||||
|         availableLanguages={t.title.SupportedLanguages()} | ||||
|         preferredLanguages={userLanguages} | ||||
|       /> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="mt-4 flex"> | ||||
|       <div class="m-3 flex-none"> | ||||
|         <Logo alt="MapComplete Logo" class="h-12 w-12 sm:h-24 sm:w-24" /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div class="link-underline flex flex-col"> | ||||
|       <div class="link-underline flex flex-col w-full"> | ||||
|         <h1 class="m-0 font-extrabold tracking-tight md:text-6xl"> | ||||
|           <Tr t={t.title} /> | ||||
|         </h1> | ||||
|  | @ -159,10 +187,12 @@ | |||
|           cls="mr-4 text-base font-semibold sm:text-lg md:mt-5 md:text-xl lg:mx-0" | ||||
|           t={Translations.t.index.intro} | ||||
|         /> | ||||
|         <a href="#about"> | ||||
|           <Tr t={Translations.t.index.learnMore} /> | ||||
|           <ChevronDoubleRight class="inline h-4 w-4" /> | ||||
|         </a> | ||||
| 
 | ||||
|         <AccordionSingle> | ||||
|           <Tr slot="header" t={Translations.t.index.about} /> | ||||
|           <Tr cls="link-underline" t={Translations.t.general.aboutMapComplete.intro} /> | ||||
|           <Tr t={tr.streetcomplete} /> | ||||
|         </AccordionSingle> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|  | @ -229,65 +259,15 @@ | |||
|       {/if} | ||||
|     </LoginToggle> | ||||
| 
 | ||||
|     <a | ||||
|       class="button flex" | ||||
|       href={window.location.protocol + "//" + window.location.host + "/studio.html"} | ||||
|     > | ||||
|       <Pencil class="mr-2 h-6 w-6" /> | ||||
|       <Tr t={Translations.t.general.morescreen.createYourOwnTheme} /> | ||||
|     </a> | ||||
| 
 | ||||
|     <h3 id="about"> | ||||
|       <Tr t={Translations.t.index.about} /> | ||||
|     </h3> | ||||
|     <Tr cls="link-underline" t={Translations.t.general.aboutMapComplete.intro} /> | ||||
| 
 | ||||
|     <span class="link-underline flex flex-col gap-y-1"> | ||||
|       <a | ||||
|         class="flex" | ||||
|         href="https://source.mapcomplete.org/MapComplete/MapComplete/" | ||||
|         target="_blank" | ||||
|       > | ||||
|         <Forgejo class="mr-2 h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.gotoSourceCode} /> | ||||
|       </a> | ||||
|       <a | ||||
|         class="flex" | ||||
|         href="https://source.mapcomplete.org/MapComplete/MapComplete/issues" | ||||
|         target="_blank" | ||||
|       > | ||||
|         <Bug class="mr-2 h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.openIssueTracker} /> | ||||
|       </a> | ||||
| 
 | ||||
|       <a class="flex" href={Utils.OsmChaLinkFor(7)} target="_blank"> | ||||
|         <ArrowTrendingUp class="mr-2 h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.openOsmchaLastWeek} /> | ||||
|       </a> | ||||
| 
 | ||||
|       <a class="flex" href="https://en.osm.town/@MapComplete" target="_blank"> | ||||
|         <Mastodon class="mr-2 h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.followOnMastodon} /> | ||||
|       </a> | ||||
| 
 | ||||
|       <a class="flex" href="https://liberapay.com/pietervdvn/" target="_blank"> | ||||
|         <Liberapay class="mr-2 h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.donate} /> | ||||
|       </a> | ||||
| 
 | ||||
|       <a | ||||
|         class="flex" | ||||
|         href={window.location.protocol + "//" + window.location.host + "/privacy.html"} | ||||
|       > | ||||
|         <Eye class="mr-2 h-6 w-6" /> | ||||
|         <Tr t={Translations.t.privacy.title} /> | ||||
|       </a> | ||||
|     </span> | ||||
| 
 | ||||
|     <Tr t={tr.streetcomplete} /> | ||||
| 
 | ||||
|     <div class="subtle mb-16 self-end"> | ||||
|       v{Constants.vNumber} | ||||
|     </div> | ||||
|   </div> | ||||
| 
 | ||||
|   <div class="absolute top-0 w-0 h-0" style="margin-left: -10em"> | ||||
|     <MenuDrawer onlyLink={false} state={menuDrawerState} /> | ||||
|   </div> | ||||
| 
 | ||||
| </main> | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ | |||
|   if (fullscreen) { | ||||
|     defaultClass = shared | ||||
|   } | ||||
|   let dialogClass = "fixed top-0 start-0 end-0 h-modal inset-0 w-full p-4 flex " + zIndex | ||||
|   let dialogClass = "fixed top-0 start-0 end-0 h-modal inset-0 w-full p-4 flex class-marker-dialog " + zIndex | ||||
|   if (fullscreen) { | ||||
|     dialogClass += " h-full-child" | ||||
|   } | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| <script lang="ts"> | ||||
|   import type { SpecialVisualizationState } from "../SpecialVisualization" | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import contributors from "../../assets/contributors.json" | ||||
|   import translators from "../../assets/translators.json" | ||||
|  | @ -14,18 +13,21 @@ | |||
|   import { UserGroupIcon } from "@babeard/svelte-heroicons/solid" | ||||
|   import Marker from "../Map/Marker.svelte" | ||||
|   import Forgejo from "../../assets/svg/Forgejo.svelte" | ||||
|   import type { MapProperties } from "../../Models/MapProperties" | ||||
|   import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" | ||||
|   import { ImmutableStore } from "../../Logic/UIEventSource" | ||||
| 
 | ||||
|   export let state: SpecialVisualizationState | ||||
|   export let state: { theme?: ThemeConfig, mapProperties?: MapProperties } | ||||
| 
 | ||||
|   const t = Translations.t.general.attribution | ||||
|   const layoutToUse = state.theme | ||||
| 
 | ||||
|   let maintainer: Translation = undefined | ||||
|   if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") { | ||||
|   if (layoutToUse?.credits !== undefined && layoutToUse?.credits !== "") { | ||||
|     maintainer = t.themeBy.Subs({ author: layoutToUse.credits }) | ||||
|   } | ||||
| 
 | ||||
|   const bgMapAttribution = state.mapProperties.rasterLayer.mapD((layer) => { | ||||
|   const bgMapAttribution = state.mapProperties?.rasterLayer?.mapD((layer) => { | ||||
|     const props = layer.properties | ||||
|     const attrUrl = props.attribution?.url | ||||
|     const attrText = props.attribution?.text | ||||
|  | @ -45,7 +47,7 @@ | |||
|       }) | ||||
|     } | ||||
|     return Translations.t.general.attribution.attributionBackgroundLayer.Subs(props) | ||||
|   }) | ||||
|   }) ?? new ImmutableStore(undefined) | ||||
| 
 | ||||
|   function calculateDataContributions(contributions: Map<string, number>): Translation { | ||||
|     if (contributions === undefined) { | ||||
|  | @ -81,7 +83,7 @@ | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const datacontributions = new ContributorCount(state).Contributors.map((counts) => | ||||
|   const datacontributions = (state.mapProperties ? new ContributorCount(<any>state).Contributors : new ImmutableStore([])).map((counts) => | ||||
|     calculateDataContributions(counts) | ||||
|   ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,10 +1,7 @@ | |||
| <script lang="ts"> | ||||
|   import Hotkeys from "../Base/Hotkeys" | ||||
|   import { Translation } from "../i18n/Translation" | ||||
|   import { Utils } from "../../Utils" | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import Tr from "../Base/Tr.svelte" | ||||
|   import AccordionSingle from "../Flowbite/AccordionSingle.svelte" | ||||
| 
 | ||||
|   let keys = Hotkeys._docs | ||||
|   const t = Translations.t.hotkeyDocumentation | ||||
|  |  | |||
|  | @ -1,6 +1,4 @@ | |||
| <script lang="ts"> | ||||
|   // All the relevant links | ||||
|   import ThemeViewState from "../../Models/ThemeViewState" | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import { CogIcon, EyeIcon, HeartIcon, TranslateIcon } from "@rgossiaux/svelte-heroicons/solid" | ||||
|   import Page from "../Base/Page.svelte" | ||||
|  | @ -17,7 +15,6 @@ | |||
|   import Mastodon from "../../assets/svg/Mastodon.svelte" | ||||
|   import Liberapay from "../../assets/svg/Liberapay.svelte" | ||||
|   import DocumentMagnifyingGlass from "@babeard/svelte-heroicons/outline/DocumentMagnifyingGlass" | ||||
|   import DocumentChartBar from "@babeard/svelte-heroicons/outline/DocumentChartBar" | ||||
|   import OpenIdEditor from "./OpenIdEditor.svelte" | ||||
|   import OpenJosm from "../Base/OpenJosm.svelte" | ||||
|   import MapillaryLink from "./MapillaryLink.svelte" | ||||
|  | @ -53,20 +50,37 @@ | |||
|   import MagnifyingGlassCircle from "@babeard/svelte-heroicons/mini/MagnifyingGlassCircle" | ||||
|   import { AndroidPolyfill } from "../../Logic/Web/AndroidPolyfill" | ||||
|   import Forgejo from "../../assets/svg/Forgejo.svelte" | ||||
|   import DocumentArrowUp from "@babeard/svelte-heroicons/mini/DocumentArrowUp" | ||||
|   import ChartBar from "@babeard/svelte-heroicons/solid/ChartBar" | ||||
|   import QueueList from "@babeard/svelte-heroicons/solid/QueueList" | ||||
|   import { MenuState } from "../../Models/MenuState" | ||||
|   import { OsmConnection } from "../../Logic/Osm/OsmConnection" | ||||
|   import FeatureSwitchState from "../../Logic/State/FeatureSwitchState" | ||||
|   import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" | ||||
|   import type { MapProperties } from "../../Models/MapProperties" | ||||
|   import FavouritesFeatureSource from "../../Logic/FeatureSource/Sources/FavouritesFeatureSource" | ||||
|   import Hotkeys from "../Base/Hotkeys" | ||||
|   import { ArrowTrendingUp } from "@babeard/svelte-heroicons/solid/ArrowTrendingUp" | ||||
|   import ArrowTopRightOnSquare from "@babeard/svelte-heroicons/mini/ArrowTopRightOnSquare" | ||||
| 
 | ||||
|   export let state: ThemeViewState | ||||
|   export let state: { | ||||
|     favourites: FavouritesFeatureSource | ||||
|     guistate: MenuState, | ||||
|     osmConnection: OsmConnection, | ||||
|     theme?: ThemeConfig, | ||||
|     featureSwitches: Partial<FeatureSwitchState>, | ||||
|     mapProperties?: MapProperties, | ||||
|     userRelatedState?: UserRelatedState | ||||
|   } | ||||
|   let hotkeys = Hotkeys._docs | ||||
|   let userdetails = state.osmConnection.userDetails | ||||
| 
 | ||||
|   let usersettingslayer = new LayerConfig(<LayerConfigJson>usersettings, "usersettings", true) | ||||
| 
 | ||||
|   let theme = state.theme | ||||
|   let featureSwitches = state.featureSwitches | ||||
|   let showHome = featureSwitches.featureSwitchBackToThemeOverview | ||||
|   let showHome = featureSwitches?.featureSwitchBackToThemeOverview | ||||
|   let pg = state.guistate.pageStates | ||||
|   let location = state.mapProperties.location | ||||
|   let location = state.mapProperties?.location | ||||
|   export let onlyLink: boolean | ||||
|   const t = Translations.t.general.menu | ||||
|   let shown = new UIEventSource(state.guistate.pageStates.menu.data || !onlyLink) | ||||
|  | @ -143,32 +157,36 @@ | |||
|     </Page> | ||||
| 
 | ||||
|     <LoginToggle {state} silentFail> | ||||
|       <Page {onlyLink} shown={pg.favourites}> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <HeartIcon /> | ||||
|           <Tr t={Translations.t.favouritePoi.tab} /> | ||||
|         </svelte:fragment> | ||||
| 
 | ||||
|         <h3> | ||||
|           <Tr t={Translations.t.favouritePoi.title} /> | ||||
|         </h3> | ||||
|         <div> | ||||
|           <Favourites {state} /> | ||||
|           <h3> | ||||
|             <Tr t={Translations.t.reviews.your_reviews} /> | ||||
|           </h3> | ||||
|           <ReviewsOverview {state} /> | ||||
|         </div> | ||||
|       </Page> | ||||
|       <div class="hidden-on-mobile w-full"> | ||||
|         <Page {onlyLink} shown={pg.hotkeys}> | ||||
|       {#if state.favourites} | ||||
|         <Page {onlyLink} shown={pg.favourites}> | ||||
|           <svelte:fragment slot="header"> | ||||
|             <BoltIcon /> | ||||
|             <Tr t={Translations.t.hotkeyDocumentation.title} /> | ||||
|             <HeartIcon /> | ||||
|             <Tr t={Translations.t.favouritePoi.tab} /> | ||||
|           </svelte:fragment> | ||||
|           <HotkeyTable /> | ||||
| 
 | ||||
|           <h3> | ||||
|             <Tr t={Translations.t.favouritePoi.title} /> | ||||
|           </h3> | ||||
|           <div> | ||||
|             <Favourites {state} /> | ||||
|             <h3> | ||||
|               <Tr t={Translations.t.reviews.your_reviews} /> | ||||
|             </h3> | ||||
|             <ReviewsOverview {state} /> | ||||
|           </div> | ||||
|         </Page> | ||||
|       </div> | ||||
|       {/if} | ||||
|       {#if $hotkeys.length > 0} | ||||
|         <div class="hidden-on-mobile w-full"> | ||||
|           <Page {onlyLink} shown={pg.hotkeys}> | ||||
|             <svelte:fragment slot="header"> | ||||
|               <BoltIcon /> | ||||
|               <Tr t={Translations.t.hotkeyDocumentation.title} /> | ||||
|             </svelte:fragment> | ||||
|             <HotkeyTable /> | ||||
|           </Page> | ||||
|         </div> | ||||
|       {/if} | ||||
| 
 | ||||
|       <div class="self-end"> | ||||
|         <LogoutButton osmConnection={state.osmConnection} /> | ||||
|  | @ -178,108 +196,103 @@ | |||
|   </SidebarUnit> | ||||
| 
 | ||||
|   <!-- Theme related: documentation links, download, ... --> | ||||
|   <SidebarUnit> | ||||
|     <h3> | ||||
|       <Tr t={t.aboutCurrentThemeTitle} /> | ||||
|     </h3> | ||||
|   {#if state.theme} | ||||
|     <SidebarUnit> | ||||
|       <h3> | ||||
|         <Tr t={t.aboutCurrentThemeTitle} /> | ||||
|       </h3> | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.about_theme}> | ||||
|       <svelte:fragment slot="link"> | ||||
|         <Marker size="h-7 w-7" icons={theme.icon} /> | ||||
|         <Tr t={t.showIntroduction} /> | ||||
|       </svelte:fragment> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <Marker size="h-8 w-8 mr-3" icons={theme.icon} /> | ||||
|         <Tr t={theme.title} /> | ||||
|       </svelte:fragment> | ||||
|       <ThemeIntroPanel {state} /> | ||||
|     </Page> | ||||
| 
 | ||||
|     <FilterPage {onlyLink} {state} /> | ||||
| 
 | ||||
|     <RasterLayerOverview {onlyLink} {state} /> | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.share}> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <Share /> | ||||
|         <Tr t={Translations.t.general.sharescreen.title} /> | ||||
|       </svelte:fragment> | ||||
|       <ShareScreen {state} /> | ||||
|     </Page> | ||||
| 
 | ||||
|     {#if state.featureSwitches.featureSwitchEnableExport} | ||||
|       <Page {onlyLink} shown={pg.download}> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <ArrowDownTray /> | ||||
|           <Tr t={Translations.t.general.download.title} /> | ||||
|       <Page {onlyLink} shown={pg.about_theme}> | ||||
|         <svelte:fragment slot="link"> | ||||
|           <Marker size="h-7 w-7" icons={theme.icon} /> | ||||
|           <Tr t={t.showIntroduction} /> | ||||
|         </svelte:fragment> | ||||
|         <DownloadPanel {state} /> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <Marker size="h-8 w-8 mr-3" icons={theme.icon} /> | ||||
|           <Tr t={theme.title} /> | ||||
|         </svelte:fragment> | ||||
|         <ThemeIntroPanel {state} /> | ||||
|       </Page> | ||||
|     {/if} | ||||
| 
 | ||||
|     {#if theme.official} | ||||
|       <a | ||||
|         class="flex" | ||||
|         href={"https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/Themes/" + | ||||
|       <FilterPage {onlyLink} {state} /> | ||||
| 
 | ||||
|       <RasterLayerOverview {onlyLink} {state} /> | ||||
| 
 | ||||
|       <Page {onlyLink} shown={pg.share}> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <Share /> | ||||
|           <Tr t={Translations.t.general.sharescreen.title} /> | ||||
|         </svelte:fragment> | ||||
|         <ShareScreen {state} /> | ||||
|       </Page> | ||||
| 
 | ||||
|       {#if state.featureSwitches?.featureSwitchEnableExport} | ||||
|         <Page {onlyLink} shown={pg.download}> | ||||
|           <svelte:fragment slot="header"> | ||||
|             <ArrowDownTray /> | ||||
|             <Tr t={Translations.t.general.download.title} /> | ||||
|           </svelte:fragment> | ||||
|           <DownloadPanel {state} /> | ||||
|         </Page> | ||||
|       {/if} | ||||
| 
 | ||||
|       {#if theme.official} | ||||
|         <a | ||||
|           class="flex" | ||||
|           href={"https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/Themes/" + | ||||
|           theme.id + | ||||
|           ".md"} | ||||
|         target="_blank" | ||||
|       > | ||||
|         <DocumentMagnifyingGlass class="h-6 w-6" /> | ||||
|         <Tr | ||||
|           t={Translations.t.general.attribution.openThemeDocumentation.Subs({ | ||||
|           target="_blank" | ||||
|         > | ||||
|           <DocumentMagnifyingGlass class="h-6 w-6" /> | ||||
|           <Tr | ||||
|             t={Translations.t.general.attribution.openThemeDocumentation.Subs({ | ||||
|             name: theme.title, | ||||
|           })} | ||||
|         /> | ||||
|       </a> | ||||
|           /> | ||||
|         </a> | ||||
| 
 | ||||
|       <a class="flex" href={Utils.OsmChaLinkFor(31, theme.id)} target="_blank"> | ||||
|         <QueueList class="h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: theme.title })} /> | ||||
|       </a> | ||||
|       <a class="flex" href={`./statistics.html?filter-mapcomplete-changes-theme-search={"search"%3A"${theme.id}"}`} | ||||
|          target="_blank"> | ||||
|         <ChartBar class="h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.openStatistics.Subs({theme: theme.title})} /> | ||||
|       </a> | ||||
|     {/if} | ||||
|   </SidebarUnit> | ||||
|         <a class="flex" href={Utils.OsmChaLinkFor(31, theme.id)} target="_blank"> | ||||
|           <QueueList class="h-6 w-6" /> | ||||
|           <Tr t={Translations.t.general.attribution.openOsmcha.Subs({ theme: theme.title })} /> | ||||
|         </a> | ||||
|         <a class="flex" href={`./statistics.html?filter-mapcomplete-changes-theme-search={"search"%3A"${theme.id}"}`} | ||||
|            target="_blank"> | ||||
|           <ChartBar class="h-6 w-6" /> | ||||
|           <Tr t={Translations.t.general.attribution.openStatistics.Subs({theme: theme.title})} /> | ||||
|         </a> | ||||
|       {/if} | ||||
|     </SidebarUnit> | ||||
|   {/if} | ||||
| 
 | ||||
|   <!-- Other links and tools for the given location: open iD/JOSM; community index, ... --> | ||||
|   <SidebarUnit> | ||||
|     <h3> | ||||
|       <Tr t={t.moreUtilsTitle} /> | ||||
|     </h3> | ||||
|   {#if state.mapProperties?.location} | ||||
|     <SidebarUnit> | ||||
|       <h3> | ||||
|         <Tr t={t.moreUtilsTitle} /> | ||||
|       </h3> | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.community_index}> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <Community /> | ||||
|         <Tr t={Translations.t.communityIndex.title} /> | ||||
|       </svelte:fragment> | ||||
|       <CommunityIndexView location={state.mapProperties.location} /> | ||||
|     </Page> | ||||
|       <Page {onlyLink} shown={pg.community_index}> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <Community /> | ||||
|           <Tr t={Translations.t.communityIndex.title} /> | ||||
|         </svelte:fragment> | ||||
|         <CommunityIndexView location={state.mapProperties.location} /> | ||||
|       </Page> | ||||
| 
 | ||||
|     <If condition={featureSwitches.featureSwitchEnableLogin}> | ||||
|       <OpenIdEditor mapProperties={state.mapProperties} /> | ||||
|       <OpenJosm {state} /> | ||||
|       <PanoramaxLink large={false} mapProperties={state.mapProperties} /> | ||||
|       <MapillaryLink large={false} mapProperties={state.mapProperties} /> | ||||
|     </If> | ||||
|       <If condition={featureSwitches?.featureSwitchEnableLogin}> | ||||
|         <OpenIdEditor mapProperties={state.mapProperties} /> | ||||
|         <OpenJosm {state} /> | ||||
|         <PanoramaxLink large={false} mapProperties={state.mapProperties} /> | ||||
|         <MapillaryLink large={false} mapProperties={state.mapProperties} /> | ||||
|       </If> | ||||
| 
 | ||||
|     <a class="sidebar-button flex" href="geo:{$location.lat},{$location.lon}"> | ||||
|       <ShareIcon /> | ||||
|       <Tr t={t.openHereDifferentApp} /> | ||||
|     </a> | ||||
| 
 | ||||
|     <a | ||||
|       class="flex" | ||||
|       href={window.location.protocol + "//" + window.location.host + "/inspector.html"} | ||||
|     > | ||||
|       <MagnifyingGlassCircle class="mr-2 h-6 w-6" /> | ||||
|       <Tr t={Translations.t.inspector.menu} /> | ||||
|     </a> | ||||
| 
 | ||||
|   </SidebarUnit> | ||||
|       <a class="sidebar-button flex" href="geo:{$location.lat},{$location.lon}"> | ||||
|         <ShareIcon /> | ||||
|         <Tr t={t.openHereDifferentApp} /> | ||||
|       </a> | ||||
|     </SidebarUnit> | ||||
|   {/if} | ||||
| 
 | ||||
|   <!-- About MC: various outward links, legal info, ... --> | ||||
|   <SidebarUnit> | ||||
|  | @ -293,8 +306,6 @@ | |||
|     </a> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     <a class="flex" href="mailto:info@mapcomplete.org"> | ||||
|       <EnvelopeOpen class="h-6 w-6" /> | ||||
|       <Tr t={Translations.t.general.attribution.emailCreators} /> | ||||
|  | @ -329,6 +340,27 @@ | |||
|       <Tr t={Translations.t.translations.activateButton} /> | ||||
|     </a> | ||||
| 
 | ||||
| 
 | ||||
|     <a | ||||
|       class="flex" | ||||
|       href={window.location.protocol + "//" + window.location.host + "/inspector.html"} | ||||
|     > | ||||
|       <MagnifyingGlassCircle class="mr-2 h-6 w-6" /> | ||||
|       <Tr t={Translations.t.inspector.menu} /> | ||||
|     </a> | ||||
| 
 | ||||
|     {#if !state.theme} | ||||
|       <a class="flex" href={`./statistics.html"}`} | ||||
|          target="_blank"> | ||||
|         <ChartBar class="h-6 w-6" /> | ||||
|         <Tr t={Translations.t.general.attribution.openStatistics.Subs({theme: "MapComplete"})} /> | ||||
|       </a> | ||||
|     {/if} | ||||
| 
 | ||||
|     <a class="flex" href={Utils.OsmChaLinkFor(7)} target="_blank"> | ||||
|       <ArrowTrendingUp class="mr-2 h-6 w-6" /> | ||||
|       <Tr t={Translations.t.general.attribution.openOsmchaLastWeek} /> | ||||
|     </a> | ||||
|   </SidebarUnit> | ||||
|   <SidebarUnit> | ||||
|     <h3> | ||||
|  | @ -341,13 +373,15 @@ | |||
|       </svelte:fragment> | ||||
|       <CopyrightPanel {state} /> | ||||
|     </Page> | ||||
|     <Page {onlyLink} shown={pg.copyright_icons}> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <Copyright /> | ||||
|         <Tr t={Translations.t.general.attribution.iconAttribution.title} /> | ||||
|       </svelte:fragment> | ||||
|       <CopyrightAllIcons {state} /> | ||||
|     </Page> | ||||
|     {#if state?.theme} | ||||
|       <Page {onlyLink} shown={pg.copyright_icons}> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <Copyright /> | ||||
|           <Tr t={Translations.t.general.attribution.iconAttribution.title} /> | ||||
|         </svelte:fragment> | ||||
|         <CopyrightAllIcons {state} /> | ||||
|       </Page> | ||||
|     {/if} | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.privacy}> | ||||
|       <svelte:fragment slot="header"> | ||||
|  | @ -355,6 +389,9 @@ | |||
|         <Tr t={Translations.t.privacy.title} /> | ||||
|       </svelte:fragment> | ||||
|       <PrivacyPolicy {state} /> | ||||
|       <a href="./privacy.html" class="button w-fit float-right" target="_blank"> | ||||
|         <ArrowTopRightOnSquare class="w-8 h-8" /> | ||||
|       </a> | ||||
|     </Page> | ||||
| 
 | ||||
|   </SidebarUnit> | ||||
|  |  | |||
|  | @ -11,48 +11,49 @@ | |||
|   export let compact: boolean = true | ||||
| 
 | ||||
|   const changes: Changes = state.changes | ||||
|   const isUploading: Store<boolean> = changes.isUploading | ||||
|   const errors = changes.errors | ||||
|   const pending = changes.pendingChanges | ||||
|   const isUploading: Store<boolean> = changes?.isUploading | ||||
|   const errors = changes?.errors | ||||
|   const pending = changes?.pendingChanges | ||||
| </script> | ||||
| {#if changes} | ||||
|   <div | ||||
|     class="pointer-events-auto flex flex-col" | ||||
|     on:click={() => changes.flushChanges("Pending changes indicator clicked")} | ||||
|   > | ||||
|     {#if $isUploading} | ||||
|       <Loading> | ||||
|         <Tr cls="thx" t={Translations.t.general.uploadingChanges} /> | ||||
|       </Loading> | ||||
|     {:else if $pending.length === 1} | ||||
|       <Tr cls="alert" t={Translations.t.general.uploadPendingSingle} /> | ||||
|     {:else if $pending.length > 1} | ||||
|       <Tr cls="alert" t={Translations.t.general.uploadPending.Subs({ count: $pending.length })} /> | ||||
|     {/if} | ||||
| 
 | ||||
| <div | ||||
|   class="pointer-events-auto flex flex-col" | ||||
|   on:click={() => changes.flushChanges("Pending changes indicator clicked")} | ||||
| > | ||||
|   {#if $isUploading} | ||||
|     <Loading> | ||||
|       <Tr cls="thx" t={Translations.t.general.uploadingChanges} /> | ||||
|     </Loading> | ||||
|   {:else if $pending.length === 1} | ||||
|     <Tr cls="alert" t={Translations.t.general.uploadPendingSingle} /> | ||||
|   {:else if $pending.length > 1} | ||||
|     <Tr cls="alert" t={Translations.t.general.uploadPending.Subs({ count: $pending.length })} /> | ||||
|   {/if} | ||||
|     {#each $errors as error} | ||||
|       <Tr cls="alert" t={Translations.t.general.uploadError.Subs({ error })} /> | ||||
|     {/each} | ||||
| 
 | ||||
|   {#each $errors as error} | ||||
|     <Tr cls="alert" t={Translations.t.general.uploadError.Subs({ error })} /> | ||||
|   {/each} | ||||
|     {#if !compact && $pending.length > 0} | ||||
|       <button on:click={() => state.changes.pendingChanges.set([])}> | ||||
|         <Tr t={Translations.t.general.clearPendingChanges} /> | ||||
|       </button> | ||||
| 
 | ||||
|   {#if !compact && $pending.length > 0} | ||||
|     <button on:click={() => state.changes.pendingChanges.set([])}> | ||||
|       <Tr t={Translations.t.general.clearPendingChanges} /> | ||||
|     </button> | ||||
| 
 | ||||
|     <ul> | ||||
|       {#each $pending as pending} | ||||
|         <li> | ||||
|           {#if pending.changes !== undefined} | ||||
|             Create {pending.type}/{pending.id} | ||||
|             {JSON.stringify(TagUtils.KVObjtoProperties(pending.tags))} | ||||
|           {:else} | ||||
|             Modify {pending.type}/{pending.id} {JSON.stringify(pending.tags)} | ||||
|           {/if} | ||||
|           {#if pending.type === "way" && pending.changes?.nodes} | ||||
|             {pending.changes.nodes.join(" ")} | ||||
|           {/if} | ||||
|         </li> | ||||
|       {/each} | ||||
|     </ul> | ||||
|   {/if} | ||||
| </div> | ||||
|       <ul> | ||||
|         {#each $pending as pending} | ||||
|           <li> | ||||
|             {#if pending.changes !== undefined} | ||||
|               Create {pending.type}/{pending.id} | ||||
|               {JSON.stringify(TagUtils.KVObjtoProperties(pending.tags))} | ||||
|             {:else} | ||||
|               Modify {pending.type}/{pending.id} {JSON.stringify(pending.tags)} | ||||
|             {/if} | ||||
|             {#if pending.type === "way" && pending.changes?.nodes} | ||||
|               {pending.changes.nodes.join(" ")} | ||||
|             {/if} | ||||
|           </li> | ||||
|         {/each} | ||||
|       </ul> | ||||
|     {/if} | ||||
|   </div> | ||||
| {/if} | ||||
|  |  | |||
|  | @ -3,29 +3,30 @@ | |||
|   import { Stores } from "../../Logic/UIEventSource" | ||||
|   import Tr from "../Base/Tr.svelte" | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import type { SpecialVisualizationState } from "../SpecialVisualization" | ||||
|   import ThemeViewState from "../../Models/ThemeViewState" | ||||
| 
 | ||||
|   /** | ||||
|    * Shows _all_ disabled questions | ||||
|    */ | ||||
|   export let state: ThemeViewState | ||||
|   let layers = state.theme.layers.filter((l) => l.isNormal()) | ||||
|   let layers = state.theme?.layers?.filter((l) => l.isNormal()) | ||||
| 
 | ||||
|   let allDisabled = Stores.concat<string>( | ||||
|     layers.map((l) => state.userRelatedState.getThemeDisabled(state.theme.id, l.id)) | ||||
|     layers?.map((l) => state.userRelatedState.getThemeDisabled(state.theme.id, l.id)) ?? [] | ||||
|   ).map((l) => [].concat(...l)) | ||||
|   const t = Translations.t.general.questions | ||||
| </script> | ||||
| 
 | ||||
| <h3> | ||||
|   <Tr t={t.disabledTitle} /> | ||||
| </h3> | ||||
| {#if $allDisabled.length === 0} | ||||
|   <Tr t={t.noneDisabled} /> | ||||
| {:else} | ||||
|   <Tr t={t.disabledIntro} /> | ||||
|   {#each layers as layer (layer.id)} | ||||
|     <DisabledQuestionsLayer {state} {layer} /> | ||||
|   {/each} | ||||
| {#if state.theme} | ||||
|   <h3> | ||||
|     <Tr t={t.disabledTitle} /> | ||||
|   </h3> | ||||
|   {#if $allDisabled.length === 0} | ||||
|     <Tr t={t.noneDisabled} /> | ||||
|   {:else} | ||||
|     <Tr t={t.disabledIntro} /> | ||||
|     {#each layers as layer (layer.id)} | ||||
|       <DisabledQuestionsLayer {state} {layer} /> | ||||
|     {/each} | ||||
|   {/if} | ||||
| {/if} | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ export class SettingsVisualisations { | |||
|                 docs: "A component to set the language of the user interface", | ||||
|                 constr(state: SpecialVisualizationState): SvelteUIElement { | ||||
|                     const availableLanguages = Locale.showLinkToWeblate.map((showTranslations) => | ||||
|                         showTranslations ? LanguageUtils.usedLanguagesSorted : state.theme.language | ||||
|                         showTranslations ? LanguageUtils.usedLanguagesSorted : (state?.theme?.language ?? LanguageUtils.usedLanguagesSorted) | ||||
|                     ) | ||||
|                     return new SvelteUIElement(LanguagePicker, { | ||||
|                         assignTo: state.userRelatedState.language, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue