Remember sort order

This commit is contained in:
Leo Vasanko 2023-11-13 14:11:32 -08:00
parent 6880f82c19
commit 36826a83c1
4 changed files with 60 additions and 51 deletions

View File

@ -5,9 +5,9 @@
<th class="selection"> <th class="selection">
<input type="checkbox" tabindex="-1" v-model="allSelected" :indeterminate="selectionIndeterminate"> <input type="checkbox" tabindex="-1" v-model="allSelected" :indeterminate="selectionIndeterminate">
</th> </th>
<th class="sortcolumn" :class="{ sortactive: sort === 'name' }" @click="toggleSort('name')">Name</th> <th class="sortcolumn" :class="{ sortactive: store.sortOrder === 'name' }" @click="store.toggleSort('name')">Name</th>
<th class="sortcolumn modified right" :class="{ sortactive: sort === 'modified' }" @click="toggleSort('modified')">Modified</th> <th class="sortcolumn modified right" :class="{ sortactive: store.sortOrder === 'modified' }" @click="store.toggleSort('modified')">Modified</th>
<th class="sortcolumn size right" :class="{ sortactive: sort === 'size' }" @click="toggleSort('size')">Size</th> <th class="sortcolumn size right" :class="{ sortactive: store.sortOrder === 'size' }" @click="store.toggleSort('size')">Size</th>
<th class="menu"></th> <th class="menu"></th>
</tr> </tr>
</thead> </thead>
@ -21,7 +21,7 @@
<FileSize :doc=editing /> <FileSize :doc=editing />
<td class="menu"></td> <td class="menu"></td>
</tr> </tr>
<template v-for="(doc, index) in sortedDocuments" :key="doc.key"> <template v-for="(doc, index) in documents" :key="doc.key">
<tr class="folder-change" v-if="showFolderBreadcrumb(index)"> <tr class="folder-change" v-if="showFolderBreadcrumb(index)">
<th colspan="5"><BreadCrumb :path="doc.loc ? doc.loc.split('/') : []" /></th> <th colspan="5"><BreadCrumb :path="doc.loc ? doc.loc.split('/') : []" /></th>
</tr> </tr>
@ -84,9 +84,10 @@ import { useMainStore } from '@/stores/main'
import { Doc } from '@/repositories/Document' import { Doc } from '@/repositories/Document'
import FileRenameInput from './FileRenameInput.vue' import FileRenameInput from './FileRenameInput.vue'
import { connect, controlUrl } from '@/repositories/WS' import { connect, controlUrl } from '@/repositories/WS'
import { collator, formatSize } from '@/utils' import { formatSize } from '@/utils'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import ContextMenu from '@imengyu/vue3-context-menu' import ContextMenu from '@imengyu/vue3-context-menu'
import type { SortOrder } from '@/utils/docsort'
const props = defineProps<{ const props = defineProps<{
path: Array<string> path: Array<string>
@ -121,12 +122,6 @@ const rename = (doc: Doc, newName: string) => {
} }
doc.name = newName // We should get an update from watch but this is quicker doc.name = newName // We should get an update from watch but this is quicker
} }
const sortedDocuments = computed(() => sorted(props.documents))
const showFolderBreadcrumb = (i: number) => {
const docs = sortedDocuments.value
const docloc = docs[i].loc
return i === 0 ? docloc !== loc.value : docloc !== docs[i - 1].loc
}
defineExpose({ defineExpose({
newFolder() { newFolder() {
const now = Math.floor(Date.now() / 1000) const now = Math.floor(Date.now() / 1000)
@ -144,8 +139,8 @@ defineExpose({
allSelected.value = !allSelected.value allSelected.value = !allSelected.value
}, },
toggleSortColumn(column: number) { toggleSortColumn(column: number) {
const columns = ['', 'name', 'modified', 'size', ''] const order = ['', 'name', 'modified', 'size', ''][column]
toggleSort(columns[column]) if (order) store.toggleSort(order as SortOrder)
}, },
isCursor() { isCursor() {
return cursor.value !== null && editing.value === null return cursor.value !== null && editing.value === null
@ -165,25 +160,25 @@ defineExpose({
}, },
cursorMove(d: number, select = false) { cursorMove(d: number, select = false) {
// Move cursor up or down (keyboard navigation) // Move cursor up or down (keyboard navigation)
const documents = sortedDocuments.value const docs = props.documents
if (documents.length === 0) { if (docs.length === 0) {
cursor.value = null cursor.value = null
return return
} }
const N = documents.length const N = docs.length
const mod = (a: number, b: number) => ((a % b) + b) % b const mod = (a: number, b: number) => ((a % b) + b) % b
const increment = (i: number, d: number) => mod(i + d, N + 1) const increment = (i: number, d: number) => mod(i + d, N + 1)
const index = const index =
cursor.value !== null ? documents.indexOf(cursor.value) : documents.length cursor.value !== null ? docs.indexOf(cursor.value) : docs.length
const moveto = increment(index, d) const moveto = increment(index, d)
cursor.value = documents[moveto] ?? null cursor.value = docs[moveto] ?? null
const tr = cursor.value ? document.getElementById(`file-${cursor.value.key}`) : null const tr = cursor.value ? document.getElementById(`file-${cursor.value.key}`) : null
if (select) { if (select) {
// Go forwards, possibly wrapping over the end; the last entry is not toggled // Go forwards, possibly wrapping over the end; the last entry is not toggled
let [begin, end] = d > 0 ? [index, moveto] : [moveto, index] let [begin, end] = d > 0 ? [index, moveto] : [moveto, index]
for (let p = begin; p !== end; p = increment(p, 1)) { for (let p = begin; p !== end; p = increment(p, 1)) {
if (p === N) continue if (p === N) continue
const key = documents[p].key const key = docs[p].key
if (store.selected.has(key)) store.selected.delete(key) if (store.selected.has(key)) store.selected.delete(key)
else store.selected.add(key) else store.selected.add(key)
} }
@ -254,22 +249,10 @@ const mkdir = (doc: Doc, name: string) => {
doc.name = name doc.name = name
doc.key = crypto.randomUUID() doc.key = crypto.randomUUID()
} }
const showFolderBreadcrumb = (i: number) => {
// Column sort const docs = props.documents
const toggleSort = (name: string) => { const docloc = docs[i].loc
sort.value = sort.value === name ? '' : name return i === 0 ? docloc !== loc.value : docloc !== docs[i - 1].loc
}
const sort = ref<string>('')
const sortCompare = {
name: (a: Doc, b: Doc) => collator.compare(a.name, b.name),
modified: (a: Doc, b: Doc) => b.mtime - a.mtime,
size: (a: Doc, b: Doc) => b.size - a.size
}
const sorted = (documents: Doc[]) => {
const cmp = sortCompare[sort.value as keyof typeof sortCompare]
const sorted = [...documents]
if (cmp) sorted.sort(cmp)
return sorted
} }
const selectionIndeterminate = computed({ const selectionIndeterminate = computed({
get: () => { get: () => {

View File

@ -5,6 +5,7 @@ import { collator } from '@/utils'
import { logoutUser } from '@/repositories/User' import { logoutUser } from '@/repositories/User'
import { watchConnect } from '@/repositories/WS' import { watchConnect } from '@/repositories/WS'
import { shallowRef } from 'vue' import { shallowRef } from 'vue'
import { sorted, type SortOrder } from '@/utils/docsort'
type User = { type User = {
username: string username: string
@ -18,10 +19,15 @@ export const useMainStore = defineStore({
state: () => ({ state: () => ({
document: shallowRef<Doc[]>([]), document: shallowRef<Doc[]>([]),
selected: new Set<FUID>(), selected: new Set<FUID>(),
query: '' as string,
fileExplorer: null as any, fileExplorer: null as any,
error: '' as string, error: '' as string,
connected: false, connected: false,
server: {} as Record<string, any>, server: {} as Record<string, any>,
prefs: {
sortListing: '' as SortOrder,
sortFiltered: '' as SortOrder,
},
user: { user: {
username: '', username: '',
privileged: false, privileged: false,
@ -29,6 +35,9 @@ export const useMainStore = defineStore({
isOpenLoginModal: false isOpenLoginModal: false
} as User } as User
}), }),
persist: {
paths: ['prefs'],
},
actions: { actions: {
updateRoot(root: FileEntry[]) { updateRoot(root: FileEntry[]) {
const docs = [] const docs = []
@ -63,22 +72,16 @@ export const useMainStore = defineStore({
this.$reset() this.$reset()
localStorage.clear() localStorage.clear()
history.go() // Reload page history.go() // Reload page
} },
toggleSort(name: SortOrder) {
if (this.query) this.prefs.sortFiltered = this.prefs.sortFiltered === name ? '' : name
else this.prefs.sortListing = this.prefs.sortListing === name ? '' : name
},
}, },
getters: { getters: {
isUserLogged(): boolean { sortOrder(): SortOrder { return this.query ? this.prefs.sortFiltered : this.prefs.sortListing },
return this.user.isLoggedIn isUserLogged(): boolean { return this.user.isLoggedIn },
}, recentDocuments(): Doc[] { return sorted(this.document, 'modified') },
recentDocuments(): Doc[] {
const ret = [...this.document]
ret.sort((a, b) => b.mtime - a.mtime)
return ret
},
largeDocuments(): Doc[] {
const ret = [...this.document]
ret.sort((a, b) => b.size - a.size)
return ret
},
selectedFiles(): SelectedItems { selectedFiles(): SelectedItems {
const selected = this.selected const selected = this.selected
const found = new Set<FUID>() const found = new Set<FUID>()

View File

@ -0,0 +1,15 @@
import { Doc } from '@/repositories/Document'
import { collator } from '@/utils'
export const ordering = {
name: (a: Doc, b: Doc) => collator.compare(a.name, b.name),
modified: (a: Doc, b: Doc) => b.mtime - a.mtime,
size: (a: Doc, b: Doc) => b.size - a.size
}
export type SortOrder = keyof typeof ordering | ''
export const sorted = (documents: Doc[], order: SortOrder) => {
if (!order) return documents
const sorted = [...documents]
sorted.sort(ordering[order])
return sorted
}

View File

@ -13,6 +13,7 @@ import { watchEffect, ref, computed } from 'vue'
import { useMainStore } from '@/stores/main' import { useMainStore } from '@/stores/main'
import Router from '@/router/index' import Router from '@/router/index'
import { needleFormat, localeIncludes, collator } from '@/utils'; import { needleFormat, localeIncludes, collator } from '@/utils';
import { sorted } from '@/utils/docsort';
const store = useMainStore() const store = useMainStore()
const fileExplorer = ref() const fileExplorer = ref()
@ -24,7 +25,10 @@ const documents = computed(() => {
const loc = props.path.join('/') const loc = props.path.join('/')
const query = props.query const query = props.query
// List the current location // List the current location
if (!query) return store.document.filter(doc => doc.loc === loc) if (!query) return sorted(
store.document.filter(doc => doc.loc === loc),
store.prefs.sortListing,
)
// Find up to 100 newest documents that match the search // Find up to 100 newest documents that match the search
const needle = needleFormat(query) const needle = needleFormat(query)
let limit = 100 let limit = 100
@ -35,8 +39,11 @@ const documents = computed(() => {
if (--limit === 0) break if (--limit === 0) break
} }
} }
// Organize by folder, by relevance
const locsub = loc + '/' const locsub = loc + '/'
// Custom sort override in effect?
const order = store.prefs.sortFiltered
if (order) return sorted(docs, order)
// Sort by relevance - current folder, then subfolders, then others
docs.sort((a, b) => ( docs.sort((a, b) => (
// @ts-ignore // @ts-ignore
(b.loc === loc) - (a.loc === loc) || (b.loc === loc) - (a.loc === loc) ||
@ -54,5 +61,6 @@ const documents = computed(() => {
watchEffect(() => { watchEffect(() => {
store.fileExplorer = fileExplorer.value store.fileExplorer = fileExplorer.value
store.query = props.query
}) })
</script> </script>