Skip to content

Commit 1051436

Browse files
authored
Merge pull request #22 from BEXIS2/table
Table
2 parents c8b7ec2 + 8b97a44 commit 1051436

18 files changed

+1107
-444
lines changed

src/lib/components/Table/Table.svelte

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { createEventDispatcher } from 'svelte';
23
import { createTable, Subscribe, Render, createRender } from 'svelte-headless-table';
34
import {
45
addSortBy,
@@ -25,6 +26,9 @@
2526
2627
type AccessorType = keyof (typeof $data)[0];
2728
29+
const dispatch = createEventDispatcher();
30+
const actionDispatcher = (obj) => dispatch('action', obj);
31+
2832
const table = createTable(data, {
2933
colFilter: addColumnFilters(),
3034
tableFilter: addTableFilter({
@@ -35,7 +39,8 @@
3539
expand: addExpandedRows()
3640
});
3741
38-
const accessors: AccessorType[] = Object.keys($data[0]) as AccessorType[];
42+
const accessors: AccessorType[] =
43+
$data.length > 0 ? (Object.keys($data[0]) as AccessorType[]) : [];
3944
4045
const tableColumns = [
4146
...accessors
@@ -49,21 +54,54 @@
4954
.map((accessor) => {
5055
const key = accessor as string;
5156
if (columns !== undefined && key in columns) {
52-
const { header, colFilterFn, colFilterComponent } = columns[key];
57+
const {
58+
header,
59+
colFilterFn,
60+
colFilterComponent,
61+
instructions,
62+
disableFiltering = false,
63+
disableSorting = false
64+
} = columns[key];
65+
66+
const { toSortableValueFn, toFilterableValueFn, toStringFn } = instructions ?? {};
67+
5368
return table.column({
5469
header: header ?? key,
5570
accessor: accessor,
71+
cell: ({ value }) => {
72+
return toStringFn ? toStringFn(value) : value;
73+
},
5674
plugins: {
57-
sort: { invert: true },
58-
colFilter: {
59-
fn: colFilterFn ?? columnFilter,
60-
render: ({ filterValue, values, id }) =>
61-
createRender(colFilterComponent ?? TableFilter, {
62-
filterValue,
63-
values,
64-
id,
65-
tableId
66-
})
75+
sort: {
76+
disable: disableSorting,
77+
invert: true,
78+
getSortValue: (row) => {
79+
return toSortableValueFn ? toSortableValueFn(row) : row;
80+
}
81+
},
82+
colFilter: !disableFiltering
83+
? {
84+
fn: ({ filterValue, value }) => {
85+
const val = toFilterableValueFn ? toFilterableValueFn(value) : value;
86+
87+
return colFilterFn
88+
? colFilterFn({ filterValue, value: val })
89+
: columnFilter({ filterValue, value: val });
90+
},
91+
render: ({ filterValue, values, id }) => {
92+
return createRender(colFilterComponent ?? TableFilter, {
93+
filterValue,
94+
id,
95+
tableId,
96+
values
97+
});
98+
}
99+
}
100+
: undefined,
101+
tableFilter: {
102+
getFilterValue: (row) => {
103+
return toStringFn ? toStringFn(row) : row;
104+
}
67105
}
68106
}
69107
});
@@ -72,11 +110,18 @@
72110
header: key,
73111
accessor: accessor,
74112
plugins: {
75-
sort: { invert: true },
113+
sort: {
114+
invert: true
115+
},
76116
colFilter: {
77117
fn: columnFilter,
78118
render: ({ filterValue, values, id }) =>
79-
createRender(TableFilter, { filterValue, values, id, tableId })
119+
createRender(TableFilter, {
120+
filterValue,
121+
id,
122+
tableId,
123+
values
124+
})
80125
}
81126
}
82127
});
@@ -91,7 +136,8 @@
91136
header: '',
92137
cell: ({ row }, _) => {
93138
return createRender(optionsComponent!, {
94-
row: row.isData() ? row.original : null
139+
row: row.isData() ? row.original : null,
140+
dispatchFn: actionDispatcher
95141
});
96142
}
97143
}) as any

src/lib/components/Table/TableFilter.svelte

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,32 @@
6767
value: 'ends',
6868
label: 'Ends with'
6969
}
70+
],
71+
date: [
72+
{
73+
value: 'ison',
74+
label: 'Is on'
75+
},
76+
{
77+
value: 'isstartingfrom',
78+
label: 'Is starting from'
79+
},
80+
{
81+
value: 'isafter',
82+
label: 'Is after'
83+
},
84+
{
85+
value: 'isuntil',
86+
label: 'Is until'
87+
},
88+
{
89+
value: 'isbefore',
90+
label: 'Is before'
91+
},
92+
{
93+
value: 'isnoton',
94+
label: 'Is not on'
95+
}
7096
]
7197
};
7298
@@ -78,7 +104,12 @@
78104
placement: 'bottom-start'
79105
};
80106
81-
const type = typeof $values[0];
107+
let type: string = typeof $values[0];
108+
if (type === 'object') {
109+
if ($values[0] instanceof Date) {
110+
type = 'date';
111+
}
112+
}
82113
</script>
83114

