chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2024-09-02 12:48:15 +02:00
parent c10fecb7e8
commit f5d7686c98
234 changed files with 3493 additions and 2482 deletions

View file

@ -102,7 +102,11 @@
</div>
</div>
<Searchbar value={themeSearchText} placeholder={tr.searchForATheme} on:search={() => MoreScreen.applySearch(themeSearchText.data)}/>
<Searchbar
value={themeSearchText}
placeholder={tr.searchForATheme}
on:search={() => MoreScreen.applySearch(themeSearchText.data)}
/>
<ThemesList search={themeSearchText} {state} themes={MoreScreen.officialThemes} />

View file

@ -3,28 +3,27 @@
import { sineIn } from "svelte/easing"
import { UIEventSource } from "../../Logic/UIEventSource.js"
export let shown: UIEventSource<boolean>;
export let shown: UIEventSource<boolean>
let transitionParams = {
x: -320,
duration: 200,
easing: sineIn
};
easing: sineIn,
}
let hidden = !shown.data
$: {
shown.setData(!hidden)
}
shown.addCallback(sh => {
shown.addCallback((sh) => {
hidden = !sh
})
</script>
<Drawer placement="left"
transitionType="fly" {transitionParams}
divClass = "overflow-y-auto z-50 "
bind:hidden={hidden}>
<slot>
CONTENTS
</slot>
<Drawer
placement="left"
transitionType="fly"
{transitionParams}
divClass="overflow-y-auto z-50 "
bind:hidden
>
<slot>CONTENTS</slot>
</Drawer>

View file

@ -30,7 +30,7 @@
}}
>
<div
class="content relative normal-background pointer-events-auto h-full"
class="content normal-background pointer-events-auto relative h-full"
on:click|stopPropagation={() => {}}
>
<div class="h-full rounded-xl">
@ -39,20 +39,16 @@
<slot name="close-button">
<!-- The close button is placed _after_ the default slot in order to always paint it on top -->
<div class="absolute top-0 right-0">
<CloseButton class="normal-background mt-2 mr-2"
on:click={() => dispatch("close")}
/>
<CloseButton class="normal-background mt-2 mr-2" on:click={() => dispatch("close")} />
</div>
</slot>
</div>
</div>
<style>
.content {
border-radius: 0.5rem;
overflow-x: hidden;
box-shadow: 0 0 1rem #00000088;
}
.content {
border-radius: 0.5rem;
overflow-x: hidden;
box-shadow: 0 0 1rem #00000088;
}
</style>

View file

@ -4,7 +4,6 @@
export let text: string
export let href: string
export let classnames: string = undefined
export let download: string = undefined
export let ariaLabel: string = undefined
@ -13,7 +12,7 @@
</script>
<a
href={Utils.prepareHref(href) }
href={Utils.prepareHref(href)}
aria-label={ariaLabel}
title={ariaLabel}
target={newTab ? "_blank" : undefined}

View file

@ -14,6 +14,6 @@
osmConnection.LogOut()
}}
>
<ArrowRightOnRectangle class="h-6 w-6 max-h-full" />
<ArrowRightOnRectangle class="h-6 max-h-full w-6" />
<Tr t={Translations.t.general.logout} />
</button>

View file

@ -14,7 +14,6 @@
export let arialabel: Translation = undefined
export let arialabelDynamic: Store<Translation> = new ImmutableStore(arialabel)
let arialabelString = arialabelDynamic.bind((tr) => tr?.current)
</script>
<button

View file

