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
				
			
		| 
						 | 
				
			
			@ -256,7 +256,7 @@ export default class UserRelatedState {
 | 
			
		|||
            _theme: layout?.id,
 | 
			
		||||
            _backend: this.osmConnection.Backend(),
 | 
			
		||||
            _applicationOpened: new Date().toISOString(),
 | 
			
		||||
            _supports_sharing: window.navigator.share ? "yes" : "no"
 | 
			
		||||
            _supports_sharing: "yes" // TODO window.navigator.share ? "yes" : "no"
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        for (const key in Constants.userJourney) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,38 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="374px" height="365px" viewBox="0 0 374 365" version="1.1">
 | 
			
		||||
  <g id="surface1">
 | 
			
		||||
    <path style="fill:none;stroke-width:2.438635;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:4;" d="M 19.212394 278.175203 L 7.243369 283.695664 L 19.18221 289.202531 " transform="matrix(18.635995,0,0,18.679091,-62.085051,-5111.07542)"/>
 | 
			
		||||
    <path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 145.808594 188.101562 C 145.808594 228.460938 113.167969 261.175781 72.902344 261.175781 C 32.640625 261.175781 0 228.460938 0 188.101562 C 0 147.746094 32.640625 115.03125 72.902344 115.03125 C 113.167969 115.03125 145.808594 147.746094 145.808594 188.101562 Z M 145.808594 188.101562 "/>
 | 
			
		||||
    <path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 374 291.453125 C 374 331.8125 341.359375 364.527344 301.097656 364.527344 C 260.832031 364.527344 228.191406 331.8125 228.191406 291.453125 C 228.191406 251.097656 260.832031 218.382812 301.097656 218.382812 C 341.359375 218.382812 374 251.097656 374 291.453125 Z M 374 291.453125 "/>
 | 
			
		||||
    <path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 374 73.546875 C 374 113.902344 341.359375 146.617188 301.097656 146.617188 C 260.832031 146.617188 228.191406 113.902344 228.191406 73.546875 C 228.191406 33.1875 260.832031 0.472656 301.097656 0.472656 C 341.359375 0.472656 374 33.1875 374 73.546875 Z M 374 73.546875 "/>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
   width="374px"
 | 
			
		||||
   height="365px"
 | 
			
		||||
   viewBox="0 0 374 365"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg11"
 | 
			
		||||
   sodipodi:docname="share.svg"
 | 
			
		||||
   inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs15" />
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="namedview13"
 | 
			
		||||
     pagecolor="#505050"
 | 
			
		||||
     bordercolor="#eeeeee"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     inkscape:pageshadow="0"
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pagecheckerboard="0"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     inkscape:zoom="2.0958904"
 | 
			
		||||
     inkscape:cx="187.03268"
 | 
			
		||||
     inkscape:cy="182.5"
 | 
			
		||||
     inkscape:window-width="1920"
 | 
			
		||||
     inkscape:window-height="995"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="0"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     inkscape:current-layer="svg11" />
 | 
			
		||||
  <path
 | 
			
		||||
     id="path2"
 | 
			
		||||
     style="color:#000000;fill:#000000;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
 | 
			
		||||
     d="M 301.09766 0.47265625 C 260.83203 0.47265625 228.19141 33.1875 228.19141 73.546875 C 228.19141 79.329826 228.8815 84.948384 230.14844 90.34375 L 126.28711 138.35938 C 112.97544 124.01509 93.990177 115.03125 72.902344 115.03125 C 32.640625 115.03125 0 147.74609 0 188.10156 C -9.4739031e-15 228.46094 32.640625 261.17578 72.902344 261.17578 C 93.990661 261.17578 112.97735 252.19308 126.28906 237.84766 L 228.48438 285.09375 C 228.30377 287.19139 228.19141 289.30857 228.19141 291.45312 C 228.19141 331.8125 260.83203 364.52734 301.09766 364.52734 C 341.35937 364.52734 374 331.8125 374 291.45312 C 374 251.09766 341.35937 218.38281 301.09766 218.38281 C 279.27697 218.38281 259.71055 228.00393 246.34961 243.22852 L 145.3125 196.51562 C 145.62871 193.75286 145.80859 190.94925 145.80859 188.10156 C 145.80859 185.2553 145.62846 182.45285 145.3125 179.69141 L 254.10547 129.39648 C 266.79684 140.13431 283.18811 146.61719 301.09766 146.61719 C 341.35937 146.61719 374 113.90234 374 73.546875 C 374 33.1875 341.35937 0.47265625 301.09766 0.47265625 z " />
 | 
			
		||||
</svg>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										32
									
								
								index.css
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								index.css
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -34,7 +34,7 @@
 | 
			
		|||
    --interactive-foreground: black;
 | 
			
		||||
    --interactive-contrast: #ff00ff;
 | 
			
		||||
 | 
			
		||||
    --button-background: #737373;
 | 
			
		||||
    --button-background: black;
 | 
			
		||||
    --button-foreground: white;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +172,6 @@ button.disabled:hover {
 | 
			
		|||
    color: unset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
button:hover {
 | 
			
		||||
    border: 2px solid var(--catch-detail-color-contrast);
 | 
			
		||||
    background-color: var(--catch-detail-color);
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +183,6 @@ button:hover img {
 | 
			
		|||
    border-radius: 100rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
button {
 | 
			
		||||
    display: inline-flex;
 | 
			
		||||
    line-height: 1.25rem;
 | 
			
		||||
| 
						 | 
				
			
			@ -319,6 +317,34 @@ label.checked {
 | 
			
		|||
    border: 2px solid var(--foreground-color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.active-links a{
 | 
			
		||||
    /*
 | 
			
		||||
    * Let a 'link' mimick a secondary button, but not entirely
 | 
			
		||||
    */
 | 
			
		||||
    display: block;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    padding: 3px;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    background: var(--low-interaction-background);
 | 
			
		||||
    color: var(--low-interaction-foreground);
 | 
			
		||||
    border: 2px solid var(--interactive-background);
 | 
			
		||||
    border-radius: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.active-links a:hover {
 | 
			
		||||
    background-color: var(--interactive-background);
 | 
			
		||||
    color: var(--catch-detail-foregroundcolor);
 | 
			
		||||
    border-color: var(--catch-detail-color-contrast);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.active-links a:hover svg path {
 | 
			
		||||
    fill: var(--catch-detail-foregroundcolor) !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/************************* OTHER CATEGORIES ********************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "mapcomplete",
 | 
			
		||||
  "version": "0.25.1",
 | 
			
		||||
  "version": "0.30.5",
 | 
			
		||||
  "lockfileVersion": 2,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "packages": {
 | 
			
		||||
    "": {
 | 
			
		||||
      "name": "mapcomplete",
 | 
			
		||||
      "version": "0.25.1",
 | 
			
		||||
      "version": "0.30.5",
 | 
			
		||||
      "license": "GPL-3.0-or-later",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@onsvisual/svelte-maps": "^1.1.6",
 | 
			
		||||
| 
						 | 
				
			
			@ -4465,9 +4465,9 @@
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/caniuse-lite": {
 | 
			
		||||
      "version": "1.0.30001445",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001445.tgz",
 | 
			
		||||
      "integrity": "sha512-8sdQIdMztYmzfTMO6KfLny878Ln9c2M0fc7EH60IjlP4Dc4PiCy7K2Vl3ITmWgOyPgVQKa5x+UP/KqFsxj4mBg==",
 | 
			
		||||
      "version": "1.0.30001486",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001486.tgz",
 | 
			
		||||
      "integrity": "sha512-uv7/gXuHi10Whlj0pp5q/tsK/32J2QSqVRKQhs2j8VsDCjgyruAh/eEXHF822VqO9yT6iZKw3nRwZRSPBE9OQg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "funding": [
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -4477,6 +4477,10 @@
 | 
			
		|||
        {
 | 
			
		||||
          "type": "tidelift",
 | 
			
		||||
          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "github",
 | 
			
		||||
          "url": "https://github.com/sponsors/ai"
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -15387,9 +15391,9 @@
 | 
			
		|||
      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
 | 
			
		||||
    },
 | 
			
		||||
    "caniuse-lite": {
 | 
			
		||||
      "version": "1.0.30001445",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001445.tgz",
 | 
			
		||||
      "integrity": "sha512-8sdQIdMztYmzfTMO6KfLny878Ln9c2M0fc7EH60IjlP4Dc4PiCy7K2Vl3ITmWgOyPgVQKa5x+UP/KqFsxj4mBg==",
 | 
			
		||||
      "version": "1.0.30001486",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001486.tgz",
 | 
			
		||||
      "integrity": "sha512-uv7/gXuHi10Whlj0pp5q/tsK/32J2QSqVRKQhs2j8VsDCjgyruAh/eEXHF822VqO9yT6iZKw3nRwZRSPBE9OQg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "canvg": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,7 @@
 | 
			
		|||
    "prepare-deploy": "npm run generate:service-worker && ./scripts/build.sh",
 | 
			
		||||
    "format": "npx prettier --write --svelte-bracket-new-line=false --html-whitespace-sensitivity=ignore '**/*.ts' '**/*.svelte'",
 | 
			
		||||
    "clean:tests": "(find . -type f -name \"*.doctest.ts\" | xargs -r rm)",
 | 
			
		||||
    "clean": "rm -rf .cache/ && (find *.html | grep -v \"^\\(404\\|index\\|land\\|test\\|preferences\\|customGenerator\\|professional\\|automaton\\|import_helper\\|import_viewer\\|theme\\).html\" | xargs -r rm) && (ls | grep \"^index_[a-zA-Z_-]\\+\\.ts$\" | xargs -r rm) && (ls | grep \".*.webmanifest$\" | grep -v \"manifest.webmanifest\" | xargs -r rm)",
 | 
			
		||||
    "clean": "rm -rf .cache/ && (find *.html | grep -v \"^\\(404\\|index\\|land\\|test\\|preferences\\|customGenerator\\|professional\\|automaton\\|import_helper\\|import_viewer\\|theme\\|style_test\\).html\" | xargs -r rm) && (ls | grep \"^index_[a-zA-Z_-]\\+\\.ts$\" | xargs -r rm) && (ls | grep \".*.webmanifest$\" | grep -v \"manifest.webmanifest\" | xargs -r rm)",
 | 
			
		||||
    "generate:dependency-graph": "node_modules/.bin/depcruise --exclude \"^node_modules\" --output-type dot Logic/State/MapState.ts > dependencies.dot && dot dependencies.dot -T svg -o dependencies.svg && rm dependencies.dot",
 | 
			
		||||
    "weblate-add-upstream": "git remote add weblate-github git@github.com:weblate/MapComplete.git && git remote add weblate-hosted-core https://hosted.weblate.org/git/mapcomplete/core/ && git remote add weblate-hosted-layers https://hosted.weblate.org/git/mapcomplete/layers/",
 | 
			
		||||
    "weblate-merge": "git remote update weblate-github; git merge weblate-github/weblate-mapcomplete-core weblate-github/weblate-mapcomplete-layers weblate-github/weblate-mapcomplete-layer-translations",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -825,11 +825,6 @@ video {
 | 
			
		|||
  margin-bottom: 0.75rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx-2 {
 | 
			
		||||
  margin-left: 0.5rem;
 | 
			
		||||
  margin-right: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mr-2 {
 | 
			
		||||
  margin-right: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1024,6 +1019,10 @@ video {
 | 
			
		|||
  height: fit-content;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.h-7 {
 | 
			
		||||
  height: 1.75rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.h-11 {
 | 
			
		||||
  height: 2.75rem;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,8 +1047,8 @@ video {
 | 
			
		|||
  height: 20rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.max-h-32 {
 | 
			
		||||
  max-height: 8rem;
 | 
			
		||||
.max-h-12 {
 | 
			
		||||
  max-height: 3rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.max-h-7 {
 | 
			
		||||
| 
						 | 
				
			
			@ -1060,14 +1059,6 @@ video {
 | 
			
		|||
  max-height: 6rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.max-h-12 {
 | 
			
		||||
  max-height: 3rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.min-h-\[8rem\] {
 | 
			
		||||
  min-height: 8rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.w-full {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1114,6 +1105,10 @@ video {
 | 
			
		|||
  width: fit-content;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.w-7 {
 | 
			
		||||
  width: 1.75rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.w-11 {
 | 
			
		||||
  width: 2.75rem;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1290,6 +1285,20 @@ video {
 | 
			
		|||
  row-gap: 0.25rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gap-x-0\.5 {
 | 
			
		||||
  -webkit-column-gap: 0.125rem;
 | 
			
		||||
          column-gap: 0.125rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gap-x-0 {
 | 
			
		||||
  -webkit-column-gap: 0px;
 | 
			
		||||
          column-gap: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gap-y-2 {
 | 
			
		||||
  row-gap: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.self-start {
 | 
			
		||||
  align-self: flex-start;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1533,6 +1542,11 @@ video {
 | 
			
		|||
  padding-right: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.px-3 {
 | 
			
		||||
  padding-left: 0.75rem;
 | 
			
		||||
  padding-right: 0.75rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.px-4 {
 | 
			
		||||
  padding-left: 1rem;
 | 
			
		||||
  padding-right: 1rem;
 | 
			
		||||
| 
						 | 
				
			
			@ -1702,11 +1716,6 @@ video {
 | 
			
		|||
  color: rgb(22 163 74 / var(--tw-text-opacity));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-\[\#999\] {
 | 
			
		||||
  --tw-text-opacity: 1;
 | 
			
		||||
  color: rgb(153 153 153 / var(--tw-text-opacity));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-white {
 | 
			
		||||
  --tw-text-opacity: 1;
 | 
			
		||||
  color: rgb(255 255 255 / var(--tw-text-opacity));
 | 
			
		||||
| 
						 | 
				
			
			@ -1761,6 +1770,12 @@ video {
 | 
			
		|||
          filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.drop-shadow-md {
 | 
			
		||||
  --tw-drop-shadow: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06));
 | 
			
		||||
  -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
 | 
			
		||||
          filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grayscale {
 | 
			
		||||
  --tw-grayscale: grayscale(100%);
 | 
			
		||||
  -webkit-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
 | 
			
		||||
| 
						 | 
				
			
			@ -1845,7 +1860,7 @@ video {
 | 
			
		|||
  --interactive-background: #dddddd;
 | 
			
		||||
  --interactive-foreground: black;
 | 
			
		||||
  --interactive-contrast: #ff00ff;
 | 
			
		||||
  --button-background: #737373;
 | 
			
		||||
  --button-background: black;
 | 
			
		||||
  --button-foreground: white;
 | 
			
		||||
  /**
 | 
			
		||||
     * Base colour of interactive elements, mainly the 'subtle button'
 | 
			
		||||
| 
						 | 
				
			
			@ -2120,6 +2135,31 @@ label.checked {
 | 
			
		|||
  border: 2px solid var(--foreground-color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.active-links a{
 | 
			
		||||
  /*
 | 
			
		||||
    * Let a 'link' mimick a secondary button, but not entirely
 | 
			
		||||
    */
 | 
			
		||||
  display: block;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  padding: 3px;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  background: var(--low-interaction-background);
 | 
			
		||||
  color: var(--low-interaction-foreground);
 | 
			
		||||
  border: 2px solid var(--interactive-background);
 | 
			
		||||
  border-radius: 0.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.active-links a:hover {
 | 
			
		||||
  background-color: var(--interactive-background);
 | 
			
		||||
  color: var(--catch-detail-foregroundcolor);
 | 
			
		||||
  border-color: var(--catch-detail-color-contrast);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.active-links a:hover svg path {
 | 
			
		||||
  fill: var(--catch-detail-foregroundcolor) !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/************************* OTHER CATEGORIES ********************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue