-
Notifications
You must be signed in to change notification settings - Fork 21
feat: implement sortable columns with visual indicators and sorting l… #414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
a80bc27
91ef36b
b963cde
3a66c2c
a8f54b6
df06a7b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -4,13 +4,28 @@ | |||||
| <table class="afcl-table w-full text-sm text-left rtl:text-right text-lightTableText dark:text-darkTableText overflow-x-auto"> | ||||||
| <thead class="afcl-table-thread text-xs text-lightTableHeadingText uppercase bg-lightTableHeadingBackground dark:bg-darkTableHeadingBackground dark:text-darkTableHeadingText"> | ||||||
| <tr> | ||||||
| <th scope="col" class="px-6 py-3" ref="headerRefs" :key="`header-${column.fieldName}`" | ||||||
| <th | ||||||
| scope="col" | ||||||
| class="px-6 py-3" | ||||||
| ref="headerRefs" | ||||||
| :key="`header-${column.fieldName}`" | ||||||
| v-for="column in columns" | ||||||
| :aria-sort="getAriaSort(column)" | ||||||
| :class="{ 'cursor-pointer select-none afcl-table-header-sortable': isColumnSortable(column) }" | ||||||
| @click="onHeaderClick(column)" | ||||||
| > | ||||||
| <slot v-if="$slots[`header:${column.fieldName}`]" :name="`header:${column.fieldName}`" :column="column" /> | ||||||
| <span v-else> | ||||||
|
|
||||||
| <span v-else class="inline-flex items-center"> | ||||||
| {{ column.label }} | ||||||
| <span v-if="isColumnSortable(column)" class="text-lightTableHeadingText dark:text-darkTableHeadingText"> | ||||||
| <!-- Unsorted indicator --> | ||||||
| <svg v-if="!isSorted(column)" class="w-3 h-3 ms-1.5 opacity-30" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"><path d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 1.086Zm6.852 1.952H8.574a2.072 2.072 0 0 0-1.847 1.087 1.9 1.9 0 0 0 .11 1.985l3.426 5.05a2.123 2.123 0 0 0 3.472 0l3.427-5.05a1.9 1.9 0 0 0 .11-1.985 2.074 2.074 0 0 0-1.846-1.087Z"></path></svg> | ||||||
| <!-- Sorted ascending indicator --> | ||||||
| <svg v-else-if="currentSortDirection === 'asc'" class="w-3 h-3 ms-1.5" fill="currentColor" viewBox="0 0 24 24"><path d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 0z"></path></svg> | ||||||
| <!-- Sorted descending indicator (rotated) --> | ||||||
| <svg v-else class="w-3 h-3 ms-1.5 rotate-180" fill="currentColor" viewBox="0 0 24 24"><path d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 0z"></path></svg> | ||||||
|
||||||
| <svg v-else class="w-3 h-3 ms-1.5 rotate-180" fill="currentColor" viewBox="0 0 24 24"><path d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 0z"></path></svg> | |
| <svg v-else class="w-3 h-3 ms-1.5 rotate-180" fill="currentColor" viewBox="0 0 24 24"><path d="M8.574 11.024h6.852a2.075 2.075 0 0 0 1.847-1.086 1.9 1.9 0 0 0-.11-1.986L13.736 2.9a2.122 2.122 0 0 0-3.472 0L6.837 7.952a1.9 1.9 0 0 0-.11 1.986 2.074 2.074 0 0 0 1.847 1.086Zm6.852 1.952H8.574a2.072 2.072 0 0 0-1.847 1.087 1.9 1.9 0 0 0 .11 1.985l3.426 5.05a2.123 2.123 0 0 0 3.472 0l3.427-5.05a1.9 1.9 0 0 0 .11-1.985 2.074 2.074 0 0 0-1.846-1.087Z"></path></svg> |
Outdated
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The as any type assertion bypasses TypeScript's type checking. Consider properly typing the emit parameter or using a union type like 'asc' | 'desc' | undefined in the emit definition instead of forcing the type with as any.
| emit('update:sortDirection', currentSortField.value ? currentSortDirection.value : undefined as any); | |
| emit('update:sortDirection', currentSortField.value ? currentSortDirection.value : undefined); |
Outdated
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The watcher triggers on initial component mount when currentSortField is initialized with props.defaultSortField, causing an unnecessary refresh() call after the onMounted hook already calls refresh(). Consider using { immediate: false } option or checking if this is the initial load to avoid duplicate data fetching.
| }); | |
| }, { immediate: false }); |
Outdated
Copilot
AI
Nov 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When sorting is cleared (sortField is undefined), the function still passes currentSortDirection.value which will be 'asc' by default. This could confuse server-side implementations. Consider only passing sortDirection when sortField has a value, e.g., ...(currentSortField.value ? { sortDirection: currentSortDirection.value } : {}).
| sortDirection: currentSortDirection.value, | |
| ...(currentSortField.value ? { sortDirection: currentSortDirection.value } : {}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SVG path for ascending sort indicator is incomplete. The path ends with '1.847 0z' but should end with '1.086Zm6.852...' to match the complete path from the unsorted indicator. This will result in an incorrect visual representation of the ascending arrow.