Skip to content

Commit 785593d

Browse files
authored
Merge pull request #94 from BEXIS2/table
Table
2 parents 849921d + dfa6226 commit 785593d

22 files changed

+915
-171
lines changed

src/docs/navigation_link.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ export const menuNavLinks: any = [
3434
{ href: base + '/components/form', label: 'Form', keywords: '' },
3535
{ href: base + '/components/table', label: 'Table', keywords: '' },
3636
{ href: base + '/components/codeEditor', label: 'Code Editor', keywords: '' },
37-
{ href: base + '/components/fileupload', label: 'File Upload', keywords: '' }
38-
// { href: base + '/components/toggle', label: 'Toggle', keywords: '' }
37+
{ href: base + '/components/fileupload', label: 'File Upload', keywords: '' },
38+
{ href: base + '/components/facets', label: 'Facets', keywords: '' }
39+
// { href: base + '/components/toggle', label: 'Toggle', keywords: '' }
3940
]
4041
},
4142
{
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<script lang="ts">
2+
import { getModalStore, Modal, TreeView, TreeViewItem } from '@skeletonlabs/skeleton';
3+
4+
import ShowMore from './ShowMore.svelte';
5+
import type { FacetOption, FacetGroup } from '$models/Models';
6+
7+
export let groupSelection = false;
8+
export let groups: FacetGroup;
9+
export let selected: FacetGroup;
10+
export let selectedGroups: { [key: string]: boolean } = {};
11+
export let showAll = false;
12+
export let open = false;
13+
14+
const modalStore = getModalStore();
15+
const showMore = (group: string) => {
16+
modalStore.trigger({
17+
type: 'component',
18+
title: `${group}`,
19+
component: {
20+
ref: ShowMore,
21+
props: {
22+
group,
23+
handleSave,
24+
handleCancel,
25+
selected: selected[group],
26+
items: groups[group].sort((a, b) => a.value.localeCompare(b.value))
27+
}
28+
}
29+
});
30+
};
31+
32+
const handleSave = (group: string, selectedItems: FacetOption[]) => {
33+
selected[group] = selectedItems;
34+
modalStore.close();
35+
};
36+
37+
const handleCancel = () => {
38+
modalStore.close();
39+
};
40+
41+
const sortOptions = () => {
42+
// Sort facets in a descending order if count exits, or sort alphabetically
43+
Object.keys(groups).forEach((group) => {
44+
groups[group] = [
45+
...selected[group].sort((a, b) => {
46+
if (a.count != undefined && b.count != undefined) {
47+
return b.count - a.count;
48+
}
49+
return a.value.localeCompare(b.value);
50+
}),
51+
...groups[group]
52+
.filter((item) => !selected[group].includes(item))
53+
.sort((a, b) => {
54+
if (a.count != undefined && b.count != undefined) {
55+
return b.count - a.count;
56+
}
57+
return a.value.localeCompare(b.value);
58+
})
59+
];
60+
});
61+
};
62+
63+
$: selected, sortOptions();
64+
</script>
65+
66+
<TreeView selection={groupSelection} multiple={groupSelection} padding="p-1" hover="">
67+
{#each Object.keys(groups) as group}
68+
<TreeViewItem
69+
name="groups"
70+
value={group}
71+
{open}
72+
hyphenOpacity="opacity-0"
73+
bind:group={selectedGroups}
74+
bind:checked={selectedGroups[group]}
75+
>
76+
<p class="font-semibold">{group}</p>
77+
78+
<svelte:fragment slot="children">
79+
<!-- If more than 5 choices, show the remaining in the Modal -->
80+
{#if !showAll}
81+
{#each groups[group].slice(0, 5) as item}
82+
<TreeViewItem
83+
bind:group={selected[group]}
84+
name={group}
85+
value={item}
86+
hyphenOpacity="opacity-0"
87+
spacing="space-x-3"
88+
selection
89+
multiple
90+
>
91+
<p>{item.value} ({item.count})</p>
92+
</TreeViewItem>
93+
{/each}
94+
<!-- Trigger for the Modal to view all options -->
95+
{#if groups[group].length > 5}
96+
<TreeViewItem hyphenOpacity="opacity-0">
97+
<button class="anchor" on:click={() => showMore(group)}>more</button></TreeViewItem
98+
>
99+
{/if}
100+
{:else}
101+
{#each groups[group] as item}
102+
<TreeViewItem
103+
bind:group={selected[group]}
104+
name={group}
105+
value={item}
106+
hyphenOpacity="opacity-0"
107+
spacing="space-x-3"
108+
selection
109+
multiple
110+
>
111+
<p>{item.value} ({item.count})</p>
112+
</TreeViewItem>
113+
{/each}
114+
{/if}
115+
</svelte:fragment>
116+
</TreeViewItem>
117+
{/each}
118+
</TreeView>
119+
120+
<Modal />
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<script lang="ts">
2+
import type { FacetOption } from '$models/Models';
3+
4+
export let group: string; // Group name
5+
export let items: FacetOption[]; // All possible choices
6+
export let selected: FacetOption[]; // Initially selected items
7+
export let handleSave: (group: string, selectedItems: FacetOption[]) => {};
8+
export let handleCancel: () => {};
9+
10+
// This local variable is needed for resetting the Modal when the user cancels selection.
11+
let selectedItems = selected; // Selected items in the Modal.
12+
13+
const handleCheck = (e, index: number) => {
14+
const target = e.target as HTMLInputElement;
15+
if (target.checked) {
16+
selectedItems = [...selectedItems, items[index]];
17+
} else {
18+
selectedItems = selectedItems.filter((item) => item !== items[index]);
19+
}
20+
};
21+
22+
const selectAll = () => {
23+
selectedItems = items;
24+
};
25+
26+
const selectNone = () => {
27+
selectedItems = [];
28+
};
29+
30+
const onSave = () => {
31+
handleSave(group, selectedItems);
32+
};
33+
34+
const onCancel = () => {
35+
selectedItems = selected;
36+
handleCancel();
37+
};
38+
39+
const gridClass = (items: FacetOption[]) => {
40+
if (items.length >= 50) {
41+
return 'grid-cols-5';
42+
} else if (items.length >= 30) {
43+
return 'grid-cols-4';
44+
} else if (items.length >= 20) {
45+
return 'grid-cols-3';
46+
}
47+
48+
return 'grid-cols-2';
49+
};
50+
</script>
51+
52+
<div class="p-5 rounded-md bg-surface-50 dark:bg-surface-800 border-primary-500 border-2">
53+
<!-- Header -->
54+
<h2 class="text-xl font-semibold">{group}</h2>
55+
56+
<!-- Items -->
57+
<div
58+
class="grid {gridClass(
59+
items
60+
)} !gap-x-20 gap-y-2 py-10 px-2 max-h-[1000px] overflow-x-auto max-w-6xl"
61+
>
62+
{#each items as item, index}
63+
<label class="flex gap-3 items-center">
64+
<input
65+
type="checkbox"
66+
class="checkbox"
67+
value={item.value}
68+
on:click={(e) => handleCheck(e, index)}
69+
checked={selectedItems.includes(item)}
70+
/>
71+
<span class="whitespace-nowrap break-before-avoid break-after-avoid">{item.value}</span>
72+
</label>
73+
{/each}
74+
</div>
75+
76+
<!-- Footer -->
77+
<div class="flex w-full justify-between gap-5">
78+
<div class="flex gap-3">
79+
<button class="btn btn-sm variant-filled-tertiary" on:click={selectNone}>None</button>
80+
<button class="btn btn-sm variant-filled-tertiary" on:click={selectAll}>All</button>
81+
</div>
82+
<div class="flex gap-3">
83+
<button class="btn btn-sm variant-filled-primary" on:click={onSave}>Save</button>
84+
<button class="btn btn-sm variant-filled-secondary" on:click={onCancel}>Cancel</button>
85+
</div>
86+
</div>
87+
</div>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<script lang="ts">
2+
import { popup } from '@skeletonlabs/skeleton';
3+
import type { PopupSettings } from '@skeletonlabs/skeleton';
4+
5+
export let columns: { id: string; label: string; visible: boolean }[] = [];
6+
export let tableId: string;
7+
8+
const popupCombobox: PopupSettings = {
9+
event: 'click',
10+
target: `${tableId}-columns-menu`,
11+
placement: 'bottom'
12+
};
13+
</script>
14+
15+
<button
16+
type="button"
17+
class="btn btn-sm variant-filled-primary rounded-full order-last"
18+
use:popup={popupCombobox}>Columns</button
19+
>
20+
21+
<div
22+
class="bg-white dark:bg-surface-500 p-4 rounded-md shadow-md z-10"
23+
data-popup="{tableId}-columns-menu"
24+
>
25+
{#each columns as column}
26+
<div class="flex gap-3 items-center">
27+
<input
28+
type="checkbox"
29+
bind:checked={column.visible}
30+
disabled={columns.filter((c) => c.visible).length === 1 && column.visible}
31+
/>
32+
<span>{column.label}</span>
33+
</div>
34+
{/each}
35+
36+
<div class="arrow bg-white dark:bg-surface-500" />
37+
</div>

0 commit comments

Comments
 (0)