Recreated page navigation buttons.
This commit is contained in:
@@ -51,23 +51,16 @@ export type { Path }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="wrapper">
|
||||
<HeaderMain WS="WS"></HeaderMain>
|
||||
<AppNavigation :path="path.pathList"></AppNavigation>
|
||||
<LoginModal />
|
||||
<header>
|
||||
<HeaderMain />
|
||||
<BreadCrumb :path="path.pathList" />
|
||||
</header>
|
||||
|
||||
<RouterView class="page-container" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.wrapper {
|
||||
background-color: var(--header-background);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.page-container {
|
||||
flex-grow: 2;
|
||||
padding: 0;
|
||||
header {
|
||||
background: #000;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="-12 -12 512 512"><path d="M480 416L355.44 291.44C373.22 262.4 384 228.58 384 192 384 85.98 298 0 192 0 85.98 0 0 85.98 0 192c0 106 85.98 192 192 192 36.58 0 70.4-10.78 99.44-28.5L416 480c8.75 8.75 23.25 8.7 32 0l32-32a22.8 22.8 0 0 0 0-32zm-288-96c-70.7 0-128-57.3-128-128S121.3 64 192 64s128 57.3 128 128-57.3 128-128 128z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="-12 -12 512 512"><path d="M480 416L355.44 291.44C373.22 262.4 384 228.58 384 192 384 85.98 298 0 192 0 85.98 0 0 85.98 0 192c0 106 85.98 192 192 192 36.58 0 70.4-10.78 99.44-28.5L416 480c8.75 8.75 23.25 8.7 32 0l32-32a22.8 22.8 0 0 0 0-32zm-288-96c-70.7 0-128-57.3-128-128S121.3 64 192 64s128 57.3 128 128-57.3 128-128 128z"/></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 405 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448" viewBox="10 10 372 468"><path d="M128 344V168c0-4.5-3.5-8-8-8h-16c-4.5 0-8 3.5-8 8v176c0 4.5 3.5 8 8 8h16c4.5 0 8-3.5 8-8zm64 0V168c0-4.5-3.5-8-8-8h-16c-4.5 0-8 3.5-8 8v176c0 4.5 3.5 8 8 8h16c4.5 0 8-3.5 8-8zm64 0V168c0-4.5-3.5-8-8-8h-16c-4.5 0-8 3.5-8 8v176c0 4.5 3.5 8 8 8h16c4.5 0 8-3.5 8-8zM120 96h112l-12-29.25c-.75-1-3-2.5-4.25-2.75H136.5c-1.5.25-3.5 1.75-4.25 2.75zm232 8v16c0 4.5-3.5 8-8 8h-24v237c0 27.5-18 51-40 51H72c-22 0-40-22.5-40-50V128H8c-4.5 0-8-3.5-8-8v-16c0-4.5 3.5-8 8-8h77.25l17.5-41.75C107.75 42 122.75 32 136 32h80c13.25 0 28.25 10 33.25 22.25L266.75 96H344c4.5 0 8 3.5 8 8z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="40" viewBox="10 10 372 468"><path d="M128 344V168c0-4.5-3.5-8-8-8h-16c-4.5 0-8 3.5-8 8v176c0 4.5 3.5 8 8 8h16c4.5 0 8-3.5 8-8zm64 0V168c0-4.5-3.5-8-8-8h-16c-4.5 0-8 3.5-8 8v176c0 4.5 3.5 8 8 8h16c4.5 0 8-3.5 8-8zm64 0V168c0-4.5-3.5-8-8-8h-16c-4.5 0-8 3.5-8 8v176c0 4.5 3.5 8 8 8h16c4.5 0 8-3.5 8-8zM120 96h112l-12-29.25c-.75-1-3-2.5-4.25-2.75H136.5c-1.5.25-3.5 1.75-4.25 2.75zm232 8v16c0 4.5-3.5 8-8 8h-24v237c0 27.5-18 51-40 51H72c-22 0-40-22.5-40-50V128H8c-4.5 0-8-3.5-8-8v-16c0-4.5 3.5-8 8-8h77.25l17.5-41.75C107.75 42 122.75 32 136 32h80c13.25 0 28.25 10 33.25 22.25L266.75 96H344c4.5 0 8 3.5 8 8z"/></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 670 B |
@@ -1,72 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
path: Array<string>
|
||||
}>(),
|
||||
{}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav>
|
||||
<!--
|
||||
|
||||
<div class="view-nav">
|
||||
<div class="view-nav-left">
|
||||
<button class="af button tip tip-se" aria-label="Upload files from disk">{{{svg "add-file"}}}</button>
|
||||
<button class="ad button tip tip-s" aria-label="Upload folder from disk">{{{svg "add-folder"}}}</button>
|
||||
<button class="cd button tip tip-s" aria-label="Create folder">{{{svg "create-folder"}}}</button>
|
||||
</div>
|
||||
<div class="view-nav-right">
|
||||
<div class="search toggled-off tip tip-s" aria-label="Search">
|
||||
{{{svg "find"}}}
|
||||
<input class="search-input" type="search" placeholder="Term" />
|
||||
</div>
|
||||
<button class="reload button tip tip-s" aria-label="Reload View">{{{svg "reload"}}}</button>
|
||||
<button class="newview button tip tip-s" aria-label="Create new View">{{{svg "window"}}}</button>
|
||||
<button class="prefs button tip tip-s" aria-label="Preferences">{{{svg "cog"}}}</button>
|
||||
<button class="about button tip tip-s" aria-label="About">{{{svg "info"}}}</button>
|
||||
<button class="logout button tip tip-sw" aria-label="Sign out">{{{svg "signout"}}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="path"></ul>
|
||||
<div class="content-container">
|
||||
<div class="content"></div>
|
||||
</div>
|
||||
|
||||
<div class="dropzone">
|
||||
<svg></svg>
|
||||
</div>
|
||||
<div class="info-box">
|
||||
<div class="icon">{{{svg "link"}}}</div>
|
||||
<span></span>
|
||||
<div class="link-out mousetrap"></div>
|
||||
<div class="link-options">
|
||||
<div class="copy-link tip tip-nw" aria-label="Copy to clipboard">
|
||||
{{{svg "copy"}}}<div>Copy</div>
|
||||
</div>
|
||||
<div class="dl-link checked tip tip-sw" aria-label="Trigger a download when opened">
|
||||
{{{svg "check"}}}<div>Is DL</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paste-button">
|
||||
{{{svg "paste"}}}
|
||||
<span>Paste here</span>
|
||||
{{{svg "triangle"}}}
|
||||
</div>
|
||||
-->
|
||||
<BreadCrumb :path="props.path" />
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
nav,
|
||||
span {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
span:hover,
|
||||
.last {
|
||||
color: var(--blue-color);
|
||||
}
|
||||
</style>
|
||||
@@ -10,8 +10,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import home from '@/assets/svg/home.svg'
|
||||
import { withDefaults, defineProps } from 'vue'
|
||||
//import home from '@/assets/svg/home.svg'
|
||||
import { withDefaults, defineProps, defineAsyncComponent } from 'vue'
|
||||
|
||||
const home = defineAsyncComponent(() => import(`@/assets/svg/home.svg`))
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
||||
@@ -38,10 +38,18 @@
|
||||
<tr v-if="editing?.key === 'new'" class="folder">
|
||||
<td class="selection"></td>
|
||||
<td class="name">
|
||||
<FileRenameInput :doc="editing" :rename="mkdir" :exit="() => { editing = null }"/>
|
||||
<FileRenameInput
|
||||
:doc="editing"
|
||||
:rename="mkdir"
|
||||
:exit="
|
||||
() => {
|
||||
editing = null
|
||||
}
|
||||
"
|
||||
/>
|
||||
</td>
|
||||
<td class="right">{{editing.modified}}</td>
|
||||
<td class="right">{{editing.sizedisp}}</td>
|
||||
<td class="right">{{ editing.modified }}</td>
|
||||
<td class="right">{{ editing.sizedisp }}</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="doc of sorted(props.documents as FolderDocument[])"
|
||||
@@ -158,7 +166,7 @@ const mkdir = (doc: FolderDocument, name: string) => {
|
||||
control.send(
|
||||
JSON.stringify({
|
||||
op: 'mkdir',
|
||||
path: `${decodeURIComponent(linkBasePath.value)}/${name}`,
|
||||
path: `${decodeURIComponent(linkBasePath.value)}/${name}`
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
import { ref } from 'vue'
|
||||
import { ref, nextTick } from 'vue'
|
||||
|
||||
const documentStore = useDocumentStore()
|
||||
const searchQuery = ref<string>('')
|
||||
const showSearchInput = ref<boolean>(false)
|
||||
const search = ref<HTMLInputElement | null>()
|
||||
|
||||
const toggleSearchInput = () => {
|
||||
showSearchInput.value = !showSearchInput.value
|
||||
if (!showSearchInput.value) {
|
||||
searchQuery.value = ''
|
||||
}
|
||||
nextTick(() => {
|
||||
const input = search.value
|
||||
if (input) input.focus()
|
||||
})
|
||||
}
|
||||
|
||||
const executeSearch = (ev: InputEvent) => {
|
||||
@@ -23,104 +28,56 @@ const executeSearch = (ev: InputEvent) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="actions-container">
|
||||
<div class="actions-list">
|
||||
<nav>
|
||||
<div class="buttons">
|
||||
<UploadButton />
|
||||
<!--
|
||||
|
||||
<a-tooltip title="Upload folder from disk">
|
||||
<a-button @click="uploadFolderHandler" type="text" class="action-button" :icon="h(FolderAddFilled)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="Create file">
|
||||
<a-button @click="createFileHandler" type="text" class="action-button" :icon="h(FileFilled)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="Create folder">
|
||||
<a-button @click="createFolderHandler" type="text" class="action-button" :icon="h(FolderFilled)" />
|
||||
</a-tooltip>
|
||||
|
||||
<template v-if="documentStore.selected.size > 0">
|
||||
<a-tooltip title="Share">
|
||||
<a-button type="text" @click="share" class="action-button" :icon="h(LinkOutlined)" />
|
||||
</a-tooltip>
|
||||
<a-tooltip title="Download Zip">
|
||||
<a-button type="text" @click="download" class="action-button" :icon="h(DownloadOutlined)" />
|
||||
</a-tooltip>
|
||||
<a-tooltip title="Delete">
|
||||
<a-button type="text" @click="deleteHandler" class="action-button" :icon="h(DeleteOutlined)" />
|
||||
</a-tooltip>
|
||||
<SvgButton name="create-folder" />
|
||||
<template v-if="true">
|
||||
<div class="smallgap"></div>
|
||||
<p>N selected files:</p>
|
||||
<!-- Needs better icons for copy/move/remove -->
|
||||
<SvgButton name="copy" />
|
||||
<SvgButton name="paste" />
|
||||
<SvgButton name="trash" />
|
||||
</template>
|
||||
-->
|
||||
</div>
|
||||
<div class="actions-list">
|
||||
<LoginModal></LoginModal>
|
||||
<div class="spacer"></div>
|
||||
<SvgButton name="find" @click="toggleSearchInput" />
|
||||
<template v-if="showSearchInput">
|
||||
<input type="search" v-model="searchQuery" class="margin-input" />
|
||||
<input
|
||||
ref="search"
|
||||
type="search"
|
||||
v-model="searchQuery"
|
||||
class="margin-input"
|
||||
@keyup.esc="toggleSearchInput"
|
||||
/>
|
||||
</template>
|
||||
<!--
|
||||
|
||||
<a-tooltip title="Search">
|
||||
<a-button @click="toggleSearchInput" type="text" class="action-button" :icon="h(SearchOutlined)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="Create new view">
|
||||
<a-button @click="newViewHandler" type="text" class="action-button" :icon="h(PlusSquareOutlined)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="Preferences">
|
||||
<a-button @click="preferencesHandler" type="text" class="action-button" :icon="h(SettingOutlined)" />
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip title="About">
|
||||
<a-button @click="about" type="text" class="action-button" :icon="h(InfoCircleOutlined)" />
|
||||
</a-tooltip>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.actions-container,
|
||||
.actions-list {
|
||||
<style scoped>
|
||||
.buttons {
|
||||
padding: 0 0.5em;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.actions-container {
|
||||
justify-content: space-between;
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
padding: 0;
|
||||
font-size: 1.5em;
|
||||
color: var(--secondary-color);
|
||||
|
||||
&:hover {
|
||||
color: var(--blue-color) !important;
|
||||
}
|
||||
.smallgap {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.actions-container,
|
||||
.actions-list {
|
||||
gap: 6px;
|
||||
}
|
||||
.search-widget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.margin-input {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.path {
|
||||
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: 0.9rem;
|
||||
position: relative;
|
||||
input[type='search'] {
|
||||
background: var(--primary-background);
|
||||
color: var(--text-color);
|
||||
border: 0;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.5rem;
|
||||
outline: none;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
37
cista-front/src/components/SvgButton.vue
Normal file
37
cista-front/src/components/SvgButton.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<button class="action-button">
|
||||
<component :is="icon" />
|
||||
<slot></slot>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineAsyncComponent, defineProps } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
name: string
|
||||
}>()
|
||||
|
||||
const icon = defineAsyncComponent(() => import(`@/assets/svg/${props.name}.svg`))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
button:hover {
|
||||
color: #fff;
|
||||
}
|
||||
svg {
|
||||
fill: #ccc;
|
||||
transform: fill 0.2s ease;
|
||||
}
|
||||
button:hover svg {
|
||||
fill: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -3,6 +3,7 @@ import { useDocumentStore } from '@/stores/documents'
|
||||
import { h, ref } from 'vue'
|
||||
|
||||
const fileUploadButton = ref()
|
||||
const folderUploadButton = ref()
|
||||
const documentStore = useDocumentStore()
|
||||
const open = (placement: any) => openNotification(placement)
|
||||
|
||||
@@ -74,19 +75,22 @@ async function uploadFileChangeHandler(event: Event) {
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
(buttons here)
|
||||
<!--
|
||||
|
||||
<a-tooltip title="Upload files from disk">
|
||||
<a-button @click="uploadFileHandler" type="text" class="action-button" :icon="h(FileAddFilled)" />
|
||||
<input ref="fileUploadButton" @change="uploadFileChangeHandler" class="upload-input" type="file" onclick="this.value=null;" />
|
||||
</a-tooltip>
|
||||
<contextHolder />
|
||||
-->
|
||||
<template>
|
||||
<input
|
||||
ref="fileUploadButton"
|
||||
@change="uploadFileChangeHandler"
|
||||
class="upload-input"
|
||||
type="file"
|
||||
multiple
|
||||
/>
|
||||
<input
|
||||
ref="folderUploadButton"
|
||||
@change="uploadFileChangeHandler"
|
||||
class="upload-input"
|
||||
type="file"
|
||||
webkitdirectory
|
||||
/>
|
||||
</template>
|
||||
<SvgButton name="add-file" @click="fileUploadButton.click()" />
|
||||
<SvgButton name="add-folder" @click="folderUploadButton.click()" />
|
||||
</template>
|
||||
<style scoped>
|
||||
/* Extends styles from HeaderMain.vue too */
|
||||
.upload-input {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -64,7 +64,7 @@ export class DocumentHandler {
|
||||
|
||||
handleWebSocketMessage(event: MessageEvent) {
|
||||
const msg = JSON.parse(event.data)
|
||||
if ("error" in msg) {
|
||||
if ('error' in msg) {
|
||||
if (msg.error.code === 401) {
|
||||
this.store.user.isLoggedIn = false
|
||||
this.store.user.isOpenLoginModal = true
|
||||
@@ -72,10 +72,12 @@ export class DocumentHandler {
|
||||
this.store.error = msg.error.message
|
||||
}
|
||||
// The server closes the websocket after errors, so we need to reopen it
|
||||
setTimeout(
|
||||
() => { this.store.wsWatch = createWebSocket(url_document_watch_ws, this.handleWebSocketMessage)},
|
||||
1000
|
||||
)
|
||||
setTimeout(() => {
|
||||
this.store.wsWatch = createWebSocket(
|
||||
url_document_watch_ws,
|
||||
this.handleWebSocketMessage
|
||||
)
|
||||
}, 1000)
|
||||
}
|
||||
switch (true) {
|
||||
case !!msg.root:
|
||||
|
||||
@@ -44,7 +44,12 @@ export const useDocumentStore = defineStore({
|
||||
wsWatch: undefined,
|
||||
wsUpload: undefined,
|
||||
error: '' as string,
|
||||
user: { username: "", privileged: false, isLoggedIn: false, isOpenLoginModal: false } as User
|
||||
user: {
|
||||
username: '',
|
||||
privileged: false,
|
||||
isLoggedIn: false,
|
||||
isOpenLoginModal: false
|
||||
} as User
|
||||
}),
|
||||
|
||||
actions: {
|
||||
|
||||
Reference in New Issue
Block a user