Studio: some UX tweaks
This commit is contained in:
parent
5e453d5cf1
commit
fb193123e0
29 changed files with 395 additions and 368 deletions
|
@ -1103,9 +1103,11 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
if (json.tagRenderings !== undefined && json.tagRenderings.length > 0) {
|
||||
new On("tagRendering", new Each(new ValidateTagRenderings(json)))
|
||||
if (json.title === undefined && json.source !== "special:library") {
|
||||
context.err(
|
||||
"This layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error."
|
||||
)
|
||||
context
|
||||
.enter("title")
|
||||
.err(
|
||||
"This layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error."
|
||||
)
|
||||
}
|
||||
if (json.title === null) {
|
||||
context.info(
|
||||
|
|
|
@ -210,7 +210,7 @@ export interface LayerConfigJson {
|
|||
minzoomVisible?: number
|
||||
|
||||
/**
|
||||
* question: What title should be shown on the infobox?
|
||||
* question: Edit the popup title
|
||||
* The title shown in a popup for elements of this layer.
|
||||
*
|
||||
* group: title
|
||||
|
@ -379,7 +379,7 @@ export interface LayerConfigJson {
|
|||
}[]
|
||||
|
||||
/**
|
||||
* question: Edit this tagRendering
|
||||
* question: Edit this way this attributed is displayed or queried
|
||||
*
|
||||
* A tag rendering is a block that either shows the known value or asks a question.
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Translatable } from "./Translatable"
|
|||
*/
|
||||
export interface MinimalTagRenderingConfigJson {
|
||||
/**
|
||||
* question: What value should be rendered?
|
||||
* question: What value should be shown (if no predifined option matches)?
|
||||
*
|
||||
* This piece of text will be shown in the infobox.
|
||||
* Note that "&LBRACEkey&RBRACE"-parts are substituted by the corresponding values of the element.
|
||||
|
@ -56,7 +56,7 @@ export interface TagRenderingConfigJson {
|
|||
*
|
||||
* Note that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`
|
||||
* type: rendered
|
||||
* ifunset: no text is rendered if no predefined options match
|
||||
* ifunset: No text is shown if no predefined options match.
|
||||
*/
|
||||
render?:
|
||||
| Translatable
|
||||
|
@ -67,7 +67,7 @@ export interface TagRenderingConfigJson {
|
|||
* An icon shown next to the rendering; typically shown pretty small
|
||||
* This is only shown next to the "render" value
|
||||
* Type: icon
|
||||
* ifunset: do not show an icon next to the "render"-value
|
||||
* ifunset: No additional icon is shown next to the always shown text
|
||||
*/
|
||||
icon?:
|
||||
| string
|
||||
|
|
|
@ -16,10 +16,10 @@ import SvelteUIElement from "../../UI/Base/SvelteUIElement"
|
|||
import DynamicMarker from "../../UI/Map/DynamicMarker.svelte"
|
||||
|
||||
export class IconConfig extends WithContextLoader {
|
||||
public static readonly defaultIcon = new IconConfig({ icon: "pin", color: "#ff9939" })
|
||||
public readonly icon: TagRenderingConfig
|
||||
public readonly color: TagRenderingConfig
|
||||
|
||||
public static readonly defaultIcon = new IconConfig({ icon: "pin", color: "#ff9939" })
|
||||
constructor(
|
||||
config: {
|
||||
icon: string | TagRenderingConfigJson
|
||||
|
@ -199,11 +199,13 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
public GetBaseIcon(tags?: Record<string, string>): BaseUIElement {
|
||||
return new SvelteUIElement(DynamicMarker, { config: this, tags: new ImmutableStore(tags) })
|
||||
}
|
||||
|
||||
public RenderIcon(
|
||||
tags: Store<Record<string, string>>,
|
||||
options?: {
|
||||
noSize?: false | boolean
|
||||
includeBadges?: true | boolean
|
||||
metatags?: Store<Record<string, string>>
|
||||
}
|
||||
): {
|
||||
html: BaseUIElement
|
||||
|
@ -225,16 +227,14 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
return Utils.SubstituteKeys(str, tags.data).replace(/{.*}/g, "")
|
||||
}
|
||||
|
||||
const iconSize = render(this.iconSize, "40,40").split(",")
|
||||
|
||||
const iconW = num(iconSize[0])
|
||||
let iconH = num(iconSize[1])
|
||||
|
||||
const anchor = render(this.anchor, "center")
|
||||
const mode = anchor?.trim()?.toLowerCase() ?? "center"
|
||||
// in MapLibre, the offset is relative to the _center_ of the object, with left = [-x, 0] and up = [0,-y]
|
||||
let anchorW = 0
|
||||
let anchorH = 0
|
||||
const anchor = render(this.anchor, "center")
|
||||
const mode = anchor?.trim()?.toLowerCase() ?? "center"
|
||||
const size = this.iconSize.GetRenderValue(tags.data).Subs(tags).txt ?? "[40,40]"
|
||||
const [iconW, iconH] = size.split(",").map((x) => num(x))
|
||||
|
||||
if (mode === "left") {
|
||||
anchorW = -iconW / 2
|
||||
}
|
||||
|
@ -254,15 +254,20 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
)
|
||||
let badges = undefined
|
||||
if (options?.includeBadges ?? true) {
|
||||
badges = this.GetBadges(tags)
|
||||
badges = this.GetBadges(tags, options.metatags)
|
||||
}
|
||||
const iconAndBadges = new Combine([icon, badges]).SetClass("block relative")
|
||||
|
||||
if (!options?.noSize) {
|
||||
iconAndBadges.SetStyle(`width: ${iconW}px; height: ${iconH}px`)
|
||||
} else {
|
||||
if (options?.noSize) {
|
||||
iconAndBadges.SetClass("w-full h-full")
|
||||
}
|
||||
tags.map((tags) => this.iconSize.GetRenderValue(tags).Subs(tags).txt ?? "[40,40]").map(
|
||||
(size) => {
|
||||
const [iconW, iconH] = size.split(",").map((x) => num(x))
|
||||
console.log("Setting size to", iconW, iconH)
|
||||
iconAndBadges.SetStyle(`width: ${iconW}px; height: ${iconH}px`)
|
||||
}
|
||||
)
|
||||
|
||||
const css = this.cssDef?.GetRenderValue(tags.data)?.txt
|
||||
const cssClasses = this.cssClasses?.GetRenderValue(tags.data)?.txt
|
||||
|
@ -293,41 +298,58 @@ export default class PointRenderingConfig extends WithContextLoader {
|
|||
}
|
||||
}
|
||||
|
||||
private GetBadges(tags: Store<Record<string, string>>): BaseUIElement {
|
||||
private GetBadges(
|
||||
tags: Store<Record<string, string>>,
|
||||
metaTags?: Store<Record<string, string>>
|
||||
): BaseUIElement {
|
||||
if (this.iconBadges.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
return new VariableUiElement(
|
||||
tags.map((tags) => {
|
||||
const badgeElements = this.iconBadges.map((badge) => {
|
||||
if (!badge.if.matchesProperties(tags)) {
|
||||
// Doesn't match...
|
||||
return undefined
|
||||
}
|
||||
tags.map(
|
||||
(tags) => {
|
||||
const badgeElements = this.iconBadges.map((badge) => {
|
||||
if (!badge.if.matchesProperties(tags)) {
|
||||
// Doesn't match...
|
||||
return undefined
|
||||
}
|
||||
const metaCondition = badge.then.metacondition
|
||||
if (
|
||||
metaCondition &&
|
||||
metaTags &&
|
||||
!metaCondition.matchesProperties(metaTags.data)
|
||||
) {
|
||||
// Doesn't match
|
||||
return undefined
|
||||
}
|
||||
|
||||
const htmlDefs = Utils.SubstituteKeys(
|
||||
badge.then.GetRenderValue(tags)?.txt,
|
||||
tags
|
||||
)
|
||||
if (htmlDefs.startsWith("<") && htmlDefs.endsWith(">")) {
|
||||
// This is probably an HTML-element
|
||||
return new FixedUiElement(Utils.SubstituteKeys(htmlDefs, tags))
|
||||
const htmlDefs = Utils.SubstituteKeys(
|
||||
badge.then.GetRenderValue(tags)?.txt,
|
||||
tags
|
||||
)
|
||||
if (htmlDefs.startsWith("<") && htmlDefs.endsWith(">")) {
|
||||
// This is probably an HTML-element
|
||||
return new FixedUiElement(Utils.SubstituteKeys(htmlDefs, tags))
|
||||
.SetStyle("width: 1.5rem")
|
||||
.SetClass("block")
|
||||
}
|
||||
const badgeElement = PointRenderingConfig.FromHtmlMulti(
|
||||
htmlDefs,
|
||||
"0",
|
||||
true
|
||||
)?.SetClass("block relative")
|
||||
if (badgeElement === undefined) {
|
||||
return undefined
|
||||
}
|
||||
return new Combine([badgeElement])
|
||||
.SetStyle("width: 1.5rem")
|
||||
.SetClass("block")
|
||||
}
|
||||
const badgeElement = PointRenderingConfig.FromHtmlMulti(
|
||||
htmlDefs,
|
||||
"0",
|
||||
true
|
||||
)?.SetClass("block relative")
|
||||
if (badgeElement === undefined) {
|
||||
return undefined
|
||||
}
|
||||
return new Combine([badgeElement]).SetStyle("width: 1.5rem").SetClass("block")
|
||||
})
|
||||
})
|
||||
|
||||
return new Combine(badgeElements).SetClass("inline-flex h-full")
|
||||
})
|
||||
return new Combine(badgeElements).SetClass("inline-flex h-full")
|
||||
},
|
||||
[metaTags]
|
||||
)
|
||||
).SetClass("absolute bottom-0 right-1/3 h-1/2 w-0")
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue