Cleanup, lint, format etc.
This commit is contained in:
1 parent
f52d58d645
commit
119aba2b3c
35 files changed
+727
-6286
No files matched your search
@@ -7,6 +7,9 @@ yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# No locking
|
||||
package-lock.json
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
|
||||
Vendored
+2
@@ -8,11 +8,13 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AppNavigation: typeof import('./src/components/AppNavigation.vue')['default']
|
||||
BreadCrumb: typeof import('./src/components/BreadCrumb.vue')['default']
|
||||
FileExplorer: typeof import('./src/components/FileExplorer.vue')['default']
|
||||
FileRenameInput: typeof import('./src/components/FileRenameInput.vue')['default']
|
||||
FileViewer: typeof import('./src/components/FileViewer.vue')['default']
|
||||
HeaderMain: typeof import('./src/components/HeaderMain.vue')['default']
|
||||
LoginModal: typeof import('./src/components/LoginModal.vue')['default']
|
||||
ModalDialog: typeof import('./src/components/ModalDialog.vue')['default']
|
||||
NotificationLoading: typeof import('./src/components/NotificationLoading.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
|
||||
Generated
-5654
File diff suppressed because it is too large.
Load diff
@@ -36,8 +36,9 @@
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"@vue/test-utils": "^2.4.1",
|
||||
"@vue/tsconfig": "^0.4.0",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^8.52.0",
|
||||
"eslint-plugin-vue": "^9.18.1",
|
||||
"jsdom": "^22.1.0",
|
||||
"npm-run-all2": "^6.0.6",
|
||||
"prettier": "^3.0.3",
|
||||
@@ -45,5 +46,13 @@
|
||||
"vite": "^4.4.9",
|
||||
"vitest": "^0.34.4",
|
||||
"vue-tsc": "^1.8.11"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"arrowParens": "avoid",
|
||||
"endOfLine": "lf",
|
||||
"printWidth": 88
|
||||
}
|
||||
}
|
||||
+56
-45
@@ -1,44 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import type { ComputedRef } from 'vue'
|
||||
import { watchEffect } from 'vue'
|
||||
import createWebSocket from '@/repositories/WS'
|
||||
import { url_document_watch_ws, url_document_upload_ws, DocumentHandler, DocumentUploadHandler } from '@/repositories/Document'
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
import { RouterView } from 'vue-router'
|
||||
import type { ComputedRef } from 'vue'
|
||||
import { watchEffect } from 'vue'
|
||||
import createWebSocket from '@/repositories/WS'
|
||||
import {
|
||||
url_document_watch_ws,
|
||||
url_document_upload_ws,
|
||||
DocumentHandler,
|
||||
DocumentUploadHandler
|
||||
} from '@/repositories/Document'
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
|
||||
import { computed } from 'vue'
|
||||
import HeaderMain from '@/components/HeaderMain.vue'
|
||||
import AppNavigation from '@/components/AppNavigation.vue'
|
||||
import Router from '@/router/index';
|
||||
import { computed } from 'vue'
|
||||
import HeaderMain from '@/components/HeaderMain.vue'
|
||||
import AppNavigation from '@/components/AppNavigation.vue'
|
||||
import Router from '@/router/index'
|
||||
|
||||
interface Path {
|
||||
path: string;
|
||||
pathList: string[];
|
||||
interface Path {
|
||||
path: string
|
||||
pathList: string[]
|
||||
}
|
||||
const documentStore = useDocumentStore()
|
||||
const path: ComputedRef<Path> = computed(() => {
|
||||
const pathList = Router.currentRoute.value.path
|
||||
.split('/')
|
||||
.filter(value => value !== '')
|
||||
|
||||
return {
|
||||
path: Router.currentRoute.value.path,
|
||||
pathList
|
||||
}
|
||||
const documentStore = useDocumentStore()
|
||||
const path: ComputedRef<Path> = computed( () => {
|
||||
const pathList = Router.currentRoute.value.path
|
||||
.split('/')
|
||||
.filter( value => value !== '')
|
||||
})
|
||||
// Update human-readable x seconds ago messages from mtimes
|
||||
setInterval(documentStore.updateModified, 1000)
|
||||
watchEffect(() => {
|
||||
const documentHandler = new DocumentHandler()
|
||||
const documentUploadHandler = new DocumentUploadHandler()
|
||||
const wsWatch = createWebSocket(
|
||||
url_document_watch_ws,
|
||||
documentHandler.handleWebSocketMessage
|
||||
)
|
||||
const wsUpload = createWebSocket(
|
||||
url_document_upload_ws,
|
||||
documentUploadHandler.handleWebSocketMessage
|
||||
)
|
||||
|
||||
return {
|
||||
path: Router.currentRoute.value.path,
|
||||
pathList
|
||||
}
|
||||
})
|
||||
// Update human-readable x seconds ago messages from mtimes
|
||||
setInterval(documentStore.updateModified, 1000)
|
||||
watchEffect(() => {
|
||||
const documentHandler = new DocumentHandler()
|
||||
const documentUploadHandler = new DocumentUploadHandler()
|
||||
const wsWatch = createWebSocket(url_document_watch_ws, documentHandler.handleWebSocketMessage)
|
||||
const wsUpload = createWebSocket(url_document_upload_ws, documentUploadHandler.handleWebSocketMessage)
|
||||
documentStore.wsWatch = wsWatch
|
||||
documentStore.wsUpload = wsUpload
|
||||
})
|
||||
|
||||
documentStore.wsWatch = wsWatch;
|
||||
documentStore.wsUpload = wsUpload;
|
||||
})
|
||||
|
||||
export type { Path }
|
||||
export type { Path }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -51,14 +62,14 @@
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.wrapper{
|
||||
background-color: var(--header-background);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.page-container{
|
||||
flex-grow: 2;
|
||||
padding: 0;
|
||||
}
|
||||
.wrapper {
|
||||
background-color: var(--header-background);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.page-container {
|
||||
flex-grow: 2;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,45 +1,48 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
:root {
|
||||
--primary-background: #181818;
|
||||
--secondary-background: #ffffff;
|
||||
--font-color: #333;
|
||||
--header-background: #000;
|
||||
--primary-background: #181818;
|
||||
--secondary-background: #ffffff;
|
||||
--font-color: #333;
|
||||
--header-background: #000;
|
||||
--table-background: #535353;
|
||||
--primary-color: #ffffff;
|
||||
--secondary-color: #ccc;
|
||||
--blue-color: #66ffeb;
|
||||
--red-color: #ff4d4f;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--primary-background: #333;
|
||||
--secondary-background: #666;
|
||||
--font-color: #ddd;
|
||||
--table-background: #535353;
|
||||
--primary-color: #ffffff;
|
||||
--secondary-color: #ccc;
|
||||
--blue-color: #66ffeb;
|
||||
--red-color: #ff4d4f;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--primary-background: #333;
|
||||
--secondary-background: #666;
|
||||
--font-color: #ddd;
|
||||
--table-background: #535353;
|
||||
--primary-color: #ffffff;
|
||||
--secondary-color: #ccc;
|
||||
--blue-color: #66ffeb;
|
||||
--red-color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
body {
|
||||
background-color: var(--primary-background);
|
||||
font-family: 'Roboto', sans-serif;
|
||||
color: var(--font-color);
|
||||
margin: 0;
|
||||
background-color: var(--primary-background);
|
||||
font-family: 'Roboto', sans-serif;
|
||||
color: var(--font-color);
|
||||
margin: 0;
|
||||
}
|
||||
a:link, a:visited, a:active, a:hover {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
a:link,
|
||||
a:visited,
|
||||
a:active,
|
||||
a:hover {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border: 0;
|
||||
gap: 0;
|
||||
border-collapse: collapse;
|
||||
border: 0;
|
||||
gap: 0;
|
||||
}
|
||||
#app{
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
#app {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -1,17 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterLink } from 'vue-router'
|
||||
import Breadcrumb from '@/components/Breadcrumb.vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
path: Array<string>
|
||||
}>(),
|
||||
{},
|
||||
{}
|
||||
)
|
||||
|
||||
function generateUrl(pathIndex: number) {
|
||||
return "/" + props.path.slice(0, pathIndex + 1).join('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -63,16 +56,17 @@ function generateUrl(pathIndex: number) {
|
||||
{{{svg "triangle"}}}
|
||||
</div>
|
||||
-->
|
||||
<Breadcrumb :path="props.path"/>
|
||||
<BreadCrumb :path="props.path" />
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
nav, span{
|
||||
color: var(--primary-color);
|
||||
}
|
||||
span:hover, .last{
|
||||
color: var(--blue-color)
|
||||
|
||||
}
|
||||
nav,
|
||||
span {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
span:hover,
|
||||
.last {
|
||||
color: var(--blue-color);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div class="breadcrumb">
|
||||
<a href="#/"><component :is="home" /></a>
|
||||
<template v-for="(location, index) in props.path" :key="index">
|
||||
<a :href="`/#/${props.path.slice(0, index + 1).join('/')}/`">{{
|
||||
decodeURIComponent(location)
|
||||
}}</a>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import home from '@/assets/svg/home.svg'
|
||||
import { withDefaults, defineProps } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
path: Array<string>
|
||||
}>(),
|
||||
{}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--breadcrumb-background-odd: #2d2d2d;
|
||||
--breadcrumb-background-even: #404040;
|
||||
--breadcrumb-color: #ddd;
|
||||
--breadcrumb-hover-color: #fff;
|
||||
--breadcrumb-hover-background-odd: #25a;
|
||||
--breadcrumb-hover-background-even: #812;
|
||||
--breadcrumb-transtime: 0.3s;
|
||||
}
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 1em 0 0;
|
||||
}
|
||||
.breadcrumb > a {
|
||||
margin: 0 -0.7rem 0 -0.7rem;
|
||||
padding: 0;
|
||||
max-width: 8em;
|
||||
font-size: 1.3em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
height: 1em;
|
||||
color: var(--breadcrumb-color);
|
||||
padding: 0.3em 1.5em;
|
||||
clip-path: polygon(0 0, 1em 50%, 0 100%, 100% 100%, 100% 0, 0 0);
|
||||
transition: all var(--breadcrumb-transtime);
|
||||
}
|
||||
.breadcrumb a:first-child {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
clip-path: none;
|
||||
}
|
||||
.breadcrumb a:last-child {
|
||||
max-width: none;
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
calc(100% - 1em) 0,
|
||||
100% 50%,
|
||||
calc(100% - 1em) 100%,
|
||||
0 100%,
|
||||
1em 50%,
|
||||
0 0
|
||||
);
|
||||
}
|
||||
.breadcrumb a:only-child {
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
calc(100% - 1em) 0,
|
||||
100% 50%,
|
||||
calc(100% - 1em) 100%,
|
||||
0 100%,
|
||||
0 0
|
||||
);
|
||||
}
|
||||
.breadcrumb svg {
|
||||
/* FIXME: Custom positioning to align it well; needs proper solution */
|
||||
transform: translate(0.3rem, -0.3rem) scale(80%);
|
||||
fill: var(--breadcrumb-color);
|
||||
transition: fill var(--breadcrumb-transtime);
|
||||
}
|
||||
.breadcrumb a:nth-child(odd) {
|
||||
background: var(--breadcrumb-background-odd);
|
||||
}
|
||||
.breadcrumb a:nth-child(even) {
|
||||
background: var(--breadcrumb-background-even);
|
||||
}
|
||||
.breadcrumb a:nth-child(odd):hover {
|
||||
background: var(--breadcrumb-hover-background-odd);
|
||||
}
|
||||
.breadcrumb a:nth-child(even):hover {
|
||||
background: var(--breadcrumb-hover-background-even);
|
||||
}
|
||||
.breadcrumb a:hover {
|
||||
color: var(--breadcrumb-hover-color);
|
||||
}
|
||||
.breadcrumb a:hover svg {
|
||||
fill: var(--breadcrumb-hover-color);
|
||||
}
|
||||
</style>
|
||||
@@ -1,76 +0,0 @@
|
||||
<template>
|
||||
<div class="breadcrumb">
|
||||
<a href="#/"><component :is="home"/></a>
|
||||
<template v-for="(location, index) in props.path">
|
||||
<a :href="`/#/${props.path.slice(0, index + 1).join('/')}/`">{{ decodeURIComponent(location) }}</a>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import home from '@/assets/svg/home.svg'
|
||||
import { withDefaults, defineProps } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
path: Array<string>
|
||||
}>(),
|
||||
{},
|
||||
)
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--breadcrumb-background-odd: #2d2d2d;
|
||||
--breadcrumb-background-even: #404040;
|
||||
--breadcrumb-color: #ddd;
|
||||
--breadcrumb-hover-color: #fff;
|
||||
--breadcrumb-hover-background-odd: #25a;
|
||||
--breadcrumb-hover-background-even: #812;
|
||||
--breadcrumb-transtime: 0.3s;
|
||||
}
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 1em 0 0;
|
||||
}
|
||||
.breadcrumb > a {
|
||||
margin: 0 -0.7rem 0 -.7rem;
|
||||
padding: 0;
|
||||
max-width: 8em;
|
||||
font-size: 1.3em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
height: 1em;
|
||||
color: var(--breadcrumb-color);
|
||||
padding: .3em 1.5em;
|
||||
clip-path: polygon(0 0, 1em 50%, 0 100%, 100% 100%, 100% 0, 0 0);
|
||||
transition: all var(--breadcrumb-transtime);
|
||||
}
|
||||
.breadcrumb a:first-child {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
clip-path: none;
|
||||
}
|
||||
.breadcrumb a:last-child {
|
||||
max-width: none;
|
||||
clip-path: polygon(0 0, calc(100% - 1em) 0, 100% 50%, calc(100% - 1em) 100%, 0 100%, 1em 50%, 0 0);
|
||||
}
|
||||
.breadcrumb a:only-child {
|
||||
clip-path: polygon(0 0, calc(100% - 1em) 0, 100% 50%, calc(100% - 1em) 100%, 0 100%, 0 0);
|
||||
}
|
||||
.breadcrumb svg {
|
||||
/* FIXME: Custom positioning to align it well; needs proper solution */
|
||||
transform: translate(.3rem, -.3rem) scale(80%);
|
||||
fill: var(--breadcrumb-color);
|
||||
transition: fill var(--breadcrumb-transtime);
|
||||
}
|
||||
.breadcrumb a:nth-child(odd) { background: var(--breadcrumb-background-odd); }
|
||||
.breadcrumb a:nth-child(even) { background: var(--breadcrumb-background-even) }
|
||||
.breadcrumb a:nth-child(odd):hover { background: var(--breadcrumb-hover-background-odd); }
|
||||
.breadcrumb a:nth-child(even):hover { background: var(--breadcrumb-hover-background-even); }
|
||||
.breadcrumb a:hover { color: var(--breadcrumb-hover-color); }
|
||||
.breadcrumb a:hover svg { fill: var(--breadcrumb-hover-color); }
|
||||
</style>
|
||||
@@ -1,69 +0,0 @@
|
||||
<template>
|
||||
<dialog ref="dialog">
|
||||
<h1 v-if="title">{{ title }}</h1>
|
||||
<div>
|
||||
<slot>Dialog with no content</slot>
|
||||
</div>
|
||||
<button onclick="dialog.close()">OK</button>
|
||||
</dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
const dialog = ref<HTMLDialogElement | null>(null)
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
title: string
|
||||
}>(),
|
||||
{
|
||||
title: '',
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
dialog.value!.showModal()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Style for the background */
|
||||
body:has(dialog[open])::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #0008;
|
||||
backdrop-filter: blur(.2em);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/* Hide the dialog by default */
|
||||
dialog[open] {
|
||||
display: block;
|
||||
border: none;
|
||||
border-radius: .5rem;
|
||||
box-shadow: .2rem .2rem 1rem #000;
|
||||
padding: 1rem;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
dialog[open] > h1 {
|
||||
background: #00f;
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin: -1rem -1rem 0 -1rem;
|
||||
padding: .5rem 1rem .5rem 1rem;
|
||||
}
|
||||
|
||||
dialog[open] > div {
|
||||
padding: 1em 0;
|
||||
}
|
||||
</style>
|
||||
@@ -3,26 +3,67 @@
|
||||
<table v-if="props.documents.length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="selection"><input type="checkbox" v-model="allSelected" :indeterminate="selectionIndeterminate"></th>
|
||||
<th class="sortcolumn" :class="{sortactive: sort === 'name'}" @click="toggleSort('name')">Name</th>
|
||||
<th class="sortcolumn modified right" :class="{sortactive: sort === 'modified'}" @click="toggleSort('modified')">Modified</th>
|
||||
<th class="sortcolumn size right" :class="{sortactive: sort === 'size'}" @click="toggleSort('size')">Size</th>
|
||||
<th class="selection">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="allSelected"
|
||||
:indeterminate="selectionIndeterminate"
|
||||
/>
|
||||
</th>
|
||||
<th
|
||||
class="sortcolumn"
|
||||
:class="{ sortactive: sort === 'name' }"
|
||||
@click="toggleSort('name')"
|
||||
>
|
||||
Name
|
||||
</th>
|
||||
<th
|
||||
class="sortcolumn modified right"
|
||||
:class="{ sortactive: sort === 'modified' }"
|
||||
@click="toggleSort('modified')"
|
||||
>
|
||||
Modified
|
||||
</th>
|
||||
<th
|
||||
class="sortcolumn size right"
|
||||
:class="{ sortactive: sort === 'size' }"
|
||||
@click="toggleSort('size')"
|
||||
>
|
||||
Size
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="doc of sorted(props.documents as FolderDocument[])" :key="doc.key" :class="doc.type === 'folder' ? 'folder' : 'file'">
|
||||
<tr
|
||||
v-for="doc of sorted(props.documents as FolderDocument[])"
|
||||
:key="doc.key"
|
||||
:class="doc.type === 'folder' ? 'folder' : 'file'"
|
||||
>
|
||||
<td class="selection">
|
||||
<input type="checkbox" :checked="doc.key in documentStore.selected" @change="documentStore.selected.add(doc.key)">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="doc.key in documentStore.selected"
|
||||
@change="documentStore.selected.add(doc.key)"
|
||||
/>
|
||||
</td>
|
||||
<td class="name">
|
||||
<template v-if="editing === doc"><FileRenameInput :doc="doc" :rename="rename" :exit="() => { editing = null}"/></template>
|
||||
<template v-if="editing === doc"
|
||||
><FileRenameInput
|
||||
:doc="doc"
|
||||
:rename="rename"
|
||||
:exit="
|
||||
() => {
|
||||
editing = null
|
||||
}
|
||||
"
|
||||
/></template>
|
||||
<template v-else>
|
||||
<a :href="url_for(doc)">{{doc.name}}</a>
|
||||
<button @click="() => editing = doc">🖊️</button>
|
||||
<a :href="url_for(doc)">{{ doc.name }}</a>
|
||||
<button @click="() => (editing = doc)">🖊️</button>
|
||||
</template>
|
||||
</td>
|
||||
<td class="right">{{doc.modified}}</td>
|
||||
<td class="right">{{doc.sizedisp}}</td>
|
||||
<td class="right">{{ doc.modified }}</td>
|
||||
<td class="right">{{ doc.sizedisp }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -35,59 +76,62 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
import type { Document, FolderDocument } from '@/repositories/Document';
|
||||
import type { Document, FolderDocument } from '@/repositories/Document'
|
||||
import FileRenameInput from './FileRenameInput.vue'
|
||||
import createWebSocket from '@/repositories/WS';
|
||||
import createWebSocket from '@/repositories/WS'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
path: string,
|
||||
documents: Document[],
|
||||
path: string
|
||||
documents: Document[]
|
||||
}>(),
|
||||
{},
|
||||
{}
|
||||
)
|
||||
|
||||
const documentStore = useDocumentStore()
|
||||
const linkBasePath = computed(()=>{
|
||||
const linkBasePath = computed(() => {
|
||||
const path = props.path
|
||||
return path === '/' ? '' : path
|
||||
})
|
||||
const filesBasePath = computed(() => `/files${linkBasePath.value}`)
|
||||
const url_for = (doc: FolderDocument) => (
|
||||
doc.type === "folder" ?
|
||||
`#${linkBasePath.value}/${doc.name}` :
|
||||
`${filesBasePath.value}/${doc.name}`
|
||||
)
|
||||
const url_for = (doc: FolderDocument) =>
|
||||
doc.type === 'folder'
|
||||
? `#${linkBasePath.value}/${doc.name}`
|
||||
: `${filesBasePath.value}/${doc.name}`
|
||||
// File rename
|
||||
const editing = ref<FolderDocument | null>(null)
|
||||
const rename = (doc: FolderDocument, newName: string) => {
|
||||
const oldName = doc.name
|
||||
const control = createWebSocket("/api/control", (ev: MessageEvent) => {
|
||||
const control = createWebSocket('/api/control', (ev: MessageEvent) => {
|
||||
const msg = JSON.parse(ev.data)
|
||||
if ("error" in msg) {
|
||||
console.error("Rename failed", msg.error.message, msg.error)
|
||||
if ('error' in msg) {
|
||||
console.error('Rename failed', msg.error.message, msg.error)
|
||||
doc.name = oldName
|
||||
} else {
|
||||
console.log("Rename succeeded", msg)
|
||||
console.log('Rename succeeded', msg)
|
||||
}
|
||||
})
|
||||
control.onopen = () => {
|
||||
control.send(JSON.stringify({
|
||||
"op": "rename",
|
||||
"path": `${linkBasePath.value}/${oldName}`,
|
||||
"to": newName
|
||||
}))
|
||||
control.send(
|
||||
JSON.stringify({
|
||||
op: 'rename',
|
||||
path: `${linkBasePath.value}/${oldName}`,
|
||||
to: newName
|
||||
})
|
||||
)
|
||||
}
|
||||
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
|
||||
const toggleSort = (name: string) => { sort.value = sort.value === name ? "" : name }
|
||||
const sort = ref<string>("")
|
||||
const toggleSort = (name: string) => {
|
||||
sort.value = sort.value === name ? '' : name
|
||||
}
|
||||
const sort = ref<string>('')
|
||||
const sortCompare = {
|
||||
"name": (a: Document, b: Document) => a.name.localeCompare(b.name),
|
||||
"modified": (a: FolderDocument, b: FolderDocument) => b.mtime - a.mtime,
|
||||
"size": (a: FolderDocument, b: FolderDocument) => b.size - a.size
|
||||
name: (a: Document, b: Document) => a.name.localeCompare(b.name),
|
||||
modified: (a: FolderDocument, b: FolderDocument) => b.mtime - a.mtime,
|
||||
size: (a: FolderDocument, b: FolderDocument) => b.size - a.size
|
||||
}
|
||||
const sorted = (documents: FolderDocument[]) => {
|
||||
const cmp = sortCompare[sort.value as keyof typeof sortCompare]
|
||||
@@ -97,13 +141,21 @@ const sorted = (documents: FolderDocument[]) => {
|
||||
}
|
||||
const selectionIndeterminate = computed({
|
||||
get: () => {
|
||||
return props.documents.length > 0 && props.documents.some((doc: Document) => doc.key in documentStore.selected) && !allSelected.value
|
||||
return (
|
||||
props.documents.length > 0 &&
|
||||
props.documents.some((doc: Document) => doc.key in documentStore.selected) &&
|
||||
!allSelected.value
|
||||
)
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
set: (value: boolean) => {}
|
||||
})
|
||||
const allSelected = computed({
|
||||
get: () => {
|
||||
return props.documents.length > 0 && props.documents.every((doc: Document) => doc.key in documentStore.selected)
|
||||
return (
|
||||
props.documents.length > 0 &&
|
||||
props.documents.every((doc: Document) => doc.key in documentStore.selected)
|
||||
)
|
||||
},
|
||||
set: (value: boolean) => {
|
||||
for (const doc of props.documents) {
|
||||
@@ -122,14 +174,19 @@ table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
table input[type=checkbox] {
|
||||
table input[type='checkbox'] {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
table .modified { width: 10em; }
|
||||
table .size { width: 6em; }
|
||||
table th, table td {
|
||||
padding: .5em;
|
||||
table .modified {
|
||||
width: 10em;
|
||||
}
|
||||
table .size {
|
||||
width: 6em;
|
||||
}
|
||||
table th,
|
||||
table td {
|
||||
padding: 0.5em;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
@@ -177,9 +234,9 @@ tbody tr:hover {
|
||||
padding-right: 1.7em;
|
||||
}
|
||||
.sortcolumn::after {
|
||||
content: "▸";
|
||||
content: '▸';
|
||||
color: #888;
|
||||
margin: 0 1em 0 .5em;
|
||||
margin: 0 1em 0 0.5em;
|
||||
position: absolute;
|
||||
transition: all 0.2s linear;
|
||||
}
|
||||
@@ -191,19 +248,19 @@ main {
|
||||
padding: 5px;
|
||||
height: 100%;
|
||||
}
|
||||
.more-action{
|
||||
.more-action {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: start;
|
||||
}
|
||||
.action-container{
|
||||
.action-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.edit-action{
|
||||
.edit-action {
|
||||
min-width: 5%;
|
||||
}
|
||||
.carousel-container{
|
||||
.carousel-container {
|
||||
height: inherit;
|
||||
}
|
||||
.name a {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<input
|
||||
ref="input"
|
||||
id="FileRenameInput"
|
||||
type="text"
|
||||
:value="doc.name"
|
||||
@keyup.esc="exit"
|
||||
@keyup.enter="apply"
|
||||
>
|
||||
ref="input"
|
||||
id="FileRenameInput"
|
||||
type="text"
|
||||
:value="doc.name"
|
||||
@keyup.esc="exit"
|
||||
@keyup.enter="apply"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -21,11 +21,11 @@ onMounted(() => {
|
||||
input.value!.setSelectionRange(0, ext > 0 ? ext : input.value!.value.length)
|
||||
})
|
||||
|
||||
const props = defineProps < {
|
||||
doc: FolderDocument
|
||||
rename: (doc: FolderDocument, newName: string) => void
|
||||
exit: () => void
|
||||
} > ()
|
||||
const props = defineProps<{
|
||||
doc: FolderDocument
|
||||
rename: (doc: FolderDocument, newName: string) => void
|
||||
exit: () => void
|
||||
}>()
|
||||
|
||||
const apply = () => {
|
||||
const name = input.value!.value
|
||||
|
||||
@@ -1,55 +1,52 @@
|
||||
<template>
|
||||
<object
|
||||
v-if="props.type === 'pdf'"
|
||||
:data= "dataURL"
|
||||
type="application/pdf" width="100%"
|
||||
height="100%"
|
||||
>
|
||||
</object>
|
||||
<a-image
|
||||
v-else-if="props.type === 'image'"
|
||||
width="50%"
|
||||
:src="dataURL"
|
||||
@click="() => setVisible(true)"
|
||||
:previewMask=false
|
||||
:preview="{
|
||||
visibleImg,
|
||||
onVisibleChange: setVisible,
|
||||
}"
|
||||
/>
|
||||
<!-- Unknown case -->
|
||||
<h1 v-else>
|
||||
Unsupported file type
|
||||
</h1>
|
||||
<object
|
||||
v-if="props.type === 'pdf'"
|
||||
:data="dataURL"
|
||||
type="application/pdf"
|
||||
width="100%"
|
||||
height="100%"
|
||||
></object>
|
||||
<a-image
|
||||
v-else-if="props.type === 'image'"
|
||||
width="50%"
|
||||
:src="dataURL"
|
||||
@click="() => setVisible(true)"
|
||||
:previewMask="false"
|
||||
:preview="{
|
||||
visibleImg,
|
||||
onVisibleChange: setVisible
|
||||
}"
|
||||
/>
|
||||
<!-- Unknown case -->
|
||||
<h1 v-else>Unsupported file type</h1>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watchEffect, ref } from 'vue'
|
||||
import Router from '@/router/index';
|
||||
import { url_document_get } from '@/repositories/Document';
|
||||
import Router from '@/router/index'
|
||||
import { url_document_get } from '@/repositories/Document'
|
||||
|
||||
const dataURL = ref('')
|
||||
watchEffect(()=>{
|
||||
watchEffect(() => {
|
||||
dataURL.value = new URL(
|
||||
url_document_get + Router.currentRoute.value.path,
|
||||
location.origin
|
||||
).toString();
|
||||
).toString()
|
||||
})
|
||||
const emit = defineEmits({
|
||||
visibleImg(value: boolean){
|
||||
return value
|
||||
}
|
||||
visibleImg(value: boolean) {
|
||||
return value
|
||||
}
|
||||
})
|
||||
|
||||
function setVisible(value: boolean) {
|
||||
emit('visibleImg', value)
|
||||
}
|
||||
|
||||
|
||||
const props = defineProps < {
|
||||
type?: string
|
||||
visibleImg: boolean
|
||||
} > ()
|
||||
const props = defineProps<{
|
||||
type?: string
|
||||
visibleImg: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -2,14 +2,14 @@
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
import LoginModal from '@/components/LoginModal.vue'
|
||||
import UploadButton from '@/components/UploadButton.vue'
|
||||
import { ref } from 'vue';
|
||||
import { ref } from 'vue'
|
||||
|
||||
const documentStore = useDocumentStore()
|
||||
const searchQuery = ref<string>('')
|
||||
const showSearchInput = ref<boolean>(false)
|
||||
|
||||
const toggleSearchInput = () => {
|
||||
showSearchInput.value = !showSearchInput.value;
|
||||
showSearchInput.value = !showSearchInput.value
|
||||
if (!showSearchInput.value) {
|
||||
searchQuery.value = ''
|
||||
}
|
||||
@@ -18,40 +18,10 @@ const toggleSearchInput = () => {
|
||||
const executeSearch = (ev: InputEvent) => {
|
||||
// FIXME: Make reactive instead of this update handler
|
||||
const query = (ev.target as HTMLInputElement).value
|
||||
console.log("Searching", query)
|
||||
console.log('Searching', query)
|
||||
documentStore.setFilter(query)
|
||||
console.log("Filtered")
|
||||
console.log('Filtered')
|
||||
}
|
||||
|
||||
function createFileHandler() {
|
||||
console.log("Creating file")
|
||||
}
|
||||
|
||||
function uploadFolderHandler() {
|
||||
console.log("Uploading Folder")
|
||||
}
|
||||
function createFolderHandler() {
|
||||
console.log("Uploading Folder")
|
||||
}
|
||||
function newViewHandler() {
|
||||
console.log("Creating new view ...")
|
||||
}
|
||||
function preferencesHandler() {
|
||||
console.log("Preferences ...")
|
||||
}
|
||||
function about() {
|
||||
console.log("About ...")
|
||||
}
|
||||
function deleteHandler(){
|
||||
console.log("Delete ...")
|
||||
}
|
||||
function share(){
|
||||
console.log("Share ...")
|
||||
}
|
||||
function download(){
|
||||
console.log("Download ...")
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -88,7 +58,7 @@ function download(){
|
||||
<div class="actions-list">
|
||||
<LoginModal></LoginModal>
|
||||
<template v-if="showSearchInput">
|
||||
<input type="search" v-model="searchQuery" class="margin-input">
|
||||
<input type="search" v-model="searchQuery" class="margin-input" />
|
||||
</template>
|
||||
<!--
|
||||
|
||||
@@ -108,7 +78,6 @@ function download(){
|
||||
<a-button @click="about" type="text" class="action-button" :icon="h(InfoCircleOutlined)" />
|
||||
</a-tooltip>
|
||||
-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -136,25 +105,24 @@ function download(){
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
|
||||
.actions-container,
|
||||
.actions-list {
|
||||
gap: 6px;
|
||||
}
|
||||
}
|
||||
.margin-input{
|
||||
.margin-input {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.path {
|
||||
box-shadow: 0 0 0.5em rgba(0,0,0,.15);
|
||||
box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.15);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
flex: 0 0 1.5rem;
|
||||
order: 1;
|
||||
font-size: .9rem;
|
||||
font-size: 0.9rem;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,34 @@
|
||||
<template>
|
||||
<!--
|
||||
<button v-if="store.isUserLogged" @click="logout" class="action-button">
|
||||
Logout
|
||||
</button>
|
||||
<ModalDialog v-else title="Login">
|
||||
<form @submit="login">
|
||||
<label for="username">Username:</label
|
||||
><input
|
||||
id="username"
|
||||
name="username"
|
||||
autocomplete="username"
|
||||
required
|
||||
v-model="loginForm.username"
|
||||
/>
|
||||
<label for="password">Password:</label
|
||||
><input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
required
|
||||
v-model="loginForm.password"
|
||||
/>
|
||||
<h3 v-if="loginForm.error.length > 0" class="error-text">
|
||||
{{ loginForm.error }}
|
||||
</h3>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</ModalDialog>
|
||||
|
||||
<!--
|
||||
|
||||
<a-tooltip title="Login">
|
||||
<template v-if="DocumentStore.isUserLogged">
|
||||
@@ -11,81 +40,68 @@
|
||||
</a-tooltip>
|
||||
<a-modal v-model:open="DocumentStore.user.isOpenLoginModal" :confirm-loading="confirmLoading" okText="Login" @ok="login">
|
||||
<div class="login-container">
|
||||
<a-form :model="loginForm">
|
||||
<a-form-item label="Username" prop="username" :rules="[{ required: true, message: 'Please input your username!' }]">
|
||||
<a-input v-model:value="loginForm.username" />
|
||||
</a-form-item>
|
||||
<a-form-item label="Password" prop="password" :rules="[{ required: true, message: 'Please input your password!' }]">
|
||||
<a-input type="password" v-model:value="loginForm.password" />
|
||||
</a-form-item>
|
||||
<h3 v-if="loginForm.error.length > 0" class="error-text">{{loginForm.error}}</h3>
|
||||
</a-form>
|
||||
</div>
|
||||
</a-modal>
|
||||
-->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, h } from 'vue';
|
||||
import { useDocumentStore } from '@/stores/documents';
|
||||
import { loginUser, logoutUser } from '@/repositories/User';
|
||||
import type { ISimpleError } from '@/repositories/Client';
|
||||
import { ref } from 'vue'
|
||||
import { loginUser, logoutUser } from '@/repositories/User'
|
||||
import type { ISimpleError } from '@/repositories/Client'
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
|
||||
const DocumentStore = useDocumentStore();
|
||||
const confirmLoading = ref<boolean>(false);
|
||||
const confirmLoading = ref<boolean>(false)
|
||||
const store = useDocumentStore()
|
||||
|
||||
const showModal = () => {
|
||||
DocumentStore.user.isOpenLoginModal = true;
|
||||
};
|
||||
const logout = async () => {
|
||||
try {
|
||||
await logoutUser();
|
||||
} catch (error) {} finally {
|
||||
location.reload();
|
||||
}
|
||||
try {
|
||||
await logoutUser()
|
||||
} finally {
|
||||
location.reload()
|
||||
}
|
||||
}
|
||||
|
||||
const loginForm = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
error: '',
|
||||
});
|
||||
username: '',
|
||||
password: '',
|
||||
error: ''
|
||||
})
|
||||
|
||||
const login = async () => {
|
||||
try {
|
||||
loginForm.value.error = '';
|
||||
confirmLoading.value = true;
|
||||
const user = await loginUser(loginForm.value.username, loginForm.value.password);
|
||||
if(user){
|
||||
location.reload();
|
||||
}
|
||||
} catch (error) {
|
||||
const httpError = error as ISimpleError
|
||||
if(httpError.name){
|
||||
loginForm.value.error = httpError.message
|
||||
}
|
||||
}finally{
|
||||
confirmLoading.value = false;
|
||||
try {
|
||||
loginForm.value.error = ''
|
||||
confirmLoading.value = true
|
||||
const user = await loginUser(loginForm.value.username, loginForm.value.password)
|
||||
if (user) {
|
||||
location.reload()
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
const httpError = error as ISimpleError
|
||||
if (httpError.name) {
|
||||
loginForm.value.error = httpError.message
|
||||
}
|
||||
} finally {
|
||||
confirmLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 30vh;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.button-login {
|
||||
background-color: var(--secondary-color);
|
||||
color: var(--secondary-background);
|
||||
background-color: var(--secondary-color);
|
||||
color: var(--secondary-background);
|
||||
}
|
||||
.ant-btn-primary:not(:disabled):hover{
|
||||
background-color: var(--blue-color);
|
||||
|
||||
.ant-btn-primary:not(:disabled):hover {
|
||||
background-color: var(--blue-color);
|
||||
}
|
||||
.error-text {
|
||||
color :var(--red-color)
|
||||
color: var(--red-color);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<dialog ref="dialog">
|
||||
<h1 v-if="props.title">{{ props.title }}</h1>
|
||||
<div>
|
||||
<slot>
|
||||
Dialog with no content
|
||||
<button onclick="dialog.close()">OK</button>
|
||||
</slot>
|
||||
</div>
|
||||
</dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
const dialog = ref<HTMLDialogElement | null>(null)
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
title: string
|
||||
}>(),
|
||||
{
|
||||
title: ''
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
dialog.value!.showModal()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Style for the background */
|
||||
body:has(dialog[open])::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #0008;
|
||||
backdrop-filter: blur(0.2em);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/* Hide the dialog by default */
|
||||
dialog[open] {
|
||||
display: block;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0.2rem 0.2rem 1rem #000;
|
||||
padding: 1rem;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
dialog[open] > h1 {
|
||||
background: #00f;
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin: -1rem -1rem 0 -1rem;
|
||||
padding: 0.5rem 1rem 0.5rem 1rem;
|
||||
}
|
||||
|
||||
dialog[open] > div {
|
||||
padding: 1em 0;
|
||||
}
|
||||
</style>
|
||||
@@ -11,17 +11,17 @@
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
const documentStore = useDocumentStore()
|
||||
|
||||
function dismissUpload(key: number){
|
||||
function dismissUpload(key: number) {
|
||||
documentStore.deleteUploadingDocument(key)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.progress-container{
|
||||
.progress-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.close-button:hover{
|
||||
.close-button:hover {
|
||||
color: #b81414;
|
||||
}
|
||||
</style>
|
||||
@@ -1,14 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
import { h, ref } from 'vue';
|
||||
import { h, ref } from 'vue'
|
||||
|
||||
const fileUploadButton = ref()
|
||||
const documentStore = useDocumentStore();
|
||||
const open = (placement: any) => openNotification(placement);
|
||||
const documentStore = useDocumentStore()
|
||||
const open = (placement: any) => openNotification(placement)
|
||||
|
||||
const isNotificationOpen = ref(false);
|
||||
const isNotificationOpen = ref(false)
|
||||
const openNotification = (placement: any) => {
|
||||
if(!isNotificationOpen.value){
|
||||
if (!isNotificationOpen.value) {
|
||||
/*
|
||||
api.open({
|
||||
message: `Uploading documents`,
|
||||
@@ -17,62 +17,64 @@ const openNotification = (placement: any) => {
|
||||
duration: 0,
|
||||
onClose: () => { isNotificationOpen.value = false }
|
||||
});*/
|
||||
isNotificationOpen.value = true;
|
||||
isNotificationOpen.value = true
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function uploadFileHandler() {
|
||||
fileUploadButton.value.click()
|
||||
}
|
||||
|
||||
async function load(file: File, start: number, end: number): Promise<ArrayBuffer> {
|
||||
const reader = new FileReader();
|
||||
const load = new Promise<Event>((resolve) => (reader.onload = resolve));
|
||||
reader.readAsArrayBuffer(file.slice(start, end));
|
||||
const event = await load;
|
||||
const reader = new FileReader()
|
||||
const load = new Promise<Event>(resolve => (reader.onload = resolve))
|
||||
reader.readAsArrayBuffer(file.slice(start, end))
|
||||
const event = await load
|
||||
if (event.target && event.target instanceof FileReader) {
|
||||
return event.target.result as ArrayBuffer;
|
||||
return event.target.result as ArrayBuffer
|
||||
} else {
|
||||
throw new Error('Error loading file' );
|
||||
throw new Error('Error loading file')
|
||||
}
|
||||
}
|
||||
|
||||
async function sendChunk(file :File, start: number, end: number) {
|
||||
const ws = documentStore.wsUpload;
|
||||
if(ws){
|
||||
async function sendChunk(file: File, start: number, end: number) {
|
||||
const ws = documentStore.wsUpload
|
||||
if (ws) {
|
||||
const chunk = await load(file, start, end)
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
start: start,
|
||||
end: end
|
||||
}))
|
||||
})
|
||||
)
|
||||
ws.send(chunk)
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadFileChangeHandler(event: Event) {
|
||||
const target = event.target as HTMLInputElement;
|
||||
const target = event.target as HTMLInputElement
|
||||
const chunkSize = 1 << 20
|
||||
if (target && target.files && target.files.length > 0) {
|
||||
const file = target.files[0];
|
||||
const file = target.files[0]
|
||||
const numChunks = Math.ceil(file.size / chunkSize)
|
||||
const document = documentStore.pushUploadingDocuments(file.name)
|
||||
open('bottomRight')
|
||||
for (let i = 0; i < numChunks; i++) {
|
||||
const start = i * chunkSize
|
||||
const end = Math.min(file.size, start + chunkSize)
|
||||
const res = await sendChunk(file, start, end)
|
||||
console.log( 'progress: '+ ( ( 100 * (i + 1) ) / numChunks) )
|
||||
console.log( 'Num Chunks: '+ numChunks )
|
||||
documentStore.updateUploadingDocuments( document.key, ((100 * (i + 1) ) / numChunks))
|
||||
const res = await sendChunk(file, start, end)
|
||||
console.log('progress: ' + (100 * (i + 1)) / numChunks)
|
||||
console.log('Num Chunks: ' + numChunks)
|
||||
documentStore.updateUploadingDocuments(document.key, (100 * (i + 1)) / numChunks)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
(buttons here)
|
||||
<!--
|
||||
|
||||
<a-tooltip title="Upload files from disk">
|
||||
@@ -84,7 +86,7 @@ async function uploadFileChangeHandler(event: Event) {
|
||||
</template>
|
||||
<style scoped>
|
||||
/* Extends styles from HeaderMain.vue too */
|
||||
.upload-input{
|
||||
.upload-input {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -7,7 +7,7 @@ import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
app.config.errorHandler = (err) => {
|
||||
app.config.errorHandler = err => {
|
||||
/* handle error */
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
@@ -4,25 +4,27 @@ export const baseURL = import.meta.env.VITE_URL_DOCUMENT
|
||||
class ClientClass {
|
||||
async post(url: string, data?: Record<string, any>): Promise<any> {
|
||||
const res = await fetch(`${baseURL}/`, {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
headers: {
|
||||
accept: 'application/json',
|
||||
"content-type": 'application/json',
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: data !== undefined ? JSON.stringify(data) : undefined,
|
||||
body: data !== undefined ? JSON.stringify(data) : undefined
|
||||
})
|
||||
return await res.json()
|
||||
const msg = await res.json()
|
||||
if ('error' in msg) throw new SimpleError(msg.error.code, msg.error.message)
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
export const Client = new ClientClass()
|
||||
export interface ISimpleError extends Error {
|
||||
code : number
|
||||
code: number
|
||||
}
|
||||
|
||||
class SimpleError extends Error implements ISimpleError {
|
||||
code : number
|
||||
constructor(code: number, message:string) {
|
||||
code: number
|
||||
constructor(code: number, message: string) {
|
||||
super(message)
|
||||
this.code = code
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { DocumentStore } from '@/stores/documents'
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
|
||||
export type FUID = string;
|
||||
export type FUID = string
|
||||
|
||||
type BaseDocument = {
|
||||
name: string
|
||||
key: FUID
|
||||
};
|
||||
}
|
||||
|
||||
export type FolderDocument = BaseDocument & {
|
||||
type: 'folder' | 'file'
|
||||
@@ -14,17 +14,17 @@ export type FolderDocument = BaseDocument & {
|
||||
sizedisp: string
|
||||
mtime: number
|
||||
modified: string
|
||||
};
|
||||
}
|
||||
|
||||
export type Document = FolderDocument
|
||||
|
||||
export type errorEvent = {
|
||||
error: {
|
||||
code : number;
|
||||
message: string;
|
||||
redirect: string;
|
||||
code: number
|
||||
message: string
|
||||
redirect: string
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Raw types the backend /api/watch sends us
|
||||
|
||||
@@ -54,41 +54,41 @@ export type UpdateEntry = {
|
||||
|
||||
export const url_document_watch_ws = '/api/watch'
|
||||
export const url_document_upload_ws = '/api/upload'
|
||||
export const url_document_get ='/files'
|
||||
export const url_document_get = '/files'
|
||||
|
||||
export class DocumentHandler {
|
||||
constructor( private store: DocumentStore = useDocumentStore() ) {
|
||||
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this);
|
||||
constructor(private store: DocumentStore = useDocumentStore()) {
|
||||
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this)
|
||||
}
|
||||
|
||||
handleWebSocketMessage(event: MessageEvent) {
|
||||
const msg = JSON.parse(event.data);
|
||||
const msg = JSON.parse(event.data)
|
||||
switch (true) {
|
||||
case !!msg.root:
|
||||
this.handleRootMessage(msg);
|
||||
break;
|
||||
this.handleRootMessage(msg)
|
||||
break
|
||||
case !!msg.update:
|
||||
this.handleUpdateMessage(msg);
|
||||
break;
|
||||
this.handleUpdateMessage(msg)
|
||||
break
|
||||
case !!msg.error:
|
||||
this.handleError(msg);
|
||||
break;
|
||||
this.handleError(msg)
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private handleRootMessage({ root }: { root: DirEntry }) {
|
||||
if (this.store && this.store.root) {
|
||||
this.store.user.isLoggedIn = true;
|
||||
this.store.root = root;
|
||||
this.store.user.isLoggedIn = true
|
||||
this.store.root = root
|
||||
}
|
||||
}
|
||||
private handleUpdateMessage(updateData: { update: UpdateEntry[] }) {
|
||||
let node: DirEntry = this.store.root;
|
||||
let node: DirEntry = this.store.root
|
||||
for (const elem of updateData.update) {
|
||||
if (elem.deleted) {
|
||||
delete node.dir[elem.name]
|
||||
break // Deleted elements can't have further children
|
||||
break // Deleted elements can't have further children
|
||||
}
|
||||
if (elem.name !== undefined) {
|
||||
// @ts-ignore
|
||||
@@ -100,31 +100,31 @@ export class DocumentHandler {
|
||||
if (elem.dir !== undefined) node.dir = elem.dir
|
||||
}
|
||||
}
|
||||
private handleError(msg: errorEvent){
|
||||
if(msg.error.code === 401){
|
||||
this.store.user.isOpenLoginModal = true;
|
||||
this.store.user.isLoggedIn = false;
|
||||
private handleError(msg: errorEvent) {
|
||||
if (msg.error.code === 401) {
|
||||
this.store.user.isOpenLoginModal = true
|
||||
this.store.user.isLoggedIn = false
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DocumentUploadHandler {
|
||||
constructor( private store: DocumentStore = useDocumentStore() ) {
|
||||
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this);
|
||||
constructor(private store: DocumentStore = useDocumentStore()) {
|
||||
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this)
|
||||
}
|
||||
|
||||
handleWebSocketMessage(event: MessageEvent) {
|
||||
const msg = JSON.parse(event.data);
|
||||
const msg = JSON.parse(event.data)
|
||||
switch (true) {
|
||||
case !!msg.written:
|
||||
this.handleWrittenMessage(msg);
|
||||
break;
|
||||
this.handleWrittenMessage(msg)
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private handleWrittenMessage(msg : { written : number}) {
|
||||
private handleWrittenMessage(msg: { written: number }) {
|
||||
// if (this.store && this.store.root) this.store.root = root;
|
||||
console.log('Written message', msg.written)
|
||||
}
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
|
||||
import Client from '@/repositories/Client'
|
||||
export const url_login = '/login'
|
||||
export const url_logout = '/logout '
|
||||
|
||||
export async function loginUser(username : string, password: string){
|
||||
try {
|
||||
const user = await Client.post(url_login, {
|
||||
username, password
|
||||
})
|
||||
return user;
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
export async function loginUser(username: string, password: string) {
|
||||
const user = await Client.post(url_login, {
|
||||
username,
|
||||
password
|
||||
})
|
||||
return user
|
||||
}
|
||||
export async function logoutUser() {
|
||||
const data = await Client.post(url_logout)
|
||||
return data
|
||||
}
|
||||
export async function logoutUser(){
|
||||
try {
|
||||
const data = await Client.post(url_logout)
|
||||
return data;
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
function createWebSocket(url: string, eventHandler: (event: MessageEvent) => void) {
|
||||
const urlObject = new URL(url, location.origin.replace( /^http/, 'ws'));
|
||||
const webSocket = new WebSocket(urlObject);
|
||||
webSocket.onmessage = eventHandler;
|
||||
return webSocket;
|
||||
const urlObject = new URL(url, location.origin.replace(/^http/, 'ws'))
|
||||
const webSocket = new WebSocket(urlObject)
|
||||
webSocket.onmessage = eventHandler
|
||||
return webSocket
|
||||
}
|
||||
|
||||
export default createWebSocket
|
||||
export default createWebSocket
|
||||
@@ -7,8 +7,8 @@ const router = createRouter({
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'explorer',
|
||||
component: ExplorerView,
|
||||
},
|
||||
component: ExplorerView
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
import type { Document, DirEntry, FileEntry, FUID, DirList } from '@/repositories/Document'
|
||||
import type {
|
||||
Document,
|
||||
DirEntry,
|
||||
FileEntry,
|
||||
FUID,
|
||||
DirList
|
||||
} from '@/repositories/Document'
|
||||
import { formatSize, formatUnixDate } from '@/utils'
|
||||
import { defineStore } from 'pinia'
|
||||
// @ts-ignore
|
||||
import { localeIncludes } from 'locale-includes'
|
||||
|
||||
type FileData = { id: string, mtime: number, size: number, dir: DirectoryData};
|
||||
type FileData = { id: string; mtime: number; size: number; dir: DirectoryData }
|
||||
type DirectoryData = {
|
||||
[filename: string]: FileData;
|
||||
};
|
||||
[filename: string]: FileData
|
||||
}
|
||||
type User = {
|
||||
isOpenLoginModal: boolean,
|
||||
isLoggedIn : boolean,
|
||||
isOpenLoginModal: boolean
|
||||
isLoggedIn: boolean
|
||||
}
|
||||
|
||||
export type DocumentStore = {
|
||||
root: DirEntry,
|
||||
document: Document[],
|
||||
selected: Set<FUID>,
|
||||
uploadingDocuments: Array<{key: number, name: string, progress: number}>,
|
||||
uploadCount: number,
|
||||
wsWatch: WebSocket | undefined,
|
||||
wsUpload: WebSocket | undefined,
|
||||
user: User,
|
||||
error: string,
|
||||
root: DirEntry
|
||||
document: Document[]
|
||||
selected: Set<FUID>
|
||||
uploadingDocuments: Array<{ key: number; name: string; progress: number }>
|
||||
uploadCount: number
|
||||
wsWatch: WebSocket | undefined
|
||||
wsUpload: WebSocket | undefined
|
||||
user: User
|
||||
error: string
|
||||
}
|
||||
|
||||
export const useDocumentStore = defineStore({
|
||||
@@ -42,9 +48,9 @@ export const useDocumentStore = defineStore({
|
||||
actions: {
|
||||
updateTable(matched: DirList) {
|
||||
// Transform data
|
||||
const dataMapped = []
|
||||
const dataMapped = []
|
||||
for (const [name, attr] of Object.entries(matched)) {
|
||||
const {id, size, mtime} = attr
|
||||
const { id, size, mtime } = attr
|
||||
const element: Document = {
|
||||
name,
|
||||
key: id,
|
||||
@@ -52,30 +58,37 @@ export const useDocumentStore = defineStore({
|
||||
sizedisp: formatSize(size),
|
||||
mtime,
|
||||
modified: formatUnixDate(mtime),
|
||||
type: "dir" in attr ? 'folder' : 'file',
|
||||
type: 'dir' in attr ? 'folder' : 'file'
|
||||
}
|
||||
dataMapped.push(element)
|
||||
}
|
||||
// Pre sort directory entries folders first then files, names in natural ordering
|
||||
dataMapped.sort((a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "folder" ? -1 : 1)
|
||||
dataMapped.sort((a, b) =>
|
||||
a.type === b.type ? a.name.localeCompare(b.name) : a.type === 'folder' ? -1 : 1
|
||||
)
|
||||
this.document = dataMapped
|
||||
},
|
||||
setFilter(filter: string){
|
||||
function traverseDir(data: DirEntry | FileEntry, path: string){
|
||||
if (!("dir" in data)) return
|
||||
setFilter(filter: string) {
|
||||
function traverseDir(data: DirEntry | FileEntry, path: string) {
|
||||
if (!('dir' in data)) return
|
||||
for (const [name, attr] of Object.entries(data.dir)) {
|
||||
const fullname = `${path}/${name}`
|
||||
if (localeIncludes(name, filter, {usage: "search", sensitivity: "base"})) {
|
||||
matched[fullname.slice(1)] = attr // No initial slash on name
|
||||
if (
|
||||
localeIncludes(name, filter, {
|
||||
usage: 'search',
|
||||
sensitivity: 'base'
|
||||
})
|
||||
) {
|
||||
matched[fullname.slice(1)] = attr // No initial slash on name
|
||||
}
|
||||
traverseDir(attr, fullname)
|
||||
}
|
||||
}
|
||||
const matched: any = {}
|
||||
traverseDir(this.root, "")
|
||||
traverseDir(this.root, '')
|
||||
this.updateTable(matched)
|
||||
},
|
||||
setActualDocument(location: string){
|
||||
setActualDocument(location: string) {
|
||||
location = decodeURIComponent(location)
|
||||
let data: FileEntry | DirEntry = this.root
|
||||
const actualDirArr = []
|
||||
@@ -83,27 +96,32 @@ export const useDocumentStore = defineStore({
|
||||
// Navigate to target folder
|
||||
for (const dirname of location.split('/').slice(1)) {
|
||||
if (!dirname) continue
|
||||
if (!("dir" in data)) throw Error("Target folder not available")
|
||||
if (!('dir' in data)) throw Error('Target folder not available')
|
||||
actualDirArr.push(dirname)
|
||||
data = data.dir[dirname]
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Cannot show requested folder", location, actualDirArr.join('/'), error)
|
||||
console.error(
|
||||
'Cannot show requested folder',
|
||||
location,
|
||||
actualDirArr.join('/'),
|
||||
error
|
||||
)
|
||||
}
|
||||
if (!("dir" in data)) {
|
||||
if (!('dir' in data)) {
|
||||
// Target folder not available
|
||||
this.document = []
|
||||
return
|
||||
}
|
||||
this.updateTable(data.dir)
|
||||
},
|
||||
updateUploadingDocuments(key: number, progress: number){
|
||||
updateUploadingDocuments(key: number, progress: number) {
|
||||
for (const d of this.uploadingDocuments) {
|
||||
if(d.key === key) d.progress = progress
|
||||
if (d.key === key) d.progress = progress
|
||||
}
|
||||
},
|
||||
pushUploadingDocuments(name: string){
|
||||
this.uploadCount++;
|
||||
pushUploadingDocuments(name: string) {
|
||||
this.uploadCount++
|
||||
const document = {
|
||||
key: this.uploadCount,
|
||||
name: name,
|
||||
@@ -112,21 +130,21 @@ export const useDocumentStore = defineStore({
|
||||
this.uploadingDocuments.push(document)
|
||||
return document
|
||||
},
|
||||
deleteUploadingDocument(key: number){
|
||||
this.uploadingDocuments = this.uploadingDocuments.filter((e)=> e.key !== key)
|
||||
deleteUploadingDocument(key: number) {
|
||||
this.uploadingDocuments = this.uploadingDocuments.filter(e => e.key !== key)
|
||||
},
|
||||
updateModified() {
|
||||
for (const d of this.document) {
|
||||
if ("mtime" in d) d.modified = formatUnixDate(d.mtime)
|
||||
if ('mtime' in d) d.modified = formatUnixDate(d.mtime)
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
mainDocument(): Document[] {
|
||||
return this.document;
|
||||
return this.document
|
||||
},
|
||||
isUserLogged(): boolean{
|
||||
isUserLogged(): boolean {
|
||||
return this.user.isLoggedIn
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -1,68 +1,75 @@
|
||||
export function determineFileType(inputString: string): "file" | "folder" {
|
||||
if (inputString.includes('.') && !inputString.endsWith('.')) {
|
||||
return 'file';
|
||||
} else {
|
||||
return 'folder';
|
||||
}
|
||||
export function determineFileType(inputString: string): 'file' | 'folder' {
|
||||
if (inputString.includes('.') && !inputString.endsWith('.')) {
|
||||
return 'file'
|
||||
} else {
|
||||
return 'folder'
|
||||
}
|
||||
}
|
||||
|
||||
export function formatSize(size: number) {
|
||||
if (size === 0) return 'empty'
|
||||
for (const unit of [null, 'kB', 'MB', 'GB', 'TB', 'PB', 'EB']) {
|
||||
if (size < 1e4) return size.toLocaleString().replace(',', '\u202F') + (unit ? `\u202F${unit}` : '')
|
||||
if (size < 1e4)
|
||||
return (
|
||||
size.toLocaleString().replace(',', '\u202F') + (unit ? `\u202F${unit}` : '')
|
||||
)
|
||||
size = Math.round(size / 1000)
|
||||
}
|
||||
return "huge"
|
||||
return 'huge'
|
||||
}
|
||||
|
||||
export function formatUnixDate(t: number) {
|
||||
const date = new Date(t * 1000)
|
||||
const now = new Date()
|
||||
const diff = date.getTime() - now.getTime()
|
||||
const formatter = new Intl.RelativeTimeFormat('en', { numeric:
|
||||
'auto' })
|
||||
const formatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
|
||||
if (Math.abs(diff) <= 5000) {
|
||||
return 'now'
|
||||
return 'now'
|
||||
}
|
||||
if (Math.abs(diff) <= 60000) {
|
||||
return formatter.format(Math.round(diff / 1000), 'second')
|
||||
return formatter.format(Math.round(diff / 1000), 'second')
|
||||
}
|
||||
|
||||
if (Math.abs(diff) <= 3600000) {
|
||||
return formatter.format(Math.round(diff / 60000), 'minute')
|
||||
return formatter.format(Math.round(diff / 60000), 'minute')
|
||||
}
|
||||
|
||||
if (Math.abs(diff) <= 86400000) {
|
||||
return formatter.format(Math.round(diff / 3600000), 'hour')
|
||||
return formatter.format(Math.round(diff / 3600000), 'hour')
|
||||
}
|
||||
|
||||
if (Math.abs(diff) <= 604800000) {
|
||||
return formatter.format(Math.round(diff / 86400000), 'day')
|
||||
return formatter.format(Math.round(diff / 86400000), 'day')
|
||||
}
|
||||
|
||||
return date.toLocaleDateString(undefined, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' })
|
||||
return date.toLocaleDateString(undefined, {
|
||||
weekday: 'short',
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
})
|
||||
}
|
||||
|
||||
export function getFileExtension(filename: string) {
|
||||
const parts = filename.split(".");
|
||||
const parts = filename.split('.')
|
||||
if (parts.length > 1) {
|
||||
return parts[parts.length - 1];
|
||||
return parts[parts.length - 1]
|
||||
} else {
|
||||
return ""; // No hay extensión
|
||||
return '' // No hay extensión
|
||||
}
|
||||
}
|
||||
export function getFileType(extension: string): string {
|
||||
const videoExtensions = ["mp4", "avi", "mkv", "mov"];
|
||||
const imageExtensions = ["jpg", "jpeg", "png", "gif"];
|
||||
const pdfExtensions = ["pdf"];
|
||||
const videoExtensions = ['mp4', 'avi', 'mkv', 'mov']
|
||||
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif']
|
||||
const pdfExtensions = ['pdf']
|
||||
|
||||
if (videoExtensions.includes(extension)) {
|
||||
return "video";
|
||||
return 'video'
|
||||
} else if (imageExtensions.includes(extension)) {
|
||||
return "image";
|
||||
return 'image'
|
||||
} else if (pdfExtensions.includes(extension)) {
|
||||
return "pdf";
|
||||
return 'pdf'
|
||||
} else {
|
||||
return "unknown";
|
||||
return 'unknown'
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@
|
||||
<script setup lang="ts">
|
||||
import { watchEffect } from 'vue'
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
import Router from '@/router/index';
|
||||
import FileExplorer from '@/components/FileExplorer.vue';
|
||||
import Router from '@/router/index'
|
||||
import FileExplorer from '@/components/FileExplorer.vue'
|
||||
|
||||
const documentStore = useDocumentStore()
|
||||
|
||||
@@ -26,21 +26,23 @@ watchEffect(async () => {
|
||||
documentStore.setActualDocument(path.toString())
|
||||
})
|
||||
|
||||
function beforeEnter(el) {
|
||||
el.style.transform = 'translateX(100%)'
|
||||
function beforeEnter(el: Element) {
|
||||
const elem = el as HTMLElement
|
||||
elem.style.transform = 'translateX(100%)'
|
||||
}
|
||||
|
||||
function enter(el, done) {
|
||||
function enter(el: Element, done: () => void) {
|
||||
const elem = el as HTMLElement
|
||||
setTimeout(() => {
|
||||
el.style.transform = 'translateX(0)'
|
||||
elem.style.transform = 'translateX(0)'
|
||||
done()
|
||||
}, 0)
|
||||
}
|
||||
function leave(el, done) {
|
||||
el.style.transform = 'translateX(-100%)'
|
||||
function leave(el: Element, done: () => void) {
|
||||
const elem = el as HTMLElement
|
||||
elem.style.transform = 'translateX(-100%)'
|
||||
setTimeout(done, 300) // Assuming 300ms is your transition duration
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -6,6 +6,7 @@ import vue from '@vitejs/plugin-vue'
|
||||
// @ts-ignore
|
||||
import pluginRewriteAll from 'vite-plugin-rewrite-all'
|
||||
import svgLoader from 'vite-svg-loader'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
|
||||
// Development mode:
|
||||
// npm run dev # Run frontend that proxies to dev_backend
|
||||
@@ -21,7 +22,8 @@ export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
pluginRewriteAll(),
|
||||
svgLoader(),
|
||||
svgLoader(), // import svg files
|
||||
Components(), // auto import components
|
||||
],
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
var Fi=Object.defineProperty;var ji=(e,t,n)=>t in e?Fi(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var ur=(e,t,n)=>(ji(e,typeof t!="symbol"?t+"":t,n),n);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const o of r)if(o.type==="childList")for(const i of o.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&s(i)}).observe(document,{childList:!0,subtree:!0});function n(r){const o={};return r.integrity&&(o.integrity=r.integrity),r.referrerPolicy&&(o.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?o.credentials="include":r.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function s(r){if(r.ep)return;r.ep=!0;const o=n(r);fetch(r.href,o)}})();function Is(e,t){const n=Object.create(null),s=e.split(",");for(let r=0;r<s.length;r++)n[s[r]]=!0;return t?r=>!!n[r.toLowerCase()]:r=>!!n[r]}const ie={},It=[],De=()=>{},Di=()=>!1,Bi=/^on[^a-z]/,$n=e=>Bi.test(e),ks=e=>e.startsWith("onUpdate:"),pe=Object.assign,Ls=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},Hi=Object.prototype.hasOwnProperty,Q=(e,t)=>Hi.call(e,t),F=Array.isArray,kt=e=>dn(e)==="[object Map]",Nn=e=>dn(e)==="[object Set]",ar=e=>dn(e)==="[object Date]",K=e=>typeof e=="function",de=e=>typeof e=="string",tn=e=>typeof e=="symbol",re=e=>e!==null&&typeof e=="object",mo=e=>re(e)&&K(e.then)&&K(e.catch),go=Object.prototype.toString,dn=e=>go.call(e),Ui=e=>dn(e).slice(8,-1),_o=e=>dn(e)==="[object Object]",$s=e=>de(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,wn=Is(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Fn=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},Ki=/-(\w)/g,qe=Fn(e=>e.replace(Ki,(t,n)=>n?n.toUpperCase():"")),Wi=/\B([A-Z])/g,St=Fn(e=>e.replace(Wi,"-$1").toLowerCase()),jn=Fn(e=>e.charAt(0).toUpperCase()+e.slice(1)),es=Fn(e=>e?`on${jn(e)}`:""),nn=(e,t)=>!Object.is(e,t),xn=(e,t)=>{for(let n=0;n<e.length;n++)e[n](t)},Rn=(e,t,n)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},fs=e=>{const t=parseFloat(e);return isNaN(t)?e:t},Vi=e=>{const t=de(e)?Number(e):NaN;return isNaN(t)?e:t};let fr;const ds=()=>fr||(fr=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Ns(e){if(F(e)){const t={};for(let n=0;n<e.length;n++){const s=e[n],r=de(s)?Qi(s):Ns(s);if(r)for(const o in r)t[o]=r[o]}return t}else{if(de(e))return e;if(re(e))return e}}const zi=/;(?![^(]*\))/g,qi=/:([^]+)/,Ji=/\/\*[^]*?\*\//g;function Qi(e){const t={};return e.replace(Ji,"").split(zi).forEach(n=>{if(n){const s=n.split(qi);s.length>1&&(t[s[0].trim()]=s[1].trim())}}),t}function Et(e){let t="";if(de(e))t=e;else if(F(e))for(let n=0;n<e.length;n++){const s=Et(e[n]);s&&(t+=s+" ")}else if(re(e))for(const n in e)e[n]&&(t+=n+" ");return t.trim()}const Yi="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",Xi=Is(Yi);function vo(e){return!!e||e===""}function Zi(e,t){if(e.length!==t.length)return!1;let n=!0;for(let s=0;n&&s<e.length;s++)n=Dn(e[s],t[s]);return n}function Dn(e,t){if(e===t)return!0;let n=ar(e),s=ar(t);if(n||s)return n&&s?e.getTime()===t.getTime():!1;if(n=tn(e),s=tn(t),n||s)return e===t;if(n=F(e),s=F(t),n||s)return n&&s?Zi(e,t):!1;if(n=re(e),s=re(t),n||s){if(!n||!s)return!1;const r=Object.keys(e).length,o=Object.keys(t).length;if(r!==o)return!1;for(const i in e){const l=e.hasOwnProperty(i),c=t.hasOwnProperty(i);if(l&&!c||!l&&c||!Dn(e[i],t[i]))return!1}}return String(e)===String(t)}function yo(e,t){return e.findIndex(n=>Dn(n,t))}const Lt=e=>de(e)?e:e==null?"":F(e)||re(e)&&(e.toString===go||!K(e.toString))?JSON.stringify(e,bo,2):String(e),bo=(e,t)=>t&&t.__v_isRef?bo(e,t.value):kt(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[s,r])=>(n[`${s} =>`]=r,n),{})}:Nn(t)?{[`Set(${t.size})`]:[...t.values()]}:re(t)&&!F(t)&&!_o(t)?String(t):t;let Ae;class Eo{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=Ae,!t&&Ae&&(this.index=(Ae.scopes||(Ae.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=Ae;try{return Ae=this,t()}finally{Ae=n}}}on(){Ae=this}off(){Ae=this.parent}stop(t){if(this._active){let n,s;for(n=0,s=this.effects.length;n<s;n++)this.effects[n].stop();for(n=0,s=this.cleanups.length;n<s;n++)this.cleanups[n]();if(this.scopes)for(n=0,s=this.scopes.length;n<s;n++)this.scopes[n].stop(!0);if(!this.detached&&this.parent&&!t){const r=this.parent.scopes.pop();r&&r!==this&&(this.parent.scopes[this.index]=r,r.index=this.index)}this.parent=void 0,this._active=!1}}}function wo(e){return new Eo(e)}function Gi(e,t=Ae){t&&t.active&&t.effects.push(e)}function xo(){return Ae}function el(e){Ae&&Ae.cleanups.push(e)}const Fs=e=>{const t=new Set(e);return t.w=0,t.n=0,t},Co=e=>(e.w&at)>0,So=e=Line truncated
|
||||
* pinia v2.1.6
|
||||
* (c) 2023 Eduardo San Martin Morote
|
||||
* @license MIT
|
||||
*/let yi;const Xn=e=>yi=e,bi=Symbol();function Rs(e){return e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"&&typeof e.toJSON!="function"}var Zt;(function(e){e.direct="direct",e.patchObject="patch object",e.patchFunction="patch function"})(Zt||(Zt={}));function Cu(){const e=wo(!0),t=e.run(()=>Me({}));let n=[],s=[];const r=Hn({install(o){Xn(r),r._a=o,o.provide(bi,r),o.config.globalProperties.$pinia=r,s.forEach(i=>n.push(i)),s=[]},use(o){return!this._a&&!xu?s.push(o):n.push(o),this},_p:n,_a:null,_e:e,_s:new Map,state:t});return r}const Ei=()=>{};function Yr(e,t,n,s=Ei){e.push(t);const r=()=>{const o=e.indexOf(t);o>-1&&(e.splice(o,1),s())};return!n&&xo()&&el(r),r}function Tt(e,...t){e.slice().forEach(n=>{n(...t)})}const Su=e=>e();function Ps(e,t){e instanceof Map&&t instanceof Map&&t.forEach((n,s)=>e.set(s,n)),e instanceof Set&&t instanceof Set&&t.forEach(e.add,e);for(const n in t){if(!t.hasOwnProperty(n))continue;const s=t[n],r=e[n];Rs(r)&&Rs(s)&&e.hasOwnProperty(n)&&!ae(s)&&!ct(s)?e[n]=Ps(r,s):e[n]=s}return e}const Ru=Symbol();function Pu(e){return!Rs(e)||!e.hasOwnProperty(Ru)}const{assign:rt}=Object;function Ou(e){return!!(ae(e)&&e.effect)}function Au(e,t,n,s){const{state:r,actions:o,getters:i}=t,l=n.state.value[e];let c;function u(){l||(n.state.value[e]=r?r():{});const f=Ml(n.state.value[e]);return rt(f,o,Object.keys(i||{}).reduce((h,p)=>(h[p]=Hn(ye(()=>{Xn(n);const _=n._s.get(e);return i[p].call(_,_)})),h),{}))}return c=wi(e,u,t,n,s,!0),c}function wi(e,t,n={},s,r,o){let i;const l=rt({actions:{}},n),c={deep:!0};let u,f,h=[],p=[],_;const b=s.state.value[e];!o&&!b&&(s.state.value[e]={}),Me({});let w;function P(M){let B;u=f=!1,typeof M=="function"?(M(s.state.value[e]),B={type:Zt.patchFunction,storeId:e,events:_}):(Ps(s.state.value[e],M),B={type:Zt.patchObject,payload:M,storeId:e,events:_});const W=w=Symbol();Vs().then(()=>{w===W&&(u=!0)}),f=!0,Tt(h,B,s.state.value[e])}const T=o?function(){const{state:B}=n,W=B?B():{};this.$patch(ne=>{rt(ne,W)})}:Ei;function k(){i.stop(),h=[],p=[],s._s.delete(e)}function H(M,B){return function(){Xn(s);const W=Array.from(arguments),ne=[],I=[];function Y(q){ne.push(q)}function ve(q){I.push(q)}Tt(p,{args:W,name:M,store:V,after:Y,onError:ve});let xe;try{xe=B.apply(this&&this.$id===e?this:V,W)}catch(q){throw Tt(I,q),q}return xe instanceof Promise?xe.then(q=>(Tt(ne,q),q)).catch(q=>(Tt(I,q),Promise.reject(q))):(Tt(ne,xe),xe)}}const $={_p:s,$id:e,$onAction:Yr.bind(null,p),$patch:P,$reset:T,$subscribe(M,B={}){const W=Yr(h,M,B.detached,()=>ne()),ne=i.run(()=>Jt(()=>s.state.value[e],I=>{(B.flush==="sync"?f:u)&&M({storeId:e,type:Zt.direct,events:_},I)},rt({},c,B)));return W},$dispose:k},V=hn($);s._s.set(e,V);const ce=s._a&&s._a.runWithContext||Su,ue=s._e.run(()=>(i=wo(),ce(()=>i.run(t))));for(const M in ue){const B=ue[M];if(ae(B)&&!Ou(B)||ct(B))o||(b&&Pu(B)&&(ae(B)?B.value=b[M]:Ps(B,b[M])),s.state.value[e][M]=B);else if(typeof B=="function"){const W=H(M,B);ue[M]=W,l.actions[M]=B}}return rt(V,ue),rt(J(V),ue),Object.defineProperty(V,"$state",{get:()=>s.state.value[e],set:M=>{P(B=>{rt(B,M)})}}),s._p.forEach(M=>{rt(V,i.run(()=>M({store:V,app:s._a,pinia:s,options:l})))}),b&&o&&n.hydrate&&n.hydrate(V.$state,b),u=!0,f=!0,V}function Tu(e,t,n){let s,r;const o=typeof t=="function";typeof e=="string"?(s=e,r=o?n:t):(r=e,s=e.id);function i(l,c){const u=Ec();return l=l||(u?ze(bi,null):null),l&&Xn(l),l=yi,l._s.has(s)||(o?wi(s,t,r,l):Au(s,r,l)),l._s.get(s)}return i.$id=s,i}/*!
|
||||
* vue-router v4.2.4
|
||||
* (c) 2023 Eduardo San Martin Morote
|
||||
* @license MIT
|
||||
*/const Mt=typeof window<"u";function Mu(e){return e.__esModule||e[Symbol.toStringTag]==="Module"}const ee=Object.assign;function cs(e,t){const n={};for(const s in t){const r=t[s];n[s]=Be(r)?r.map(e):e(r)}return n}const Gt=()=>{},Be=Array.isArray,Iu=/\/$/,ku=e=>e.replace(Iu,"");function us(e,t,n="/"){let s,r={},o="",i="";const l=t.indexOf("#");let c=t.indexOf("?");return l<c&&l>=0&&(c=-1),c>-1&&(s=t.slice(0,c),o=t.slice(c+1,l>-1?l:t.length),r=e(o)),l>-1&&(s=s||t.slice(0,l),i=t.slice(l,t.length)),s=Fu(s??t,n),{fullPath:s+(o&&"?")+o+i,path:s,query:r,hash:i}}function Lu(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function Xr(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function $u(e,t,n){const s=t.matched.length-1,r=n.matched.length-1;return s>-1&&s===r&&jt(t.matched[s],n.matched[r])&&xi(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function jt(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function xi(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!Nu(e[n],t[n]))return!1;return!0}function Nu(e,t){return Be(e)?Zr(e,t):Be(t)?Zr(t,e):e===t}function Zr(e,t){return Be(t)?e.length===t.length&&e.every((n,s)=>n===t[s]):e.length===1&&e[0]===t}function Fu(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),s=e.split("/"),r=s[s.length-1];(r===".."||r===".")&&s.push("");let o=n.length-1,i,l;for(i=0;i<s.length;i++)if(l=s[i],l!==".")if(l==="..")o>1&&o--;else break;return n.slice(0,o).join("/")+"/"+s.slice(i-(i===s.length?1:0)).join("/")}var an;(function(e){e.pop="pop",e.push="push"})(an||(an={}));var en;(function(e){e.back="back",e.forward="forward",e.unknown=""})(en||(en={}));function ju(e){if(!e)if(Mt){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),ku(e)}const Du=/^[^#]+#/;function Bu(e,t){return e.replace(Du,"#")+t}function Hu(e,t){const n=document.documentElement.getBoundingClientRect(),s=e.getBoundingClientRect();return{behavior:t.behavior,left:s.left-n.left-(t.left||0),top:s.top-n.top-(t.top||0)}}const Zn=()=>({left:window.pageXOffset,top:window.pageYOffset});function Uu(e){let t;if("el"in e){const n=e.el,s=typeof n=="string"&&n.startsWith("#"),r=typeof n=="string"?s?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!r)return;t=Hu(r,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.pageXOffset,t.top!=null?t.top:window.pageYOffset)}function Gr(e,t){return(history.state?history.state.position-t:-1)+e}const Os=new Map;function Ku(e,t){Os.set(e,t)}function Wu(e){const t=Os.get(e);return Os.delete(e),t}let Vu=()=>location.protocol+"//"+location.host;function Ci(e,t){const{pathname:n,search:s,hash:r}=t,o=e.indexOf("#");if(o>-1){let l=r.includes(e.slice(o))?e.slice(o).length:1,c=r.slice(l);return c[0]!=="/"&&(c="/"+c),Xr(c,"")}return Xr(n,e)+s+r}function zu(e,t,n,s){let r=[],o=[],i=null;const l=({state:p})=>{const _=Ci(e,location),b=n.value,w=t.value;let P=0;if(p){if(n.value=_,t.value=p,i&&i===b){i=null;return}P=w?p.position-w.position:0}else s(_);r.forEach(T=>{T(n.value,b,{delta:P,type:an.pop,direction:P?P>0?en.forward:en.back:en.unknown})})};function c(){i=n.value}function u(p){r.push(p);const _=()=>{const b=r.indexOf(p);b>-1&&r.splice(b,1)};return o.push(_),_}function f(){const{history:p}=window;p.state&&p.replaceState(ee({},p.state,{scroll:Zn()}),"")}function h(){for(const p of o)p();o=[],window.removeEventListener("popstate",l),window.removeEventListener("beforeunload",f)}return window.addEventListener("popstate",l),window.addEventListener("beforeunload",f,{passive:!0}),{pauseListeners:c,listen:u,destroy:h}}function eo(e,t,n,s=!1,r=!1){return{back:e,current:t,forward:n,replaced:s,position:window.history.length,scroll:r?Zn():null}}function qu(e){const{history:t,location:n}=window,s={value:Ci(e,n)},r={value:t.state};r.value||o(s.value,{back:null,current:s.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function o(c,u,f){const h=e.indexOf("#"),p=h>-1?(n.host&&document.querySelector("base")?e:e.slice(h))+c:Vu()+e+c;try{t[f?"replaceState":"pushState"](u,"",p),r.value=u}catch(_){console.error(_),n[f?"replace":"assign"](p)}}function i(c,u){const f=ee({},t.state,eo(r.value.back,c,r.value.forward,!0),u,{position:r.value.position});o(c,f,!0),s.value=c}function l(c,u){const f=ee({},r.value,t.state,{forward:c,scroll:Zn()});o(f.current,f,!0);const h=ee({},eo(s.value,c,null),{position:f.position+1},u);o(c,h,!1),s.value=c}return{location:s,state:r,push:l,replace:i}}function Ju(e){e=ju(e);const t=qu(e),n=zu(e,t.state,t.location,t.replace);function s(o,i=!0){i||n.pauseListeners(),history.go(o)}const r=ee({location:"",base:e,go:s,createHref:Bu.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerLine truncated
|
||||
@@ -1,9 +0,0 @@
|
||||
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const o of r)if(o.type==="childList")for(const i of o.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&s(i)}).observe(document,{childList:!0,subtree:!0});function n(r){const o={};return r.integrity&&(o.integrity=r.integrity),r.referrerPolicy&&(o.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?o.credentials="include":r.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function s(r){if(r.ep)return;r.ep=!0;const o=n(r);fetch(r.href,o)}})();function vs(e,t){const n=Object.create(null),s=e.split(",");for(let r=0;r<s.length;r++)n[s[r]]=!0;return t?r=>!!n[r.toLowerCase()]:r=>!!n[r]}const te={},Ct=[],je=()=>{},ci=()=>!1,ui=/^on[^a-z]/,Cn=e=>ui.test(e),ys=e=>e.startsWith("onUpdate:"),ue=Object.assign,bs=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},fi=Object.prototype.hasOwnProperty,K=(e,t)=>fi.call(e,t),F=Array.isArray,Pt=e=>nn(e)==="[object Map]",Pn=e=>nn(e)==="[object Set]",Ws=e=>nn(e)==="[object Date]",D=e=>typeof e=="function",ie=e=>typeof e=="string",Vt=e=>typeof e=="symbol",ee=e=>e!==null&&typeof e=="object",Ur=e=>ee(e)&&D(e.then)&&D(e.catch),Kr=Object.prototype.toString,nn=e=>Kr.call(e),ai=e=>nn(e).slice(8,-1),Wr=e=>nn(e)==="[object Object]",xs=e=>ie(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,dn=vs(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),On=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},di=/-(\w)/g,Ke=On(e=>e.replace(di,(t,n)=>n?n.toUpperCase():"")),hi=/\B([A-Z])/g,vt=On(e=>e.replace(hi,"-$1").toLowerCase()),Sn=On(e=>e.charAt(0).toUpperCase()+e.slice(1)),Kn=On(e=>e?`on${Sn(e)}`:""),qt=(e,t)=>!Object.is(e,t),hn=(e,t)=>{for(let n=0;n<e.length;n++)e[n](t)},vn=(e,t,n)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},Zn=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let zs;const Gn=()=>zs||(zs=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function ws(e){if(F(e)){const t={};for(let n=0;n<e.length;n++){const s=e[n],r=ie(s)?_i(s):ws(s);if(r)for(const o in r)t[o]=r[o]}return t}else{if(ie(e))return e;if(ee(e))return e}}const pi=/;(?![^(]*\))/g,gi=/:([^]+)/,mi=/\/\*[^]*?\*\//g;function _i(e){const t={};return e.replace(mi,"").split(pi).forEach(n=>{if(n){const s=n.split(gi);s.length>1&&(t[s[0].trim()]=s[1].trim())}}),t}function ht(e){let t="";if(ie(e))t=e;else if(F(e))for(let n=0;n<e.length;n++){const s=ht(e[n]);s&&(t+=s+" ")}else if(ee(e))for(const n in e)e[n]&&(t+=n+" ");return t.trim()}const vi="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",yi=vs(vi);function zr(e){return!!e||e===""}function bi(e,t){if(e.length!==t.length)return!1;let n=!0;for(let s=0;n&&s<e.length;s++)n=Mn(e[s],t[s]);return n}function Mn(e,t){if(e===t)return!0;let n=Ws(e),s=Ws(t);if(n||s)return n&&s?e.getTime()===t.getTime():!1;if(n=Vt(e),s=Vt(t),n||s)return e===t;if(n=F(e),s=F(t),n||s)return n&&s?bi(e,t):!1;if(n=ee(e),s=ee(t),n||s){if(!n||!s)return!1;const r=Object.keys(e).length,o=Object.keys(t).length;if(r!==o)return!1;for(const i in e){const l=e.hasOwnProperty(i),c=t.hasOwnProperty(i);if(l&&!c||!l&&c||!Mn(e[i],t[i]))return!1}}return String(e)===String(t)}function Vr(e,t){return e.findIndex(n=>Mn(n,t))}const Wn=e=>ie(e)?e:e==null?"":F(e)||ee(e)&&(e.toString===Kr||!D(e.toString))?JSON.stringify(e,qr,2):String(e),qr=(e,t)=>t&&t.__v_isRef?qr(e,t.value):Pt(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[s,r])=>(n[`${s} =>`]=r,n),{})}:Pn(t)?{[`Set(${t.size})`]:[...t.values()]}:ee(t)&&!F(t)&&!Wr(t)?String(t):t;let Ee;class Jr{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=Ee,!t&&Ee&&(this.index=(Ee.scopes||(Ee.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=Ee;try{return Ee=this,t()}finally{Ee=n}}}on(){Ee=this}off(){Ee=this.parent}stop(t){if(this._active){let n,s;for(n=0,s=this.effects.length;n<s;n++)this.effects[n].stop();for(n=0,s=this.cleanups.length;n<s;n++)this.cleanups[n]();if(this.scopes)for(n=0,s=this.scopes.length;n<s;n++)this.scopes[n].stop(!0);if(!this.detached&&this.parent&&!t){const r=this.parent.scopes.pop();r&&r!==this&&(this.parent.scopes[this.index]=r,r.index=this.index)}this.parent=void 0,this._active=!1}}}function Qr(e){return new Jr(e)}function xi(e,t=Ee){t&&t.active&&t.effects.push(e)}function Yr(){return Ee}function wi(e){Ee&&Ee.cleanups.push(e)}const Es=e=>{const t=new Set(e);return t.w=0,t.n=0,t},Xr=e=>(e.w&ot)>0,Zr=e=>(e.n&ot)>0,Ei=({deps:e})=>{if(e.length)for(let t=0;t<e.length;t++)e[t].w|=ot},Ri=e=>{const{deps:t}=e;if(t.length){let n=0;for(let s=0;s<t.length;s++){const r=t[s];Xr(r)&&!Zr(r)?r.delete(e):t[n++]=r,r.w&=~ot,r.n&=~ot}t.length=n}}Line truncated
|
||||
* pinia v2.1.6
|
||||
* (c) 2023 Eduardo San Martin Morote
|
||||
* @license MIT
|
||||
*/let zo;const Dn=e=>zo=e,Vo=Symbol();function ds(e){return e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"&&typeof e.toJSON!="function"}var Kt;(function(e){e.direct="direct",e.patchObject="patch object",e.patchFunction="patch function"})(Kt||(Kt={}));function Dc(){const e=Qr(!0),t=e.run(()=>Me({}));let n=[],s=[];const r=In({install(o){Dn(r),r._a=o,o.provide(Vo,r),o.config.globalProperties.$pinia=r,s.forEach(i=>n.push(i)),s=[]},use(o){return!this._a&&!Lc?s.push(o):n.push(o),this},_p:n,_a:null,_e:e,_s:new Map,state:t});return r}const qo=()=>{};function Rr(e,t,n,s=qo){e.push(t);const r=()=>{const o=e.indexOf(t);o>-1&&(e.splice(o,1),s())};return!n&&Yr()&&wi(r),r}function Et(e,...t){e.slice().forEach(n=>{n(...t)})}const Hc=e=>e();function hs(e,t){e instanceof Map&&t instanceof Map&&t.forEach((n,s)=>e.set(s,n)),e instanceof Set&&t instanceof Set&&t.forEach(e.add,e);for(const n in t){if(!t.hasOwnProperty(n))continue;const s=t[n],r=e[n];ds(r)&&ds(s)&&e.hasOwnProperty(n)&&!re(s)&&!st(s)?e[n]=hs(r,s):e[n]=s}return e}const Bc=Symbol();function Uc(e){return!ds(e)||!e.hasOwnProperty(Bc)}const{assign:Ge}=Object;function Kc(e){return!!(re(e)&&e.effect)}function Wc(e,t,n,s){const{state:r,actions:o,getters:i}=t,l=n.state.value[e];let c;function f(){l||(n.state.value[e]=r?r():{});const d=Gi(n.state.value[e]);return Ge(d,o,Object.keys(i||{}).reduce((h,g)=>(h[g]=In(ae(()=>{Dn(n);const m=n._s.get(e);return i[g].call(m,m)})),h),{}))}return c=Jo(e,f,t,n,s,!0),c}function Jo(e,t,n={},s,r,o){let i;const l=Ge({actions:{}},n),c={deep:!0};let f,d,h=[],g=[],m;const w=s.state.value[e];!o&&!w&&(s.state.value[e]={}),Me({});let R;function N(z){let U;f=d=!1,typeof z=="function"?(z(s.state.value[e]),U={type:Kt.patchFunction,storeId:e,events:m}):(hs(s.state.value[e],z),U={type:Kt.patchObject,payload:z,storeId:e,events:m});const ne=R=Symbol();Is().then(()=>{R===ne&&(f=!0)}),d=!0,Et(h,U,s.state.value[e])}const I=o?function(){const{state:U}=n,ne=U?U():{};this.$patch(he=>{Ge(he,ne)})}:qo;function A(){i.stop(),h=[],g=[],s._s.delete(e)}function B(z,U){return function(){Dn(s);const ne=Array.from(arguments),he=[],xe=[];function Ce(V){he.push(V)}function lt(V){xe.push(V)}Et(g,{args:ne,name:z,store:X,after:Ce,onError:lt});let Pe;try{Pe=U.apply(this&&this.$id===e?this:X,ne)}catch(V){throw Et(xe,V),V}return Pe instanceof Promise?Pe.then(V=>(Et(he,V),V)).catch(V=>(Et(xe,V),Promise.reject(V))):(Et(he,Pe),Pe)}}const $={_p:s,$id:e,$onAction:Rr.bind(null,g),$patch:N,$reset:I,$subscribe(z,U={}){const ne=Rr(h,z,U.detached,()=>he()),he=i.run(()=>Ht(()=>s.state.value[e],xe=>{(U.flush==="sync"?d:f)&&z({storeId:e,type:Kt.direct,events:m},xe)},Ge({},c,U)));return ne},$dispose:A},X=sn($);s._s.set(e,X);const fe=s._a&&s._a.runWithContext||Hc,de=s._e.run(()=>(i=Qr(),fe(()=>i.run(t))));for(const z in de){const U=de[z];if(re(U)&&!Kc(U)||st(U))o||(w&&Uc(U)&&(re(U)?U.value=w[z]:hs(U,w[z])),s.state.value[e][z]=U);else if(typeof U=="function"){const ne=B(z,U);de[z]=ne,l.actions[z]=U}}return Ge(X,de),Ge(W(X),de),Object.defineProperty(X,"$state",{get:()=>s.state.value[e],set:z=>{N(U=>{Ge(U,z)})}}),s._p.forEach(z=>{Ge(X,i.run(()=>z({store:X,app:s._a,pinia:s,options:l})))}),w&&o&&n.hydrate&&n.hydrate(X.$state,w),f=!0,d=!0,X}function zc(e,t,n){let s,r;const o=typeof t=="function";typeof e=="string"?(s=e,r=o?n:t):(r=e,s=e.id);function i(l,c){const f=Hl();return l=l||(f?Ue(Vo,null):null),l&&Dn(l),l=zo,l._s.has(s)||(o?Jo(s,t,r,l):Wc(s,r,l)),l._s.get(s)}return i.$id=s,i}/*!
|
||||
* vue-router v4.2.4
|
||||
* (c) 2023 Eduardo San Martin Morote
|
||||
* @license MIT
|
||||
*/const Rt=typeof window<"u";function Vc(e){return e.__esModule||e[Symbol.toStringTag]==="Module"}const Q=Object.assign;function Qn(e,t){const n={};for(const s in t){const r=t[s];n[s]=Fe(r)?r.map(e):e(r)}return n}const Wt=()=>{},Fe=Array.isArray,qc=/\/$/,Jc=e=>e.replace(qc,"");function Yn(e,t,n="/"){let s,r={},o="",i="";const l=t.indexOf("#");let c=t.indexOf("?");return l<c&&l>=0&&(c=-1),c>-1&&(s=t.slice(0,c),o=t.slice(c+1,l>-1?l:t.length),r=e(o)),l>-1&&(s=s||t.slice(0,l),i=t.slice(l,t.length)),s=Zc(s??t,n),{fullPath:s+(o&&"?")+o+i,path:s,query:r,hash:i}}function Qc(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function Cr(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function Yc(e,t,n){const s=t.matched.length-1,r=n.matched.length-1;return s>-1&&s===r&&It(t.matched[s],n.matched[r])&&Qo(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function It(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Qo(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!Xc(e[n],t[n]))return!1;return!0}function Xc(e,t){return Fe(e)?Pr(e,t):Fe(t)?Pr(t,e):e===t}function Pr(e,t){return Fe(t)?e.length===t.length&&e.every((n,s)=>n===t[s]):e.length===1&&e[0]===t}function Zc(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),s=e.split("/"),r=s[s.length-1];(r===".."||r===".")&&s.push("");let o=n.length-1,i,l;for(i=0;i<s.length;i++)if(l=s[i],l!==".")if(l==="..")o>1&&o--;else break;return n.slice(0,o).join("/")+"/"+s.slice(i-(i===s.length?1:0)).join("/")}var en;(function(e){e.pop="pop",e.push="push"})(en||(en={}));var zt;(function(e){e.back="back",e.forward="forward",e.unknown=""})(zt||(zt={}));function Gc(e){if(!e)if(Rt){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),Jc(e)}const eu=/^[^#]+#/;function tu(e,t){return e.replace(eu,"#")+t}function nu(e,t){const n=document.documentElement.getBoundingClientRect(),s=e.getBoundingClientRect();return{behavior:t.behavior,left:s.left-n.left-(t.left||0),top:s.top-n.top-(t.top||0)}}const Hn=()=>({left:window.pageXOffset,top:window.pageYOffset});function su(e){let t;if("el"in e){const n=e.el,s=typeof n=="string"&&n.startsWith("#"),r=typeof n=="string"?s?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!r)return;t=nu(r,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.pageXOffset,t.top!=null?t.top:window.pageYOffset)}function Or(e,t){return(history.state?history.state.position-t:-1)+e}const ps=new Map;function ru(e,t){ps.set(e,t)}function ou(e){const t=ps.get(e);return ps.delete(e),t}let iu=()=>location.protocol+"//"+location.host;function Yo(e,t){const{pathname:n,search:s,hash:r}=t,o=e.indexOf("#");if(o>-1){let l=r.includes(e.slice(o))?e.slice(o).length:1,c=r.slice(l);return c[0]!=="/"&&(c="/"+c),Cr(c,"")}return Cr(n,e)+s+r}function lu(e,t,n,s){let r=[],o=[],i=null;const l=({state:g})=>{const m=Yo(e,location),w=n.value,R=t.value;let N=0;if(g){if(n.value=m,t.value=g,i&&i===w){i=null;return}N=R?g.position-R.position:0}else s(m);r.forEach(I=>{I(n.value,w,{delta:N,type:en.pop,direction:N?N>0?zt.forward:zt.back:zt.unknown})})};function c(){i=n.value}function f(g){r.push(g);const m=()=>{const w=r.indexOf(g);w>-1&&r.splice(w,1)};return o.push(m),m}function d(){const{history:g}=window;g.state&&g.replaceState(Q({},g.state,{scroll:Hn()}),"")}function h(){for(const g of o)g();o=[],window.removeEventListener("popstate",l),window.removeEventListener("beforeunload",d)}return window.addEventListener("popstate",l),window.addEventListener("beforeunload",d,{passive:!0}),{pauseListeners:c,listen:f,destroy:h}}function Sr(e,t,n,s=!1,r=!1){return{back:e,current:t,forward:n,replaced:s,position:window.history.length,scroll:r?Hn():null}}function cu(e){const{history:t,location:n}=window,s={value:Yo(e,n)},r={value:t.state};r.value||o(s.value,{back:null,current:s.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function o(c,f,d){const h=e.indexOf("#"),g=h>-1?(n.host&&document.querySelector("base")?e:e.slice(h))+c:iu()+e+c;try{t[d?"replaceState":"pushState"](f,"",g),r.value=f}catch(m){console.error(m),n[d?"replace":"assign"](g)}}function i(c,f){const d=Q({},t.state,Sr(r.value.back,c,r.value.forward,!0),f,{position:r.value.position});o(c,d,!0),s.value=c}function l(c,f){const d=Q({},r.value,t.state,{forward:c,scroll:Hn()});o(d.current,d,!0);const h=Q({},Sr(s.value,c,null),{position:d.position+1},f);o(c,h,!1),s.value=c}return{location:s,state:r,push:l,replace:i}}function uu(e){e=Gc(e);const t=cu(e),n=lu(e,t.state,t.location,t.replace);function s(o,i=!0){i||n.pauseListeners(),history.go(o)}const r=Q({location:"",base:e,go:s,createHref:tu.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
@charset "UTF-8";:root{--primary-background: #181818;--secondary-background: #ffffff;--font-color: #333;--header-background: #000;--table-background: #535353;--primary-color: #ffffff;--secondary-color: #ccc;--blue-color: #66ffeb;--red-color: #ff4d4f}@media (prefers-color-scheme: dark){:root{--primary-background: #333;--secondary-background: #666;--font-color: #ddd;--table-background: #535353;--primary-color: #ffffff;--secondary-color: #ccc;--blue-color: #66ffeb;--red-color: #ff4d4f}}body{background-color:var(--primary-background);font-family:Roboto,sans-serif;color:var(--font-color);margin:0}a:link,a:visited,a:active,a:hover{color:var(--primary-color);text-decoration:none}table{border-collapse:collapse;border:0;gap:0}#app{height:100%;display:flex;flex-direction:column}body:has(dialog[open]):before{content:"";display:block;position:fixed;top:0;left:0;width:100%;height:100%;background:#0008;-webkit-backdrop-filter:blur(.2em);backdrop-filter:blur(.2em);z-index:1000}dialog[open]{display:block;border:none;border-radius:.5rem;box-shadow:.2rem .2rem 1rem #000;padding:1rem;position:fixed;top:0;left:0;z-index:1001}dialog[open]>h1{background:#00f;color:#fff;font-size:1rem;margin:-1rem -1rem 0;padding:.5rem 1rem}dialog[open]>div{padding:1em 0}.login-container[data-v-453c8d3d]{display:grid;grid-template-columns:1fr 2fr;justify-content:center;align-items:center}.button-login[data-v-453c8d3d]{background-color:var(--secondary-color);color:var(--secondary-background)}.ant-btn-primary[data-v-453c8d3d]:not(:disabled):hover{background-color:var(--blue-color)}.error-text[data-v-453c8d3d]{color:var(--red-color)}.upload-input[data-v-2834b7f8]{display:none}.actions-container,.actions-list{display:flex;flex-wrap:nowrap;gap:15px}.actions-container{justify-content:space-between}.action-button{padding:0;font-size:1.5em;color:var(--secondary-color)}.action-button:hover{color:var(--blue-color)!important}@media only screen and (max-width: 600px){.actions-container,.actions-list{gap:6px}}.margin-input{margin-top:5px}.path{box-shadow:0 0 .5em #00000026;overflow:hidden;white-space:nowrap;width:100%;z-index:1;flex:0 0 1.5rem;order:1;font-size:.9rem;position:relative}:root{--breadcrumb-background-odd: #2d2d2d;--breadcrumb-background-even: #404040;--breadcrumb-color: #ddd;--breadcrumb-hover-color: #fff;--breadcrumb-hover-background-odd: #25a;--breadcrumb-hover-background-even: #812;--breadcrumb-transtime: .3s}.breadcrumb{display:flex;list-style:none;margin:0;padding:0 1em 0 0}.breadcrumb>a{margin:0 -.7rem;max-width:8em;font-size:1.3em;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;height:1em;color:var(--breadcrumb-color);padding:.3em 1.5em;clip-path:polygon(0 0,1em 50%,0 100%,100% 100%,100% 0,0 0);transition:all var(--breadcrumb-transtime)}.breadcrumb a:first-child{margin-left:0;padding-left:0;clip-path:none}.breadcrumb a:last-child{max-width:none;clip-path:polygon(0 0,calc(100% - 1em) 0,100% 50%,calc(100% - 1em) 100%,0 100%,1em 50%,0 0)}.breadcrumb a:only-child{clip-path:polygon(0 0,calc(100% - 1em) 0,100% 50%,calc(100% - 1em) 100%,0 100%,0 0)}.breadcrumb svg{transform:translate(.3rem,-.3rem) scale(.8);fill:var(--breadcrumb-color);transition:fill var(--breadcrumb-transtime)}.breadcrumb a:nth-child(odd){background:var(--breadcrumb-background-odd)}.breadcrumb a:nth-child(2n){background:var(--breadcrumb-background-even)}.breadcrumb a:nth-child(odd):hover{background:var(--breadcrumb-hover-background-odd)}.breadcrumb a:nth-child(2n):hover{background:var(--breadcrumb-hover-background-even)}.breadcrumb a:hover{color:var(--breadcrumb-hover-color)}.breadcrumb a:hover svg{fill:var(--breadcrumb-hover-color)}nav[data-v-f793c45b],span[data-v-f793c45b]{color:var(--primary-color)}span[data-v-f793c45b]:hover,.last[data-v-f793c45b]{color:var(--blue-color)}input#FileRenameInput{color:#8f8;border:0;padding:0;width:90%;outline:none;background:transparent}table{width:100%;table-layout:fixed}table input[type=checkbox]{width:1em;height:1em}table .modified{width:10em}table .size{width:6em}table th,table td{padding:.5em;font-weight:400;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.name{white-space:nowrap;text-overflow:initial;overflow:initial}.name button{visibility:hidden;padding-left:1em}.name:hover button{visibility:visible}.name button{cursor:pointer;border:0;background:transparent}thead tr{border:1px solid #ddd;background:#ddd;color:#000}tbody tr:hover{background:#00f8}.right{text-align:right}.selection{width:2em}.sortcolumn:hover{cursor:pointer}.sortcolumn:hover:after{color:#f80}.sortcolumn{padding-right:1.7em}.sortcolumn:after{content:"▸";color:#888;margin:0 1em 0 .5em;position:absolute;transition:all .2s linear}.sortactive:after{transform:rotate(90deg);color:#000}main{padding:5px;height:100%}.more-action{display:flex;flex-direction:column;justify-content:start}.action-container{display:flex;align-items:center}.edit-action{min-width:5%}.carousel-container{height:inherit}.name a{text-decoration:none}.file .name:beforeLine truncated
|
||||
@@ -1 +0,0 @@
|
||||
@charset "UTF-8";:root{--primary-background: #181818;--secondary-background: #ffffff;--font-color: #333333;--table-background: #535353;--primary-color: #ffffff;--secondary-color: #ccc;--blue-color: #66ffeb;--red-color: #ff4d4f}@media (prefers-color-scheme: dark){:root{--primary-background: #333;--secondary-background: #666;--font-color: #ffffff;--table-background: #535353;--primary-color: #ffffff;--secondary-color: #ccc;--blue-color: #66ffeb;--red-color: #ff4d4f}}body{background-color:var(--primary-background);font-family:Roboto,sans-serif;margin:0}a:link,a:visited,a:active,a:hover{color:var(--primary-color);text-decoration:none}table{border-collapse:collapse;border:0;gap:0}#app{height:100%;display:flex;flex-direction:column;background-color:var(--secondary-background)}.login-container[data-v-b14929a5]{display:flex;justify-content:center;align-items:center;min-height:30vh}.button-login[data-v-b14929a5]{background-color:var(--secondary-color);color:var(--secondary-background)}.ant-btn-primary[data-v-b14929a5]:not(:disabled):hover{background-color:var(--blue-color)}.error-text[data-v-b14929a5]{color:var(--red-color)}.upload-input[data-v-8cbd2944]{display:none}.actions-container,.actions-list{display:flex;flex-wrap:nowrap;gap:15px}.actions-container{justify-content:space-between}.action-button{padding:0;font-size:1.5em;color:var(--secondary-color)}.action-button:hover{color:var(--blue-color)!important}@media only screen and (max-width: 600px){.actions-container,.actions-list{gap:6px}}.margin-input{margin-top:5px}.path{box-shadow:0 0 .5em #00000026;overflow:hidden;white-space:nowrap;width:100%;z-index:1;flex:0 0 1.5rem;order:1;font-size:.9rem;position:relative}nav[data-v-953811b0],span[data-v-953811b0]{color:var(--primary-color)}span[data-v-953811b0]:hover,.last[data-v-953811b0]{color:var(--blue-color)}input#FileRenameInput{color:#8f8;border:0;padding:0;width:90%;outline:none;background:transparent}table{width:100%;table-layout:fixed}table input[type=checkbox]{width:1em;height:1em}table .modified{width:10em}table .size{width:6em}table th,table td{padding:.5em;font-weight:400;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.name{white-space:nowrap;text-overflow:initial;overflow:initial}.name button{visibility:hidden;padding-left:1em}.name:hover button{visibility:visible}.name button{cursor:pointer;border:0;background:transparent}thead tr{border:1px solid #ddd;background:#ddd}tbody tr{background:#444;color:#ddd}tbody tr:hover{background:#00f8}.right{text-align:right}.selection{width:2em}.sortcolumn:hover{cursor:pointer}.sortcolumn:hover:after{color:#f80}.sortcolumn{padding-right:1.7em}.sortcolumn:after{content:"▸";color:#888;margin:0 1em 0 .5em;position:absolute;transition:transform .2s linear}.sortactive:after{transform:rotate(90deg);color:#000}main{padding:5px;height:100%}.more-action{display:flex;flex-direction:column;justify-content:start}.action-container{display:flex;align-items:center}.edit-action{min-width:5%}.carousel-container{height:inherit}.name a{text-decoration:none}.file .name:before{content:"📄 ";font-size:1.5em}.folder .name:before{content:"📁 ";font-size:1.5em}.wrapper[data-v-aa2747c4]{background-color:var(--primary-background);padding:.2em .5em;display:flex;flex-direction:column;gap:10px}.page-container[data-v-aa2747c4]{flex-grow:2;padding:0}
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang=en>
|
||||
<script type="module" crossorigin src="/assets/index-68773a87.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-d4bfeeb6.css">
|
||||
<script type="module" crossorigin src="/assets/index-2034a7a8.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-c3cea0a2.css">
|
||||
|
||||
<meta charset=UTF-8>
|
||||
<title>Cista</title>
|
||||
@@ -10,5 +10,6 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Emoji&family=Roboto:wght@400;700&display=swap" rel="stylesheet">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<div id="app"></div>
|
||||
|
||||
|
||||
<div id="app"></div>
|
||||
Generated
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "cista-storage",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"locale-includes": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/locale-includes": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/locale-includes/-/locale-includes-1.0.5.tgz",
|
||||
"integrity": "sha512-8pcOkyBbMZvHGskk3gbi+o6dYSOmkLJ+hh1lle+LaULxB2YtwNrCMEhgpAJb3WruTUC2cSEu71bOe6im6DuCuA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"locale-includes": "^1.0.5"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user