Replace event dispatcher with a callback in filemanager
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { preventDefault } from 'svelte/legacy';
|
import { preventDefault } from 'svelte/legacy';
|
||||||
import { fs_encode_path, node_is_shared } from "lib/FilesystemAPI";
|
import { fs_encode_path } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "./FSNavigator";
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
|
|
||||||
let { nav }: {
|
let { nav }: {
|
||||||
@@ -17,7 +17,7 @@ let { nav }: {
|
|||||||
>
|
>
|
||||||
{#if node.abuse_type !== undefined}
|
{#if node.abuse_type !== undefined}
|
||||||
<i class="icon small">block</i>
|
<i class="icon small">block</i>
|
||||||
{:else if node_is_shared(node)}
|
{:else if node.is_shared()}
|
||||||
<i class="icon small">share</i>
|
<i class="icon small">share</i>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="node_name" class:base={$nav.base_index === i}>
|
<div class="node_name" class:base={$nav.base_index === i}>
|
||||||
|
@@ -3,7 +3,7 @@ import { run } from 'svelte/legacy';
|
|||||||
import Chart from "util/Chart.svelte";
|
import Chart from "util/Chart.svelte";
|
||||||
import { formatDataVolume, formatDate, formatThousands } from "util/Formatting";
|
import { formatDataVolume, formatDate, formatThousands } from "util/Formatting";
|
||||||
import Modal from "util/Modal.svelte";
|
import Modal from "util/Modal.svelte";
|
||||||
import { fs_path_url, fs_share_hotlink_url, fs_share_url, fs_timeseries, type FSNode } from "lib/FilesystemAPI";
|
import { fs_path_url, fs_share_hotlink_url, fs_share_url, fs_timeseries, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||||
import { color_by_name } from "util/Util";
|
import { color_by_name } from "util/Util";
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
@@ -86,7 +86,7 @@ let update_chart = async (base: FSNode, timespan: number, interval: number) => {
|
|||||||
display: true,
|
display: true,
|
||||||
position: "right",
|
position: "right",
|
||||||
ticks: {
|
ticks: {
|
||||||
callback: function (value, index, values) {
|
callback: function (value: number, index, values) {
|
||||||
return formatDataVolume(value, 3);
|
return formatDataVolume(value, 3);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { loading_finish, loading_start } from "lib/Loading";
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
import { fs_get_node, fs_encode_path, fs_split_path } from "../lib/FilesystemAPI";
|
import { fs_get_node, fs_encode_path, fs_split_path } from "../lib/FilesystemAPI.svelte";
|
||||||
import type { FSNode, FSPath, FSPermissions, FSContext } from "../lib/FilesystemAPI";
|
import type { FSNode, FSPath, FSPermissions, FSContext } from "../lib/FilesystemAPI.svelte";
|
||||||
|
|
||||||
export class FSNavigator {
|
export class FSNavigator {
|
||||||
// Parts of the raw API response
|
// Parts of the raw API response
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDataVolume, formatThousands } from "util/Formatting"
|
import { formatDataVolume, formatThousands } from "util/Formatting"
|
||||||
import { fs_path_url } from "lib/FilesystemAPI";
|
import { fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "./FSNavigator";
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
|
|
||||||
let { nav }: {
|
let { nav }: {
|
||||||
|
@@ -6,7 +6,7 @@ import Breadcrumbs from "./Breadcrumbs.svelte";
|
|||||||
import DetailsWindow from "./DetailsWindow.svelte";
|
import DetailsWindow from "./DetailsWindow.svelte";
|
||||||
import FilePreview from "./viewers/FilePreview.svelte";
|
import FilePreview from "./viewers/FilePreview.svelte";
|
||||||
import FSUploadWidget from "./upload_widget/FSUploadWidget.svelte";
|
import FSUploadWidget from "./upload_widget/FSUploadWidget.svelte";
|
||||||
import { fs_download, type FSPath } from "lib/FilesystemAPI";
|
import { fs_download, type FSPath } from "lib/FilesystemAPI.svelte";
|
||||||
import { FSNavigator } from "./FSNavigator"
|
import { FSNavigator } from "./FSNavigator"
|
||||||
import { css_from_path } from "filesystem/edit_window/Branding";
|
import { css_from_path } from "filesystem/edit_window/Branding";
|
||||||
import AffiliatePrompt from "user_home/AffiliatePrompt.svelte";
|
import AffiliatePrompt from "user_home/AffiliatePrompt.svelte";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { FSNavigator } from "./FSNavigator";
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
import { fs_node_icon, fs_share_hotlink_url, fs_share_url, fs_update, node_is_shared, type FSNode, type FSPermissions } from "lib/FilesystemAPI";
|
import { fs_node_icon, fs_share_hotlink_url, fs_share_url, fs_update, type FSNode, type FSPermissions } from "lib/FilesystemAPI.svelte";
|
||||||
import { copy_text } from "util/Util";
|
import { copy_text } from "util/Util";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
import Dialog from "layout/Dialog.svelte";
|
import Dialog from "layout/Dialog.svelte";
|
||||||
@@ -38,7 +38,7 @@ export const open = async (e: MouseEvent, p: FSNode[]) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const make_public = async () => {
|
const make_public = async () => {
|
||||||
if (!node_is_shared(base)) {
|
if (!base.is_shared()) {
|
||||||
base = await fs_update(
|
base = await fs_update(
|
||||||
base.path,
|
base.path,
|
||||||
{link_permissions: {read: true} as FSPermissions},
|
{link_permissions: {read: true} as FSPermissions},
|
||||||
|
@@ -4,7 +4,7 @@ import { copy_text } from "util/Util";
|
|||||||
import FileStats from "./FileStats.svelte";
|
import FileStats from "./FileStats.svelte";
|
||||||
import type { FSNavigator } from "./FSNavigator";
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
import EditWindow from "./edit_window/EditWindow.svelte";
|
import EditWindow from "./edit_window/EditWindow.svelte";
|
||||||
import { fs_share_url, path_is_shared } from "lib/FilesystemAPI";
|
import { fs_share_url, path_is_shared } from "lib/FilesystemAPI.svelte";
|
||||||
import ShareDialog from "./ShareDialog.svelte";
|
import ShareDialog from "./ShareDialog.svelte";
|
||||||
import { bookmark_add, bookmark_del, bookmarks_store, is_bookmark } from "lib/Bookmarks";
|
import { bookmark_add, bookmark_del, bookmarks_store, is_bookmark } from "lib/Bookmarks";
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import type { FSPermissions, NodeOptions } from "lib/FilesystemAPI";
|
import type { FSPermissions, NodeOptions } from "lib/FilesystemAPI.svelte";
|
||||||
import PermissionButton from "./PermissionButton.svelte";
|
import PermissionButton from "./PermissionButton.svelte";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
|
@@ -2,7 +2,7 @@ import parse from "pure-color/parse";
|
|||||||
import rgb2hsl from "pure-color/convert/rgb2hsl";
|
import rgb2hsl from "pure-color/convert/rgb2hsl";
|
||||||
import hsl2rgb from "pure-color/convert/hsl2rgb";
|
import hsl2rgb from "pure-color/convert/hsl2rgb";
|
||||||
import rgb2hex from "pure-color/convert/rgb2hex";
|
import rgb2hex from "pure-color/convert/rgb2hex";
|
||||||
import type { FSNode, FSNodeProperties } from "lib/FilesystemAPI";
|
import type { FSNode, FSNodeProperties } from "lib/FilesystemAPI.svelte";
|
||||||
|
|
||||||
type Style = {
|
type Style = {
|
||||||
input_background: string,
|
input_background: string,
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
import { run } from 'svelte/legacy';
|
import { run } from 'svelte/legacy';
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import ThemePresets from "./ThemePresets.svelte";
|
import ThemePresets from "./ThemePresets.svelte";
|
||||||
import { fs_update, fs_node_type, type FSNode, type NodeOptions, node_is_shared, type FSPermissions } from "lib/FilesystemAPI";
|
import { fs_update, fs_node_type, type FSNode, type NodeOptions, type FSPermissions } from "lib/FilesystemAPI.svelte";
|
||||||
import CustomBanner from "filesystem/viewers/CustomBanner.svelte";
|
import CustomBanner from "filesystem/viewers/CustomBanner.svelte";
|
||||||
import HelpButton from "layout/HelpButton.svelte";
|
import HelpButton from "layout/HelpButton.svelte";
|
||||||
import FilePicker from "filesystem/filemanager/FilePicker.svelte";
|
import FilePicker from "filesystem/filemanager/FilePicker.svelte";
|
||||||
@@ -49,7 +49,7 @@ const handle_picker = async (e: CustomEvent<FSNode[]>) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If this image is not public, it will be made public
|
// If this image is not public, it will be made public
|
||||||
if (!node_is_shared(f)) {
|
if (!f.is_shared()) {
|
||||||
try {
|
try {
|
||||||
f = await fs_update(
|
f = await fs_update(
|
||||||
e.detail[0].path,
|
e.detail[0].path,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { preventDefault } from 'svelte/legacy';
|
import { preventDefault } from 'svelte/legacy';
|
||||||
import { fs_rename, fs_update, type FSNode, type NodeOptions } from "lib/FilesystemAPI";
|
import { fs_rename, fs_update, type FSNode, type NodeOptions } from "lib/FilesystemAPI.svelte";
|
||||||
import Modal from "util/Modal.svelte";
|
import Modal from "util/Modal.svelte";
|
||||||
import BrandingOptions from "./BrandingOptions.svelte";
|
import BrandingOptions from "./BrandingOptions.svelte";
|
||||||
import { branding_from_node } from "./Branding";
|
import { branding_from_node } from "./Branding";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import { fs_delete_all, type FSNode } from "lib/FilesystemAPI";
|
import { fs_delete_all, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||||
import PathLink from "filesystem/util/PathLink.svelte";
|
import PathLink from "filesystem/util/PathLink.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import { loading_finish, loading_start } from "lib/Loading";
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ToggleButton from "layout/ToggleButton.svelte";
|
import ToggleButton from "layout/ToggleButton.svelte";
|
||||||
import type { FSPermissions } from "lib/FilesystemAPI";
|
import type { FSPermissions } from "lib/FilesystemAPI.svelte";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
permissions = $bindable()
|
permissions = $bindable()
|
||||||
|
@@ -3,7 +3,7 @@ import { run } from 'svelte/legacy';
|
|||||||
import { domain_url } from "util/Util";
|
import { domain_url } from "util/Util";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
import { formatDate } from "util/Formatting";
|
import { formatDate } from "util/Formatting";
|
||||||
import { node_is_shared, type FSNode, type NodeOptions } from "lib/FilesystemAPI";
|
import { type FSNode, type NodeOptions } from "lib/FilesystemAPI.svelte";
|
||||||
import AccessControl from "./AccessControl.svelte";
|
import AccessControl from "./AccessControl.svelte";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -18,7 +18,7 @@ let embed_html: string = $state()
|
|||||||
let preview_area: HTMLDivElement = $state()
|
let preview_area: HTMLDivElement = $state()
|
||||||
|
|
||||||
const embed_iframe = (file: FSNode, options: NodeOptions) => {
|
const embed_iframe = (file: FSNode, options: NodeOptions) => {
|
||||||
if (!node_is_shared(file)) {
|
if (!file.is_shared()) {
|
||||||
example = false
|
example = false
|
||||||
embed_html = "File is not shared, can't generate embed code"
|
embed_html = "File is not shared, can't generate embed code"
|
||||||
return
|
return
|
||||||
@@ -34,7 +34,7 @@ const embed_iframe = (file: FSNode, options: NodeOptions) => {
|
|||||||
|
|
||||||
let example = $state(false)
|
let example = $state(false)
|
||||||
const toggle_example = () => {
|
const toggle_example = () => {
|
||||||
if (node_is_shared(file)) {
|
if (file.is_shared()) {
|
||||||
example = !example
|
example = !example
|
||||||
if (example) {
|
if (example) {
|
||||||
preview_area.innerHTML = embed_html
|
preview_area.innerHTML = embed_html
|
||||||
@@ -86,7 +86,7 @@ run(() => {
|
|||||||
<textarea bind:value={embed_html} style="width: 100%; height: 4em;"></textarea>
|
<textarea bind:value={embed_html} style="width: 100%; height: 4em;"></textarea>
|
||||||
<br/>
|
<br/>
|
||||||
<CopyButton text={embed_html}>Copy HTML</CopyButton>
|
<CopyButton text={embed_html}>Copy HTML</CopyButton>
|
||||||
<button onclick={toggle_example} class:button_highlight={example} disabled={!node_is_shared(file)}>
|
<button onclick={toggle_example} class:button_highlight={example} disabled={!file.is_shared()}>
|
||||||
<i class="icon">visibility</i> Show example
|
<i class="icon">visibility</i> Show example
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { FSNodeProperties } from "lib/FilesystemAPI";
|
import type { FSNodeProperties } from "lib/FilesystemAPI.svelte";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
properties = $bindable({} as FSNodeProperties)
|
properties = $bindable({} as FSNodeProperties)
|
||||||
|
@@ -1,21 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { fs_encode_path, fs_node_icon } from "lib/FilesystemAPI.svelte"
|
||||||
import { fs_encode_path, fs_node_icon, node_is_shared } from "lib/FilesystemAPI"
|
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import { FileAction } from "./FileManagerLib";
|
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
let {
|
let {
|
||||||
nav,
|
nav,
|
||||||
|
file_event,
|
||||||
show_hidden = false,
|
show_hidden = false,
|
||||||
large_icons = false,
|
large_icons = false,
|
||||||
hide_edit = false
|
hide_edit = false
|
||||||
}: {
|
}: {
|
||||||
nav: FSNavigator;
|
nav: FSNavigator;
|
||||||
show_hidden?: boolean;
|
file_event: FileActionHandler
|
||||||
large_icons?: boolean;
|
show_hidden?: boolean
|
||||||
hide_edit?: boolean;
|
large_icons?: boolean
|
||||||
|
hide_edit?: boolean
|
||||||
} = $props();
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -23,8 +22,8 @@ let {
|
|||||||
{#each $nav.children as child, index (child.path)}
|
{#each $nav.children as child, index (child.path)}
|
||||||
<a
|
<a
|
||||||
href={"/d"+fs_encode_path(child.path)}
|
href={"/d"+fs_encode_path(child.path)}
|
||||||
onclick={e => dispatch("file", {index: index, action: FileAction.Click, original: e})}
|
onclick={e => file_event(FileAction.Click, index, e)}
|
||||||
oncontextmenu={e => dispatch("file", {index: index, action: FileAction.Context, original: e})}
|
oncontextmenu={e => file_event(FileAction.Context, index, e)}
|
||||||
class="node"
|
class="node"
|
||||||
class:node_selected={child.fm_selected}
|
class:node_selected={child.fm_selected}
|
||||||
class:hidden={child.name.startsWith(".") && !show_hidden}
|
class:hidden={child.name.startsWith(".") && !show_hidden}
|
||||||
@@ -34,14 +33,14 @@ let {
|
|||||||
{child.name}
|
{child.name}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if node_is_shared(child)}
|
{#if child.is_shared()}
|
||||||
<i class="icon" title="This file / directory is shared. Click to open public link">share</i>
|
<i class="icon" title="This file / directory is shared. Click to open public link">share</i>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if !hide_edit}
|
{#if !hide_edit}
|
||||||
<button
|
<button
|
||||||
class="action_button flat"
|
class="action_button flat"
|
||||||
onclick={e => dispatch("file", {index: index, action: FileAction.Menu, original: e})}
|
onclick={e => file_event(FileAction.Menu, index, e)}
|
||||||
>
|
>
|
||||||
<i class="icon">menu</i>
|
<i class="icon">menu</i>
|
||||||
</button>
|
</button>
|
||||||
@@ -66,8 +65,8 @@ let {
|
|||||||
color: var(--body_text-color);
|
color: var(--body_text-color);
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: var(--shaded_background);
|
background: var(--body_background);
|
||||||
backdrop-filter: blur(4px);
|
/* backdrop-filter: blur(4px); */
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { preventDefault } from 'svelte/legacy';
|
import { preventDefault } from 'svelte/legacy';
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { fs_mkdir } from "lib/FilesystemAPI";
|
import { fs_mkdir } from "lib/FilesystemAPI.svelte";
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import { loading_finish, loading_start } from "lib/Loading";
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { run } from 'svelte/legacy';
|
import { run } from 'svelte/legacy';
|
||||||
import { fs_delete_all, fs_download, fs_rename, type FSNode } from "lib/FilesystemAPI"
|
import { fs_delete_all, fs_rename, type FSNode } from "lib/FilesystemAPI.svelte"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import CreateDirectory from "./CreateDirectory.svelte"
|
import CreateDirectory from "./CreateDirectory.svelte"
|
||||||
import ListView from "./ListView.svelte"
|
import ListView from "./ListView.svelte"
|
||||||
@@ -13,7 +13,7 @@ import SearchBar from "./SearchBar.svelte";
|
|||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import FsUploadWidget from "filesystem/upload_widget/FSUploadWidget.svelte";
|
import FsUploadWidget from "filesystem/upload_widget/FSUploadWidget.svelte";
|
||||||
import EditWindow from "filesystem/edit_window/EditWindow.svelte";
|
import EditWindow from "filesystem/edit_window/EditWindow.svelte";
|
||||||
import { FileAction, type FileEvent } from "./FileManagerLib";
|
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||||
import FileMenu from "./FileMenu.svelte";
|
import FileMenu from "./FileMenu.svelte";
|
||||||
import { loading_finish, loading_start } from "lib/Loading";
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
|
|
||||||
@@ -43,13 +43,12 @@ export const upload = (files: File[]) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Navigation functions
|
// Navigation functions
|
||||||
const file_event = (e: CustomEvent<FileEvent>) => {
|
const file_event: FileActionHandler = (action: FileAction, index: number, orig: Event) => {
|
||||||
const index = e.detail.index
|
orig.preventDefault()
|
||||||
|
orig.stopPropagation()
|
||||||
|
|
||||||
switch (e.detail.action) {
|
switch (action) {
|
||||||
case FileAction.Click:
|
case FileAction.Click:
|
||||||
e.detail.original.preventDefault()
|
|
||||||
e.detail.original.stopPropagation()
|
|
||||||
creating_dir = false
|
creating_dir = false
|
||||||
|
|
||||||
if (mode === "viewing") {
|
if (mode === "viewing") {
|
||||||
@@ -68,40 +67,26 @@ const file_event = (e: CustomEvent<FileEvent>) => {
|
|||||||
case FileAction.Context:
|
case FileAction.Context:
|
||||||
// If this is a touch event we will select the item
|
// If this is a touch event we will select the item
|
||||||
if (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) {
|
if (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) {
|
||||||
e.detail.original.preventDefault()
|
|
||||||
select_node(index)
|
select_node(index)
|
||||||
|
} else {
|
||||||
|
file_menu.open(nav.children[index], orig.target)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case FileAction.Edit:
|
case FileAction.Edit:
|
||||||
e.detail.original.preventDefault()
|
|
||||||
e.detail.original.stopPropagation()
|
|
||||||
edit_window.edit(nav.children[index], false, "file")
|
edit_window.edit(nav.children[index], false, "file")
|
||||||
break
|
break
|
||||||
case FileAction.Share:
|
case FileAction.Share:
|
||||||
e.detail.original.preventDefault()
|
|
||||||
e.detail.original.stopPropagation()
|
|
||||||
creating_dir = false
|
creating_dir = false
|
||||||
edit_window.edit(nav.children[index], false, "share")
|
edit_window.edit(nav.children[index], false, "share")
|
||||||
break
|
break
|
||||||
case FileAction.Branding:
|
case FileAction.Branding:
|
||||||
e.detail.original.preventDefault()
|
|
||||||
e.detail.original.stopPropagation()
|
|
||||||
edit_window.edit(nav.children[index], false, "branding")
|
edit_window.edit(nav.children[index], false, "branding")
|
||||||
break
|
break
|
||||||
case FileAction.Select:
|
case FileAction.Select:
|
||||||
e.detail.original.preventDefault()
|
|
||||||
e.detail.original.stopPropagation()
|
|
||||||
select_node(index)
|
select_node(index)
|
||||||
break
|
break
|
||||||
case FileAction.Download:
|
|
||||||
e.detail.original.preventDefault()
|
|
||||||
e.detail.original.stopPropagation()
|
|
||||||
fs_download(nav.children[index])
|
|
||||||
break
|
|
||||||
case FileAction.Menu:
|
case FileAction.Menu:
|
||||||
e.detail.original.preventDefault()
|
file_menu.open(nav.children[index], orig.target)
|
||||||
e.detail.original.stopPropagation()
|
|
||||||
file_menu.open(nav.children[index], e.detail.original.target)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,11 +408,11 @@ run(() => {
|
|||||||
{@render children?.()}
|
{@render children?.()}
|
||||||
|
|
||||||
{#if directory_view === "list"}
|
{#if directory_view === "list"}
|
||||||
<ListView nav={nav} show_hidden={show_hidden} large_icons={large_icons} on:file={file_event} />
|
<ListView nav={nav} file_event={file_event} show_hidden={show_hidden} large_icons={large_icons}/>
|
||||||
{:else if directory_view === "gallery"}
|
{:else if directory_view === "gallery"}
|
||||||
<GalleryView nav={nav} show_hidden={show_hidden} large_icons={large_icons} on:file={file_event} />
|
<GalleryView nav={nav} file_event={file_event} show_hidden={show_hidden} large_icons={large_icons}/>
|
||||||
{:else if directory_view === "compact"}
|
{:else if directory_view === "compact"}
|
||||||
<CompactView nav={nav} show_hidden={show_hidden} large_icons={large_icons} on:file={file_event} />
|
<CompactView nav={nav} file_event={file_event} show_hidden={show_hidden} large_icons={large_icons}/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -447,8 +432,8 @@ run(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background: var(--shaded_background);
|
background: var(--body_background);
|
||||||
backdrop-filter: blur(4px);
|
/* backdrop-filter: blur(4px); */
|
||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -3,4 +3,18 @@ export type FileEvent = {
|
|||||||
action: FileAction,
|
action: FileAction,
|
||||||
original: MouseEvent,
|
original: MouseEvent,
|
||||||
}
|
}
|
||||||
export enum FileAction { Click, Context, Edit, Share, Branding, Select, Download, Menu }
|
export enum FileAction {
|
||||||
|
Click,
|
||||||
|
Context,
|
||||||
|
Edit,
|
||||||
|
Share,
|
||||||
|
Branding,
|
||||||
|
Select,
|
||||||
|
Download,
|
||||||
|
Menu,
|
||||||
|
}
|
||||||
|
export type FileActionHandler = (
|
||||||
|
action: FileAction,
|
||||||
|
file_index: number,
|
||||||
|
original_event: Event,
|
||||||
|
) => void
|
||||||
|
@@ -4,7 +4,8 @@ import type { FSNavigator } from "filesystem/FSNavigator";
|
|||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import Dialog from "layout/Dialog.svelte";
|
import Dialog from "layout/Dialog.svelte";
|
||||||
import { bookmark_add, bookmark_del, bookmarks_store, is_bookmark } from "lib/Bookmarks";
|
import { bookmark_add, bookmark_del, bookmarks_store, is_bookmark } from "lib/Bookmarks";
|
||||||
import { fs_download, type FSNode } from "lib/FilesystemAPI";
|
import { fs_delete, fs_download, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||||
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -20,10 +21,26 @@ let node: FSNode = $state(null)
|
|||||||
|
|
||||||
export const open = async (n: FSNode, target: EventTarget) => {
|
export const open = async (n: FSNode, target: EventTarget) => {
|
||||||
node = n
|
node = n
|
||||||
|
let el: HTMLElement = (target as Element).closest("button")
|
||||||
|
if (el === null) {
|
||||||
|
el = (target as Element).closest("a")
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for the view to update, so the dialog gets the proper measurements
|
// Wait for the view to update, so the dialog gets the proper measurements
|
||||||
await tick()
|
await tick()
|
||||||
dialog.open((target as Element).closest("button").getBoundingClientRect())
|
dialog.open(el.getBoundingClientRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
const delete_node = async () => {
|
||||||
|
try {
|
||||||
|
loading_start()
|
||||||
|
await fs_delete(node.path)
|
||||||
|
nav.reload()
|
||||||
|
} catch (err) {
|
||||||
|
alert(JSON.stringify(err))
|
||||||
|
} finally {
|
||||||
|
loading_finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -36,6 +53,7 @@ export const open = async (n: FSNode, target: EventTarget) => {
|
|||||||
<Button click={() => {dialog.close(); bookmark_add(node)}} icon="bookmark_add" label="Add bookmark"/>
|
<Button click={() => {dialog.close(); bookmark_add(node)}} icon="bookmark_add" label="Add bookmark"/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $nav.permissions.write}
|
{#if $nav.permissions.write}
|
||||||
|
<Button click={() => {dialog.close(); delete_node()}} icon="delete" label="Delete"/>
|
||||||
<Button click={() => {dialog.close(); edit_window.edit(node, false, "file")}} icon="edit" label="Edit"/>
|
<Button click={() => {dialog.close(); edit_window.edit(node, false, "file")}} icon="edit" label="Edit"/>
|
||||||
<Button click={() => {dialog.close(); edit_window.edit(node, false, "share")}} icon="share" label="Share"/>
|
<Button click={() => {dialog.close(); edit_window.edit(node, false, "share")}} icon="share" label="Share"/>
|
||||||
<Button click={() => {dialog.close(); edit_window.edit(node, false, "branding")}} icon="palette" label="Branding"/>
|
<Button click={() => {dialog.close(); edit_window.edit(node, false, "branding")}} icon="palette" label="Branding"/>
|
||||||
|
@@ -6,8 +6,8 @@ import CompactView from "./CompactView.svelte"
|
|||||||
import Modal from "util/Modal.svelte";
|
import Modal from "util/Modal.svelte";
|
||||||
import Breadcrumbs from "filesystem/Breadcrumbs.svelte"
|
import Breadcrumbs from "filesystem/Breadcrumbs.svelte"
|
||||||
import { FSNavigator } from "filesystem/FSNavigator";
|
import { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import type { FSNode } from "lib/FilesystemAPI";
|
import type { FSNode } from "lib/FilesystemAPI.svelte";
|
||||||
import { FileAction, type FileEvent } from "./FileManagerLib";
|
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||||
|
|
||||||
let nav = $state(new FSNavigator(false))
|
let nav = $state(new FSNavigator(false))
|
||||||
let modal: Modal = $state()
|
let modal: Modal = $state()
|
||||||
@@ -34,12 +34,10 @@ let selected_files = $derived($nav.children.reduce((acc, file) => {
|
|||||||
|
|
||||||
// Navigation functions
|
// Navigation functions
|
||||||
|
|
||||||
const file_event = (e: CustomEvent<FileEvent>) => {
|
const file_event: FileActionHandler = (action: FileAction, index: number, orig: Event) => {
|
||||||
const index = e.detail.index
|
switch (action) {
|
||||||
|
|
||||||
switch (e.detail.action) {
|
|
||||||
case FileAction.Click:
|
case FileAction.Click:
|
||||||
e.detail.original.preventDefault()
|
orig.preventDefault()
|
||||||
if (nav.children[index].type === "dir") {
|
if (nav.children[index].type === "dir") {
|
||||||
nav.navigate(nav.children[index].path, true)
|
nav.navigate(nav.children[index].path, true)
|
||||||
} else {
|
} else {
|
||||||
@@ -49,12 +47,12 @@ const file_event = (e: CustomEvent<FileEvent>) => {
|
|||||||
case FileAction.Context:
|
case FileAction.Context:
|
||||||
// If this is a touch event we will select the item
|
// If this is a touch event we will select the item
|
||||||
if (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) {
|
if (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) {
|
||||||
e.detail.original.preventDefault()
|
orig.preventDefault()
|
||||||
select_node(index)
|
select_node(index)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case FileAction.Select:
|
case FileAction.Select:
|
||||||
e.detail.original.preventDefault()
|
orig.preventDefault()
|
||||||
nav.children[index].fm_selected = !nav.children[index].fm_selected
|
nav.children[index].fm_selected = !nav.children[index].fm_selected
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -134,7 +132,7 @@ onMount(() => {
|
|||||||
<svelte:window onkeydown={detect_shift} onkeyup={detect_shift} />
|
<svelte:window onkeydown={detect_shift} onkeyup={detect_shift} />
|
||||||
|
|
||||||
<Modal bind:this={modal} width="900px">
|
<Modal bind:this={modal} width="900px">
|
||||||
{#snippet title()}
|
{#snippet header()}
|
||||||
<div class="header" >
|
<div class="header" >
|
||||||
<button class="button round" onclick={modal.hide}>
|
<button class="button round" onclick={modal.hide}>
|
||||||
<i class="icon">close</i>
|
<i class="icon">close</i>
|
||||||
@@ -175,26 +173,26 @@ onMount(() => {
|
|||||||
{#if directory_view === "list"}
|
{#if directory_view === "list"}
|
||||||
<ListView
|
<ListView
|
||||||
nav={nav}
|
nav={nav}
|
||||||
|
file_event={file_event}
|
||||||
show_hidden={show_hidden}
|
show_hidden={show_hidden}
|
||||||
large_icons={large_icons}
|
large_icons={large_icons}
|
||||||
hide_edit
|
hide_edit
|
||||||
hide_branding
|
hide_branding
|
||||||
on:file={file_event}
|
|
||||||
/>
|
/>
|
||||||
{:else if directory_view === "gallery"}
|
{:else if directory_view === "gallery"}
|
||||||
<GalleryView
|
<GalleryView
|
||||||
nav={nav}
|
nav={nav}
|
||||||
|
file_event={file_event}
|
||||||
show_hidden={show_hidden}
|
show_hidden={show_hidden}
|
||||||
large_icons={large_icons}
|
large_icons={large_icons}
|
||||||
on:file={file_event}
|
|
||||||
/>
|
/>
|
||||||
{:else if directory_view === "compact"}
|
{:else if directory_view === "compact"}
|
||||||
<CompactView
|
<CompactView
|
||||||
nav={nav}
|
nav={nav}
|
||||||
|
file_event={file_event}
|
||||||
show_hidden={show_hidden}
|
show_hidden={show_hidden}
|
||||||
large_icons={large_icons}
|
large_icons={large_icons}
|
||||||
hide_edit
|
hide_edit
|
||||||
on:file={file_event}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@@ -1,18 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte"
|
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 type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import { FileAction } from "./FileManagerLib";
|
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||||
let dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
let {
|
let {
|
||||||
nav,
|
nav,
|
||||||
|
file_event,
|
||||||
show_hidden = false,
|
show_hidden = false,
|
||||||
large_icons = false
|
large_icons = false
|
||||||
}: {
|
}: {
|
||||||
nav: FSNavigator;
|
nav: FSNavigator
|
||||||
show_hidden?: boolean;
|
file_event: FileActionHandler
|
||||||
large_icons?: boolean;
|
show_hidden?: boolean
|
||||||
|
large_icons?: boolean
|
||||||
} = $props();
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ let {
|
|||||||
{#each $nav.children as child, index (child.path)}
|
{#each $nav.children as child, index (child.path)}
|
||||||
<a class="file"
|
<a class="file"
|
||||||
href={"/d"+fs_encode_path(child.path)}
|
href={"/d"+fs_encode_path(child.path)}
|
||||||
onclick={e => dispatch("file", {index: index, action: FileAction.Click, original: e})}
|
onclick={e => file_event(FileAction.Click, index, e)}
|
||||||
oncontextmenu={e => dispatch("file", {index: index, action: FileAction.Context, original: e})}
|
oncontextmenu={e => file_event(FileAction.Context, index, e)}
|
||||||
class:selected={child.fm_selected}
|
class:selected={child.fm_selected}
|
||||||
class:hidden={child.name.startsWith(".") && !show_hidden}
|
class:hidden={child.name.startsWith(".") && !show_hidden}
|
||||||
class:large_icons
|
class:large_icons
|
||||||
@@ -52,8 +52,8 @@ let {
|
|||||||
width: 150px;
|
width: 150px;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: var(--shaded_background);
|
background: var(--body_background);
|
||||||
backdrop-filter: blur(4px);
|
/* backdrop-filter: blur(4px); */
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: var(--input_text);
|
color: var(--input_text);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -1,25 +1,24 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
|
||||||
import { formatDataVolume } from "util/Formatting";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import { fs_encode_path, fs_node_icon, node_is_shared } from "lib/FilesystemAPI"
|
import { fs_encode_path, fs_node_icon } from "lib/FilesystemAPI.svelte"
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import SortButton from "layout/SortButton.svelte";
|
import SortButton from "layout/SortButton.svelte";
|
||||||
import { FileAction } from "./FileManagerLib";
|
import { FileAction, type FileActionHandler } from "./FileManagerLib";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
let {
|
let {
|
||||||
nav,
|
nav,
|
||||||
|
file_event,
|
||||||
show_hidden = false,
|
show_hidden = false,
|
||||||
large_icons = false,
|
large_icons = false,
|
||||||
hide_edit = false,
|
hide_edit = false,
|
||||||
hide_branding = false
|
hide_branding = false
|
||||||
}: {
|
}: {
|
||||||
nav: FSNavigator;
|
nav: FSNavigator
|
||||||
show_hidden?: boolean;
|
file_event: FileActionHandler
|
||||||
large_icons?: boolean;
|
show_hidden?: boolean
|
||||||
hide_edit?: boolean;
|
large_icons?: boolean
|
||||||
hide_branding?: boolean;
|
hide_edit?: boolean
|
||||||
|
hide_branding?: boolean
|
||||||
} = $props();
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -35,8 +34,8 @@ let {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{#each $nav.children as child, index (child.path)}
|
{#each $nav.children as child, index (child.path)}
|
||||||
<tr
|
<tr
|
||||||
onclick={e => dispatch("file", {index: index, action: FileAction.Click, original: e})}
|
onclick={e => file_event(FileAction.Click, index, e)}
|
||||||
oncontextmenu={e => dispatch("file", {index: index, action: FileAction.Context, original: e})}
|
oncontextmenu={e => file_event(FileAction.Context, index, e)}
|
||||||
class="node"
|
class="node"
|
||||||
class:node_selected={child.fm_selected}
|
class:node_selected={child.fm_selected}
|
||||||
class:hidden={child.name.startsWith(".") && !show_hidden}
|
class:hidden={child.name.startsWith(".") && !show_hidden}
|
||||||
@@ -45,7 +44,7 @@ let {
|
|||||||
<img src={fs_node_icon(child, 64, 64)} class="node_icon" class:large_icons alt="icon"/>
|
<img src={fs_node_icon(child, 64, 64)} class="node_icon" class:large_icons alt="icon"/>
|
||||||
</td>
|
</td>
|
||||||
<td class="node_name">
|
<td class="node_name">
|
||||||
<a href={"/d"+fs_encode_path(child.path)}>
|
<a class="title_link" href={"/d"+fs_encode_path(child.path)}>
|
||||||
{child.name}
|
{child.name}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@@ -58,22 +57,22 @@ let {
|
|||||||
<div class="icons_wrap">
|
<div class="icons_wrap">
|
||||||
{#if child.abuse_type !== undefined}
|
{#if child.abuse_type !== undefined}
|
||||||
<i class="icon" title="This file / directory has received an abuse report. It cannot be shared">block</i>
|
<i class="icon" title="This file / directory has received an abuse report. It cannot be shared">block</i>
|
||||||
{:else if node_is_shared(child)}
|
{:else if child.is_shared()}
|
||||||
<a
|
<a
|
||||||
href="/d/{child.id}"
|
href="/d/{child.id}"
|
||||||
onclick={e => dispatch("file", {index: index, action: FileAction.Share, original: e})}
|
onclick={e => file_event(FileAction.Share, index, e)}
|
||||||
class="button action_button"
|
class="button action_button"
|
||||||
>
|
>
|
||||||
<i class="icon" title="This file / directory is shared. Click to open public link">share</i>
|
<i class="icon" title="This file / directory is shared. Click to open public link">share</i>
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
{#if child.properties !== undefined && child.properties.branding_enabled === "true" && !hide_branding}
|
{#if child.properties !== undefined && child.properties.branding_enabled === "true" && !hide_branding}
|
||||||
<button class="action_button" onclick={e => dispatch("file", {index: index, action: FileAction.Branding, original: e})}>
|
<button class="action_button" onclick={e => file_event(FileAction.Branding, index, e)}>
|
||||||
<i class="icon">palette</i>
|
<i class="icon">palette</i>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if !hide_edit}
|
{#if !hide_edit}
|
||||||
<button class="action_button" onclick={e => dispatch("file", {index: index, action: FileAction.Menu, original: e})}>
|
<button class="action_button" onclick={e => file_event(FileAction.Menu, index, e)}>
|
||||||
<i class="icon">menu</i>
|
<i class="icon">menu</i>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -87,9 +86,9 @@ let {
|
|||||||
<style>
|
<style>
|
||||||
.directory {
|
.directory {
|
||||||
display: table;
|
display: table;
|
||||||
background: var(--shaded_background);
|
background: var(--body_background);
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
backdrop-filter: blur(4px);
|
/* backdrop-filter: blur(4px); */
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: auto; /* center */
|
margin: auto; /* center */
|
||||||
}
|
}
|
||||||
@@ -99,11 +98,14 @@ let {
|
|||||||
.directory > * > * {
|
.directory > * > * {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
}
|
}
|
||||||
|
td {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
.node {
|
.node {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--body_text-color);
|
color: var(--body_text-color);
|
||||||
padding: 6px;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.node:not(:last-child) {
|
.node:not(:last-child) {
|
||||||
border-bottom: 1px solid var(--separator);
|
border-bottom: 1px solid var(--separator);
|
||||||
@@ -118,6 +120,7 @@ let {
|
|||||||
color: var(--highlight_text_color);
|
color: var(--highlight_text_color);
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
|
padding: 2px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.node_icon {
|
.node_icon {
|
||||||
@@ -132,6 +135,10 @@ td {
|
|||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
.title_link {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--body_text_color);
|
||||||
|
}
|
||||||
.node_size {
|
.node_size {
|
||||||
min-width: 5em;
|
min-width: 5em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { preventDefault } from 'svelte/legacy';
|
|
||||||
|
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { fs_search, fs_encode_path, fs_thumbnail_url } from "lib/FilesystemAPI";
|
import { fs_search, fs_encode_path, fs_thumbnail_url } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import { loading_finish, loading_start } from "lib/Loading";
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
|
|
||||||
@@ -118,13 +116,17 @@ const input_keyup = (e: KeyboardEvent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Submitting opens the selected result
|
// Submitting opens the selected result
|
||||||
const submit_search = () => {
|
const submit_search = (e: Event) => {
|
||||||
|
e.preventDefault()
|
||||||
if (search_results.length !== 0) {
|
if (search_results.length !== 0) {
|
||||||
open_result(selected_result)
|
open_result(selected_result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const open_result = (index: number) => {
|
const open_result = (index: number, e?: MouseEvent) => {
|
||||||
|
if (e !== undefined) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
nav.navigate(search_results[index], true)
|
nav.navigate(search_results[index], true)
|
||||||
clear_search(false)
|
clear_search(false)
|
||||||
}
|
}
|
||||||
@@ -164,7 +166,7 @@ const window_keydown = (e: KeyboardEvent) => {
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<form class="search_form" onsubmit={preventDefault(submit_search)}>
|
<form class="search_form" onsubmit={submit_search}>
|
||||||
<i class="icon">search</i>
|
<i class="icon">search</i>
|
||||||
<input
|
<input
|
||||||
bind:this={search_bar}
|
bind:this={search_bar}
|
||||||
@@ -192,7 +194,7 @@ const window_keydown = (e: KeyboardEvent) => {
|
|||||||
{#each search_results as result, index}
|
{#each search_results as result, index}
|
||||||
<a
|
<a
|
||||||
href={"/d"+fs_encode_path(result)}
|
href={"/d"+fs_encode_path(result)}
|
||||||
onclick={preventDefault(() => open_result(index))}
|
onclick={(e) => open_result(index, e)}
|
||||||
class="node"
|
class="node"
|
||||||
class:node_selected={selected_result === index}
|
class:node_selected={selected_result === index}
|
||||||
>
|
>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
//
|
//
|
||||||
// on_error is called when the upload has failed. The parameters are the error
|
// on_error is called when the upload has failed. The parameters are the error
|
||||||
|
|
||||||
import { fs_path_url, type GenericResponse } from "lib/FilesystemAPI"
|
import { fs_path_url, type GenericResponse } from "lib/FilesystemAPI.svelte"
|
||||||
|
|
||||||
// code and an error message
|
// code and an error message
|
||||||
export const upload_file = (
|
export const upload_file = (
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { preventDefault } from 'svelte/legacy';
|
import { preventDefault } from 'svelte/legacy';
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { fs_path_url, fs_encode_path, fs_node_icon } from "lib/FilesystemAPI"
|
import { fs_path_url, fs_encode_path, fs_node_icon } from "lib/FilesystemAPI.svelte"
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
import type { FSNavigator } from 'filesystem/FSNavigator';
|
import type { FSNavigator } from 'filesystem/FSNavigator';
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { FSNode } from 'lib/FilesystemAPI';
|
import type { FSNode } from 'lib/FilesystemAPI.svelte';
|
||||||
import { run } from 'svelte/legacy';
|
import { run } from 'svelte/legacy';
|
||||||
|
|
||||||
let { path = [] }: {path: FSNode[]} = $props();
|
let { path = [] }: {path: FSNode[]} = $props();
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import IconBlock from "layout/IconBlock.svelte";
|
import IconBlock from "layout/IconBlock.svelte";
|
||||||
import { fs_thumbnail_url } from "lib/FilesystemAPI";
|
import { fs_thumbnail_url } from "lib/FilesystemAPI.svelte";
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
import { formatDataVolume, formatDate } from "util/Formatting";
|
import { formatDataVolume, formatDate } from "util/Formatting";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, tick } from "svelte";
|
import { onMount, tick } from "svelte";
|
||||||
import Spinner from "util/Spinner.svelte";
|
import Spinner from "util/Spinner.svelte";
|
||||||
import { fs_node_type } from "lib/FilesystemAPI";
|
import { fs_node_type } from "lib/FilesystemAPI.svelte";
|
||||||
import FileManager from "filesystem/filemanager/FileManager.svelte";
|
import FileManager from "filesystem/filemanager/FileManager.svelte";
|
||||||
import Audio from "./Audio.svelte";
|
import Audio from "./Audio.svelte";
|
||||||
import File from "./File.svelte";
|
import File from "./File.svelte";
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { swipe_nav } from "lib/SwipeNavigate";
|
import { swipe_nav } from "lib/SwipeNavigate";
|
||||||
import { fs_path_url } from "lib/FilesystemAPI";
|
import { fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher();
|
let dispatch = createEventDispatcher();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fs_path_url } from "lib/FilesystemAPI";
|
import { fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let { nav }: {
|
let { nav }: {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import { fs_path_url, type FSNode } from "lib/FilesystemAPI";
|
import { fs_path_url, type FSNode } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let { nav, children }: {
|
let { nav, children }: {
|
||||||
|
@@ -19,7 +19,7 @@ import { formatDate } from "util/Formatting"
|
|||||||
import TorrentItem from "./TorrentItem.svelte"
|
import TorrentItem from "./TorrentItem.svelte"
|
||||||
import IconBlock from "layout/IconBlock.svelte";
|
import IconBlock from "layout/IconBlock.svelte";
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
import { fs_node_icon, fs_path_url } from "lib/FilesystemAPI";
|
import { fs_node_icon, fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import { loading_finish, loading_start } from "lib/Loading";
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, createEventDispatcher, tick } from "svelte";
|
import { onMount, createEventDispatcher, tick } from "svelte";
|
||||||
import { video_position } from "lib/VideoPosition";
|
import { video_position } from "lib/VideoPosition";
|
||||||
import { fs_path_url } from "lib/FilesystemAPI";
|
import { fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ import { formatDataVolume, formatDate } from "util/Formatting"
|
|||||||
import ZipItem from "filesystem/viewers/ZipItem.svelte";
|
import ZipItem from "filesystem/viewers/ZipItem.svelte";
|
||||||
import IconBlock from "layout/IconBlock.svelte";
|
import IconBlock from "layout/IconBlock.svelte";
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
import { fs_node_icon, fs_path_url } from "lib/FilesystemAPI";
|
import { fs_node_icon, fs_path_url } from "lib/FilesystemAPI.svelte";
|
||||||
import type { FSNavigator } from "filesystem/FSNavigator";
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
import { loading_finish, loading_start } from "lib/Loading";
|
import { loading_finish, loading_start } from "lib/Loading";
|
||||||
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
let { style = "" }: {
|
let {
|
||||||
style: string;
|
style = ""
|
||||||
|
}: {
|
||||||
|
style?: string;
|
||||||
} = $props();
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import { fs_check_response, fs_path_url, type FSNode } from "./FilesystemAPI"
|
import { fs_check_response, fs_path_url, type FSNode } from "./FilesystemAPI.svelte"
|
||||||
import { loading_finish, loading_start } from "lib/Loading"
|
import { loading_finish, loading_start } from "lib/Loading"
|
||||||
import { get_user } from "./PixeldrainAPI"
|
import { get_user } from "lib/PixeldrainAPI"
|
||||||
|
|
||||||
const bookmarks_file = "/me/.fnx/bookmarks.json"
|
const bookmarks_file = "/me/.fnx/bookmarks.json"
|
||||||
|
|
||||||
|
@@ -6,15 +6,24 @@ export type GenericResponse = {
|
|||||||
message: string,
|
message: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FSPath = {
|
export class FSPath {
|
||||||
path: Array<FSNode>,
|
path: Array<FSNode>
|
||||||
base_index: number,
|
base_index: number
|
||||||
children: Array<FSNode>,
|
children: Array<FSNode>
|
||||||
permissions: FSPermissions,
|
permissions: FSPermissions
|
||||||
context: FSContext,
|
context: FSContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FSNode = {
|
export const path_is_shared = (path: FSNode[]): boolean => {
|
||||||
|
for (let i = 0; i < path.length; i++) {
|
||||||
|
if (path[i].is_shared()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FSNode {
|
||||||
type: string
|
type: string
|
||||||
path: string
|
path: string
|
||||||
name: string
|
name: string
|
||||||
@@ -42,26 +51,13 @@ export type FSNode = {
|
|||||||
// Added by us
|
// Added by us
|
||||||
|
|
||||||
// Indicates whether the file is selected in the file manager
|
// Indicates whether the file is selected in the file manager
|
||||||
fm_selected?: boolean
|
fm_selected?: boolean = $state(false)
|
||||||
}
|
|
||||||
|
|
||||||
export const node_is_shared = (node: FSNode): boolean => {
|
is_shared = (): boolean => {
|
||||||
if (
|
return (this.link_permissions !== undefined && this.link_permissions.read === true) ||
|
||||||
(node.link_permissions !== undefined && node.link_permissions.read === true) ||
|
(this.user_permissions !== undefined && Object.keys(this.user_permissions).length > 0) ||
|
||||||
(node.user_permissions !== undefined && Object.keys(node.user_permissions).length > 0) ||
|
(this.password_permissions !== undefined && Object.keys(this.password_permissions).length > 0)
|
||||||
(node.password_permissions !== undefined && Object.keys(node.password_permissions).length > 0)
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
|
||||||
export const path_is_shared = (path: FSNode[]): boolean => {
|
|
||||||
for (let i = 0; i < path.length; i++) {
|
|
||||||
if (node_is_shared(path[i])) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FSNodeProperties = {
|
export type FSNodeProperties = {
|
||||||
@@ -143,9 +139,23 @@ export const fs_mkdirall = async (path: string, opts: NodeOptions) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const fs_get_node = async (path: string) => {
|
export const fs_get_node = async (path: string) => {
|
||||||
return await fs_check_response(
|
const resp = await fs_check_response(
|
||||||
await fetch(fs_path_url(path) + "?stat")
|
await fetch(fs_path_url(path) + "?stat")
|
||||||
) as FSPath
|
) as FSPath
|
||||||
|
|
||||||
|
const fsp = new FSPath()
|
||||||
|
fsp.path = new Array(resp.path.length)
|
||||||
|
resp.path.forEach((node, index) => {
|
||||||
|
fsp.path[index] = Object.assign(new FSNode(), node)
|
||||||
|
})
|
||||||
|
fsp.base_index = resp.base_index
|
||||||
|
fsp.children = new Array(resp.children.length)
|
||||||
|
resp.children.forEach((node, index) => {
|
||||||
|
fsp.children[index] = Object.assign(new FSNode(), node)
|
||||||
|
})
|
||||||
|
fsp.permissions = resp.permissions
|
||||||
|
fsp.context = resp.context
|
||||||
|
return fsp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates a node's parameters. Available options are:
|
// Updates a node's parameters. Available options are:
|
||||||
@@ -171,9 +181,10 @@ export const fs_update = async (path: string, opts: NodeOptions) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await fs_check_response(
|
const resp = await fs_check_response(
|
||||||
await fetch(fs_path_url(path), { method: "POST", body: form })
|
await fetch(fs_path_url(path), { method: "POST", body: form })
|
||||||
) as FSNode
|
)
|
||||||
|
return Object.assign(new FSNode(), resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fs_rename = async (old_path: string, new_path: string) => {
|
export const fs_rename = async (old_path: string, new_path: string) => {
|
||||||
@@ -181,9 +192,10 @@ export const fs_rename = async (old_path: string, new_path: string) => {
|
|||||||
form.append("action", "rename")
|
form.append("action", "rename")
|
||||||
form.append("target", new_path)
|
form.append("target", new_path)
|
||||||
|
|
||||||
return await fs_check_response(
|
const resp = await fs_check_response(
|
||||||
await fetch(fs_path_url(old_path), { method: "POST", body: form })
|
await fetch(fs_path_url(old_path), { method: "POST", body: form })
|
||||||
) as FSNode
|
)
|
||||||
|
return Object.assign(new FSNode(), resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fs_delete = async (path: string) => {
|
export const fs_delete = async (path: string) => {
|
||||||
@@ -334,7 +346,7 @@ export const fs_node_type = (node: FSNode) => {
|
|||||||
export const fs_node_icon = (node: FSNode, width = 64, height = 64) => {
|
export const fs_node_icon = (node: FSNode, width = 64, height = 64) => {
|
||||||
if (node.type === "dir") {
|
if (node.type === "dir") {
|
||||||
// Folders with an ID are publically shared, use the shared folder icon
|
// Folders with an ID are publically shared, use the shared folder icon
|
||||||
if (node_is_shared(node)) {
|
if (node.is_shared()) {
|
||||||
return "/res/img/mime/folder-remote.png"
|
return "/res/img/mime/folder-remote.png"
|
||||||
} else {
|
} else {
|
||||||
return "/res/img/mime/folder.png"
|
return "/res/img/mime/folder.png"
|
||||||
@@ -372,7 +384,7 @@ export const fs_share_path = (path: FSNode[]): string => {
|
|||||||
|
|
||||||
// Find the last node in the path that has a public ID
|
// Find the last node in the path that has a public ID
|
||||||
for (let i = path.length - 1; i >= 0; i--) {
|
for (let i = path.length - 1; i >= 0; i--) {
|
||||||
if (node_is_shared(path[i])) {
|
if (path[i].is_shared()) {
|
||||||
bucket_idx = i
|
bucket_idx = i
|
||||||
break
|
break
|
||||||
}
|
}
|
@@ -20,21 +20,21 @@ let {
|
|||||||
padding = false,
|
padding = false,
|
||||||
visible = $bindable(false),
|
visible = $bindable(false),
|
||||||
style = "",
|
style = "",
|
||||||
title_slot,
|
header,
|
||||||
children
|
children
|
||||||
}: {
|
}: {
|
||||||
// Form can be used to turn the modal into a save dialog. Enter the ID of a
|
// Form can be used to turn the modal into a save dialog. Enter the ID of a
|
||||||
// form inside the modal and the modal will provide a submit button for that
|
// form inside the modal and the modal will provide a submit button for that
|
||||||
// form
|
// form
|
||||||
form: string,
|
form?: string,
|
||||||
title: string,
|
title?: string,
|
||||||
width: string,
|
width?: string,
|
||||||
height: string,
|
height?: string,
|
||||||
padding: boolean,
|
padding?: boolean,
|
||||||
visible: boolean,
|
visible?: boolean,
|
||||||
style: string,
|
style?: string,
|
||||||
title_slot: Snippet,
|
header?: Snippet,
|
||||||
children: Snippet,
|
children?: Snippet,
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
const load_bg = background => {
|
const load_bg = background => {
|
||||||
@@ -91,7 +91,7 @@ const keydown = (e: KeyboardEvent) => {
|
|||||||
onkeydown={keydown}
|
onkeydown={keydown}
|
||||||
>
|
>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{#if title_slot}{@render title_slot()}{:else}
|
{#if header}{@render header()}{:else}
|
||||||
{#if form !== ""}
|
{#if form !== ""}
|
||||||
<Button round click={hide} icon="close"/>
|
<Button round click={hide} icon="close"/>
|
||||||
<span class="title">{title}</span>
|
<span class="title">{title}</span>
|
||||||
|
@@ -1,22 +1,50 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { bookmark_del, bookmarks_store } from "lib/Bookmarks";
|
import { bookmark_del, bookmarks_store } from "lib/Bookmarks";
|
||||||
import { fs_encode_path } from "lib/FilesystemAPI";
|
import { fs_encode_path } from "lib/FilesystemAPI.svelte";
|
||||||
import { highlight_current_page } from "lib/HighlightCurrentPage";
|
import { highlight_current_page } from "lib/HighlightCurrentPage";
|
||||||
|
|
||||||
|
let editing = $state(false)
|
||||||
|
|
||||||
|
const toggle_edit = () => {
|
||||||
|
editing = !editing
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="title">
|
||||||
|
<div class="hide_small">Bookmarks</div>
|
||||||
|
<button onclick={() => toggle_edit()} class:button_highlight={editing}>
|
||||||
|
<i class="icon">edit</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#each $bookmarks_store as bookmark}
|
{#each $bookmarks_store as bookmark}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<a class="button" href="/d{fs_encode_path(bookmark.path)}" use:highlight_current_page>
|
<a class="button" href="/d{fs_encode_path(bookmark.path)}" use:highlight_current_page>
|
||||||
<i class="icon">{bookmark.icon}</i>
|
<i class="icon">{bookmark.icon}</i>
|
||||||
<span class="hide_small">{bookmark.label}</span>
|
<span class="hide_small">{bookmark.label}</span>
|
||||||
</a>
|
</a>
|
||||||
<button onclick={() => bookmark_del(bookmark.id)}>
|
{#if editing}
|
||||||
<i class="icon">delete</i>
|
<button onclick={() => bookmark_del(bookmark.id)}>
|
||||||
</button>
|
<i class="icon">delete</i>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid var(--separator);
|
||||||
|
}
|
||||||
|
.title > div {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.title > button {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
.row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@@ -6,7 +6,7 @@ import { formatDataVolume } from "util/Formatting";
|
|||||||
import Router from "wrap/Router.svelte";
|
import Router from "wrap/Router.svelte";
|
||||||
import Bookmarks from "./Bookmarks.svelte";
|
import Bookmarks from "./Bookmarks.svelte";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { fs_get_node } from "lib/FilesystemAPI";
|
import { fs_get_node } from "lib/FilesystemAPI.svelte";
|
||||||
import { css_from_path } from "filesystem/edit_window/Branding";
|
import { css_from_path } from "filesystem/edit_window/Branding";
|
||||||
import { loading_run, loading_store } from "lib/Loading";
|
import { loading_run, loading_store } from "lib/Loading";
|
||||||
import Spinner from "util/Spinner.svelte";
|
import Spinner from "util/Spinner.svelte";
|
||||||
@@ -25,82 +25,84 @@ onMount(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="nav_container">
|
<div class="nav_container">
|
||||||
<nav class="nav">
|
<div class="scroll_container">
|
||||||
<a class="button" href="/" use:highlight_current_page>
|
<nav class="nav">
|
||||||
<i class="icon">home</i>
|
<a class="button" href="/" use:highlight_current_page>
|
||||||
<span class="hide_small">Home</span>
|
<i class="icon">home</i>
|
||||||
</a>
|
<span class="hide_small">Home</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
{#if $user.username !== undefined && $user.username !== ""}
|
{#if $user.username !== undefined && $user.username !== ""}
|
||||||
<div class="separator hide_small"></div>
|
<div class="separator hide_small"></div>
|
||||||
|
|
||||||
<div class="username hide_small">
|
<div class="username hide_small">
|
||||||
{$user.username}
|
{$user.username}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div class="stats_table hide_small">
|
||||||
|
<div>Subscription</div>
|
||||||
|
<div>{$user.subscription.name}</div>
|
||||||
|
|
||||||
|
{#if $user.subscription.type === "prepaid"}
|
||||||
|
<div>Credit</div>
|
||||||
|
<div><Euro amount={$user.balance_micro_eur}/></div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div>Storage used</div>
|
||||||
|
<div>{formatDataVolume($user.filesystem_storage_used, 3)}</div>
|
||||||
|
<div>Transfer used</div>
|
||||||
|
<div>{formatDataVolume($user.monthly_transfer_used, 3)}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator hide_small"></div>
|
||||||
|
|
||||||
|
<a class="button" href="/d/me" use:highlight_current_page>
|
||||||
|
<i class="icon">folder</i>
|
||||||
|
<span class="hide_small">Filesystem</span>
|
||||||
|
</a>
|
||||||
|
<a class="button" href="/user" use:highlight_current_page>
|
||||||
|
<i class="icon">dashboard</i>
|
||||||
|
<span class="hide_small">Dashboard</span>
|
||||||
|
</a>
|
||||||
|
{#if $user.is_admin}
|
||||||
|
<a class="button" href="/admin" use:highlight_current_page>
|
||||||
|
<i class="icon">admin_panel_settings</i>
|
||||||
|
<span class="hide_small">Admin Panel</span>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
<button class="button" onclick={()=> logout_user("/")}>
|
||||||
|
<i class="icon">logout</i>
|
||||||
|
<span class="hide_small">Log out</span>
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<a class="button" href="/login" use:highlight_current_page>
|
||||||
|
<i class="icon">login</i>
|
||||||
|
<span class="hide_small">Login</span>
|
||||||
|
</a>
|
||||||
|
<a class="button" href="/register" use:highlight_current_page>
|
||||||
|
<i class="icon">how_to_reg</i>
|
||||||
|
<span class="hide_small">Register</span>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="stats_table hide_small">
|
<a class="button" href="/speedtest" use:highlight_current_page>
|
||||||
<div>Subscription</div>
|
<i class="icon">speed</i>
|
||||||
<div>{$user.subscription.name}</div>
|
<span class="hide_small">Speedtest</span>
|
||||||
|
|
||||||
{#if $user.subscription.type === "prepaid"}
|
|
||||||
<div>Credit</div>
|
|
||||||
<div><Euro amount={$user.balance_micro_eur}/></div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div>Storage used</div>
|
|
||||||
<div>{formatDataVolume($user.filesystem_storage_used, 3)}</div>
|
|
||||||
<div>Transfer used</div>
|
|
||||||
<div>{formatDataVolume($user.monthly_transfer_used, 3)}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator hide_small"></div>
|
|
||||||
|
|
||||||
<a class="button" href="/d/me" use:highlight_current_page>
|
|
||||||
<i class="icon">folder</i>
|
|
||||||
<span class="hide_small">Filesystem</span>
|
|
||||||
</a>
|
</a>
|
||||||
<a class="button" href="/user" use:highlight_current_page>
|
<a class="button" href="/appearance" use:highlight_current_page>
|
||||||
<i class="icon">dashboard</i>
|
<i class="icon">palette</i>
|
||||||
<span class="hide_small">Dashboard</span>
|
<span class="hide_small">Themes</span>
|
||||||
</a>
|
</a>
|
||||||
{#if $user.is_admin}
|
|
||||||
<a class="button" href="/admin" use:highlight_current_page>
|
|
||||||
<i class="icon">admin_panel_settings</i>
|
|
||||||
<span class="hide_small">Admin Panel</span>
|
|
||||||
</a>
|
|
||||||
{/if}
|
|
||||||
<button class="button" onclick={()=> logout_user("/")}>
|
|
||||||
<i class="icon">logout</i>
|
|
||||||
<span class="hide_small">Log out</span>
|
|
||||||
</button>
|
|
||||||
{:else}
|
|
||||||
<a class="button" href="/login" use:highlight_current_page>
|
|
||||||
<i class="icon">login</i>
|
|
||||||
<span class="hide_small">Login</span>
|
|
||||||
</a>
|
|
||||||
<a class="button" href="/register" use:highlight_current_page>
|
|
||||||
<i class="icon">how_to_reg</i>
|
|
||||||
<span class="hide_small">Register</span>
|
|
||||||
</a>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<a class="button" href="/speedtest" use:highlight_current_page>
|
<Bookmarks/>
|
||||||
<i class="icon">speed</i>
|
</nav>
|
||||||
<span class="hide_small">Speedtest</span>
|
</div>
|
||||||
</a>
|
|
||||||
<a class="button" href="/appearance" use:highlight_current_page>
|
|
||||||
<i class="icon">palette</i>
|
|
||||||
<span class="hide_small">Themes</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<Bookmarks/>
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
@@ -133,13 +135,17 @@ onMount(async () => {
|
|||||||
background: var(--shaded_background);
|
background: var(--shaded_background);
|
||||||
backdrop-filter: blur(4px);
|
backdrop-filter: blur(4px);
|
||||||
}
|
}
|
||||||
|
.scroll_container {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
max-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
.nav {
|
.nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: 15em;
|
max-width: 15em;
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.nav > .button {
|
.nav > .button {
|
||||||
background: none;
|
background: none;
|
||||||
@@ -165,7 +171,7 @@ onMount(async () => {
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto;
|
grid-template-columns: auto auto;
|
||||||
gap: 0.2em 1em;
|
gap: 0.2em 1em;
|
||||||
margin: 3px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media(max-width: 1000px) {
|
@media(max-width: 1000px) {
|
||||||
|
Reference in New Issue
Block a user