forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			110 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			110 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
<script lang="ts">
 | 
						|
  /**
 | 
						|
   * The FilterView shows the various options to enable/disable a single layer or to only show a subset of the data.
 | 
						|
   */
 | 
						|
  import type FilteredLayer from "../../Models/FilteredLayer"
 | 
						|
  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 If from "../Base/If.svelte"
 | 
						|
  import Dropdown from "../Base/Dropdown.svelte"
 | 
						|
  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 zoomlevel: Store<number> = new ImmutableStore(22)
 | 
						|
  let layer: LayerConfig = filteredLayer.layerDef
 | 
						|
  let isDisplayed: Store<boolean> = filteredLayer.isDisplayed
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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)
 | 
						|
    )
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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)
 | 
						|
  }
 | 
						|
 | 
						|
  let mainElem: HTMLElement
 | 
						|
  $: onDestroy(
 | 
						|
    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} class="mb-1.5">
 | 
						|
    <label class="no-image-background flex gap-1">
 | 
						|
      <Checkbox selected={isDisplayed} />
 | 
						|
      <If condition={filteredLayer.isDisplayed}>
 | 
						|
        <ToSvelte
 | 
						|
          construct={() => layer.defaultIcon()?.SetClass("block h-6 w-6 no-image-background")}
 | 
						|
        />
 | 
						|
        <ToSvelte
 | 
						|
          slot="else"
 | 
						|
          construct={() =>
 | 
						|
            layer.defaultIcon()?.SetClass("block h-6 w-6 no-image-background opacity-50")}
 | 
						|
        />
 | 
						|
      </If>
 | 
						|
 | 
						|
      {filteredLayer.layerDef.name}
 | 
						|
 | 
						|
      {#if $zoomlevel < layer.minzoom}
 | 
						|
        <span class="alert">
 | 
						|
          <Tr t={Translations.t.general.layerSelection.zoomInToSeeThisLayer} />
 | 
						|
        </span>
 | 
						|
      {/if}
 | 
						|
    </label>
 | 
						|
 | 
						|
    {#if $isDisplayed && filteredLayer.layerDef.filters?.length > 0}
 | 
						|
      <div id="subfilters" class="ml-4 flex flex-col gap-y-1">
 | 
						|
        {#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} option={filter.options[0]} />
 | 
						|
            {/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}
 | 
						|
      </div>
 | 
						|
    {/if}
 | 
						|
  </div>
 | 
						|
{/if}
 |