Merge pull request #20 from gtsteffaniak/broken-style

Fixed styling
This commit is contained in:
Graham Steffaniak 2023-09-04 14:40:00 -05:00 committed by GitHub
commit c2a6c649d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 925 additions and 265 deletions

View File

@ -50,6 +50,7 @@ func setDefaults() Settings {
AdminUsername: "admin", AdminUsername: "admin",
AdminPassword: "admin", AdminPassword: "admin",
Server: Server{ Server: Server{
EnableThumbnails: true,
EnableExec: false, EnableExec: false,
IndexingInterval: 5, IndexingInterval: 5,
Port: 8080, Port: 8080,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 843 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -33,13 +33,14 @@ header {
#search #input { #search #input {
background: var(--surfaceSecondary); background: var(--surfaceSecondary);
border-color: var(--surfacePrimary); border-color: var(--surfaceSecondary);
} }
#search #input input::placeholder { #search #input input::placeholder {
color: var(--textSecondary); color: var(--textSecondary);
} }
#search.active #input { #search.active #input {
background: var(--surfacePrimary); background: var(--surfacePrimary);
border-color: white;
} }
#search.active input { #search.active input {
color: var(--textPrimary); color: var(--textPrimary);
@ -131,8 +132,8 @@ nav > div {
.input { .input {
background: var(--surfaceSecondary); background: var(--surfaceSecondary);
color: var(--textPrimary); color: var(--textPrimary);
border: 1px solid rgba(255, 255, 255, 0.05);
} }
.input:hover, .input:hover,
.input:focus { .input:focus {
border-color: rgba(255, 255, 255, 0.15); border-color: rgba(255, 255, 255, 0.15);
@ -215,5 +216,5 @@ nav {
} }
#result-desktop #result-list { #result-desktop #result-list {
background: #2a3137; background: #2a3137;
max-height: unset;
} }

View File

@ -1,27 +1,12 @@
<template> <template>
<div id="search" @click="open" v-bind:class="{ active, ongoing }"> <div id="search" @click="open" v-bind:class="{ active, ongoing }">
<div id="input"> <div id="input">
<button <button v-if="active" class="action" @click="close" :aria-label="$t('buttons.close')" :title="$t('buttons.close')">
v-if="active"
class="action"
@click="close"
:aria-label="$t('buttons.close')"
:title="$t('buttons.close')"
>
<i class="material-icons">close</i> <i class="material-icons">close</i>
</button> </button>
<i v-else class="material-icons">search</i> <i v-else class="material-icons">search</i>
<input <input class="main-input" type="text" @keyup.exact="keyup" @input="submit" ref="input" :autofocus="active"
class="main-input" v-model.trim="value" :aria-label="$t('search.search')" :placeholder="$t('search.search')" />
type="text"
@keyup.exact="keyup"
@input="submit"
ref="input"
:autofocus="active"
v-model.trim="value"
:aria-label="$t('search.search')"
:placeholder="$t('search.search')"
/>
</div> </div>
<div v-if="isMobile && active" id="result" :class="{ hidden: !active }" ref="result"> <div v-if="isMobile && active" id="result" :class="{ hidden: !active }" ref="result">
<div id="result-list"> <div id="result-list">
@ -29,12 +14,7 @@
Search Context: {{ getContext(this.$route.path) }} Search Context: {{ getContext(this.$route.path) }}
</div> </div>
<ul v-show="results.length > 0"> <ul v-show="results.length > 0">
<li <li v-for="(s, k) in results" :key="k" @click.stop.prevent="navigateTo(s.url)" style="cursor: pointer">
v-for="(s, k) in results"
:key="k"
@click.stop.prevent="navigateTo(s.url)"
style="cursor: pointer"
>
<router-link to="#" event=""> <router-link to="#" event="">
<i v-if="s.dir" class="material-icons folder-icons"> folder </i> <i v-if="s.dir" class="material-icons folder-icons"> folder </i>
<i v-else-if="s.audio" class="material-icons audio-icons"> volume_up </i> <i v-else-if="s.audio" class="material-icons audio-icons"> volume_up </i>
@ -57,26 +37,15 @@
</div> </div>
</div> </div>
<template v-if="isEmpty"> <template v-if="isEmpty">
<button <button class="mobile-boxes" v-if="value.length === 0 && !showBoxes" @click="resetSearchFilters()">
class="mobile-boxes"
v-if="value.length === 0 && !showBoxes"
@click="resetSearchFilters()"
>
Reset filters Reset filters
</button> </button>
<template v-if="value.length === 0 && showBoxes"> <template v-if="value.length === 0 && showBoxes">
<div class="boxes"> <div class="boxes">
<h3>{{ $t("search.types") }}</h3> <h3>{{ $t("search.types") }}</h3>
<div> <div>
<div <div class="mobile-boxes" tabindex="0" v-for="(v, k) in boxes" :key="k" role="button"
class="mobile-boxes" @click="addToTypes('type:' + k)" :aria-label="v.label">
tabindex="0"
v-for="(v, k) in boxes"
:key="k"
role="button"
@click="addToTypes('type:' + k)"
:aria-label="v.label"
>
<i class="material-icons">{{ v.icon }}</i> <i class="material-icons">{{ v.icon }}</i>
<p>{{ v.label }}</p> <p>{{ v.label }}</p>
</div> </div>
@ -121,52 +90,26 @@
</p> </p>
</div> </div>
<template> <template>
<ButtonGroup <ButtonGroup :buttons="folderSelect" @button-clicked="addToTypes" @remove-button-clicked="removeFromTypes"
:buttons="folderSelect" @disableAll="folderSelectClicked()" @enableAll="resetButtonGroups()" />
@button-clicked="addToTypes" <ButtonGroup :buttons="typeSelect" @button-clicked="addToTypes" @remove-button-clicked="removeFromTypes"
@remove-button-clicked="removeFromTypes" :isDisabled="isTypeSelectDisabled" />
@disableAll="folderSelectClicked()"
@enableAll="resetButtonGroups()"
/>
<ButtonGroup
:buttons="typeSelect"
@button-clicked="addToTypes"
@remove-button-clicked="removeFromTypes"
:isDisabled="isTypeSelectDisabled"
/>
<div class="sizeConstraints"> <div class="sizeConstraints">
<div class="sizeInputWrapper"> <div class="sizeInputWrapper">
<p>Smaller Than:</p> <p>Smaller Than:</p>
<input <input class="sizeInput" v-model="smallerThan" type="number" min="0" placeholder="number" />
class="sizeInput"
v-model="smallerThan"
type="number"
min="0"
placeholder="number"
/>
<p>MB</p> <p>MB</p>
</div> </div>
<div class="sizeInputWrapper"> <div class="sizeInputWrapper">
<p>Larger Than:</p> <p>Larger Than:</p>
<input <input class="sizeInput" v-model="largerThan" type="number" placeholder="number" />
class="sizeInput"
v-model="largerThan"
type="number"
placeholder="number"
/>
<p>MB</p> <p>MB</p>
</div> </div>
</div> </div>
</template> </template>
</template> </template>
<ul v-show="results.length > 0"> <ul v-show="results.length > 0">
<li <li v-for="(s, k) in results" :key="k" @click.stop.prevent="navigateTo(s.url)" style="cursor: pointer">
v-for="(s, k) in results"
:key="k"
@click.stop.prevent="navigateTo(s.url)"
style="cursor: pointer"
>
<router-link to="#" event=""> <router-link to="#" event="">
<i v-if="s.dir" class="material-icons folder-icons"> folder </i> <i v-if="s.dir" class="material-icons folder-icons"> folder </i>
<i v-else-if="s.audio" class="material-icons audio-icons"> volume_up </i> <i v-else-if="s.audio" class="material-icons audio-icons"> volume_up </i>
@ -189,43 +132,56 @@
.main-input { .main-input {
width: 100%; width: 100%;
} }
.searchContext { .searchContext {
width: 100%; width: 100%;
padding: 0.5em 1em; padding: 0.5em 1em;
background: var(--blue); background: var(--blue);
color: white; color: white;
border: 1px solid rgba(0, 0, 0, 0.05); border-left: 1px solid gray;
border-right: 1px solid gray;
} }
#result-desktop #result-list {
#result-desktop>#result-list {
max-height: 80vh;
width: 35em;
overflow: scroll;
padding-bottom: 1em;
-webkit-transition: width 0.3s ease 0s;
transition: width 0.3s ease 0s; transition: width 0.3s ease 0s;
max-width: 100%; }
overflow-x: hidden;
overflow-y: auto; #result-desktop {
border-color: gray; -webkit-animation: SlideDown 0.5s forwards;
width: 30em; animation: SlideDown 0.5s forwards;
padding-top: 0em; border-radius: 1m;
border-color: #a7a7a7;
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
border-radius: 1em; border-radius: 1em;
max-height: 100%;
border-top: none; border-top: none;
border-top-width: initial;
border-top-style: none;
border-top-color: initial;
border-top-left-radius: 0px; border-top-left-radius: 0px;
border-top-right-radius: 0px; border-top-right-radius: 0px;
background: white;
max-height: 80vh;
left: 50%;
-webkit-transform: translateX(-50%); -webkit-transform: translateX(-50%);
transform: translateX(-50%); transform: translateX(-50%);
-webkit-box-shadow: 0px 2em 50px 10px rgba(0, 0, 0, 0.3); -webkit-box-shadow: 0px 2em 50px 10px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2em 50px 10px rgba(0, 0, 0, 0.3); box-shadow: 0px 2em 50px 10px rgba(0, 0, 0, 0.3);
background-color: lightgray;
max-height: 80vh;
overflow: hidden;
} }
#search.active #result-desktop ul li a { #search.active #result-desktop ul li a {
display: flex; display: flex;
align-items: center; align-items: center;
padding: .3em 0; padding: .3em 0;
margin-right: .3em; margin-right: .3em;
} }
#result-list.active {
#search #result-list.active {
width: 65em !important; width: 65em !important;
max-width: 85vw !important; max-width: 85vw !important;
} }
@ -236,18 +192,22 @@
transform: translateY(-3em); transform: translateY(-3em);
opacity: 0; opacity: 0;
} }
100% { 100% {
transform: translateY(0); transform: translateY(0);
opacity: 1; opacity: 1;
} }
} }
/* Search */ /* Search */
#search { #search {
flex-basis: auto; z-index:3;
position: fixed;
top: .5em;
min-width: 35em; min-width: 35em;
height: 3em; left: 50%;
display: flex; -webkit-transform: translateX(-50%);
flex-direction: column; transform: translateX(-50%);
} }
#search #input { #search #input {
@ -256,14 +216,11 @@
height: 100%; height: 100%;
padding: 0em 0.75em; padding: 0em 0.75em;
border-style: solid; border-style: solid;
border-color: #ccc;
border-radius: 1em; border-radius: 1em;
border-style: solid; border-style: unset;
border-color: #a7a7a7;
border-width: 1px; border-width: 1px;
transition: 1s ease all;
align-items: center; align-items: center;
z-index: 3; height: 3em;
} }
#search input { #search input {
@ -283,8 +240,10 @@
/* Hiding scrollbar for IE, Edge and Firefox */ /* Hiding scrollbar for IE, Edge and Firefox */
#result-list { #result-list {
scrollbar-width: none; /* Firefox */ scrollbar-width: none;
-ms-overflow-style: none; /* IE and Edge */ /* Firefox */
-ms-overflow-style: none;
/* IE and Edge */
} }
.text-container { .text-container {
@ -309,6 +268,7 @@
color: rgba(0, 0, 0, 0.6); color: rgba(0, 0, 0, 0.6);
height: 0; height: 0;
transition: 2s ease height, 2s ease padding; transition: 2s ease height, 2s ease padding;
transition: 2s ease width, 2s ease padding;
z-index: 3; z-index: 3;
} }
@ -316,7 +276,7 @@ body.rtl #search #result {
direction: ltr; direction: ltr;
} }
#search #result > div > *:first-child { #search #result>div>*:first-child {
margin-top: 0; margin-top: 0;
} }
@ -326,7 +286,7 @@ body.rtl #search #result {
} }
/* Search Results */ /* Search Results */
body.rtl #search #result ul > * { body.rtl #search #result ul>* {
direction: ltr; direction: ltr;
text-align: left; text-align: left;
} }
@ -352,12 +312,14 @@ body.rtl #search #result ul > * {
#search.ongoing #renew { #search.ongoing #renew {
display: block; display: block;
} }
#search.active #input { #search.active #input {
border-bottom-left-radius: 0px; background-color: lightgray;
border-bottom-right-radius: 0px; border-color: black;
border-style: solid;
border-bottom-style: none; border-bottom-style: none;
border-bottom-left-radius: 0px; border-bottom-right-radius: 0;
border-bottom-right-radius: 0px; border-bottom-left-radius: 0;
} }
/* Search Input Placeholder */ /* Search Input Placeholder */
@ -406,10 +368,6 @@ body.rtl #search .boxes h3 {
font-size: 3.5em; font-size: 3.5em;
} }
#result-desktop {
animation: SlideDown 0.5s forwards;
}
.mobile-boxes { .mobile-boxes {
cursor: pointer; cursor: pointer;
overflow: hidden; overflow: hidden;
@ -420,6 +378,7 @@ body.rtl #search .boxes h3 {
border-radius: 1em; border-radius: 1em;
text-align: center; text-align: center;
} }
/* Hiding scrollbar for Chrome, Safari and Opera */ /* Hiding scrollbar for Chrome, Safari and Opera */
.mobile-boxes::-webkit-scrollbar { .mobile-boxes::-webkit-scrollbar {
display: none; display: none;
@ -427,9 +386,12 @@ body.rtl #search .boxes h3 {
/* Hiding scrollbar for IE, Edge and Firefox */ /* Hiding scrollbar for IE, Edge and Firefox */
.mobile-boxes { .mobile-boxes {
scrollbar-width: none; /* Firefox */ scrollbar-width: none;
-ms-overflow-style: none; /* IE and Edge */ /* Firefox */
-ms-overflow-style: none;
/* IE and Edge */
} }
.helpText { .helpText {
padding: 1em; padding: 1em;
} }
@ -455,17 +417,17 @@ body.rtl #search .boxes h3 {
.sizeInputWrapper { .sizeInputWrapper {
border-radius: 1em; border-radius: 1em;
margin-left: 0.5em; margin-left: 0.5em;
margin-right: 0.5em; margin-right: 0.5em;
display: -ms-flexbox; display: -ms-flexbox;
display: flex; display: flex;
background-color: rgb(245, 245, 245); background-color: rgb(245, 245, 245);
padding: 0.25em; padding: 0.25em;
height: 3em; height: 3em;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
align-items: center; align-items: center;
border: 1px solid #ccc border: 1px solid #ccc
} }
.helpButton { .helpButton {
@ -545,7 +507,7 @@ export default {
setTimeout(() => { setTimeout(() => {
resultList.classList.add("active"); resultList.classList.add("active");
}, 100); }, 100);
}, },
show(val, old) { show(val, old) {
this.active = val === "search"; this.active = val === "search";

View File

@ -16,7 +16,7 @@
<i class="material-icons">note_add</i> <i class="material-icons">note_add</i>
<span>{{ $t("sidebar.newFile") }}</span> <span>{{ $t("sidebar.newFile") }}</span>
</button> </button>
<button id="upload-button" @click="upload($event)" class="action" :aria-label="$t('sidebar.upload')" > <button id="upload-button" @click="upload($event)" class="action" >
<i class="material-icons">file_upload</i> <i class="material-icons">file_upload</i>
<span>Upload file</span> <span>Upload file</span>
</button> </button>

View File

@ -126,8 +126,13 @@ main {
padding-top: 4em; padding-top: 4em;
overflow: scroll; overflow: scroll;
top: 0; top: 0;
height: 100vh; height: 100%;
width: 100%; width: 100%;
display: flex;
flex-direction: column;
}
main > div {
height: calc(100% - 3em);
} }
.breadcrumbs { .breadcrumbs {

View File

@ -53,11 +53,6 @@ header .action span {
display: none; display: none;
} }
header>div div {
vertical-align: middle;
position: relative;
}
/* Icon Colors */ /* Icon Colors */
.folder-icons { .folder-icons {
color: var(--icon-blue); color: var(--icon-blue);

View File

@ -54,16 +54,20 @@
} }
#search { #search {
min-width: unset; min-width: unset;
max-width: 60%;
} }
#search.active { #search.active {
display: block; display: block;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 50%;
width: 100%; width: 100%;
max-width: 100%;
}
#search #input {
transition: 1s ease all;
} }
#search.active #input { #search.active #input {
border-bottom: 3px solid rgba(0, 0, 0, 0.075); border-bottom: 3px solid rgba(0, 0, 0, 0.075);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);

View File

@ -280,15 +280,11 @@ main .spinner .bounce2 {
#editor-container { #editor-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: #fafafa; background-color: none;
position: fixed;
padding-top: 4em;
top: 0;
left: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
z-index: 9999;
overflow: hidden; overflow: hidden;
position: relative;
} }
#editor-container #editor { #editor-container #editor {

View File

@ -1,7 +1,5 @@
<template> <template>
<div> <div>
<header-bar v-if="showHeader" showMenu showLogo />
<h2 class="message"> <h2 class="message">
<i class="material-icons">{{ info.icon }}</i> <i class="material-icons">{{ info.icon }}</i>
<span>{{ $t(info.message) }}</span> <span>{{ $t(info.message) }}</span>

View File

@ -1,7 +1,5 @@
<template> <template>
<div> <div>
<header-bar v-if="error || req.type == null" showMenu showLogo />
<breadcrumbs base="/files" /> <breadcrumbs base="/files" />
<errors v-if="error" :errorCode="error.status" /> <errors v-if="error" :errorCode="error.status" />
@ -91,8 +89,12 @@ export default {
} }
this.$store.commit("updateRequest", {}); this.$store.commit("updateRequest", {});
}, },
currentView(newView) {
// Commit the new value to the store
this.setCurrentValue(this.newValue);
},
methods: { methods: {
...mapMutations(["setLoading"]), ...mapMutations(["setLoading","setCurrentView"]),
async fetchData() { async fetchData() {
// Reset view information. // Reset view information.
this.$store.commit("setReload", false); this.$store.commit("setReload", false);

View File

@ -3,9 +3,8 @@
<div v-if="progress" class="progress"> <div v-if="progress" class="progress">
<div v-bind:style="{ width: this.progress + '%' }"></div> <div v-bind:style="{ width: this.progress + '%' }"></div>
</div> </div>
<editorBar v-if="getCurrentView === 'editor'"></editorBar> <listingBar v-if="currentView === 'listing'"></listingBar>
<listingBar v-else-if="getCurrentView === 'listing'"></listingBar> <editorBar v-else-if="currentView === 'editor'"></editorBar>
<previewBar v-else-if="getCurrentView === 'preview'"></previewBar>
<defaultBar v-else></defaultBar> <defaultBar v-else></defaultBar>
<sidebar></sidebar> <sidebar></sidebar>
<main> <main>
@ -17,24 +16,21 @@
</template> </template>
<script> <script>
import editorBar from "./files/Editor.vue" import editorBar from "./bars/EditorBar.vue"
import defaultBar from "./files/Default.vue" import defaultBar from "./bars/Default.vue"
import listingBar from"./files/Listing.vue" import listingBar from "./bars/ListingBar.vue"
import previewBar from "./files/Preview.vue"
import Prompts from "@/components/prompts/Prompts"; import Prompts from "@/components/prompts/Prompts";
import Action from "@/components/header/Action"; import Action from "@/components/header/Action";
import { mapState, mapGetters } from "vuex"; import { mapState, mapGetters } from "vuex";
import Sidebar from "@/components/Sidebar.vue"; import Sidebar from "@/components/Sidebar.vue";
import UploadFiles from "../components/prompts/UploadFiles"; import UploadFiles from "../components/prompts/UploadFiles";
import { enableExec } from "@/utils/constants"; import { enableExec } from "@/utils/constants";
export default { export default {
name: "layout", name: "layout",
components: { components: {
defaultBar, defaultBar,
editorBar, editorBar,
listingBar, listingBar,
previewBar,
Action, Action,
Sidebar, Sidebar,
Prompts, Prompts,
@ -49,18 +45,28 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(["isLogged", "progress"]), ...mapGetters(["isLogged", "progress", "isListing"]),
...mapState(["req", "user", "currentView"]), ...mapState(["req", "user", "state"]),
isExecEnabled: () => enableExec, isExecEnabled: () => enableExec,
getCurrentView() { currentView() {
return this.currentView; if (this.req.type == undefined) {
return null;
}
if (this.req.isDir) {
return "listing";
} else if (
this.req.type === "text" ||
this.req.type === "textImmutable"
) {
return "editor";
} else {
return "preview";
}
}, },
}, },
watch: { watch: {
getCurrentView: function () {
console.log(this.currentView)
},
$route: function () { $route: function () {
this.$store.commit("resetSelected"); this.$store.commit("resetSelected");
this.$store.commit("multiple", false); this.$store.commit("multiple", false);
@ -70,7 +76,7 @@ export default {
methods: { methods: {
getTitle() { getTitle() {
let title = "Title" let title = "Title"
if (this.$route.path.startsWith('/settings/')){ if (this.$route.path.startsWith('/settings/')) {
title = "Settings" title = "Settings"
} }
return title return title

View File

@ -1,7 +1,5 @@
<template> <template>
<div class="dashboard"> <div class="dashboard">
<header-bar showMenu showLogo />
<div id="nav"> <div id="nav">
<div class="wrapper"> <div class="wrapper">
<ul> <ul>
@ -52,15 +50,14 @@
<script> <script>
import { mapState } from "vuex"; import { mapState } from "vuex";
import HeaderBar from "@/components/header/HeaderBar";
export default { export default {
name: "settings", name: "settings",
components: { mounted() {
HeaderBar, // Update the req name property
this.$store.commit("updateRequest", { name: "Settings" });
}, },
computed: { computed: {
...mapState(["user", "loading"]), ...mapState(["user", "loading","req"]),
}, },
}; };
</script> </script>

View File

@ -1,30 +1,5 @@
<template> <template>
<div> <div>
<header-bar showMenu showLogo>
<title />
<action
v-if="selectedCount"
icon="file_download"
:label="$t('buttons.download')"
@action="download"
:counter="selectedCount"
/>
<button
v-if="isSingleFile()"
class="action copy-clipboard"
:data-clipboard-text="linkSelected()"
:aria-label="$t('buttons.copyDownloadLinkToClipboard')"
:title="$t('buttons.copyDownloadLinkToClipboard')"
>
<i class="material-icons">content_paste</i>
</button>
<action
icon="check_circle"
:label="$t('buttons.selectMultiple')"
@action="toggleMultipleSelection"
/>
</header-bar>
<breadcrumbs :base="'/share/' + hash" /> <breadcrumbs :base="'/share/' + hash" />

View File

@ -1,18 +1,8 @@
<template> <template>
<header-bar> <header-bar>
<action <action icon="close" :label="$t('buttons.close')" @action="close()" />
class="menu-button" <title class="topTitle">{{ req.name }}</title>
icon="menu"
:label="$t('buttons.toggleSidebar')"
@action="toggleSidebar()"
/>
<search />
<action
class="menu-button"
icon="grid_view"
:label="$t('buttons.switchView')"
@action="switchView"
/>
</header-bar> </header-bar>
</template> </template>
@ -29,6 +19,7 @@ import Vue from "vue";
import { mapState, mapGetters, mapMutations } from "vuex"; import { mapState, mapGetters, mapMutations } from "vuex";
import { users, files as api } from "@/api"; import { users, files as api } from "@/api";
import { enableExec } from "@/utils/constants"; import { enableExec } from "@/utils/constants";
import url from "@/utils/url";
import HeaderBar from "@/components/header/HeaderBar.vue"; import HeaderBar from "@/components/header/HeaderBar.vue";
import Action from "@/components/header/Action.vue"; import Action from "@/components/header/Action.vue";
import * as upload from "@/utils/upload"; import * as upload from "@/utils/upload";
@ -58,6 +49,9 @@ export default {
computed: { computed: {
...mapState(["req", "selected", "user", "show", "multiple", "selected", "loading"]), ...mapState(["req", "selected", "user", "show", "multiple", "selected", "loading"]),
...mapGetters(["selectedCount"]), ...mapGetters(["selectedCount"]),
isSettings() {
return this.$route.path.includes("/settings/")
},
nameSorted() { nameSorted() {
return this.req.sorting.by === "name"; return this.req.sorting.by === "name";
}, },
@ -587,7 +581,17 @@ export default {
}, },
}); });
}, },
close() {
if (this.isSettings) { // Use this.isSettings to access the computed property
this.$router.push({ path: "/files/" }, () => { });
this.$store.commit("closeHovers");
return;
}
this.$store.commit("updateRequest", {});
let uri = url.removeLastDir(this.$route.path) + "/";
console.log(url)
this.$router.push({ path: uri });
},
upload: function () { upload: function () {
if ( if (
typeof window.DataTransferItem !== "undefined" && typeof window.DataTransferItem !== "undefined" &&

View File

@ -0,0 +1,141 @@
<template>
<header-bar>
<action icon="close" :label="$t('buttons.close')" @action="close()" />
<title class="topTitle">{{ req.name }}</title>
<action v-if="user.perm.modify" id="save-button" icon="save" :label="$t('buttons.save')"
@action="save()" />
</header-bar>
</template>
<style>
.flexbar {
display: flex;
flex-direction: block;
justify-content: space-between;
}
.topTitle {
display: flex;
justify-content: center;
}
</style>
<script>
import { mapState } from "vuex";
import { files as api } from "@/api";
import { theme } from "@/utils/constants";
import buttons from "@/utils/buttons";
import url from "@/utils/url";
import ace from "ace-builds/src-min-noconflict/ace.js";
import modelist from "ace-builds/src-min-noconflict/ext-modelist.js";
import "ace-builds/webpack-resolver";
import HeaderBar from "@/components/header/HeaderBar";
import Action from "@/components/header/Action";
import Breadcrumbs from "@/components/Breadcrumbs";
export default {
name: "editor",
components: {
HeaderBar,
Action,
Breadcrumbs,
},
data: function () {
return {};
},
computed: {
...mapState(["req", "user", "currentView"]),
breadcrumbs() {
let parts = this.$route.path.split("/");
if (parts[0] === "") {
parts.shift();
}
if (parts[parts.length - 1] === "") {
parts.pop();
}
let breadcrumbs = [];
for (let i = 0; i < parts.length; i++) {
breadcrumbs.push({ name: decodeURIComponent(parts[i]) });
}
breadcrumbs.shift();
if (breadcrumbs.length > 3) {
while (breadcrumbs.length !== 4) {
breadcrumbs.shift();
}
breadcrumbs[0].name = "...";
}
return breadcrumbs;
},
},
created() {
window.addEventListener("keydown", this.keyEvent);
},
beforeDestroy() {
window.removeEventListener("keydown", this.keyEvent);
this.editor.destroy();
},
mounted: function () {
const fileContent = this.req.content || "";
this.editor = ace.edit("editor", {
value: fileContent,
showPrintMargin: false,
readOnly: this.req.type === "textImmutable",
theme: "ace/theme/chrome",
mode: modelist.getModeForPath(this.req.name).mode,
wrap: true,
});
if (theme == "dark") {
this.editor.setTheme("ace/theme/twilight");
}
},
methods: {
back() {
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
keyEvent(event) {
if (!event.ctrlKey && !event.metaKey) {
return;
}
if (String.fromCharCode(event.which).toLowerCase() !== "s") {
return;
}
event.preventDefault();
this.save();
},
async save() {
const button = "save";
buttons.loading("save");
try {
await api.put(this.$route.path, this.editor.getValue());
buttons.success(button);
} catch (e) {
buttons.done(button);
this.$showError(e);
}
},
close() {
this.$store.commit("updateRequest", {});
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
},
};
</script>

View File

@ -0,0 +1,630 @@
<template>
<header-bar>
<action
class="menu-button"
icon="menu"
:label="$t('buttons.toggleSidebar')"
@action="toggleSidebar()"
/>
<search />
<action
class="menu-button"
icon="grid_view"
:label="$t('buttons.switchView')"
@action="switchView"
/>
</header-bar>
</template>
<style>
.flexbar {
display:flex;
flex-direction:block;
justify-content: space-between;
}
</style>
<script>
import Vue from "vue";
import { mapState, mapGetters, mapMutations } from "vuex";
import { users, files as api } from "@/api";
import HeaderBar from "@/components/header/HeaderBar.vue";
import Action from "@/components/header/Action.vue";
import url from "@/utils/url";
import * as upload from "@/utils/upload";
import css from "@/utils/css";
import throttle from "lodash.throttle";
import Search from "@/components/Search.vue";
import Item from "@/components/files/ListingItem.vue";
export default {
name: "listing",
components: {
HeaderBar,
Action,
Search,
Item,
},
data: function () {
return {
showLimit: 50,
columnWidth: 280,
dragCounter: 0,
width: window.innerWidth,
itemWeight: 0,
};
},
computed: {
...mapState(["req", "selected", "user", "show", "multiple", "selected", "loading"]),
...mapGetters(["selectedCount"]),
nameSorted() {
return this.req.sorting.by === "name";
},
sizeSorted() {
return this.req.sorting.by === "size";
},
modifiedSorted() {
return this.req.sorting.by === "modified";
},
ascOrdered() {
return this.req.sorting.asc;
},
items() {
const dirs = [];
const files = [];
this.req.items.forEach((item) => {
if (item.isDir) {
dirs.push(item);
} else {
files.push(item);
}
});
return { dirs, files };
},
dirs() {
return this.items.dirs.slice(0, this.showLimit);
},
files() {
let showLimit = this.showLimit - this.items.dirs.length;
if (showLimit < 0) showLimit = 0;
return this.items.files.slice(0, showLimit);
},
nameIcon() {
if (this.nameSorted && !this.ascOrdered) {
return "arrow_upward";
}
return "arrow_downward";
},
sizeIcon() {
if (this.sizeSorted && this.ascOrdered) {
return "arrow_downward";
}
return "arrow_upward";
},
modifiedIcon() {
if (this.modifiedSorted && this.ascOrdered) {
return "arrow_downward";
}
return "arrow_upward";
},
viewIcon() {
const icons = {
list: "view_module",
mosaic: "grid_view",
"mosaic gallery": "view_list",
};
return icons[this.user.viewMode];
},
headerButtons() {
return {
select: this.selectedCount > 0,
upload: this.user.perm.create && this.selectedCount > 0,
download: this.user.perm.download && this.selectedCount > 0,
delete: this.selectedCount > 0 && this.user.perm.delete,
rename: this.selectedCount === 1 && this.user.perm.rename,
share: this.selectedCount === 1 && this.user.perm.share,
move: this.selectedCount > 0 && this.user.perm.rename,
copy: this.selectedCount > 0 && this.user.perm.create,
};
},
},
watch: {
req: function () {
// Reset the show value
this.showLimit = 50;
// Ensures that the listing is displayed
Vue.nextTick(() => {
// How much every listing item affects the window height
this.setItemWeight();
// Fill and fit the window with listing items
this.fillWindow(true);
});
},
},
mounted: function () {
// Check the columns size for the first time.
this.colunmsResize();
// How much every listing item affects the window height
this.setItemWeight();
// Fill and fit the window with listing items
this.fillWindow(true);
// Add the needed event listeners to the window and document.
window.addEventListener("keydown", this.keyEvent);
window.addEventListener("scroll", this.scrollEvent);
window.addEventListener("resize", this.windowsResize);
if (!this.user.perm.create) return;
document.addEventListener("dragover", this.preventDefault);
document.addEventListener("dragenter", this.dragEnter);
document.addEventListener("dragleave", this.dragLeave);
document.addEventListener("drop", this.drop);
},
beforeDestroy() {
// Remove event listeners before destroying this page.
window.removeEventListener("keydown", this.keyEvent);
window.removeEventListener("scroll", this.scrollEvent);
window.removeEventListener("resize", this.windowsResize);
if (this.user && !this.user.perm.create) return;
document.removeEventListener("dragover", this.preventDefault);
document.removeEventListener("dragenter", this.dragEnter);
document.removeEventListener("dragleave", this.dragLeave);
document.removeEventListener("drop", this.drop);
},
methods: {
action: function () {
if (this.show) {
this.$store.commit("showHover", this.show);
}
this.$emit("action");
},
toggleSidebar() {
if (this.$store.state.show == "sidebar") {
this.$store.commit("closeHovers");
} else {
this.$store.commit("showHover", "sidebar");
}
},
...mapMutations(["updateUser", "addSelected"]),
base64: function (name) {
return window.btoa(unescape(encodeURIComponent(name)));
},
keyEvent(event) {
// No prompts are shown
if (this.show !== null) {
return;
}
// Esc!
if (event.keyCode === 27) {
// Reset files selection.
this.$store.commit("resetSelected");
}
// Del!
if (event.keyCode === 46) {
if (!this.user.perm.delete || this.selectedCount == 0) return;
// Show delete prompt.
this.$store.commit("showHover", "delete");
}
// F2!
if (event.keyCode === 113) {
if (!this.user.perm.rename || this.selectedCount !== 1) return;
// Show rename prompt.
this.$store.commit("showHover", "rename");
}
// Ctrl is pressed
if (!event.ctrlKey && !event.metaKey) {
return;
}
let key = String.fromCharCode(event.which).toLowerCase();
switch (key) {
case "f":
event.preventDefault();
this.$store.commit("showHover", "search");
break;
case "c":
case "x":
this.copyCut(event, key);
break;
case "v":
this.paste(event);
break;
case "a":
event.preventDefault();
for (let file of this.items.files) {
if (this.$store.state.selected.indexOf(file.index) === -1) {
this.addSelected(file.index);
}
}
for (let dir of this.items.dirs) {
if (this.$store.state.selected.indexOf(dir.index) === -1) {
this.addSelected(dir.index);
}
}
break;
case "s":
event.preventDefault();
document.getElementById("download-button").click();
break;
}
},
switchView: async function () {
this.$store.commit("closeHovers");
const modes = {
list: "mosaic",
mosaic: "mosaic gallery",
"mosaic gallery": "list",
};
const data = {
id: this.user.id,
viewMode: modes[this.user.viewMode] || "list",
};
//users.update(data, ["viewMode"]).catch(this.$showError);
this.$store.commit("updateUser", data);
//this.setItemWeight();
//this.fillWindow();
},
preventDefault(event) {
// Wrapper around prevent default.
event.preventDefault();
},
copyCut(event, key) {
if (event.target.tagName.toLowerCase() === "input") {
return;
}
let items = [];
for (let i of this.selected) {
items.push({
from: this.req.items[i].url,
name: this.req.items[i].name,
});
}
if (items.length == 0) {
return;
}
this.$store.commit("updateClipboard", {
key: key,
items: items,
path: this.$route.path,
});
},
paste(event) {
if (event.target.tagName.toLowerCase() === "input") {
return;
}
let items = [];
for (let item of this.$store.state.clipboard.items) {
const from = item.from.endsWith("/") ? item.from.slice(0, -1) : item.from;
const to = this.$route.path + encodeURIComponent(item.name);
items.push({ from, to, name: item.name });
}
if (items.length === 0) {
return;
}
let action = (overwrite, rename) => {
api
.copy(items, overwrite, rename)
.then(() => {
this.$store.commit("setReload", true);
})
.catch(this.$showError);
};
if (this.$store.state.clipboard.key === "x") {
action = (overwrite, rename) => {
api
.move(items, overwrite, rename)
.then(() => {
this.$store.commit("resetClipboard");
this.$store.commit("setReload", true);
})
.catch(this.$showError);
};
}
if (this.$store.state.clipboard.path == this.$route.path) {
action(false, true);
return;
}
let conflict = upload.checkConflict(items, this.req.items);
let overwrite = false;
let rename = false;
if (conflict) {
this.$store.commit("showHover", {
prompt: "replace-rename",
confirm: (event, option) => {
overwrite = option == "overwrite";
rename = option == "rename";
event.preventDefault();
this.$store.commit("closeHovers");
action(overwrite, rename);
},
});
return;
}
action(overwrite, rename);
},
colunmsResize() {
// Update the columns size based on the window width.
let columns = Math.floor(
document.querySelector("main").offsetWidth / this.columnWidth
);
let items = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
if (columns === 0) columns = 1;
items.style.width = `calc(${100 / columns}% - 1em)`;
},
scrollEvent: throttle(function () {
const totalItems = this.req.numDirs + this.req.numFiles;
// All items are displayed
if (this.showLimit >= totalItems) return;
const currentPos = window.innerHeight + window.scrollY;
// Trigger at the 75% of the window height
const triggerPos = document.body.offsetHeight - window.innerHeight * 0.25;
if (currentPos > triggerPos) {
// Quantity of items needed to fill 2x of the window height
const showQuantity = Math.ceil((window.innerHeight * 2) / this.itemWeight);
// Increase the number of displayed items
this.showLimit += showQuantity;
}
}, 100),
dragEnter() {
this.dragCounter++;
// When the user starts dragging an item, put every
// file on the listing with 50% opacity.
let items = document.getElementsByClassName("item");
Array.from(items).forEach((file) => {
file.style.opacity = 0.5;
});
},
dragLeave() {
this.dragCounter--;
if (this.dragCounter == 0) {
this.resetOpacity();
}
},
drop: async function (event) {
event.preventDefault();
this.dragCounter = 0;
this.resetOpacity();
let dt = event.dataTransfer;
let el = event.target;
if (dt.files.length <= 0) return;
for (let i = 0; i < 5; i++) {
if (el !== null && !el.classList.contains("item")) {
el = el.parentElement;
}
}
let files = await upload.scanFiles(dt);
let items = this.req.items;
let path = this.$route.path.endsWith("/")
? this.$route.path
: this.$route.path + "/";
if (el !== null && el.classList.contains("item") && el.dataset.dir === "true") {
// Get url from ListingItem instance
path = el.__vue__.url;
try {
items = (await api.fetch(path)).items;
} catch (error) {
this.$showError(error);
}
}
let conflict = upload.checkConflict(files, items);
if (conflict) {
this.$store.commit("showHover", {
prompt: "replace",
confirm: (event) => {
event.preventDefault();
this.$store.commit("closeHovers");
upload.handleFiles(files, path, true);
},
});
return;
}
upload.handleFiles(files, path);
},
uploadInput(event) {
this.$store.commit("closeHovers");
let files = event.currentTarget.files;
let folder_upload =
files[0].webkitRelativePath !== undefined && files[0].webkitRelativePath !== "";
if (folder_upload) {
for (let i = 0; i < files.length; i++) {
let file = files[i];
files[i].fullPath = file.webkitRelativePath;
}
}
let path = this.$route.path.endsWith("/")
? this.$route.path
: this.$route.path + "/";
let conflict = upload.checkConflict(files, this.req.items);
if (conflict) {
this.$store.commit("showHover", {
prompt: "replace",
confirm: (event) => {
event.preventDefault();
this.$store.commit("closeHovers");
upload.handleFiles(files, path, true);
},
});
return;
}
upload.handleFiles(files, path);
},
resetOpacity() {
let items = document.getElementsByClassName("item");
Array.from(items).forEach((file) => {
file.style.opacity = 1;
});
},
async sort(by) {
let asc = false;
if (by === "name") {
if (this.nameIcon === "arrow_upward") {
asc = true;
}
} else if (by === "size") {
if (this.sizeIcon === "arrow_upward") {
asc = true;
}
} else if (by === "modified") {
if (this.modifiedIcon === "arrow_upward") {
asc = true;
}
}
try {
await users.update({ id: this.user.id, sorting: { by, asc } }, ["sorting"]);
} catch (e) {
this.$showError(e);
}
this.$store.commit("setReload", true);
},
openSearch() {
this.$store.commit("showHover", "search");
},
toggleMultipleSelection() {
this.$store.commit("multiple", !this.multiple);
this.$store.commit("closeHovers");
},
windowsResize: throttle(function () {
this.colunmsResize();
this.width = window.innerWidth;
// Listing element is not displayed
if (this.$refs.listing == null) return;
// How much every listing item affects the window height
this.setItemWeight();
// Fill but not fit the window
this.fillWindow();
}, 100),
download() {
if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) {
api.download(null, this.req.items[this.selected[0]].url);
return;
}
this.$store.commit("showHover", {
prompt: "download",
confirm: (format) => {
this.$store.commit("closeHovers");
let files = [];
if (this.selectedCount > 0) {
for (let i of this.selected) {
files.push(this.req.items[i].url);
}
} else {
files.push(this.$route.path);
}
api.download(format, ...files);
},
});
},
upload: function () {
if (
typeof window.DataTransferItem !== "undefined" &&
typeof DataTransferItem.prototype.webkitGetAsEntry !== "undefined"
) {
this.$store.commit("showHover", "upload");
} else {
document.getElementById("upload-input").click();
}
},
setItemWeight() {
// Listing element is not displayed
if (this.$refs.listing == null) return;
let itemQuantity = this.req.numDirs + this.req.numFiles;
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
// How much every listing item affects the window height
this.itemWeight = this.$refs.listing.offsetHeight / itemQuantity;
},
fillWindow(fit = false) {
const totalItems = this.req.numDirs + this.req.numFiles;
// More items are displayed than the total
if (this.showLimit >= totalItems && !fit) return;
const windowHeight = window.innerHeight;
// Quantity of items needed to fill 2x of the window height
const showQuantity = Math.ceil((windowHeight + windowHeight * 2) / this.itemWeight);
// Less items to display than current
if (this.showLimit > showQuantity && !fit) return;
// Set the number of displayed items
this.showLimit = showQuantity > totalItems ? totalItems : showQuantity;
},
},
};
</script>

View File

@ -1,20 +1,5 @@
<template> <template>
<div id="editor-container"> <div id="editor-container">
<header-bar>
<action icon="close" :label="$t('buttons.close')" @action="close()" />
<title>{{ req.name }}</title>
<action
v-if="user.perm.modify"
id="save-button"
icon="save"
:label="$t('buttons.save')"
@action="save()"
/>
</header-bar>
<breadcrumbs base="/files" noLink />
<form id="editor"></form> <form id="editor"></form>
</div> </div>
</template> </template>
@ -45,7 +30,7 @@ export default {
return {}; return {};
}, },
computed: { computed: {
...mapState(["req", "user"]), ...mapState(["req", "user","currentView"]),
breadcrumbs() { breadcrumbs() {
let parts = this.$route.path.split("/"); let parts = this.$route.path.split("/");

View File

@ -4,48 +4,6 @@
@mousemove="toggleNavigation" @mousemove="toggleNavigation"
@touchstart="toggleNavigation" @touchstart="toggleNavigation"
> >
<header-bar>
<action icon="close" :label="$t('buttons.close')" @action="close()" />
<title>{{ name }}</title>
<action
:disabled="loading"
v-if="isResizeEnabled && req.type === 'image'"
:icon="fullSize ? 'photo_size_select_large' : 'hd'"
@action="toggleSize"
/>
<template #actions>
<action
:disabled="loading"
v-if="user.perm.rename"
icon="mode_edit"
:label="$t('buttons.rename')"
show="rename"
/>
<action
:disabled="loading"
v-if="user.perm.delete"
icon="delete"
:label="$t('buttons.delete')"
@action="deleteFile"
id="delete-button"
/>
<action
:disabled="loading"
v-if="user.perm.download"
icon="file_download"
:label="$t('buttons.download')"
@action="download"
/>
<action
:disabled="loading"
icon="info"
:label="$t('buttons.info')"
show="info"
/>
</template>
</header-bar>
<div class="loading delayed" v-if="loading"> <div class="loading delayed" v-if="loading">
<div class="spinner"> <div class="spinner">
<div class="bounce1"></div> <div class="bounce1"></div>