forked from MapComplete/MapComplete
Merge master
This commit is contained in:
commit
51fa48a01f
151 changed files with 16260 additions and 1872 deletions
|
|
@ -124,7 +124,7 @@
|
|||
|
||||
<LoginToggle {state}>
|
||||
<LoginButton clss="primary" {osmConnection} slot="not-logged-in">
|
||||
<Tr t={t.logIn}/>
|
||||
<Tr t={t.logIn} />
|
||||
</LoginButton>
|
||||
<ThemesList
|
||||
hideThemes={false}
|
||||
|
|
|
|||
|
|
@ -26,14 +26,13 @@
|
|||
return state.layout.getMatchingLayer(properties)
|
||||
}
|
||||
|
||||
|
||||
let layer = getLayer(selected.properties)
|
||||
|
||||
let stillMatches = tags.map(
|
||||
(tags) => !layer?.source?.osmTags || layer?.source?.osmTags?.matchesProperties(tags)
|
||||
)
|
||||
onDestroy(
|
||||
stillMatches.addCallbackAndRunD(matches => {
|
||||
stillMatches.addCallbackAndRunD((matches) => {
|
||||
if (matches) {
|
||||
return
|
||||
}
|
||||
|
|
@ -42,7 +41,7 @@
|
|||
* However, because there are quite some legacy elements and some elements have a different layer calculation,
|
||||
* we simply close the popup and open it again.
|
||||
* See #1956
|
||||
*/
|
||||
*/
|
||||
state.selectedElement.setData(undefined)
|
||||
requestAnimationFrame(() => {
|
||||
state.selectedElement.setData(selected)
|
||||
|
|
@ -51,11 +50,10 @@
|
|||
)
|
||||
</script>
|
||||
|
||||
|
||||
{#if !$stillMatches}
|
||||
<Loading />
|
||||
{:else}
|
||||
<div class="normal-background flex h-full w-full flex-col" class:absolute={absolute}>
|
||||
<div class="normal-background flex h-full w-full flex-col" class:absolute>
|
||||
<SelectedElementTitle {state} {layer} selectedElement={selected} />
|
||||
<SelectedElementView {state} {layer} selectedElement={selected} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -38,28 +38,19 @@
|
|||
|
||||
let bgAttr: BaseUIElement | string = undefined
|
||||
if (attrText && attrUrl) {
|
||||
bgAttr =
|
||||
"<a href='" +
|
||||
attrUrl +
|
||||
"' target='_blank' rel='noopener'>" +
|
||||
attrText +
|
||||
"</a>"
|
||||
bgAttr = "<a href='" + attrUrl + "' target='_blank' rel='noopener'>" + attrText + "</a>"
|
||||
} else if (attrUrl) {
|
||||
bgAttr = attrUrl
|
||||
} else {
|
||||
bgAttr = attrText
|
||||
}
|
||||
if (bgAttr) {
|
||||
return Translations.t.general.attribution.attributionBackgroundLayerWithCopyright.Subs(
|
||||
{
|
||||
name: props.name,
|
||||
copyright: bgAttr
|
||||
}
|
||||
)
|
||||
return Translations.t.general.attribution.attributionBackgroundLayerWithCopyright.Subs({
|
||||
name: props.name,
|
||||
copyright: bgAttr,
|
||||
})
|
||||
}
|
||||
return Translations.t.general.attribution.attributionBackgroundLayer.Subs(
|
||||
props
|
||||
)
|
||||
return Translations.t.general.attribution.attributionBackgroundLayer.Subs(props)
|
||||
})
|
||||
|
||||
const allLicenses = {}
|
||||
|
|
@ -68,14 +59,13 @@
|
|||
allLicenses[license.path] = license
|
||||
}
|
||||
|
||||
|
||||
function calculateDataContributions(contributions: Map<string, number>): Translation {
|
||||
if (contributions === undefined) {
|
||||
return undefined
|
||||
}
|
||||
const sorted = Array.from(contributions, ([name, value]) => ({
|
||||
name,
|
||||
value
|
||||
value,
|
||||
})).filter((x) => x.name !== undefined && x.name !== "undefined")
|
||||
if (sorted.length === 0) {
|
||||
return undefined
|
||||
|
|
@ -87,29 +77,30 @@
|
|||
sorted.splice(10, sorted.length - 10)
|
||||
}
|
||||
const links = sorted.map(
|
||||
(kv) =>
|
||||
`<a href="https://openstreetmap.org/user/${kv.name}" target="_blank">${kv.name}</a>`
|
||||
(kv) => `<a href="https://openstreetmap.org/user/${kv.name}" target="_blank">${kv.name}</a>`
|
||||
)
|
||||
const contribs = links.join(", ")
|
||||
|
||||
if (hiddenCount <= 0) {
|
||||
return t.mapContributionsBy.Subs({
|
||||
contributors: contribs
|
||||
contributors: contribs,
|
||||
})
|
||||
} else {
|
||||
return t.mapContributionsByAndHidden.Subs({
|
||||
contributors: contribs,
|
||||
hiddenCount: hiddenCount
|
||||
hiddenCount: hiddenCount,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const datacontributions = new ContributorCount(state).Contributors.map(counts => calculateDataContributions(counts))
|
||||
|
||||
|
||||
function codeContributors(contributors,
|
||||
translation: TypedTranslation<{ contributors; hiddenCount }>): Translation {
|
||||
const datacontributions = new ContributorCount(state).Contributors.map((counts) =>
|
||||
calculateDataContributions(counts)
|
||||
)
|
||||
|
||||
function codeContributors(
|
||||
contributors,
|
||||
translation: TypedTranslation<{ contributors; hiddenCount }>
|
||||
): Translation {
|
||||
const total = contributors.contributors.length
|
||||
let filtered = [...contributors.contributors]
|
||||
|
||||
|
|
@ -124,23 +115,23 @@
|
|||
|
||||
return translation.Subs({
|
||||
contributors: contribsStr,
|
||||
hiddenCount: total - 10
|
||||
hiddenCount: total - 10,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-y-4 link-underline">
|
||||
<div class="link-underline flex flex-col gap-y-4">
|
||||
<h3>
|
||||
<Tr t={t.attributionTitle} />
|
||||
</h3>
|
||||
<div class="flex items-center gap-x-2">
|
||||
<Osm_logo class="w-8 h-8 shrink-0" />
|
||||
<Osm_logo class="h-8 w-8 shrink-0" />
|
||||
<Tr t={t.attributionContent} />
|
||||
</div>
|
||||
|
||||
{#if $bgMapAttribution !== undefined}
|
||||
<div class="flex items-center gap-x-2">
|
||||
<Generic_map class="w-8 h-8 shrink-0" />
|
||||
<Generic_map class="h-8 w-8 shrink-0" />
|
||||
<Tr t={$bgMapAttribution} />
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -151,23 +142,20 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
{#if $datacontributions !== undefined}
|
||||
<div class="flex items-center gap-x-2">
|
||||
<UserGroupIcon class="w-8 h-8 shrink-0" />
|
||||
<UserGroupIcon class="h-8 w-8 shrink-0" />
|
||||
<Tr t={$datacontributions} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex items-center gap-x-2">
|
||||
|
||||
|
||||
<Github class="w-8 h-8 shrink-0" />
|
||||
<Github class="h-8 w-8 shrink-0" />
|
||||
<Tr t={codeContributors(contributors, t.codeContributionsBy)} />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-x-2">
|
||||
<TranslateIcon class="w-8 h-8 shrink-0" />
|
||||
<TranslateIcon class="h-8 w-8 shrink-0" />
|
||||
<Tr t={codeContributors(translators, t.translatedBy)} />
|
||||
</div>
|
||||
|
||||
|
|
@ -180,7 +168,6 @@
|
|||
{/each}
|
||||
</AccordionSingle>
|
||||
|
||||
|
||||
<div class="self-end">
|
||||
MapComplete {Constants.vNumber}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -48,14 +48,13 @@
|
|||
</script>
|
||||
|
||||
<TitledPanel>
|
||||
<div class="flex flex-wrap items-center justify-between w-full mr-10" slot="title">
|
||||
<div class="mr-10 flex w-full flex-wrap items-center justify-between" slot="title">
|
||||
<div class="flex">
|
||||
<Filter class="h-6 w-6 pr-2" />
|
||||
<Tr t={Translations.t.general.menu.filter} />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex self-end text-sm gap-x-2 ml-2 self-end">
|
||||
<div class="ml-2 flex gap-x-2 self-end self-end text-sm">
|
||||
<button class="small as-link" class:disabled={allEnabled} on:click={() => enableAll(true)}>
|
||||
<Tr t={Translations.t.general.filterPanel.enableAll} />
|
||||
</button>
|
||||
|
|
@ -63,24 +62,22 @@
|
|||
<Tr t={Translations.t.general.filterPanel.disableAll} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{#each layout.layers as layer}
|
||||
<Filterview
|
||||
zoomlevel={state.mapProperties.zoom}
|
||||
filteredLayer={state.layerState.filteredLayers.get(layer.id)}
|
||||
highlightedLayer={state.guistate.highlightedLayerInFilters}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
{#each layout.tileLayerSources as tilesource}
|
||||
<OverlayToggle
|
||||
layerproperties={tilesource}
|
||||
state={state.overlayLayerStates.get(tilesource.id)}
|
||||
highlightedLayer={state.guistate.highlightedLayerInFilters}
|
||||
zoomlevel={state.mapProperties.zoom}
|
||||
/>
|
||||
{/each}
|
||||
{#each layout.layers as layer}
|
||||
<Filterview
|
||||
zoomlevel={state.mapProperties.zoom}
|
||||
filteredLayer={state.layerState.filteredLayers.get(layer.id)}
|
||||
highlightedLayer={state.guistate.highlightedLayerInFilters}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
{#each layout.tileLayerSources as tilesource}
|
||||
<OverlayToggle
|
||||
layerproperties={tilesource}
|
||||
state={state.overlayLayerStates.get(tilesource.id)}
|
||||
highlightedLayer={state.guistate.highlightedLayerInFilters}
|
||||
zoomlevel={state.mapProperties.zoom}
|
||||
/>
|
||||
{/each}
|
||||
</TitledPanel>
|
||||
|
|
|
|||
|
|
@ -23,9 +23,14 @@
|
|||
</script>
|
||||
|
||||
{#if license != undefined && license.license.indexOf("trivial") < 0}
|
||||
<div class="flex flex-wrap border-b border-gray-300 m-2 border-box">
|
||||
<img class={twJoin( "w-12 min-h-12 mr-2 mb-2", license["mostly_white"] && "bg-slate-400 rounded-full h-12" )}
|
||||
src={iconPath} />
|
||||
<div class="border-box m-2 flex flex-wrap border-b border-gray-300">
|
||||
<img
|
||||
class={twJoin(
|
||||
"min-h-12 mr-2 mb-2 w-12",
|
||||
license["mostly_white"] && "h-12 rounded-full bg-slate-400"
|
||||
)}
|
||||
src={iconPath}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col" style="width: calc(100% - 50px - 0.5em); min-width: 12rem;">
|
||||
<div class="font-bold">
|
||||
|
|
@ -36,7 +41,5 @@
|
|||
<a href={source} target="_blank">{sourceName(source)}</a>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@
|
|||
</div>
|
||||
<slot name="close-button">
|
||||
<button
|
||||
class="mt-2 h-fit shrink-0 rounded-full border-none p-0 cursor-pointer self-center"
|
||||
class="mt-2 h-fit shrink-0 cursor-pointer self-center rounded-full border-none p-0"
|
||||
on:click={() => state.selectedElement.setData(undefined)}
|
||||
style="border: 0 !important; padding: 0 !important;"
|
||||
use:ariaLabel={Translations.t.general.backToMap}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
(t) => t?.id?.startsWith(LastClickFeatureSource.newPointElementId) ?? false
|
||||
)
|
||||
|
||||
|
||||
export let layer: LayerConfig
|
||||
|
||||
let _metatags: Record<string, string>
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@
|
|||
{:else if icon === "party"}
|
||||
<Party {color} class={clss} />
|
||||
{:else if icon === "cross_bottom_right"}
|
||||
<Cross_bottom_right {color} class={"m-0 "+clss} />
|
||||
<Cross_bottom_right {color} class={"m-0 " + clss} />
|
||||
{:else if icon === "addSmall"}
|
||||
<AddSmall {color} class={clss} />
|
||||
{:else if icon === "gear"}
|
||||
|
|
@ -137,9 +137,9 @@
|
|||
{:else if icon === "popout"}
|
||||
<LinkIcon style="--svg-color: {color}" />
|
||||
{:else if icon === "wifi"}
|
||||
<WifiIcon class={"m-0 " +clss} {color} />
|
||||
<WifiIcon class={"m-0 " + clss} {color} />
|
||||
{:else if icon === "computer"}
|
||||
<DesktopComputerIcon class={"m-0 "+clss} {color} />
|
||||
<DesktopComputerIcon class={"m-0 " + clss} {color} />
|
||||
{:else if icon === "relocation"}
|
||||
<Relocation class={clss} {color} />
|
||||
{:else if Utils.isEmoji(icon)}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
{#if iconsParsed !== undefined && iconsParsed.length > 0}
|
||||
<div class={twMerge("relative", size)}>
|
||||
{#each iconsParsed as icon}
|
||||
<div class="absolute top-0 left-0 h-full w-full flex items-center">
|
||||
<div class="absolute top-0 left-0 flex h-full w-full items-center">
|
||||
<Icon icon={icon.icon} color={icon.color} {clss} />
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,11 @@ export default class OpeningHoursInput extends InputElement<string> {
|
|||
|
||||
const ohPicker = new OpeningHoursPicker(rulesFromOhPicker)
|
||||
|
||||
this._element = new Combine([leftoverWarning, ohPicker, new SvelteUIElement(PublicHolidaySelector, {value: phSelectorValue})])
|
||||
this._element = new Combine([
|
||||
leftoverWarning,
|
||||
ohPicker,
|
||||
new SvelteUIElement(PublicHolidaySelector, { value: phSelectorValue }),
|
||||
])
|
||||
}
|
||||
|
||||
GetValue(): UIEventSource<string> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts">
|
||||
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Dropdown from "../Base/Dropdown.svelte"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
|
|
@ -15,7 +14,6 @@
|
|||
const t = Translations.t.general.opening_hours
|
||||
let mode = new UIEventSource("")
|
||||
|
||||
|
||||
value
|
||||
.map((ph) => OH.ParsePHRule(ph))
|
||||
.addCallbackAndRunD((parsed) => {
|
||||
|
|
@ -47,11 +45,9 @@
|
|||
startValue.addCallbackAndRunD(() => updateValue())
|
||||
endValue.addCallbackAndRunD(() => updateValue())
|
||||
mode.addCallbackAndRunD(() => updateValue())
|
||||
|
||||
</script>
|
||||
|
||||
<label>
|
||||
|
||||
<Tr t={t.open_during_ph} />
|
||||
|
||||
<Dropdown value={mode}>
|
||||
|
|
@ -67,7 +63,8 @@
|
|||
<Tr t={t.ph_open_as_usual} />
|
||||
</option>
|
||||
|
||||
<option value={" "}> <!-- Yes, the value is a single space-->
|
||||
<option value={" "}>
|
||||
<!-- Yes, the value is a single space-->
|
||||
<Tr t={t.ph_open} />
|
||||
</option>
|
||||
</Dropdown>
|
||||
|
|
@ -76,20 +73,20 @@
|
|||
{#if $mode === " "}
|
||||
<div class="flex">
|
||||
<Tr t={t.opensAt} />
|
||||
<ToSvelte construct={
|
||||
|
||||
new TextField({
|
||||
value: startValue,
|
||||
placeholder: "starthour",
|
||||
htmlType: "time",
|
||||
}).SetClass("inline-block")
|
||||
} />
|
||||
<ToSvelte
|
||||
construct={new TextField({
|
||||
value: startValue,
|
||||
placeholder: "starthour",
|
||||
htmlType: "time",
|
||||
}).SetClass("inline-block")}
|
||||
/>
|
||||
<Tr t={t.openTill} />
|
||||
<ToSvelte construct={ new TextField({
|
||||
value: endValue,
|
||||
placeholder: "endhour",
|
||||
htmlType: "time",
|
||||
}).SetClass("inline-block")
|
||||
} />
|
||||
<ToSvelte
|
||||
construct={new TextField({
|
||||
value: endValue,
|
||||
placeholder: "endhour",
|
||||
htmlType: "time",
|
||||
}).SetClass("inline-block")}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
<button
|
||||
on:click
|
||||
class="as-link h-8 w-8 shrink-0 self-start rounded-full p-1 edit-button"
|
||||
class="as-link edit-button h-8 w-8 shrink-0 self-start rounded-full p-1"
|
||||
aria-labelledby={arialabel === undefined ? ariaLabelledBy : undefined}
|
||||
use:ariaLabel={arialabel}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -118,7 +118,9 @@
|
|||
</button>
|
||||
</TagRenderingQuestion>
|
||||
{:else}
|
||||
<div class="low-interaction flex items-center justify-between overflow-hidden rounded pl-2 answer">
|
||||
<div
|
||||
class="low-interaction answer flex items-center justify-between overflow-hidden rounded pl-2"
|
||||
>
|
||||
<TagRenderingAnswer
|
||||
id={answerId}
|
||||
{config}
|
||||
|
|
@ -143,14 +145,13 @@
|
|||
<TagRenderingAnswer {config} {tags} {selectedElement} {state} {layer} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.answer {
|
||||
border: 1px solid #00000000;
|
||||
}
|
||||
|
||||
.answer {
|
||||
border: 1px solid #00000000;
|
||||
}
|
||||
|
||||
.answer:has(.edit-button:hover) {
|
||||
border: 1px solid var(--catch-detail-color-contrast);
|
||||
}
|
||||
|
||||
.answer:has(.edit-button:hover) {
|
||||
border: 1px solid var(--catch-detail-color-contrast);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -82,7 +82,7 @@
|
|||
</script>
|
||||
|
||||
<div class="flex h-screen flex-col">
|
||||
<div class="my-2 flex flex-wrap w-full justify-between">
|
||||
<div class="my-2 flex w-full flex-wrap justify-between">
|
||||
<slot />
|
||||
{#if $title === undefined}
|
||||
<h3>Creating a new layer</h3>
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@
|
|||
<div class="flex justify-between">
|
||||
<Checkbox selected={expertMode}>Enable more options (expert mode)</Checkbox>
|
||||
<span class="subtle">MapComplete version {version}</span>
|
||||
<div>{$uid}</div>
|
||||
<div>{$uid}</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if state === "edit_layer"}
|
||||
|
|
@ -371,7 +371,7 @@
|
|||
{:else if state === "editing_layer"}
|
||||
<EditLayer state={editLayerState} {backToStudio}>
|
||||
<BackButton clss="small p-1" imageClass="w-8 h-8" on:click={() => backToStudio()}>
|
||||
Studio
|
||||
Studio
|
||||
</BackButton>
|
||||
</EditLayer>
|
||||
{:else if state === "editing_theme"}
|
||||
|
|
|
|||
|
|
@ -310,10 +310,8 @@
|
|||
on:keydown={forwardEventToMap}
|
||||
htmlElem={openCurrentViewLayerButton}
|
||||
>
|
||||
<div class="w-8 h-8 cursor-pointer">
|
||||
<ToSvelte
|
||||
construct={() => currentViewLayer.defaultIcon()}
|
||||
/>
|
||||
<div class="h-8 w-8 cursor-pointer">
|
||||
<ToSvelte construct={() => currentViewLayer.defaultIcon()} />
|
||||
</div>
|
||||
</MapControlButton>
|
||||
{/if}
|
||||
|
|
@ -324,9 +322,7 @@
|
|||
<div class="alert w-fit">Testmode</div>
|
||||
</If>
|
||||
{#if state.osmConnection.Backend().startsWith("https://master.apis.dev.openstreetmap.org")}
|
||||
<div class="thanks">
|
||||
Testserver
|
||||
</div>
|
||||
<div class="thanks">Testserver</div>
|
||||
{/if}
|
||||
<If condition={state.featureSwitches.featureSwitchFakeUser}>
|
||||
<div class="alert w-fit">Faking a user (Testmode)</div>
|
||||
|
|
@ -488,8 +484,8 @@
|
|||
{#if $selectedLayer.popupInFloatover === "title"}
|
||||
<FloatOver
|
||||
on:close={() => {
|
||||
state.selectedElement.setData(undefined)
|
||||
}}
|
||||
state.selectedElement.setData(undefined)
|
||||
}}
|
||||
>
|
||||
<span slot="close-button" />
|
||||
<SelectedElementPanel absolute={false} {state} selected={$selectedElement} />
|
||||
|
|
@ -497,13 +493,12 @@
|
|||
{:else}
|
||||
<FloatOver
|
||||
on:close={() => {
|
||||
state.selectedElement.setData(undefined)
|
||||
}}
|
||||
state.selectedElement.setData(undefined)
|
||||
}}
|
||||
>
|
||||
<SelectedElementView {state} layer={$selectedLayer} selectedElement={$selectedElement} />
|
||||
</FloatOver>
|
||||
{/if}
|
||||
|
||||
{/if}
|
||||
|
||||
<If condition={state.previewedImage.map((i) => i !== undefined)}>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue