New filterbar
This commit is contained in:
parent
d31a4bbcc4
commit
22c1b4a784
3 changed files with 81 additions and 28 deletions
|
@ -35,6 +35,7 @@
|
||||||
bootstrap5Plugin
|
bootstrap5Plugin
|
||||||
],
|
],
|
||||||
locale: frLocale,
|
locale: frLocale,
|
||||||
|
allDayContent: '',
|
||||||
headerToolbar: {
|
headerToolbar: {
|
||||||
left: 'prev,next today',
|
left: 'prev,next today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
openModal = true;
|
openModal = true;
|
||||||
event.set(info.event);
|
event.set(info.event);
|
||||||
},
|
},
|
||||||
|
titleFormat: { year: '2-digit', month: 'numeric', day: 'numeric' },
|
||||||
events: [],
|
events: [],
|
||||||
themeSystem: 'bootstrap5'
|
themeSystem: 'bootstrap5'
|
||||||
});
|
});
|
||||||
|
@ -82,13 +84,16 @@
|
||||||
|
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<h1 class="title">Calendrier de la vie étudiante à l'ENS</h1>
|
<h1 class="title">Calendrier de la vie étudiante à l'ENS</h1>
|
||||||
<div style="height: 100%; display: flex;">
|
|
||||||
<FilterBar {calendarTree} bind:selected={selectedCalendars} />
|
<FilterBar {calendarTree} bind:selected={selectedCalendars} />
|
||||||
<div style="flex: 1;">
|
|
||||||
|
<div class="h-100 d-flex">
|
||||||
|
<div class="flex-grow-1">
|
||||||
<FullCalendar bind:this={calendar} options={$options} />
|
<FullCalendar bind:this={calendar} options={$options} />
|
||||||
</div>
|
</div>
|
||||||
<EventModal event={$event} open={openModal} {toggle} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<EventModal event={$event} open={openModal} {toggle} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -1,14 +1,29 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { Button, Offcanvas, Icon } from 'sveltestrap';
|
||||||
import FilterItem from './FilterItem.svelte';
|
import FilterItem from './FilterItem.svelte';
|
||||||
export let calendarTree = [];
|
export let calendarTree = [];
|
||||||
export let selected = null;
|
export let selected = null;
|
||||||
|
|
||||||
let subSelections = Array.from({length: Object.keys(calendarTree).length}, e => []);
|
let subSelections = Array.from({ length: Object.keys(calendarTree).length }, _ => []);
|
||||||
$: selected = subSelections.flat();
|
$: selected = subSelections.flat();
|
||||||
|
|
||||||
|
let open = true;
|
||||||
|
const toggle = () => (open = !open);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ul>
|
<Button on:click={toggle} class="my-2">
|
||||||
{#each Object.entries(calendarTree) as [toplevel, subtrees], i}
|
<span class="me-2">Sélection des calendriers</span>
|
||||||
<FilterItem item={toplevel} children={subtrees} bind:selected={subSelections[i]} />
|
<Icon name="chevron-double-right" />
|
||||||
{/each}
|
</Button>
|
||||||
</ul>
|
|
||||||
|
<Offcanvas
|
||||||
|
isOpen={open}
|
||||||
|
{toggle}
|
||||||
|
scroll
|
||||||
|
placement="start"
|
||||||
|
header="Sélection des calendriers"
|
||||||
|
>
|
||||||
|
{#each Object.entries(calendarTree) as [toplevel, subtrees], i}
|
||||||
|
<FilterItem item={toplevel} children={subtrees} bind:selected={subSelections[i]} />
|
||||||
|
{/each}
|
||||||
|
</Offcanvas>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
import TriStateCheckbox from './TriStateCheckbox.svelte';
|
import TriStateCheckbox from './TriStateCheckbox.svelte';
|
||||||
import { createTriState, createTriStates, UNCHECKED, CHECKED, WEIRD } from './stores';
|
import { createTriState, createTriStates, UNCHECKED, CHECKED, WEIRD } from './stores';
|
||||||
|
import { Icon } from 'sveltestrap';
|
||||||
|
|
||||||
export let item = null;
|
export let item = null;
|
||||||
|
|
||||||
|
@ -11,12 +12,12 @@
|
||||||
export let selected = [];
|
export let selected = [];
|
||||||
export let filtering = createTriState(CHECKED);
|
export let filtering = createTriState(CHECKED);
|
||||||
let subfiltering = createTriStates(CHECKED, Object.entries(children).length);
|
let subfiltering = createTriStates(CHECKED, Object.entries(children).length);
|
||||||
let subselected = Array.from({length: Object.entries(children).length}, e => []);
|
let subselected = Array.from({ length: Object.entries(children).length }, e => []);
|
||||||
|
|
||||||
function isVal(val) {
|
function isVal(val) {
|
||||||
return function (other) {
|
return function (other) {
|
||||||
return other === val;
|
return other === val;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function areAllChecked(values) {
|
function areAllChecked(values) {
|
||||||
|
@ -30,7 +31,7 @@
|
||||||
function handleChildChange(i) {
|
function handleChildChange(i) {
|
||||||
return function handler(evt) {
|
return function handler(evt) {
|
||||||
subfiltering.setAt(i, evt.detail.value);
|
subfiltering.setAt(i, evt.detail.value);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
subfiltering.subscribe(subvalues => {
|
subfiltering.subscribe(subvalues => {
|
||||||
|
@ -38,7 +39,11 @@
|
||||||
filtering.setChecked();
|
filtering.setChecked();
|
||||||
} else if (areAllUnchecked(subvalues) && $filtering !== UNCHECKED) {
|
} else if (areAllUnchecked(subvalues) && $filtering !== UNCHECKED) {
|
||||||
filtering.setUnchecked();
|
filtering.setUnchecked();
|
||||||
} else if (!areAllChecked(subvalues) && !areAllUnchecked(subvalues) && $filtering !== WEIRD) {
|
} else if (
|
||||||
|
!areAllChecked(subvalues) &&
|
||||||
|
!areAllUnchecked(subvalues) &&
|
||||||
|
$filtering !== WEIRD
|
||||||
|
) {
|
||||||
filtering.setWeird();
|
filtering.setWeird();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -62,21 +67,49 @@
|
||||||
dispatch('change', { value: evt.detail.value });
|
dispatch('change', { value: evt.detail.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
$: selected = $filtering === CHECKED ? [item, ...subselected.flat()] : subselected.flat();
|
$: icon = () => {
|
||||||
|
switch ($filtering) {
|
||||||
|
case UNCHECKED:
|
||||||
|
return 'circle';
|
||||||
|
case WEIRD:
|
||||||
|
return 'circle-half';
|
||||||
|
case CHECKED:
|
||||||
|
return 'check-circle-fill';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$: selected =
|
||||||
|
$filtering === CHECKED ? [item, ...subselected.flat()] : subselected.flat();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if item != null}
|
{#if item != null}
|
||||||
<li>
|
<li>
|
||||||
<TriStateCheckbox state={$filtering} on:change={handleChange} value={item} initialValue={true} />
|
<TriStateCheckbox
|
||||||
<span>{item}</span>
|
state={$filtering}
|
||||||
<ul>
|
on:change={handleChange}
|
||||||
{#each Object.entries(children) as [toplevel, subchildren], i}
|
value={item}
|
||||||
{#if subchildren}
|
initialValue={true}
|
||||||
<svelte:self item={toplevel} children={subchildren} on:change={handleChildChange(i)} filtering={subfiltering.storeAt(i)} bind:selected={subselected[i]} />
|
/>
|
||||||
{:else}
|
<span><Icon name={icon()} />{item}</span>
|
||||||
<svelte:self item={toplevel} on:change={handleChildChange(i)} filtering={subfiltering.storeAt(i)} bind:selected={subselected[i]} />
|
<ul>
|
||||||
{/if}
|
{#each Object.entries(children) as [toplevel, subchildren], i}
|
||||||
{/each}
|
{#if subchildren}
|
||||||
</ul>
|
<svelte:self
|
||||||
</li>
|
item={toplevel}
|
||||||
|
children={subchildren}
|
||||||
|
on:change={handleChildChange(i)}
|
||||||
|
filtering={subfiltering.storeAt(i)}
|
||||||
|
bind:selected={subselected[i]}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<svelte:self
|
||||||
|
item={toplevel}
|
||||||
|
on:change={handleChildChange(i)}
|
||||||
|
filtering={subfiltering.storeAt(i)}
|
||||||
|
bind:selected={subselected[i]}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
Loading…
Reference in a new issue