Merge branch 'develop'
This commit is contained in:
commit
7d02b90232
41 changed files with 2507 additions and 170 deletions
|
@ -7,6 +7,21 @@
|
|||
*/
|
||||
|
||||
export let open = new UIEventSource(false)
|
||||
export let dotsSize = `w-6 h-6`
|
||||
export let dotsPosition = `top-0 right-0`
|
||||
export let hideBackground= false
|
||||
let menuPosition = ``
|
||||
if(dotsPosition.indexOf("left-0") >= 0){
|
||||
menuPosition = "left-0"
|
||||
}else{
|
||||
menuPosition = `right-0`
|
||||
}
|
||||
|
||||
if(dotsPosition.indexOf("top-0") > 0){
|
||||
menuPosition += " bottom-0"
|
||||
}else{
|
||||
menuPosition += ` top-0`
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
open.set(!open.data)
|
||||
|
@ -17,18 +32,22 @@
|
|||
|
||||
<div class="relative" style="z-index: 50">
|
||||
<div
|
||||
class="sidebar-unit absolute right-0 top-0 collapsable normal-background button-unstyled"
|
||||
class="sidebar-unit absolute {menuPosition} collapsable normal-background button-unstyled "
|
||||
class:transition-background={hideBackground}
|
||||
class:collapsed={!$open}>
|
||||
<slot />
|
||||
</div>
|
||||
<DotsCircleHorizontal class={ `absolute top-0 right-0 w-6 h-6 dots-menu transition-colors ${$open?"dots-menu-opened":""}`} on:click={toggle} />
|
||||
<DotsCircleHorizontal
|
||||
class={ `absolute ${dotsPosition} ${dotsSize} dots-menu transition-colors ${$open?"dots-menu-opened":""}`}
|
||||
on:click={toggle} />
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.dots-menu{
|
||||
.dots-menu {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
:global(.dots-menu > path) {
|
||||
fill: var(--interactive-background);
|
||||
transition: fill 350ms linear;
|
||||
|
@ -41,16 +60,25 @@
|
|||
}
|
||||
|
||||
.collapsable {
|
||||
max-width: 100rem;
|
||||
max-height: 100rem;
|
||||
transition: border 150ms linear, max-width 500ms linear, max-height 500ms linear;
|
||||
max-width: 50rem;
|
||||
max-height: 10rem;
|
||||
transition: max-width 500ms linear, max-height 500ms linear, border 500ms linear;
|
||||
overflow: hidden;
|
||||
flex-wrap: nowrap;
|
||||
text-wrap: none;
|
||||
width: max-content;
|
||||
box-shadow: #ccc ;
|
||||
box-shadow: #ccc;
|
||||
white-space: nowrap;
|
||||
border: 1px solid var(--button-background);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.transition-background {
|
||||
transition: background-color 150ms linear;
|
||||
}
|
||||
|
||||
.transition-background.collapsed {
|
||||
background-color: #00000000;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
{/each}
|
||||
|
||||
{#if $favourites.length > 0}
|
||||
<div class="mt-8 flex">
|
||||
<div class="mt-8 sm:flex">
|
||||
<button on:click={() => downloadGeojson()}>
|
||||
<ArrowDownTray class="h-6 w-6" />
|
||||
<Tr t={Translations.t.favouritePoi.downloadGeojson} />
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
import Loading from "../Base/Loading.svelte"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import DotMenu from "../Base/DotMenu.svelte"
|
||||
|
||||
export let image: ProvidedImage
|
||||
export let clss: string = undefined
|
||||
|
||||
let isLoaded = new UIEventSource(false)
|
||||
|
||||
async function download() {
|
||||
const response = await fetch(image.url_hd ?? image.url)
|
||||
const blob = await response.blob()
|
||||
|
@ -36,6 +38,16 @@
|
|||
{/if}
|
||||
<ImagePreview {image} {isLoaded} />
|
||||
</div>
|
||||
|
||||
<DotMenu dotsPosition="top-0 left-0" dotsSize="w-8 h-8" hideBackground>
|
||||
<button
|
||||
class="no-image-background pointer-events-auto flex items-center"
|
||||
on:click={() => download()}
|
||||
>
|
||||
<DownloadIcon class="h-6 w-6 px-2 opacity-100" />
|
||||
<Tr t={Translations.t.general.download.downloadImage} />
|
||||
</button>
|
||||
</DotMenu>
|
||||
<div
|
||||
class="pointer-events-none absolute bottom-0 left-0 flex w-full flex-wrap items-end justify-between"
|
||||
>
|
||||
|
@ -43,14 +55,8 @@
|
|||
<ImageAttribution {image} attributionFormat="large" />
|
||||
</div>
|
||||
|
||||
<slot/>
|
||||
<slot />
|
||||
|
||||
|
||||
<button
|
||||
class="no-image-background pointer-events-auto flex items-center bg-black text-white opacity-50 transition-colors duration-200 hover:opacity-100"
|
||||
on:click={() => download()}
|
||||
>
|
||||
<DownloadIcon class="h-6 w-6 px-2 opacity-100" />
|
||||
<Tr t={Translations.t.general.download.downloadImage} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -83,11 +83,11 @@
|
|||
{/each}
|
||||
<FileSelector
|
||||
accept="image/*"
|
||||
cls="button border-2 text-2xl"
|
||||
cls="button border-2 flex flex-col"
|
||||
multiple={true}
|
||||
on:submit={(e) => handleFiles(e.detail)}
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<div class="flex items-center text-2xl w-full justify-center">
|
||||
{#if image !== undefined}
|
||||
<img src={image} aria-hidden="true" />
|
||||
{:else}
|
||||
|
@ -100,8 +100,10 @@
|
|||
{/if}
|
||||
</div>
|
||||
</FileSelector>
|
||||
<div class="text-sm">
|
||||
<Tr cls="subtle italic" t={t.respectPrivacy} />
|
||||
<div class="text-xs subtle italic">
|
||||
<Tr t={Translations.t.general.attribution.panoramaxLicenseCCBYSA}/>
|
||||
<span class="mx-1">—</span>
|
||||
<Tr t={t.respectPrivacy} />
|
||||
</div>
|
||||
</div>
|
||||
</LoginToggle>
|
||||
|
|
|
@ -3,13 +3,10 @@
|
|||
* Opens the 'Opening hours input' in another top level window
|
||||
*/
|
||||
import { UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import ToSvelte from "../../Base/ToSvelte.svelte"
|
||||
import OpeningHoursInput from "../../OpeningHours/OpeningHoursState"
|
||||
import PublicHolidaySelector from "../../OpeningHours/PublicHolidaySelector.svelte"
|
||||
import OHTable from "./OpeningHours/OHTable.svelte"
|
||||
import OpeningHoursState from "../../OpeningHours/OpeningHoursState"
|
||||
import Popup from "../../Base/Popup.svelte"
|
||||
import CheckCircle from "@babeard/svelte-heroicons/mini/CheckCircle"
|
||||
import Check from "@babeard/svelte-heroicons/mini/Check"
|
||||
|
||||
export let value: UIEventSource<string>
|
||||
|
@ -31,7 +28,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
const state = new OpeningHoursState(value)
|
||||
const state = new OpeningHoursState(value, prefix, postfix)
|
||||
let expanded = new UIEventSource(false)
|
||||
</script>
|
||||
<Popup bodyPadding="p-0" shown={expanded}>
|
||||
|
|
|
@ -39,10 +39,10 @@ export abstract class Validator {
|
|||
this.inputmode = inputmode
|
||||
this.textArea = textArea ?? false
|
||||
if (this.name.endsWith("textfield")) {
|
||||
this.name = this.name.substr(0, this.name.length - "TextField".length)
|
||||
this.name = this.name.substring(0, this.name.length - "TextField".length)
|
||||
}
|
||||
if (this.name.endsWith("textfielddef")) {
|
||||
this.name = this.name.substr(0, this.name.length - "TextFieldDef".length)
|
||||
this.name = this.name.substring(0, this.name.length - "TextFieldDef".length)
|
||||
}
|
||||
if (typeof explanation === "string") {
|
||||
this.explanation = explanation
|
||||
|
|
|
@ -1,42 +1,29 @@
|
|||
import Combine from "../../Base/Combine"
|
||||
import Title from "../../Base/Title"
|
||||
import Table from "../../Base/Table"
|
||||
import { Validator } from "../Validator"
|
||||
import MarkdownUtils from "../../../Utils/MarkdownUtils"
|
||||
|
||||
export default class OpeningHoursValidator extends Validator {
|
||||
constructor() {
|
||||
super(
|
||||
"opening_hours",
|
||||
new Combine([
|
||||
[
|
||||
"Has extra elements to easily input when a POI is opened.",
|
||||
new Title("Helper arguments"),
|
||||
new Table(
|
||||
["name", "doc"],
|
||||
("### Helper arguments"),
|
||||
"Only one helper argument named `options` can be provided. It is a JSON-object of type `{ prefix: string, postfix: string }`:",
|
||||
MarkdownUtils.table(
|
||||
["subarg", "doc"],
|
||||
[
|
||||
[
|
||||
"options",
|
||||
new Combine([
|
||||
"A JSON-object of type `{ prefix: string, postfix: string }`. ",
|
||||
new Table(
|
||||
["subarg", "doc"],
|
||||
[
|
||||
[
|
||||
"prefix",
|
||||
"Piece of text that will always be added to the front of the generated opening hours. If the OSM-data does not start with this, it will fail to parse.",
|
||||
],
|
||||
[
|
||||
"postfix",
|
||||
"Piece of text that will always be added to the end of the generated opening hours",
|
||||
],
|
||||
]
|
||||
),
|
||||
]),
|
||||
"prefix",
|
||||
"Piece of text that will always be added to the front of the generated opening hours. If the OSM-data does not start with this, it will fail to parse."
|
||||
],
|
||||
]
|
||||
),
|
||||
new Title("Example usage"),
|
||||
[
|
||||
"postfix",
|
||||
"Piece of text that will always be added to the end of the generated opening hours"
|
||||
]
|
||||
]),
|
||||
("### Example usage"),
|
||||
"To add a conditional (based on time) access restriction:\n\n```\n" +
|
||||
`
|
||||
`
|
||||
"freeform": {
|
||||
"key": "access:conditional",
|
||||
"type": "opening_hours",
|
||||
|
@ -47,8 +34,8 @@ export default class OpeningHoursValidator extends Validator {
|
|||
}
|
||||
]
|
||||
}` +
|
||||
"\n```\n\n*Don't forget to pass the prefix and postfix in the rendering as well*: `{opening_hours_table(opening_hours,yes @ &LPARENS, &RPARENS )`",
|
||||
])
|
||||
"\n```\n\n*Don't forget to pass the prefix and postfix in the rendering as well*: `{opening_hours_table(opening_hours,yes @ &LPARENS, &RPARENS )`"
|
||||
].join("\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { parsePhoneNumberFromString } from "libphonenumber-js"
|
||||
import { CountryCode, parsePhoneNumberFromString } from "libphonenumber-js"
|
||||
import { Validator } from "../Validator"
|
||||
import { Translation } from "../../i18n/Translation"
|
||||
import Translations from "../../i18n/Translations"
|
||||
|
@ -46,16 +46,16 @@ export default class PhoneValidator extends Validator {
|
|||
if (str.startsWith("tel:")) {
|
||||
str = str.substring("tel:".length)
|
||||
}
|
||||
let countryCode = undefined
|
||||
let countryCode: CountryCode = undefined
|
||||
if (country) {
|
||||
countryCode = country()
|
||||
countryCode = <CountryCode> country()?.toUpperCase()
|
||||
}
|
||||
if (this.isShortCode(str, countryCode?.toUpperCase())) {
|
||||
if (this.isShortCode(str, countryCode)) {
|
||||
return str
|
||||
}
|
||||
return parsePhoneNumberFromString(
|
||||
str,
|
||||
countryCode?.toUpperCase() as any
|
||||
countryCode
|
||||
)?.formatInternational()
|
||||
}
|
||||
|
||||
|
|
|
@ -10,49 +10,49 @@ import MarkdownUtils from "../../../Utils/MarkdownUtils"
|
|||
export default class WikidataValidator extends Validator {
|
||||
public static readonly _searchCache = new Map<string, Promise<WikidataResponse[]>>()
|
||||
|
||||
public static docs = new Combine([
|
||||
new Title("Helper arguments"),
|
||||
new Table(
|
||||
public static docs = [
|
||||
"### Helper arguments",
|
||||
MarkdownUtils.table(
|
||||
["name", "doc"],
|
||||
[
|
||||
[
|
||||
"key",
|
||||
"the value of this tag will initialize search (default: name). This can be a ';'-separated list in which case every key will be inspected. The non-null value will be used as search",
|
||||
"the value of this tag will initialize search (default: name). This can be a ';'-separated list in which case every key will be inspected. The non-null value will be used as search"
|
||||
],
|
||||
[
|
||||
"options",
|
||||
new Combine([
|
||||
"A JSON-object of type `{ removePrefixes: string[], removePostfixes: string[] }`.",
|
||||
MarkdownUtils.table(
|
||||
["subarg", "doc"],
|
||||
[
|
||||
[
|
||||
"removePrefixes",
|
||||
"remove these snippets of text from the start of the passed string to search. This is either a list OR a hash of languages to a list. The individual strings are interpreted as case ignoring regexes",
|
||||
],
|
||||
[
|
||||
"removePostfixes",
|
||||
"remove these snippets of text from the end of the passed string to search. This is either a list OR a hash of languages to a list. The individual strings are interpreted as case ignoring regexes.",
|
||||
],
|
||||
[
|
||||
"instanceOf",
|
||||
"A list of Q-identifier which indicates that the search results _must_ be an entity of this type, e.g. [`Q5`](https://www.wikidata.org/wiki/Q5) for humans",
|
||||
],
|
||||
[
|
||||
"notInstanceof",
|
||||
"A list of Q-identifiers which indicates that the search results _must not_ be an entity of this type, e.g. [`Q79007`](https://www.wikidata.org/wiki/Q79007) to filter away all streets from the search results",
|
||||
],
|
||||
[
|
||||
"multiple",
|
||||
"If 'yes' or 'true', will allow to select multiple values at once",
|
||||
],
|
||||
]
|
||||
),
|
||||
]),
|
||||
],
|
||||
"A JSON-object of type `{ removePrefixes: Record<string, string[]>, removePostfixes: Record<string, string[]>, ... }`. See the more detailed explanation below"
|
||||
]
|
||||
]
|
||||
),
|
||||
new Title("Example usage"),
|
||||
"#### Suboptions",
|
||||
MarkdownUtils.table(
|
||||
["subarg", "doc"],
|
||||
[
|
||||
[
|
||||
"removePrefixes",
|
||||
"remove these snippets of text from the start of the passed string to search. This is either a list OR a hash of languages to a list. The individual strings are interpreted as case ignoring regexes"
|
||||
],
|
||||
[
|
||||
"removePostfixes",
|
||||
"remove these snippets of text from the end of the passed string to search. This is either a list OR a hash of languages to a list. The individual strings are interpreted as case ignoring regexes."
|
||||
],
|
||||
[
|
||||
"instanceOf",
|
||||
"A list of Q-identifier which indicates that the search results _must_ be an entity of this type, e.g. [`Q5`](https://www.wikidata.org/wiki/Q5) for humans"
|
||||
],
|
||||
[
|
||||
"notInstanceof",
|
||||
"A list of Q-identifiers which indicates that the search results _must not_ be an entity of this type, e.g. [`Q79007`](https://www.wikidata.org/wiki/Q79007) to filter away all streets from the search results"
|
||||
],
|
||||
[
|
||||
"multiple",
|
||||
"If 'yes' or 'true', will allow to select multiple values at once"
|
||||
]
|
||||
]
|
||||
)
|
||||
].join("\n\n")
|
||||
private static readonly docsExampleUsage: string = "### Example usage\n\n" +
|
||||
`The following is the 'freeform'-part of a layer config which will trigger a search for the wikidata item corresponding with the name of the selected feature. It will also remove '-street', '-square', ... if found at the end of the name
|
||||
|
||||
\`\`\`json
|
||||
|
@ -94,10 +94,11 @@ Another example is to search for species and trees:
|
|||
}]
|
||||
}
|
||||
\`\`\`
|
||||
`,
|
||||
])
|
||||
`
|
||||
|
||||
|
||||
constructor() {
|
||||
super("wikidata", new Combine(["A wikidata identifier, e.g. Q42.", WikidataValidator.docs]))
|
||||
super("wikidata", "A wikidata identifier, e.g. Q42.\n\n" + WikidataValidator.docs + WikidataValidator.docsExampleUsage)
|
||||
}
|
||||
|
||||
public isValid(str): boolean {
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
{#if $reviews === undefined}
|
||||
<Loading />
|
||||
{:else}
|
||||
<div class="flex flex-col">
|
||||
|
||||
{#if $reviews?.length > 0}
|
||||
<div class="flex flex-col gap-y-1" on:keypress={(e) => console.log("Got keypress", e)}>
|
||||
{#each $reviews as review (review.sub)}
|
||||
|
@ -61,9 +63,11 @@
|
|||
>
|
||||
<Tr t={t.reviews_bug} />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex justify-end">
|
||||
<Mangrove_logo class="h-6 w-6 shrink-0 p-1" />
|
||||
<Tr cls="text-sm subtle" t={t.attribution} />
|
||||
</div>
|
||||
|
||||
</LoginToggle>
|
||||
|
|
|
@ -93,6 +93,23 @@
|
|||
})
|
||||
})
|
||||
}
|
||||
{
|
||||
services.push({
|
||||
name: Constants.panoramax.url,
|
||||
status: testDownload(Constants.panoramax.url + "/api").mapD((result) => {
|
||||
if (result["success"]?.stac_version === "1.0.0") {
|
||||
return "online"
|
||||
}
|
||||
if (result["error"]) {
|
||||
return "offline"
|
||||
} else {
|
||||
return "degraded"
|
||||
}
|
||||
}),
|
||||
message: simpleMessage(testDownload(Constants.panoramax.url + "/api"))
|
||||
|
||||
})
|
||||
}
|
||||
{
|
||||
services.push({
|
||||
name: Constants.GeoIpServer,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue