Frontend created and rewritten a few times, with some backend fixes #1

Merged
leo merged 110 commits from plaintable into main 2023-11-08 20:38:40 +00:00
7 changed files with 32 additions and 43 deletions
Showing only changes of commit ece64f48be - Show all commits

View File

@ -62,7 +62,9 @@ const headerMain = ref<typeof HeaderMain | null>(null)
let vert = 0
let timer: any = null
const globalShortcutHandler = (event: KeyboardEvent) => {
const c = documentStore.fileExplorer.isCursor()
const fileExplorer = documentStore.fileExplorer as any
if (!fileExplorer) return
const c = fileExplorer.isCursor()
const keyup = event.type === 'keyup'
if (event.repeat) {
if (
@ -84,7 +86,7 @@ const globalShortcutHandler = (event: KeyboardEvent) => {
}
// Select all (toggle); keydown to prevent builtin
else if (!keyup && event.key === 'a' && (event.ctrlKey || event.metaKey)) {
documentStore.fileExplorer.toggleSelectAll()
fileExplorer.toggleSelectAll()
}
// Keys 1-3 to sort columns
else if (
@ -92,16 +94,16 @@ const globalShortcutHandler = (event: KeyboardEvent) => {
keyup &&
(event.key === '1' || event.key === '2' || event.key === '3')
) {
documentStore.fileExplorer.toggleSortColumn(+event.key)
fileExplorer.toggleSortColumn(+event.key)
}
// Rename
else if (c && keyup && !event.ctrlKey && (event.key === 'F2' || event.key === 'r')) {
documentStore.fileExplorer.cursorRename()
fileExplorer.cursorRename()
}
// Toggle selections on file explorer; ignore all spaces to prevent scrolling built-in hotkey
else if (c && event.code === 'Space') {
if (keyup && !event.altKey && !event.ctrlKey)
documentStore.fileExplorer.cursorSelect()
fileExplorer.cursorSelect()
} else return
event.preventDefault()
if (!vert) {
@ -114,13 +116,13 @@ const globalShortcutHandler = (event: KeyboardEvent) => {
if (!timer) {
// Initial move, then t0 delay until repeats at tr intervals
const select = event.shiftKey
documentStore.fileExplorer.cursorMove(vert, select)
fileExplorer.cursorMove(vert, select)
const t0 = 200,
tr = 30
timer = setTimeout(
() =>
(timer = setInterval(() => {
documentStore.fileExplorer.cursorMove(vert, select)
fileExplorer.cursorMove(vert, select)
}, tr)),
t0 - tr
)

View File

@ -35,7 +35,7 @@
justify-content: space-between;
align-items: end;
}
.breadcrumb {
header .breadcrumb {
font-size: 1.7em;
flex-shrink: 10;
}

View File

@ -57,7 +57,7 @@
<td class="menu"></td>
</tr>
<template
v-for="doc of sorted(props.documents as FolderDocument[])"
v-for="doc of sorted(props.documents as Document[])"
:key="doc.key">
<tr v-if="doc.loc !== prevloc && ((prevloc = doc.loc) || true)">
<th colspan="5"><BreadCrumb :path="doc.loc ? doc.loc.split('/') : []" /></th>
@ -141,7 +141,7 @@
<script setup lang="ts">
import { ref, computed, watchEffect, onBeforeUpdate } from 'vue'
import { useDocumentStore } from '@/stores/documents'
import type { Document, FolderDocument } from '@/repositories/Document'
import type { Document } from '@/repositories/Document'
import FileRenameInput from './FileRenameInput.vue'
import createWebSocket from '@/repositories/WS'
import { collator, formatSize, formatUnixDate } from '@/utils'
@ -156,14 +156,14 @@ const props = withDefaults(
)
const documentStore = useDocumentStore()
const router = useRouter()
const url_for = (doc: FolderDocument) => {
const url_for = (doc: Document) => {
const p = doc.loc ? `${doc.loc}/${doc.name}` : doc.name
return doc.type === 'folder' ? `#/${p}/` : `/files/${p}`
}
const cursor = ref<FolderDocument | null>(null)
const cursor = ref<Document | null>(null)
// File rename
const editing = ref<FolderDocument | null>(null)
const rename = (doc: FolderDocument, newName: string) => {
const editing = ref<Document | null>(null)
const rename = (doc: Document, newName: string) => {
const oldName = doc.name
const control = createWebSocket('/api/control', (ev: MessageEvent) => {
const msg = JSON.parse(ev.data)
@ -189,14 +189,15 @@ defineExpose({
newFolder() {
const now = Date.now() / 1000
editing.value = {
loc,
loc: loc.value,
key: 'new',
name: 'New Folder',
type: 'folder',
mtime: now,
size: 0,
sizedisp: formatSize(0),
modified: formatUnixDate(now)
modified: formatUnixDate(now),
haystack: '',
}
},
toggleSelectAll() {
@ -225,7 +226,7 @@ defineExpose({
},
cursorMove(d: number, select = false) {
// Move cursor up or down (keyboard navigation)
const documents = sorted(props.documents as FolderDocument[])
const documents = sorted(props.documents as Document[])
if (documents.length === 0) {
cursor.value = null
return
@ -311,10 +312,10 @@ const toggleSort = (name: string) => {
const sort = ref<string>('')
const sortCompare = {
name: (a: Document, b: Document) => collator.compare(a.name, b.name),
modified: (a: FolderDocument, b: FolderDocument) => b.mtime - a.mtime,
size: (a: FolderDocument, b: FolderDocument) => b.size - a.size
modified: (a: Document, b: Document) => b.mtime - a.mtime,
size: (a: Document, b: Document) => b.size - a.size
}
const sorted = (documents: FolderDocument[]) => {
const sorted = (documents: Document[]) => {
const cmp = sortCompare[sort.value as keyof typeof sortCompare]
const sorted = [...documents]
if (cmp) sorted.sort(cmp)

View File

@ -12,7 +12,7 @@
</template>
<script setup lang="ts">
import type { FolderDocument } from '@/repositories/Document'
import type { Document } from '@/repositories/Document'
import { ref, onMounted, nextTick } from 'vue'
const input = ref<HTMLInputElement | null>(null)
@ -28,8 +28,8 @@ onMounted(() => {
})
const props = defineProps<{
doc: FolderDocument
rename: (doc: FolderDocument, newName: string) => void
doc: Document
rename: (doc: Document, newName: string) => void
exit: () => void
}>()

View File

@ -37,6 +37,7 @@ defineExpose({
ref="search"
type="search"
v-model="documentStore.search"
placeholder="Search words"
class="margin-input"
@blur="() => { if (documentStore.search === '') toggleSearchInput() }"
@keyup.esc="toggleSearchInput"

View File

@ -1,4 +1,3 @@
import type { DocumentStore } from '@/stores/documents'
import { useDocumentStore } from '@/stores/documents'
import createWebSocket from './WS'
@ -68,7 +67,7 @@ export const url_document_upload_ws = '/api/upload'
export const url_document_get = '/files'
export class DocumentHandler {
constructor(private store: DocumentStore = useDocumentStore()) {
constructor(private store = useDocumentStore()) {
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this)
}
@ -142,7 +141,7 @@ export class DocumentHandler {
}
export class DocumentUploadHandler {
constructor(private store: DocumentStore = useDocumentStore()) {
constructor(private store = useDocumentStore()) {
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this)
}

View File

@ -6,7 +6,7 @@ import type {
DirList,
SelectedItems
} from '@/repositories/Document'
import { needleFormat, formatSize, formatUnixDate, haystackFormat, localeIncludes } from '@/utils'
import { formatSize, formatUnixDate, haystackFormat } from '@/utils'
import { defineStore } from 'pinia'
import { collator } from '@/utils'
@ -21,23 +21,9 @@ type User = {
isLoggedIn: boolean
}
export type DocumentStore = {
root: DirEntry
document: Document[]
search: string
selected: Set<FUID>
uploadingDocuments: Array<{ key: number; name: string; progress: number }>
uploadCount: number
wsWatch: WebSocket | undefined
wsUpload: WebSocket | undefined
fileExplorer: any
user: User
error: string
}
export const useDocumentStore = defineStore({
id: 'documents',
state: (): DocumentStore => ({
state: () => ({
root: {} as DirEntry,
document: [] as Document[],
search: "" as string,
@ -70,7 +56,7 @@ export const useDocumentStore = defineStore({
modified: formatUnixDate(attr.mtime),
haystack: haystackFormat(name),
})
const queue = [...Object.entries(root.dir).map(mapper)]
const queue = [...Object.entries(root.dir ?? {}).map(mapper)]
const docs = []
for (let doc; (doc = queue.shift()) !== undefined;) {
docs.push(doc)