11<script setup lang="ts">
2+ import type { SftpFileSortColumn } from " #koko/composables/sftp/file-manager/filePresentation" ;
23import type { SftpFileEntry } from " #koko/composables/sftp/useSftpFileManager" ;
34import {
45 formatSftpFileSize ,
@@ -19,6 +20,8 @@ const props = withDefaults(
1920 compact? : boolean ;
2021 listKey? : string ;
2122 refreshing? : boolean ;
23+ sortBy: SftpFileSortColumn ;
24+ sortDirection: " asc" | " desc" ;
2225 }>(),
2326 {
2427 highlightedNames : () => [],
@@ -32,6 +35,7 @@ const props = withDefaults(
3235);
3336
3437const emit = defineEmits <{
38+ sort: [column : SftpFileSortColumn , direction : " asc" | " desc" ];
3539 select: [entry : SftpFileEntry , event : MouseEvent ];
3640 toggle: [entry : SftpFileEntry , selected : boolean ];
3741 toggleAll: [selected : boolean ];
@@ -43,6 +47,7 @@ const emit = defineEmits<{
4347const { t } = useI18n ();
4448const selectedSet = computed (() => new Set (props .selectedNames ));
4549const highlightedSet = computed (() => new Set (props .highlightedNames ));
50+ const sortIcon = computed (() => (props .sortDirection === " asc" ? " i-lucide-arrow-up" : " i-lucide-arrow-down" ));
4651const emptyColspan = computed (() => (props .compact ? 3 : 5 ));
4752const selectedBytes = computed (() => {
4853 if (! props .selectedNames .length ) return 0 ;
@@ -71,6 +76,16 @@ const sizeColClass = computed(() => (props.compact ? "w-22 px-2.5" : "w-27.5 px-
7176/** Keep row enter/leave for transfer highlight & delete; same-key refresh does not re-enter rows. */
7277const rowTransitionName = computed (() => (prefersReducedMotion .value ? " " : " sftp-file-row" ));
7378
79+ function requestSort(column : SftpFileSortColumn ): void {
80+ const direction = props .sortBy === column && props .sortDirection === " asc" ? " desc" : " asc" ;
81+ emit (" sort" , column , direction );
82+ }
83+
84+ function columnSort(column : SftpFileSortColumn ): " ascending" | " descending" | " none" {
85+ if (props .sortBy !== column ) return " none" ;
86+ return props .sortDirection === " asc" ? " ascending" : " descending" ;
87+ }
88+
7489function fileType(entry : SftpFileEntry ): string {
7590 return resolveSftpFileType (entry , {
7691 folder: t (" koko.fileManagement.folder" ),
@@ -175,26 +190,66 @@ onUnmounted(() => {
175190 </th >
176191 <th
177192 class =" h-8.5 min-w-0 border-b border-(--app-border) bg-(--app-panel-bg) px-3.5 py-1.5 text-left text-[11px] font-semibold text-muted"
193+ :aria-sort =" columnSort('name')"
178194 >
179- {{ t("koko.fileManagement.name") }}
195+ <UButton
196+ size="xs"
197+ color="neutral"
198+ variant="link"
199+ :trailing-icon =" sortBy === ' name' ? sortIcon : undefined "
200+ class="gap-1 p-0 text-[11px] font-semibold text-muted"
201+ @click =" requestSort (' name' )"
202+ >
203+ {{ t("koko.fileManagement.name") }}
204+ </UButton >
180205 </th >
181206 <th
182207 v-if =" !compact"
183208 class =" hidden h-8.5 border-b border-(--app-border) bg-(--app-panel-bg) px-3.5 py-1.5 text-right text-[11px] font-semibold text-muted md:table-cell"
209+ :aria-sort =" columnSort('mod_time')"
184210 >
185- {{ t("koko.fileManagement.modifiedTime") }}
211+ <UButton
212+ size="xs"
213+ color="neutral"
214+ variant="link"
215+ :trailing-icon =" sortBy === ' mod_time' ? sortIcon : undefined "
216+ class="gap-1 p-0 text-[11px] font-semibold text-muted"
217+ @click =" requestSort (' mod_time' )"
218+ >
219+ {{ t("koko.fileManagement.modifiedTime") }}
220+ </UButton >
186221 </th >
187222 <th
188223 class =" h-8.5 border-b border-(--app-border) bg-(--app-panel-bg) py-1.5 text-right text-[11px] font-semibold text-muted"
189224 :class =" sizeColClass"
225+ :aria-sort =" columnSort('size')"
190226 >
191- {{ t("koko.fileManagement.size") }}
227+ <UButton
228+ size="xs"
229+ color="neutral"
230+ variant="link"
231+ :trailing-icon =" sortBy === ' size' ? sortIcon : undefined "
232+ class="gap-1 p-0 text-[11px] font-semibold text-muted"
233+ @click =" requestSort (' size' )"
234+ >
235+ {{ t("koko.fileManagement.size") }}
236+ </UButton >
192237 </th >
193238 <th
194239 v-if =" !compact"
195240 class =" h-8.5 border-b border-(--app-border) bg-(--app-panel-bg) px-3.5 py-1.5 text-left text-[11px] font-semibold text-muted"
241+ :aria-sort =" columnSort('type')"
196242 >
197- {{ t("koko.fileManagement.type") }}
243+ <UButton
244+ size="xs"
245+ color="neutral"
246+ variant="link"
247+ :trailing-icon =" sortBy === ' type' ? sortIcon : undefined "
248+ class="gap-1 p-0 text-[11px] font-semibold text-muted"
249+ @click =" requestSort (' type' )"
250+ >
251+ {{ t("koko.fileManagement.type") }}
252+ </UButton >
198253 </th >
199254 </tr >
200255 </thead >
0 commit comments