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

281 lines
6.5 KiB
Svelte
Raw Normal View History

<script>
import { onMount } from 'svelte';
2022-04-26 15:23:57 +02:00
import LoadingIndicator from '../util/LoadingIndicator.svelte';
2024-02-16 14:50:34 +01:00
import EditWindow from './edit_window/EditWindow.svelte';
import Toolbar from './Toolbar.svelte';
import Breadcrumbs from './Breadcrumbs.svelte';
import DetailsWindow from './DetailsWindow.svelte';
import FilePreview from './viewers/FilePreview.svelte';
2024-09-10 18:51:13 +02:00
import FSUploadWidget from './upload_widget/FSUploadWidget.svelte';
2024-11-19 15:31:51 +01:00
import { fs_path_url } from './FilesystemAPI.mjs';
2024-03-12 17:53:53 +01:00
import Menu from './Menu.svelte';
import { FSNavigator } from "./FSNavigator"
import { writable } from 'svelte/store';
2024-09-05 17:28:31 +02:00
import TransferLimit from '../file_viewer/TransferLimit.svelte';
import { stats } from "../lib/StatsSocket.mjs"
2024-09-10 18:51:13 +02:00
import { css_from_path } from './edit_window/Branding';
2025-03-21 01:11:03 +01:00
import AffiliatePrompt from '../user_home/AffiliatePrompt.svelte';
let file_viewer
let file_preview
2023-11-16 12:17:36 +01:00
let toolbar
2023-05-29 18:01:23 +02:00
let upload_widget
let details_visible = false
2023-05-11 19:07:29 +02:00
let edit_window
let edit_visible = false
const loading = writable(true)
const nav = new FSNavigator(true)
onMount(() => {
nav.loading = loading
nav.open_node(window.initial_node, false)
// Subscribe to navigation updates. This function returns a deconstructor
// which we can conveniently return from our mount function as well
return nav.subscribe(nav => {
if (!nav.initialized) {
return
}
// Custom CSS rules for the whole viewer
2024-09-10 18:51:13 +02:00
document.documentElement.style = css_from_path(nav.path)
2020-11-17 23:39:27 +01:00
loading.set(false)
})
})
const keydown = e => {
if (e.ctrlKey || e.altKey || e.metaKey) {
return // prevent custom shortcuts from interfering with system shortcuts
2024-02-16 11:49:38 +01:00
} else if (document.activeElement.type && document.activeElement.type === "text") {
return // Prevent shortcuts from interfering with input fields
}
2024-03-12 17:53:53 +01:00
let action_performed = true
switch (e.key) {
2023-11-16 12:17:36 +01:00
case "c":
toolbar.copy_link()
break;
2020-11-26 11:13:27 +01:00
case "i":
details_visible = !details_visible
break;
case "e":
if (edit_visible) {
edit_visible = false
} else {
edit_window.edit(nav.base, true, "file")
}
break;
2020-11-26 11:13:27 +01:00
case "s":
download()
break;
case "r":
nav.shuffle = !nav.shuffle
break;
2025-02-03 16:29:26 +01:00
case "f": // F fullscreen
if (toolbar) {
toolbar.toggle_fullscreen()
}
break
case "a":
case "ArrowLeft":
nav.open_sibling(-1)
break;
case "d":
case "ArrowRight":
nav.open_sibling(1)
break;
case " ": // Spacebar pauses / unpauses video and audio playback
if (file_preview) {
if (file_preview.toggle_playback()) {
2025-02-03 16:29:26 +01:00
e.preventDefault()
e.stopPropagation()
}
}
break
2025-02-03 15:38:07 +01:00
case "m": // M mutes / unmutes audio
if (file_preview) {
file_preview.toggle_mute()
}
break
2024-08-14 19:58:25 +02:00
case "h":
file_preview.seek(-20)
break
case "j":
file_preview.seek(-5)
break
case "k":
file_preview.seek(5)
break
case "l":
file_preview.seek(20)
break
case ",":
file_preview.seek(-0.04) // Roughly a single frame.. assuming 25fps
break
case ".":
file_preview.seek(0.04)
break
2024-03-12 17:53:53 +01:00
default:
action_performed = false
}
2023-05-25 17:06:17 +02:00
2024-03-12 17:53:53 +01:00
if (action_performed) {
e.preventDefault()
}
};
2020-11-17 23:39:27 +01:00
const download = () => {
let a = document.createElement("a")
if (nav.base.type === "file") {
a.href = fs_path_url(nav.base.path) + "?attach"
a.download = nav.base.name
} else if (nav.base.type === "dir") {
a.href = fs_path_url(nav.base.path) + "?bulk_download"
a.download = nav.base.name+".zip"
}
a.click()
a.remove()
}
</script>
<svelte:window on:keydown={keydown} />
<div bind:this={file_viewer} class="file_viewer">
<div class="headerbar">
2024-03-12 17:53:53 +01:00
<Menu/>
<Breadcrumbs nav={nav}/>
</div>
2023-05-25 17:06:17 +02:00
<div class="viewer_area">
<Toolbar
2023-11-16 12:17:36 +01:00
bind:this={toolbar}
nav={nav}
file_viewer={file_viewer}
2025-02-03 16:29:26 +01:00
file_preview={file_preview}
bind:details_visible={details_visible}
edit_window={edit_window}
bind:edit_visible={edit_visible}
on:download={download}
/>
<div class="file_preview">
2024-11-14 16:14:58 +01:00
<FilePreview
bind:this={file_preview}
nav={nav}
upload_widget={upload_widget}
edit_window={edit_window}
on:open_sibling={e => nav.open_sibling(e.detail)}
on:download={download}
2025-02-03 16:29:26 +01:00
on:details={() => details_visible = !details_visible}
2024-11-14 16:14:58 +01:00
/>
2023-05-25 17:06:17 +02:00
</div>
</div>
2024-09-05 17:28:31 +02:00
{#if $nav.context.premium_transfer === false}
<div class="download_limit">
{#if $stats.limits.transfer_limit_used > $stats.limits.transfer_limit}
<div class="highlight_yellow">
Your free download limit has been used up and your download
speed has been limited to 1 MiB/s. <a href="/#pro"
target="_blank">Upgrade to premium</a> to continue fast
downloading
</div>
{:else}
<TransferLimit/>
{/if}
</div>
{/if}
<DetailsWindow nav={nav} bind:visible={details_visible} />
<EditWindow nav={nav} bind:this={edit_window} bind:visible={edit_visible} />
2024-09-10 18:51:13 +02:00
<!-- This one is included at the highest level so uploads can keep running
even when the user navigates to a different directory -->
<FSUploadWidget nav={nav} bind:this={upload_widget} />
2025-03-21 01:11:03 +01:00
<AffiliatePrompt/>
<LoadingIndicator loading={$loading}/>
</div>
<style>
:global(*) {
2024-11-14 16:14:58 +01:00
transition: background-color 0.2s,
border 0.2s,
border-top 0.2s,
border-right 0.2s,
border-bottom 0.2s,
border-left 0.2s,
color 0.2s;
}
/* Viewer container */
.file_viewer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-direction: column;
overflow: hidden;
/* Force some variable usage that is normally out of scope */
color: var(--body_text_color);
background-image: var(--background_image, var(--background_pattern));
background-color: var(--background_pattern_color);
background-size: var(--background_image_size, initial);
background-position: var(--background_image_position, initial);
background-repeat: var(--background_image_repeat, repeat);
}
/* Headerbar (row 1) */
.headerbar {
flex: 0 0 0;
display: flex;
flex-direction: row;
text-align: left;
box-shadow: none;
background-color: var(--shaded_background);
2024-11-19 15:31:51 +01:00
backdrop-filter: blur(4px);
}
/* File preview area (row 2) */
.viewer_area {
flex: 1 1 0;
display: flex;
flex-direction: row;
overflow: hidden;
}
2024-02-16 21:07:01 +01:00
2024-09-05 17:28:31 +02:00
/* Download limit gauge (row 3) */
.download_limit {
flex: 0 0 auto;
display: flex;
flex-direction: column;
text-align: center;
background-color: var(--shaded_background);
2024-11-19 15:31:51 +01:00
backdrop-filter: blur(4px);
2024-09-05 17:28:31 +02:00
}
2024-02-16 21:07:01 +01:00
/* This max-width needs to be synced with the .toolbar max-width in
Toolbar.svelte and the .label max-width in FileStats.svelte */
2025-01-27 22:54:47 +01:00
@media (max-width: 1000px) {
.viewer_area {
flex-direction: column-reverse;
}
}
2023-05-25 17:06:17 +02:00
.file_preview {
flex: 1 1 0;
overflow: auto;
border: 1px solid var(--separator);
2023-05-25 17:06:17 +02:00
}
</style>