84115
<form class="">
@@ -95,7 +126,7 @@
95126
<div class="card p-3 absolute grid gap-2 shadow-lg z-10 w-min">
96127
<button
97128
class="btn variant-filled-primary btn-sm"
98-
type="submit"
129+
type="button"
99130
on:click|preventDefault={() => {
100131
firstOption = 'isequal';
101132
firstValue = undefined;
@@ -126,13 +157,20 @@
126157
bind:value={firstValue}
127158
on:click|stopPropagation
128159
/>
129-
{:else}
160+
{:else if type === 'string'}
130161
<input
131162
type="text"
132163
class="input p-1 border border-primary-500"
133164
bind:value={firstValue}
134165
on:click|stopPropagation
135166
/>
167+
{:else}
168+
<input
169+
type="date"
170+
class="input p-1 border border-primary-500"
171+
bind:value={firstValue}
172+
on:click|stopPropagation
173+
/>
136174
{/if}
137175
</div>
138176
<label for="" class="label normal-case">And</label>
@@ -154,18 +192,25 @@
154192
bind:value={secondValue}
155193
on:click|stopPropagation
156194
/>
157-
{:else}
195+
{:else if type === 'string'}
158196
<input
159197
type="text"
160198
class="input p-1 border border-primary-500"
161199
bind:value={secondValue}
162200
on:click|stopPropagation
163201
/>
202+
{:else}
203+
<input
204+
type="date"
205+
class="input p-1 border border-primary-500"
206+
bind:value={secondValue}
207+
on:click|stopPropagation
208+
/>
164209
{/if}
165210
</div>
166211
<button
167212
class="btn variant-filled-primary btn-sm"
168-
type="submit"
213+
type="button"
169214
on:click|preventDefault={() => {
170215
active = firstValue?.toString().length > 0 || secondValue?.toString().length > 0;
171216
$filterValue = [firstOption, firstValue, secondOption, secondValue];

src/lib/components/Table/TablePagination.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<select
4141
name="pageSize"
4242
id="pageSize"
43-
class="select btn btn-sm variant-filled-primary w-min font-bold"
43+
class="select variant-filled-primary w-min font-bold"
4444
bind:value={$pageSize}
4545
>
4646
{#each pageSizes as size}

src/lib/components/Table/filter.ts

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,42 @@ const numberFilter = (filterOption, filterValue, value) => {
3939
}
4040
};
4141

42+
const dateFilter = (filterOption, filterValue, value) => {
43+
const filter = new Date(filterValue);
44+
45+
switch (filterOption) {
46+
case 'ison':
47+
return value === filter;
48+
case 'isstartingfrom':
49+
return value >= filter;
50+
case 'isafter':
51+
return value > filter;
52+
case 'isuntil':
53+
return value <= filter;
54+
case 'isbefore':
55+
return value < filter;
56+
case 'isnoton':
57+
return value !== filter;
58+
default:
59+
return false;
60+
}
61+
};
62+
4263
const numericFilter: ColumnFilterFn = ({ filterValue, value }) => {
4364
const [firstFilterOption, firstFilterValue, secondFilterOption, secondFilterValue] = filterValue;
44-
if (!firstFilterValue && !secondFilterValue) {
65+
if (firstFilterValue == null && !secondFilterValue == null) {
4566
return true;
46-
} else if ((!firstFilterOption || !firstFilterValue) && secondFilterOption && secondFilterValue) {
67+
} else if (
68+
(firstFilterOption == null || firstFilterValue == null) &&
69+
secondFilterOption != null &&
70+
secondFilterValue != null
71+
) {
4772
return numberFilter(secondFilterOption, secondFilterValue, value);
48-
} else if ((!secondFilterOption || !secondFilterValue) && firstFilterOption && firstFilterValue) {
73+
} else if (
74+
(secondFilterOption == null || secondFilterValue == null) &&
75+
firstFilterOption != null &&
76+
firstFilterValue != null
77+
) {
4978
return numberFilter(firstFilterOption, firstFilterValue, value);
5079
}
5180
return (
@@ -77,11 +106,29 @@ const stringFilter: ColumnFilterFn = ({ filterValue, value }) => {
77106
);
78107
};
79108

109+
const dateTypeFilter: ColumnFilterFn = ({ filterValue, value }) => {
110+
const [firstFilterOption, firstFilterValue, secondFilterOption, secondFilterValue] = filterValue;
111+
if (!firstFilterValue && !secondFilterValue) {
112+
return true;
113+
} else if ((!firstFilterOption || !firstFilterValue) && secondFilterOption && secondFilterValue) {
114+
return dateFilter(secondFilterOption, secondFilterValue, value);
115+
} else if ((!secondFilterOption || !secondFilterValue) && firstFilterOption && firstFilterValue) {
116+
return dateFilter(firstFilterOption, firstFilterValue, value);
117+
}
118+
119+
return (
120+
dateFilter(firstFilterOption, firstFilterValue, value) &&
121+
dateFilter(secondFilterOption, secondFilterValue, value)
122+
);
123+
};
124+
80125
export const columnFilter: ColumnFilterFn = ({ filterValue, value }) => {
81126
if (typeof value === 'string') {
82127
return stringFilter({ filterValue, value });
83128
} else if (typeof value === 'number') {
84129
return numericFilter({ filterValue, value });
130+
} else if (typeof value === 'object' && value instanceof Date) {
131+
return dateTypeFilter({ filterValue, value });
85132
}
86133
return false;
87134
};

src/lib/models/Models.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,19 @@ export interface FileObj {
5555
webkitRelativePath: string;
5656
}
5757

58+
export interface ColumnInstructions {
59+
toStringFn?: (value: any) => string;
60+
toSortableValueFn?: (value: any) => string | number;
61+
toFilterableValueFn?: (value: any) => string | number | Date;
62+
}
63+
5864
// Table column type
5965
export interface Column {
6066
header?: string;
61-
exclude?: boolean;
67+
exclude?: boolean; // false by default
68+
instructions?: ColumnInstructions;
69+
disableFiltering?: boolean; // false by default
70+
disableSorting?: boolean; // false by default
6271
colFilterFn?: ColumnFilterFn;
6372
colFilterComponent?: typeof SvelteComponent;
6473
}

src/routes/+layout.svelte

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,18 @@
1010
import { storeHighlightJs } from '@skeletonlabs/skeleton';
1111
import { AppShell, TableOfContents } from '@skeletonlabs/skeleton';
1212
import Navigation from '$docs/Navigation.svelte';
13-
13+
// import '@skeletonlabs/skeleton/themes/theme-skeleton.css';
14+
import '$lib/css/themes/theme-bexis2.css';
15+
// If you have source.organizeImports set to true in VSCode, then it will auto change this ordering
16+
import '@skeletonlabs/skeleton/styles/all.css';
17+
// Most of your app wide CSS should be put in this file
18+
import '../app.postcss';
19+
1420
// Config for the floating UI elements
1521
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
1622
// Config for the syntax highlighting
1723
storeHighlightJs.set(hljs);
1824
// storeHighlightJs.set(hljs2);
19-
20-
// import '@skeletonlabs/skeleton/themes/theme-skeleton.css';
21-
import '$lib/css/themes/theme-bexis2.css';
22-
// If you have source.organizeImports set to true in VSCode, then it will auto change this ordering
23-
import '@skeletonlabs/skeleton/styles/skeleton.css';
24-
// Most of your app wide CSS should be put in this file
25-
import '../app.postcss';
26-
2725
</script>
2826

2927
<AppShell
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script lang="ts">
2+
import { AppShell, TableOfContents } from '@skeletonlabs/skeleton';
3+
</script>
4+
5+
<AppShell
6+
slotSidebarLeft="flex-none overflow-x-hidden overflow-y-auto bg-surface-50-900-token lg:w-auto"
7+
>
8+
<svelte:fragment slot="sidebarRight">
9+
<TableOfContents target="#toc-target" />
10+
</svelte:fragment>
11+
<!-- (pageHeader) -->
12+
<!-- Router Slot -->
13+
<slot />
14+
</AppShell>

0 commit comments

Comments
 (0)