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
Showing only changes of commit 7e5901a2cf - Show all commits

View File

@ -32,43 +32,31 @@
</table> </table>
</main> </main>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, h, computed, reactive, watchEffect } from 'vue' import { ref, computed } from 'vue'
import type { UnwrapRef } from 'vue' import { useDocumentStore } from '@/stores/documents'
import { useDocumentStore } from '@/stores/documents' import Router from '@/router/index';
import Router from '@/router/index'; import type { Document, FolderDocument } from '@/repositories/Document';
import { message } from 'ant-design-vue'; import FileCarousel from './FileCarousel.vue';
import type { Document, FolderDocument } from '@/repositories/Document'; import FileRenameInput from './FileRenameInput.vue'
import FileCarousel from './FileCarousel.vue';
import FileRenameInput from './FileRenameInput.vue'
import createWebSocket from '@/repositories/WS'; import createWebSocket from '@/repositories/WS';
const [messageApi, contextHolder] = message.useMessage(); const documentStore = useDocumentStore()
const linkBasePath = computed(()=>{
type Key = string | number;
const documentStore = useDocumentStore()
const editableData: UnwrapRef<Record<string, Document>> = reactive({});
const state = reactive<{
selectedRowKeys: Key[];
}>({
selectedRowKeys: [],
});
const linkBasePath = computed(()=>{
const path = Router.currentRoute.value.path const path = Router.currentRoute.value.path
return path === '/' ? '' : path return path === '/' ? '' : path
}) })
const filesBasePath = computed(() => `/files${linkBasePath.value}`) const filesBasePath = computed(() => `/files${linkBasePath.value}`)
const url_for = (doc: FolderDocument) => ( const url_for = (doc: FolderDocument) => (
doc.type === "folder" ? doc.type === "folder" ?
`#${linkBasePath.value}/${doc.name}` : `#${linkBasePath.value}/${doc.name}` :
`${filesBasePath.value}/${doc.name}` `${filesBasePath.value}/${doc.name}`
) )
// File rename // File rename
const editing = ref<FolderDocument | null>(null) const editing = ref<FolderDocument | null>(null)
const rename = (doc: FolderDocument, newName: string) => { const rename = (doc: FolderDocument, newName: string) => {
const oldName = doc.name const oldName = doc.name
const control = createWebSocket("/api/control", (ev: MessageEvent) => { const control = createWebSocket("/api/control", (ev: MessageEvent) => {
const msg = JSON.parse(ev.data) const msg = JSON.parse(ev.data)
@ -87,29 +75,29 @@ import createWebSocket from '@/repositories/WS';
})) }))
} }
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
} }
// Column sort // Column sort
const toggleSort = (name: string) => { sort.value = sort.value === name ? "" : name } const toggleSort = (name: string) => { sort.value = sort.value === name ? "" : name }
const sort = ref<string>("") const sort = ref<string>("")
const sortCompare = { const sortCompare = {
"name": (a: Document, b: Document) => a.name.localeCompare(b.name), "name": (a: Document, b: Document) => a.name.localeCompare(b.name),
"modified": (a: FolderDocument, b: FolderDocument) => b.mtime - a.mtime, "modified": (a: FolderDocument, b: FolderDocument) => b.mtime - a.mtime,
"size": (a: FolderDocument, b: FolderDocument) => b.size - a.size "size": (a: FolderDocument, b: FolderDocument) => b.size - a.size
} }
const sorted = (documents: FolderDocument[]) => { const sorted = (documents: FolderDocument[]) => {
const cmp = sortCompare[sort.value as keyof typeof sortCompare] const cmp = sortCompare[sort.value as keyof typeof sortCompare]
const sorted = [...documents] const sorted = [...documents]
if (cmp) sorted.sort(cmp) if (cmp) sorted.sort(cmp)
return sorted return sorted
} }
const selectionIndeterminate = computed({ const selectionIndeterminate = computed({
get: () => { get: () => {
return documentStore.mainDocument && documentStore.mainDocument.length > 0 && documentStore.mainDocument.some((doc: Document) => doc.selected) && !allSelected.value return documentStore.mainDocument && documentStore.mainDocument.length > 0 && documentStore.mainDocument.some((doc: Document) => doc.selected) && !allSelected.value
}, },
set: (value: boolean) => {} set: (value: boolean) => {}
}) })
const allSelected = computed({ const allSelected = computed({
get: () => { get: () => {
return documentStore.mainDocument && documentStore.mainDocument.length > 0 && documentStore.mainDocument.every((doc: Document) => doc.selected) return documentStore.mainDocument && documentStore.mainDocument.length > 0 && documentStore.mainDocument.every((doc: Document) => doc.selected)
}, },
@ -118,110 +106,110 @@ import createWebSocket from '@/repositories/WS';
documentStore.mainDocument.forEach((doc: Document) => doc.selected = value) documentStore.mainDocument.forEach((doc: Document) => doc.selected = value)
} }
} }
}) })
</script> </script>
<style> <style>
table { table {
width: 100%; width: 100%;
table-layout: fixed; table-layout: fixed;
} }
table input[type=checkbox] { table input[type=checkbox] {
width: 1em; width: 1em;
height: 1em; height: 1em;
} }
table .modified { width: 10em; } table .modified { width: 10em; }
table .size { width: 6em; } table .size { width: 6em; }
table th, table td { table th, table td {
padding: .5em; padding: .5em;
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.name { .name {
white-space: nowrap; white-space: nowrap;
text-overflow: initial; text-overflow: initial;
overflow: initial; overflow: initial;
} }
.name button { .name button {
visibility: hidden; visibility: hidden;
padding-left: 1em; padding-left: 1em;
} }
.name:hover button { .name:hover button {
visibility: visible; visibility: visible;
} }
.name button { .name button {
cursor: pointer; cursor: pointer;
border: 0; border: 0;
background: transparent; background: transparent;
} }
thead tr { thead tr {
border: 1px solid #ddd; border: 1px solid #ddd;
background: #ddd; background: #ddd;
} }
tbody tr { tbody tr {
background: #444; background: #444;
color: #ddd; color: #ddd;
} }
tbody tr:hover { tbody tr:hover {
background: #00f8; background: #00f8;
} }
.right { .right {
text-align: right; text-align: right;
} }
.selection { .selection {
width: 2em; width: 2em;
} }
.sortcolumn:hover { .sortcolumn:hover {
cursor: pointer; cursor: pointer;
} }
.sortcolumn:hover::after { .sortcolumn:hover::after {
color: #f80; color: #f80;
} }
.sortcolumn { .sortcolumn {
padding-right: 1.7em; padding-right: 1.7em;
} }
.sortcolumn::after { .sortcolumn::after {
content: "▸"; content: "▸";
color: #888; color: #888;
margin: 0 1em 0 .5em; margin: 0 1em 0 .5em;
position: absolute; position: absolute;
transition: transform 0.2s linear; transition: transform 0.2s linear;
} }
.sortactive::after { .sortactive::after {
transform: rotate(90deg); transform: rotate(90deg);
color: #000; color: #000;
} }
main { main {
padding: 5px; padding: 5px;
height: 100%; height: 100%;
} }
.more-action{ .more-action{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: start; justify-content: start;
} }
.action-container{ .action-container{
display: flex; display: flex;
align-items: center; align-items: center;
} }
.edit-action{ .edit-action{
min-width: 5%; min-width: 5%;
} }
.carousel-container{ .carousel-container{
height: inherit; height: inherit;
} }
.name a { .name a {
text-decoration: none; text-decoration: none;
} }
.file .name::before { .file .name::before {
content: '📄 '; content: '📄 ';
font-size: 1.5em; font-size: 1.5em;
} }
.folder .name::before { .folder .name::before {
content: '📁 '; content: '📁 ';
font-size: 1.5em; font-size: 1.5em;
} }
</style> </style>