Skip to content

Commit 0e79854

Browse files
committed
✨ Add sorting functionality to Astro data tables
1 parent 5ca8180 commit 0e79854

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

src/components/DataTable/DataTable.astro

+52-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
---
2+
/* eslint-disable max-lines */
23
import type { DataTableProps, HeadingObject } from './datatable'
34
45
import Button from '../Button/Button.astro'
@@ -8,6 +9,7 @@ import Pagination from '../Pagination/Pagination.astro'
89
import Select from '../Select/Select.astro'
910
1011
import checkIcon from '../../icons/check.svg?raw'
12+
import orderIcon from '../../icons/order.svg?raw'
1113
import searchIcon from '../../icons/search.svg?raw'
1214
1315
import styles from './datatable.module.scss'
@@ -117,8 +119,9 @@ const hasPagination = data?.length && itemsPerPage
117119
{headings.map(heading => (
118120
<th data-name={getColumnName(heading)}>
119121
<ConditionalWrapper condition={!!(heading as HeadingObject).sortable}>
120-
<Button theme="flat" slot="wrapper">
122+
<Button theme="flat" slot="wrapper" data-id="w-data-table-sort">
121123
children
124+
<Fragment set:html={orderIcon} />
122125
</Button>
123126
{(heading as HeadingObject).name || heading}
124127
</ConditionalWrapper>
@@ -170,6 +173,7 @@ const hasPagination = data?.length && itemsPerPage
170173
import { dispatch, listen } from '../../utils/event'
171174

172175
const filters = document.querySelectorAll('[data-id="w-data-table-filter"]')
176+
const sorts = document.querySelectorAll('[data-id="w-data-table-sort"]')
173177

174178
Array.from(filters).forEach(filter => {
175179
filter.addEventListener('input', debounce((event: Event) => {
@@ -233,6 +237,53 @@ const hasPagination = data?.length && itemsPerPage
233237
}, 400))
234238
})
235239

240+
Array.from(sorts).forEach(sort => {
241+
let sortOrder = 1
242+
243+
sort.addEventListener('click', event => {
244+
const target = event.target as HTMLButtonElement
245+
const sortBy = target.parentElement?.dataset.name
246+
const table = target.closest('section')?.querySelector('table')
247+
const tableBody = table?.querySelector('tbody')
248+
const sortedTableRows = Array.from(
249+
table?.querySelectorAll('tbody tr') as NodeListOf<HTMLTableRowElement>
250+
).sort((a, b) => {
251+
let aValue: string | number = (a.querySelector(`[data-name=${sortBy}]`) as HTMLElement)
252+
?.innerText.replace(/\s/g, '')
253+
let bValue: string | number = (b.querySelector(`[data-name=${sortBy}]`) as HTMLElement)
254+
?.innerText.replace(/\s/g, '')
255+
256+
if (!isNaN(aValue as any)) {
257+
aValue = Number(aValue)
258+
}
259+
260+
if (!isNaN(bValue as any)) {
261+
bValue = Number(bValue)
262+
}
263+
264+
return aValue > bValue
265+
? sortOrder * -1
266+
: sortOrder
267+
}).map((row, index) => {
268+
if (table?.dataset.page) {
269+
row.dataset.page = `${Math.ceil((index + 1) / Number(table.dataset.itemsPerPage))}`
270+
271+
if (row.dataset.page !== table.dataset.page) {
272+
row.dataset.hidden = 'true'
273+
} else {
274+
row.removeAttribute('data-hidden')
275+
}
276+
}
277+
278+
return row
279+
})
280+
281+
tableBody?.replaceChildren(...sortedTableRows)
282+
283+
sortOrder = sortOrder === 1 ? -1 : 1
284+
})
285+
})
286+
236287
listen('selectOnChange', event => {
237288
const eventName = event.name.toLowerCase().replace(/\s/g, '')
238289
const table = event.selectElement

src/components/DataTable/datatable.module.scss

+9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020
@include typography(bold);
2121
}
2222

23+
thead button {
24+
@include spacing(p-xxs);
25+
26+
svg {
27+
@include size(15px);
28+
pointer-events: none;
29+
}
30+
}
31+
2332
th,
2433
td {
2534
@include spacing(py-xs, px-sm);

src/components/Icon/map.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Close from '../../icons/close.svg?raw'
88
import Github from '../../icons/github.svg?raw'
99
import Info from '../../icons/info.svg?raw'
1010
import Moon from '../../icons/moon.svg?raw'
11+
import Order from '../../icons/order.svg?raw'
1112
import Search from '../../icons/search.svg?raw'
1213
import Sun from '../../icons/sun.svg?raw'
1314
import Warning from '../../icons/warning.svg?raw'
@@ -23,6 +24,7 @@ const iconMap = {
2324
'github': Github,
2425
'info': Info,
2526
'moon': Moon,
27+
'order': Order,
2628
'search': Search,
2729
'sun': Sun,
2830
'warning': Warning

src/icons/order.svg

+3
Loading

0 commit comments

Comments
 (0)