UI overhaul, import fixes, fix user store
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { fs_encode_path } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_encode_path } from "lib/FilesystemAPI";
|
||||
import { path_link, type FSNavigator } from "./FSNavigator";
|
||||
import FileMenu from "./filemanager/FileMenu.svelte";
|
||||
import EditWindow from "./edit_window/EditWindow.svelte";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { run } from 'svelte/legacy';
|
||||
import Chart from "util/Chart.svelte";
|
||||
import { formatDataVolume, formatDate, formatThousands } from "util/Formatting";
|
||||
import Modal from "util/Modal.svelte";
|
||||
import { fs_path_url, fs_share_hotlink_url, fs_share_url, fs_timeseries, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_path_url, fs_share_hotlink_url, fs_share_url, fs_timeseries, type FSNode } from "lib/FilesystemAPI";
|
||||
import { color_by_name } from "util/Util";
|
||||
import { tick } from "svelte";
|
||||
import CopyButton from "layout/CopyButton.svelte";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
import { fs_get_node, fs_encode_path, fs_split_path } from "../lib/FilesystemAPI.svelte";
|
||||
import type { FSNode, FSPath, FSPermissions, FSContext } from "../lib/FilesystemAPI.svelte";
|
||||
import { fs_get_node, fs_encode_path, fs_split_path } from "lib/FilesystemAPI";
|
||||
import type { FSNode, FSPath, FSPermissions, FSContext } from "lib/FilesystemAPI";
|
||||
|
||||
export class FSNavigator {
|
||||
// Parts of the raw API response
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { formatDataVolume, formatThousands } from "util/Formatting"
|
||||
import { fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_path_url } from "lib/FilesystemAPI";
|
||||
import type { FSNavigator } from "./FSNavigator";
|
||||
|
||||
let {
|
||||
|
||||
@@ -35,15 +35,16 @@ const open = () => dialog.open(button.getBoundingClientRect())
|
||||
<NovaLogo style="height: 1.6em; width: 1.6em;"/>
|
||||
{/if}
|
||||
<span class="button_username" class:hide_name>
|
||||
{$user.username === "" ? no_login_label : $user.username}
|
||||
{#if $user !== null}
|
||||
{$user.username === "" ? no_login_label : $user.username}
|
||||
{/if}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Dialog bind:this={dialog}>
|
||||
<div class="menu">
|
||||
{#if $user.username !== undefined && $user.username !== ""}
|
||||
|
||||
{#if $user !== null}
|
||||
<Button link_href="/user" link_target={target} icon="dashboard" label="Dashboard" />
|
||||
<div class="separator"></div>
|
||||
|
||||
@@ -63,12 +64,7 @@ const open = () => dialog.open(button.getBoundingClientRect())
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
|
||||
{#if $user.subscription.filesystem_access}
|
||||
<Button link_href="/d/me" link_target={target} icon="folder" label="My Filesystem"/>
|
||||
{:else}
|
||||
<Button link_href="/#pro" link_target={target} icon="star" label="Get Premium"/>
|
||||
{/if}
|
||||
|
||||
<Button link_href="/d/me" link_target={target} icon="folder" label="My Filesystem"/>
|
||||
<Button link_href="/filesystem" link_target={target} icon="description" label="Filesystem Guide"/>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount, tick } from "svelte";
|
||||
import { fs_search, fs_encode_path, fs_thumbnail_url, FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_search, fs_encode_path, fs_thumbnail_url, FSNode } from "lib/FilesystemAPI";
|
||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
import Modal from "util/Modal.svelte";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { FSNavigator } from "./FSNavigator";
|
||||
import { fs_node_icon, fs_share_hotlink_url, fs_share_url, fs_update, type FSNode, type FSPermissions } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_node_icon, fs_share_hotlink_url, fs_share_url, fs_update, type FSNode, type FSPermissions } from "lib/FilesystemAPI";
|
||||
import { copy_text } from "util/Util";
|
||||
import CopyButton from "layout/CopyButton.svelte";
|
||||
import Dialog from "layout/Dialog.svelte";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { copy_text } from "util/Util";
|
||||
import FileStats from "./FileStats.svelte";
|
||||
import type { FSNavigator } from "./FSNavigator";
|
||||
import EditWindow from "./edit_window/EditWindow.svelte";
|
||||
import { fs_share_url, path_is_shared } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_share_url, path_is_shared } from "lib/FilesystemAPI";
|
||||
import ShareDialog from "./ShareDialog.svelte";
|
||||
import { bookmark_add, bookmark_del, bookmarks_store, is_bookmark } from "lib/Bookmarks";
|
||||
|
||||
@@ -36,7 +36,7 @@ export const copy_link = () => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="toolbar bubble">
|
||||
<FileStats nav={nav} bind:expanded={toolbar_expanded}/>
|
||||
|
||||
<div class="grid" class:hide={!toolbar_expanded}>
|
||||
@@ -110,11 +110,10 @@ export const copy_link = () => {
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
transition: max-height 0.3s;
|
||||
border-top: 1px solid var(--separator);
|
||||
|
||||
background: var(--shaded_background);
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
bottom: 4px;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Button from "layout/Button.svelte";
|
||||
import type { FSPermissions, NodeOptions } from "lib/FilesystemAPI.svelte";
|
||||
import type { FSPermissions, NodeOptions } from "lib/FilesystemAPI";
|
||||
import PermissionButton from "./PermissionButton.svelte";
|
||||
|
||||
let {
|
||||
@@ -60,7 +60,6 @@ const del_password = (pass: string) => {
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
||||
<fieldset>
|
||||
<legend>User permissions</legend>
|
||||
<p>
|
||||
|
||||
@@ -2,7 +2,7 @@ import parse from "pure-color/parse";
|
||||
import rgb2hsl from "pure-color/convert/rgb2hsl";
|
||||
import hsl2rgb from "pure-color/convert/hsl2rgb";
|
||||
import rgb2hex from "pure-color/convert/rgb2hex";
|
||||
import type { FSNode, FSNodeProperties } from "lib/FilesystemAPI.svelte";
|
||||
import type { FSNode, FSNodeProperties } from "lib/FilesystemAPI";
|
||||
|
||||
const text_contrast = 85
|
||||
const body_alpha = 0.9
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import ThemePresets from "./ThemePresets.svelte";
|
||||
import { fs_update, fs_node_type, type FSNode, type NodeOptions, type FSPermissions } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_update, fs_node_type, type FSNode, type NodeOptions, type FSPermissions } from "lib/FilesystemAPI";
|
||||
import CustomBanner from "filesystem/viewers/CustomBanner.svelte";
|
||||
import HelpButton from "layout/HelpButton.svelte";
|
||||
import FilePicker from "filesystem/filemanager/FilePicker.svelte";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { fs_rename, fs_update, type FSNode, type FSPermissions, type NodeOptions } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_rename, fs_update, type FSNode, type FSPermissions, type NodeOptions } from "lib/FilesystemAPI";
|
||||
import Modal from "util/Modal.svelte";
|
||||
import BrandingOptions from "./BrandingOptions.svelte";
|
||||
import { branding_from_props } from "./Branding";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Button from "layout/Button.svelte";
|
||||
import { fs_trash, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_trash, type FSNode } from "lib/FilesystemAPI";
|
||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import ToggleButton from "layout/ToggleButton.svelte";
|
||||
import type { FSPermissions } from "lib/FilesystemAPI.svelte";
|
||||
import type { FSPermissions } from "lib/FilesystemAPI";
|
||||
|
||||
let {
|
||||
permissions = $bindable()
|
||||
|
||||
@@ -3,7 +3,7 @@ import { run } from 'svelte/legacy';
|
||||
import { domain_url } from "util/Util";
|
||||
import CopyButton from "layout/CopyButton.svelte";
|
||||
import { formatDate } from "util/Formatting";
|
||||
import { type FSNode, type NodeOptions } from "lib/FilesystemAPI.svelte";
|
||||
import { type FSNode, type NodeOptions } from "lib/FilesystemAPI";
|
||||
import AccessControl from "./AccessControl.svelte";
|
||||
|
||||
let {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type { FSNodeProperties } from "lib/FilesystemAPI.svelte";
|
||||
import type { FSNodeProperties } from "lib/FilesystemAPI";
|
||||
|
||||
let {
|
||||
properties = $bindable({} as FSNodeProperties)
|
||||
@@ -88,7 +88,7 @@ const themes = [
|
||||
brand_card_color: "#313244",
|
||||
}, {
|
||||
name: "Nova",
|
||||
brand_input_color: "#170025",
|
||||
brand_input_color: "#28033f",
|
||||
brand_highlight_color: "#57e389",
|
||||
brand_danger_color: "#ed333b",
|
||||
brand_background_color: "#0d0015",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { fs_encode_path, fs_node_icon } from "lib/FilesystemAPI.svelte"
|
||||
import { fs_encode_path, fs_node_icon } from "lib/FilesystemAPI"
|
||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { fs_mkdir } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_mkdir } from "lib/FilesystemAPI";
|
||||
import Button from "layout/Button.svelte";
|
||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { fs_rename, fs_trash, FSNode } from "lib/FilesystemAPI.svelte"
|
||||
import { fs_rename, fs_trash, FSNode } from "lib/FilesystemAPI"
|
||||
import { onMount } from "svelte"
|
||||
import CreateDirectory from "./CreateDirectory.svelte"
|
||||
import ListView from "./ListView.svelte"
|
||||
@@ -305,7 +305,7 @@ onMount(() => {
|
||||
shadow: "var(--highlight_color) 0 0 10px 2px inset",
|
||||
}}
|
||||
>
|
||||
<div class="width_container">
|
||||
<div class="width_container bubble">
|
||||
{#if mode === "viewing"}
|
||||
<div class="toolbar">
|
||||
<div class="toolbar_left">
|
||||
@@ -430,11 +430,9 @@ onMount(() => {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
background: var(--body_background);
|
||||
/* backdrop-filter: blur(4px); */
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import Button from "layout/Button.svelte";
|
||||
import Dialog from "layout/Dialog.svelte";
|
||||
import { bookmark_add, bookmark_del, bookmarks_store, is_bookmark } from "lib/Bookmarks";
|
||||
import { fs_trash, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_trash, type FSNode } from "lib/FilesystemAPI";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
import { tick } from "svelte";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import GalleryView from "./GalleryView.svelte"
|
||||
import CompactView from "./CompactView.svelte"
|
||||
import Modal from "util/Modal.svelte";
|
||||
import { FSNavigator, path_link } from "filesystem/FSNavigator";
|
||||
import { fs_encode_path, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_encode_path, type FSNode } from "lib/FilesystemAPI";
|
||||
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||
|
||||
let nav = $state(new FSNavigator(false))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { fs_node_icon, fs_node_type, fs_encode_path } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_node_icon, fs_node_type, fs_encode_path } from "lib/FilesystemAPI";
|
||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { formatDataVolume } from "util/Formatting";
|
||||
import { fs_encode_path, fs_node_icon } from "lib/FilesystemAPI.svelte"
|
||||
import { fs_encode_path, fs_node_icon } from "lib/FilesystemAPI"
|
||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import SortButton from "layout/SortButton.svelte";
|
||||
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||
|
||||
260
svelte/src/filesystem/filemanager/TrashBin.svelte
Normal file
260
svelte/src/filesystem/filemanager/TrashBin.svelte
Normal file
@@ -0,0 +1,260 @@
|
||||
<script lang="ts">
|
||||
import { formatDataVolume, formatDate } from "util/Formatting";
|
||||
import { fs_check_response, fs_encode_path, fs_get_trash, fs_node_icon, fs_path_url, type TrashEntry } from "lib/FilesystemAPI";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let { root_path = "/me" }: { root_path?: string } = $props();
|
||||
|
||||
let entries: TrashEntry[] = $state([]);
|
||||
let error: string = $state("");
|
||||
let loaded = $state(false);
|
||||
|
||||
const load = async () => {
|
||||
loaded = false;
|
||||
entries = [];
|
||||
try {
|
||||
loading_start();
|
||||
entries = await fs_get_trash(root_path)
|
||||
error = "";
|
||||
} catch (err: any) {
|
||||
error = err?.message ?? JSON.stringify(err);
|
||||
} finally {
|
||||
loaded = true;
|
||||
loading_finish();
|
||||
}
|
||||
};
|
||||
|
||||
const delete_entry = async (entry: TrashEntry) => {
|
||||
if (!confirm(`Permanently delete "${entry.node.name}"?`)) return;
|
||||
try {
|
||||
loading_start();
|
||||
await fs_check_response(
|
||||
await fetch(fs_path_url(entry.node.path) + "?trash", { method: "DELETE" })
|
||||
);
|
||||
entries = entries.filter(e => e.node.id !== entry.node.id);
|
||||
} catch (err: any) {
|
||||
alert(err?.message ?? JSON.stringify(err));
|
||||
} finally {
|
||||
loading_finish();
|
||||
}
|
||||
};
|
||||
|
||||
const restore_entry = async (entry: TrashEntry) => {
|
||||
if (!entry.original_path) {
|
||||
alert("Original path is not known, cannot restore this file.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
loading_start();
|
||||
const form = new FormData();
|
||||
form.append("action", "rename");
|
||||
form.append("target", "/me" + entry.original_path);
|
||||
await fs_check_response(
|
||||
await fetch(fs_path_url(entry.node.path), { method: "POST", body: form })
|
||||
);
|
||||
entries = entries.filter(e => e.node.id !== entry.node.id);
|
||||
} catch (err: any) {
|
||||
alert(err?.message ?? JSON.stringify(err));
|
||||
} finally {
|
||||
loading_finish();
|
||||
}
|
||||
};
|
||||
|
||||
const empty_trash = async () => {
|
||||
if (!confirm("Permanently delete all items in the trash?")) return;
|
||||
try {
|
||||
loading_start();
|
||||
await fs_check_response(
|
||||
await fetch(fs_path_url(root_path) + "?empty_trash", { method: "DELETE" })
|
||||
);
|
||||
entries = [];
|
||||
} catch (err: any) {
|
||||
alert(err?.message ?? JSON.stringify(err));
|
||||
} finally {
|
||||
loading_finish();
|
||||
}
|
||||
};
|
||||
|
||||
onMount(load);
|
||||
</script>
|
||||
|
||||
<div class="trash_container">
|
||||
<div class="header">
|
||||
<h2 class="title"><i class="icon">delete</i> Trash</h2>
|
||||
<div class="actions">
|
||||
<button onclick={load}>
|
||||
<i class="icon">refresh</i>
|
||||
<span>Refresh</span>
|
||||
</button>
|
||||
{#if entries.length > 0}
|
||||
<button class="danger" onclick={empty_trash}>
|
||||
<i class="icon">delete_forever</i>
|
||||
<span>Empty trash</span>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<p class="error">{error}</p>
|
||||
{:else if loaded && entries.length === 0}
|
||||
<p class="empty">The trash is empty.</p>
|
||||
{:else if entries.length > 0}
|
||||
<table class="trash_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Name</td>
|
||||
<td class="hide_small">Original location</td>
|
||||
<td class="hide_small">Deleted</td>
|
||||
<td class="hide_small">Size</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each entries as entry (entry.node.id)}
|
||||
<tr class="entry">
|
||||
<td class="icon_cell">
|
||||
<img
|
||||
src={fs_node_icon(entry.node, 32, 32)}
|
||||
class="node_icon"
|
||||
alt="icon"
|
||||
/>
|
||||
</td>
|
||||
<td class="name_cell">
|
||||
<a class="entry_link" href={"/d" + fs_encode_path(entry.node.path)}>
|
||||
{entry.node.name}
|
||||
</a>
|
||||
</td>
|
||||
<td class="hide_small original_path">
|
||||
{entry.original_path || "—"}
|
||||
</td>
|
||||
<td class="hide_small date_cell">
|
||||
{entry.deletion_date ? formatDate(entry.deletion_date) : "—"}
|
||||
</td>
|
||||
<td class="hide_small size_cell">
|
||||
{#if entry.node.type === "file"}
|
||||
{formatDataVolume(entry.node.file_size, 3)}
|
||||
{/if}
|
||||
</td>
|
||||
<td class="button_cell">
|
||||
<div class="row_actions">
|
||||
<button title="Restore to original location" onclick={() => restore_entry(entry)}>
|
||||
<i class="icon">restore_from_trash</i>
|
||||
</button>
|
||||
<button class="danger" title="Delete permanently" onclick={() => delete_entry(entry)}>
|
||||
<i class="icon">delete_forever</i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.trash_container {
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
margin: 0;
|
||||
font-size: 1.2em;
|
||||
border: none;
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
}
|
||||
.error {
|
||||
color: var(--danger_color, #c0392b);
|
||||
}
|
||||
.empty {
|
||||
color: var(--body_text_color);
|
||||
opacity: 0.6;
|
||||
}
|
||||
.trash_table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: var(--body_background);
|
||||
}
|
||||
.trash_table td {
|
||||
padding: 0;
|
||||
}
|
||||
.entry {
|
||||
cursor: default;
|
||||
border-top: 1px solid var(--separator);
|
||||
}
|
||||
.entry:hover {
|
||||
background: var(--input_hover_background);
|
||||
}
|
||||
.icon_cell {
|
||||
width: 2.5em;
|
||||
padding: 0.3em 0.3em 0.3em 0.5em;
|
||||
}
|
||||
.node_icon {
|
||||
display: block;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
object-fit: contain;
|
||||
}
|
||||
.name_cell {
|
||||
padding: 0.3em 0.5em;
|
||||
word-break: break-all;
|
||||
}
|
||||
.entry_link {
|
||||
color: var(--body_text_color);
|
||||
text-decoration: none;
|
||||
}
|
||||
.entry_link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.original_path {
|
||||
padding: 0.3em 0.5em;
|
||||
color: var(--body_text_color);
|
||||
opacity: 0.7;
|
||||
font-size: 0.85em;
|
||||
word-break: break-all;
|
||||
}
|
||||
.date_cell {
|
||||
padding: 0.3em 0.5em;
|
||||
white-space: nowrap;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.size_cell {
|
||||
padding: 0.3em 0.5em;
|
||||
white-space: nowrap;
|
||||
font-size: 0.85em;
|
||||
text-align: right;
|
||||
}
|
||||
.button_cell {
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
.row_actions {
|
||||
display: flex;
|
||||
gap: 0.25em;
|
||||
}
|
||||
.danger {
|
||||
color: var(--danger_color, #c0392b);
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.hide_small {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -9,7 +9,7 @@
|
||||
//
|
||||
// on_error is called when the upload has failed. The parameters are the error
|
||||
|
||||
import { fs_path_url, type GenericResponse } from "lib/FilesystemAPI.svelte"
|
||||
import { fs_path_url, type GenericResponse } from "lib/FilesystemAPI"
|
||||
|
||||
// code and an error message
|
||||
export const upload_file = (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import { fs_path_url, fs_encode_path, fs_node_icon, FSNode } from "lib/FilesystemAPI.svelte"
|
||||
import { fs_path_url, fs_encode_path, fs_node_icon, FSNode } from "lib/FilesystemAPI"
|
||||
import TextBlock from "layout/TextBlock.svelte"
|
||||
import type { FSNavigator } from 'filesystem/FSNavigator';
|
||||
|
||||
@@ -64,7 +64,7 @@ onMount(() => {
|
||||
{@render children?.()}
|
||||
|
||||
<div bind:this={background_div} class="background_div">
|
||||
<TextBlock width="auto">
|
||||
<TextBlock>
|
||||
<audio
|
||||
bind:this={player}
|
||||
class="player"
|
||||
@@ -111,6 +111,7 @@ onMount(() => {
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
min-height: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.player {
|
||||
width: 100%;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type { FSNode } from 'lib/FilesystemAPI.svelte';
|
||||
import type { FSNode } from 'lib/FilesystemAPI';
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
let { path = [] }: {path: FSNode[]} = $props();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import IconBlock from "layout/IconBlock.svelte";
|
||||
import { fs_thumbnail_url, FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_thumbnail_url, FSNode } from "lib/FilesystemAPI";
|
||||
import TextBlock from "layout/TextBlock.svelte"
|
||||
import { formatDataVolume, formatDate } from "util/Formatting";
|
||||
|
||||
@@ -17,12 +17,24 @@ let {
|
||||
|
||||
{@render children?.()}
|
||||
|
||||
<h1>{node.name}</h1>
|
||||
|
||||
<IconBlock icon_href={fs_thumbnail_url(node.path, 256, 256)}>
|
||||
Type: {node.file_type}<br/>
|
||||
Size: {formatDataVolume(node.file_size, 3)}<br/>
|
||||
Upload date: {formatDate(node.created, true, true, false)}
|
||||
{node.name}<br/>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td>{node.file_type}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Size</td>
|
||||
<td>{formatDataVolume(node.file_size, 3)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Upload date</td>
|
||||
<td>{formatDate(node.created, true, true, false)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr/>
|
||||
<button class="button_highlight" onclick={() => node.download()}>
|
||||
<i class="icon">download</i>
|
||||
@@ -79,9 +91,12 @@ let {
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
text-shadow: 1px 1px 3px var(--shadow_color);
|
||||
line-break: anywhere;
|
||||
table {
|
||||
width: auto;
|
||||
}
|
||||
td {
|
||||
padding: 0;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.icon {
|
||||
display: inline-block;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { onMount, tick } from "svelte";
|
||||
import Spinner from "util/Spinner.svelte";
|
||||
import { fs_node_type } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_node_type } from "lib/FilesystemAPI";
|
||||
import FileManager from "filesystem/filemanager/FileManager.svelte";
|
||||
import TrashBin from "filesystem/filemanager/TrashBin.svelte";
|
||||
import Audio from "./Audio.svelte";
|
||||
import File from "./File.svelte";
|
||||
import Image from "./Image.svelte";
|
||||
@@ -88,6 +89,8 @@ export const seek = (delta: number) => {
|
||||
<div class="center">
|
||||
<Spinner/>
|
||||
</div>
|
||||
{:else if viewer_type === "dir" && $nav.base.name === ".Trash"}
|
||||
<TrashBin root_path={$nav.path[$nav.path.length - 2].path}/>
|
||||
{:else if viewer_type === "dir"}
|
||||
<FileManager nav={nav} upload_widget={upload_widget} edit_window={edit_window} search_bar={search_bar}>
|
||||
<CustomBanner path={$nav.path}/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { swipe_nav } from "lib/SwipeNavigate";
|
||||
import { fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_path_url } from "lib/FilesystemAPI";
|
||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { fs_path_url, FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_path_url, FSNode } from "lib/FilesystemAPI";
|
||||
|
||||
let { node }: { node: FSNode } = $props();
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { tick } from "svelte";
|
||||
import { fs_path_url, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_path_url, type FSNode } from "lib/FilesystemAPI";
|
||||
|
||||
let {
|
||||
node,
|
||||
|
||||
@@ -18,7 +18,7 @@ import { formatDate } from "util/Formatting"
|
||||
import TorrentItem from "./TorrentItem.svelte"
|
||||
import IconBlock from "layout/IconBlock.svelte";
|
||||
import TextBlock from "layout/TextBlock.svelte"
|
||||
import { fs_node_icon, fs_path_url, FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_node_icon, fs_path_url, FSNode } from "lib/FilesystemAPI";
|
||||
import CopyButton from "layout/CopyButton.svelte";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount, tick } from "svelte";
|
||||
import { video_position } from "lib/VideoPosition";
|
||||
import { fs_path_url, FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_path_url, FSNode } from "lib/FilesystemAPI";
|
||||
|
||||
let {
|
||||
node,
|
||||
|
||||
@@ -12,7 +12,7 @@ import { formatDataVolume, formatDate } from "util/Formatting"
|
||||
import ZipItem from "filesystem/viewers/ZipItem.svelte";
|
||||
import IconBlock from "layout/IconBlock.svelte";
|
||||
import TextBlock from "layout/TextBlock.svelte"
|
||||
import { fs_node_icon, fs_path_url, FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { fs_node_icon, fs_path_url, FSNode } from "lib/FilesystemAPI";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
|
||||
let {
|
||||
@@ -26,7 +26,7 @@ let {
|
||||
let status = $state("loading")
|
||||
|
||||
let zip: ZipEntry = $state({size: 0} as ZipEntry)
|
||||
let uncomp_size = 0
|
||||
let uncomp_size = $state(0)
|
||||
let comp_ratio = $state(0)
|
||||
let archive_type = $state("")
|
||||
let truncated = $state(false)
|
||||
@@ -97,8 +97,6 @@ const recursive_size = (file: ZipEntry) => {
|
||||
|
||||
{@render children?.()}
|
||||
|
||||
<h1>{node.name}</h1>
|
||||
|
||||
<IconBlock icon_href={fs_node_icon(node, 256, 256)}>
|
||||
{#if archive_type === "7z"}
|
||||
This is a 7-zip archive. You will need
|
||||
@@ -106,12 +104,26 @@ const recursive_size = (file: ZipEntry) => {
|
||||
extract it<br/>
|
||||
{/if}
|
||||
|
||||
Compressed size: {formatDataVolume(node.file_size, 3)}<br/>
|
||||
{#if !truncated}
|
||||
Uncompressed size: {formatDataVolume(zip.size, 3)} (Ratio: {comp_ratio.toFixed(2)}x)<br/>
|
||||
{/if}
|
||||
Uploaded on: {formatDate(node.created, true, true, true)}
|
||||
<br/>
|
||||
{node.name}<br/>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Compressed size</td>
|
||||
<td>{formatDataVolume(node.file_size, 3)}</td>
|
||||
</tr>
|
||||
{#if !truncated}
|
||||
<tr>
|
||||
<td>Uncompressed size</td>
|
||||
<td>{formatDataVolume(uncomp_size, 3)} (Ratio: {comp_ratio.toFixed(2)}x)</td>
|
||||
</tr>
|
||||
{/if}
|
||||
<tr>
|
||||
<td>Upload date</td>
|
||||
<td>{formatDate(node.created, true, true, true)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr/>
|
||||
<button class="button_highlight" onclick={() => node.download()}>
|
||||
<i class="icon">download</i>
|
||||
<span>Download</span>
|
||||
@@ -140,8 +152,11 @@ const recursive_size = (file: ZipEntry) => {
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
text-shadow: 1px 1px 3px var(--shadow_color);
|
||||
line-break: anywhere;
|
||||
table {
|
||||
width: auto;
|
||||
}
|
||||
td {
|
||||
padding: 0;
|
||||
padding-right: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user