ui changes

This commit is contained in:
Jewel Lukose 2024-04-04 15:32:43 +05:30
parent ae0af1f996
commit f7c0a677b9
28 changed files with 3904 additions and 1146 deletions

View File

@ -187,6 +187,6 @@
</div> </div>
</div> </div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.js"></script>
</body> </body>
</html> </html>

View File

@ -0,0 +1,10 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2349_1587)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.9997 6.83337C14.2758 6.83337 14.4997 7.05723 14.4997 7.33337V14.6484L15.62 13.3413C15.7998 13.1316 16.1154 13.1074 16.3251 13.2871C16.5347 13.4668 16.559 13.7824 16.3793 13.9921L14.3793 16.3254C14.2843 16.4363 14.1456 16.5 13.9997 16.5C13.8537 16.5 13.715 16.4363 13.62 16.3254L11.62 13.9921C11.4403 13.7824 11.4646 13.4668 11.6743 13.2871C11.8839 13.1074 12.1996 13.1316 12.3793 13.3413L13.4997 14.6484V7.33337C13.4997 7.05723 13.7235 6.83337 13.9997 6.83337ZM10.6636 11.5014C10.9397 11.4998 11.1648 11.7224 11.1663 11.9986C11.1679 12.2747 10.9453 12.4998 10.6691 12.5013C9.94013 12.5054 9.4234 12.5243 9.03124 12.5964C8.65337 12.6658 8.43465 12.7772 8.27235 12.9395C8.08784 13.124 7.96754 13.3831 7.90177 13.8723C7.83407 14.3758 7.83301 15.0432 7.83301 16.0002V16.6669C7.83301 17.6238 7.83407 18.2912 7.90177 18.7948C7.96754 19.284 8.08784 19.543 8.27235 19.7275C8.45686 19.912 8.7159 20.0323 9.20509 20.0981C9.70866 20.1658 10.3761 20.1669 11.333 20.1669H16.6663C17.6233 20.1669 18.2907 20.1658 18.7943 20.0981C19.2834 20.0323 19.5425 19.912 19.727 19.7275C19.9115 19.543 20.0318 19.284 20.0976 18.7948C20.1653 18.2912 20.1663 17.6238 20.1663 16.6669V16.0002C20.1663 15.0432 20.1653 14.3758 20.0976 13.8723C20.0318 13.3831 19.9115 13.124 19.727 12.9395C19.5647 12.7772 19.346 12.6658 18.9681 12.5964C18.5759 12.5243 18.0592 12.5054 17.3302 12.5013C17.0541 12.4998 16.8315 12.2747 16.833 11.9986C16.8346 11.7224 17.0597 11.4998 17.3358 11.5014C18.0568 11.5054 18.6577 11.5226 19.1488 11.6128C19.6541 11.7056 20.0842 11.8825 20.4341 12.2324C20.8354 12.6337 21.008 13.1389 21.0887 13.739C21.1664 14.317 21.1664 15.0519 21.1663 15.9636V16.7034C21.1664 17.6152 21.1664 18.35 21.0887 18.928C21.008 19.5281 20.8354 20.0333 20.4341 20.4346C20.0328 20.8359 19.5276 21.0085 18.9275 21.0892C18.3495 21.1669 17.6146 21.1669 16.7029 21.1669H11.2964C10.3847 21.1669 9.64982 21.1669 9.07184 21.0892C8.47177 21.0085 7.96652 20.8359 7.56524 20.4346C7.16396 20.0333 6.99137 19.5281 6.91069 18.928C6.83298 18.35 6.83299 17.6152 6.83301 16.7034V15.9636C6.83299 15.0519 6.83298 14.317 6.91069 13.739C6.99137 13.1389 7.16396 12.6337 7.56524 12.2324C7.91519 11.8825 8.34524 11.7056 8.85058 11.6128C9.34162 11.5226 9.94254 11.5054 10.6636 11.5014Z" fill="#EBEBF5" fill-opacity="0.6"/>
</g>
<defs>
<clipPath id="clip0_2349_1587">
<rect x="6" y="6" width="16" height="16" rx="3.33333" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2510_1572)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.07168 2.09429C6.67365 2.28785 6.19751 2.58263 5.52033 3.00291L4.187 3.83041C3.54645 4.22796 3.09672 4.50773 2.76126 4.76463C2.43487 5.01459 2.24709 5.22087 2.11871 5.4554C1.98988 5.69076 1.91467 5.96593 1.87506 6.38752C1.83449 6.81922 1.83398 7.36404 1.83398 8.13611V9.15013C1.83398 10.4641 1.83498 11.4009 1.92744 12.1123C2.01826 12.811 2.18933 13.2164 2.47451 13.5114C2.75741 13.804 3.14256 13.9778 3.81013 14.0706C4.49387 14.1657 5.39563 14.1668 6.66732 14.1668H9.33398C10.6057 14.1668 11.5074 14.1657 12.1912 14.0706C12.8587 13.9778 13.2439 13.804 13.5268 13.5114C13.812 13.2164 13.983 12.811 14.0739 12.1123C14.1663 11.4009 14.1673 10.4641 14.1673 9.15013V8.13611C14.1673 7.36404 14.1668 6.81922 14.1262 6.38752C14.0866 5.96593 14.0114 5.69076 13.8826 5.4554C13.7542 5.22087 13.5664 5.01459 13.24 4.76463C12.9046 4.50773 12.4549 4.22796 11.8143 3.83041L10.481 3.00291C9.80379 2.58263 9.32765 2.28785 8.92962 2.09429C8.54183 1.90571 8.2672 1.8335 8.00065 1.8335C7.73411 1.8335 7.45947 1.90571 7.07168 2.09429ZM6.63435 1.19499C7.09967 0.968709 7.52857 0.833496 8.00065 0.833496C8.47273 0.833496 8.90163 0.968709 9.36695 1.19499C9.81675 1.41373 10.3364 1.73622 10.9854 2.13904L12.3631 2.99411C12.9773 3.37524 13.469 3.68043 13.8481 3.9707C14.2406 4.27129 14.542 4.57742 14.7598 4.97525C14.9771 5.37224 15.0749 5.79466 15.1219 6.29397C15.1673 6.77785 15.1673 7.36957 15.1673 8.11164V9.18671C15.1673 10.456 15.1673 11.4579 15.0655 12.2412C14.9611 13.0448 14.7416 13.6935 14.2457 14.2065C13.7476 14.7217 13.1137 14.9519 12.3289 15.0611C11.5683 15.1669 10.5969 15.1668 9.37271 15.1668H6.62859C5.40438 15.1668 4.43298 15.1669 3.67239 15.0611C2.88762 14.9519 2.25371 14.7217 1.75556 14.2065C1.25969 13.6935 1.04023 13.0448 0.935787 12.2412C0.833968 11.4579 0.833975 10.456 0.833985 9.18673L0.833985 8.11165C0.833979 7.36957 0.833975 6.77786 0.879444 6.29397C0.926362 5.79466 1.02422 5.37224 1.24152 4.97525C1.45928 4.57742 1.76075 4.27129 2.15325 3.9707C2.53228 3.68043 3.02404 3.37524 3.63817 2.99409L5.01589 2.13904C5.66493 1.73622 6.18455 1.41373 6.63435 1.19499Z" fill="#737373"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.7805 9.19543C7.27655 9.2986 6.80063 9.66808 6.50271 10.056C6.38468 10.2097 6.3291 10.4386 6.3291 10.7514V14.297H5.3291V10.7514C5.3291 10.3521 5.39398 9.85795 5.7096 9.44695C6.10465 8.93253 6.77147 8.38126 7.57994 8.21575C8.43927 8.03984 9.36288 8.32 10.153 9.30267C10.5432 9.78805 10.6683 10.391 10.6683 10.9308V14.297H9.66829V10.9308C9.66829 10.529 9.57341 10.1778 9.37363 9.92927C8.79205 9.20594 8.23358 9.10268 7.7805 9.19543Z" fill="#737373"/>
</g>
<defs>
<clipPath id="clip0_2510_1572">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.0 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -16,8 +16,8 @@
[{[ if .Name -]}][{[ .Name ]}][{[ else ]}]File Browser[{[ end ]}] [{[ if .Name -]}][{[ .Name ]}][{[ else ]}]File Browser[{[ end ]}]
</title> </title>
<meta name="robots" content="noindex,nofollow" /> <meta name="robots" content="noindex,nofollow">
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
@ -126,8 +126,8 @@
} }
#loading .spinner > div { #loading .spinner > div {
width: 18px; width: 12px;
height: 18px; height: 12px;
background-color: #333; background-color: #333;
border-radius: 100%; border-radius: 100%;
display: inline-block; display: inline-block;
@ -181,9 +181,14 @@
</div> </div>
</div> </div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.js"></script>
[{[ if .CSS -]}] [{[ if .Theme -]}]
<link
rel="stylesheet"
href="[{[ .StaticURL ]}]/themes/[{[ .Theme ]}].css"
/>
[{[ end ]}] [{[ if .CSS -]}]
<link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" /> <link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" />
[{[ end ]}] [{[ end ]}]
</body> </body>

View File

@ -0,0 +1,556 @@
:root {
--background: #141D24;
--surfacePrimary: #20292F;
--surfaceSecondary: #3A4147;
--divider: rgba(255, 255, 255, 0.12);
--icon: #ffffff;
/* --textPrimary: rgba(255, 255, 255, 0.87); */
--textPrimary: #DFDEDF !important;
--textSecondary: rgba(255, 255, 255, 0.6);
}
body {
background: var(--background);
color: var(--textPrimary);
}
/* ::-webkit-scrollbar {
display: none!important;
} */
#listing.mosaic,
.breadcrumbs {
background-color: #38393A !important;
}
#listing.list {
background-color: transparent !important;
}
#loading {
background: var(--background);
}
#loading .spinner div,
main .spinner div {
background: var(--icon);
}
#login {
background: var(--background);
}
header {
background: #38393A !important;
}
#search #input {
background: var(--surfaceSecondary);
border-color: var(--surfacePrimary);
}
#search #input input::placeholder {
color: var(--textSecondary);
}
#search.active #input {
background: rgb(71 71 71) !important;
}
#search.active input {
color: var(--textPrimary);
}
#search #result {
background: var(--background);
color: var(--textPrimary);
}
#search .boxes {
/* background: var(--surfaceSecondary); */
}
#search #result .boxes {
background: #38393A !important;
border: 0.5px solid #4C4C4C !important;
box-shadow: 0px 36px 100px rgba(0, 0, 0, 0.4), 0px 0px 3px rgba(0, 0, 0, 0.55) !important;
border-radius: 12px !important;
}
#search .boxes>div>div {
background: #282828 !important;
}
#search .boxes h3,
#search .boxes>div>div>p {
color: var(--textPrimary) !important;
}
.action {
color: var(--textPrimary) !important;
}
.action:hover {
background-color: rgba(255, 255, 255, .1) !important;
}
.action i {
/* color: var(--icon) !important; */
}
.action .counter {
border-color: var(--surfacePrimary);
}
nav>div {
border-color: var(--divider);
}
.breadcrumbs {
border-color: var(--divider);
color: var(--textPrimary) !important;
}
.breadcrumbs span {
color: var(--textPrimary) !important;
}
.breadcrumbs a:hover {
background: rgba(120, 120, 128, 0.2);
}
#listing .item {
background: var(--surfacePrimary);
color: var(--textPrimary);
border-color: var(--divider) !important;
}
#listing .item i {
color: var(--icon);
}
#listing .item .modified {
color: var(--textSecondary);
}
#listing h2,
#listing.list .header span {
color: var(--textPrimary) !important;
}
#listing.list .header span {
color: var(--textPrimary);
}
#listing.list .header i {
color: var(--icon);
}
#listing.list .item.header {
background: var(--background);
}
.message {
color: var(--textPrimary);
}
.card {
background: #38393A !important;
color: var(--textPrimary) !important;
box-shadow: 0px 36px 100px rgba(0, 0, 0, 0.4), 0px 0px 3px rgba(0, 0, 0, 0.55) !important;
border-radius: 12px !important;
}
.card-title,
.card-content {
color: var(--textPrimary) !important;
}
.button--flat:hover {
background: var(--surfaceSecondary);
}
.dashboard #nav ul li {
color: var(--textSecondary);
}
.dashboard #nav ul li:hover {
background: var(--surfaceSecondary);
}
.card h3,
.dashboard #nav,
.dashboard p label {
color: var(--textPrimary);
}
.card#share input,
.card#share select,
.input {
background: var(--surfaceSecondary);
color: var(--textPrimary);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.input:hover,
.input:focus {
border-color: rgba(255, 255, 255, 0.15);
}
.input--red {
background: #73302D;
}
.input--green {
background: #147A41;
}
.dashboard #nav .wrapper,
.collapsible {
border-color: var(--divider);
}
.collapsible>label * {
color: var(--textPrimary);
}
table th {
color: var(--textSecondary);
}
.file-list li:hover {
background: var(--surfaceSecondary);
}
.file-list li:before {
color: var(--textSecondary);
}
.file-list li[aria-selected=true]:before {
color: var(--icon);
}
.shell {
background: var(--surfacePrimary);
color: var(--textPrimary);
}
.shell__divider {
background: rgba(255, 255, 255, 0.1);
}
.shell__divider:hover {
background: rgba(255, 255, 255, 0.4);
}
.shell__result {
border-top: 1px solid var(--divider);
}
#editor-container {
background: var(--background);
}
#editor-container .bar {
background: var(--surfacePrimary);
}
@media (max-width: 736px) {
#file-selection {
background: var(--surfaceSecondary) !important;
}
#file-selection span {
color: var(--textPrimary) !important;
}
nav {
background: var(--surfaceSecondary) !important;
}
#dropdown {
background: var(--surfaceSecondary) !important;
}
}
.share__box {
background: var(--surfacePrimary) !important;
color: var(--textPrimary);
}
.share__box__element {
border-top-color: var(--divider);
}
/*----------Custom---------------------------*/
body,
#login {
background-color: #303030 !important;
}
/* header {
background-color: #1b1b1b !important;
} */
#search #input {
background-color: #424242 !important;
color: rgba(255, 255, 255, 0.7) !important;
}
#listing.list .item,
#listing.mosaic .item {
background: rgba(50, 50, 50, 1) !important;
color: rgba(255, 255, 255, 0.7) !important;
}
#listing.list .item:hover,
#listing.mosaic .item:hover,
#listing .item[aria-selected=true] {
background: linear-gradient(0deg, rgba(30, 30, 30, 0.6), rgba(30, 30, 30, 0.6)), rgba(84, 84, 88, 0.3) !important;
}
/* #listing.mosaic,
.breadcrumbs {
background-color: #303030 !important;
} */
/*action*/
.action span {
color: #DFDEDF !important;
}
/* listing */
#listing .item .size,
#listing .item .modified {
color: rgba(223, 222, 223, 0.8) !important;
}
#listing .item .name {
color: #DFDEDF !important;
}
select,
textarea,
input,
.dashboard textarea,
.dashboard #locale,
.dashboard input[type=password],
.dashboard input[type=text] {
background: #212121;
color: rgba(255, 255, 255, 0.9) !important;
border-color: #303030;
}
.action,
#breadcrumbs,
#breadcrumbs span,
.dashboard #nav,
#login h1 {
color: rgba(255, 255, 255, 0.7) !important;
}
#search #result {
background-color: #212121 !important;
color: rgba(255, 255, 255, 0.7) !important;
}
.action:hover {
/* background: rgba(120, 120, 128, 0.2) !important; */
/* border: 1px solid transparent !important; */
box-shadow: unset !important;
border-radius: 45px !important;
}
nav>div:first-of-type:before {
/* color: rgba(255, 255, 255, 0.45)!important; */
}
nav.active,
#dropdown.active {
background-color: rgb(51, 51, 51) !important;
}
button[aria-label="New file"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/new-file-dark.svg') !important;
background-repeat: no-repeat;
background-position: 4px center;
}
button[aria-label="New folder"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/new-folder-dark.svg') !important;
background-repeat: no-repeat;
background-position: 4px center;
}
button[aria-label="Download"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/download-dark.svg') !important;
}
button[aria-label="Close"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/close-dark.svg') !important;
}
#dropdown button[aria-label="Rename"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/edit-dark.svg') !important;
background-repeat: no-repeat;
background-position: center;
width: 36px;
height: 36px;
}
/* button[aria-label="Delete"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/delete-dark.svg') !important;
} */
button[aria-label="Switch view"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/switch-view-dark.svg') !important;
}
button[aria-label="Upload"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/upload-dark.svg') !important;
}
button[aria-label="My files"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/files-dark.svg') !important;
background-repeat: no-repeat !important;
background-position: left center !important;
}
a[aria-label="Home"] {
background-image: url('https://evoque-localportal.s3.ap-south-1.amazonaws.com/file-browser/home-dark.svg') !important;
background-repeat: no-repeat !important;
background-position: 16px center !important;
width: 36px;
height: 36px;
background-size: auto;
}
.card .card-action.full .action .title,
.card.floating .card-title>h2 {
color: rgba(255, 255, 255, 1) !important;
}
.card.floating .card-content>p {
color: rgba(255, 255, 255, 0.8) !important;
}
.card#download,
.card.floating {
background: #38393A !important;
border: 0.5px solid #4C4C4C !important;
box-shadow: 0px 36px 100px rgba(0, 0, 0, 0.4), 0px 0px 3px rgba(0, 0, 0, 0.55) !important;
}
.card .card-action.full .action {
background: rgba(40, 40, 40, 1) !important;
}
.card .card-action.full .action:hover,
#download .card-content .button:hover {
background: linear-gradient(0deg, rgba(30, 30, 30, 0.6), rgba(30, 30, 30, 0.6)), rgba(84, 84, 88, 0.3) !important;
}
#download .card-content .button {
background: rgba(50, 50, 50, 1) !important;
color: rgba(223, 222, 223, 1) !important;
}
#previewer {
background-color: rgba(0, 0, 0, 0.9) !important;
}
#previewer header>title {
color: rgb(255, 255, 255) !important;
}
#search button[aria-label="Close"] {
background-image: unset !important;
}
#search.active #input>.action i {
background-color: rgba(255, 255, 255, .5) !important;
}
#previewer .preview .info {
color: #ffffff !important;
}
.button--flat.button--grey {
color: #ffff !important;
}
button[aria-label="Upload"]>i,
button[aria-label="Delete"]>i,
button[aria-label="Move file"]>i,
button[aria-label="Copy file"]>i,
button[aria-label="Share"]>i,
button[aria-label="Rename"]>i
{
display: none;
}
button[aria-label="Download"]>i {
display: none;
}
button[aria-label="Switch view"]>i {
display: none;
}
.card .card-action.full .action i {
font-size: 0;
}
.card .card-action.full .action .title {
margin-top: 10px;
}
a[aria-label="Home"]>i.material-icons {
font-size: 0 !important;
}
button[aria-label="My files"]>i {
display: none !important;
}
button[aria-label="New file"]>i {
display: none;
}
button[aria-label="New folder"]>i {
display: none;
}
#search .boxes i {
color: transparent !important;
font-size: 0 !important;
}
#dropdown.active button[aria-label="Switch view"] {
background-image: unset !important;
}
#dropdown.active button[aria-label="Switch view"] {
background-image: unset !important;
}
#dropdown.active button[aria-label="Upload"] {
background-image: unset !important;
}
#dropdown.active button[aria-label="Download"] {
background-image: unset !important
}
button[aria-label="More"].action:hover {
background-color: transparent !important;
}

View File

@ -1,111 +1,38 @@
<template> <template>
<div class="card floating"> <div class="card floating">
<div class="card-title"> <div class="card-title">
<h2>{{ t("prompts.upload") }}</h2> <h2>{{ $t("prompts.upload") }}</h2>
</div> </div>
<div class="card-content"> <div class="card-content">
<p>{{ t("prompts.uploadMessage") }}</p> <p>{{ $t("prompts.uploadMessage") }}</p>
</div> </div>
<div class="card-action full"> <div class="card-action full">
<div <div @click="uploadFile" class="action">
@click="uploadFile" <i class="material-icons"></i>
@keypress.enter="uploadFile" <div class="title">{{ $t("buttons.file") }}</div>
class="action"
id="focus-prompt"
tabindex="1"
>
<i class="material-icons">insert_drive_file</i>
<div class="title">{{ t("buttons.file") }}</div>
</div> </div>
<div <div @click="uploadFolder" class="action">
@click="uploadFolder" <i class="material-icons"></i>
@keypress.enter="uploadFolder" <div class="title">{{ $t("buttons.folder") }}</div>
class="action"
tabindex="2"
>
<i class="material-icons">folder</i>
<div class="title">{{ t("buttons.folder") }}</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script>
import { useI18n } from "vue-i18n"; export default {
import { useRoute } from "vue-router"; name: "upload",
import { useFileStore } from "@/stores/file"; methods: {
import { useLayoutStore } from "@/stores/layout"; uploadFile: function () {
document.getElementById("upload-input").value = "";
import * as upload from "@/utils/upload"; document.getElementById("upload-input").click();
},
const { t } = useI18n(); uploadFolder: function () {
const route = useRoute(); document.getElementById("upload-folder-input").value = "";
document.getElementById("upload-folder-input").click();
const fileStore = useFileStore(); },
const layoutStore = useLayoutStore(); },
// TODO: this is a copy of the same function in FileListing.vue
const uploadInput = (event: Event) => {
layoutStore.closeHovers();
let files = (event.currentTarget as HTMLInputElement)?.files;
if (files === null) return;
let folder_upload = !!files[0].webkitRelativePath;
const uploadFiles: UploadList = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const fullPath = folder_upload ? file.webkitRelativePath : undefined;
uploadFiles.push({
file,
name: file.name,
size: file.size,
isDir: false,
fullPath,
});
}
let path = route.path.endsWith("/") ? route.path : route.path + "/";
let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
if (conflict) {
layoutStore.showHover({
prompt: "replace",
action: (event: Event) => {
event.preventDefault();
layoutStore.closeHovers();
upload.handleFiles(uploadFiles, path, false);
},
confirm: (event: Event) => {
event.preventDefault();
layoutStore.closeHovers();
upload.handleFiles(uploadFiles, path, true);
},
});
return;
}
upload.handleFiles(uploadFiles, path);
};
const openUpload = (isFolder: boolean) => {
const input = document.createElement("input");
input.type = "file";
input.multiple = true;
input.webkitdirectory = isFolder;
// TODO: call the function in FileListing.vue instead
input.onchange = uploadInput;
input.click();
};
const uploadFile = () => {
openUpload(false);
};
const uploadFolder = () => {
openUpload(true);
}; };
</script> </script>

View File

@ -1,14 +1,14 @@
.button { .button {
outline: 0; outline: 0;
border: 0; border: 0;
padding: 0.5em 1em; padding: .5em 1em;
border-radius: 0.1em; border-radius: .1em;
cursor: pointer; cursor: pointer;
background: var(--blue); background: var(--blue);
color: white; color: white;
border: 1px solid var(--divider); border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 0 5px var(--divider); box-shadow: 0 0 5px rgba(0, 0, 0, 0.05);
transition: 0.1s ease all; transition: .1s ease all;
} }
.button:hover { .button:hover {
@ -38,7 +38,7 @@
} }
.button--flat:hover { .button--flat:hover {
background: var(--surfaceSecondary); background: var(--moon-grey);
} }
.button--flat.button--red { .button--flat.button--red {
@ -50,6 +50,6 @@
} }
.button[disabled] { .button[disabled] {
opacity: 0.5; opacity: .5;
cursor: not-allowed; cursor: not-allowed;
} }

View File

@ -1,35 +1,35 @@
.input { .input {
background: var(--surfacePrimary); border-radius: .1em;
color: var(--textSecondary); padding: .5em 1em;
border: 1px solid var(--borderPrimary); background: white;
border-radius: 0.1em; border: 1px solid rgba(0, 0, 0, 0.1);
padding: 0.5em 1em; transition: .2s ease all;
transition: 0.2s ease all; color: #333;
margin: 0; margin: 0;
} }
.input:hover, .input:hover,
.input:focus { .input:focus {
border-color: var(--borderSecondary); border-color: rgba(0, 0, 0, 0.2);
} }
.input--block { .input--block {
margin-bottom: 0.5em; margin-bottom: .5em;
display: block; display: block;
width: 100%; width: 100%;
} }
.input--textarea { .input--textarea {
line-height: 1.15; line-height: 1.15;
font-family: monospace; font-family: "Inter", sans-serif;
min-height: 10em; min-height: 10em;
resize: vertical; resize: vertical;
} }
.input--red { .input--red {
background: var(--input-red) !important; background: #fcd0cd;
} }
.input--green { .input--green {
background: var(--input-green) !important; background: #c9f2da;
} }

View File

@ -12,11 +12,8 @@
} }
.share__box { .share__box {
box-shadow: box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
rgba(0, 0, 0, 0.06) 0px 1px 3px, background: #fff;
rgba(0, 0, 0, 0.12) 0px 1px 2px;
background: var(--surfacePrimary);
color: var(--textPrimary);
border-radius: 0.2em; border-radius: 0.2em;
margin: 5px; margin: 5px;
overflow: hidden; overflow: hidden;
@ -42,7 +39,7 @@
.share__box__element { .share__box__element {
padding: 1em; padding: 1em;
border-top: 1px solid var(--borderPrimary); border-top: 1px solid rgba(0, 0, 0, 0.1);
word-break: break-all; word-break: break-all;
} }
@ -65,7 +62,7 @@
border-left: 0; border-left: 0;
border-right: 0; border-right: 0;
border-bottom: 0; border-bottom: 0;
border-top: 1px solid var(--borderPrimary); border-top: 1px solid rgba(0, 0, 0, 0.1);
} }
.share__box__items #listing.list .item .name { .share__box__items #listing.list .item .name {
@ -79,7 +76,7 @@
.share__wrong__password { .share__wrong__password {
background: var(--red); background: var(--red);
color: #fff; color: #fff;
padding: 0.5em; padding: .5em;
text-align: center; text-align: center;
animation: 0.2s opac forwards; animation: .2s opac forwards;
} }

View File

@ -3,8 +3,17 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
max-height: calc(100% - 4em); max-height: calc(100% - 4em);
background: var(--surfacePrimary); background: white;
color: var(--textPrimary); color: #212121;
z-index: 9997;
width: 100%;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
transition: .2s ease transform;
}
.shell__divider {
position: relative;
height: 8px;
z-index: 9999; z-index: 9999;
background: rgba(127, 127, 127, 0.1); background: rgba(127, 127, 127, 0.1);
transition: 0.2s ease background; transition: 0.2s ease background;
@ -23,8 +32,6 @@
overflow: auto; overflow: auto;
font-size: 1rem; font-size: 1rem;
cursor: text; cursor: text;
box-shadow: 0 0 5px var(--borderPrimary);
transition: 0.2s ease transform;
} }
.shell__overlay { .shell__overlay {
@ -45,7 +52,7 @@ body.rtl .shell-content {
display: flex; display: flex;
padding: 0.5em; padding: 0.5em;
align-items: flex-start; align-items: flex-start;
border-top: 1px solid var(--divider); border-top: 1px solid rgba(0, 0, 0, 0.05);
} }
.shell--hidden { .shell--hidden {

View File

@ -1,8 +1,8 @@
:root { :root {
--blue: #2196f3; --blue: #2196f3;
--dark-blue: #1e88e5; --dark-blue: #1E88E5;
--red: #f44336; --red: #F44336;
--dark-red: #d32f2f; --dark-red: #D32F2F;
--moon-grey: #f2f2f2; --moon-grey: #f2f2f2;
--icon-red: #da4453; --icon-red: #da4453;
@ -11,44 +11,4 @@
--icon-green: #2ecc71; --icon-green: #2ecc71;
--icon-blue: #1d99f3; --icon-blue: #1d99f3;
--icon-violet: #9b59b6; --icon-violet: #9b59b6;
--input-red: rgb(252, 208, 205);
--input-green: rgb(201, 242, 218);
--item-selected: white;
--action: rgb(84, 110, 122);
--background: rgb(250, 250, 250);
--surfacePrimary: rgb(255, 255, 255);
--surfaceSecondary: rgb(230, 230, 230);
--divider: rgba(0, 0, 0, 0.05);
--iconPrimary: var(--icon-blue);
--iconSecondary: rgb(255, 255, 255);
--iconTertiary: rgb(204, 204, 204);
--textPrimary: rgb(111, 111, 111);
--textSecondary: rgb(51, 51, 51);
--hover: rgba(0, 0, 0, 0.1);
--borderPrimary: rgba(0, 0, 0, 0.1);
--borderSecondary: rgba(0, 0, 0, 0.2);
}
:root.dark {
--input-red: rgb(115, 48, 45);
--input-green: rgb(20, 122, 65);
--action: rgb(255, 255, 255);
--background: rgb(20, 29, 36);
--surfacePrimary: rgb(32, 41, 47);
--surfaceSecondary: rgb(58, 65, 71);
--textPrimary: rgba(255, 255, 255, 0.6);
--textSecondary: rgba(255, 255, 255, 0.87);
--divider: rgba(255, 255, 255, 0.12);
--iconPrimary: rgb(255, 255, 255);
--iconSecondary: rgb(255, 255, 255);
--iconTertiary: rgb(255, 255, 255);
--hover: rgba(255, 255, 255, 0.1);
--borderPrimary: rgba(255, 255, 255, 0.05);
--borderSecondary: rgba(255, 255, 255, 0.15);
} }

View File

@ -1,180 +1,154 @@
body { body {
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
padding-top: 4em; padding-top: 4em;
background: var(--background); background-color: #fafafa;
color: var(--textSecondary); color: #333333;
}
body.rtl {
direction: rtl;
} }
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
*, *,
*:hover, *:hover,
*:active, *:active,
*:focus { *:focus {
outline: 0; outline: 0;
} }
a { a {
text-decoration: none; text-decoration: none;
} }
img { img {
max-width: 100%; max-width: 100%;
} }
audio, audio,
video { video {
width: 100%; width: 100%;
} }
.mobile-only { .mobile-only {
display: none !important; display: none !important;
} }
.container { .container {
width: 95%; width: 95%;
max-width: 960px; max-width: 960px;
margin: 1em auto 0; margin: 1em auto 0;
} }
i.spin { i.spin {
animation: 1s spin linear infinite; animation: 1s spin linear infinite;
} }
#app { #app {
transition: 0.2s ease padding; transition: 0.2s ease padding;
} }
#app.multiple { #app.multiple {
padding-bottom: 4em; padding-bottom: 4em;
} }
nav { nav {
width: 16em; width: 16em;
position: fixed; position: fixed;
top: 4em; top: 4em;
left: 0; left: 0;
} }
html[dir="rtl"] nav { body.rtl nav {
left: initial; left: unset;
right: 0; right: 0;
} }
nav .action { nav .action {
width: 100%; width: 100%;
display: block; display: block;
border-radius: 0; border-radius: 0;
font-size: 1.1em; font-size: 1.1em;
padding: 0.5em; padding: 0.5em;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
html[dir="rtl"] nav .action { body.rtl .action {
text-align: right; direction: rtl;
text-align: right;
} }
nav > div { nav>div {
border-top: 1px solid var(--divider); border-top: 1px solid rgba(0, 0, 0, 0.05);
} }
nav .action > * { nav .action>* {
vertical-align: middle; vertical-align: middle;
} }
main { main {
min-height: 1em; min-height: 1em;
margin: 0 1em 1em auto; margin: 0 1em 1em auto;
width: calc(100% - 19em); width: calc(100% - 19em);
} }
.breadcrumbs { .breadcrumbs {
height: 3em; height: 3em;
background: var(--background); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
border-bottom: 1px solid var(--divider);
} }
.breadcrumbs span, .breadcrumbs span,
.breadcrumbs { .breadcrumbs {
display: flex; display: flex;
align-items: center; align-items: center;
color: var(--textPrimary); color: #6f6f6f;
} }
.breadcrumbs a { .breadcrumbs a {
color: inherit; color: inherit;
transition: 0.1s ease-in; transition: 0.1s ease-in;
border-radius: 0.125em; border-radius: 0.125em;
} }
html[dir="rtl"] .breadcrumbs a { body.rtl .breadcrumbs a {
transform: translateX(-16em); transform: translateX(-16em);
} }
.breadcrumbs a:hover { .breadcrumbs a:hover {
background-color: var(--divider); background-color: rgba(0, 0, 0, 0.05);
} }
.breadcrumbs span a { .breadcrumbs span a {
padding: 0.2em; padding: 0.2em;
} }
.files { .files {
position: absolute; position: absolute;
bottom: 30px; bottom: 30px;
width: 100%; width: 100%;
} }
.progress { .progress {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 3px; height: 3px;
z-index: 9999999999; z-index: 9999999999;
} }
.progress div { .progress div {
height: 100%; height: 100%;
background-color: #40c4ff; background-color: #40c4ff;
width: 0; width: 0;
transition: 0.2s ease width; transition: 0.2s ease width;
} }
.break-word { .break-word {
word-break: break-all; word-break: break-all;
} }
.vue-number-input > input {
background: var(--surfacePrimary) !important;
border-color: var(--surfaceSecondary) !important;
color: var(--textSecondary) !important;
}
.vue-number-input--small > input {
height: 1rem !important;
font-size: 1rem !important;
}
.vue-number-input :hover,
.vue-number-input :focus {
border-color: var(--borderSecondary) !important;
}
.vue-number-input__button {
background: var(--surfacePrimary) !important;
}
.vue-number-input__button--minus,
.vue-number-input__button--plus {
border-color: var(--surfaceSecondary) !important;
}
.vue-number-input__button::before,
.vue-number-input__button::after {
background: var(--textSecondary) !important;
}

1098
frontend/src/css/custom.css Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,17 +4,17 @@
.dashboard .row { .dashboard .row {
display: flex; display: flex;
margin: 0 -0.5em; margin: 0 -.5em;
flex-wrap: wrap; flex-wrap: wrap;
} }
html[dir="rtl"] .dashboard .row { body.rtl .dashboard .row {
margin-right: 16em; margin-right: 16em;
} }
.dashboard .row .column { .dashboard .row .column {
display: flex; display: flex;
padding: 0 0.5em; padding: 0 .5em;
width: 50%; width: 50%;
} }
@ -22,33 +22,33 @@ html[dir="rtl"] .dashboard .row {
flex-grow: 1; flex-grow: 1;
} }
@media (max-width: 1200px) { @media(max-width: 1200px) {
.dashboard .row .column { .dashboard .row .column {
width: 100%; width: 100%;
} }
} }
a { a {
color: inherit; color: inherit
} }
.dashboard p label { .dashboard p label {
margin-bottom: 0.2em; margin-bottom: .2em;
display: block; display: block;
font-size: 0.8em; font-size: .8em;
font-weight: 500; font-weight: 500;
color: var(--textPrimary); color: rgba(0, 0, 0, 0.57);
} }
li code, li code,
p code { p code {
background: var(--divider); background: rgba(0, 0, 0, 0.05);
padding: 0.1em; padding: .1em;
border-radius: 0.2em; border-radius: .2em;
} }
.small { .small {
font-size: 0.8em; font-size: .8em;
line-height: 1.5; line-height: 1.5;
} }
@ -61,21 +61,21 @@ p code {
.dashboard #nav .wrapper { .dashboard #nav .wrapper {
display: flex; display: flex;
flex-grow: 1; flex-grow: 1;
border-bottom: 2px solid var(--divider); border-bottom: 2px solid rgba(0, 0, 0, 0.05);
} }
html[dir="rtl"] .dashboard #nav .wrapper { body.rtl #nav .wrapper {
margin-right: 16em; margin-right: 16em;
} }
.dashboard #nav ul { .dashboard #nav ul {
list-style: none; list-style: none;
display: flex; display: flex;
color: var(--action); color: rgb(84, 110, 122);
font-weight: 500; font-weight: 500;
padding: 0; padding: 0;
margin: 0 0 -2px 0; margin: 0 0 -2px 0;
font-size: 0.8em; font-size: .8em;
text-align: center; text-align: center;
justify-content: left; justify-content: left;
} }
@ -85,11 +85,12 @@ html[dir="rtl"] .dashboard #nav .wrapper {
padding: 1.5em 2em; padding: 1.5em 2em;
white-space: nowrap; white-space: nowrap;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
transition: 0.1s ease-in-out all; transition: .1s ease-in-out all;
} }
.dashboard #nav ul li:hover { .dashboard #nav ul li:hover {
background: var(--surfaceSecondary); background: var(--moon-grey);
} }
.dashboard #nav ul li.active { .dashboard #nav ul li.active {
@ -119,7 +120,7 @@ table {
} }
table tr { table tr {
border-bottom: 1px solid var(--iconTertiary); border-bottom: 1px solid #ccc;
} }
table tr:last-child { table tr:last-child {
@ -128,44 +129,40 @@ table tr:last-child {
table th { table th {
font-weight: 500; font-weight: 500;
color: var(--textSecondary); color: #757575;
text-align: left; text-align: left;
} }
table th, table th,
table td { table td {
padding: 0.5em 0; padding: .5em 0;
} }
table td.small { table td.small {
width: 1em; width: 1em;
} }
table tr > *:first-child { table tr>*:first-child {
padding-left: 1em; padding-left: 1em;
} }
html[dir="rtl"] table tr > * { body.rtl table tr>* {
padding-left: unset; padding-left: unset;
padding-right: 1em; padding-right: 1em;
text-align: right; text-align: right;
direction: ltr; direction: ltr;
} }
table tr > *:last-child { table tr>*:last-child {
padding-right: 1em; padding-right: 1em;
} }
.card { .card {
position: relative; position: relative;
margin: 0 0 1rem 0; margin: 0 0 1rem 0;
background: var(--surfacePrimary); background-color: #fff;
color: var(--textSecondary);
border-radius: 2px; border-radius: 2px;
box-shadow: box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12),
0 3px 1px -2px rgba(0, 0, 0, 0.2);
overflow: auto; overflow: auto;
} }
@ -174,18 +171,18 @@ table tr > *:last-child {
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 99999;
max-width: 25em; max-width: 25em;
width: 90%; width: 90%;
max-height: 95%; max-height: 95%;
/* animation-duration: 0.3s; animation: .1s show forwards;
animation-fill-mode: forwards; */
} }
.card > * > *:first-child { .card>*>*:first-child {
margin-top: 0; margin-top: 0;
} }
.card > * > *:last-child { .card>*>*:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
@ -194,24 +191,24 @@ table tr > *:last-child {
display: flex; display: flex;
} }
.card .card-title > *:first-child { .card .card-title>*:first-child {
margin-right: auto; margin-right: auto;
} }
html[dir="rtl"] .card .card-title > *:first-child { body.rtl .card .card-title>*:first-child {
margin-right: 0; margin-right: 0;
text-align: right; text-align: right;
} }
.card > div { .card>div {
padding: 1em 1em; padding: 1em 1em;
} }
.card > div:first-child { .card>div:first-child {
padding-top: 1.5em; padding-top: 1.5em;
} }
.card > div:last-child { .card>div:last-child {
padding-bottom: 1.5em; padding-bottom: 1.5em;
} }
@ -237,7 +234,7 @@ body.rtl .card .card-action {
} }
.card h3 { .card h3 {
color: var(--textPrimary); color: rgba(0, 0, 0, 0.53);
font-size: 1em; font-size: 1em;
font-weight: 500; font-weight: 500;
margin: 2em 0 1em; margin: 2em 0 1em;
@ -256,14 +253,6 @@ body.rtl .card .card-action {
max-width: 15em; max-width: 15em;
} }
.card#share input,
.card#share select,
.card#share input::-webkit-inner-spin-button,
.card#share input::-webkit-outer-spin-button {
background: var(--surfacePrimary);
color: var(--textSecondary);
}
.card#share ul { .card#share ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
@ -288,24 +277,24 @@ body.rtl .card .card-action {
.card#share ul li input, .card#share ul li input,
.card#share ul li select { .card#share ul li select {
padding: 0.2em; padding: .2em;
margin-right: 0.5em; margin-right: .5em;
border: 1px solid var(--borderPrimary); border: 1px solid #dadada;
} }
.card#share .action.copy-clipboard::after { .card#share .action.copy-clipboard::after {
content: "Copied!"; content: 'Copied!';
position: absolute; position: absolute;
left: -25%; left: -25%;
width: 150%; width: 150%;
font-size: 0.6em; font-size: .6em;
text-align: center; text-align: center;
background: #44a6f5; background: #44a6f5;
color: #fff; color: #fff;
padding: 0.5em 0.2em; padding: .5em .2em;
border-radius: 0.4em; border-radius: .4em;
top: -2em; top: -2em;
transition: 0.1s ease opacity; transition: .1s ease opacity;
opacity: 0; opacity: 0;
} }
@ -335,9 +324,10 @@ body.rtl .card .card-action {
z-index: 9999; z-index: 9999;
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
animation: 0.1s show forwards; animation: .1s show forwards;
} }
/* * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * *
* PROMPT - MOVE * * PROMPT - MOVE *
* * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * */
@ -354,33 +344,33 @@ body.rtl .card .card-action {
.file-list li { .file-list li {
width: 100%; width: 100%;
user-select: none; user-select: none;
border-radius: 0.2em; border-radius: .2em;
padding: 0.3em; padding: .3em;
} }
.file-list li[aria-selected="true"] { .file-list li[aria-selected=true] {
background: var(--blue) !important; background: var(--blue) !important;
color: var(--iconSecondary) !important; color: #fff !important;
transition: 0.1s ease all; transition: .1s ease all;
} }
.file-list li:hover { .file-list li:hover {
background: var(--surfaceSecondary); background-color: #e9eaeb;
cursor: pointer; cursor: pointer;
} }
.file-list li:before { .file-list li:before {
content: "folder"; content: "folder";
color: var(--textPrimary); color: #6f6f6f;
vertical-align: middle; vertical-align: middle;
line-height: 1.4; line-height: 1.4;
font-family: "Material Icons"; font-family: 'Material Icons';
font-size: 1.75em; font-size: 1.75em;
margin-right: 0.25em; margin-right: .25em;
} }
.file-list li[aria-selected="true"]:before { .file-list li[aria-selected=true]:before {
color: var(--iconSecondary); color: white;
} }
.help { .help {
@ -409,11 +399,11 @@ body.rtl .card .card-action {
} }
.collapsible { .collapsible {
border-top: 1px solid var(--borderPrimary); border-top: 1px solid rgba(0,0,0,0.1);
} }
.collapsible:last-of-type { .collapsible:last-of-type {
border-bottom: 1px solid var(--borderPrimary); border-bottom: 1px solid rgba(0,0,0,0.1);
} }
.collapsible > input { .collapsible > input {
@ -431,18 +421,18 @@ body.rtl .card .card-action {
.collapsible > label * { .collapsible > label * {
margin: 0; margin: 0;
color: var(--textPrimary); color: rgba(0,0,0,0.57);
} }
.collapsible > label i { .collapsible > label i {
transition: 0.2s ease transform; transition: .2s ease transform;
user-select: none; user-select: none;
} }
.collapsible .collapse { .collapsible .collapse {
max-height: 0; max-height: 0;
overflow: hidden; overflow: hidden;
transition: 0.2s ease all; transition: .2s ease all;
} }
.collapsible > input:checked ~ .collapse { .collapsible > input:checked ~ .collapse {
@ -452,7 +442,7 @@ body.rtl .card .card-action {
} }
.collapsible > input:checked ~ label i { .collapsible > input:checked ~ label i {
transform: rotate(180deg); transform: rotate(180deg)
} }
.card .collapsible { .card .collapsible {
@ -478,12 +468,12 @@ body.rtl .card .card-action {
flex: 1; flex: 1;
padding: 2em; padding: 2em;
border-radius: 0.2em; border-radius: 0.2em;
border: 1px solid var(--borderPrimary); border: 1px solid rgba(0, 0, 0, 0.1);
text-align: center; text-align: center;
} }
.card .card-action.full .action { .card .card-action.full .action {
margin: 0 0.25em 0.5em; margin: 0 0.25em 0.50em;
} }
.card .card-action.full .action i { .card .card-action.full .action i {
@ -499,7 +489,7 @@ body.rtl .card .card-action {
} }
/*** RTL - Fix disk usage information (in english) ***/ /*** RTL - Fix disk usage information (in english) ***/
html[dir="rtl"] .credits { body.rtl .credits {
text-align: right; text-align: right;
direction: ltr; direction: ltr;
} }

View File

@ -1,279 +1,273 @@
header { header {
z-index: 1000; z-index: 1000;
background: var(--surfacePrimary); background-color: #fff;
border-bottom: 1px solid var(--divider); border-bottom: 1px solid rgba(0, 0, 0, 0.075);
box-shadow: 0 0 5px var(--borderPrimary); box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
height: 4em; height: 4em;
width: 100%; width: 100%;
padding: 0; padding: 0;
display: flex; display: flex;
padding: 0.5em 0.5em 0.5em 1em; padding: 0.5em 0.5em 0.5em 1em;
align-items: center; align-items: center;
} }
header > * { header>* {
flex: 0 0 auto; flex: 0 0 auto;
} }
header title { header title {
display: block; display: block;
flex: 1 1 auto; flex: 1 1 auto;
padding: 0 1em; padding: 0 1em;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
font-size: 1.2em; font-size: 1.2em;
} }
header .overlay { header .overlay {
width: 0; width: 0;
height: 0; height: 0;
} }
header a, header a,
header a:hover { header a:hover {
color: inherit; color: inherit;
} }
header > div:first-child > .action, header>div:first-child>.action,
header img { header img {
margin-right: 1em; margin-right: 1em;
} }
header img { header img {
height: 2.5em; height: 2.5em;
} }
header .action span { header .action span {
display: none; display: none;
} }
header > div div { header>div div {
vertical-align: middle; vertical-align: middle;
position: relative; position: relative;
} }
header .search-button, header .search-button,
header .menu-button { header .menu-button {
display: none; display: none;
} }
#more { #more {
display: none; display: none;
} }
#search { #search {
position: relative; position: relative;
height: 100%; height: 100%;
width: 100%; width: 100%;
max-width: 25em; max-width: 25em;
} }
#search.active { #search.active {
position: fixed; position: fixed;
top: 0; top: 0;
right: 0; right: 0;
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
height: 100%; height: 100%;
z-index: 9999; z-index: 9999;
} }
#search #input { #search #input {
background: var(--surfaceSecondary); background-color: #f5f5f5;
border-color: var(--surfacePrimary); display: flex;
display: flex; height: 100%;
height: 100%; padding: 0em 0.75em;
padding: 0em 0.75em; border-radius: 0.3em;
border-radius: 0.3em; transition: .1s ease all;
transition: 0.1s ease all; align-items: center;
align-items: center; z-index: 2;
z-index: 2;
}
#search #input input::placeholder {
color: var(--textSecondary);
} }
#search.active #input { #search.active #input {
border-bottom: 1px solid var(--borderPrimary); border-bottom: 1px solid rgba(0, 0, 0, 0.075);
box-shadow: 0 0 5px var(--borderPrimary); box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: var(--surfacePrimary); background-color: #fff;
height: 4em; height: 4em;
} }
#search.active > div { #search.active>div {
border-radius: 0 !important; border-radius: 0 !important;
} }
#search.active i, #search.active i,
#search.active input { #search.active input {
color: var(--textPrimary); color: #212121;
} }
#search #input > .action, #search #input>.action,
#search #input > i { #search #input>i {
margin-right: 0.3em; margin-right: 0.3em;
user-select: none; user-select: none;
} }
#search input { #search input {
width: 100%; width: 100%;
border: 0; border: 0;
background-color: transparent; background-color: transparent;
padding: 0; padding: 0;
} }
#search #result { #search #result {
visibility: visible; visibility: visible;
max-height: none; max-height: none;
background: var(--background); background-color: #f8f8f8;
text-align: left; text-align: left;
padding: 0; padding: 0;
color: var(--textPrimary); color: rgba(0, 0, 0, 0.6);
height: 0; height: 0;
transition: transition: .1s ease height, .1s ease padding;
0.1s ease height, overflow-x: hidden;
0.1s ease padding; overflow-y: auto;
overflow-x: hidden; z-index: 1;
overflow-y: auto;
z-index: 1;
} }
html[dir="rtl"] #search #result { body.rtl #search #result {
direction: ltr; direction: ltr;
} }
#search #result > div > *:first-child { #search #result>div>*:first-child {
margin-top: 0; margin-top: 0;
} }
html[dir="rtl"] #search #result { body.rtl #search #result {
text-align: right; direction: rtl;
text-align: right;
} }
/*** RTL - Keep search result LTR because it has paths (in english) ***/ /*** RTL - Keep search result LTR because it has paths (in english) ***/
html[dir="rtl"] #search #result ul > * { body.rtl #search #result ul>* {
direction: ltr; direction: ltr;
text-align: left; text-align: left;
} }
#search.active #result { #search.active #result {
padding: 0.5em; padding: .5em;
height: calc(100% - 4em); height: calc(100%);
} }
#search ul { #search ul {
padding: 0; padding: 0;
margin: 0; margin: 0;
list-style: none; list-style: none;
} }
#search li { #search li {
margin-bottom: 0.5em; margin-bottom: .5em;
} }
#search #result > div { #search #result>div {
max-width: 45em; max-width: 45em;
margin: 0 auto; margin: 0 auto;
} }
#search #result #renew { #search #result #renew {
width: 100%; width: 100%;
text-align: center; text-align: center;
display: none; display: none;
margin: 0; margin: 0;
max-width: none; max-width: none;
} }
#search.ongoing #result #renew { #search.ongoing #result #renew {
display: block; display: block;
} }
#search.active #result i { #search.active #result i {
color: var(--iconTertiary); color: #ccc;
} }
#search.active #result > p > i { #search.active #result>p>i {
text-align: center; text-align: center;
margin: 0 auto; margin: 0 auto;
display: table; display: table;
} }
#search.active #result ul li a { #search.active #result ul li a {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0.3em 0; padding: .3em 0;
} }
#search.active #result ul li a i { #search.active #result ul li a i {
margin-right: 0.3em; margin-right: .3em;
} }
/* I dont think we need these anymore */ #search::-webkit-input-placeholder {
/* #search::-webkit-input-placeholder { color: rgba(255, 255, 255, .5);
color: var(--textPrimary); }
#search:-moz-placeholder {
opacity: 1;
color: rgba(255, 255, 255, .5);
} }
#search::-moz-placeholder { #search::-moz-placeholder {
opacity: 1; opacity: 1;
color: var(--textPrimary); color: rgba(255, 255, 255, .5);
} }
#search:-ms-input-placeholder { #search:-ms-input-placeholder {
color: var(--textPrimary); color: rgba(255, 255, 255, .5);
} }
#search #input input::placeholder {
color: var(--textPrimary);
} */
#search .boxes { #search .boxes {
border: 1px solid var(--borderPrimary); border: 1px solid rgba(0, 0, 0, 0.075);
box-shadow: 0 0 5px var(--borderPrimary); box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: var(--surfacePrimary); background: #fff;
margin: 1em 0; margin: 1em 0;
} }
#search .boxes h3 { #search .boxes h3 {
margin: 0; margin: 0;
font-weight: 500; font-weight: 500;
font-size: 1em; font-size: 1em;
color: var(--textSecondary); color: #212121;
padding: 0.5em; padding: .5em;
} }
html[dir="rtl"] #search .boxes h3 { body.rtl #search .boxes h3 {
text-align: right; text-align: right;
} }
#search .boxes > div { #search .boxes>div {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
margin-right: -1em; margin-right: -1em;
margin-bottom: -1em; margin-bottom: -1em;
} }
#search .boxes > div > div { #search .boxes>div>div {
background: var(--blue); background: var(--blue);
color: #fff; color: #fff;
text-align: center; text-align: center;
width: 10em; width: 10em;
padding: 1em; padding: 1em;
cursor: pointer; cursor: pointer;
margin-bottom: 1em; margin-bottom: 1em;
margin-right: 1em; margin-right: 1em;
flex-grow: 1; flex-grow: 1;
} }
#search .boxes p { #search .boxes p {
margin: 1em 0 0; margin: 1em 0 0;
} }
#search .boxes i { #search .boxes i {
color: #fff !important; color: #fff !important;
font-size: 3.5em; font-size: 3.5em;
} }

