diff --git a/src/reprocess/ReprocessResultTable.vue b/src/reprocess/ReprocessResultTable.vue
index 0e9d368..e850aa9 100644
--- a/src/reprocess/ReprocessResultTable.vue
+++ b/src/reprocess/ReprocessResultTable.vue
@@ -1,5 +1,6 @@
+
+
+ |
+ ▲
+
+ ▼
+ |
+
+
+
diff --git a/src/table/index.ts b/src/table/index.ts
new file mode 100644
index 0000000..0019ad9
--- /dev/null
+++ b/src/table/index.ts
@@ -0,0 +1,3 @@
+export { default as SortableHeader } from './SortableHeader.vue';
+export * from './sort';
+
diff --git a/src/table/sort.ts b/src/table/sort.ts
new file mode 100644
index 0000000..36f6ef1
--- /dev/null
+++ b/src/table/sort.ts
@@ -0,0 +1,42 @@
+import { MaybeRefOrGetter, computed, ref, toValue } from "vue";
+
+export type SortDirection = "asc" | "desc";
+export type UseSortOptions = {
+ defaultSortKey?: string;
+ defaultSortDirection?: SortDirection;
+};
+
+export const useSort = (array: MaybeRefOrGetter, options?: UseSortOptions) => {
+ const sortKey = ref(options?.defaultSortKey ?? null);
+ const sortDirection = ref(options?.defaultSortDirection ?? null);
+ const sortBy = (key: string, direction: SortDirection) => {
+ sortKey.value = key;
+ sortDirection.value = direction;
+ };
+ const headerProps = computed(() => ({
+ onSort: sortBy,
+ currentSortKey: sortKey.value,
+ sortDirection: sortDirection.value,
+ }));
+
+ const sortedArray = computed(() => toValue(array).sort((a, b) => {
+ if (sortKey.value === null || sortDirection.value === null) {
+ return 0;
+ }
+
+ const aValue = (a as any)[sortKey.value];
+ const bValue = (b as any)[sortKey.value];
+
+ if (aValue === bValue) {
+ return 0;
+ }
+
+ if (sortDirection.value === "asc") {
+ return aValue > bValue ? 1 : -1;
+ } else {
+ return aValue > bValue ? -1 : 1;
+ }
+ }));
+
+ return { sortedArray, headerProps };
+}
\ No newline at end of file