Skip to content

Commit b963cde

Browse files
committed
fix: enhance sorting indicators and logic for table columns
1 parent 91ef36b commit b963cde

File tree

1 file changed

+41
-60
lines changed

1 file changed

+41
-60
lines changed

adminforth/spa/src/afcl/Table.vue

Lines changed: 41 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
<span v-else class="inline-flex items-center">
2020
{{ column.label }}
2121
<span v-if="isColumnSortable(column)" class="text-lightTableHeadingText dark:text-darkTableHeadingText">
22-
<!-- Unsorted indicator -->
23-
<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>
24-
<!-- Sorted ascending indicator -->
25-
<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>
26-
<!-- Sorted descending indicator (rotated) -->
27-
<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>
22+
<!-- Unsorted -->
23+
<svg v-if="currentSortField !== column.fieldName" 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"/></svg>
24+
25+
<!-- Sorted ascending -->
26+
<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"/></svg>
27+
28+
<!-- Sorted descending -->
29+
<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"/></svg>
2830
</span>
2931
</span>
3032
</th>
@@ -293,63 +295,42 @@
293295
}
294296
}
295297
296-
function isColumnSortable(column: { fieldName: string; sortable?: boolean }) {
297-
return !!props.sortable && column.sortable !== false;
298-
}
298+
function isColumnSortable(col:{fieldName:string; sortable?:boolean}) {
299+
return !!props.sortable && col.sortable !== false;
300+
}
299301
300-
function isSorted(column: { fieldName: string }) {
301-
return currentSortField.value === column.fieldName;
302+
function onHeaderClick(col:{fieldName:string; sortable?:boolean}) {
303+
if (!isColumnSortable(col)) return;
304+
if (currentSortField.value !== col.fieldName) {
305+
currentSortField.value = col.fieldName;
306+
currentSortDirection.value = props.defaultSortDirection ?? 'asc';
307+
} else {
308+
currentSortDirection.value =
309+
currentSortDirection.value === 'asc' ? 'desc' :
310+
currentSortField.value ? (currentSortField.value = undefined, props.defaultSortDirection ?? 'asc') :
311+
'asc';
302312
}
313+
}
303314
304-
function getAriaSort(column: { fieldName: string; sortable?: boolean }) {
305-
if (!isColumnSortable(column)) return undefined;
306-
if (!isSorted(column)) return 'none';
307-
return currentSortDirection.value === 'asc' ? 'ascending' : 'descending';
308-
}
315+
function getAriaSort(col:{fieldName:string; sortable?:boolean}) {
316+
if (!isColumnSortable(col)) return undefined;
317+
if (currentSortField.value !== col.fieldName) return 'none';
318+
return currentSortDirection.value === 'asc' ? 'ascending' : 'descending';
319+
}
309320
310-
function onHeaderClick(column: { fieldName: string; sortable?: boolean }) {
311-
if (!isColumnSortable(column)) return;
312-
if (currentSortField.value !== column.fieldName) {
313-
currentSortField.value = column.fieldName;
314-
currentSortDirection.value = props.defaultSortDirection ?? 'asc';
315-
} else {
316-
if (currentSortDirection.value === 'asc') {
317-
currentSortDirection.value = 'desc';
318-
} else if (currentSortDirection.value === 'desc') {
319-
currentSortField.value = undefined;
320-
currentSortDirection.value = props.defaultSortDirection ?? 'asc';
321-
} else {
322-
currentSortDirection.value = 'asc';
323-
}
324-
}
325-
}
326-
327-
function getValueByPath(obj: any, path: string | undefined) {
328-
if (!path) return undefined;
329-
return path.split('.').reduce((acc: any, key: string) => (acc == null ? acc : acc[key]), obj);
330-
}
331-
332-
function compareValues(a: any, b: any) {
333-
if (a == null && b == null) return 0;
334-
if (a == null) return 1;
335-
if (b == null) return -1;
336-
if (typeof a === 'number' && typeof b === 'number') return a - b;
337-
const aDate = a instanceof Date ? a : undefined;
338-
const bDate = b instanceof Date ? b : undefined;
339-
if (aDate && bDate) return aDate.getTime() - bDate.getTime();
340-
return String(a).localeCompare(String(b), undefined, { numeric: true, sensitivity: 'base' });
341-
}
342-
343-
function sortArrayData(data: { [key: string]: any }[], sortField?: string, sortDirection: 'asc' | 'desc' = 'asc') {
344-
if (!props.sortable || !sortField) return data;
345-
const copy = data.slice();
346-
copy.sort((rowA, rowB) => {
347-
const aVal = getValueByPath(rowA, sortField);
348-
const bVal = getValueByPath(rowB, sortField);
349-
const cmp = compareValues(aVal, bVal);
350-
return sortDirection === 'asc' ? cmp : -cmp;
351-
});
352-
return copy;
353-
}
321+
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
354322
323+
function sortArrayData(data:any[], sortField?:string, dir:'asc'|'desc'='asc') {
324+
if (!props.sortable || !sortField) return data;
325+
const get = (o:any, p:string) => p.split('.').reduce((a:any,k)=>a?.[k], o);
326+
return [...data].sort((a,b) => {
327+
let av = get(a, sortField), bv = get(b, sortField);
328+
if (av == null && bv == null) return 0;
329+
if (av == null) return 1; if (bv == null) return -1;
330+
if (av instanceof Date && bv instanceof Date) return dir === 'asc' ? av.getTime() - bv.getTime() : bv.getTime() - av.getTime();
331+
if (typeof av === 'number' && typeof bv === 'number') return dir === 'asc' ? av - bv : bv - av;
332+
const cmp = collator.compare(String(av), String(bv));
333+
return dir === 'asc' ? cmp : -cmp;
334+
});
335+
}
355336
</script>

0 commit comments

Comments
 (0)