View File

@ -2,50 +2,30 @@
/* General */ /* General */
.file-icons [aria-label^="."] { .file-icons [aria-label^="."] { opacity: 0.33 }
opacity: 0.33; .file-icons [aria-label$=".bak"] { opacity: 0.33 }
}
.file-icons [aria-label$=".bak"] {
opacity: 0.33;
}
.file-icons [data-type="audio"] i::before { .file-icons [data-type=audio] i::before { content: 'volume_up' }
content: "volume_up"; .file-icons [data-type=blob] i::before { content: 'insert_drive_file' }
} .file-icons [data-type=image] i::before { content: 'image' }
.file-icons [data-type="blob"] i::before { .file-icons [data-type=pdf] i::before { content: 'description' }
content: "insert_drive_file"; .file-icons [data-type=text] i::before { content: 'description' }
} .file-icons [data-type=video] i::before { content: 'movie' }
.file-icons [data-type="image"] i::before { .file-icons [data-type=invalid_link] i::before { content: 'link_off' }
content: "image";
}
.file-icons [data-type="pdf"] i::before {
content: "description";
}
.file-icons [data-type="text"] i::before {
content: "description";
}
.file-icons [data-type="video"] i::before {
content: "movie";
}
.file-icons [data-type="invalid_link"] i::before {
content: "link_off";
}
/* #f90 - Image */ /* #f90 - Image */
.file-icons [aria-label$=".ai"] i::before, .file-icons [aria-label$=".ai"] i::before,
.file-icons [aria-label$=".odg"] i::before, .file-icons [aria-label$=".odg"] i::before,
.file-icons [aria-label$=".xcf"] i::before { .file-icons [aria-label$=".xcf"] i::before
content: "image"; { content: 'image' }
}
/* #f90 - Presentation */ /* #f90 - Presentation */
.file-icons [aria-label$=".odp"] i::before, .file-icons [aria-label$=".odp"] i::before,
.file-icons [aria-label$=".ppt"] i::before, .file-icons [aria-label$=".ppt"] i::before,
.file-icons [aria-label$=".pptx"] i::before { .file-icons [aria-label$=".pptx"] i::before
content: "slideshow"; { content: 'slideshow' }
}
/* #0f0 - Spreadsheet/Database */ /* #0f0 - Spreadsheet/Database */
@ -54,9 +34,8 @@
.file-icons [aria-label$=".odb"] i::before, .file-icons [aria-label$=".odb"] i::before,
.file-icons [aria-label$=".ods"] i::before, .file-icons [aria-label$=".ods"] i::before,
.file-icons [aria-label$=".xls"] i::before, .file-icons [aria-label$=".xls"] i::before,
.file-icons [aria-label$=".xlsx"] i::before { .file-icons [aria-label$=".xlsx"] i::before
content: "border_all"; { content: 'border_all' }
}
/* #00f - Document */ /* #00f - Document */
@ -64,9 +43,8 @@
.file-icons [aria-label$=".docx"] i::before, .file-icons [aria-label$=".docx"] i::before,
.file-icons [aria-label$=".log"] i::before, .file-icons [aria-label$=".log"] i::before,
.file-icons [aria-label$=".odt"] i::before, .file-icons [aria-label$=".odt"] i::before,
.file-icons [aria-label$=".rtf"] i::before { .file-icons [aria-label$=".rtf"] i::before
content: "description"; { content: 'description' }
}
/* #999 - Code */ /* #999 - Code */
@ -87,9 +65,8 @@
.file-icons [aria-label$=".rs"] i::before, .file-icons [aria-label$=".rs"] i::before,
.file-icons [aria-label$=".vue"] i::before, .file-icons [aria-label$=".vue"] i::before,
.file-icons [aria-label$=".xml"] i::before, .file-icons [aria-label$=".xml"] i::before,
.file-icons [aria-label$=".yml"] i::before { .file-icons [aria-label$=".yml"] i::before
content: "code"; { content: 'code' }
}
/* #999 - Executable */ /* #999 - Executable */
@ -98,18 +75,16 @@
.file-icons [aria-label$=".exe"] i::before, .file-icons [aria-label$=".exe"] i::before,
.file-icons [aria-label$=".jar"] i::before, .file-icons [aria-label$=".jar"] i::before,
.file-icons [aria-label$=".ps1"] i::before, .file-icons [aria-label$=".ps1"] i::before,
.file-icons [aria-label$=".sh"] i::before { .file-icons [aria-label$=".sh"] i::before
content: "web_asset"; { content: 'web_asset' }
}
/* #999 - Installer */ /* #999 - Installer */
.file-icons [aria-label$=".deb"] i::before, .file-icons [aria-label$=".deb"] i::before,
.file-icons [aria-label$=".msi"] i::before, .file-icons [aria-label$=".msi"] i::before,
.file-icons [aria-label$=".pkg"] i::before, .file-icons [aria-label$=".pkg"] i::before,
.file-icons [aria-label$=".rpm"] i::before { .file-icons [aria-label$=".rpm"] i::before
content: "archive"; { content: 'archive' }
}
/* #999 - Compressed */ /* #999 - Compressed */
@ -121,9 +96,8 @@
.file-icons [aria-label$=".tar"] i::before, .file-icons [aria-label$=".tar"] i::before,
.file-icons [aria-label$=".xz"] i::before, .file-icons [aria-label$=".xz"] i::before,
.file-icons [aria-label$=".zip"] i::before, .file-icons [aria-label$=".zip"] i::before,
.file-icons [aria-label$=".zst"] i::before { .file-icons [aria-label$=".zst"] i::before
content: "folder_zip"; { content: 'folder_zip' }
}
/* #999 - Disk */ /* #999 - Disk */
@ -134,35 +108,25 @@
.file-icons [aria-label$=".vdi"] i::before, .file-icons [aria-label$=".vdi"] i::before,
.file-icons [aria-label$=".vhd"] i::before, .file-icons [aria-label$=".vhd"] i::before,
.file-icons [aria-label$=".vmdk"] i::before, .file-icons [aria-label$=".vmdk"] i::before,
.file-icons [aria-label$=".wim"] i::before { .file-icons [aria-label$=".wim"] i::before
content: "album"; { content: 'album' }
}
/* #999 - Font */ /* #999 - Font */
.file-icons [aria-label$=".otf"] i::before, .file-icons [aria-label$=".otf"] i::before,
.file-icons [aria-label$=".ttf"] i::before, .file-icons [aria-label$=".ttf"] i::before,
.file-icons [aria-label$=".woff"] i::before, .file-icons [aria-label$=".woff"] i::before,
.file-icons [aria-label$=".woff2"] i::before { .file-icons [aria-label$=".woff2"] i::before
content: "font_download"; { content: 'font_download' }
}
/* Colors */ /* Colors */
/* General */ /* General */
.file-icons [data-type="audio"] i { .file-icons [data-type=audio] i { color: var(--icon-yellow) }
color: var(--icon-yellow); .file-icons [data-type=image] i { color: var(--icon-orange) }
} .file-icons [data-type=video] i { color: var(--icon-violet) }
.file-icons [data-type="image"] i { .file-icons [data-type=invalid_link] i { color: var(--icon-red) }
color: var(--icon-orange);
}
.file-icons [data-type="video"] i {
color: var(--icon-violet);
}
.file-icons [data-type="invalid_link"] i {
color: var(--icon-red);
}
/* #f00 - Adobe/Oracle */ /* #f00 - Adobe/Oracle */
@ -171,9 +135,8 @@
.file-icons [aria-label$=".jar"] i, .file-icons [aria-label$=".jar"] i,
.file-icons [aria-label$=".psd"] i, .file-icons [aria-label$=".psd"] i,
.file-icons [aria-label$=".rb"] i, .file-icons [aria-label$=".rb"] i,
.file-icons [data-type="pdf"] i { .file-icons [data-type=pdf] i
color: var(--icon-red); { color: var(--icon-red) }
}
/* #f90 - Image/Presentation */ /* #f90 - Image/Presentation */
@ -183,18 +146,16 @@
.file-icons [aria-label$=".ppt"] i, .file-icons [aria-label$=".ppt"] i,
.file-icons [aria-label$=".pptx"] i, .file-icons [aria-label$=".pptx"] i,
.file-icons [aria-label$=".vue"] i, .file-icons [aria-label$=".vue"] i,
.file-icons [aria-label$=".xcf"] i { .file-icons [aria-label$=".xcf"] i
color: var(--icon-orange); { color: var(--icon-orange) }
}
/* #ff0 - Various */ /* #ff0 - Various */
.file-icons [aria-label$=".css"] i, .file-icons [aria-label$=".css"] i,
.file-icons [aria-label$=".js"] i, .file-icons [aria-label$=".js"] i,
.file-icons [aria-label$=".json"] i, .file-icons [aria-label$=".json"] i,
.file-icons [aria-label$=".zip"] i { .file-icons [aria-label$=".zip"] i
color: var(--icon-yellow); { color: var(--icon-yellow) }
}
/* #0f0 - Spreadsheet/Google */ /* #0f0 - Spreadsheet/Google */
@ -203,9 +164,8 @@
.file-icons [aria-label$=".go"] i, .file-icons [aria-label$=".go"] i,
.file-icons [aria-label$=".ods"] i, .file-icons [aria-label$=".ods"] i,
.file-icons [aria-label$=".xls"] i, .file-icons [aria-label$=".xls"] i,
.file-icons [aria-label$=".xlsx"] i { .file-icons [aria-label$=".xlsx"] i
color: var(--icon-green); { color: var(--icon-green) }
}
/* #00f - Document/Microsoft/Apple/Closed */ /* #00f - Document/Microsoft/Apple/Closed */
@ -228,26 +188,18 @@
.file-icons [aria-label$=".ps1"] i, .file-icons [aria-label$=".ps1"] i,
.file-icons [aria-label$=".rtf"] i, .file-icons [aria-label$=".rtf"] i,
.file-icons [aria-label$=".vob"] i, .file-icons [aria-label$=".vob"] i,
.file-icons [aria-label$=".wim"] i { .file-icons [aria-label$=".wim"] i
color: var(--icon-blue); { color: var(--icon-blue) }
}
/* #60f - Various */ /* #60f - Various */
.file-icons [aria-label$=".iso"] i, .file-icons [aria-label$=".iso"] i,
.file-icons [aria-label$=".php"] i, .file-icons [aria-label$=".php"] i,
.file-icons [aria-label$=".rar"] i { .file-icons [aria-label$=".rar"] i
color: var(--icon-violet); { color: var(--icon-violet) }
}
/* Overrides */ /* Overrides */
.file-icons [data-dir="true"] i { .file-icons [data-dir=true] i { color: var(--icon-blue) }
color: var(--icon-blue); .file-icons [data-dir=true] i::before { content: 'folder' }
} .file-icons [aria-selected=true] i { color: var(--item-selected) }
.file-icons [data-dir="true"] i::before {
content: "folder";
}
.file-icons [aria-selected="true"] i {
color: var(--iconSecondary);
}

