Skip to content

Commit

Permalink
migrate CEEI dashboard to svelte 5
Browse files Browse the repository at this point in the history
  • Loading branch information
JinIgarashi committed Dec 27, 2024
1 parent ed84015 commit f8c6733
Show file tree
Hide file tree
Showing 6 changed files with 397 additions and 353 deletions.
124 changes: 64 additions & 60 deletions sites/geohub/src/routes/(map)/dashboards/ceei/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<script lang="ts">
import DropdownSearch from './components/DropdownSearch.svelte';
import { page } from '$app/stores';
import { page } from '$app/state';
import { MapStyles } from '$lib/config/AppConfig';
import { HEADER_HEIGHT_CONTEXT_KEY, type HeaderHeightStore } from '$stores';
import { GeocodingControl } from '@maptiler/geocoding-control/maplibregl';
Expand Down Expand Up @@ -33,22 +31,27 @@
import * as topojson from 'topojson-client';
import { read, utils } from 'xlsx';
import type { PageData } from './$types';
import DropdownSearch from './components/DropdownSearch.svelte';
import LayerControl from './components/LayerControl.svelte';
import { layers as layerStore, mapPopup as popupStore, type Layer } from './stores';
import { computeCEEI, headerMapping, loadInitial } from './utils/layerHelper';
export let data: PageData;
interface Props {
data: PageData;
}
let { data }: Props = $props();
let drawerWidth = 355;
let map: Map;
let mapContainer: HTMLDivElement;
let popup: Popup;
let drawerWidth = $state(355);
let map: Map = $state();
let mapContainer: HTMLDivElement = $state();
let popup: Popup = $state();
let styles = MapStyles;
let baseCeeiJson: FeatureCollection;
let fullCountries;
let countriesList: { label: string; value: string }[];
let selectedCountryFilter = null;
let baseCeeiJson: FeatureCollection = $state();
let fullCountries = $state();
let countriesList: { label: string; value: string }[] = $state();
let selectedCountryFilter: string | null = $state(null);
const headerHeightStore: HeaderHeightStore = getContext(HEADER_HEIGHT_CONTEXT_KEY);
const mapStore = createMapStore();
Expand Down Expand Up @@ -139,7 +142,7 @@
};
};
$: {
$effect(() => {
let filter =
selectedCountryFilter === null ? undefined : ['==', 'Country', selectedCountryFilter];
$layerStore.forEach((l) => {
Expand Down Expand Up @@ -173,7 +176,7 @@
}
}
}
}
});
onMount(async () => {
let protocol = new pmtiles.Protocol();
Expand Down Expand Up @@ -206,7 +209,7 @@
const styleSwitcher = new MaplibreStyleSwitcherControl(MapStyles, {});
map.addControl(styleSwitcher, 'bottom-left');
const apiKey = $page.data.maptilerKey;
const apiKey = page.data.maptilerKey;
if (apiKey) {
const gc = new GeocodingControl({
apiKey: apiKey,
Expand Down Expand Up @@ -263,55 +266,56 @@
bind:marginTop={$headerHeightStore}
border="none"
>
<div
slot="content"
class="drawer-content m-0 px-4 pb-4 is-flex is-flex-direction-column is-gap-1"
>
<div class="is-flex is-flex-direction-column is-gap-1">
{#if $layerStore.length === 0}
<div
class="is-flex is-flex-direction-column is-align-items-center is-justify-content-center"
>
<Loader />
<div>Loading data...</div>
</div>
{:else}
<div class="field is-fullwidth">
<h2 class="title is-size-6 mt-4 mb-4">DASHBOARD</h2>
<h2 class="title is-size-4 mb-5">CEEI Dashboard</h2>
<p>
<b
>Developed with IBM through the <a
href="https://www.ibm.com/impact/initiatives/ibm-sustainability-accelerator"
>IBM Sustainability Accelerator</a
></b
>
</p>
<label class="label mt-4" for="country-filter">Filter map to a country</label>
<div class="is-fullwidth">
<DropdownSearch
items={countriesList}
on:select={(e) => {
selectedCountryFilter = e.detail === null ? null : e.detail.value;
}}
></DropdownSearch>
{#snippet content()}
<div class="drawer-content m-0 px-4 pb-4 is-flex is-flex-direction-column is-gap-1">
<div class="is-flex is-flex-direction-column is-gap-1">
{#if $layerStore.length === 0}
<div
class="is-flex is-flex-direction-column is-align-items-center is-justify-content-center"
>
<Loader />
<div>Loading data...</div>
</div>
</div>

{#each $layerStore as l, i}
<div>
<LayerControl layerDetails={l} index={i} />
{:else}
<div class="field is-fullwidth">
<h2 class="title is-size-6 mt-4 mb-4">DASHBOARD</h2>
<h2 class="title is-size-4 mb-5">CEEI Dashboard</h2>
<p>
<b
>Developed with IBM through the <a
href="https://www.ibm.com/impact/initiatives/ibm-sustainability-accelerator"
>IBM Sustainability Accelerator</a
></b
>
</p>
<label class="label mt-4" for="country-filter">Filter map to a country</label>
<div class="is-fullwidth">
<DropdownSearch
items={countriesList}
select={(item) => {
selectedCountryFilter = item?.value ?? null;
}}
></DropdownSearch>
</div>
</div>
{/each}
{/if}

{#each $layerStore as l, i}
<div>
<LayerControl layerDetails={l} index={i} />
</div>
{/each}
{/if}
</div>
</div>
</div>
<div slot="main">
<div class="toast-wrapper">
<SvelteToast />
{/snippet}
{#snippet main()}
<div>
<div class="toast-wrapper">
<SvelteToast />
</div>
<div class="map" bind:this={mapContainer}></div>
</div>
<div class="map" bind:this={mapContainer}></div>
</div>
{/snippet}
</Sidebar>

<style lang="scss">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { clickOutside } from 'svelte-use-click-outside';
interface Item {
label: string;
value: string;
}
const dispatch = createEventDispatcher();
interface Props {
items: Item[];
selectedItem?: Item | null;
select?: (item: Item | null) => void;
}
export let items: Item[];
export let selectedItem = null;
let {
items,
selectedItem = $bindable(null),
select = (item) => {
console.log(item);
}
}: Props = $props();
let showResults = false;
let inputValue = '';
$: filteredItemResults = items.filter((i) =>
i.label.toLowerCase().includes(inputValue.toLowerCase())
let showResults = $state(false);
let inputValue = $state('');
let filteredItemResults = $derived(
items.filter((i) => i.label.toLowerCase().includes(inputValue.toLowerCase()))
);
const handleItemClick = (item: Item) => {
selectedItem = item;
inputValue = item.label;
showResults = false;
dispatch('select', item);
select(item);
};
const handleClear = () => {
inputValue = '';
selectedItem = null;
dispatch('select', null);
select(null);
};
</script>

Expand All @@ -41,15 +49,15 @@
placeholder="Select a country..."
use:clickOutside={() => (showResults = false)}
bind:value={inputValue}
on:focusin={() => (showResults = true)}
onfocusin={() => (showResults = true)}
/>
<div class="icon is-small is-left">
<i class="fa fa-search"></i>
</div>
<button
class="icon is-small is-right"
style="pointer-events: all; cursor: pointer"
on:click={handleClear}
onclick={handleClear}
aria-label="close"
>
<i class="fa-solid fa-xmark"></i>
Expand All @@ -64,7 +72,7 @@
<button
class="dropdown-item"
class:is-active={selectedItem?.value === item.value}
on:click={() => handleItemClick(item)}
onclick={() => handleItemClick(item)}
>
{item.label}
</button>
Expand Down
Loading

0 comments on commit f8c6733

Please sign in to comment.