@ -6,12 +6,13 @@
export let shown: UIEventSource<boolean>
let _shown = false
export let onlyLink: boolean = false
shown.addCallbackAndRun(sh => {
shown.addCallbackAndRun((sh) => {
_shown = sh
})
export let fullscreen: boolean = false
const shared = "in-page normal-background dark:bg-gray-800 rounded-lg border-gray-200 dark:border-gray-700 border-gray-200 dark:border-gray-700 divide-gray-200 dark:divide-gray-700 shadow-md"
const shared =
"in-page normal-background dark:bg-gray-800 rounded-lg border-gray-200 dark:border-gray-700 border-gray-200 dark:border-gray-700 divide-gray-200 dark:divide-gray-700 shadow-md"
let defaultClass = "relative flex flex-col mx-auto w-full divide-y " + shared
if (fullscreen) {
defaultClass = shared
@ -21,14 +22,21 @@
dialogClass += " h-full-child"
}
let bodyClass = "h-full p-4 md:p-5 space-y-4 flex-1 overflow-y-auto overscroll-contain"
let headerClass = "flex justify-between items-center p-2 px-4 md:px-5 rounded-t-lg";
let headerClass = "flex justify-between items-center p-2 px-4 md:px-5 rounded-t-lg"
</script>
{#if !onlyLink}
<Modal open={_shown} on:close={() => shown.set(false)} outsideclose
size="xl"
{defaultClass} {bodyClass} {dialogClass} {headerClass}
color="none">
<Modal
open={_shown}
on:close={() => shown.set(false)}
outsideclose
size="xl"
{defaultClass}
{bodyClass}
{dialogClass}
{headerClass}
color="none"
>
<h1 slot="header" class="page-header w-full">
<slot name="header" />
</h1>
@ -40,20 +48,20 @@
{:else}
<button class="as-link sidebar-button" on:click={() => shown.setData(true)}>
<slot name="link">
<slot name="header" />
<slot name="header" />
</slot>
</button>
{/if}
<style>
:global(.page-header) {
display: flex;
align-items: center;
}
:global(.page-header) {
display: flex;
align-items: center;
}
:global(.page-header svg) {
width: 2rem;
height: 2rem;
margin-right: 0.75rem;
width: 2rem;
height: 2rem;
margin-right: 0.75rem;
}
</style>

View file

@ -9,35 +9,30 @@
export let value: UIEventSource<string>
let _value = value.data ?? ""
value.addCallbackD(v => {
value.addCallbackD((v) => {
_value = v
})
$: value.set(_value)
const dispatch = createEventDispatcher<{ search }>()
export let placeholder: Translation = Translations.t.general.search.search
export let placeholder: Translation = Translations.t.general.search.search
</script>
<form
class="flex justify-center"
on:submit|preventDefault={() => dispatch("search")}
>
<form class="flex justify-center" on:submit|preventDefault={() => dispatch("search")}>
<label
class="neutral-label my-2 flex w-full items-center rounded-full border-2 border-black sm:w-1/2 box-shadow"
class="neutral-label box-shadow my-2 flex w-full items-center rounded-full border-2 border-black sm:w-1/2"
>
<input
type="search"
style=" --tw-ring-color: rgb(0 0 0 / 0) !important;"
class="ml-4 pl-1 w-full outline-none border-none"
class="ml-4 w-full border-none pl-1 outline-none"
on:keypress={(keypr) => {
return keypr.key === "Enter" ? dispatch("search") : undefined
}}
return keypr.key === "Enter" ? dispatch("search") : undefined
}}
bind:value={_value}
use:set_placeholder={placeholder}
use:ariaLabel={Translations.t.general.search.search}
/>
<SearchIcon aria-hidden="true" class="h-8 w-8 mx-2" />
<SearchIcon aria-hidden="true" class="mx-2 h-8 w-8" />
</label>
</form>

View file

@ -7,6 +7,5 @@
<slot />
</div>
<slot class="border-t-gray-300 mt-1" name="footer" />
<slot class="mt-1 border-t-gray-300" name="footer" />
</div>

View file

@ -14,7 +14,6 @@
const license: SmallLicense = licenses[key]
allLicenses[license.path] = license
}
</script>
{#each iconAttributions as iconAttribution}

View file

@ -20,7 +20,6 @@
const t = Translations.t.general.attribution
const layoutToUse = state.layout
let maintainer: Translation = undefined
if (layoutToUse.credits !== undefined && layoutToUse.credits !== "") {
maintainer = t.themeBy.Subs({ author: layoutToUse.credits })
@ -48,8 +47,6 @@
return Translations.t.general.attribution.attributionBackgroundLayer.Subs(props)
})
function calculateDataContributions(contributions: Map<string, number>): Translation {
if (contributions === undefined) {
return undefined
@ -147,7 +144,6 @@
<Tr t={codeContributors(translators, t.translatedBy)} />
</div>
<div class="self-end">
MapComplete {Constants.vNumber}
</div>

View file

@ -107,14 +107,14 @@
</script>
<div class="normal-background flex justify-between rounded-full pl-2">
<form class="flex w-full flex-wrap items-center ">
<form class="flex w-full flex-wrap items-center">
{#if isRunning}
<Loading>{Translations.t.general.search.searching}</Loading>
{:else}
<input
type="search"
style="border: none !important;"
class="w-full outline-none border-none mx-2"
class="mx-2 w-full border-none outline-none"
bind:this={inputElement}
on:keypress={(keypr) => {
feedback = undefined
@ -132,5 +132,5 @@
{/if}
{/if}
</form>
<SearchIcon aria-hidden="true" class="h-6 w-6 mx-2 self-center" on:click={performSearch} />
<SearchIcon aria-hidden="true" class="mx-2 h-6 w-6 self-center" on:click={performSearch} />
</div>

View file

@ -15,31 +15,31 @@
}
</script>
<Tr t={t.intro} />
<table>
<Tr t={t.intro} />
<table>
<tr>
<th>
<Tr t={t.key} />
</th>
<th>
<Tr t={t.action} />
</th>
</tr>
{#each byKey as [key, doc, alsoTriggeredBy]}
<tr>
<th>
<Tr t={t.key} />
</th>
<th>
<Tr t={t.action} />
</th>
<td class="flex items-center justify-center">
{#if alsoTriggeredBy}
<div class="flex items-center justify-center gap-x-1">
<div class="literal-code h-fit w-fit">{key}</div>
<div class="literal-code h-fit w-fit">{alsoTriggeredBy}</div>
</div>
{:else}
<div class="literal-code flex h-fit w-fit w-full items-center">{key}</div>
{/if}
</td>
<td>
<Tr t={doc} />
</td>
</tr>
{#each byKey as [key, doc, alsoTriggeredBy]}
<tr>
<td class="flex items-center justify-center">
{#if alsoTriggeredBy}
<div class="flex items-center justify-center gap-x-1">
<div class="literal-code h-fit w-fit">{key}</div>
<div class="literal-code h-fit w-fit">{alsoTriggeredBy}</div>
</div>
{:else}
<div class="literal-code flex h-fit w-fit w-full items-center">{key}</div>
{/if}
</td>
<td>
<Tr t={doc} />
</td>
</tr>
{/each}
</table>
{/each}
</table>

View file

@ -1,5 +1,4 @@
<script lang="ts">
// All the relevant links
import ThemeViewState from "../../Models/ThemeViewState"
import Translations from "../i18n/Translations"
@ -63,15 +62,19 @@
const t = Translations.t.general.menu
</script>
<div class="flex flex-col p-2 sm:p-3 low-interaction gap-y-2 sm:gap-y-3 h-screen overflow-y-auto">
<div class="low-interaction flex h-screen flex-col gap-y-2 overflow-y-auto p-2 sm:gap-y-3 sm:p-3">
<div class="flex justify-between">
<h2>
<Tr t={t.title}/>
<Tr t={t.title} />
</h2>
<CloseButton on:click={() => {pg.menu.set(false)}} />
<CloseButton
on:click={() => {
pg.menu.set(false)
}}
/>
</div>
{#if $showHome}
<a class="flex button primary" href={Utils.HomepageLink()}>
<a class="button primary flex" href={Utils.HomepageLink()}>
<Squares2x2 class="h-10 w-10" />
{#if Utils.isIframe}
<Tr t={Translations.t.general.seeIndex} />
@ -81,23 +84,21 @@
</a>
{/if}
<!-- User related: avatar, settings, favourits, logout -->
<div class="sidebar-unit">
<LoginToggle {state}>
<LoginButton osmConnection={state.osmConnection} slot="not-logged-in"></LoginButton>
<div class="flex gap-x-4 items-center">
<LoginButton osmConnection={state.osmConnection} slot="not-logged-in" />
<div class="flex items-center gap-x-4">
{#if $userdetails.img}
<img src={$userdetails.img} class="rounded-full w-14 h-14" />
<img src={$userdetails.img} class="h-14 w-14 rounded-full" />
{/if}
<b>{$userdetails.name}</b>
</div>
</LoginToggle>
<Page {onlyLink} shown={pg.usersettings}>
<svelte:fragment slot="header">
<CogIcon/>
<CogIcon />
<Tr t={UserRelatedState.usersettingsConfig.title.GetRenderValue({})} />
</svelte:fragment>
@ -112,30 +113,24 @@
highlightedRendering={state.guistate.highlightedUserSetting}
layer={usersettingslayer}
selectedElement={{
type: "Feature",
properties: { id: "settings" },
geometry: { type: "Point", coordinates: [0, 0] },
}}
type: "Feature",
properties: { id: "settings" },
geometry: { type: "Point", coordinates: [0, 0] },
}}
{state}
tags={state.userRelatedState.preferencesAsTags}
/>
</LoginToggle>
</Page>
<LoginToggle {state}>
<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>
@ -152,10 +147,8 @@
</LoginToggle>
<LanguagePicker />
</div>
<!-- Theme related: documentation links, download, ... -->
<div class="sidebar-unit">
<h3>
@ -167,7 +160,7 @@
<Marker icons={layout.icon} size="h-6 w-6 mr-2" />
<Tr t={t.showIntroduction} />
</div>
<svelte:fragment slot="header">
<svelte:fragment slot="header">
<Marker icons={layout.icon} />
<Tr t={layout.title} />
</svelte:fragment>
@ -180,17 +173,16 @@
<Page {onlyLink} shown={pg.share}>
<svelte:fragment slot="header">
<Share/>
<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 />
<ArrowDownTray />
<Tr t={Translations.t.general.download.title} />
</svelte:fragment>
<DownloadPanel {state} />
@ -201,15 +193,15 @@
<a
class="flex"
href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
layout.id +
".md"}
layout.id +
".md"}
target="_blank"
>
<DocumentMagnifyingGlass class="h-6 w-6" />
<Tr
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
name: layout.title,
})}
name: layout.title,
})}
/>
</a>
@ -220,53 +212,43 @@
{/if}
</div>
<!-- Other links and tools for the given location: open iD/JOSM; community index, ... -->
<div class="sidebar-unit">
<h3>
<Tr t={t.moreUtilsTitle} />
</h3>
<Page {onlyLink} shown={pg.community_index}>
<svelte:fragment slot="header">
<Community/>
<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} />
<MapillaryLink large={false} mapProperties={state.mapProperties} />
</If>
</div>
<!-- About MC: various outward links, legal info, ... -->
<div class="sidebar-unit">
<h3>
<Tr t={Translations.t.general.menu.aboutMapComplete} />
</h3>
<a
class="flex"
href={window.location.protocol + "//" + window.location.host + "/studio.html"}
>
<a class="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>
<div class="hidden-on-mobile w-full">
<Page {onlyLink} shown={pg.hotkeys}>
<svelte:fragment slot="header">
<svelte:fragment slot="header">
<BoltIcon />
<Tr t={ Translations.t.hotkeyDocumentation.title} />
<Tr t={Translations.t.hotkeyDocumentation.title} />
</svelte:fragment>
<HotkeyTable />
</Page>
@ -282,7 +264,6 @@
<Tr t={Translations.t.general.attribution.openIssueTracker} />
</a>
<a class="flex" href="https://en.osm.town/@MapComplete" target="_blank">
<Mastodon class="h-6 w-6" />
<Tr t={Translations.t.general.attribution.followOnMastodon} />
@ -293,7 +274,6 @@
<Tr t={Translations.t.general.attribution.donate} />
</a>
<Page {onlyLink} shown={pg.copyright}>
<svelte:fragment slot="header">
<Copyright />
@ -302,17 +282,14 @@
<CopyrightPanel {state} />
</Page>
<Page {onlyLink} shown={pg.copyright_icons}>
<svelte:fragment slot="header" >
<Copyright/>
<Tr t={ Translations.t.general.attribution.iconAttribution.title} />
<svelte:fragment slot="header">
<Copyright />
<Tr t={Translations.t.general.attribution.iconAttribution.title} />
</svelte:fragment>
<CopyrightAllIcons {state} />
</Page>
<Page {onlyLink} shown={pg.privacy}>
<svelte:fragment slot="header">
<EyeIcon />
@ -321,62 +298,62 @@
<PrivacyPolicy {state} />
</Page>
<div class="subtle self-end">
{Constants.vNumber}
</div>
</div>
</div>
<style>
:global(.sidebar-unit) {
display: flex;
flex-direction: column;
row-gap: 0.25rem;
background: var(--background-color);
padding: 0.5rem;
border-radius: 0.5rem;
}
:global(.sidebar-unit) {
display: flex;
flex-direction: column;
row-gap: 0.25rem;
background: var(--background-color);
padding: 0.5rem;
border-radius: 0.5rem;
}
:global(.sidebar-unit > h3) {
margin-top: 0;
margin-bottom: 0.5rem;
padding: 0.25rem;
}
:global(.sidebar-unit > h3) {
margin-top: 0;
margin-bottom: 0.5rem;
padding: 0.25rem;
}
:global(.sidebar-button svg, .sidebar-button img) {
width: 1.5rem;
height: 1.5rem;
margin-right: 0.5rem;
flex-shrink: 0;
}
:global(.sidebar-button svg, .sidebar-button img) {
width: 1.5rem;
height: 1.5rem;
margin-right: 0.5rem;
flex-shrink: 0;
}
:global(.sidebar-button .weblate-link > svg) {
width: 0.75rem;
height: 0.75rem;
flex-shrink: 0;
}
:global(.sidebar-button .weblate-link > svg) {
width: 0.75rem;
height: 0.75rem;
flex-shrink: 0;
}
:global(.sidebar-button, .sidebar-unit > a) {
display: flex;
align-items: center;
border-radius: 0.25rem !important;
padding: 0.4rem 0.75rem !important;
text-decoration: none !important;
width: 100%;
text-align: start;
}
:global(.sidebar-button, .sidebar-unit > a) {
display: flex;
align-items: center;
border-radius: 0.25rem !important;
padding: 0.4rem 0.75rem !important;
text-decoration: none !important;
width: 100%;
text-align: start;
}
:global(.sidebar-button > svg , .sidebar-button > img, .sidebar-unit a > img, .sidebar-unit > a svg) {
margin-right: 0.5rem;
flex-shrink: 0;
}
:global(.sidebar-button:hover, .sidebar-unit > a:hover) {
background: var(--low-interaction-background) !important;
}
:global(
.sidebar-button > svg,
.sidebar-button > img,
.sidebar-unit a > img,
.sidebar-unit > a svg
) {
margin-right: 0.5rem;
flex-shrink: 0;
}
:global(.sidebar-button:hover, .sidebar-unit > a:hover) {
background: var(--low-interaction-background) !important;
}
</style>

View file

@ -74,9 +74,8 @@
</div>
<slot name="close-button">
<div class="mt-4">
<CloseButton on:click={() => state.selectedElement.setData(undefined)}/>
<CloseButton on:click={() => state.selectedElement.setData(undefined)} />
</div>
</slot>
</div>

View file

@ -118,8 +118,7 @@
)
</script>
<div class="flex flex-col link-underline">
<div class="link-underline flex flex-col">
<a href="geo:{$location.lat},{$location.lon}">Open the current location in other applications</a>
<div class="flex flex-col">

View file

@ -63,7 +63,10 @@
<Tr t={layout.descriptionTail} />
<!-- Buttons: open map, go to location, search -->
<NextButton clss="primary w-full" on:click={() => state.guistate.pageStates.about_theme.setData(false)}>
<NextButton
clss="primary w-full"
on:click={() => state.guistate.pageStates.about_theme.setData(false)}
>
<div class="flex w-full flex-col items-center">
<div class="flex w-full justify-center text-2xl">
<Tr t={Translations.t.general.openTheMap} />
@ -136,10 +139,9 @@
{/if}
</div>
<div class="link-underline flex justify-end text-sm mt-8">
<div class="link-underline mt-8 flex justify-end text-sm">
<a href="https://mapcomplete.org" target="_blank">
<Tr t={Translations.t.general.poweredByMapComplete} />
</a>
</div>
</div>

View file

@ -47,7 +47,6 @@
</script>
<LoginToggle {state} silentFail>
{#if !$sourceUrl || !$enableLogin}
<!-- empty block -->
{:else if $externalData === undefined}
@ -59,15 +58,15 @@
{:else if $propertyKeysExternal.length === 0 && $knownImages.size + $unknownImages.length === 0}
<Tr cls="subtle" t={t.noDataLoaded} />
{:else if !$hasDifferencesAtStart}
<span class="subtle text-sm">
<Tr t={t.allIncluded.Subs({ source: $sourceUrl })} />
</span>
<span class="subtle text-sm">
<Tr t={t.allIncluded.Subs({ source: $sourceUrl })} />
</span>
{:else if $comparisonState !== undefined}
<AccordionSingle expanded={!collapsed}>
<span slot="header" class="flex">
<GlobeAlt class="h-6 w-6" />
<Tr t={Translations.t.external.title} />
</span>
<span slot="header" class="flex">
<GlobeAlt class="h-6 w-6" />
<Tr t={Translations.t.external.title} />
</span>
<ComparisonTable
externalProperties={$externalData["success"]}
{state}

View file

@ -26,26 +26,28 @@
<div class="relative w-fit">
<img
bind:this={imgEl}
on:load={() => loaded = true}
on:load={() => (loaded = true)}
class={imgClass ?? ""}
class:cursor-zoom-in={previewedImage !== undefined}
on:click={() => {
previewedImage?.setData(image)
}}
previewedImage?.setData(image)
}}
on:error={() => {
if (fallbackImage) {
imgEl.src = fallbackImage
}
}}
if (fallbackImage) {
imgEl.src = fallbackImage
}
}}
src={image.url}
/>
{#if canZoom && loaded}
<div class="absolute right-0 top-0 bg-black-transparent rounded-bl-full" on:click={() => previewedImage.set(image)}>
<MagnifyingGlassPlusIcon class="w-8 h-8 pl-3 pb-3 cursor-zoom-in" color="white" />
<div
class="bg-black-transparent absolute right-0 top-0 rounded-bl-full"
on:click={() => previewedImage.set(image)}
>
<MagnifyingGlassPlusIcon class="h-8 w-8 cursor-zoom-in pl-3 pb-3" color="white" />
</div>
{/if}
</div>
<div class="absolute bottom-0 left-0">
<ImageAttribution {image} {attributionFormat} />

View file

@ -20,7 +20,9 @@
</script>
{#if $license !== undefined}
<div class="no-images flex items-center rounded-lg bg-black-transparent p-0.5 px-3 text-sm text-white">
<div
class="no-images bg-black-transparent flex items-center rounded-lg p-0.5 px-3 text-sm text-white"
>
{#if icon !== undefined}
<div class="mr-2 h-6 w-6">
<ToSvelte construct={icon} />
@ -28,7 +30,7 @@
{/if}
<div class="flex gap-x-2" class:flex-col={attributionFormat !== "minimal"}>
{#if attributionFormat !== "minimal" }
{#if attributionFormat !== "minimal"}
{#if $license.title}
{#if $license.informationLocation}
<a href={$license.informationLocation.href} target="_blank" rel="noopener nofollower">
@ -42,7 +44,7 @@
{#if $license.artist}
{#if attributionFormat === "large"}
<Tr t={Translations.t.general.attribution.madeBy.Subs({author: $license.artist})} />
<Tr t={Translations.t.general.attribution.madeBy.Subs({ author: $license.artist })} />
{:else}
<div class="font-bold">
{@html $license.artist}
@ -58,7 +60,7 @@
{#if attributionFormat !== "minimal"}
<div class="flex w-full justify-between gap-x-1">
{#if ($license.license !== undefined || $license.licenseShortName !== undefined)}
{#if $license.license !== undefined || $license.licenseShortName !== undefined}
<div>
{$license?.license ?? $license?.licenseShortName}
</div>
@ -72,7 +74,6 @@
{/if}
</div>
{/if}
</div>
</div>
{/if}

View file

@ -39,10 +39,8 @@
<div
class="pointer-events-none absolute bottom-0 left-0 flex w-full flex-wrap items-end justify-between"
>
<div
class="pointer-events-auto m-1 w-fit transition-colors duration-200"
>
<ImageAttribution {image} attributionFormat="large"/>
<div class="pointer-events-auto m-1 w-fit transition-colors duration-200">
<ImageAttribution {image} attributionFormat="large" />
</div>
<button
@ -50,7 +48,7 @@
on:click={() => download()}
>
<DownloadIcon class="h-6 w-6 px-2 opacity-100" />
<Tr t={Translations.t.general.download.downloadImage}/>
<Tr t={Translations.t.general.download.downloadImage} />
</button>
</div>
</div>

View file

@ -33,7 +33,7 @@
key: undefined,
provider: AllImageProviders.byName(image.provider),
date: new Date(image.date),
id: Object.values(image.osmTags)[0]
id: Object.values(image.osmTags)[0],
}
async function applyLink(isLinked: boolean) {
@ -44,7 +44,7 @@
if (isLinked) {
const action = new LinkImageAction(currentTags.id, key, url, tags, {
theme: tags.data._orig_theme ?? state.layout.id,
changeType: "link-image"
changeType: "link-image",
})
await state.changes.applyAction(action)
} else {
@ -53,7 +53,7 @@
if (v === url) {
const action = new ChangeTagAction(currentTags.id, new Tag(k, ""), currentTags, {
theme: tags.data._orig_theme ?? state.layout.id,
changeType: "remove-image"
changeType: "remove-image",
})
state.changes.applyAction(action)
}
@ -62,11 +62,13 @@
}
isLinked.addCallback((isLinked) => applyLink(isLinked))
</script>
<div class="flex w-fit shrink-0 flex-col rounded-lg overflow-hidden" class:border-interactive={$isLinked}
style="border-width: 2px">
<div
class="flex w-fit shrink-0 flex-col overflow-hidden rounded-lg"
class:border-interactive={$isLinked}
style="border-width: 2px"
>
<AttributedImage
image={providedImage}
imgClass="max-h-64 w-auto"

View file

@ -13,12 +13,10 @@ export default class UrlValidator extends Validator {
"tripadvisor.co.uk",
"tripadvisor.com.au",
"katestravelexperience.eu",
"hoteldetails.eu"
"hoteldetails.eu",
])
private static readonly discouragedWebsites = new Set<string>([
"facebook.com"
])
private static readonly discouragedWebsites = new Set<string>(["facebook.com"])
constructor(name?: string, explanation?: string, forceHttps?: boolean) {
super(
@ -93,14 +91,10 @@ export default class UrlValidator extends Validator {
* v.getFeedback("https://booking.com/some-hotel.html").textFor("en") // => Translations.t.validation.url.spamSite.Subs({host: "booking.com"}).textFor("en")
*/
getFeedback(s: string, getCountry?: () => string): Translation | undefined {
if (
!s.startsWith("http://") &&
!s.startsWith("https://") &&
!s.startsWith("http:")
) {
if (!s.startsWith("http://") && !s.startsWith("https://") && !s.startsWith("http:")) {
s = "https://" + s
}
try{
try {
const url = new URL(s)
let host = url.host.toLowerCase()
if (host.startsWith("www.")) {
@ -112,9 +106,7 @@ export default class UrlValidator extends Validator {
if (UrlValidator.discouragedWebsites.has(host)) {
return Translations.t.validation.url.aggregator.Subs({ host })
}
}catch (e) {
} catch (e) {
// pass
}
const upstream = super.getFeedback(s, getCountry)
@ -122,7 +114,6 @@ export default class UrlValidator extends Validator {
return upstream
}
return undefined
}
@ -131,7 +122,6 @@ export default class UrlValidator extends Validator {
* v.isValid("https://booking.com/some-hotel.html") // => false
*/
isValid(str: string): boolean {
try {
if (
!str.startsWith("http://") &&

View file

@ -27,7 +27,7 @@
photo: ["photo", "historicphoto"],
map: ["map", "historicmap"],
other: ["other", "elevation"],
osmbasedmap: ["osmbasedmap"]
osmbasedmap: ["osmbasedmap"],
}
function availableForCategory(type: CategoryType): Store<RasterLayerPolygon[]> {
@ -51,20 +51,18 @@
}
export let onlyLink: boolean
</script>
<Page {onlyLink} shown={shown} fullscreen={true}>
<div slot="header" class="flex" >
<Page {onlyLink} {shown} fullscreen={true}>
<div slot="header" class="flex">
<Square3Stack3dIcon class="h-6 w-6" />
<Tr t={Translations.t.general.backgroundMap} />
<Tr t={Translations.t.general.backgroundMap} />
</div>
{#if $_availableLayers?.length < 1}
<Loading />
{:else}
<div class="flex gap-x-2 flex-col sm:flex-row gap-y-2" style="height: calc( 100% - 5rem)">
<div class="flex flex-col gap-x-2 gap-y-2 sm:flex-row" style="height: calc( 100% - 5rem)">
<RasterLayerPicker
availableLayers={$photoLayers}
favourite={getPref("photo")}

View file

@ -55,7 +55,7 @@
for (const preset of layer.presets) {
const tags = TagUtils.KVtoProperties(preset.tags ?? [])
if(preset.preciseInput.snapToLayers){
if (preset.preciseInput.snapToLayers) {
tags["_referencing_ways"] = '["way/-1"]'
}

View file

@ -386,7 +386,7 @@
/>
{:else if config.mappings !== undefined && !config.multiAnswer}
<!-- Simple radiobuttons as mapping -->
<div class="flex flex-col no-bold">
<div class="no-bold flex flex-col">
{#each config.mappings as mapping, i (mapping.then)}
<!-- Even though we have a list of 'mappings' already, we still iterate over the list as to keep the original indices-->
<TagRenderingMappingInput
@ -401,7 +401,7 @@
>
<input
type="radio"
class="self-center mr-1"
class="mr-1 self-center"
bind:group={selectedMapping}
name={"mappings-radio-" + config.id}
value={i}
@ -413,7 +413,7 @@
<label class="flex gap-x-1">
<input
type="radio"
class="self-center mr-1"
class="mr-1 self-center"
bind:group={selectedMapping}
name={"mappings-radio-" + config.id}
value={config.mappings?.length}
@ -436,7 +436,7 @@
</div>
{:else if config.mappings !== undefined && config.multiAnswer}
<!-- Multiple answers can be chosen: checkboxes -->
<div class="flex flex-col no-bold">
<div class="no-bold flex flex-col">
{#each config.mappings as mapping, i (mapping.then)}
<TagRenderingMappingInput
{mapping}
@ -450,7 +450,7 @@
>
<input
type="checkbox"
class="self-center mr-1"
class="mr-1 self-center"
name={"mappings-checkbox-" + config.id + "-" + i}
bind:checked={checkedMappings[i]}
on:keypress={(e) => onInputKeypress(e)}
@ -461,7 +461,7 @@
<label class="flex gap-x-1">
<input
type="checkbox"
class="self-center mr-1"
class="mr-1 self-center"
name={"mappings-checkbox-" + config.id + "-" + config.mappings?.length}
bind:checked={checkedMappings[config.mappings.length]}
on:keypress={(e) => onInputKeypress(e)}

File diff suppressed because it is too large Load diff

View file

@ -28,8 +28,8 @@
}
let configJson: Store<QuestionableTagRenderingConfigJson[]> = value.map((x) => {
if(x === undefined){
console.log("No config found for ",path)
if (x === undefined) {
console.log("No config found for ", path)
return []
}
if (typeof x === "string") {

View file

@ -13,9 +13,7 @@
import type { MapProperties } from "../Models/MapProperties"
import Geosearch from "./BigComponents/Geosearch.svelte"
import Translations from "./i18n/Translations"
import {
MenuIcon,
} from "@rgossiaux/svelte-heroicons/solid"
import { MenuIcon } from "@rgossiaux/svelte-heroicons/solid"
import Tr from "./Base/Tr.svelte"
import FloatOver from "./Base/FloatOver.svelte"
import Constants from "../Models/Constants"
@ -73,7 +71,6 @@
})
})
let selectedLayer: Store<LayerConfig> = state.selectedElement.mapD((element) => {
const id = element.properties.id
if (id.startsWith("current_view")) {
@ -100,11 +97,11 @@
state.mapProperties.installCustomKeyboardHandler(viewport)
let canZoomIn = mapproperties.maxzoom.map(
(mz) => mapproperties.zoom.data < mz,
[mapproperties.zoom],
[mapproperties.zoom]
)
let canZoomOut = mapproperties.minzoom.map(
(mz) => mapproperties.zoom.data > mz,
[mapproperties.zoom],
[mapproperties.zoom]
)
function updateViewport() {
@ -140,7 +137,7 @@
onDestroy(
rasterLayer.addCallbackAndRunD((l) => {
rasterLayerName = l.properties.name
}),
})
)
let previewedImage = state.previewedImage
let addNewFeatureMode = state.userRelatedState.addNewFeatureMode
@ -148,7 +145,6 @@
let gpsButtonAriaLabel = state.geolocation.geolocationState.gpsStateExplanation
let debug = state.featureSwitches.featureSwitchIsDebugging
debug.addCallbackAndRun((dbg) => {
if (dbg) {
document.body.classList.add("debug")
@ -193,14 +189,17 @@
<!-- Top components -->
<div
class="flex bg-black-light-transparent pointer-events-auto items-center justify-between px-4 py-1 flex-wrap-reverse">
class="bg-black-light-transparent pointer-events-auto flex flex-wrap-reverse items-center justify-between px-4 py-1"
>
<!-- Top bar with tools -->
<div class="flex items-center">
<MapControlButton
cls="m-0.5 p-0.5 sm:p-1"
arialabel={Translations.t.general.labels.menu}
on:click={() => {console.log("Opening...."); state.guistate.pageStates.menu.setData(true)}}
on:click={() => {
console.log("Opening....")
state.guistate.pageStates.menu.setData(true)
}}
on:keydown={forwardEventToMap}
>
<MenuIcon class="h-6 w-6 cursor-pointer" />
@ -210,9 +209,7 @@
on:click={() => state.guistate.pageStates.about_theme.set(true)}
on:keydown={forwardEventToMap}
>
<div
class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 mr-2"
>
<div class="m-0.5 mx-1 mr-2 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1">
<Marker icons={layout.icon} size="h-6 w-6 shrink-0 mr-0.5 sm:mr-1 md:mr-2" />
<b class="mr-1">
<Tr t={layout.title} />
@ -228,20 +225,18 @@
{/if}
<If condition={state.featureSwitches.featureSwitchSearch}>
<div class="w-full sm:w-64 my-2 sm:mt-0">
<div class="my-2 w-full sm:mt-0 sm:w-64">
<Geosearch
bounds={state.mapProperties.bounds}
on:searchCompleted={() => {
state.map?.data?.getCanvas()?.focus()
}}
state.map?.data?.getCanvas()?.focus()
}}
perLayer={state.perLayer}
selectedElement={state.selectedElement}
geolocationState={state.geolocation.geolocationState}
/>
</div>
</If>
</div>
<div class="pointer-events-auto float-right mt-1 flex flex-col px-1 max-[480px]:w-full sm:m-2">
@ -252,13 +247,9 @@
</div>
{/if}
</If>
</div>
<div class="float-left m-1 flex flex-col sm:mt-2">
<If condition={state.featureSwitches.featureSwitchWelcomeMessage}>
</If>
<If condition={state.featureSwitches.featureSwitchWelcomeMessage} />
{#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()}
<MapControlButton
on:click={() => {
@ -329,15 +320,14 @@
</MapControlButton>
</If>
<If condition={state.featureSwitches.featureSwitchBackgroundSelection}>
<OpenBackgroundSelectorButton
hideTooltip={true}
{state}
/>
<OpenBackgroundSelectorButton hideTooltip={true} {state} />
</If>
<button
class="unstyled bg-black-transparent pointer-events-auto ml-1 h-fit max-h-12 cursor-pointer overflow-hidden rounded-2xl px-1 text-white opacity-50 hover:opacity-100"
style="background: #00000088; padding: 0.25rem; border-radius: 2rem;"
on:click={() => {state.guistate.pageStates.copyright.set(true)}}
on:click={() => {
state.guistate.pageStates.copyright.set(true)
}}
>
© <span class="hidden sm:inline sm:pr-2">
OpenStreetMap
@ -450,7 +440,11 @@
state.selectedElement.setData(undefined)
}}
>
<SelectedElementView {state} layer={$selectedLayer} selectedElement={$state_selectedElement} />
<SelectedElementView
{state}
layer={$selectedLayer}
selectedElement={$state_selectedElement}
/>
</FloatOver>
{/if}
{/if}
@ -461,6 +455,4 @@
<ImageOperations image={$previewedImage} />
</FloatOver>
</If>
</main>