View File

@ -1,288 +1,571 @@
html[dir="rtl"] #listing { #listing {
margin-right: 16em; --item-selected: white;
}
body.rtl #listing {
margin-right: 16em;
} }
#listing h2 { #listing h2 {
margin: 0 0 0 0.5em; margin: 0 0 0 0.5em;
font-size: 0.9em; font-size: .9em;
color: var(--textPrimary); color: rgba(0, 0, 0, 0.38);
font-weight: 500; font-weight: 500;
} }
#listing .item div:last-of-type * { #listing .item div:last-of-type * {
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
} }
#listing > div { #listing>div {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-start; justify-content: flex-start;
} }
#listing .item { #listing .item {
background: var(--surfacePrimary); background-color: #fff;
border-color: var(--divider); position: relative;
position: relative; display: flex;
display: flex; flex-wrap: nowrap;
flex-wrap: nowrap; color: #6f6f6f;
color: var(--textPrimary); transition: .1s ease background, .1s ease opacity;
transition: align-items: center;
0.1s ease background, cursor: pointer;
0.1s ease opacity; user-select: none;
align-items: center;
cursor: pointer;
user-select: none;
} }
#listing .item div:last-of-type { #listing .item div:last-of-type {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
#listing .item p { #listing .item p {
margin: 0; margin: 0;
} }
#listing .item .size, #listing .item .size,
#listing .item .modified { #listing .item .modified {
font-size: 0.9em; font-size: 0.9em;
} }
#listing .item .name { #listing .item .name {
font-weight: bold; font-weight: bold;
} }
#listing .item i { #listing .item i {
font-size: 4em; font-size: 4em;
margin-right: 0.1em; margin-right: 0.1em;
vertical-align: bottom; vertical-align: bottom;
} }
#listing .item img { #listing .item img {
width: 4em; width: 4em;
height: 4em; height: 4em;
object-fit: cover; object-fit: cover;
margin-right: 0.1em; margin-right: 0.1em;
vertical-align: bottom; vertical-align: bottom;
} }
.message { .message {
text-align: center; text-align: center;
font-size: 2em; font-size: 2em;
margin: 1em auto; margin: 1em auto;
display: block !important; display: block !important;
width: 95%; width: 95%;
color: var(--textPrimary); color: rgba(0, 0, 0, 0.3);
font-weight: 500; font-weight: 500;
} }
.message i { .message i {
font-size: 2.5em; font-size: 2.5em;
margin-bottom: 0.2em; margin-bottom: .2em;
display: block; display: block;
} }
#listing.mosaic { #listing.mosaic {
padding-top: 1em; padding-top: 1em;
margin: 0 -0.5em; margin: 0 -0.5em;
} }
#listing.mosaic .item { #listing.mosaic .item {
width: calc(33% - 1em); width: calc(33% - 1em);
margin: 0.5em; margin: .5em;
padding: 0.5em; padding: 0.5em;
border-radius: 0.2em; border-radius: 0.2em;
box-shadow: box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12);
0 1px 3px rgba(0, 0, 0, 0.06),
0 1px 2px rgba(0, 0, 0, 0.12);
} }
#listing.mosaic .item:hover { #listing.mosaic .item:hover {
box-shadow: box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24) !important;
0 1px 3px rgba(0, 0, 0, 0.12),
0 1px 2px rgba(0, 0, 0, 0.24) !important;
} }
#listing.mosaic .header { #listing.mosaic .header {
display: none; display: none;
} }
#listing.mosaic .item div:first-of-type { #listing.mosaic .item div:first-of-type {
width: 5em; width: 5em;
} }
#listing.mosaic .item div:last-of-type { #listing.mosaic .item div:last-of-type {
width: calc(100% - 5vw); width: calc(100% - 5vw);
} }
#listing.mosaic.gallery .item div:first-of-type { #listing.mosaic.gallery .item div:first-of-type {
width: 100%; width: 100%;
height: 12em; height: 12em;
} }
#listing.mosaic.gallery .item div:last-of-type { #listing.mosaic.gallery .item div:last-of-type {
position: absolute; position: absolute;
bottom: 0.5em; bottom: 0.5em;
padding: 1em; padding: 1em;
width: calc(100% - 1em); width: calc(100% - 1em);
text-align: center; text-align: center;
} }
#listing.mosaic.gallery .item[data-type="image"] div:last-of-type { #listing.mosaic.gallery .item[data-type=image] div:last-of-type {
color: white; color: white;
background: linear-gradient(#0000, #0009); background: linear-gradient(#0000, #0009);
} }
#listing.mosaic.gallery .item i { #listing.mosaic.gallery .item i {
width: 100%; width: 100%;
margin-right: 0; margin-right: 0;
font-size: 8em; font-size: 8em;
text-align: center; text-align: center;
} }
#listing.mosaic.gallery .item img { #listing.mosaic.gallery .item img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
#listing.gallery .size, #listing.gallery .size,
#listing.gallery .modified { #listing.gallery .modified {
display: none; display: none;
} }
#listing.list { #listing.list {
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
margin: 0; margin: 0;
} }
#listing.list .item { #listing.list .item {
width: 100%; width: 100%;
margin: 0; margin: 0;
border: 1px solid var(--borderPrimary); border: 1px solid rgba(0, 0, 0, 0.1);
padding: 1em; padding: 1em;
border-top: 0; border-top: 0;
} }
#listing.list h2 { #listing.list h2 {
display: none; display: none;
} }
#listing .item[aria-selected="true"] { #listing .item[aria-selected=true] {
background: var(--blue) !important; /* background: var(--blue) !important; */
color: var(--iconSecondary) !important; color: var(--item-selected) !important;
} }
#listing.list .item div:first-of-type { #listing.list .item div:first-of-type {
width: 3em; width: 3em;
} }
#listing.list .item div:first-of-type i { #listing.list .item div:first-of-type i {
font-size: 2em; font-size: 2em;
} }
#listing.list .item div:first-of-type img { #listing.list .item div:first-of-type img {
width: 2em; width: 2em;
height: 2em; height: 2em;
} }
#listing.list .item div:last-of-type { #listing.list .item div:last-of-type {
width: calc(100% - 3em); width: calc(100% - 3em);
display: flex; display: flex;
align-items: center; align-items: center;
} }
#listing.list .item .name { #listing.list .item .name {
width: 50%; width: 50%;
} }
#listing.list .item .size { #listing.list .item .size {
width: 25%; width: 25%;
} }
#listing .item.header { #listing .item.header {
display: none !important; display: none !important;
background-color: var(--iconTertiary); background-color: #ccc;
} }
#listing.list .header i { #listing.list .header i {
font-size: 1.5em; font-size: 1.5em;
vertical-align: middle; vertical-align: middle;
margin-left: 0.2em; margin-left: .2em;
} }
#listing.list .item.header { #listing.list .item.header {
display: flex !important; display: flex !important;
background: var(--background); background: #fafafa;
z-index: 999; z-index: 999;
padding: 0.85em; padding: .85em;
border: 0; border: 0;
border-bottom: 1px solid var(--borderPrimary); border-bottom: 1px solid rgba(0, 0, 0, 0.1);
} }
#listing.list .item.header > div:first-child { #listing.list .item.header>div:first-child {
width: 0; width: 0;
} }
#listing.list .item.header .name { #listing.list .item.header .name {
margin-right: 3em; margin-right: 3em;
} }
#listing.list .header a { #listing.list .header a {
color: inherit; color: inherit;
} }
#listing.list .item.header > div:first-child { #listing.list .item.header>div:first-child {
width: 0; width: 0;
} }
#listing.list .name { #listing.list .name {
font-weight: normal; font-weight: normal;
} }
#listing.list .item.header .name { #listing.list .item.header .name {
margin-right: 3em; margin-right: 3em;
} }
#listing.list .header span { #listing.list .header span {
vertical-align: middle; vertical-align: middle;
} }
#listing.list .header i { #listing.list .header i {
opacity: 0; opacity: 0;
transition: 0.1s ease all; transition: .1s ease all;
} }
#listing.list .header p:hover i, #listing.list .header p:hover i,
#listing.list .header .active i { #listing.list .header .active i {
opacity: 1; opacity: 1;
} }
#listing.list .item.header .active { #listing.list .item.header .active {
font-weight: bold; font-weight: bold;
} }
#listing #multiple-selection { #listing #multiple-selection {
position: fixed; position: fixed;
bottom: -4em; bottom: -4em;
left: 0; left: 0;
z-index: 99999; z-index: 99999;
width: 100%; width: 100%;
background-color: var(--blue); background-color: var(--blue);
height: 4em; height: 4em;
padding: 0.5em 0.5em 0.5em 1em; padding: 0.5em 0.5em 0.5em 1em;
justify-content: space-between; justify-content: space-between;
transition: 0.2s ease bottom; transition: .2s ease bottom;
} }
#listing #multiple-selection.active { #listing #multiple-selection.active {
bottom: 0; bottom: 0;
} }
#listing #multiple-selection p, #listing #multiple-selection p,
#listing #multiple-selection i { #listing #multiple-selection i {
color: var(--iconSecondary); color: var(--item-selected);
} }
/* remove a bit of padding from the file list entries */
#listing.list .item {
padding: 0.7em;
}
/* make folders yellow-ish */
#listing .item[data-dir=true] div i {
color: #ffc84b;
}
/* packed files - colorize and change icon */
#listing .item[aria-label$=".7z"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".7z"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".7z"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".arj"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".arj"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".arj"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".zip"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".zip"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".zip"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".gz"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".gz"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".gz"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".tar"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".tar"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".tar"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".bz"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".bz"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".bz"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".bz2"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".bz2"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".bz2"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".xz"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".xz"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".xz"] .material-icons::before {
content: "archive";
visibility: visible;
}
#listing .item[aria-label$=".tbz"] div i {
color: #a268a1;
}
#listing .item[aria-label$=".tbz"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".tbz"] .material-icons::before {
content: "archive";
visibility: visible;
}
/* office files */
/* PDF - colorize and change icon /*
/* Note: This is yellow because I use SumatraPDF */
#listing .item[aria-label$=".pdf"] div i {
color: #FFEE00;
}
#listing .item[aria-label$=".pdf"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".pdf"] .material-icons::before {
content: "picture_as_pdf";
visibility: visible;
}
/* word processors - colorize and change icon */
/* Word */
#listing .item[aria-label$=".doc"] div i {
color: #185ABD;
}
#listing .item[aria-label$=".doc"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".doc"] .material-icons::before {
content: "description";
visibility: visible;
}
#listing .item[aria-label$=".docx"] div i {
color: #185ABD;
}
#listing .item[aria-label$=".docx"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".docx"] .material-icons::before {
content: "description";
visibility: visible;
}
/* OpenOffice Writer */
#listing .item[aria-label$=".odt"] div i {
color: #185ABD;
}
#listing .item[aria-label$=".odt"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".odt"] .material-icons::before {
content: "description";
visibility: visible;
}
/* LibreOffice Writer */
#listing .item[aria-label$=".sxw"] div i {
color: #185ABD;
}
#listing .item[aria-label$=".sxw"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".sxw"] .material-icons::before {
content: "description";
visibility: visible;
}
/* PowerPoint */
#listing .item[aria-label$=".ppt"] div i {
color: #D35230;
}
#listing .item[aria-label$=".pptx"] div i {
color: #D35230;
}
#listing .item[aria-label$=".pps"] div i {
color: #D35230;
}
/* OpenOffice Impress */
#listing .item[aria-label$=".odp"] div i {
color: #D35230;
}
/* Excel */
#listing .item[aria-label$=".xls"] div i {
color: #107C41;
}
#listing .item[aria-label$=".xlsx"] div i {
color: #107C41;
}
#listing .item[aria-label$=".ods"] div i {
color: #107C41;
}
#listing .item[aria-label$=".sxc"] div i {
color: #107C41;
}
#listing .item[aria-label$=".wri"] div i {
color: #336eff;
}
/* sound files - colorize */
#listing .item[data-type=audio] div i {
color: #F47900;
}
/* video files - colorize */
#listing .item[data-type=video] div i {
color: #F47900;
}
/* text files - change icon*/
#listing .item[aria-label$=".txt"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".txt"] .material-icons::before {
content: "description";
visibility: visible;
}
#listing .item[aria-label$=".md"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".md"] .material-icons::before {
content: "description";
visibility: visible;
}
/* various other files*/
/* iCal - change icon*/
#listing .item[aria-label$=".ics"] .material-icons {
visibility: hidden;
}
#listing .item[aria-label$=".ics"] .material-icons::before {
content: "event";
visibility: visible;
}

