Convert the whole filesystem UI to Typescript
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import svelte from 'rollup-plugin-svelte';
|
import svelte from 'rollup-plugin-svelte';
|
||||||
import resolve, { nodeResolve } from '@rollup/plugin-node-resolve';
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
import commonjs from '@rollup/plugin-commonjs';
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
import livereload from 'rollup-plugin-livereload';
|
import livereload from 'rollup-plugin-livereload';
|
||||||
import terser from '@rollup/plugin-terser';
|
import terser from '@rollup/plugin-terser';
|
||||||
@@ -52,13 +52,10 @@ export default [
|
|||||||
resolve({
|
resolve({
|
||||||
browser: true,
|
browser: true,
|
||||||
exportConditions: ['svelte'],
|
exportConditions: ['svelte'],
|
||||||
extensions: ['.svelte'],
|
modulePaths: [process.cwd() + "/src", process.cwd() + "/node_modules"],
|
||||||
|
extensions: [".svelte", ".mjs", ".js", ".json", ".mts", ".ts"],
|
||||||
}),
|
}),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
nodeResolve({
|
|
||||||
modulePaths: [process.cwd() + "/src"],
|
|
||||||
extensions: [".svelte", ".mjs", ".js", ".json"]
|
|
||||||
}),
|
|
||||||
typescript(),
|
typescript(),
|
||||||
|
|
||||||
// Watch the `public` directory and refresh the browser on changes when
|
// Watch the `public` directory and refresh the browser on changes when
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDate, formatNumber } from "util/Formatting.svelte";
|
import { formatDate, formatNumber } from "util/Formatting";
|
||||||
import Expandable from "util/Expandable.svelte";
|
import Expandable from "util/Expandable.svelte";
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import Modal from "util/Modal.svelte"
|
import Modal from "util/Modal.svelte"
|
||||||
import SortButton from "./SortButton.svelte";
|
import SortButton from "./SortButton.svelte";
|
||||||
import { flip } from "svelte/animate";
|
import { flip } from "svelte/animate";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onDestroy, onMount } from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
import { formatDataVolume, formatThousands, formatDate, formatNumber, formatDuration } from "util/Formatting.svelte";
|
import { formatDataVolume, formatThousands, formatDate, formatNumber, formatDuration } from "util/Formatting";
|
||||||
import Chart from "util/Chart.svelte";
|
import Chart from "util/Chart.svelte";
|
||||||
import { color_by_name } from "util/Util.svelte";
|
import { color_by_name } from "util/Util.svelte";
|
||||||
import ServerDiagnostics from "./ServerDiagnostics.svelte";
|
import ServerDiagnostics from "./ServerDiagnostics.svelte";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import Expandable from "util/Expandable.svelte";
|
import Expandable from "util/Expandable.svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import { mollie_proxy_call } from "./MollieAPI.js";
|
import { mollie_proxy_call } from "./MollieAPI";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import Euro from "util/Euro.svelte";
|
import Euro from "util/Euro.svelte";
|
||||||
|
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import Expandable from "util/Expandable.svelte";
|
import Expandable from "util/Expandable.svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import Euro from "util/Euro.svelte";
|
import Euro from "util/Euro.svelte";
|
||||||
import MollieSettlement from "./MollieSettlement.svelte";
|
import MollieSettlement from "./MollieSettlement.svelte";
|
||||||
import { mollie_proxy_call } from "./MollieAPI.js";
|
import { mollie_proxy_call } from "./MollieAPI";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let response = {}
|
let response = {}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import Expandable from "util/Expandable.svelte";
|
import Expandable from "util/Expandable.svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import Euro from "util/Euro.svelte";
|
import Euro from "util/Euro.svelte";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { flip } from "svelte/animate";
|
import { flip } from "svelte/animate";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import SortButton from "./SortButton.svelte";
|
import SortButton from "./SortButton.svelte";
|
||||||
|
|
||||||
export let peers = [];
|
export let peers = [];
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
import { createEventDispatcher, onMount } from "svelte";
|
||||||
import { formatDuration } from "util/Formatting.svelte";
|
import { formatDuration } from "util/Formatting";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let running_since = ""
|
export let running_since = ""
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import Euro from "util/Euro.svelte";
|
import Euro from "util/Euro.svelte";
|
||||||
import { formatDataVolume, formatDate } from "util/Formatting.svelte";
|
import { formatDataVolume, formatDate } from "util/Formatting";
|
||||||
|
|
||||||
export let row = {}
|
export let row = {}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import Expandable from "util/Expandable.svelte";
|
import Expandable from "util/Expandable.svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import Button from "layout/Button.svelte"
|
import Button from "layout/Button.svelte"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import { formatDataVolume, formatDate } from "util/Formatting.svelte";
|
import { formatDataVolume, formatDate } from "util/Formatting";
|
||||||
import SortButton from "admin_panel/SortButton.svelte";
|
import SortButton from "admin_panel/SortButton.svelte";
|
||||||
|
|
||||||
export let user_id = ""
|
export let user_id = ""
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
|
|
||||||
export let user_id = ""
|
export let user_id = ""
|
||||||
let lists = []
|
let lists = []
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDataVolume, formatDate, formatThousands } from "util/Formatting.svelte"
|
import { formatDataVolume, formatDate, formatThousands } from "util/Formatting"
|
||||||
import { color_by_name, domain_url } from "util/Util.svelte";
|
import { color_by_name, domain_url } from "util/Util.svelte";
|
||||||
import Chart from "util/Chart.svelte";
|
import Chart from "util/Chart.svelte";
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher, tick } from "svelte";
|
import { createEventDispatcher, tick } from "svelte";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import DirectoryElement from "user_home/filemanager/DirectoryElement.svelte";
|
import DirectoryElement from "user_home/filemanager/DirectoryElement.svelte";
|
||||||
import Modal from "util/Modal.svelte";
|
import Modal from "util/Modal.svelte";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDataVolume, formatThousands } from "util/Formatting.svelte"
|
import { formatDataVolume, formatThousands } from "util/Formatting"
|
||||||
import { set_file, stats } from "lib/StatsSocket.mjs"
|
import { set_file, stats } from "lib/StatsSocket"
|
||||||
|
|
||||||
export let file = {
|
export let file = {
|
||||||
id: "",
|
id: "",
|
||||||
|
@@ -3,7 +3,7 @@ import { createEventDispatcher } from "svelte"
|
|||||||
import { flip } from "svelte/animate"
|
import { flip } from "svelte/animate"
|
||||||
import FilePicker from "./FilePicker.svelte"
|
import FilePicker from "./FilePicker.svelte"
|
||||||
import { file_type } from "./FileUtilities.svelte";
|
import { file_type } from "./FileUtilities.svelte";
|
||||||
import { get_video_position } from "lib/VideoPosition.mjs"
|
import { get_video_position } from "lib/VideoPosition"
|
||||||
import ProgressBar from "util/ProgressBar.svelte"
|
import ProgressBar from "util/ProgressBar.svelte"
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDataVolume, formatThousands } from "util/Formatting.svelte"
|
import { formatDataVolume, formatThousands } from "util/Formatting"
|
||||||
|
|
||||||
export let list = {
|
export let list = {
|
||||||
files: [],
|
files: [],
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import { stats } from "lib/StatsSocket.mjs"
|
import { stats } from "lib/StatsSocket"
|
||||||
|
|
||||||
let percent = 0
|
let percent = 0
|
||||||
let title = ""
|
let title = ""
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
import ProgressBar from "util/ProgressBar.svelte";
|
import ProgressBar from "util/ProgressBar.svelte";
|
||||||
import { stats } from "lib/StatsSocket.mjs"
|
import { stats } from "lib/StatsSocket"
|
||||||
|
|
||||||
export let file = {
|
export let file = {
|
||||||
size: 0,
|
size: 0,
|
||||||
|
@@ -3,7 +3,7 @@ import { createEventDispatcher } from "svelte";
|
|||||||
import BandwidthUsage from "./BandwidthUsage.svelte";
|
import BandwidthUsage from "./BandwidthUsage.svelte";
|
||||||
import IconBlock from "layout/IconBlock.svelte";
|
import IconBlock from "layout/IconBlock.svelte";
|
||||||
import FileTitle from "layout/FileTitle.svelte";
|
import FileTitle from "layout/FileTitle.svelte";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export const set_file = f => file = f
|
export const set_file = f => file = f
|
||||||
|
@@ -11,7 +11,7 @@ import Abuse from "./Abuse.svelte";
|
|||||||
import { file_type } from "file_viewer/FileUtilities.svelte";
|
import { file_type } from "file_viewer/FileUtilities.svelte";
|
||||||
import RateLimit from "./RateLimit.svelte";
|
import RateLimit from "./RateLimit.svelte";
|
||||||
import Torrent from "./Torrent.svelte";
|
import Torrent from "./Torrent.svelte";
|
||||||
import { stats } from "lib/StatsSocket.mjs"
|
import { stats } from "lib/StatsSocket"
|
||||||
import Zip from "./Zip.svelte";
|
import Zip from "./Zip.svelte";
|
||||||
import SlowDown from "layout/SlowDown.svelte";
|
import SlowDown from "layout/SlowDown.svelte";
|
||||||
import TextBlock from "layout/TextBlock.svelte";
|
import TextBlock from "layout/TextBlock.svelte";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { swipe_nav } from "lib/SwipeNavigate.mjs";
|
import { swipe_nav } from "lib/SwipeNavigate";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export const set_file = f => {
|
export const set_file = f => {
|
||||||
@@ -74,16 +74,19 @@ const on_load = () => dispatch("loading", false)
|
|||||||
bind:this={container}
|
bind:this={container}
|
||||||
class="container"
|
class="container"
|
||||||
class:zoom
|
class:zoom
|
||||||
use:swipe_nav={{enabled: !zoom && is_list, prev: true, next: true}}
|
use:swipe_nav={{
|
||||||
on:prev
|
enabled: !zoom && is_list,
|
||||||
on:next
|
prev: true,
|
||||||
|
next: true,
|
||||||
|
on_prev: () => dispatch("prev"),
|
||||||
|
on_next: () => dispatch("prev"),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
<img
|
<img
|
||||||
on:load={on_load}
|
on:load={on_load}
|
||||||
on:error={on_load}
|
on:error={on_load}
|
||||||
on:dblclick={double_click}
|
on:dblclick={double_click}
|
||||||
on:doubletap={double_click}
|
|
||||||
on:mousedown={mousedown}
|
on:mousedown={mousedown}
|
||||||
class="image"
|
class="image"
|
||||||
class:zoom
|
class:zoom
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import { stats } from "lib/StatsSocket.mjs"
|
import { stats } from "lib/StatsSocket"
|
||||||
import IconBlock from "layout/IconBlock.svelte";
|
import IconBlock from "layout/IconBlock.svelte";
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import Magnet from "icons/Magnet.svelte";
|
import Magnet from "icons/Magnet.svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte"
|
import { formatDate } from "util/Formatting"
|
||||||
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 TorrentItem from "./TorrentItem.svelte"
|
import TorrentItem from "./TorrentItem.svelte"
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
|
|
||||||
export let item = {
|
export let item = {
|
||||||
size: 0,
|
size: 0,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount, createEventDispatcher, tick } from "svelte";
|
import { onMount, createEventDispatcher, tick } from "svelte";
|
||||||
import { video_position } from "lib/VideoPosition.mjs";
|
import { video_position } from "lib/VideoPosition";
|
||||||
import BandwidthUsage from "./BandwidthUsage.svelte";
|
import BandwidthUsage from "./BandwidthUsage.svelte";
|
||||||
import IconBlock from "layout/IconBlock.svelte";
|
import IconBlock from "layout/IconBlock.svelte";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { formatDataVolume, formatDate } from "util/Formatting.svelte"
|
import { formatDataVolume, formatDate } from "util/Formatting"
|
||||||
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 ZipItem from "./ZipItem.svelte";
|
import ZipItem from "./ZipItem.svelte";
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import type { ZipEntry } from "filesystem/viewers/Zip.svelte";
|
||||||
|
import { formatDataVolume } from "util/Formatting";
|
||||||
|
|
||||||
export let item = {
|
export let item: ZipEntry = {} as ZipEntry
|
||||||
download_url: "",
|
|
||||||
size: 0,
|
|
||||||
children: null,
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- First get directories and render them as details collapsibles -->
|
<!-- First get directories and render them as details collapsibles -->
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { fs_encode_path } from "./FilesystemAPI.mjs";
|
import { fs_encode_path } from "./FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="breadcrumbs">
|
<div class="breadcrumbs">
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import Chart from "util/Chart.svelte";
|
import Chart from "util/Chart.svelte";
|
||||||
import { formatDataVolume, formatDate, formatNumber, formatThousands } from "util/Formatting.svelte";
|
import { formatDataVolume, formatDate, formatThousands } from "util/Formatting";
|
||||||
import Modal from "util/Modal.svelte";
|
import Modal from "util/Modal.svelte";
|
||||||
import { fs_path_url, fs_timeseries } from "./FilesystemAPI.mjs";
|
import { fs_path_url, fs_share_path, fs_share_url, fs_timeseries, type FSNode } from "./FilesystemAPI";
|
||||||
import { generate_share_path, generate_share_url } from "./Sharebar.svelte";
|
|
||||||
import { color_by_name } from "util/Util.svelte";
|
import { color_by_name } from "util/Util.svelte";
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let visible = false
|
export let visible = false
|
||||||
export const toggle = () => visible = !visible
|
export const toggle = () => visible = !visible
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ const visibility_change = visible => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$: direct_url = $nav.base.path ? window.location.origin+fs_path_url($nav.base.path) : ""
|
$: direct_url = $nav.base.path ? window.location.origin+fs_path_url($nav.base.path) : ""
|
||||||
$: share_url = generate_share_url($nav.path)
|
$: share_url = fs_share_url($nav.path)
|
||||||
$: direct_share_url = $nav.base.path ? window.location.origin+fs_path_url(generate_share_path($nav.path)) : ""
|
$: direct_share_url = $nav.base.path ? window.location.origin+fs_path_url(fs_share_path($nav.path)) : ""
|
||||||
|
|
||||||
let chart
|
let chart
|
||||||
let chart_timespan = 0
|
let chart_timespan = 0
|
||||||
@@ -40,7 +40,7 @@ let total_downloads = 0
|
|||||||
let total_transfer = 0
|
let total_transfer = 0
|
||||||
|
|
||||||
$: update_chart($nav.base, chart_timespan, chart_interval)
|
$: update_chart($nav.base, chart_timespan, chart_interval)
|
||||||
let update_chart = async (base, timespan, interval) => {
|
let update_chart = async (base: FSNode, timespan: number, interval: number) => {
|
||||||
if (chart === undefined) {
|
if (chart === undefined) {
|
||||||
// Wait for the chart element to render, if it's not rendered already
|
// Wait for the chart element to render, if it's not rendered already
|
||||||
await tick()
|
await tick()
|
||||||
@@ -94,7 +94,6 @@ let update_chart = async (base, timespan, interval) => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resp.downloads.timestamps.forEach((val, idx) => {
|
resp.downloads.timestamps.forEach((val, idx) => {
|
||||||
let date = new Date(val);
|
let date = new Date(val);
|
||||||
let str = ("00" + (date.getMonth() + 1)).slice(-2);
|
let str = ("00" + (date.getMonth() + 1)).slice(-2);
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { fs_get_node, fs_encode_path, fs_split_path } from "./FilesystemAPI.mjs";
|
import { fs_get_node, fs_encode_path, fs_split_path } from "./FilesystemAPI";
|
||||||
import type { FSNode, FSPath, FSPermissions, FSContext } from "./FilesystemAPI.mjs";
|
import type { FSNode, FSPath, FSPermissions, FSContext } from "./FilesystemAPI";
|
||||||
import type { Writable } from "svelte/store"
|
import type { Writable } from "svelte/store"
|
||||||
|
|
||||||
export class FSNavigator {
|
export class FSNavigator {
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDataVolume, formatThousands } from "util/Formatting.svelte"
|
import { formatDataVolume, formatThousands } from "util/Formatting"
|
||||||
import { fs_path_url } from "./FilesystemAPI.mjs";
|
import { fs_path_url } from "./FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let downloads = 0
|
let downloads = 0
|
||||||
@@ -71,7 +72,7 @@ const update_base = async () => {
|
|||||||
|
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
if (socket === null) {
|
if (socket === null) {
|
||||||
update_base(nav.base)
|
update_base()
|
||||||
}
|
}
|
||||||
}, 5000)
|
}, 5000)
|
||||||
}
|
}
|
||||||
@@ -119,12 +120,12 @@ const close_socket = () => {
|
|||||||
|
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<div class="label">Directories</div>
|
<div class="label">Directories</div>
|
||||||
<div class="stat">{formatThousands(total_directories, 3)}</div>
|
<div class="stat">{formatThousands(total_directories)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<div class="label">Files</div>
|
<div class="label">Files</div>
|
||||||
<div class="stat">{formatThousands(total_files, 3)}</div>
|
<div class="stat">{formatThousands(total_files)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="group">
|
<div class="group">
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import EditWindow from "./edit_window/EditWindow.svelte";
|
import EditWindow from "./edit_window/EditWindow.svelte";
|
||||||
@@ -7,21 +7,21 @@ 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_path_url } from "./FilesystemAPI.mjs";
|
import { fs_path_url, type FSPath } from "./FilesystemAPI";
|
||||||
import Menu from "./Menu.svelte";
|
import Menu from "./Menu.svelte";
|
||||||
import { FSNavigator } from "./FSNavigator"
|
import { FSNavigator } from "./FSNavigator"
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import TransferLimit from "file_viewer/TransferLimit.svelte";
|
import TransferLimit from "file_viewer/TransferLimit.svelte";
|
||||||
import { stats } from "lib/StatsSocket.mjs"
|
import { stats } from "lib/StatsSocket"
|
||||||
import { css_from_path } from "filesystem/edit_window/Branding.js";
|
import { css_from_path } from "filesystem/edit_window/Branding";
|
||||||
import AffiliatePrompt from "user_home/AffiliatePrompt.svelte";
|
import AffiliatePrompt from "user_home/AffiliatePrompt.svelte";
|
||||||
|
|
||||||
let file_viewer
|
let file_viewer: HTMLDivElement
|
||||||
let file_preview
|
let file_preview: FilePreview
|
||||||
let toolbar
|
let toolbar: Toolbar
|
||||||
let upload_widget
|
let upload_widget: FSUploadWidget
|
||||||
let details_visible = false
|
let details_visible = false
|
||||||
let edit_window
|
let edit_window: EditWindow
|
||||||
let edit_visible = false
|
let edit_visible = false
|
||||||
|
|
||||||
const loading = writable(true)
|
const loading = writable(true)
|
||||||
@@ -29,7 +29,7 @@ const nav = new FSNavigator(true)
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
nav.loading = loading
|
nav.loading = loading
|
||||||
nav.open_node(window.initial_node, false)
|
nav.open_node((window as any).initial_node as FSPath, false)
|
||||||
|
|
||||||
// Subscribe to navigation updates. This function returns a deconstructor
|
// Subscribe to navigation updates. This function returns a deconstructor
|
||||||
// which we can conveniently return from our mount function as well
|
// which we can conveniently return from our mount function as well
|
||||||
@@ -45,10 +45,10 @@ onMount(() => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const keydown = e => {
|
const keydown = (e: KeyboardEvent) => {
|
||||||
if (e.ctrlKey || e.altKey || e.metaKey) {
|
if (e.ctrlKey || e.altKey || e.metaKey) {
|
||||||
return // prevent custom shortcuts from interfering with system shortcuts
|
return // prevent custom shortcuts from interfering with system shortcuts
|
||||||
} else if (document.activeElement.type && document.activeElement.type === "text") {
|
} else if ((document.activeElement as any).type !== undefined && (document.activeElement as any).type === "text") {
|
||||||
return // Prevent shortcuts from interfering with input fields
|
return // Prevent shortcuts from interfering with input fields
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ const keydown = e => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const download = () => {
|
const download = () => {
|
||||||
let a = document.createElement("a")
|
const a = document.createElement("a")
|
||||||
|
|
||||||
if (nav.base.type === "file") {
|
if (nav.base.type === "file") {
|
||||||
a.href = fs_path_url(nav.base.path) + "?attach"
|
a.href = fs_path_url(nav.base.path) + "?attach"
|
||||||
|
@@ -24,18 +24,38 @@ export type FSNode = {
|
|||||||
mode_octal: string,
|
mode_octal: string,
|
||||||
created_by: string,
|
created_by: string,
|
||||||
|
|
||||||
abuse_type: string | undefined,
|
abuse_type?: string,
|
||||||
abuse_report_time: string | undefined,
|
abuse_report_time?: string,
|
||||||
|
|
||||||
file_size: number,
|
file_size: number,
|
||||||
file_type: string,
|
file_type: string,
|
||||||
sha256_sum: string,
|
sha256_sum: string,
|
||||||
|
|
||||||
id: string | undefined,
|
id?: string,
|
||||||
properties: {} | undefined,
|
properties?: FSNodeProperties,
|
||||||
link_permissions: FSPermissions | undefined,
|
link_permissions?: FSPermissions,
|
||||||
user_permissions: [string: FSPermissions] | undefined,
|
user_permissions?: { [index: string]: FSPermissions },
|
||||||
password_permissions: [string: FSPermissions] | undefined,
|
password_permissions?: { [index: string]: FSPermissions },
|
||||||
|
|
||||||
|
// Added by us
|
||||||
|
|
||||||
|
// Indicates whether the file is selected in the file manager
|
||||||
|
fm_selected?: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FSNodeProperties = {
|
||||||
|
branding_enabled?: string,
|
||||||
|
brand_input_color?: string,
|
||||||
|
brand_highlight_color?: string,
|
||||||
|
brand_danger_color?: string,
|
||||||
|
brand_background_color?: string,
|
||||||
|
brand_body_color?: string,
|
||||||
|
brand_card_color?: string,
|
||||||
|
brand_header_image?: string,
|
||||||
|
brand_header_link?: string,
|
||||||
|
brand_footer_image?: string,
|
||||||
|
brand_footer_link?: string,
|
||||||
|
brand_background_image?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FSPermissions = {
|
export type FSPermissions = {
|
||||||
@@ -53,38 +73,26 @@ export type FSContext = {
|
|||||||
// ==============
|
// ==============
|
||||||
|
|
||||||
export type NodeOptions = {
|
export type NodeOptions = {
|
||||||
mode: number | undefined,
|
mode?: number,
|
||||||
created: string | undefined,
|
created?: string,
|
||||||
modified: string | undefined,
|
modified?: string,
|
||||||
shared: boolean | undefined,
|
shared?: boolean,
|
||||||
|
|
||||||
// Permissions
|
// Permissions
|
||||||
link_permissions: FSPermissions | undefined,
|
link_permissions?: FSPermissions,
|
||||||
user_permissions: FSPermissions | undefined,
|
user_permissions?: { [index: string]: FSPermissions },
|
||||||
password_permissions: FSPermissions | undefined,
|
password_permissions?: { [index: string]: FSPermissions },
|
||||||
|
} & FSNodeProperties
|
||||||
// Branding
|
|
||||||
branding_enabled: boolean | undefined,
|
|
||||||
brand_input_color: string | undefined,
|
|
||||||
brand_highlight_color: string | undefined,
|
|
||||||
brand_danger_color: string | undefined,
|
|
||||||
brand_background_color: string | undefined,
|
|
||||||
brand_body_color: string | undefined,
|
|
||||||
brand_card_color: string | undefined,
|
|
||||||
brand_header_image: string | undefined,
|
|
||||||
brand_header_link: string | undefined,
|
|
||||||
brand_background_image: string | undefined,
|
|
||||||
}
|
|
||||||
|
|
||||||
// API methods
|
// API methods
|
||||||
// ===========
|
// ===========
|
||||||
|
|
||||||
// mkdir only supports the "mode" option
|
// mkdir only supports the "mode" option
|
||||||
export const fs_mkdir = async (path: string, opts: NodeOptions) => {
|
export const fs_mkdir = async (path: string, opts?: NodeOptions) => {
|
||||||
const form = new FormData()
|
const form = new FormData()
|
||||||
form.append("action", "mkdir")
|
form.append("action", "mkdir")
|
||||||
|
|
||||||
if (opts && opts.mode) {
|
if (opts !== undefined && opts.mode !== undefined) {
|
||||||
form.append("mode", opts.mode.toFixed(0))
|
form.append("mode", opts.mode.toFixed(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +177,17 @@ export const fs_search = async (path: string, term: string, limit = 10) => {
|
|||||||
"?search=" + encodeURIComponent(term) +
|
"?search=" + encodeURIComponent(term) +
|
||||||
"&limit=" + limit
|
"&limit=" + limit
|
||||||
)
|
)
|
||||||
) as Array<string>
|
) as string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TimeSeries = {
|
||||||
|
timestamps: string[],
|
||||||
|
amounts: number[],
|
||||||
|
}
|
||||||
|
export type NodeTimeSeries = {
|
||||||
|
downloads: TimeSeries,
|
||||||
|
transfer_free: TimeSeries,
|
||||||
|
transfer_paid: TimeSeries,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fs_timeseries = async (path: string, start: Date, end: Date, interval = 60) => {
|
export const fs_timeseries = async (path: string, start: Date, end: Date, interval = 60) => {
|
||||||
@@ -181,7 +199,7 @@ export const fs_timeseries = async (path: string, start: Date, end: Date, interv
|
|||||||
"&end=" + end.toISOString() +
|
"&end=" + end.toISOString() +
|
||||||
"&interval=" + interval
|
"&interval=" + interval
|
||||||
)
|
)
|
||||||
)
|
) as NodeTimeSeries
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fs_import = async (parent_dir_path = "", filelist: Array<string>) => {
|
export const fs_import = async (parent_dir_path = "", filelist: Array<string>) => {
|
||||||
@@ -301,3 +319,35 @@ export const fs_node_icon = (node: FSNode, width = 64, height = 64) => {
|
|||||||
export const fs_thumbnail_url = (path: string, width = 64, height = 64) => {
|
export const fs_thumbnail_url = (path: string, width = 64, height = 64) => {
|
||||||
return fs_path_url(path) + "?thumbnail&width=" + width + "&height=" + height
|
return fs_path_url(path) + "?thumbnail&width=" + width + "&height=" + height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const fs_share_url = (path: FSNode[]): string => {
|
||||||
|
let share_path = fs_share_path(path)
|
||||||
|
if (share_path !== "") {
|
||||||
|
share_path = window.location.protocol + "//" + window.location.host + "/d/" + fs_encode_path(share_path)
|
||||||
|
}
|
||||||
|
return share_path
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fs_share_path = (path: FSNode[]): string => {
|
||||||
|
let share_url = ""
|
||||||
|
let bucket_idx = -1
|
||||||
|
|
||||||
|
// Find the last node in the path that has a public ID
|
||||||
|
for (let i = path.length - 1; i >= 0; i--) {
|
||||||
|
if (path[i].id !== undefined && path[i].id !== "me") {
|
||||||
|
bucket_idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bucket_idx !== -1) {
|
||||||
|
share_url = path[bucket_idx].id
|
||||||
|
|
||||||
|
// Construct the path starting from the bucket
|
||||||
|
for (let i = bucket_idx + 1; i < path.length; i++) {
|
||||||
|
share_url += "/" + path[i].name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return share_url
|
||||||
|
}
|
@@ -1,11 +1,12 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import PixeldrainLogo from "util/PixeldrainLogo.svelte";
|
import PixeldrainLogo from "util/PixeldrainLogo.svelte";
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import Euro from "util/Euro.svelte";
|
import Euro from "util/Euro.svelte";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
|
import { user } from "lib/UserStore";
|
||||||
|
|
||||||
let button
|
let button: HTMLButtonElement
|
||||||
let dialog
|
let dialog: HTMLDialogElement
|
||||||
|
|
||||||
export let no_login_label = "Pixeldrain"
|
export let no_login_label = "Pixeldrain"
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ const open = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close the dialog when the user clicks the background
|
// Close the dialog when the user clicks the background
|
||||||
const click = e => {
|
const click = (e: MouseEvent) => {
|
||||||
if (e.target === dialog) {
|
if (e.target === dialog) {
|
||||||
dialog.close()
|
dialog.close()
|
||||||
}
|
}
|
||||||
@@ -53,7 +54,7 @@ const click = e => {
|
|||||||
<PixeldrainLogo style="height: 1.6em; width: 1.6em;"/>
|
<PixeldrainLogo style="height: 1.6em; width: 1.6em;"/>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="button_username" class:hide_name>
|
<span class="button_username" class:hide_name>
|
||||||
{window.user.username === "" ? no_login_label : window.user.username}
|
{$user.username === "" ? no_login_label : $user.username}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,28 +63,28 @@ const click = e => {
|
|||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
<dialog bind:this={dialog} on:click={click}>
|
<dialog bind:this={dialog} on:click={click}>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
{#if window.user.username !== ""}
|
{#if $user.username !== undefined && $user.username !== ""}
|
||||||
|
|
||||||
<Button link_href="/user" link_target={target} icon="dashboard" label="Dashboard" />
|
<Button link_href="/user" link_target={target} icon="dashboard" label="Dashboard" />
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="stats_table">
|
<div class="stats_table">
|
||||||
<div>Subscription</div>
|
<div>Subscription</div>
|
||||||
<div>{window.user.subscription.name}</div>
|
<div>{$user.subscription.name}</div>
|
||||||
|
|
||||||
{#if window.user.subscription.type === "prepaid"}
|
{#if $user.subscription.type === "prepaid"}
|
||||||
<div>Credit</div>
|
<div>Credit</div>
|
||||||
<div><Euro amount={window.user.balance_micro_eur}/></div>
|
<div><Euro amount={$user.balance_micro_eur}/></div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div>Storage used</div>
|
<div>Storage used</div>
|
||||||
<div>{formatDataVolume(window.user.filesystem_storage_used, 3)}</div>
|
<div>{formatDataVolume($user.filesystem_storage_used, 3)}</div>
|
||||||
<div>Transfer used</div>
|
<div>Transfer used</div>
|
||||||
<div>{formatDataVolume(window.user.monthly_transfer_used, 3)}</div>
|
<div>{formatDataVolume($user.monthly_transfer_used, 3)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
{#if window.user.subscription.filesystem_access}
|
{#if $user.subscription.filesystem_access}
|
||||||
<Button link_href="/d/me" link_target={target} icon="folder" label="My Filesystem"/>
|
<Button link_href="/d/me" link_target={target} icon="folder" label="My Filesystem"/>
|
||||||
{:else}
|
{:else}
|
||||||
<Button link_href="/#pro" link_target={target} icon="star" label="Get Premium"/>
|
<Button link_href="/#pro" link_target={target} icon="star" label="Get Premium"/>
|
||||||
@@ -102,7 +103,7 @@ const click = e => {
|
|||||||
<Button link_href="/user/subscription" link_target={target} icon="shopping_cart" label="Subscription"/>
|
<Button link_href="/user/subscription" link_target={target} icon="shopping_cart" label="Subscription"/>
|
||||||
<Button link_href="/user/prepaid/transactions" link_target={target} icon="receipt" label="Transactions"/>
|
<Button link_href="/user/prepaid/transactions" link_target={target} icon="receipt" label="Transactions"/>
|
||||||
|
|
||||||
{#if window.user.is_admin}
|
{#if $user.is_admin}
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
<Button link_href="/admin" link_target={target} icon="admin_panel_settings" label="Admin Panel"/>
|
<Button link_href="/admin" link_target={target} icon="admin_panel_settings" label="Admin Panel"/>
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -1,157 +0,0 @@
|
|||||||
<script context="module">
|
|
||||||
export const generate_share_url = path => {
|
|
||||||
let share_path = generate_share_path(path)
|
|
||||||
if (share_path !== "") {
|
|
||||||
share_path = window.location.protocol+"//"+window.location.host+"/d/"+fs_encode_path(share_path)
|
|
||||||
}
|
|
||||||
return share_path
|
|
||||||
}
|
|
||||||
export const generate_share_path = path => {
|
|
||||||
let share_url = ""
|
|
||||||
let bucket_idx = -1
|
|
||||||
|
|
||||||
// Find the last node in the path that has a public ID
|
|
||||||
for (let i = path.length-1; i >= 0; i--) {
|
|
||||||
if (path[i].id !== undefined && path[i].id !== "me") {
|
|
||||||
bucket_idx = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (bucket_idx !== -1) {
|
|
||||||
share_url = path[bucket_idx].id
|
|
||||||
|
|
||||||
// Construct the path starting from the bucket
|
|
||||||
for (let i = bucket_idx+1; i < path.length; i++) {
|
|
||||||
share_url += "/" + path[i].name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return share_url
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { fs_update, fs_encode_path } from "./FilesystemAPI.mjs";
|
|
||||||
|
|
||||||
export let visible = false
|
|
||||||
export let share_url = ""
|
|
||||||
$: {
|
|
||||||
if (share_url === "") {
|
|
||||||
visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const share = async () => {
|
|
||||||
console.debug("Making file sharable", state.base)
|
|
||||||
try {
|
|
||||||
await fs_update(state.base.path, {shared: true})
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err)
|
|
||||||
alert(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fs_navigator.navigate(state.base.path, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
export let state
|
|
||||||
export let fs_navigator
|
|
||||||
|
|
||||||
const share_email = () => {
|
|
||||||
window.open(
|
|
||||||
'mailto:please@set.address?subject=File%20on%20pixeldrain&body='+encodeURIComponent(share_url)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const share_reddit = () => {
|
|
||||||
window.open('https://www.reddit.com/submit?url='+encodeURIComponent(share_url));
|
|
||||||
}
|
|
||||||
const share_twitter = () => {
|
|
||||||
window.open('https://twitter.com/share?url='+encodeURIComponent(share_url));
|
|
||||||
}
|
|
||||||
const share_facebook = () => {
|
|
||||||
window.open('http://www.facebook.com/sharer.php?u='+encodeURIComponent(share_url));
|
|
||||||
}
|
|
||||||
const share_tumblr = () => {
|
|
||||||
window.open('http://www.tumblr.com/share/link?url='+encodeURIComponent(share_url));
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="sharebar" class:visible>
|
|
||||||
{#if share_url !== ""}
|
|
||||||
Share on:<br/>
|
|
||||||
<button class="button_full_width" on:click={share_email}>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
|
||||||
<path d="M22 4H2v16h20V4zm-2 4l-8 5-8-5V6l8 5 8-5v2z"/>
|
|
||||||
</svg>
|
|
||||||
<br/>
|
|
||||||
E-Mail
|
|
||||||
</button>
|
|
||||||
<button class="button_full_width" on:click={share_reddit}>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
|
||||||
<path d="M22,12.14C22,10.92 21,9.96 19.81,9.96C19.22,9.96 18.68,10.19 18.29,10.57C16.79,9.5 14.72,8.79 12.43,8.7L13.43,4L16.7,4.71C16.73,5.53 17.41,6.19 18.25,6.19C19.11,6.19 19.81,5.5 19.81,4.63C19.81,3.77 19.11,3.08 18.25,3.08C17.65,3.08 17.11,3.43 16.86,3.95L13.22,3.18C13.11,3.16 13,3.18 12.93,3.24C12.84,3.29 12.79,3.38 12.77,3.5L11.66,8.72C9.33,8.79 7.23,9.5 5.71,10.58C5.32,10.21 4.78,10 4.19,10C2.97,10 2,10.96 2,12.16C2,13.06 2.54,13.81 3.29,14.15C3.25,14.37 3.24,14.58 3.24,14.81C3.24,18.18 7.16,20.93 12,20.93C16.84,20.93 20.76,18.2 20.76,14.81C20.76,14.6 20.75,14.37 20.71,14.15C21.46,13.81 22,13.04 22,12.14M7,13.7C7,12.84 7.68,12.14 8.54,12.14C9.4,12.14 10.1,12.84 10.1,13.7A1.56,1.56 0 0,1 8.54,15.26C7.68,15.28 7,14.56 7,13.7M15.71,17.84C14.63,18.92 12.59,19 12,19C11.39,19 9.35,18.9 8.29,17.84C8.13,17.68 8.13,17.43 8.29,17.27C8.45,17.11 8.7,17.11 8.86,17.27C9.54,17.95 11,18.18 12,18.18C13,18.18 14.47,17.95 15.14,17.27C15.3,17.11 15.55,17.11 15.71,17.27C15.85,17.43 15.85,17.68 15.71,17.84M15.42,15.28C14.56,15.28 13.86,14.58 13.86,13.72A1.56,1.56 0 0,1 15.42,12.16C16.28,12.16 17,12.86 17,13.72C17,14.56 16.28,15.28 15.42,15.28Z" />
|
|
||||||
</svg>
|
|
||||||
<br/>
|
|
||||||
Reddit
|
|
||||||
</button>
|
|
||||||
<button class="button_full_width" on:click={share_twitter}>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
|
||||||
<path d="M22.46,6C21.69,6.35 20.86,6.58 20,6.69C20.88,6.16 21.56,5.32 21.88,4.31C21.05,4.81 20.13,5.16 19.16,5.36C18.37,4.5 17.26,4 16,4C13.65,4 11.73,5.92 11.73,8.29C11.73,8.63 11.77,8.96 11.84,9.27C8.28,9.09 5.11,7.38 3,4.79C2.63,5.42 2.42,6.16 2.42,6.94C2.42,8.43 3.17,9.75 4.33,10.5C3.62,10.5 2.96,10.3 2.38,10C2.38,10 2.38,10 2.38,10.03C2.38,12.11 3.86,13.85 5.82,14.24C5.46,14.34 5.08,14.39 4.69,14.39C4.42,14.39 4.15,14.36 3.89,14.31C4.43,16 6,17.26 7.89,17.29C6.43,18.45 4.58,19.13 2.56,19.13C2.22,19.13 1.88,19.11 1.54,19.07C3.44,20.29 5.7,21 8.12,21C16,21 20.33,14.46 20.33,8.79C20.33,8.6 20.33,8.42 20.32,8.23C21.16,7.63 21.88,6.87 22.46,6Z" />
|
|
||||||
</svg>
|
|
||||||
<br/>
|
|
||||||
Twitter
|
|
||||||
</button>
|
|
||||||
<button class="button_full_width" on:click={share_facebook}>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
|
||||||
<path d="M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M18,5H15.5A3.5,3.5 0 0,0 12,8.5V11H10V14H12V21H15V14H18V11H15V9A1,1 0 0,1 16,8H18V5Z" />
|
|
||||||
</svg>
|
|
||||||
<br/>
|
|
||||||
Facebook
|
|
||||||
</button>
|
|
||||||
<button class="button_full_width" on:click={share_tumblr}>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 24 24">
|
|
||||||
<path d="M17,11H13V15.5C13,16.44 13.28,17 14.5,17H17V21C17,21 15.54,21.05 14.17,21.05C10.8,21.05 9.5,19 9.5,16.75V11H7V7C10.07,6.74 10.27,4.5 10.5,3H13V7H17" />
|
|
||||||
</svg>
|
|
||||||
<br/>
|
|
||||||
Tumblr
|
|
||||||
</button>
|
|
||||||
{:else}
|
|
||||||
This file or directory is not currently shared. Would you like to make it sharable?
|
|
||||||
<button on:click={share}>
|
|
||||||
<i class="icon">share</i>
|
|
||||||
Make sharable
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.sharebar{
|
|
||||||
position: absolute;
|
|
||||||
width: 7em;
|
|
||||||
left: -8em;
|
|
||||||
bottom: 0;
|
|
||||||
top: 0;
|
|
||||||
overflow-y: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
float: left;
|
|
||||||
background: var(--shaded_background);
|
|
||||||
backdrop-filter: blur(4px);
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
transition: left 0.3s, opacity 0.3s;
|
|
||||||
border-top-left-radius: 16px;
|
|
||||||
border-bottom-left-radius: 16px;
|
|
||||||
}
|
|
||||||
.visible {
|
|
||||||
left: 8em;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.button_full_width {
|
|
||||||
width: calc(100% - 6px);
|
|
||||||
}
|
|
||||||
.button_full_width > svg {
|
|
||||||
height: 3em;
|
|
||||||
width: 3em;
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -1,19 +1,22 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { generate_share_url } from "./Sharebar.svelte";
|
|
||||||
import { copy_text } from "util/Util.svelte";
|
import { copy_text } from "util/Util.svelte";
|
||||||
import FileStats from "./FileStats.svelte";
|
import FileStats from "./FileStats.svelte";
|
||||||
|
import type { FSNavigator } from "./FSNavigator";
|
||||||
|
import EditWindow from "./edit_window/EditWindow.svelte";
|
||||||
|
import FilePreview from "./viewers/FilePreview.svelte";
|
||||||
|
import { fs_share_url } from "./FilesystemAPI";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let details_visible = false
|
export let details_visible = false
|
||||||
export let edit_window
|
export let edit_window: EditWindow
|
||||||
export let edit_visible = false
|
export let edit_visible = false
|
||||||
export let file_viewer
|
export let file_viewer: HTMLDivElement
|
||||||
export let file_preview
|
export let file_preview: FilePreview
|
||||||
|
|
||||||
$: share_url = generate_share_url($nav.path)
|
$: share_url = fs_share_url($nav.path)
|
||||||
let link_copied = false
|
let link_copied = false
|
||||||
export const copy_link = () => {
|
export const copy_link = () => {
|
||||||
if (share_url === "") {
|
if (share_url === "") {
|
||||||
@@ -60,7 +63,7 @@ export const toggle_fullscreen = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let expanded = true
|
let expanded = true
|
||||||
let expand = e => {
|
let expand = (e: Event) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
expanded = !expanded
|
expanded = !expanded
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import type { FSNode, FSPermissions } from "filesystem/FilesystemAPI.mjs";
|
import type { FSNode, FSPermissions } from "filesystem/FilesystemAPI";
|
||||||
import PermissionButton from "./PermissionButton.svelte";
|
import PermissionButton from "./PermissionButton.svelte";
|
||||||
|
|
||||||
export let file: FSNode
|
export let file: FSNode
|
||||||
@@ -10,7 +10,7 @@ let new_user_perms = <FSPermissions>{read: true}
|
|||||||
const add_user = (e: SubmitEvent) => {
|
const add_user = (e: SubmitEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (file.user_permissions === undefined) {
|
if (file.user_permissions === undefined) {
|
||||||
file.user_permissions = <[string: FSPermissions]>{}
|
file.user_permissions = {} as {[index: string]: FSPermissions}
|
||||||
}
|
}
|
||||||
file.user_permissions[new_user_id] = structuredClone(new_user_perms)
|
file.user_permissions[new_user_id] = structuredClone(new_user_perms)
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ let new_password_perms = <FSPermissions>{read: true}
|
|||||||
const add_password = (e: SubmitEvent) => {
|
const add_password = (e: SubmitEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (file.password_permissions === undefined) {
|
if (file.password_permissions === undefined) {
|
||||||
file.password_permissions = <[string: FSPermissions]>{}
|
file.password_permissions = {} as {[index: string]: FSPermissions}
|
||||||
}
|
}
|
||||||
file.password_permissions[new_password] = structuredClone(new_password_perms)
|
file.password_permissions[new_password] = structuredClone(new_password_perms)
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import parse from "pure-color/parse"
|
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";
|
@@ -1,33 +1,17 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import ThemePresets from "./ThemePresets.svelte";
|
import ThemePresets from "./ThemePresets.svelte";
|
||||||
import FilePicker from "file_viewer/FilePicker.svelte";
|
import { fs_update, fs_node_type, type FSNode } from "filesystem/FilesystemAPI";
|
||||||
import { fs_update, fs_node_type } from "filesystem/FilesystemAPI.mjs";
|
|
||||||
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";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let file = {
|
export let file: FSNode
|
||||||
properties: {
|
|
||||||
branding_enabled: "",
|
|
||||||
brand_input_color: "",
|
|
||||||
brand_highlight_color: "",
|
|
||||||
brand_danger_color: "",
|
|
||||||
brand_background_color: "",
|
|
||||||
brand_body_color: "",
|
|
||||||
brand_card_color: "",
|
|
||||||
brand_header_image: "",
|
|
||||||
brand_header_link: "",
|
|
||||||
brand_footer_image: "",
|
|
||||||
brand_footer_link: "",
|
|
||||||
brand_background_image: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export let enabled = false
|
export let enabled = false
|
||||||
|
|
||||||
$: update_colors(file)
|
$: update_colors(file)
|
||||||
const update_colors = file => {
|
const update_colors = (file: FSNode) => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
file.properties.branding_enabled = "true"
|
file.properties.branding_enabled = "true"
|
||||||
dispatch("style_change")
|
dispatch("style_change")
|
||||||
@@ -36,13 +20,13 @@ const update_colors = file => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let picker
|
let picker: FilePicker
|
||||||
let picking = ""
|
let picking = ""
|
||||||
const pick_image = type => {
|
const pick_image = (type: string) => {
|
||||||
picking = type
|
picking = type
|
||||||
picker.open(file.path)
|
picker.open(file.path)
|
||||||
}
|
}
|
||||||
const handle_picker = async e => {
|
const handle_picker = async (e: CustomEvent<FSNode[]>) => {
|
||||||
if (e.detail.length !== 1) {
|
if (e.detail.length !== 1) {
|
||||||
alert("Please select one file")
|
alert("Please select one file")
|
||||||
return
|
return
|
||||||
|
@@ -1,29 +1,24 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { fs_rename, fs_update } from "filesystem/FilesystemAPI.mjs";
|
import { fs_rename, fs_update, type FSNode, type FSNodeProperties, type NodeOptions } from "filesystem/FilesystemAPI";
|
||||||
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";
|
||||||
import FileOptions from "./FileOptions.svelte";
|
import FileOptions from "./FileOptions.svelte";
|
||||||
import SharingOptions from "./SharingOptions.svelte";
|
import SharingOptions from "./SharingOptions.svelte";
|
||||||
import AccessControl from "./AccessControl.svelte";
|
import AccessControl from "./AccessControl.svelte";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
let file = {
|
let file: FSNode = {} as FSNode
|
||||||
path: "",
|
|
||||||
name: "",
|
|
||||||
id: "",
|
|
||||||
mode_octal: "",
|
|
||||||
properties: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
let custom_css = ""
|
let custom_css = ""
|
||||||
|
|
||||||
export let visible
|
export let visible: boolean
|
||||||
|
|
||||||
// Open the edit window. Argument 1 is the file to edit, 2 is whether the file
|
// Open the edit window. Argument 1 is the file to edit, 2 is whether the file
|
||||||
// should be opened after the user finishes editing and 3 is the default tab
|
// should be opened after the user finishes editing and 3 is the default tab
|
||||||
// that should be open when the window shows
|
// that should be open when the window shows
|
||||||
export const edit = (f, oae = false, open_tab = "") => {
|
export const edit = (f: FSNode, oae = false, open_tab = "") => {
|
||||||
file = f
|
file = f
|
||||||
open_after_edit = oae
|
open_after_edit = oae
|
||||||
if (open_tab !== "") {
|
if (open_tab !== "") {
|
||||||
@@ -38,12 +33,12 @@ export const edit = (f, oae = false, open_tab = "") => {
|
|||||||
shared = !(file.id === undefined || file.id === "")
|
shared = !(file.id === undefined || file.id === "")
|
||||||
|
|
||||||
if (file.properties === undefined) {
|
if (file.properties === undefined) {
|
||||||
file.properties = {}
|
file.properties = {} as FSNodeProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shared && file.link_permissions === undefined) {
|
if (shared && file.link_permissions === undefined) {
|
||||||
// Default to read-only for public links
|
// Default to read-only for public links
|
||||||
file.link_permissions = {read: true, write: false, delete: false}
|
file.link_permissions = { owner: false, read: true, write: false, delete: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
branding_enabled = file.properties.branding_enabled === "true"
|
branding_enabled = file.properties.branding_enabled === "true"
|
||||||
@@ -59,51 +54,31 @@ export const edit = (f, oae = false, open_tab = "") => {
|
|||||||
let tab = "file"
|
let tab = "file"
|
||||||
let open_after_edit = false
|
let open_after_edit = false
|
||||||
|
|
||||||
let shared = false
|
|
||||||
let new_name = ""
|
let new_name = ""
|
||||||
|
let shared = false
|
||||||
let branding_enabled = false
|
let branding_enabled = false
|
||||||
let branding_colors
|
|
||||||
let branding_fields = [
|
|
||||||
"brand_input_color",
|
|
||||||
"brand_highlight_color",
|
|
||||||
"brand_danger_color",
|
|
||||||
"brand_background_color",
|
|
||||||
"brand_body_color",
|
|
||||||
"brand_card_color",
|
|
||||||
"brand_header_image",
|
|
||||||
"brand_header_link",
|
|
||||||
"brand_background_image",
|
|
||||||
]
|
|
||||||
|
|
||||||
const save = async (keep_editing = false) => {
|
const save = async (keep_editing = false) => {
|
||||||
console.debug("Saving file", file.path)
|
console.debug("Saving file", file.path)
|
||||||
|
|
||||||
let new_file
|
let new_file: FSNode
|
||||||
try {
|
try {
|
||||||
nav.set_loading(true)
|
nav.set_loading(true)
|
||||||
let opts = {
|
let opts = {
|
||||||
shared: shared,
|
shared: shared,
|
||||||
}
|
branding_enabled: JSON.stringify(branding_enabled)
|
||||||
|
} as NodeOptions
|
||||||
|
|
||||||
opts.branding_enabled = branding_enabled ? "true" : ""
|
if (branding_enabled && file.properties !== undefined) {
|
||||||
|
for (let field of Object.keys(file.properties)) {
|
||||||
if (branding_enabled && file.properties) {
|
|
||||||
for (let field of branding_fields) {
|
|
||||||
if (file.properties[field] !== undefined) {
|
|
||||||
console.log("setting", field, "to", file.properties[field])
|
console.log("setting", field, "to", file.properties[field])
|
||||||
opts[field] = file.properties[field]
|
opts[field] = file.properties[field]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (shared && file.link_permissions !== undefined) {
|
if (shared) {
|
||||||
opts.link_permissions = file.link_permissions
|
opts.link_permissions = file.link_permissions
|
||||||
}
|
|
||||||
if (shared && file.user_permissions !== undefined) {
|
|
||||||
opts.user_permissions = file.user_permissions
|
opts.user_permissions = file.user_permissions
|
||||||
}
|
|
||||||
if (shared && file.password_permissions !== undefined) {
|
|
||||||
opts.password_permissions = file.password_permissions
|
opts.password_permissions = file.password_permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,11 +154,10 @@ const save = async (keep_editing = false) => {
|
|||||||
{:else if tab === "share"}
|
{:else if tab === "share"}
|
||||||
<SharingOptions bind:file bind:shared on:save={() => save(true)} />
|
<SharingOptions bind:file bind:shared on:save={() => save(true)} />
|
||||||
{:else if tab === "access"}
|
{:else if tab === "access"}
|
||||||
<AccessControl bind:file bind:shared />
|
<AccessControl bind:file />
|
||||||
{:else if tab === "branding"}
|
{:else if tab === "branding"}
|
||||||
<BrandingOptions
|
<BrandingOptions
|
||||||
bind:enabled={branding_enabled}
|
bind:enabled={branding_enabled}
|
||||||
bind:colors={branding_colors}
|
|
||||||
bind:file
|
bind:file
|
||||||
on:style_change={e => custom_css = branding_from_node(file)}
|
on:style_change={e => custom_css = branding_from_node(file)}
|
||||||
/>
|
/>
|
||||||
|
@@ -1,17 +1,18 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import { fs_delete_all } from "filesystem/FilesystemAPI.mjs";
|
import { fs_delete_all, type FSNode } from "filesystem/FilesystemAPI";
|
||||||
import PathLink from "filesystem/util/PathLink.svelte";
|
import PathLink from "filesystem/util/PathLink.svelte";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let file = {}
|
export let file: FSNode = {} as FSNode
|
||||||
export let new_name
|
export let new_name: string
|
||||||
export let visible
|
export let visible: boolean
|
||||||
export let open_after_edit
|
export let open_after_edit: boolean
|
||||||
|
|
||||||
$: is_root_dir = file.path === "/"+file.id
|
$: is_root_dir = file.path === "/"+file.id
|
||||||
|
|
||||||
const delete_file = async e => {
|
const delete_file = async (e: MouseEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@@ -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 "filesystem/FilesystemAPI.mjs";
|
import type { FSPermissions } from "filesystem/FilesystemAPI";
|
||||||
|
|
||||||
export let permissions = <FSPermissions>{}
|
export let permissions = <FSPermissions>{}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,20 +1,21 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { domain_url } from "util/Util.svelte";
|
import { domain_url } from "util/Util.svelte";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
|
import type { FSNode } from "filesystem/FilesystemAPI";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
export let shared
|
export let shared: boolean
|
||||||
export let file
|
export let file: FSNode = {} as FSNode
|
||||||
|
|
||||||
let embed_html
|
let embed_html: string
|
||||||
let preview_area
|
let preview_area: HTMLDivElement
|
||||||
|
|
||||||
$: is_shared = file.id !== undefined && file.id !== ""
|
$: is_shared = file.id !== undefined && file.id !== ""
|
||||||
$: share_link = window.location.protocol+"//"+window.location.host+"/d/"+file.id
|
$: share_link = window.location.protocol+"//"+window.location.host+"/d/"+file.id
|
||||||
$: embed_iframe(file)
|
$: embed_iframe(file)
|
||||||
let embed_iframe = file => {
|
let embed_iframe = (file: FSNode) => {
|
||||||
if (!is_shared) {
|
if (!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"
|
||||||
@@ -41,7 +42,7 @@ const toggle_example = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const update_shared = e => {
|
const update_shared = () => {
|
||||||
// If sharing is enabled we automatically save the file so the user can copy
|
// If sharing is enabled we automatically save the file so the user can copy
|
||||||
// the sharing link. But if the user disables sharing we don't automatically
|
// the sharing link. But if the user disables sharing we don't automatically
|
||||||
// save so that the user can't accidentally discard a sharing link that's in
|
// save so that the user can't accidentally discard a sharing link that's in
|
||||||
|
@@ -1,17 +1,15 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
export let properties = {
|
import type { FSNodeProperties } from "filesystem/FilesystemAPI";
|
||||||
brand_input_color: "",
|
|
||||||
brand_highlight_color: "",
|
export let properties: FSNodeProperties = {} as FSNodeProperties
|
||||||
brand_danger_color: "",
|
|
||||||
brand_background_color: "",
|
|
||||||
brand_body_color: "",
|
|
||||||
brand_card_color: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_theme = -1
|
let current_theme = -1
|
||||||
|
|
||||||
const set_theme = index => {
|
const set_theme = (index: number) => {
|
||||||
current_theme = index
|
current_theme = index
|
||||||
|
|
||||||
|
// Copy all the properties of the theme to the file, except for the theme
|
||||||
|
// name
|
||||||
Object.keys(themes[index]).forEach(key => {
|
Object.keys(themes[index]).forEach(key => {
|
||||||
if (key !== "name") {
|
if (key !== "name") {
|
||||||
properties[key] = themes[index][key]
|
properties[key] = themes[index][key]
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { fs_encode_path, fs_node_icon } from "filesystem/FilesystemAPI.mjs"
|
import { fs_encode_path, fs_node_icon } from "filesystem/FilesystemAPI"
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let show_hidden = false
|
export let show_hidden = false
|
||||||
export let large_icons = false
|
export let large_icons = false
|
||||||
</script>
|
</script>
|
||||||
@@ -13,8 +14,8 @@ export let large_icons = false
|
|||||||
{#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)}
|
||||||
on:click|preventDefault={() => dispatch("node_click", index)}
|
on:click|preventDefault={e => dispatch("node_click", {index: index, original: e})}
|
||||||
on:contextmenu={e => dispatch("node_context", {event: e, index: index})}
|
on:contextmenu={e => dispatch("node_context", {index: index, original: 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}
|
||||||
@@ -26,7 +27,7 @@ export let large_icons = false
|
|||||||
{#if child.id}
|
{#if child.id}
|
||||||
<a
|
<a
|
||||||
href="/d/{child.id}"
|
href="/d/{child.id}"
|
||||||
on:click|preventDefault|stopPropagation={() => {dispatch("node_share_click", index)}}
|
on:click|preventDefault|stopPropagation={e => {dispatch("node_share_click", {index: index, original: 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>
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { fs_mkdir } from "filesystem/FilesystemAPI.mjs";
|
import { fs_mkdir } from "filesystem/FilesystemAPI";
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav;
|
export let nav: FSNavigator
|
||||||
|
|
||||||
let name_input;
|
let name_input: HTMLInputElement;
|
||||||
let new_dir_name = ""
|
let new_dir_name = ""
|
||||||
let error_msg = ""
|
let error_msg = ""
|
||||||
let create_dir = async () => {
|
let create_dir = async () => {
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import FilePicker from "file_viewer/FilePicker.svelte";
|
import FilePicker from "file_viewer/FilePicker.svelte";
|
||||||
import { fs_import } from "filesystem/FilesystemAPI.mjs";
|
import { fs_import } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
let file_picker
|
let file_picker: FilePicker
|
||||||
|
|
||||||
export const open = () => file_picker.open()
|
export const open = () => file_picker.open()
|
||||||
|
|
||||||
const import_files = async files => {
|
// TODO: Give files a proper type
|
||||||
|
const import_files = async (files: any) => {
|
||||||
nav.set_loading(true)
|
nav.set_loading(true)
|
||||||
|
|
||||||
let fileids = []
|
let fileids = []
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
<script>
|
<script lang="ts" context="module">
|
||||||
import { fs_delete_all, fs_rename } from "filesystem/FilesystemAPI.mjs"
|
export type FMNodeEvent = {
|
||||||
|
index: number,
|
||||||
|
original: MouseEvent,
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script lang="ts">
|
||||||
|
import { fs_delete_all, fs_rename, type FSNode } from "filesystem/FilesystemAPI"
|
||||||
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"
|
||||||
@@ -7,29 +13,32 @@ import GalleryView from "./GalleryView.svelte"
|
|||||||
import CompactView from "./CompactView.svelte"
|
import CompactView from "./CompactView.svelte"
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import FileImporter from "./FileImporter.svelte";
|
import FileImporter from "./FileImporter.svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import { drop_target } from "lib/DropTarget.ts"
|
import { drop_target } from "lib/DropTarget"
|
||||||
import SearchBar from "./SearchBar.svelte";
|
import SearchBar from "./SearchBar.svelte";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
import FsUploadWidget from "filesystem/upload_widget/FSUploadWidget.svelte";
|
||||||
|
import EditWindow from "filesystem/edit_window/EditWindow.svelte";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let upload_widget
|
export let upload_widget: FsUploadWidget
|
||||||
export let edit_window
|
export let edit_window: EditWindow
|
||||||
export let directory_view = ""
|
export let directory_view = ""
|
||||||
let large_icons = false
|
let large_icons = false
|
||||||
let uploader
|
let uploader: FsUploadWidget
|
||||||
let mode = "viewing"
|
let mode = "viewing"
|
||||||
let creating_dir = false
|
let creating_dir = false
|
||||||
let show_hidden = false
|
let show_hidden = false
|
||||||
let file_importer
|
let file_importer: FileImporter
|
||||||
|
|
||||||
export const upload = files => {
|
export const upload = (files: File[]) => {
|
||||||
return uploader.upload(files)
|
return uploader.upload(files)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigation functions
|
// Navigation functions
|
||||||
|
|
||||||
const node_click = e => {
|
const node_click = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
let index = e.detail
|
const index = e.detail.index
|
||||||
|
|
||||||
creating_dir = false
|
creating_dir = false
|
||||||
|
|
||||||
@@ -48,27 +57,29 @@ const node_click = e => {
|
|||||||
select_node(index)
|
select_node(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let node_context = e => {
|
let node_context = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
// 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.event.preventDefault()
|
e.detail.original.preventDefault()
|
||||||
node_select({detail: e.detail.index})
|
node_select(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const node_share_click = e => {
|
const node_share_click = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
let index = e.detail
|
|
||||||
|
|
||||||
creating_dir = false
|
creating_dir = false
|
||||||
nav.navigate(nav.children[index].id, true)
|
nav.navigate(nav.children[e.detail.index].id, true)
|
||||||
}
|
}
|
||||||
const node_select = e => {
|
const node_select = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
let index = e.detail
|
const index = e.detail.index
|
||||||
mode = "selecting"
|
mode = "selecting"
|
||||||
nav.children[index].fm_selected = !nav.children[index].fm_selected
|
nav.children[index].fm_selected = !nav.children[index].fm_selected
|
||||||
}
|
}
|
||||||
|
|
||||||
const node_settings = e => edit_window.edit(nav.children[e.detail], false, "file")
|
const node_settings = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
const node_branding = e => edit_window.edit(nav.children[e.detail], false, "branding")
|
edit_window.edit(nav.children[e.detail.index], false, "file")
|
||||||
|
}
|
||||||
|
const node_branding = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
|
edit_window.edit(nav.children[e.detail.index], false, "branding")
|
||||||
|
}
|
||||||
|
|
||||||
const navigate_back = () => {
|
const navigate_back = () => {
|
||||||
creating_dir = false
|
creating_dir = false
|
||||||
@@ -147,7 +158,7 @@ const toggle_view = () => {
|
|||||||
}
|
}
|
||||||
const toggle_large_icons = () => {
|
const toggle_large_icons = () => {
|
||||||
large_icons = !large_icons
|
large_icons = !large_icons
|
||||||
localStorage.setItem("large_icons", large_icons)
|
localStorage.setItem("large_icons", JSON.stringify(large_icons))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Moving functions
|
// Moving functions
|
||||||
@@ -157,7 +168,7 @@ let moving_items = []
|
|||||||
// We need to detect if shift is pressed so we can select multiple items
|
// We need to detect if shift is pressed so we can select multiple items
|
||||||
let shift_pressed = false
|
let shift_pressed = false
|
||||||
let last_selected_node = -1
|
let last_selected_node = -1
|
||||||
const keypress = e => {
|
const keypress = (e: KeyboardEvent) => {
|
||||||
if (e.key === "Shift") {
|
if (e.key === "Shift") {
|
||||||
shift_pressed = e.type === "keydown"
|
shift_pressed = e.type === "keydown"
|
||||||
} else if (e.type === "keydown" && e.key === "a" && e.ctrlKey) {
|
} else if (e.type === "keydown" && e.key === "a" && e.ctrlKey) {
|
||||||
@@ -176,7 +187,7 @@ const keypress = e => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const select_node = index => {
|
const select_node = (index: number) => {
|
||||||
if (shift_pressed) {
|
if (shift_pressed) {
|
||||||
// If shift is pressed we do a range select. We select all files between
|
// If shift is pressed we do a range select. We select all files between
|
||||||
// the last selected file and the file that is being selected now
|
// the last selected file and the file that is being selected now
|
||||||
@@ -199,7 +210,7 @@ const select_node = index => {
|
|||||||
// function watches the children array for changes and updates the selection
|
// function watches the children array for changes and updates the selection
|
||||||
// when it changes
|
// when it changes
|
||||||
$: update($nav.children)
|
$: update($nav.children)
|
||||||
const update = (children) => {
|
const update = (children: FSNode[]) => {
|
||||||
creating_dir = false
|
creating_dir = false
|
||||||
|
|
||||||
// Highlight the files which were previously selected
|
// Highlight the files which were previously selected
|
||||||
@@ -327,11 +338,7 @@ onMount(() => {
|
|||||||
<i class="icon">move_to_inbox</i>
|
<i class="icon">move_to_inbox</i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button on:click={selecting_mode} title="Select and delete files">
|
||||||
on:click={selecting_mode}
|
|
||||||
class:button_highlight={mode === "selecting"}
|
|
||||||
title="Select and delete files"
|
|
||||||
>
|
|
||||||
<i class="icon">select_all</i>
|
<i class="icon">select_all</i>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from "svelte"
|
import { createEventDispatcher, onMount } from "svelte"
|
||||||
import ListView from "./ListView.svelte"
|
import ListView from "./ListView.svelte"
|
||||||
import GalleryView from "./GalleryView.svelte"
|
import GalleryView from "./GalleryView.svelte"
|
||||||
@@ -6,19 +6,20 @@ import CompactView from "./CompactView.svelte"
|
|||||||
import Modal from "util/Modal.svelte";
|
import Modal from "util/Modal.svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import Breadcrumbs from "filesystem/Breadcrumbs.svelte"
|
import Breadcrumbs from "filesystem/Breadcrumbs.svelte"
|
||||||
import { FSNavigator } from "filesystem/FSNavigator.js";
|
import { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
import type { FMNodeEvent } from "./FileManager.svelte";
|
||||||
|
import type { FSNode } from "filesystem/FilesystemAPI";
|
||||||
|
|
||||||
let nav = new FSNavigator(false)
|
let nav = new FSNavigator(false)
|
||||||
let modal
|
let modal: Modal
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
let directory_view = ""
|
let directory_view = ""
|
||||||
let loading = false
|
let loading = false
|
||||||
const loading_evt = e => loading = e.detail
|
|
||||||
let large_icons = false
|
let large_icons = false
|
||||||
let show_hidden = false
|
let show_hidden = false
|
||||||
export let select_multiple = false
|
export let select_multiple = false
|
||||||
|
|
||||||
export const open = path => {
|
export const open = (path: string) => {
|
||||||
modal.show()
|
modal.show()
|
||||||
nav.navigate(path, false)
|
nav.navigate(path, false)
|
||||||
}
|
}
|
||||||
@@ -32,8 +33,8 @@ $: selected_files = $nav.children.reduce((acc, file) => {
|
|||||||
|
|
||||||
// Navigation functions
|
// Navigation functions
|
||||||
|
|
||||||
const node_click = e => {
|
const node_click = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
let index = e.detail
|
const index = e.detail.index
|
||||||
|
|
||||||
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)
|
||||||
@@ -41,16 +42,15 @@ const node_click = e => {
|
|||||||
select_node(index)
|
select_node(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let node_context = e => {
|
let node_context = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
// 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.event.preventDefault()
|
e.detail.original.preventDefault()
|
||||||
node_select({detail: e.detail.index})
|
node_select(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const node_select = e => {
|
const node_select = (e: CustomEvent<FMNodeEvent>) => {
|
||||||
let index = e.detail
|
const index = e.detail.index
|
||||||
mode = "selecting"
|
|
||||||
nav.children[index].fm_selected = !nav.children[index].fm_selected
|
nav.children[index].fm_selected = !nav.children[index].fm_selected
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,13 +69,13 @@ const toggle_view = () => {
|
|||||||
// We need to detect if shift is pressed so we can select multiple items
|
// We need to detect if shift is pressed so we can select multiple items
|
||||||
let shift_pressed = false
|
let shift_pressed = false
|
||||||
let last_selected_node = -1
|
let last_selected_node = -1
|
||||||
const detect_shift = (e) => {
|
const detect_shift = (e: KeyboardEvent) => {
|
||||||
if (e.key === "Shift") {
|
if (e.key === "Shift") {
|
||||||
shift_pressed = e.type === "keydown"
|
shift_pressed = e.type === "keydown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const select_node = index => {
|
const select_node = (index: number) => {
|
||||||
if (select_multiple && shift_pressed) {
|
if (select_multiple && shift_pressed) {
|
||||||
// If shift is pressed we do a range select. We select all files between
|
// If shift is pressed we do a range select. We select all files between
|
||||||
// the last selected file and the file that is being selected now
|
// the last selected file and the file that is being selected now
|
||||||
@@ -101,7 +101,7 @@ const select_node = index => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let done = () => {
|
let done = () => {
|
||||||
let selected_files = []
|
let selected_files: FSNode[] = []
|
||||||
for (let i = 0; i < nav.children.length; i++) {
|
for (let i = 0; i < nav.children.length; i++) {
|
||||||
if (nav.children[i].fm_selected) {
|
if (nav.children[i].fm_selected) {
|
||||||
selected_files.push(nav.children[i])
|
selected_files.push(nav.children[i])
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { fs_node_icon, fs_node_type, fs_encode_path } from "filesystem/FilesystemAPI.mjs";
|
import { fs_node_icon, fs_node_type, fs_encode_path } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let show_hidden = false
|
export let show_hidden = false
|
||||||
export let large_icons = false
|
export let large_icons = false
|
||||||
</script>
|
</script>
|
||||||
@@ -12,8 +13,8 @@ export let large_icons = false
|
|||||||
{#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)}
|
||||||
on:click|preventDefault={() => dispatch("node_click", index)}
|
on:click|preventDefault={e => dispatch("node_click", {index: index, original: e})}
|
||||||
on:contextmenu={e => dispatch("node_context", {event: e, index: index})}
|
on:contextmenu={e => dispatch("node_context", {index: index, original: 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
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import { fs_encode_path, fs_node_icon } from "filesystem/FilesystemAPI.mjs"
|
import { fs_encode_path, fs_node_icon } from "filesystem/FilesystemAPI"
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let show_hidden = false
|
export let show_hidden = false
|
||||||
export let large_icons = false
|
export let large_icons = false
|
||||||
export let hide_edit = false
|
export let hide_edit = false
|
||||||
@@ -22,8 +23,8 @@ export let hide_branding = false
|
|||||||
{#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)}
|
||||||
on:click|preventDefault={() => dispatch("node_click", index)}
|
on:click|preventDefault={e => dispatch("node_click", {index: index, original: e})}
|
||||||
on:contextmenu={e => dispatch("node_context", {event: e, index: index})}
|
on:contextmenu={e => dispatch("node_context", {index: index, original: 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}
|
||||||
@@ -46,19 +47,19 @@ export let hide_branding = false
|
|||||||
{:else if child.id}
|
{:else if child.id}
|
||||||
<a
|
<a
|
||||||
href="/d/{child.id}"
|
href="/d/{child.id}"
|
||||||
on:click|preventDefault|stopPropagation={() => {dispatch("node_share_click", index)}}
|
on:click|preventDefault|stopPropagation={e => {dispatch("node_share_click", {index: index, original: 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 && child.properties.branding_enabled && !hide_branding}
|
{#if child.properties !== undefined && child.properties.branding_enabled !== undefined && !hide_branding}
|
||||||
<button class="action_button" on:click|preventDefault|stopPropagation={() => dispatch("node_branding", index)}>
|
<button class="action_button" on:click|preventDefault|stopPropagation={e => dispatch("node_branding", {index: index, original: e})}>
|
||||||
<i class="icon">palette</i>
|
<i class="icon">palette</i>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $nav.permissions.write && !hide_edit}
|
{#if $nav.permissions.write && !hide_edit}
|
||||||
<button class="action_button" on:click|preventDefault|stopPropagation={() => dispatch("node_settings", index)}>
|
<button class="action_button" on:click|preventDefault|stopPropagation={e => dispatch("node_settings", {index: index, original: e})}>
|
||||||
<i class="icon">edit</i>
|
<i class="icon">edit</i>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -1,13 +1,14 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { fs_search, fs_encode_path, fs_thumbnail_url } from "filesystem/FilesystemAPI.mjs";
|
import { fs_search, fs_encode_path, fs_thumbnail_url } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
|
|
||||||
let search_bar
|
let search_bar: HTMLInputElement
|
||||||
let error = ""
|
let error = ""
|
||||||
let search_term = ""
|
let search_term = ""
|
||||||
let search_results = []
|
let search_results: string[] = []
|
||||||
let selected_result = 0
|
let selected_result = 0
|
||||||
let searching = false
|
let searching = false
|
||||||
let last_searched_term = ""
|
let last_searched_term = ""
|
||||||
@@ -71,7 +72,7 @@ const search = async (limit = 10) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const clear_search = (blur) => {
|
const clear_search = (blur: boolean) => {
|
||||||
error = ""
|
error = ""
|
||||||
search_term = ""
|
search_term = ""
|
||||||
search_results = []
|
search_results = []
|
||||||
@@ -89,12 +90,12 @@ const clear_search = (blur) => {
|
|||||||
|
|
||||||
// Cursor navigation events can only be prevented with keydown. But we want to
|
// Cursor navigation events can only be prevented with keydown. But we want to
|
||||||
// use keyup for searching, so we use two listeners here
|
// use keyup for searching, so we use two listeners here
|
||||||
const input_keydown = e => {
|
const input_keydown = (e: KeyboardEvent) => {
|
||||||
if (e.key === "Escape" || e.key === "ArrowUp" || e.key === "ArrowDown") {
|
if (e.key === "Escape" || e.key === "ArrowUp" || e.key === "ArrowDown") {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const input_keyup = e => {
|
const input_keyup = (e: KeyboardEvent) => {
|
||||||
if (e.key === "Escape") {
|
if (e.key === "Escape") {
|
||||||
clear_search(true)
|
clear_search(true)
|
||||||
} else if (e.key === "ArrowUp") {
|
} else if (e.key === "ArrowUp") {
|
||||||
@@ -117,15 +118,15 @@ const submit_search = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const open_result = index => {
|
const open_result = (index: number) => {
|
||||||
nav.navigate(search_results[index], true)
|
nav.navigate(search_results[index], true)
|
||||||
clear_search(false)
|
clear_search(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const window_keydown = (e) => {
|
const window_keydown = (e: KeyboardEvent) => {
|
||||||
if (e.ctrlKey || e.altKey || e.metaKey) {
|
if (e.ctrlKey || e.altKey || e.metaKey) {
|
||||||
return // prevent custom shortcuts from interfering with system shortcuts
|
return // prevent custom shortcuts from interfering with system shortcuts
|
||||||
} else if (document.activeElement.type && document.activeElement.type === "text") {
|
} else if ((document.activeElement as any).type !== undefined && (document.activeElement as any).type === "text") {
|
||||||
return // Prevent shortcuts from interfering with input fields
|
return // Prevent shortcuts from interfering with input fields
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +172,7 @@ const window_keydown = (e) => {
|
|||||||
/>
|
/>
|
||||||
{#if search_term !== ""}
|
{#if search_term !== ""}
|
||||||
<!-- Button needs to be of button type in order to not submit the form -->
|
<!-- Button needs to be of button type in order to not submit the form -->
|
||||||
<button on:click={clear_search} type="button">
|
<button on:click={() => clear_search(false)} type="button">
|
||||||
<i class="icon">close</i>
|
<i class="icon">close</i>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -1,16 +1,28 @@
|
|||||||
<script>
|
<script lang="ts" context="module">
|
||||||
|
export type UploadJob = {
|
||||||
|
task_id: number,
|
||||||
|
file: File,
|
||||||
|
path: string,
|
||||||
|
component: UploadProgress,
|
||||||
|
status: string,
|
||||||
|
total_size: number,
|
||||||
|
loaded_size: number,
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script lang="ts">
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import { fade } from "svelte/transition";
|
import { fade } from "svelte/transition";
|
||||||
import UploadProgress from "./UploadProgress.svelte";
|
import UploadProgress from "./UploadProgress.svelte";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
|
|
||||||
const max_concurrent_uploads = 5
|
const max_concurrent_uploads = 5
|
||||||
|
|
||||||
let file_input_field
|
let file_input_field: HTMLInputElement
|
||||||
let file_input_change = (e) => {
|
let file_input_change = (e: Event) => {
|
||||||
// Start uploading the files async
|
// Start uploading the files async
|
||||||
upload_files(e.target.files)
|
upload_files((e.target as HTMLInputElement).files)
|
||||||
|
|
||||||
// This resets the file input field
|
// This resets the file input field
|
||||||
file_input_field.nodeValue = ""
|
file_input_field.nodeValue = ""
|
||||||
@@ -20,10 +32,10 @@ export const pick_files = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let visible = false
|
let visible = false
|
||||||
let upload_queue = [];
|
let upload_queue: UploadJob[] = [];
|
||||||
let task_id_counter = 0
|
let task_id_counter = 0
|
||||||
|
|
||||||
export const upload_files = async files => {
|
export const upload_files = async (files: File[]|FileList) => {
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
return
|
return
|
||||||
} else if (nav.base.type !== "dir") {
|
} else if (nav.base.type !== "dir") {
|
||||||
@@ -37,7 +49,7 @@ export const upload_files = async files => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const upload_file = async file => {
|
export const upload_file = async (file: File) => {
|
||||||
if (nav.base.type !== "dir") {
|
if (nav.base.type !== "dir") {
|
||||||
alert("Can only upload to directory")
|
alert("Can only upload to directory")
|
||||||
return
|
return
|
||||||
@@ -122,7 +134,7 @@ const finish_upload = () => {
|
|||||||
start_upload()
|
start_upload()
|
||||||
}
|
}
|
||||||
|
|
||||||
const leave_confirmation = (e) => {
|
const leave_confirmation = (e: BeforeUnloadEvent) => {
|
||||||
if (state === "uploading") {
|
if (state === "uploading") {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
return "If you close this page your files will stop uploading. Do you want to continue?"
|
return "If you close this page your files will stop uploading. Do you want to continue?"
|
||||||
|
@@ -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 "filesystem/FilesystemAPI.mjs"
|
import { fs_path_url, type GenericResponse } from "filesystem/FilesystemAPI"
|
||||||
|
|
||||||
// code and an error message
|
// code and an error message
|
||||||
export const upload_file = (
|
export const upload_file = (
|
||||||
|
@@ -1,22 +1,18 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { fade } from "svelte/transition";
|
import { fade } from "svelte/transition";
|
||||||
import { upload_file } from "./UploadFunc";
|
import { upload_file } from "./UploadFunc";
|
||||||
import ProgressBar from "util/ProgressBar.svelte";
|
import ProgressBar from "util/ProgressBar.svelte";
|
||||||
import Button from "layout/Button.svelte"
|
import Button from "layout/Button.svelte"
|
||||||
|
import type { UploadJob } from "./FSUploadWidget.svelte";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
export let job = {
|
export let job: UploadJob
|
||||||
file: null,
|
|
||||||
path: "",
|
|
||||||
name: "",
|
|
||||||
status: "",
|
|
||||||
}
|
|
||||||
export let total = 0
|
export let total = 0
|
||||||
export let loaded = 0
|
export let loaded = 0
|
||||||
let error_code = ""
|
let error_code = ""
|
||||||
let error_message = ""
|
let error_message = ""
|
||||||
let xhr = null
|
let xhr: XMLHttpRequest = null
|
||||||
|
|
||||||
export const start = () => {
|
export const start = () => {
|
||||||
xhr = upload_file(
|
xhr = upload_file(
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
export let nav
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
|
export let nav: FSNavigator
|
||||||
export let path = ""
|
export let path = ""
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { fs_path_url, fs_encode_path, fs_node_icon } from "filesystem/FilesystemAPI.mjs"
|
import { fs_path_url, fs_encode_path, fs_node_icon } from "filesystem/FilesystemAPI"
|
||||||
import FileTitle from "layout/FileTitle.svelte";
|
import FileTitle from "layout/FileTitle.svelte";
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
|
import type { FSNavigator } from 'filesystem/FSNavigator';
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
let player
|
let player: HTMLAudioElement
|
||||||
let playing = false
|
let playing = false
|
||||||
let media_session = false
|
let media_session = false
|
||||||
let siblings = []
|
let siblings = []
|
||||||
@@ -13,7 +14,7 @@ let siblings = []
|
|||||||
export const toggle_playback = () => playing ? player.pause() : player.play()
|
export const toggle_playback = () => playing ? player.pause() : player.play()
|
||||||
export const toggle_mute = () => player.muted = !player.muted
|
export const toggle_mute = () => player.muted = !player.muted
|
||||||
|
|
||||||
export const seek = delta => {
|
export const seek = (delta: number) => {
|
||||||
// fastseek can be pretty imprecise, so we don't use it for small seeks
|
// fastseek can be pretty imprecise, so we don't use it for small seeks
|
||||||
// below 5 seconds
|
// below 5 seconds
|
||||||
if (player.fastSeek && delta > 5) {
|
if (player.fastSeek && delta > 5) {
|
||||||
@@ -40,7 +41,7 @@ onMount(() => {
|
|||||||
media_session = true
|
media_session = true
|
||||||
navigator.mediaSession.setActionHandler('play', () => player.play());
|
navigator.mediaSession.setActionHandler('play', () => player.play());
|
||||||
navigator.mediaSession.setActionHandler('pause', () => player.pause());
|
navigator.mediaSession.setActionHandler('pause', () => player.pause());
|
||||||
navigator.mediaSession.setActionHandler('stop', () => player.stop());
|
navigator.mediaSession.setActionHandler('stop', () => player.pause());
|
||||||
navigator.mediaSession.setActionHandler('previoustrack', () => nav.open_sibling(-1));
|
navigator.mediaSession.setActionHandler('previoustrack', () => nav.open_sibling(-1));
|
||||||
navigator.mediaSession.setActionHandler('nexttrack', () => nav.open_sibling(1));
|
navigator.mediaSession.setActionHandler('nexttrack', () => nav.open_sibling(1));
|
||||||
}
|
}
|
||||||
@@ -56,8 +57,8 @@ onMount(() => {
|
|||||||
bind:this={player}
|
bind:this={player}
|
||||||
class="player"
|
class="player"
|
||||||
src={fs_path_url($nav.base.path)}
|
src={fs_path_url($nav.base.path)}
|
||||||
autoplay="autoplay"
|
autoplay
|
||||||
controls="controls"
|
controls
|
||||||
on:pause={() => playing = false }
|
on:pause={() => playing = false }
|
||||||
on:play={() => playing = true }
|
on:play={() => playing = true }
|
||||||
on:ended={() => nav.open_sibling(1) }>
|
on:ended={() => nav.open_sibling(1) }>
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
export let path = []
|
export let path = []
|
||||||
|
|
||||||
let image_uri
|
let image_uri: string
|
||||||
let image_link
|
let image_link: string
|
||||||
$: update_links(path)
|
$: update_links(path)
|
||||||
const update_links = (path) => {
|
const update_links = (path) => {
|
||||||
image_uri = null
|
image_uri = null
|
||||||
|
@@ -1,13 +1,14 @@
|
|||||||
<script>
|
<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 "filesystem/FilesystemAPI.mjs";
|
import { fs_thumbnail_url } from "filesystem/FilesystemAPI";
|
||||||
import TextBlock from "layout/TextBlock.svelte"
|
import TextBlock from "layout/TextBlock.svelte"
|
||||||
import { formatDataVolume, formatDate } from "util/Formatting.svelte";
|
import { formatDataVolume, formatDate } from "util/Formatting";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<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, fs_thumbnail_url } from "filesystem/FilesystemAPI.mjs";
|
import { fs_node_type, fs_thumbnail_url } from "filesystem/FilesystemAPI";
|
||||||
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";
|
||||||
@@ -12,14 +12,17 @@ import Video from "./Video.svelte";
|
|||||||
import Torrent from "./Torrent.svelte";
|
import Torrent from "./Torrent.svelte";
|
||||||
import Zip from "./Zip.svelte";
|
import Zip from "./Zip.svelte";
|
||||||
import CustomBanner from "./CustomBanner.svelte";
|
import CustomBanner from "./CustomBanner.svelte";
|
||||||
import { stats } from "lib/StatsSocket.mjs"
|
import { stats } from "lib/StatsSocket"
|
||||||
import SlowDown from "layout/SlowDown.svelte";
|
import SlowDown from "layout/SlowDown.svelte";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
import FsUploadWidget from "filesystem/upload_widget/FSUploadWidget.svelte";
|
||||||
|
import EditWindow from "filesystem/edit_window/EditWindow.svelte";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
export let upload_widget
|
export let upload_widget: FsUploadWidget
|
||||||
export let edit_window
|
export let edit_window: EditWindow
|
||||||
|
|
||||||
let viewer
|
let viewer: any
|
||||||
let viewer_type = ""
|
let viewer_type = ""
|
||||||
let last_path = ""
|
let last_path = ""
|
||||||
|
|
||||||
@@ -64,7 +67,7 @@ export const toggle_fullscreen = () => {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
export const seek = delta => {
|
export const seek = (delta: number) => {
|
||||||
if (viewer && viewer.seek) {
|
if (viewer && viewer.seek) {
|
||||||
viewer.seek(delta)
|
viewer.seek(delta)
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { swipe_nav } from "lib/SwipeNavigate.mjs";
|
import { swipe_nav } from "lib/SwipeNavigate";
|
||||||
import { fs_path_url } from "filesystem/FilesystemAPI.mjs";
|
import { fs_path_url } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher();
|
let dispatch = createEventDispatcher();
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
let container
|
let container: HTMLDivElement
|
||||||
let zoom = false
|
let zoom = false
|
||||||
let x = 0, y = 0
|
let x = 0, y = 0
|
||||||
let dragging = false
|
let dragging = false
|
||||||
@@ -30,7 +31,7 @@ export const update = async () => {
|
|||||||
|
|
||||||
const on_load = () => dispatch("loading", false)
|
const on_load = () => dispatch("loading", false)
|
||||||
|
|
||||||
const mousedown = (e) => {
|
const mousedown = (e: MouseEvent) => {
|
||||||
if (!dragging && e.which === 1 && zoom) {
|
if (!dragging && e.which === 1 && zoom) {
|
||||||
x = e.pageX
|
x = e.pageX
|
||||||
y = e.pageY
|
y = e.pageY
|
||||||
@@ -41,7 +42,7 @@ const mousedown = (e) => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const mousemove = (e) => {
|
const mousemove = (e: MouseEvent) => {
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
container.scrollLeft = container.scrollLeft - (e.pageX - x)
|
container.scrollLeft = container.scrollLeft - (e.pageX - x)
|
||||||
container.scrollTop = container.scrollTop - (e.pageY - y)
|
container.scrollTop = container.scrollTop - (e.pageY - y)
|
||||||
@@ -54,7 +55,7 @@ const mousemove = (e) => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const mouseup = (e) => {
|
const mouseup = (e: MouseEvent) => {
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
dragging = false
|
dragging = false
|
||||||
|
|
||||||
@@ -71,9 +72,13 @@ const mouseup = (e) => {
|
|||||||
bind:this={container}
|
bind:this={container}
|
||||||
class="container"
|
class="container"
|
||||||
class:zoom
|
class:zoom
|
||||||
use:swipe_nav={{enabled: !zoom, prev: swipe_prev, next: swipe_next}}
|
use:swipe_nav={{
|
||||||
on:prev={() => nav.open_sibling(-1)}
|
enabled: !zoom,
|
||||||
on:next={() => nav.open_sibling(1)}
|
prev: swipe_prev,
|
||||||
|
next: swipe_next,
|
||||||
|
on_prev: () => nav.open_sibling(-1),
|
||||||
|
on_next: () => nav.open_sibling(1),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
<img
|
<img
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { fs_path_url } from "filesystem/FilesystemAPI.mjs";
|
import { fs_path_url } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<iframe
|
<iframe
|
||||||
|
@@ -1,14 +1,15 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import { fs_path_url } from "filesystem/FilesystemAPI.mjs";
|
import { fs_path_url, type FSNode } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
let text_type = "text"
|
let text_type = "text"
|
||||||
|
|
||||||
export const update = () => {
|
export const update = () => {
|
||||||
console.debug("Loading text file", nav.base.name)
|
console.debug("Loading text file", nav.base.name)
|
||||||
|
|
||||||
if (nav.base.size > 1 << 21) { // File larger than 2 MiB
|
if (nav.base.file_size > 1 << 21) { // File larger than 2 MiB
|
||||||
text_pre.innerText = "File is too large to view online.\nPlease download and view it locally."
|
text_pre.innerText = "File is too large to view online.\nPlease download and view it locally."
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -24,8 +25,8 @@ export const update = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_pre
|
let text_pre: HTMLPreElement
|
||||||
const text = async file => {
|
const text = async (file: FSNode) => {
|
||||||
text_type = "text"
|
text_type = "text"
|
||||||
await tick()
|
await tick()
|
||||||
|
|
||||||
@@ -41,8 +42,8 @@ const text = async file => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let md_container
|
let md_container: HTMLElement
|
||||||
const markdown = async file => {
|
const markdown = async (file: FSNode) => {
|
||||||
text_type = "markdown"
|
text_type = "markdown"
|
||||||
await tick()
|
await tick()
|
||||||
|
|
||||||
|
@@ -1,16 +1,31 @@
|
|||||||
<script>
|
<script lang="ts" context="module">
|
||||||
|
export type TorrentInfo = {
|
||||||
|
trackers: string[]
|
||||||
|
comment: string,
|
||||||
|
created_by: string,
|
||||||
|
created_at: string,
|
||||||
|
info_hash: string,
|
||||||
|
files: TorrentFile
|
||||||
|
};
|
||||||
|
export type TorrentFile = {
|
||||||
|
size: number,
|
||||||
|
children?: {[index: string]: TorrentFile}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import Magnet from "icons/Magnet.svelte";
|
import Magnet from "icons/Magnet.svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte"
|
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 "filesystem/FilesystemAPI.mjs";
|
import { fs_node_icon, fs_path_url } from "filesystem/FilesystemAPI";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
|
|
||||||
let status = "loading"
|
let status = "loading"
|
||||||
|
|
||||||
@@ -48,15 +63,7 @@ export const update = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let torrent = {
|
let torrent: TorrentInfo = {} as TorrentInfo
|
||||||
trackers: [],
|
|
||||||
comment: "",
|
|
||||||
created_by: "",
|
|
||||||
created_at: "",
|
|
||||||
info_hash: "",
|
|
||||||
files: null,
|
|
||||||
}
|
|
||||||
|
|
||||||
let magnet = ""
|
let magnet = ""
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
|
import type { TorrentFile } from "./Torrent.svelte";
|
||||||
|
|
||||||
export let item = {
|
export let item: TorrentFile = {} as TorrentFile
|
||||||
size: 0,
|
|
||||||
children: null,
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ul class="list_open">
|
<ul class="list_open">
|
||||||
|
@@ -1,16 +1,17 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount, createEventDispatcher, tick } from "svelte";
|
import { onMount, createEventDispatcher, tick } from "svelte";
|
||||||
import { video_position } from "lib/VideoPosition.mjs";
|
import { video_position } from "lib/VideoPosition";
|
||||||
import { fs_path_url } from "filesystem/FilesystemAPI.mjs";
|
import { fs_path_url } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
|
|
||||||
// Used to detect when the file path changes
|
// Used to detect when the file path changes
|
||||||
let last_path = ""
|
let last_path = ""
|
||||||
let loaded = false
|
let loaded = false
|
||||||
|
|
||||||
let player
|
let player: HTMLVideoElement
|
||||||
let playing = false
|
let playing = false
|
||||||
let media_session = false
|
let media_session = false
|
||||||
let loop = false
|
let loop = false
|
||||||
@@ -64,13 +65,13 @@ onMount(() => {
|
|||||||
media_session = true
|
media_session = true
|
||||||
navigator.mediaSession.setActionHandler('play', () => player.play());
|
navigator.mediaSession.setActionHandler('play', () => player.play());
|
||||||
navigator.mediaSession.setActionHandler('pause', () => player.pause());
|
navigator.mediaSession.setActionHandler('pause', () => player.pause());
|
||||||
navigator.mediaSession.setActionHandler('stop', () => player.stop());
|
navigator.mediaSession.setActionHandler('stop', () => player.pause());
|
||||||
navigator.mediaSession.setActionHandler('previoustrack', () => dispatch("open_sibling", -1));
|
navigator.mediaSession.setActionHandler('previoustrack', () => dispatch("open_sibling", -1));
|
||||||
navigator.mediaSession.setActionHandler('nexttrack', () => dispatch("open_sibling", 1));
|
navigator.mediaSession.setActionHandler('nexttrack', () => dispatch("open_sibling", 1));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const video_keydown = e => {
|
const video_keydown = (e: KeyboardEvent) => {
|
||||||
if (e.key === " ") {
|
if (e.key === " ") {
|
||||||
// Prevent spacebar from pausing playback in Chromium. This conflicts
|
// Prevent spacebar from pausing playback in Chromium. This conflicts
|
||||||
// with our own global key handler, causing the video to immediately
|
// with our own global key handler, causing the video to immediately
|
||||||
@@ -78,7 +79,6 @@ const video_keydown = e => {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
@@ -1,21 +1,28 @@
|
|||||||
<script>
|
<script lang="ts" context="module">
|
||||||
|
export type ZipEntry = {
|
||||||
|
size: number,
|
||||||
|
children?: {[index: string]: ZipEntry},
|
||||||
|
properties?: string[],
|
||||||
|
download_url?: string, // Added by us
|
||||||
|
details_open?: boolean, // Added by us
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { formatDataVolume, formatDate } from "util/Formatting.svelte"
|
import { formatDataVolume, formatDate } from "util/Formatting"
|
||||||
import ZipItem from "file_viewer/viewers/ZipItem.svelte";
|
import ZipItem from "file_viewer/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 "filesystem/FilesystemAPI.mjs";
|
import { fs_node_icon, fs_path_url } from "filesystem/FilesystemAPI";
|
||||||
|
import type { FSNavigator } from "filesystem/FSNavigator";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let nav
|
export let nav: FSNavigator
|
||||||
|
|
||||||
let status = "loading"
|
let status = "loading"
|
||||||
|
|
||||||
let zip = {
|
let zip: ZipEntry = {size: 0} as ZipEntry
|
||||||
size: 0,
|
|
||||||
children: [],
|
|
||||||
}
|
|
||||||
let uncomp_size = 0
|
let uncomp_size = 0
|
||||||
let comp_ratio = 0
|
let comp_ratio = 0
|
||||||
let archive_type = ""
|
let archive_type = ""
|
||||||
@@ -38,7 +45,7 @@ export const update = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
zip = await resp.json()
|
zip = await resp.json() as ZipEntry
|
||||||
|
|
||||||
// Check if the zip has the property which allows separate files to be
|
// Check if the zip has the property which allows separate files to be
|
||||||
// downloaded. If so then we set the download URL for each file
|
// downloaded. If so then we set the download URL for each file
|
||||||
@@ -61,25 +68,23 @@ export const update = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const recursive_set_url = (parent_path, file) => {
|
const recursive_set_url = (parent_path: string, file: ZipEntry) => {
|
||||||
file.download_url = parent_path
|
file.download_url = parent_path
|
||||||
|
|
||||||
if (file.children) {
|
if (file.children !== undefined) {
|
||||||
Object.entries(file.children).forEach(child => {
|
for (const [name, child] of Object.entries(file.children)) {
|
||||||
recursive_set_url(file.download_url + "/" + child[0], child[1])
|
recursive_set_url(file.download_url + "/" + name, child)
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const recursive_size = (file) => {
|
const recursive_size = (file: ZipEntry) => {
|
||||||
let size = file.size
|
let size = file.size
|
||||||
|
|
||||||
// If the file has children (array is iterable) we call this function on all
|
if (file.children !== undefined) {
|
||||||
// the children and add the size to our size accumulator
|
for (const v of Object.values(file.children)) {
|
||||||
if (file.children.forEach) {
|
size += recursive_size(v)
|
||||||
file.children.forEach(child => {
|
}
|
||||||
size += recursive_size(child)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the total size of this file and all its children
|
// Return the total size of this file and all its children
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Expandable from "util/Expandable.svelte";
|
import Expandable from "util/Expandable.svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
|
|
||||||
let result = null;
|
let result = null;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { add_upload_history, domain_url } from "util/Util.svelte"
|
import { add_upload_history, domain_url } from "util/Util.svelte"
|
||||||
import { formatDataVolume, formatDuration } from "util/Formatting.svelte"
|
import { formatDataVolume, formatDuration } from "util/Formatting"
|
||||||
import Spinner from "util/Spinner.svelte";
|
import Spinner from "util/Spinner.svelte";
|
||||||
|
|
||||||
export let job = {}
|
export let job = {}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDataVolume, formatDuration } from "util/Formatting.svelte";
|
import { formatDataVolume, formatDuration } from "util/Formatting";
|
||||||
import ProgressBar from "util/ProgressBar.svelte";
|
import ProgressBar from "util/ProgressBar.svelte";
|
||||||
|
|
||||||
export let upload_queue = []
|
export let upload_queue = []
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
export let highlight = false;
|
export let highlight = false;
|
||||||
export let highlight_on_click = false
|
export let highlight_on_click = false
|
||||||
export let red = false;
|
export let red = false;
|
||||||
@@ -11,12 +11,12 @@ export let label = ""
|
|||||||
export let title = null
|
export let title = null
|
||||||
export let link_href = ""
|
export let link_href = ""
|
||||||
export let link_target = "_self"
|
export let link_target = "_self"
|
||||||
export let click = e => {}
|
export let click: (e?: MouseEvent) => void = null
|
||||||
export let style = null
|
export let style = null
|
||||||
export let type = null
|
export let type = null
|
||||||
export let form = null
|
export let form = null
|
||||||
|
|
||||||
let click_int = e => {
|
let click_int = (e: MouseEvent) => {
|
||||||
if (highlight_on_click) {
|
if (highlight_on_click) {
|
||||||
try {
|
try {
|
||||||
click(e)
|
click(e)
|
||||||
@@ -25,7 +25,7 @@ let click_int = e => {
|
|||||||
red = true
|
red = true
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
} else {
|
} else if (click !== null) {
|
||||||
click(e)
|
click(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ let click_int = e => {
|
|||||||
style={style}
|
style={style}
|
||||||
type={type}
|
type={type}
|
||||||
form={form}
|
form={form}
|
||||||
disabled={disabled ? "disabled":null}
|
disabled={disabled ? true:null}
|
||||||
>
|
>
|
||||||
{#if icon !== ""}
|
{#if icon !== ""}
|
||||||
<i class="icon" class:small={icon_small}>{icon}</i>
|
<i class="icon" class:small={icon_small}>{icon}</i>
|
||||||
@@ -63,7 +63,6 @@ let click_int = e => {
|
|||||||
class:flat
|
class:flat
|
||||||
title={title}
|
title={title}
|
||||||
style={style}
|
style={style}
|
||||||
disabled={disabled ? "disabled":null}
|
|
||||||
>
|
>
|
||||||
{#if icon !== ""}
|
{#if icon !== ""}
|
||||||
<i class="icon" class:small={icon_small}>{icon}</i>
|
<i class="icon" class:small={icon_small}>{icon}</i>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { copy_text } from "util/Util.svelte";
|
import { copy_text } from "util/Util.svelte";
|
||||||
|
|
||||||
export let text = ""
|
export let text = ""
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
export let title = ""
|
export let title = ""
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Discord from "icons/Discord.svelte";
|
import Discord from "icons/Discord.svelte";
|
||||||
import Github from "icons/Github.svelte";
|
import Github from "icons/Github.svelte";
|
||||||
import Mastodon from "icons/Mastodon.svelte";
|
import Mastodon from "icons/Mastodon.svelte";
|
||||||
import Patreon from "icons/Patreon.svelte";
|
import Patreon from "icons/Patreon.svelte";
|
||||||
import Reddit from "icons/Reddit.svelte";
|
import Reddit from "icons/Reddit.svelte";
|
||||||
import { formatDataVolumeBits } from "util/Formatting.svelte";
|
import { formatDataVolumeBits } from "util/Formatting";
|
||||||
|
import { get_endpoint, get_hostname } from "lib/PixeldrainAPI";
|
||||||
|
|
||||||
export let nobg = false
|
export let nobg = false
|
||||||
let server_tx = 0
|
let server_tx = 0
|
||||||
@@ -13,7 +14,7 @@ let cache_tx = 0
|
|||||||
let storage_tx = 0
|
let storage_tx = 0
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(window.api_endpoint+"/misc/cluster_speed")
|
const resp = await fetch(get_endpoint()+"/misc/cluster_speed")
|
||||||
if (resp.status >= 400) {
|
if (resp.status >= 400) {
|
||||||
throw Error(await resp.text())
|
throw Error(await resp.text())
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,7 @@ onMount(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<span class="small_footer_text" style="font-size: .75em; line-height: .75em;">
|
<span class="small_footer_text" style="font-size: .75em; line-height: .75em;">
|
||||||
page rendered by {window.server_hostname}
|
page rendered by {get_hostname()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
export let toggle = false;
|
export let toggle = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
export let icon_href = ""
|
export let icon_href = ""
|
||||||
export let width = "750px"
|
export let width = "750px"
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
let nav;
|
import { user } from "lib/UserStore";
|
||||||
|
|
||||||
|
let nav: HTMLElement;
|
||||||
|
|
||||||
export const toggle = () => {
|
export const toggle = () => {
|
||||||
var body = document.getElementById("page_body");
|
var body = document.getElementById("page_body");
|
||||||
@@ -24,11 +26,11 @@ export const reset = () => {
|
|||||||
<a href="/#">Home</a>
|
<a href="/#">Home</a>
|
||||||
<a href="/#prepaid">For Creators</a>
|
<a href="/#prepaid">For Creators</a>
|
||||||
<hr />
|
<hr />
|
||||||
{#if window.user !== ""}
|
{#if $user.username !== ""}
|
||||||
<a href="/user">{window.user.username}</a>
|
<a href="/user">{$user.username}</a>
|
||||||
<a href="/user/filemanager#files">My Files</a>
|
<a href="/user/filemanager#files">My Files</a>
|
||||||
<a href="/user/filemanager#lists">My Albums</a>
|
<a href="/user/filemanager#lists">My Albums</a>
|
||||||
{#if window.user.is_admin}
|
{#if $user.is_admin}
|
||||||
<a href="/user/buckets">Buckets</a>
|
<a href="/user/buckets">Buckets</a>
|
||||||
<a href="/admin">Admin Panel</a>
|
<a href="/admin">Admin Panel</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import { formatDataVolume, formatDuration } from "util/Formatting.svelte";
|
import { formatDataVolume, formatDuration } from "util/Formatting";
|
||||||
import { stats } from "lib/StatsSocket.mjs"
|
import { stats } from "lib/StatsSocket"
|
||||||
import TextBlock from "./TextBlock.svelte"
|
import TextBlock from "./TextBlock.svelte"
|
||||||
import IconBlock from "./IconBlock.svelte";
|
import IconBlock from "./IconBlock.svelte";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
@@ -48,12 +48,18 @@ export const get_endpoint = () => {
|
|||||||
if ((window as any).api_endpoint !== undefined) {
|
if ((window as any).api_endpoint !== undefined) {
|
||||||
return (window as any).api_endpoint as string
|
return (window as any).api_endpoint as string
|
||||||
}
|
}
|
||||||
|
|
||||||
console.warn("api_endpoint property is not defined on window")
|
console.warn("api_endpoint property is not defined on window")
|
||||||
|
|
||||||
return "/api"
|
return "/api"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const get_hostname = () => {
|
||||||
|
if ((window as any).server_hostname !== undefined) {
|
||||||
|
return (window as any).server_hostname as string
|
||||||
|
}
|
||||||
|
console.warn("server_hostname property is not defined on window")
|
||||||
|
return "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
export const check_response = async (resp: Response) => {
|
export const check_response = async (resp: Response) => {
|
||||||
let text = await resp.text()
|
let text = await resp.text()
|
||||||
if (resp.status >= 400) {
|
if (resp.status >= 400) {
|
@@ -3,7 +3,16 @@ const swipe_inital_offset = 25
|
|||||||
// Amount of pixels after which the navigation triggers
|
// Amount of pixels after which the navigation triggers
|
||||||
const swipe_trigger_offset = 75
|
const swipe_trigger_offset = 75
|
||||||
|
|
||||||
export const swipe_nav = (node: HTMLElement, props: { enabled: boolean, prev: boolean, next: boolean }) => {
|
export const swipe_nav = (
|
||||||
|
node: HTMLElement,
|
||||||
|
props: {
|
||||||
|
enabled: boolean,
|
||||||
|
prev: boolean,
|
||||||
|
next: boolean,
|
||||||
|
on_prev: () => void,
|
||||||
|
on_next: () => void,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
let start_x = 0
|
let start_x = 0
|
||||||
let start_y = 0
|
let start_y = 0
|
||||||
let render_offset = 0
|
let render_offset = 0
|
||||||
@@ -43,10 +52,10 @@ export const swipe_nav = (node: HTMLElement, props: { enabled: boolean, prev: bo
|
|||||||
|
|
||||||
if (render_offset > swipe_trigger_offset) {
|
if (render_offset > swipe_trigger_offset) {
|
||||||
set_offset(1000, true)
|
set_offset(1000, true)
|
||||||
node.dispatchEvent(new CustomEvent("prev"))
|
props.on_prev()
|
||||||
} else if (render_offset < -swipe_trigger_offset) {
|
} else if (render_offset < -swipe_trigger_offset) {
|
||||||
set_offset(-1000, true)
|
set_offset(-1000, true)
|
||||||
node.dispatchEvent(new CustomEvent("next"))
|
props.on_next()
|
||||||
} else {
|
} else {
|
||||||
set_offset(0, true)
|
set_offset(0, true)
|
||||||
}
|
}
|
13
svelte/src/lib/UserStore.ts
Normal file
13
svelte/src/lib/UserStore.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
import { get_user, type Subscription, type User } from "./PixeldrainAPI";
|
||||||
|
|
||||||
|
export const user = writable(
|
||||||
|
{ subscription: {} as Subscription } as User,
|
||||||
|
(set: (value: User) => void) => {
|
||||||
|
get_user().then((u: User) => {
|
||||||
|
set(u)
|
||||||
|
}).catch((err: any) => {
|
||||||
|
alert("Could not fetch user:\n" + JSON.stringify(err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
import { createEventDispatcher, onMount } from "svelte";
|
||||||
import Form, { type FormConfig } from "util/Form.svelte"
|
import Form, { type FormConfig } from "util/Form.svelte"
|
||||||
import { check_response, get_endpoint } from "lib/PixeldrainAPI.mjs";
|
import { check_response, get_endpoint } from "lib/PixeldrainAPI";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import Login from "./Login.svelte";
|
import Login from "./Login.svelte";
|
||||||
import Register from "./Register.svelte";
|
import Register from "./Register.svelte";
|
||||||
|
|
||||||
const finish_login = async e => {
|
const finish_login = async () => {
|
||||||
location.reload()
|
location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Form, { type FormConfig } from "util/Form.svelte"
|
import Form, { type FormConfig } from "util/Form.svelte"
|
||||||
import { get_endpoint } from "lib/PixeldrainAPI.mjs";
|
import { get_endpoint } from "lib/PixeldrainAPI";
|
||||||
|
|
||||||
let form: FormConfig = {
|
let form: FormConfig = {
|
||||||
fields: [
|
fields: [
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import TabMenu from "util/TabMenu.svelte";
|
import TabMenu from "util/TabMenu.svelte";
|
||||||
import Register from "./Register.svelte";
|
import Register from "./Register.svelte";
|
||||||
import Login from "./Login.svelte";
|
import Login from "./Login.svelte";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { get_user } from "lib/PixeldrainAPI.mjs";
|
import { get_user } from "lib/PixeldrainAPI";
|
||||||
|
|
||||||
let pages = [
|
let pages = [
|
||||||
{
|
{
|
||||||
@@ -33,4 +33,4 @@ onMount(async () => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<TabMenu pages={pages} title="Login" large_tabs />
|
<TabMenu pages={pages} title="Login" />
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import { formatDataVolume, formatDataVolumeBits } from "util/Formatting.svelte";
|
import { formatDataVolume, formatDataVolumeBits } from "util/Formatting";
|
||||||
import ProgressBar from "util/ProgressBar.svelte";
|
import ProgressBar from "util/ProgressBar.svelte";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import Footer from "layout/Footer.svelte"
|
import Footer from "layout/Footer.svelte"
|
||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte"
|
import LoadingIndicator from "util/LoadingIndicator.svelte"
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Modal from "util/Modal.svelte";
|
import Modal from "util/Modal.svelte";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import { get_user, put_user } from "lib/PixeldrainAPI.mjs";
|
import { get_user, put_user } from "lib/PixeldrainAPI";
|
||||||
|
|
||||||
// When the always flag is set then the pop-up will also show if the user
|
// When the always flag is set then the pop-up will also show if the user
|
||||||
// already has an affiliate ID set
|
// already has an affiliate ID set
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Pro from "icons/Pro.svelte";
|
import Pro from "icons/Pro.svelte";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte";
|
import { formatDataVolume } from "util/Formatting";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import ProgressBar from "util/ProgressBar.svelte";
|
import ProgressBar from "util/ProgressBar.svelte";
|
||||||
import SuccessMessage from "util/SuccessMessage.svelte";
|
import SuccessMessage from "util/SuccessMessage.svelte";
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Euro from "util/Euro.svelte";
|
import Euro from "util/Euro.svelte";
|
||||||
import { formatDate } from "util/Formatting.svelte";
|
import { formatDate } from "util/Formatting";
|
||||||
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
import LoadingIndicator from "util/LoadingIndicator.svelte";
|
||||||
import MollieDeposit from "./MollieDeposit.svelte";
|
import MollieDeposit from "./MollieDeposit.svelte";
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import ProgressBar from "util/ProgressBar.svelte";
|
import ProgressBar from "util/ProgressBar.svelte";
|
||||||
import { formatDataVolume } from "util/Formatting.svelte"
|
import { formatDataVolume } from "util/Formatting"
|
||||||
|
|
||||||
export let total = 0
|
export let total = 0
|
||||||
export let used = 0
|
export let used = 0
|
||||||
|
@@ -3,7 +3,7 @@ import { onMount } from "svelte";
|
|||||||
import Button from "layout/Button.svelte";
|
import Button from "layout/Button.svelte";
|
||||||
import CopyButton from "layout/CopyButton.svelte";
|
import CopyButton from "layout/CopyButton.svelte";
|
||||||
import ToggleButton from "layout/ToggleButton.svelte";
|
import ToggleButton from "layout/ToggleButton.svelte";
|
||||||
import { check_response, get_endpoint, get_user, type User } from "lib/PixeldrainAPI.mjs";
|
import { check_response, get_endpoint, get_user, type User } from "lib/PixeldrainAPI";
|
||||||
|
|
||||||
let user: User = null
|
let user: User = null
|
||||||
let secret = ""
|
let secret = ""
|
||||||
|
@@ -14,7 +14,7 @@ import Dashboard from "./dashboard/Dashboard.svelte";
|
|||||||
import AffiliatePrompt from "./AffiliatePrompt.svelte";
|
import AffiliatePrompt from "./AffiliatePrompt.svelte";
|
||||||
import FileManager from "./filemanager/FileManager.svelte";
|
import FileManager from "./filemanager/FileManager.svelte";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { get_user, type User } from "lib/PixeldrainAPI.mjs";
|
import { get_user, type User } from "lib/PixeldrainAPI";
|
||||||
|
|
||||||
let pages: Tab[] = [
|
let pages: Tab[] = [
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user