Frontend created and rewritten a few times, with some backend fixes #1
|
@ -87,8 +87,7 @@
|
||||||
tbody .selection input:checked {
|
tbody .selection input:checked {
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
transform: scale(0.5);
|
transform: scale(0.5);
|
||||||
top: 0.1rem !important;
|
left: 0;
|
||||||
left: -0.3rem !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ main {
|
||||||
body {
|
body {
|
||||||
background-color: var(--primary-background);
|
background-color: var(--primary-background);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto';
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
@ -157,8 +156,48 @@ table {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
nav {
|
||||||
|
/* Position so that tooltips can appear on top of other positioned elements */
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
main {
|
main {
|
||||||
height: calc(100svh - 9rem); /* fill almost the rest of the screen after header */
|
height: calc(100svh - 9rem); /* fill almost the rest of the screen after header */
|
||||||
padding-bottom: 3rem; /* convenience space on the bottom */
|
padding-bottom: 3rem; /* convenience space on the bottom */
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
[data-tooltip]:hover:after {
|
||||||
|
z-index: 1000;
|
||||||
|
content: attr(data-tooltip);
|
||||||
|
position: absolute;
|
||||||
|
font-size: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
border-radius: 3rem 0 3rem 0;
|
||||||
|
box-shadow: 0 0 2rem var(--accent-color);
|
||||||
|
transform: translate(calc(1rem + -50%), 150%);
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
color: var(--primary-color);
|
||||||
|
white-space: pre;
|
||||||
|
animation: appearbriefly calc(10 * var(--transition-time)) linear forwards;
|
||||||
|
}
|
||||||
|
.modified [data-tooltip]:hover:after {
|
||||||
|
transform: translate(calc(1rem + 1ex + -100%), calc(-1.5rem + 100%));
|
||||||
|
}
|
||||||
|
@keyframes appearbriefly {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,20 +34,20 @@ const props = defineProps<{
|
||||||
.breadcrumb > a {
|
.breadcrumb > a {
|
||||||
margin: 0 -0.7rem 0 -0.7rem;
|
margin: 0 -0.7rem 0 -0.7rem;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
max-width: 8em;
|
max-width: 8rem;
|
||||||
font-size: 1.3em;
|
font-size: 1.3rem;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 1em;
|
height: 1.5rem;
|
||||||
color: var(--breadcrumb-color);
|
color: var(--breadcrumb-color);
|
||||||
padding: 0.3em 1.5em;
|
padding: 0.3rem 1.5rem;
|
||||||
clip-path: polygon(0 0, 1em 50%, 0 100%, 100% 100%, 100% 0, 0 0);
|
clip-path: polygon(0 0, 1rem 50%, 0 100%, 100% 100%, 100% 0, 0 0);
|
||||||
transition: all var(--breadcrumb-transtime);
|
transition: all var(--breadcrumb-transtime);
|
||||||
}
|
}
|
||||||
.breadcrumb a:first-child {
|
.breadcrumb a:first-child {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
padding-left: 0;
|
padding-left: .2rem;
|
||||||
clip-path: none;
|
clip-path: none;
|
||||||
}
|
}
|
||||||
.breadcrumb a:last-child {
|
.breadcrumb a:last-child {
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="modified right">
|
<td class="modified right">
|
||||||
<time
|
<time
|
||||||
:datetime="new Date(1000 * doc.mtime).toISOString().replace('.000', '')"
|
:data-tooltip="new Date(1000 * doc.mtime).toISOString().replace('T', '\n').replace('.000Z', ' UTC')"
|
||||||
>{{ doc.modified }}</time
|
>{{ doc.modified }}</time
|
||||||
>
|
>
|
||||||
</td>
|
</td>
|
||||||
|
@ -136,7 +136,7 @@ import type { Document, FolderDocument } from '@/repositories/Document'
|
||||||
import FileRenameInput from './FileRenameInput.vue'
|
import FileRenameInput from './FileRenameInput.vue'
|
||||||
import createWebSocket from '@/repositories/WS'
|
import createWebSocket from '@/repositories/WS'
|
||||||
import { formatSize, formatUnixDate } from '@/utils'
|
import { formatSize, formatUnixDate } from '@/utils'
|
||||||
import { isNavigationFailure, useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -352,12 +352,13 @@ thead tr {
|
||||||
}
|
}
|
||||||
tbody tr {
|
tbody tr {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: auto;
|
||||||
}
|
}
|
||||||
table thead input[type='checkbox'] {
|
table thead input[type='checkbox'] {
|
||||||
position: inherit;
|
position: inherit;
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
margin: 0.5rem;
|
padding: 0.5rem;
|
||||||
}
|
}
|
||||||
table tbody input[type='checkbox'] {
|
table tbody input[type='checkbox'] {
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
|
@ -413,6 +414,7 @@ table td {
|
||||||
thead tr {
|
thead tr {
|
||||||
background: linear-gradient(to bottom, #eee, #fff 30%, #ddd);
|
background: linear-gradient(to bottom, #eee, #fff 30%, #ddd);
|
||||||
color: #000;
|
color: #000;
|
||||||
|
box-shadow: 0 0 .2rem black;
|
||||||
}
|
}
|
||||||
tbody tr.cursor {
|
tbody tr.cursor {
|
||||||
background: var(--accent-color);
|
background: var(--accent-color);
|
||||||
|
@ -459,11 +461,12 @@ tbody .selection input {
|
||||||
}
|
}
|
||||||
.file .selection::before {
|
.file .selection::before {
|
||||||
content: '📄';
|
content: '📄';
|
||||||
font-size: 1.5em;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
.folder .selection::before {
|
.folder .selection::before {
|
||||||
|
height: 2rem;
|
||||||
content: '📁';
|
content: '📁';
|
||||||
font-size: 1.5em;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
.empty-container {
|
.empty-container {
|
||||||
padding-top: 3rem;
|
padding-top: 3rem;
|
||||||
|
|
|
@ -32,6 +32,7 @@ defineExpose({
|
||||||
<UploadButton />
|
<UploadButton />
|
||||||
<SvgButton
|
<SvgButton
|
||||||
name="create-folder"
|
name="create-folder"
|
||||||
|
data-tooltip="New folder"
|
||||||
@click="() => documentStore.fileExplorer.newFolder()"
|
@click="() => documentStore.fileExplorer.newFolder()"
|
||||||
/>
|
/>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -53,10 +54,11 @@ defineExpose({
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.buttons {
|
.buttons {
|
||||||
padding: 0 0.5em;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 3.5rem;
|
height: 3.5rem;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
.buttons > * {
|
.buttons > * {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
<template v-if="documentStore.selected.size">
|
<template v-if="documentStore.selected.size">
|
||||||
<div class="smallgap"></div>
|
<div class="smallgap"></div>
|
||||||
<p class="select-text">{{ documentStore.selected.size }} selected ➤</p>
|
<p class="select-text">{{ documentStore.selected.size }} selected ➤</p>
|
||||||
<SvgButton name="download" @click="download" />
|
<SvgButton name="download" data-tooltip="Download" @click="download" />
|
||||||
<SvgButton name="copy" @click="op('cp', dst)" />
|
<SvgButton name="copy" data-tooltip="Copy here" @click="op('cp', dst)" />
|
||||||
<SvgButton name="paste" @click="op('mv', dst)" />
|
<SvgButton name="paste" data-tooltip="Move here" @click="op('mv', dst)" />
|
||||||
<SvgButton name="trash" @click="op('rm')" />
|
<SvgButton name="trash" data-tooltip="Delete ⚠️" @click="op('rm')" />
|
||||||
<button @click="documentStore.selected.clear()">❌</button>
|
<button class="action-button unselect" data-tooltip="Unselect all" @click="documentStore.selected.clear()">❌</button>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ const props = defineProps<{
|
||||||
const icon = defineAsyncComponent(() => import(`@/assets/svg/${props.name}.svg`))
|
const icon = defineAsyncComponent(() => import(`@/assets/svg/${props.name}.svg`))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style>
|
||||||
button {
|
.action-button {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
|
@ -26,8 +26,8 @@ button {
|
||||||
width: 3rem;
|
width: 3rem;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
}
|
}
|
||||||
button:hover,
|
.action-button:hover,
|
||||||
button:focus {
|
.action-button:focus {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ svg {
|
||||||
fill: #ccc;
|
fill: #ccc;
|
||||||
transform: fill 0.2s ease;
|
transform: fill 0.2s ease;
|
||||||
}
|
}
|
||||||
button:hover svg,
|
.action-button:hover svg,
|
||||||
button:focus svg {
|
.action-button:focus svg {
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -91,6 +91,6 @@ async function uploadFileChangeHandler(event: Event) {
|
||||||
webkitdirectory
|
webkitdirectory
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<SvgButton name="add-file" @click="fileUploadButton.click()" />
|
<SvgButton name="add-file" data-tooltip="Upload files" @click="fileUploadButton.click()" />
|
||||||
<SvgButton name="add-folder" @click="folderUploadButton.click()" />
|
<SvgButton name="add-folder" data-tooltip="Upload folder" @click="folderUploadButton.click()" />
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user