View File

@ -1,5 +1,5 @@
#login { #login {
background: var(--surfacePrimary); background: #fff;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
@ -17,7 +17,7 @@
#login h1 { #login h1 {
text-align: center; text-align: center;
font-size: 2.5em; font-size: 2.5em;
margin: 0.4em 0 0.67em; margin: .4em 0 .67em;
} }
#login form { #login form {
@ -34,15 +34,15 @@
} }
#login #recaptcha { #login #recaptcha {
margin: 0.5em 0 0; margin: .5em 0 0;
} }
#login .wrong { #login .wrong {
background: var(--red); background: var(--red);
color: #fff; color: #fff;
padding: 0.5em; padding: .5em;
text-align: center; text-align: center;
animation: 0.2s opac forwards; animation: .2s opac forwards;
} }
@keyframes opac { @keyframes opac {
@ -61,5 +61,5 @@
text-transform: lowercase; text-transform: lowercase;
font-weight: 500; font-weight: 500;
font-size: 0.9rem; font-size: 0.9rem;
margin: 0.5rem 0; margin: .5rem 0;
} }

View File

@ -1,12 +1,16 @@
@media (max-width: 1024px) { @media (max-width: 1024px) {
nav { nav {
width: 10em; width: 10em
}
/* Mobile Only fix div hidden by bottom navigation bar of mobile browser when using height: 100vh */
#previewer .preview {
/* height: calc(100% - 4em) !important; */
} }
} }
@media (max-width: 1024px) { @media (max-width: 1024px) {
main { main {
width: calc(100% - 13em); width: calc(100% - 13em)
} }
} }
@ -21,27 +25,27 @@
width: 60%; width: 60%;
} }
#more { #more {
display: inherit; display: inherit
} }
header .overlay { header .overlay {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: var(--borderPrimary); background-color: rgba(0, 0, 0, 0.1);
} }
#dropdown { #dropdown {
position: fixed; position: fixed;
top: 1em; top: 1em;
right: 1em; right: 1em;
display: block; display: block;
background: var(--surfaceSecondary); background-color: #fff;
box-shadow: 0 0 5px var(--borderPrimary); box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
transform: scale(0); transform: scale(0);
transition: 0.1s ease-in-out transform; transition: .1s ease-in-out transform;
transform-origin: top right; transform-origin: top right;
z-index: 99999; z-index: 99999;
} }
html[dir="rtl"] #dropdown { body.rtl #dropdown {
right: unset; right: unset;
left: 1em; left: 1em;
transform-origin: top left; transform-origin: top left;
@ -61,7 +65,7 @@
} }
#dropdown .action span:not(.counter) { #dropdown .action span:not(.counter) {
display: inline-block; display: inline-block;
padding: 0.4em; padding: .4em;
} }
#dropdown .counter { #dropdown .counter {
left: 2.25em; left: 2.25em;
@ -73,10 +77,8 @@
transform: translateX(-50%); transform: translateX(-50%);
display: flex; display: flex;
align-items: center; align-items: center;
background: var(--surfaceSecondary); background: #fff;
box-shadow: box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
rgba(0, 0, 0, 0.06) 0px 1px 3px,
rgba(0, 0, 0, 0.12) 0px 1px 2px;
width: 95%; width: 95%;
max-width: 20em; max-width: 20em;
z-index: 1; z-index: 1;
@ -88,7 +90,7 @@
#file-selection > span { #file-selection > span {
display: inline-block; display: inline-block;
margin-left: 1em; margin-left: 1em;
color: var(--textPrimary); color: #6f6f6f;
margin-right: auto; margin-right: auto;
} }
#file-selection .action span { #file-selection .action span {
@ -97,15 +99,15 @@
nav { nav {
top: 0; top: 0;
z-index: 99999; z-index: 99999;
background: var(--surfaceSecondary); background: #fff;
height: 100%; height: 100%;
width: 16em; width: 16em;
box-shadow: 0 0 5px var(--borderPrimary); box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
transition: 0.1s ease left; transition: .1s ease left;
left: -17em; left: -17em;
} }
html[dir="rtl"] nav { body.rtl nav {
left: unset; left: unset;
right: -17em; right: -17em;
} }
@ -113,7 +115,7 @@
left: 0; left: 0;
} }
html[dir="rtl"] nav.active { body.rtl nav.active {
left: unset; left: unset;
right: 0; right: 0;
} }
@ -133,19 +135,19 @@
margin-bottom: 5em; margin-bottom: 5em;
} }
html[dir="rtl"] #listing { body.rtl #listing {
margin-right: unset; margin-right: unset;
} }
html[dir="rtl"] .breadcrumbs { body.rtl .breadcrumbs {
transform: translateX(16em); transform: translateX(16em);
} }
html[dir="rtl"] #nav .wrapper { body.rtl #nav .wrapper {
margin-right: unset; margin-right: unset;
} }
html[dir="rtl"] .dashboard .row { body.rtl .dashboard .row {
margin-right: unset; margin-right: unset;
} }
@ -168,4 +170,4 @@
#listing.list .item .name { #listing.list .item .name {
width: 100%; width: 100%;
} }
} }

View File

