Files
fnx_web/svelte/src/filesystem/Filesystem.svelte

279 lines
5.6 KiB
Svelte
Raw Normal View History

<script>
import { onMount } from 'svelte';
import PixeldrainLogo from '../util/PixeldrainLogo.svelte';
2022-04-26 15:23:57 +02:00
import LoadingIndicator from '../util/LoadingIndicator.svelte';
import EditWindow from './EditWindow.svelte';
import Toolbar from './Toolbar.svelte';
import Breadcrumbs from './Breadcrumbs.svelte';
import DetailsWindow from './DetailsWindow.svelte';
import Navigator from './Navigator.svelte';
import FilePreview from './viewers/FilePreview.svelte';
2023-05-25 17:06:17 +02:00
import SearchView from './SearchView.svelte';
2023-05-27 15:50:44 +02:00
import UploadWidget from './upload_widget/UploadWidget.svelte';
2023-05-31 00:27:00 +02:00
import { fs_path_url } from './FilesystemUtil';
let loading = true
2020-11-26 11:13:27 +01:00
let toolbar_visible = (window.innerWidth > 600)
2023-05-29 18:01:23 +02:00
let upload_widget
let download_frame
let details_visible = false
2023-05-11 19:07:29 +02:00
let edit_window
let edit_visible = false
2023-05-25 17:06:17 +02:00
let view = "file"
2023-05-17 22:46:27 +02:00
let fs_navigator
2020-11-17 23:39:27 +01:00
let state = {
2023-04-11 23:44:50 +02:00
path: window.initial_node.path,
base_index: window.initial_node.base_index,
2021-12-09 22:33:02 +01:00
children: window.initial_node.children,
permissions: window.initial_node.permissions,
// Shortcuts
base: window.initial_node.path[window.initial_node.base_index],
shuffle: false,
2020-11-17 23:39:27 +01:00
}
2023-05-29 12:33:22 +02:00
onMount(() => {
fs_navigator.open_node(window.initial_node, false)
})
const keydown = e => {
if (e.ctrlKey || e.altKey || e.metaKey) {
return // prevent custom shortcuts from interfering with system shortcuts
}
if (document.activeElement.type && document.activeElement.type === "text") {
return // Prevent shortcuts from interfering with input fields
}
switch (e.key) {
2020-11-26 11:13:27 +01:00
case "i":
details_visible = !details_visible
break;
case "e":
if (edit_visible) {
edit_visible = false
} else {
2023-05-25 14:47:36 +02:00
edit_window.edit(state.base, true)
}
break;
2020-11-26 11:13:27 +01:00
case "s":
download()
break;
case "r":
state.shuffle = !state.shuffle
break;
2023-05-25 17:06:17 +02:00
case "/":
case "f":
2023-05-25 20:19:37 +02:00
search()
2023-05-25 17:06:17 +02:00
break
case "a":
case "ArrowLeft":
2023-05-17 22:46:27 +02:00
fs_navigator.open_sibling(-1)
break;
case "d":
case "ArrowRight":
2023-05-17 22:46:27 +02:00
fs_navigator.open_sibling(1)
break;
}
2023-05-25 17:06:17 +02:00
e.preventDefault()
};
2020-11-17 23:39:27 +01:00
const download = () => {
download_frame.src = fs_path_url(state.base.path) + "?attach"
}
2023-05-25 20:19:37 +02:00
const search = async () => {
if (view === "search") {
view = "file"
return
}
if (state.base.type !== "dir") {
await fs_navigator.navigate(state.path[state.path.length-2].path)
}
view = "search"
}
2023-05-25 21:36:59 +02:00
const loading_evt = e => {
loading = e.detail
}
</script>
<svelte:window on:keydown={keydown} />
<Navigator
bind:this={fs_navigator}
bind:state
2023-05-25 21:36:59 +02:00
on:loading={loading_evt}
/>
2023-04-11 23:44:50 +02:00
<div class="file_viewer">
<div class="headerbar">
<button
on:click={() => toolbar_visible = !toolbar_visible}
class="button_toggle_toolbar round"
class:button_highlight={toolbar_visible}
>
<i class="icon">menu</i>
</button>
2021-10-19 15:59:49 +02:00
<a href="/" id="button_home" class="button button_home round">
<PixeldrainLogo style="height: 1.6em; width: 1.6em; margin: 0 0.2em 0 0; color: currentColor;"/>
</a>
<div class="breadcrumbs">
2023-05-17 22:46:27 +02:00
<Breadcrumbs state={state} fs_navigator={fs_navigator}/>
</div>
</div>
2023-05-25 17:06:17 +02:00
<div class="viewer_area">
<div class="file_preview checkers" class:toolbar_visible>
{#if view === "file"}
<FilePreview
fs_navigator={fs_navigator}
state={state}
edit_window={edit_window}
2023-05-25 21:36:59 +02:00
on:loading={loading_evt}
2023-05-25 17:06:17 +02:00
on:open_sibling={e => fs_navigator.open_sibling(e.detail)}
on:download={download}
2023-05-29 18:01:23 +02:00
on:upload_picker={() => upload_widget.pick_files()}
2023-05-25 17:06:17 +02:00
/>
{:else if view === "search"}
<SearchView
state={state}
fs_navigator={fs_navigator}
2023-05-25 21:36:59 +02:00
on:loading={loading_evt}
2023-05-29 12:33:22 +02:00
on:done={() => {view = "file"}}
2023-05-25 17:06:17 +02:00
/>
{/if}
</div>
2023-05-27 15:50:44 +02:00
<Toolbar
visible={toolbar_visible}
fs_navigator={fs_navigator}
state={state}
bind:details_visible={details_visible}
edit_window={edit_window}
bind:edit_visible={edit_visible}
bind:view={view}
on:download={download}
on:search={search}
/>
</div>
<!-- This frame will load the download URL when a download button is pressed -->
<iframe
bind:this={download_frame}
title="Frame for downloading files"
style="display: none; width: 1px; height: 1px;">
</iframe>
2023-05-27 15:50:44 +02:00
</div>
2023-05-27 15:50:44 +02:00
<DetailsWindow
state={state}
bind:visible={details_visible}
/>
2023-05-27 15:50:44 +02:00
<EditWindow
bind:this={edit_window}
bind:visible={edit_visible}
fs_navigator={fs_navigator}
on:loading={loading_evt}
/>
2023-05-29 18:01:23 +02:00
<UploadWidget
bind:this={upload_widget}
fs_state={state}
drop_upload
on:uploads_finished={() => fs_navigator.reload()}
/>
2023-05-27 15:50:44 +02:00
<LoadingIndicator loading={loading}/>
<style>
/* Viewer container */
.file_viewer {
position: absolute;
display: flex;
flex-direction: column;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
2022-03-29 21:41:46 +02:00
background: var(--body_background);
}
/* Headerbar (row 1) */
.headerbar {
flex-grow: 0;
flex-shrink: 0;
display: flex;
flex-direction: row;
text-align: left;
box-shadow: none;
padding: 4px;
}
/* Headerbar components */
.headerbar > * {
flex-grow: 0;
flex-shrink: 0;
margin-left: 4px;
margin-right: 4px;
display: inline;
align-self: center;
}
.button_toggle_toolbar > .icon {
2021-10-19 15:59:49 +02:00
font-size: 1.6em;
}
.breadcrumbs {
flex-grow: 1;
flex-shrink: 1;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
flex-direction: row;
}
.button_home::after {
content: "pixeldrain";
}
@media (max-width: 600px) {
.button_home::after {
content: "pd";
}
}
/* File preview area (row 2) */
2023-05-25 17:06:17 +02:00
.viewer_area {
flex-grow: 1;
flex-shrink: 1;
position: relative;
display: inline-block;
width: auto;
height: auto;
margin: 0;
}
2023-05-25 17:06:17 +02:00
.file_preview {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: block;
min-height: 100px;
min-width: 100px;
transition: left 0.25s;
overflow: auto;
text-align: center;
border-radius: 8px;
border: 2px solid var(--separator);
}
.file_preview.toolbar_visible {
left: 8em;
}
</style>