Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/docs/navigation_link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ export const menuNavLinks: any = [
{ href: base + '/components/form', label: 'Form', keywords: '' },
{ href: base + '/components/table', label: 'Table', keywords: '' },
{ href: base + '/components/codeEditor', label: 'Code Editor', keywords: '' },
{ href: base + '/components/fileupload', label: 'File Upload', keywords: '' }
// { href: base + '/components/toggle', label: 'Toggle', keywords: '' }
{ href: base + '/components/fileupload', label: 'File Upload', keywords: '' },
{ href: base + '/components/facets', label: 'Facets', keywords: '' }
// { href: base + '/components/toggle', label: 'Toggle', keywords: '' }
]
},
{
Expand Down
120 changes: 120 additions & 0 deletions src/lib/components/Facets/Facets.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<script lang="ts">
import { getModalStore, Modal, TreeView, TreeViewItem } from '@skeletonlabs/skeleton';

import ShowMore from './ShowMore.svelte';
import type { FacetOption, FacetGroup } from '$models/Models';

export let groupSelection = false;
export let groups: FacetGroup;
export let selected: FacetGroup;
export let selectedGroups: { [key: string]: boolean } = {};
export let showAll = false;
export let open = false;

const modalStore = getModalStore();
const showMore = (group: string) => {
modalStore.trigger({
type: 'component',
title: `${group}`,
component: {
ref: ShowMore,
props: {
group,
handleSave,
handleCancel,
selected: selected[group],
items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
}
}
});
};

const handleSave = (group: string, selectedItems: FacetOption[]) => {
selected[group] = selectedItems;
modalStore.close();
};

const handleCancel = () => {
modalStore.close();
};

const sortOptions = () => {
// Sort facets in a descending order if count exits, or sort alphabetically
Object.keys(groups).forEach((group) => {
groups[group] = [
...selected[group].sort((a, b) => {
if (a.count != undefined && b.count != undefined) {
return b.count - a.count;
}
return a.value.localeCompare(b.value);
}),
...groups[group]
.filter((item) => !selected[group].includes(item))
.sort((a, b) => {
if (a.count != undefined && b.count != undefined) {
return b.count - a.count;
}
return a.value.localeCompare(b.value);
})
];
});
};

$: selected, sortOptions();
</script>

<TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
{#each Object.keys(groups) as group}
<TreeViewItem
name="groups"
value={group}
{open}
hyphenOpacity="opacity-0"
bind:group={selectedGroups}
bind:checked={selectedGroups[group]}
>
<p class="font-semibold">{group}</p>

<svelte:fragment slot="children">
<!-- If more than 5 choices, show the remaining in the Modal -->
{#if !showAll}
{#each groups[group].slice(0, 5) as item}
<TreeViewItem
bind:group={selected[group]}
name={group}
value={item}
hyphenOpacity="opacity-0"
spacing="space-x-3"
selection
multiple
>
<p>{item.value} ({item.count})</p>
</TreeViewItem>
{/each}
<!-- Trigger for the Modal to view all options -->
{#if groups[group].length > 5}
<TreeViewItem hyphenOpacity="opacity-0">
<button class="anchor" on:click={() => showMore(group)}>more</button></TreeViewItem
>
{/if}
{:else}
{#each groups[group] as item}
<TreeViewItem
bind:group={selected[group]}
name={group}
value={item}
hyphenOpacity="opacity-0"
spacing="space-x-3"
selection
multiple
>
<p>{item.value} ({item.count})</p>
</TreeViewItem>
{/each}
{/if}
</svelte:fragment>
</TreeViewItem>
{/each}
</TreeView>

<Modal />
87 changes: 87 additions & 0 deletions src/lib/components/Facets/ShowMore.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<script lang="ts">
import type { FacetOption } from '$models/Models';

export let group: string; // Group name
export let items: FacetOption[]; // All possible choices
export let selected: FacetOption[]; // Initially selected items
export let handleSave: (group: string, selectedItems: FacetOption[]) => {};
export let handleCancel: () => {};

// This local variable is needed for resetting the Modal when the user cancels selection.
let selectedItems = selected; // Selected items in the Modal.

const handleCheck = (e, index: number) => {
const target = e.target as HTMLInputElement;
if (target.checked) {
selectedItems = [...selectedItems, items[index]];
} else {
selectedItems = selectedItems.filter((item) => item !== items[index]);
}
};

const selectAll = () => {
selectedItems = items;
};

const selectNone = () => {
selectedItems = [];
};

const onSave = () => {
handleSave(group, selectedItems);
};

const onCancel = () => {
selectedItems = selected;
handleCancel();
};

const gridClass = (items: FacetOption[]) => {
if (items.length >= 50) {
return 'grid-cols-5';
} else if (items.length >= 30) {
return 'grid-cols-4';
} else if (items.length >= 20) {
return 'grid-cols-3';
}

return 'grid-cols-2';
};
</script>

<div class="p-5 rounded-md bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
<!-- Header -->
<h2 class="text-xl font-semibold">{group}</h2>

<!-- Items -->
<div
class="grid {gridClass(
items
)} !gap-x-20 gap-y-2 py-10 px-2 max-h-[1000px] overflow-x-auto max-w-6xl"
>
{#each items as item, index}
<label class="flex gap-3 items-center">
<input
type="checkbox"
class="checkbox"
value={item.value}
on:click={(e) => handleCheck(e, index)}
checked={selectedItems.includes(item)}
/>
<span class="whitespace-nowrap break-before-avoid break-after-avoid">{item.value}</span>
</label>
{/each}
</div>

<!-- Footer -->
<div class="flex w-full justify-between gap-5">
<div class="flex gap-3">
<button class="btn btn-sm variant-filled-tertiary" on:click={selectNone}>None</button>
<button class="btn btn-sm variant-filled-tertiary" on:click={selectAll}>All</button>
</div>
<div class="flex gap-3">
<button class="btn btn-sm variant-filled-primary" on:click={onSave}>Save</button>
<button class="btn btn-sm variant-filled-secondary" on:click={onCancel}>Cancel</button>
</div>
</div>
</div>
37 changes: 37 additions & 0 deletions src/lib/components/Table/ColumnsMenu.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script lang="ts">
import { popup } from '@skeletonlabs/skeleton';
import type { PopupSettings } from '@skeletonlabs/skeleton';

export let columns: { id: string; label: string; visible: boolean }[] = [];
export let tableId: string;

const popupCombobox: PopupSettings = {
event: 'click',
target: `${tableId}-columns-menu`,
placement: 'bottom'
};
</script>

<button
type="button"
class="btn btn-sm variant-filled-primary rounded-full order-last"
use:popup={popupCombobox}>Columns</button
>

<div
class="bg-white dark:bg-surface-500 p-4 rounded-md shadow-md z-10"
data-popup="{tableId}-columns-menu"
>
{#each columns as column}
<div class="flex gap-3 items-center">
<input
type="checkbox"
bind:checked={column.visible}
disabled={columns.filter((c) => c.visible).length === 1 && column.visible}
/>
<span>{column.label}</span>
</div>
{/each}

<div class="arrow bg-white dark:bg-surface-500" />
</div>
Loading
Loading