forked from MapComplete/MapComplete
More style tweaks
This commit is contained in:
parent
63a6fb2dd5
commit
07f9f1bb15
18 changed files with 304 additions and 188 deletions
34
UI/Base/ShareButton.svelte
Normal file
34
UI/Base/ShareButton.svelte
Normal file
|
@ -0,0 +1,34 @@
|
|||
<script lang="ts">
|
||||
|
||||
import ToSvelte from "./ToSvelte.svelte";
|
||||
import Svg from "../../Svg";
|
||||
|
||||
export let generateShareData: () => {
|
||||
text: string
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
function share(){
|
||||
alert("Sharing...")
|
||||
if (!navigator.share) {
|
||||
console.log("web share not supported")
|
||||
return;
|
||||
}
|
||||
navigator
|
||||
.share(this._shareData())
|
||||
.then(() => {
|
||||
console.log("Thanks for sharing!")
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Couldn't share because of`, err.message)
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<button on:click={share} class="secondary w-8 h-8 m-0 p-0">
|
||||
<slot name="content">
|
||||
<ToSvelte construct={Svg.share_svg().SetClass("w-7 h-7 p-1")}/>
|
||||
</slot>
|
||||
</button>
|
|
@ -6,103 +6,122 @@ import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
|
|||
import ToSvelte from "../Base/ToSvelte.svelte";
|
||||
import Checkbox from "../Base/Checkbox.svelte";
|
||||
import FilterConfig from "../../Models/ThemeConfig/FilterConfig";
|
||||
import type { Writable } from "svelte/store";
|
||||
import type {Writable} from "svelte/store";
|
||||
import If from "../Base/If.svelte";
|
||||
import Dropdown from "../Base/Dropdown.svelte";
|
||||
import { onDestroy } from "svelte";
|
||||
import { ImmutableStore, Store } from "../../Logic/UIEventSource";
|
||||
import {onDestroy} from "svelte";
|
||||
import {ImmutableStore, Store} from "../../Logic/UIEventSource";
|
||||
import FilterviewWithFields from "./FilterviewWithFields.svelte";
|
||||
import Tr from "../Base/Tr.svelte";
|
||||
import Translations from "../i18n/Translations";
|
||||
|
||||
export let filteredLayer: FilteredLayer;
|
||||
export let highlightedLayer: Store<string | undefined> = new ImmutableStore(undefined);
|
||||
export let highlightedLayer: Store<string | undefined> = new ImmutableStore(undefined);
|
||||
export let zoomlevel: Store<number> = new ImmutableStore(22);
|
||||
let layer: LayerConfig = filteredLayer.layerDef;
|
||||
let isDisplayed: boolean = filteredLayer.isDisplayed.data;
|
||||
onDestroy(filteredLayer.isDisplayed.addCallbackAndRunD(d => {
|
||||
isDisplayed = d;
|
||||
return false;
|
||||
isDisplayed = d;
|
||||
return false;
|
||||
}));
|
||||
|
||||
/**
|
||||
* Gets a UIEventSource as boolean for the given option, to be used with a checkbox
|
||||
*/
|
||||
function getBooleanStateFor(option: FilterConfig): Writable<boolean> {
|
||||
const state = filteredLayer.appliedFilters.get(option.id);
|
||||
return state.sync(f => f === 0, [], (b) => b ? 0 : undefined);
|
||||
const state = filteredLayer.appliedFilters.get(option.id);
|
||||
return state.sync(f => f === 0, [], (b) => b ? 0 : undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a UIEventSource as number for the given option, to be used with a dropdown or radiobutton
|
||||
*/
|
||||
function getStateFor(option: FilterConfig): Writable<number> {
|
||||
return filteredLayer.appliedFilters.get(option.id);
|
||||
return filteredLayer.appliedFilters.get(option.id);
|
||||
}
|
||||
|
||||
let mainElem: HTMLElement;
|
||||
$: onDestroy(
|
||||
highlightedLayer.addCallbackAndRun(highlightedLayer => {
|
||||
if (highlightedLayer === filteredLayer.layerDef.id) {
|
||||
mainElem?.classList?.add("glowing-shadow");
|
||||
} else {
|
||||
mainElem?.classList?.remove("glowing-shadow");
|
||||
}
|
||||
})
|
||||
highlightedLayer.addCallbackAndRun(highlightedLayer => {
|
||||
if (highlightedLayer === filteredLayer.layerDef.id) {
|
||||
mainElem?.classList?.add("glowing-shadow");
|
||||
} else {
|
||||
mainElem?.classList?.remove("glowing-shadow");
|
||||
}
|
||||
})
|
||||
);
|
||||
</script>
|
||||
{#if filteredLayer.layerDef.name}
|
||||
<div bind:this={mainElem}>
|
||||
<label class="flex gap-1">
|
||||
<Checkbox selected={filteredLayer.isDisplayed} />
|
||||
<If condition={filteredLayer.isDisplayed}>
|
||||
<ToSvelte construct={() => layer.defaultIcon()?.SetClass("block h-6 w-6")}></ToSvelte>
|
||||
<ToSvelte slot="else" construct={() => layer.defaultIcon()?.SetClass("block h-6 w-6 opacity-50")}></ToSvelte>
|
||||
</If>
|
||||
<div bind:this={mainElem}>
|
||||
<label class="flex gap-1">
|
||||
<Checkbox selected={filteredLayer.isDisplayed}/>
|
||||
<If condition={filteredLayer.isDisplayed}>
|
||||
<ToSvelte
|
||||
construct={() => layer.defaultIcon()?.SetClass("block h-6 w-6 no-image-background")}></ToSvelte>
|
||||
<ToSvelte slot="else"
|
||||
construct={() => layer.defaultIcon()?.SetClass("block h-6 w-6 no-image-background opacity-50")}></ToSvelte>
|
||||
</If>
|
||||
|
||||
{filteredLayer.layerDef.name}
|
||||
{filteredLayer.layerDef.name}
|
||||
|
||||
{#if $zoomlevel < layer.minzoom}
|
||||
{#if $zoomlevel < layer.minzoom}
|
||||
<span class="alert">
|
||||
<Tr t={Translations.t.general.layerSelection.zoomInToSeeThisLayer} />
|
||||
<Tr t={Translations.t.general.layerSelection.zoomInToSeeThisLayer}/>
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
</label>
|
||||
<If condition={filteredLayer.isDisplayed}>
|
||||
<div id="subfilters" class="flex flex-col gap-y-1 mb-4 ml-4">
|
||||
{#each filteredLayer.layerDef.filters as filter}
|
||||
<div>
|
||||
|
||||
<!-- There are three (and a half) modes of filters: a single checkbox, a radio button/dropdown or with fields -->
|
||||
{#if filter.options.length === 1 && filter.options[0].fields.length === 0}
|
||||
<label>
|
||||
<Checkbox selected={getBooleanStateFor(filter)} />
|
||||
{filter.options[0].question}
|
||||
</label>
|
||||
{/if}
|
||||
|
||||
{#if filter.options.length === 1 && filter.options[0].fields.length > 0}
|
||||
<FilterviewWithFields id={filter.id} filteredLayer={filteredLayer}
|
||||
option={filter.options[0]}></FilterviewWithFields>
|
||||
</label>
|
||||
|
||||
{/if}
|
||||
|
||||
{#if filter.options.length > 1}
|
||||
<Dropdown value={getStateFor(filter)}>
|
||||
{#each filter.options as option, i}
|
||||
<option value={i}>
|
||||
{ option.question}
|
||||
</option>
|
||||
<If condition={filteredLayer.isDisplayed}>
|
||||
<div id="subfilters" class="flex flex-col gap-y-1 mb-4 ml-4">
|
||||
{#each filteredLayer.layerDef.filters as filter}
|
||||
<div>
|
||||
|
||||
<!-- There are three (and a half) modes of filters: a single checkbox, a radio button/dropdown or with searchable fields -->
|
||||
{#if filter.options.length === 1 && filter.options[0].fields.length === 0}
|
||||
<label>
|
||||
<Checkbox selected={getBooleanStateFor(filter)}/>
|
||||
{filter.options[0].question}
|
||||
</label>
|
||||
{/if}
|
||||
|
||||
{#if filter.options.length === 1 && filter.options[0].fields.length > 0}
|
||||
<FilterviewWithFields id={filter.id} filteredLayer={filteredLayer}
|
||||
option={filter.options[0]}></FilterviewWithFields>
|
||||
|
||||
{/if}
|
||||
|
||||
{#if filter.options.length > 1}
|
||||
<Dropdown value={getStateFor(filter)}>
|
||||
{#each filter.options as option, i}
|
||||
<option value={i}>
|
||||
{ option.question}
|
||||
</option>
|
||||
{/each}
|
||||
</Dropdown>
|
||||
{/if}
|
||||
|
||||
|
||||
</div>
|
||||
{/each}
|
||||
</Dropdown>
|
||||
{/if}
|
||||
</div>
|
||||
</If>
|
||||
|
||||
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</If>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
||||
:global(.no-image-background * img) {
|
||||
background: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:global(.no-image-background * svg) {
|
||||
background: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
{#if _tags._deleted === "yes"}
|
||||
<Tr t={ Translations.t.delete.isDeleted}/>
|
||||
{:else}
|
||||
<div class="flex border-b-2 border-black shadow justify-between items-center">
|
||||
<div class="flex border-b-2 border-black drop-shadow-md justify-between items-center low-interaction px-3 active-links">
|
||||
<div class="flex flex-col">
|
||||
|
||||
<!-- Title element-->
|
||||
|
@ -40,12 +40,12 @@
|
|||
{layer}></TagRenderingAnswer>
|
||||
</h3>
|
||||
|
||||
<div class="flex flex-row flex-wrap pt-0.5 sm:pt-1 items-center mr-2">
|
||||
<div class="flex flex-row flex-wrap pt-0.5 sm:pt-1 items-center mr-2 gap-x-0.5 p-1">
|
||||
{#each layer.titleIcons as titleIconConfig}
|
||||
{#if (titleIconConfig.condition?.matchesProperties(_tags) ?? true) && (titleIconConfig.metacondition?.matchesProperties({..._metatags, ..._tags}) ?? true) && titleIconConfig.IsKnown(_tags)}
|
||||
<div class="w-8 h-8">
|
||||
<div class="w-8 h-8 flex items-center">
|
||||
<TagRenderingAnswer config={titleIconConfig} {tags} {selectedElement} {state}
|
||||
{layer}></TagRenderingAnswer>
|
||||
{layer} extraClasses="h-full justify-center" ></TagRenderingAnswer>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -55,3 +55,7 @@
|
|||
<XCircleIcon class="w-8 h-8 cursor-pointer" on:click={() => state.selectedElement.setData(undefined)}/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
{#if _tags._deleted === "yes"}
|
||||
<Tr t={ Translations.t.delete.isDeleted}/>
|
||||
{:else}
|
||||
<div class="flex flex-col overflow-y-auto">
|
||||
<div class="flex flex-col overflow-y-auto p-1 px-2 gap-y-2">
|
||||
{#each layer.tagRenderings as config (config.id)}
|
||||
{#if (config.condition === undefined || config.condition.matchesProperties(_tags)) && (config.metacondition === undefined || config.metacondition.matchesProperties({..._tags, ..._metatags}))}
|
||||
{#if config.IsKnown(_tags)}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import BaseUIElement from "../BaseUIElement"
|
||||
|
||||
export default class ShareButton extends BaseUIElement {
|
||||
private _embedded: BaseUIElement
|
||||
private _shareData: () => { text: string; title: string; url: string }
|
||||
|
||||
constructor(
|
||||
embedded: BaseUIElement,
|
||||
generateShareData: () => {
|
||||
text: string
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
) {
|
||||
super()
|
||||
this._embedded = embedded
|
||||
this._shareData = generateShareData
|
||||
this.SetClass("share-button")
|
||||
}
|
||||
|
||||
protected InnerConstructElement(): HTMLElement {
|
||||
const e = document.createElement("button")
|
||||
e.type = "button"
|
||||
e.appendChild(this._embedded.ConstructElement())
|
||||
|
||||
e.addEventListener("click", () => {
|
||||
if (navigator.share) {
|
||||
navigator
|
||||
.share(this._shareData())
|
||||
.then(() => {
|
||||
console.log("Thanks for sharing!")
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Couldn't share because of`, err.message)
|
||||
})
|
||||
} else {
|
||||
console.log("web share not supported")
|
||||
}
|
||||
})
|
||||
|
||||
return e
|
||||
}
|
||||
}
|
|
@ -1,20 +1,20 @@
|
|||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import {Store, UIEventSource} from "../../Logic/UIEventSource"
|
||||
import Combine from "../Base/Combine"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Svg from "../../Svg"
|
||||
import { Tag } from "../../Logic/Tags/Tag"
|
||||
import {Tag} from "../../Logic/Tags/Tag"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import Toggle from "../Input/Toggle"
|
||||
import FileSelectorButton from "../Input/FileSelectorButton"
|
||||
import ImgurUploader from "../../Logic/ImageProviders/ImgurUploader"
|
||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import {FixedUiElement} from "../Base/FixedUiElement"
|
||||
import {VariableUiElement} from "../Base/VariableUIElement"
|
||||
import Loading from "../Base/Loading"
|
||||
import { LoginToggle } from "../Popup/LoginButton"
|
||||
import {LoginToggle} from "../Popup/LoginButton"
|
||||
import Constants from "../../Models/Constants"
|
||||
import { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import {SpecialVisualizationState} from "../SpecialVisualization"
|
||||
|
||||
export class ImageUploadFlow extends Toggle {
|
||||
private static readonly uploadCountsPerId = new Map<string, UIEventSource<number>>()
|
||||
|
@ -70,17 +70,22 @@ export class ImageUploadFlow extends Toggle {
|
|||
const label = new Combine([
|
||||
Svg.camera_plus_svg().SetClass("block w-12 h-12 p-1 text-4xl "),
|
||||
labelContent,
|
||||
])
|
||||
.SetClass(
|
||||
"p-2 border-4 border-detail rounded-full font-bold h-full align-middle w-full flex justify-center"
|
||||
)
|
||||
.SetStyle(" border-color: var(--foreground-color);")
|
||||
]).SetClass("w-full flex justify-center items-center")
|
||||
|
||||
const licenseStore = state?.osmConnection?.GetPreference(
|
||||
Constants.OsmPreferenceKeyPicturesLicense,
|
||||
"CC0"
|
||||
)
|
||||
|
||||
const fileSelector = new FileSelectorButton(label)
|
||||
const fileSelector = new FileSelectorButton(label, {
|
||||
acceptType: "image/*",
|
||||
allowMultiple: true,
|
||||
labelClasses: "rounded-full border-2 border-black font-bold"
|
||||
})
|
||||
/* fileSelector.SetClass(
|
||||
"p-2 border-4 border-detail rounded-full font-bold h-full align-middle w-full flex justify-center"
|
||||
)
|
||||
.SetStyle(" border-color: var(--foreground-color);")*/
|
||||
fileSelector.GetValue().addCallback((filelist) => {
|
||||
if (filelist === undefined || filelist.length === 0) {
|
||||
return
|
||||
|
@ -139,7 +144,7 @@ export class ImageUploadFlow extends Toggle {
|
|||
return new Loading(t.uploadingPicture).SetClass("alert")
|
||||
} else {
|
||||
return new Loading(
|
||||
t.uploadingMultiple.Subs({ count: "" + l })
|
||||
t.uploadingMultiple.Subs({count: "" + l})
|
||||
).SetClass("alert")
|
||||
}
|
||||
})
|
||||
|
@ -163,7 +168,7 @@ export class ImageUploadFlow extends Toggle {
|
|||
if (l == 1) {
|
||||
return t.uploadDone.Clone().SetClass("thanks block")
|
||||
}
|
||||
return t.uploadMultipleDone.Subs({ count: l }).SetClass("thanks block")
|
||||
return t.uploadMultipleDone.Subs({count: l}).SetClass("thanks block")
|
||||
})
|
||||
),
|
||||
|
||||
|
@ -172,7 +177,7 @@ export class ImageUploadFlow extends Toggle {
|
|||
Translations.t.image.respectPrivacy,
|
||||
new VariableUiElement(
|
||||
licenseStore.map((license) =>
|
||||
Translations.t.image.currentLicense.Subs({ license })
|
||||
Translations.t.image.currentLicense.Subs({license})
|
||||
)
|
||||
)
|
||||
.onClick(() => {
|
||||
|
|
|
@ -11,17 +11,20 @@ export default class FileSelectorButton extends InputElement<FileList> {
|
|||
private readonly _label: BaseUIElement
|
||||
private readonly _acceptType: string
|
||||
private readonly allowMultiple: boolean
|
||||
private readonly _labelClasses: string;
|
||||
|
||||
constructor(
|
||||
label: BaseUIElement,
|
||||
options?: {
|
||||
acceptType: "image/*" | string
|
||||
allowMultiple: true | boolean
|
||||
allowMultiple: true | boolean,
|
||||
labelClasses?: string
|
||||
}
|
||||
) {
|
||||
super()
|
||||
this._label = label
|
||||
this._acceptType = options?.acceptType ?? "image/*"
|
||||
this._labelClasses= options?.labelClasses ?? ""
|
||||
this.SetClass("block cursor-pointer")
|
||||
label.SetClass("cursor-pointer")
|
||||
this.allowMultiple = options?.allowMultiple ?? true
|
||||
|
@ -40,6 +43,7 @@ export default class FileSelectorButton extends InputElement<FileList> {
|
|||
const el = document.createElement("form")
|
||||
const label = document.createElement("label")
|
||||
label.appendChild(this._label.ConstructElement())
|
||||
label.classList.add(...this._labelClasses.split(" ").filter(t => t !== ""))
|
||||
el.appendChild(label)
|
||||
|
||||
const actualInputElement = document.createElement("input")
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
// The type changed -> reset some values
|
||||
validator = Validators.get(type)
|
||||
_value.setData(value.data ?? "")
|
||||
console.log("REseting validated input, _value is ", _value.data, validator?.getFeedback(_value.data, getCountry))
|
||||
feedback = feedback?.setData(validator?.getFeedback(_value.data, getCountry));
|
||||
_placeholder = placeholder ?? validator?.getPlaceholder() ?? type
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import ShareButton from "../BigComponents/ShareButton"
|
||||
import Svg from "../../Svg"
|
||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization";
|
||||
import SvelteUIElement from "../Base/SvelteUIElement";
|
||||
import ShareButton from "../Base/ShareButton.svelte";
|
||||
|
||||
export class ShareLinkViz implements SpecialVisualization {
|
||||
funcName = "share_link"
|
||||
|
@ -18,7 +19,6 @@ export class ShareLinkViz implements SpecialVisualization {
|
|||
]
|
||||
|
||||
public constr(state: SpecialVisualizationState, tagSource: UIEventSource<Record<string, string>>, args: string[]) {
|
||||
if (window.navigator.share) {
|
||||
const generateShareData = () => {
|
||||
const title = state?.layout?.title?.txt ?? "MapComplete"
|
||||
|
||||
|
@ -45,9 +45,7 @@ export class ShareLinkViz implements SpecialVisualization {
|
|||
}
|
||||
}
|
||||
|
||||
return new ShareButton(Svg.share_svg().SetClass("w-8 h-8"), generateShareData)
|
||||
} else {
|
||||
return new FixedUiElement("")
|
||||
}
|
||||
return new SvelteUIElement(ShareButton, {generateShareData})
|
||||
//return new ShareButton(Svg.share_svg().SetClass("w-8 h-8"), generateShareData)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
$:{
|
||||
trs = Utils.NoNull(config?.GetRenderValues(_tags));
|
||||
}
|
||||
export let extraClasses: string= ""
|
||||
let classes = ""
|
||||
$:classes = config?.classes?.join(" ") ?? "";
|
||||
</script>
|
||||
|
||||
{#if config !== undefined && (config?.condition === undefined || config.condition.matchesProperties(_tags))}
|
||||
<div class={"flex flex-col w-full "+classes}>
|
||||
<div class={"flex flex-col w-full "+classes+" "+extraClasses}>
|
||||
{#if trs.length === 1}
|
||||
<TagRenderingMapping mapping={trs[0]} {tags} {state} {selectedElement} {layer}></TagRenderingMapping>
|
||||
{/if}
|
||||
|
|
|
@ -71,25 +71,22 @@
|
|||
<div bind:this={htmlElem} class="">
|
||||
{#if config.question && $editingEnabled}
|
||||
{#if editMode}
|
||||
<div class="m-1 mx-2">
|
||||
<TagRenderingQuestion {config} {tags} {selectedElement} {state} {layer}>
|
||||
<button slot="cancel" class="secondary" on:click={() => {editMode = false}}>
|
||||
<Tr t={Translations.t.general.cancel}/>
|
||||
</button>
|
||||
<XCircleIcon slot="upper-right" class="w-8 h-8" on:click={() => {editMode = false}}/>
|
||||
</TagRenderingQuestion>
|
||||
</div>
|
||||
<TagRenderingQuestion {config} {tags} {selectedElement} {state} {layer}>
|
||||
<button slot="cancel" class="secondary" on:click={() => {editMode = false}}>
|
||||
<Tr t={Translations.t.general.cancel}/>
|
||||
</button>
|
||||
<XCircleIcon slot="upper-right" class="w-8 h-8" on:click={() => {editMode = false}}/>
|
||||
</TagRenderingQuestion>
|
||||
{:else}
|
||||
<div class="flex justify-between low-interaction items-center m-1 mx-2 p-1 px-2 rounded">
|
||||
<div class="flex justify-between low-interaction items-center rounded px-2">
|
||||
<TagRenderingAnswer {config} {tags} {selectedElement} {state} {layer}/>
|
||||
<button on:click={() => {editMode = true}} class="shrink-0 w-8 h-8 rounded-full p-1 secondary self-start">
|
||||
<button on:click={() => {editMode = true}}
|
||||
class="shrink-0 w-8 h-8 rounded-full p-1 secondary self-start">
|
||||
<PencilAltIcon/>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
{:else }
|
||||
<div class="m-1 p-1 px-2 mx-2">
|
||||
<TagRenderingAnswer {config} {tags} {selectedElement} {state} {layer}/>
|
||||
</div>
|
||||
<TagRenderingAnswer {config} {tags} {selectedElement} {state} {layer}/>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
export let layer: LayerConfig;
|
||||
|
||||
let feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined);
|
||||
feedback.addCallbackAndRunD(f => console.trace("Feedback is now", f.txt))
|
||||
|
||||
// Will be bound if a freeform is available
|
||||
let freeformInput = new UIEventSource<string>(tags?.[config.freeform?.key]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue