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}
 |