@ -1,6 +1,6 @@
@import "normalize.css/normalize.css"; @import "normalize.css/normalize.css";
@import "vue-toastification/dist/index.css"; @import "noty/lib/noty.css";
@import "vue-final-modal/style.css"; @import "noty/lib/themes/mint.css";
@import "./_variables.css"; @import "./_variables.css";
@import "./_buttons.css"; @import "./_buttons.css";
@import "./_inputs.css"; @import "./_inputs.css";
@ -16,23 +16,10 @@
@import "./login.css"; @import "./login.css";
@import "./mobile.css"; @import "./mobile.css";
/* For testing only
:focus {
outline: 2px solid crimson !important;
border-radius: 3px !important;
} */
.link { .link {
color: var(--blue); color: var(--blue);
} }
#loading {
background: var(--background);
}
#loading .spinner > div {
background: var(--iconPrimary);
}
main .spinner { main .spinner {
display: block; display: block;
text-align: center; text-align: center;
@ -45,7 +32,7 @@ main .spinner > div {
height: 0.8em; height: 0.8em;
margin: 0 0.1em; margin: 0 0.1em;
font-size: 1em; font-size: 1em;
background: var(--iconPrimary); background-color: rgba(0, 0, 0, 0.3);
border-radius: 100%; border-radius: 100%;
display: inline-block; display: inline-block;
animation: sk-bouncedelay 1.4s infinite ease-in-out both; animation: sk-bouncedelay 1.4s infinite ease-in-out both;
@ -85,7 +72,7 @@ main .spinner .bounce2 {
transition: 0.2s ease all; transition: 0.2s ease all;
border: 0; border: 0;
margin: 0; margin: 0;
color: var(--action); color: #546e7a;
border-radius: 50%; border-radius: 50%;
background: transparent; background: transparent;
padding: 0; padding: 0;
@ -107,7 +94,7 @@ main .spinner .bounce2 {
} }
.action:hover { .action:hover {
background-color: var(--hover); background-color: rgba(0, 0, 0, 0.1);
} }
.action ul { .action ul {
@ -128,7 +115,7 @@ main .spinner .bounce2 {
} }
.action ul li:hover { .action ul li:hover {
background-color: var(--divider); background-color: rgba(0, 0, 0, 0.04);
} }
#click-overlay { #click-overlay {
@ -151,7 +138,7 @@ main .spinner .bounce2 {
bottom: 0; bottom: 0;
right: 0; right: 0;
background: var(--blue); background: var(--blue);
color: var(--iconSecondary); color: #fff;
border-radius: 50%; border-radius: 50%;
font-size: 0.75em; font-size: 0.75em;
width: 1.8em; width: 1.8em;
@ -159,13 +146,14 @@ main .spinner .bounce2 {
text-align: center; text-align: center;
line-height: 1.55em; line-height: 1.55em;
font-weight: bold; font-weight: bold;
border: 2px solid var(--borderPrimary); border: 2px solid white;
} }
/* PREVIEWER */ /* PREVIEWER */
#previewer { #previewer {
background-color: rgba(0, 0, 0, 0.99); background-color: rgba(0, 0, 0, 0.9);
padding-top: 4em;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
@ -178,25 +166,15 @@ main .spinner .bounce2 {
#previewer header { #previewer header {
background: none; background: none;
color: #fff; color: #fff;
border-bottom: 0px;
box-shadow: 0px 0px 0px;
z-index: 19999;
} }
#previewer header > .action i { #previewer header > .action i {
color: #fff; color: #fff;
text-shadow: 1px 1px 1px #000000;
}
#previewer header > title {
white-space: nowrap;
text-shadow: 1px 1px 1px #000000;
} }
@media (min-width: 738px) { @media (min-width: 738px) {
#previewer header #dropdown .action i { #previewer header #dropdown .action i {
color: #fff; color: #fff;
text-shadow: 1px 1px 1px #000000;
} }
} }
@ -210,7 +188,7 @@ main .spinner .bounce2 {
#previewer .preview { #previewer .preview {
text-align: center; text-align: center;
height: 100%; height: calc(100vh - 4em);
} }
#previewer .preview pre { #previewer .preview pre {
@ -225,11 +203,6 @@ main .spinner .bounce2 {
margin: 0; margin: 0;
} }
#previewer .preview audio {
width: 95%;
height: 88%;
}
#previewer .preview video { #previewer .preview video {
height: 100%; height: 100%;
} }
@ -274,7 +247,7 @@ main .spinner .bounce2 {
#previewer > button { #previewer > button {
margin: 0; margin: 0;
position: fixed; position: fixed;
top: 50%; top: calc(50% + 1.85em);
transform: translateY(-50%); transform: translateY(-50%);
background-color: rgba(80, 80, 80, 0.5); background-color: rgba(80, 80, 80, 0.5);
color: white; color: white;
@ -314,7 +287,7 @@ main .spinner .bounce2 {
#previewer .spinner > div { #previewer .spinner > div {
width: 18px; width: 18px;
height: 18px; height: 18px;
background: var(--iconPrimary); background-color: white;
} }
/* EDITOR */ /* EDITOR */
@ -322,21 +295,17 @@ main .spinner .bounce2 {
#editor-container { #editor-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: var(--background); background-color: #fafafa;
position: fixed; position: fixed;
padding-top: 4em; padding-top: 4em;
top: 0; top: 0;
left: 0; left: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
z-index: 9998; z-index: 9999;
overflow: hidden; overflow: hidden;
} }
#editor-container .bar {
background: var(--surfacePrimary);
}
#editor-container #editor { #editor-container #editor {
flex: 1; flex: 1;
} }
@ -347,7 +316,7 @@ main .spinner .bounce2 {
} }
/*** RTL - flip and position arrow of path ***/ /*** RTL - flip and position arrow of path ***/
html[dir="rtl"] .breadcrumbs .chevron { body.rtl .breadcrumbs .chevron {
transform: scaleX(-1) translateX(16em); transform: scaleX(-1) translateX(16em);
} }
@ -359,6 +328,22 @@ html[dir="rtl"] .breadcrumbs .chevron {
font-size: 1rem; font-size: 1rem;
} }
/* * * * * * * * * * * * * * * *
* PROMPT *
* * * * * * * * * * * * * * * */
.noty_buttons {
text-align: right;
padding: 0 10px 10px !important;
}
.noty_buttons button {
background: rgba(0, 0, 0, 0.05);
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0 0 0;
font-size: 1rem;
}
/* * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * *
* FOOTER * * FOOTER *
* * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * */
@ -436,17 +421,17 @@ html[dir="rtl"] .breadcrumbs .chevron {
* RTL overrides * * RTL overrides *
* * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * */
html[dir="rtl"] .card-content textarea { body.rtl .card-content textarea {
direction: ltr; direction: ltr;
text-align: left; text-align: left;
} }
html[dir="rtl"] .card-content .small + input { body.rtl .card-content .small + input {
direction: ltr; direction: ltr;
text-align: left; text-align: left;
} }
html[dir="rtl"] .card.floating .card-content .file-list { body.rtl .card.floating .card-content .file-list {
direction: ltr; direction: ltr;
text-align: left; text-align: left;
} }

View File

@ -0,0 +1,46 @@
const name = window.FileBrowser.Name || "File Browser";
const disableExternal = window.FileBrowser.DisableExternal;
const disableUsedPercentage = window.FileBrowser.DisableUsedPercentage;
const baseURL = window.FileBrowser.BaseURL;
const staticURL = window.FileBrowser.StaticURL;
const recaptcha = window.FileBrowser.ReCaptcha;
const recaptchaKey = window.FileBrowser.ReCaptchaKey;
const signup = window.FileBrowser.Signup;
const version = window.FileBrowser.Version;
const logoURL = `${staticURL}/img/logo.svg`;
const Folder=`${staticURL}/img/icons/folder.svg`;
const Home=`${staticURL}/img/icons/home.svg`;
const noAuth = window.FileBrowser.NoAuth;
const authMethod = window.FileBrowser.AuthMethod;
const loginPage = window.FileBrowser.LoginPage;
const theme = window.FileBrowser.Theme;
const enableThumbs = window.FileBrowser.EnableThumbs;
const resizePreview = window.FileBrowser.ResizePreview;
const enableExec = window.FileBrowser.EnableExec;
const tusSettings = window.FileBrowser.TusSettings;
const origin = window.location.origin;
const tusEndpoint = `/api/tus`;
export {
name,
disableExternal,
disableUsedPercentage,
baseURL,
logoURL,
Folder,
Home,
recaptcha,
recaptchaKey,
signup,
version,
noAuth,
authMethod,
loginPage,
theme,
enableThumbs,
resizePreview,
enableExec,
tusSettings,
origin,
tusEndpoint,
};

View File

@ -1,129 +1,152 @@
<template> <template>
<div id="editor-container" @touchmove.prevent.stop @wheel.prevent.stop> <div id="editor-container">
<header-bar> <header-bar>
<action icon="close" :label="t('buttons.close')" @action="close()" /> <action :label="$t('buttons.close')" @action="close()" />
<title>{{ fileStore.req?.name ?? "" }}</title> <title>{{ req.name }}</title>
<action <action
v-if="authStore.user?.perm.modify" v-if="user.perm.modify"
id="save-button" id="save-button"
icon="save" icon="save"
:label="t('buttons.save')" :label="$t('buttons.save')"
@action="save()" @action="save()"
/> />
</header-bar> </header-bar>
<Breadcrumbs base="/files" noLink /> <breadcrumbs base="/files" noLink />
<form id="editor"></form> <form id="editor"></form>
</div> </div>
</template> </template>
<script setup lang="ts"> <script>
import { mapState } from "vuex";
import { files as api } from "@/api"; import { files as api } from "@/api";
import { theme } from "@/utils/constants";
import buttons from "@/utils/buttons"; import buttons from "@/utils/buttons";
import url from "@/utils/url"; import url from "@/utils/url";
import ace, { Ace, version as ace_version } from "ace-builds";
import modelist from "ace-builds/src-noconflict/ext-modelist"; import { version as ace_version } from "ace-builds";
import "ace-builds/src-noconflict/ext-language_tools"; import ace from "ace-builds/src-min-noconflict/ace.js";
import modelist from "ace-builds/src-min-noconflict/ext-modelist.js";
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 Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
import { useAuthStore } from "@/stores/auth";
import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout";
import { inject, onBeforeUnmount, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { getTheme } from "@/utils/theme";
const $showError = inject<IToastError>("$showError")!; export default {
name: "editor",
components: {
HeaderBar,
Action,
Breadcrumbs,
},
data: function () {
return {};
},
computed: {
...mapState(["req", "user"]),
breadcrumbs() {
let parts = this.$route.path.split("/");
const fileStore = useFileStore(); if (parts[0] === "") {
const authStore = useAuthStore(); parts.shift();
const layoutStore = useLayoutStore(); }
const { t } = useI18n(); if (parts[parts.length - 1] === "") {
parts.pop();
}
const route = useRoute(); let breadcrumbs = [];
const router = useRouter();
const editor = ref<Ace.Editor | null>(null); for (let i = 0; i < parts.length; i++) {
breadcrumbs.push({ name: decodeURIComponent(parts[i]) });
}
onMounted(() => { breadcrumbs.shift();
window.addEventListener("keydown", keyEvent);
const fileContent = fileStore.req?.content || ""; if (breadcrumbs.length > 3) {
while (breadcrumbs.length !== 4) {
breadcrumbs.shift();
}
ace.config.set( breadcrumbs[0].name = "...";
"basePath", }
`https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/`
);
editor.value = ace.edit("editor", { return breadcrumbs;
value: fileContent, },
showPrintMargin: false, },
readOnly: fileStore.req?.type === "textImmutable", created() {
theme: "ace/theme/chrome", window.addEventListener("keydown", this.keyEvent);
mode: modelist.getModeForPath(fileStore.req?.name).mode, },
wrap: true, beforeDestroy() {
enableBasicAutocompletion: true, window.removeEventListener("keydown", this.keyEvent);
enableLiveAutocompletion: true, this.editor.destroy();
enableSnippets: true, },
}); mounted: function () {
const fileContent = this.req.content || "";
if (getTheme() === "dark") { ace.config.set(
editor.value!.setTheme("ace/theme/twilight"); "basePath",
} `https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/`
);
editor.value.focus(); 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,
});
onBeforeUnmount(() => { if (theme == "dark") {
window.removeEventListener("keydown", keyEvent); this.editor.setTheme("ace/theme/twilight");
editor.value?.destroy(); }
});
const keyEvent = (event: KeyboardEvent) => { this.editor.focus();
if (event.code === "Escape") { },
close(); methods: {
} keyEvent(event) {
if (event.code === "Escape") {
this.close();
}
if (!event.ctrlKey && !event.metaKey) { if (!event.ctrlKey && !event.metaKey) {
return; return;
} }
if (event.key !== "s") { if (String.fromCharCode(event.which).toLowerCase() !== "s") {
return; return;
} }
event.preventDefault(); event.preventDefault();
save(); this.save();
}; },
async save() {
const button = "save";
buttons.loading("save");
const save = async () => { try {
const button = "save"; await api.put(this.$route.path, this.editor.getValue());
buttons.loading("save"); this.editor.session.getUndoManager().markClean();
buttons.success(button);
} catch (e) {
buttons.done(button);
this.$showError(e);
}
},
close() {
if (!this.editor.session.getUndoManager().isClean()) {
this.$store.commit("showHover", "discardEditorChanges");
return;
}
try { this.$store.commit("updateRequest", {});
await api.put(route.path, editor.value?.getValue());
editor.value?.session.getUndoManager().markClean();
buttons.success(button);
} catch (e: any) {
buttons.done(button);
$showError(e);
}
};
const close = () => {
if (!editor.value?.session.getUndoManager().isClean()) {
layoutStore.showHover("discardEditorChanges");
return;
}
fileStore.updateRequest(null); let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
let uri = url.removeLastDir(route.path) + "/"; },
router.push({ path: uri }); },
}; };
</script> </script>

View File

@ -0,0 +1,822 @@
<template>
<div>
<header-bar showMenu showLogo>
<search />
<title />
<action
class="search-button"
icon="search"
:label="$t('buttons.search')"
@action="openSearch()"
/>
<template #actions>
<action
v-if="headerButtons.shell"
icon="code"
:label="$t('buttons.shell')"
@action="$store.commit('toggleShell')"
/>
<action
:label="$t('buttons.switchView')"
@action="switchView"
/>
<action
v-if="headerButtons.download"
:label="$t('buttons.download')"
@action="download"
:counter="selectedCount"
/>
<action
v-if="headerButtons.upload"
id="upload-button"
:label="$t('buttons.upload')"
@action="upload"
/>
<action icon="info" :label="$t('buttons.info')" show="info" />
<action
icon="check_circle"
:label="$t('buttons.selectMultiple')"
@action="toggleMultipleSelection"
/>
</template>
</header-bar>
<div v-if="isMobile" id="file-selection">
<span v-if="selectedCount > 0">{{ selectedCount }} selected</span>
</div>
<div v-if="loading">
<h2 class="message delayed">
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
<span>{{ $t("files.loading") }}</span>
</h2>
</div>
<template v-else>
<div v-if="req.numDirs + req.numFiles == 0">
<h2 class="message">
<i class="material-icons">sentiment_dissatisfied</i>
<span>{{ $t("files.lonely") }}</span>
</h2>
<input
style="display: none"
type="file"
id="upload-input"
@change="uploadInput($event)"
multiple
/>
<input
style="display: none"
type="file"
id="upload-folder-input"
@change="uploadInput($event)"
webkitdirectory
multiple
/>
</div>
<div
v-else
id="listing"
ref="listing"
:class="user.viewMode + ' file-icons'"
>
<div>
<div class="item header">
<div></div>
<div>
<p
:class="{ active: nameSorted }"
class="name"
role="button"
tabindex="0"
@click="sort('name')"
:title="$t('files.sortByName')"
:aria-label="$t('files.sortByName')"
>
<span>{{ $t("files.name") }}</span>
<i class="material-icons">{{ nameIcon }}</i>
</p>
<p
:class="{ active: sizeSorted }"
class="size"
role="button"
tabindex="0"
@click="sort('size')"
:title="$t('files.sortBySize')"
:aria-label="$t('files.sortBySize')"
>
<span>{{ $t("files.size") }}</span>
<i class="material-icons">{{ sizeIcon }}</i>
</p>
<p
:class="{ active: modifiedSorted }"
class="modified"
role="button"
tabindex="0"
@click="sort('modified')"
:title="$t('files.sortByLastModified')"
:aria-label="$t('files.sortByLastModified')"
>
<span>{{ $t("files.lastModified") }}</span>
<i class="material-icons">{{ modifiedIcon }}</i>
</p>
</div>
</div>
</div>
<h2 v-if="req.numDirs > 0">{{ $t("files.folders") }}</h2>
<div v-if="req.numDirs > 0">
<item
v-for="item in dirs"
:key="base64(item.name)"
v-bind:index="item.index"
v-bind:name="item.name"
v-bind:isDir="item.isDir"
v-bind:url="item.url"
v-bind:modified="item.modified"
v-bind:type="item.type"
v-bind:size="item.size"
v-bind:path="item.path"
>
</item>
</div>
<h2 v-if="req.numFiles > 0">{{ $t("files.files") }}</h2>
<div v-if="req.numFiles > 0">
<item
v-for="item in files"
:key="base64(item.name)"
v-bind:index="item.index"
v-bind:name="item.name"
v-bind:isDir="item.isDir"
v-bind:url="item.url"
v-bind:modified="item.modified"
v-bind:type="item.type"
v-bind:size="item.size"
v-bind:path="item.path"
>
</item>
</div>
<input
style="display: none"
type="file"
id="upload-input"
@change="uploadInput($event)"
multiple
/>
<input
style="display: none"
type="file"
id="upload-folder-input"
@change="uploadInput($event)"
webkitdirectory
multiple
/>
<div :class="{ active: $store.state.multiple }" id="multiple-selection">
<p>{{ $t("files.multipleSelectionEnabled") }}</p>
<div
@click="$store.commit('multiple', false)"
tabindex="0"
role="button"
:title="$t('files.clear')"
:aria-label="$t('files.clear')"
class="action"
>
<i class="material-icons">clear</i>
</div>
</div>
</div>
</template>
</div>
</template>
<script>
import Vue from "vue";
import { mapState, mapGetters, mapMutations } from "vuex";
import { users, files as api } from "@/api";
import { enableExec } from "@/utils/constants";
import * as upload from "@/utils/upload";
import css from "@/utils/css";
import throttle from "lodash.throttle";
import HeaderBar from "@/components/header/HeaderBar.vue";
import Action from "@/components/header/Action.vue";
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", "multiple", "selected", "loading"]),
...mapGetters(["selectedCount", "currentPrompt"]),
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 {
upload: this.user.perm.create,
download: this.user.perm.download,
shell: this.user.perm.execute && enableExec,
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,
};
},
isMobile() {
return this.width <= 736;
},
},
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: {
...mapMutations(["updateUser", "addSelected"]),
base64: function (name) {
return window.btoa(unescape(encodeURIComponent(name)));
},
keyEvent(event) {
// No prompts are shown
if (this.currentPrompt !== 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;
}
},
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 items = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
if (!items) return;
let columns = Math.floor(
document.querySelector("main").offsetWidth / this.columnWidth
);
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",
action: (event) => {
event.preventDefault();
this.$store.commit("closeHovers");
upload.handleFiles(files, path, false);
},
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",
action: (event) => {
event.preventDefault();
this.$store.commit("closeHovers");
upload.handleFiles(files, path, false);
},
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);
},
});
},
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);
// Await ensures correct value for setItemWeight()
await this.$store.commit("updateUser", data);
this.setItemWeight();
this.fillWindow();
},
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,46 +1,34 @@
<template> <template>
<div <div
id="previewer" id="previewer"
@touchmove.prevent.stop
@wheel.prevent.stop
@mousemove="toggleNavigation" @mousemove="toggleNavigation"
@touchstart="toggleNavigation" @touchstart="toggleNavigation"
> >
<header-bar v-if="showNav"> <header-bar>
<action icon="close" :label="$t('buttons.close')" @action="close()" /> <action :label="$t('buttons.close')" @action="close()" />
<title>{{ name }}</title> <title>{{ name }}</title>
<action
:disabled="layoutStore.loading"
v-if="isResizeEnabled && fileStore.req?.type === 'image'"
:icon="fullSize ? 'photo_size_select_large' : 'hd'"
@action="toggleSize"
/>
<template #actions> <template #actions>
<action <action
:disabled="layoutStore.loading" :disabled="loading"
v-if="authStore.user?.perm.rename" v-if="user.perm.rename"
icon="mode_edit"
:label="$t('buttons.rename')" :label="$t('buttons.rename')"
show="rename" show="rename"
/> />
<action <action
:disabled="layoutStore.loading" :disabled="loading"
v-if="authStore.user?.perm.delete" v-if="user.perm.delete"
icon="delete"
:label="$t('buttons.delete')" :label="$t('buttons.delete')"
@action="deleteFile" @action="deleteFile"
id="delete-button" id="delete-button"
/> />
<action <action
:disabled="layoutStore.loading" :disabled="loading"
v-if="authStore.user?.perm.download" v-if="user.perm.download"
icon="file_download"
:label="$t('buttons.download')" :label="$t('buttons.download')"
@action="download" @action="download"
/> />
<action <action
:disabled="layoutStore.loading" :disabled="loading"
icon="info" icon="info"
:label="$t('buttons.info')" :label="$t('buttons.info')"
show="info" show="info"
@ -48,7 +36,7 @@
</template> </template>
</header-bar> </header-bar>
<div class="loading delayed" v-if="layoutStore.loading"> <div class="loading delayed" v-if="loading">
<div class="spinner"> <div class="spinner">
<div class="bounce1"></div> <div class="bounce1"></div>
<div class="bounce2"></div> <div class="bounce2"></div>
@ -57,29 +45,41 @@
</div> </div>
<template v-else> <template v-else>
<div class="preview"> <div class="preview">
<ExtendedImage v-if="fileStore.req?.type == 'image'" :src="raw" /> <ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
<audio <audio
v-else-if="fileStore.req?.type == 'audio'" v-else-if="req.type == 'audio'"
ref="player" ref="player"
:src="raw" :src="raw"
controls controls
:autoplay="autoPlay" :autoplay="autoPlay"
@play="autoPlay = true" @play="autoPlay = true"
></audio> ></audio>
<VideoPlayer <video
v-else-if="fileStore.req?.type == 'video'" v-else-if="req.type == 'video'"
ref="player" ref="player"
:source="raw" :src="raw"
:subtitles="subtitles" controls
:options="videoOptions" :autoplay="autoPlay"
@play="autoPlay = true"
> >
</VideoPlayer> <track
kind="captions"
v-for="(sub, index) in subtitles"
:key="index"
:src="sub"
:label="'Subtitle ' + index"
:default="index === 0"
/>
Sorry, your browser doesn't support embedded videos, but don't worry,
you can <a :href="downloadUrl">download it</a>
and watch it with your favorite video player!
</video>
<object <object
v-else-if="fileStore.req?.extension.toLowerCase() == '.pdf'" v-else-if="req.extension.toLowerCase() == '.pdf'"
class="pdf" class="pdf"
:data="raw" :data="raw"
></object> ></object>
<div v-else-if="fileStore.req?.type == 'blob'" class="info"> <div v-else-if="req.type == 'blob'" class="info">
<div class="title"> <div class="title">
<i class="material-icons">feedback</i> <i class="material-icons">feedback</i>
{{ $t("files.noPreview") }} {{ $t("files.noPreview") }}
@ -91,17 +91,6 @@
>{{ $t("buttons.download") }} >{{ $t("buttons.download") }}
</div> </div>
</a> </a>
<a
target="_blank"
:href="raw"
class="button button--flat"
v-if="!fileStore.req?.isDir"
>
<div>
<i class="material-icons">open_in_new</i
>{{ $t("buttons.openFile") }}
</div>
</a>
</div> </div>
</div> </div>
</div> </div>
@ -132,215 +121,214 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script>
import { useAuthStore } from "@/stores/auth"; import { mapGetters, mapState } from "vuex";
import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout";
import { files as api } from "@/api"; import { files as api } from "@/api";
import { resizePreview } from "@/utils/constants"; import { resizePreview } from "@/utils/constants";
import url from "@/utils/url"; import url from "@/utils/url";
import throttle from "lodash/throttle"; import throttle from "lodash.throttle";
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 ExtendedImage from "@/components/files/ExtendedImage.vue"; import ExtendedImage from "@/components/files/ExtendedImage.vue";
import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import VideoPlayer from "@/components/files/VideoPlayer.vue";
const mediaTypes: ResourceType[] = ["image", "video", "audio", "blob"]; const mediaTypes = ["image", "video", "audio", "blob"];
const previousLink = ref<string>(""); export default {
const nextLink = ref<string>(""); name: "preview",
const listing = ref<ResourceItem[] | null>(null); components: {
const name = ref<string>(""); HeaderBar,
const fullSize = ref<boolean>(false); Action,
const showNav = ref<boolean>(true); ExtendedImage,
const navTimeout = ref<null | number>(null); },
const hoverNav = ref<boolean>(false); data: function () {
const autoPlay = ref<boolean>(false); return {
const previousRaw = ref<string>(""); previousLink: "",
const nextRaw = ref<string>(""); nextLink: "",
listing: null,
name: "",
fullSize: false,
showNav: true,
navTimeout: null,
hoverNav: false,
autoPlay: false,
previousRaw: "",
nextRaw: "",
};
},
computed: {
...mapState(["req", "user", "oldReq", "jwt", "loading"]),
...mapGetters(["currentPrompt"]),
hasPrevious() {
return this.previousLink !== "";
},
hasNext() {
return this.nextLink !== "";
},
downloadUrl() {
return api.getDownloadURL(this.req);
},
raw() {
if (this.req.type === "image" && !this.fullSize) {
return api.getPreviewURL(this.req, "big");
}
const player = ref<HTMLVideoElement | HTMLAudioElement | null>(null); return api.getDownloadURL(this.req, true);
},
showMore() {
return this.currentPrompt?.prompt === "more";
},
isResizeEnabled() {
return resizePreview;
},
subtitles() {
if (this.req.subtitles) {
return api.getSubtitlesURL(this.req);
}
return [];
},
},
watch: {
$route: function () {
this.updatePreview();
this.toggleNavigation();
},
},
async mounted() {
window.addEventListener("keydown", this.key);
this.listing = this.oldReq.items;
this.updatePreview();
},
beforeDestroy() {
window.removeEventListener("keydown", this.key);
},
methods: {
deleteFile() {
this.$store.commit("showHover", {
prompt: "delete",
confirm: () => {
this.listing = this.listing.filter((item) => item.name !== this.name);
const $showError = inject<IToastError>("$showError")!; if (this.hasNext) {
this.next();
const authStore = useAuthStore(); } else if (!this.hasPrevious && !this.hasNext) {
const fileStore = useFileStore(); this.close();
const layoutStore = useLayoutStore(); } else {
this.prev();
const route = useRoute(); }
const router = useRouter(); },
});
const hasPrevious = computed(() => previousLink.value !== ""); },
prev() {
const hasNext = computed(() => nextLink.value !== ""); this.hoverNav = false;
this.$router.replace({ path: this.previousLink });
const downloadUrl = computed(() => },
fileStore.req ? api.getDownloadURL(fileStore.req, true) : "" next() {
); this.hoverNav = false;
this.$router.replace({ path: this.nextLink });
const raw = computed(() => { },
if (fileStore.req?.type === "image" && !fullSize.value) { key(event) {
return api.getPreviewURL(fileStore.req, "big"); if (this.currentPrompt !== null) {
}
return downloadUrl.value;
});
const isResizeEnabled = computed(() => resizePreview);
const subtitles = computed(() => {
if (fileStore.req?.subtitles) {
return api.getSubtitlesURL(fileStore.req);
}
return [];
});
const videoOptions = computed(() => {
return { autoplay: autoPlay.value };
});
watch(route, () => {
updatePreview();
toggleNavigation();
});
// Specify hooks
onMounted(async () => {
window.addEventListener("keydown", key);
if (fileStore.oldReq) {
listing.value = fileStore.oldReq.items;
updatePreview();
}
});
onBeforeUnmount(() => window.removeEventListener("keydown", key));
// Specify methods
const deleteFile = () => {
layoutStore.showHover({
prompt: "delete",
confirm: () => {
if (listing.value === null) {
return; return;
} }
listing.value = listing.value.filter((item) => item.name !== name.value);
if (hasNext.value) { if (event.which === 13 || event.which === 39) {
next(); // right arrow
} else if (!hasPrevious.value && !hasNext.value) { if (this.hasNext) this.next();
close(); } else if (event.which === 37) {
} else { // left arrow
prev(); if (this.hasPrevious) this.prev();
} else if (event.which === 27) {
// esc
this.close();
} }
}, },
}); async updatePreview() {
}; if (
this.$refs.player &&
const prev = () => { this.$refs.player.paused &&
hoverNav.value = false; !this.$refs.player.ended
router.replace({ path: previousLink.value }); ) {
}; this.autoPlay = false;
const next = () => {
hoverNav.value = false;
router.replace({ path: nextLink.value });
};
const key = (event: KeyboardEvent) => {
if (layoutStore.currentPrompt !== null) {
return;
}
if (event.which === 13 || event.which === 39) {
// right arrow
if (hasNext.value) next();
} else if (event.which === 37) {
// left arrow
if (hasPrevious.value) prev();
} else if (event.which === 27) {
// esc
close();
}
};
const updatePreview = async () => {
if (player.value && player.value.paused && !player.value.ended) {
autoPlay.value = false;
}
let dirs = route.fullPath.split("/");
name.value = decodeURIComponent(dirs[dirs.length - 1]);
if (!listing.value) {
try {
const path = url.removeLastDir(route.path);
const res = await api.fetch(path);
listing.value = res.items;
} catch (e: any) {
$showError(e);
}
}
previousLink.value = "";
nextLink.value = "";
if (listing.value) {
for (let i = 0; i < listing.value.length; i++) {
if (listing.value[i].name !== name.value) {
continue;
} }
for (let j = i - 1; j >= 0; j--) { let dirs = this.$route.fullPath.split("/");
if (mediaTypes.includes(listing.value[j].type)) { this.name = decodeURIComponent(dirs[dirs.length - 1]);
previousLink.value = listing.value[j].url;
previousRaw.value = prefetchUrl(listing.value[j]); if (!this.listing) {
break; try {
} const path = url.removeLastDir(this.$route.path);
} const res = await api.fetch(path);
for (let j = i + 1; j < listing.value.length; j++) { this.listing = res.items;
if (mediaTypes.includes(listing.value[j].type)) { } catch (e) {
nextLink.value = listing.value[j].url; this.$showError(e);
nextRaw.value = prefetchUrl(listing.value[j]);
break;
} }
} }
return; this.previousLink = "";
} this.nextLink = "";
}
for (let i = 0; i < this.listing.length; i++) {
if (this.listing[i].name !== this.name) {
continue;
}
for (let j = i - 1; j >= 0; j--) {
if (mediaTypes.includes(this.listing[j].type)) {
this.previousLink = this.listing[j].url;
this.previousRaw = this.prefetchUrl(this.listing[j]);
break;
}
}
for (let j = i + 1; j < this.listing.length; j++) {
if (mediaTypes.includes(this.listing[j].type)) {
this.nextLink = this.listing[j].url;
this.nextRaw = this.prefetchUrl(this.listing[j]);
break;
}
}
return;
}
},
prefetchUrl(item) {
if (item.type !== "image") {
return "";
}
return this.fullSize
? api.getDownloadURL(item, true)
: api.getPreviewURL(item, "big");
},
openMore() {
this.$store.commit("showHover", "more");
},
resetPrompts() {
this.$store.commit("closeHovers");
},
toggleSize() {
this.fullSize = !this.fullSize;
},
toggleNavigation: throttle(function () {
this.showNav = true;
if (this.navTimeout) {
clearTimeout(this.navTimeout);
}
this.navTimeout = setTimeout(() => {
this.showNav = false || this.hoverNav;
this.navTimeout = null;
}, 1500);
}, 500),
close() {
this.$store.commit("updateRequest", {});
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
download() {
window.open(this.downloadUrl);
},
},
}; };
const prefetchUrl = (item: ResourceItem) => {
if (item.type !== "image") {
return "";
}
return fullSize.value
? api.getDownloadURL(item, true)
: api.getPreviewURL(item, "big");
};
const toggleSize = () => (fullSize.value = !fullSize.value);
const toggleNavigation = throttle(function () {
showNav.value = true;
if (navTimeout.value) {
clearTimeout(navTimeout.value);
}
navTimeout.value = setTimeout(() => {
showNav.value = false || hoverNav.value;
navTimeout.value = null;
}, 1500);
}, 500);
const close = () => {
fileStore.updateRequest(null);
let uri = url.removeLastDir(route.path) + "/";
router.push({ path: uri });
};
const download = () => window.open(downloadUrl.value);
</script> </script>

70
frontend/vite.config.js Normal file
View File

@ -0,0 +1,70 @@
import { fileURLToPath, URL } from "node:url";
import path from "node:path";
import { defineConfig } from "vite";
import legacy from "@vitejs/plugin-legacy";
import vue2 from "@vitejs/plugin-vue2";
import { compression } from "vite-plugin-compression2";
import pluginRewriteAll from "vite-plugin-rewrite-all";
const plugins = [
vue2(),
legacy({
targets: ["ie >= 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"],
}),
compression({ include: /\.js$/i, deleteOriginalAssets: true }),
pluginRewriteAll(), // fixes 404 error with paths containing dot in dev server
];
const resolve = {
alias: {
vue: "vue/dist/vue.esm.js",
"@/": `${path.resolve(__dirname, "src")}/`,
},
};
// https://vitejs.dev/config/
export default defineConfig(({ command }) => {
if (command === "serve") {
return {
plugins,
resolve,
server: {
proxy: {
"/api/command": {
target: "ws://127.0.0.1:8080",
ws: true,
},
"/api": "http://127.0.0.1:8080",
},
},
};
} else {
// command === 'build'
return {
plugins,
resolve,
base: "",
build: {
rollupOptions: {
input: {
index: fileURLToPath(
new URL(`./public/index.html`, import.meta.url)
),
},
},
},
experimental: {
renderBuiltUrl(filename, { hostType }) {
if (hostType === "js") {
return { runtime: `window.__prependStaticUrl("${filename}")` };
} else if (hostType === "html") {
return `[{[ .StaticURL ]}]/${filename}`;
} else {
return { relative: true };
}
},
},
};
}
});