Use centralized loading indicator
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount, tick } from "svelte";
|
import { onMount, tick } from "svelte";
|
||||||
import { formatDate, formatDuration } from "../util/Formatting.svelte";
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
|
||||||
import AbuseReporterTable from "./AbuseReporterTable.svelte";
|
import AbuseReporterTable from "./AbuseReporterTable.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
@@ -122,11 +121,7 @@ const delete_reporter = async reporter => {
|
|||||||
onMount(get_reporters);
|
onMount(get_reporters);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="toolbar" style="text-align: left;">
|
<div class="toolbar" style="text-align: left;">
|
||||||
@@ -201,14 +196,6 @@ onMount(get_reporters);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
import AbuseReport from "./AbuseReport.svelte";
|
import AbuseReport from "./AbuseReport.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
@@ -91,11 +91,7 @@ onMount(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="toolbar" style="text-align: left;">
|
<div class="toolbar" style="text-align: left;">
|
||||||
@@ -123,14 +119,6 @@ onMount(() => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDate } from "../util/Formatting.svelte";
|
import { formatDate } from "../util/Formatting.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
|
||||||
import Expandable from "../util/Expandable.svelte";
|
import Expandable from "../util/Expandable.svelte";
|
||||||
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let rows = []
|
let rows = []
|
||||||
@@ -79,11 +79,7 @@ const delete_ban = async (addr) => {
|
|||||||
onMount(get_bans);
|
onMount(get_bans);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
@@ -188,14 +184,6 @@ onMount(get_bans);
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Euro from "../util/Euro.svelte";
|
import Euro from "../util/Euro.svelte";
|
||||||
import Form from "./../util/Form.svelte";
|
import Form from "./../util/Form.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
|
|
||||||
@@ -173,12 +173,9 @@ onMount(get_coupons)
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<LoadingIndicator loading={loading}/>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
{#if loading}
|
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<h2>Give user credit</h2>
|
<h2>Give user credit</h2>
|
||||||
<p>
|
<p>
|
||||||
This adds credit to a user's account. You only need to enter one of
|
This adds credit to a user's account. You only need to enter one of
|
||||||
@@ -222,14 +219,3 @@ onMount(get_coupons)
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@@ -17,10 +17,10 @@ import AdLeaderboard from "./AdLeaderboard.svelte";
|
|||||||
import AdSkyscraper from "./AdSkyscraper.svelte";
|
import AdSkyscraper from "./AdSkyscraper.svelte";
|
||||||
import Sharebar from "./Sharebar.svelte";
|
import Sharebar from "./Sharebar.svelte";
|
||||||
import GalleryView from "./GalleryView.svelte";
|
import GalleryView from "./GalleryView.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
|
||||||
import Downloader from "./Downloader.svelte";
|
import Downloader from "./Downloader.svelte";
|
||||||
import CustomBanner from "./CustomBanner.svelte";
|
import CustomBanner from "./CustomBanner.svelte";
|
||||||
import UkraineModal from "./UkraineModal.svelte";
|
import UkraineModal from "./UkraineModal.svelte";
|
||||||
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let embedded = false
|
let embedded = false
|
||||||
@@ -366,11 +366,7 @@ const keyboard_event = evt => {
|
|||||||
<!-- Head elements for the ads -->
|
<!-- Head elements for the ads -->
|
||||||
<AdHead></AdHead>
|
<AdHead></AdHead>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner></Spinner>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div id="headerbar" class="headerbar">
|
<div id="headerbar" class="headerbar">
|
||||||
<button
|
<button
|
||||||
@@ -618,15 +614,6 @@ const keyboard_event = evt => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
right: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file_viewer {
|
.file_viewer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -3,7 +3,6 @@ import { onMount } from 'svelte';
|
|||||||
import { formatDate, formatDataVolume, formatThousands } from '../util/Formatting.svelte'
|
import { formatDate, formatDataVolume, formatThousands } from '../util/Formatting.svelte'
|
||||||
import { fs_get_file_url, fs_get_node } from './FilesystemAPI.svelte'
|
import { fs_get_file_url, fs_get_node } from './FilesystemAPI.svelte'
|
||||||
import Sharebar from './Sharebar.svelte'
|
import Sharebar from './Sharebar.svelte'
|
||||||
import Spinner from '../util/Spinner.svelte'
|
|
||||||
import Modal from '../util/Modal.svelte'
|
import Modal from '../util/Modal.svelte'
|
||||||
import FileManager from './filemanager/FileManager.svelte';
|
import FileManager from './filemanager/FileManager.svelte';
|
||||||
import Audio from './viewers/Audio.svelte';
|
import Audio from './viewers/Audio.svelte';
|
||||||
@@ -11,6 +10,7 @@ import Image from './viewers/Image.svelte';
|
|||||||
import Video from './viewers/Video.svelte';
|
import Video from './viewers/Video.svelte';
|
||||||
import PDF from './viewers/PDF.svelte';
|
import PDF from './viewers/PDF.svelte';
|
||||||
import PixeldrainLogo from '../util/PixeldrainLogo.svelte';
|
import PixeldrainLogo from '../util/PixeldrainLogo.svelte';
|
||||||
|
import LoadingIndicator from '../util/LoadingIndicator.svelte';
|
||||||
|
|
||||||
// Elements
|
// Elements
|
||||||
let file_viewer
|
let file_viewer
|
||||||
@@ -271,13 +271,9 @@ const share = () => {
|
|||||||
|
|
||||||
<svelte:window on:keydown={keydown} />
|
<svelte:window on:keydown={keydown} />
|
||||||
|
|
||||||
<div bind:this={file_viewer} class="file_viewer">
|
<LoadingIndicator loading={state.loading}/>
|
||||||
{#if state.loading}
|
|
||||||
<div style="position: absolute; right: 0; top: 0; height: 48px; width: 48px; z-index: 100;">
|
|
||||||
<Spinner></Spinner>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
|
<div bind:this={file_viewer} class="file_viewer">
|
||||||
<div bind:this={header_bar} class="file_viewer_headerbar">
|
<div bind:this={header_bar} class="file_viewer_headerbar">
|
||||||
<button on:click={toolbar_toggle} class="button_toggle_toolbar round" class:button_highlight={toolbar_visible}>
|
<button on:click={toolbar_toggle} class="button_toggle_toolbar round" class:button_highlight={toolbar_visible}>
|
||||||
<i class="icon">menu</i>
|
<i class="icon">menu</i>
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import UserBucket from "./UserBucket.svelte";
|
import UserBucket from "./UserBucket.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
|
||||||
import { fs_get_buckets, fs_create_bucket } from "../filesystem/FilesystemAPI.svelte";
|
import { fs_get_buckets, fs_create_bucket } from "../filesystem/FilesystemAPI.svelte";
|
||||||
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let buckets = []
|
let buckets = []
|
||||||
@@ -41,11 +41,7 @@ const create_bucket = async () => {
|
|||||||
onMount(get_buckets);
|
onMount(get_buckets);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="toolbar" style="text-align: right;">
|
<div class="toolbar" style="text-align: right;">
|
||||||
@@ -84,13 +80,3 @@ onMount(get_buckets);
|
|||||||
<UserBucket bucket={bucket} on:refresh={get_buckets}></UserBucket>
|
<UserBucket bucket={bucket} on:refresh={get_buckets}></UserBucket>
|
||||||
{/each}
|
{/each}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { formatDate } from "../util/Formatting.svelte";
|
import { formatDate } from "../util/Formatting.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
let loaded = false
|
let loaded = false
|
||||||
@@ -82,11 +82,7 @@ const logout = async (key) => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
{#if !loaded}
|
{#if !loaded}
|
||||||
@@ -164,14 +160,6 @@ const logout = async (key) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@@ -139,75 +139,6 @@ let delete_account = {
|
|||||||
return {success: true, message: "Success! Your account has been scheduled for deletion in 7 days"}
|
return {success: true, message: "Success! Your account has been scheduled for deletion in 7 days"}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let success_message
|
|
||||||
let changes_made = false
|
|
||||||
|
|
||||||
let file_picker
|
|
||||||
let currently_selecting = "" // header, background or footer
|
|
||||||
|
|
||||||
let theme = ""
|
|
||||||
let header_image = ""
|
|
||||||
let background_image = ""
|
|
||||||
let footer_image = ""
|
|
||||||
|
|
||||||
let select_file = t => {
|
|
||||||
currently_selecting = t
|
|
||||||
file_picker.open()
|
|
||||||
}
|
|
||||||
let add_file = files => {
|
|
||||||
let type = files[0].type
|
|
||||||
if (type != "image/png" && type != "image/jpeg" && type != "image/gif" && type != "image/webp") {
|
|
||||||
success_message.set(false, "File must be an image type")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (files[0].size > 10e6) {
|
|
||||||
success_message.set(false, "Files larger than 10 MB are not allowed. Recommended size is below 1 MB")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currently_selecting === "header") {
|
|
||||||
header_image = files[0].id
|
|
||||||
} else if (currently_selecting === "background") {
|
|
||||||
background_image = files[0].id
|
|
||||||
} else if (currently_selecting === "footer") {
|
|
||||||
footer_image = files[0].id
|
|
||||||
}
|
|
||||||
|
|
||||||
changes_made = true
|
|
||||||
}
|
|
||||||
let save = async () => {
|
|
||||||
const form = new FormData()
|
|
||||||
form.append("theme", theme)
|
|
||||||
form.append("header_image", header_image)
|
|
||||||
form.append("background_image", background_image)
|
|
||||||
form.append("footer_image", footer_image)
|
|
||||||
|
|
||||||
const resp = await fetch(
|
|
||||||
window.api_endpoint+"/user/file_customization",
|
|
||||||
{ method: "PUT", body: form }
|
|
||||||
);
|
|
||||||
if(resp.status >= 400) {
|
|
||||||
let json = await resp.json()
|
|
||||||
console.debug(json)
|
|
||||||
success_message.set(false, json.message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
success_message.set(true, "Changes saved")
|
|
||||||
changes_made = false
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (window.user.file_viewer_branding) {
|
|
||||||
let b = window.user.file_viewer_branding
|
|
||||||
theme = b.theme ? b.theme : ""
|
|
||||||
header_image = b.header_image ? b.header_image : ""
|
|
||||||
background_image = b.background_image ? b.background_image : ""
|
|
||||||
footer_image = b.footer_image ? b.footer_image : ""
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
@@ -223,125 +154,4 @@ onMount(() => {
|
|||||||
|
|
||||||
<h3>Delete account</h3>
|
<h3>Delete account</h3>
|
||||||
<Form config={delete_account}></Form>
|
<Form config={delete_account}></Form>
|
||||||
|
|
||||||
<h2>File viewer branding</h2>
|
|
||||||
{#if !window.user.subscription.file_viewer_branding}
|
|
||||||
<div class="highlight_red">
|
|
||||||
File viewer branding is not available for your account. Subscribe to
|
|
||||||
the Persistence plan or higher to enable this feature.
|
|
||||||
</div>
|
|
||||||
{:else if !window.user.hotlinking_enabled}
|
|
||||||
<div class="highlight_red">
|
|
||||||
To use the branding feature bandwidth sharing needs to be enabled.
|
|
||||||
Without this the custom images will not be able to load. Enable
|
|
||||||
bandwidth sharing on the
|
|
||||||
<a href="/user/subscription">subscription page</a>.
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<SuccessMessage bind:this={success_message}></SuccessMessage>
|
|
||||||
<p>
|
|
||||||
You can change the appearance of your file viewer pages. The images you
|
|
||||||
choose here will be loaded each time someone visits one of your files.
|
|
||||||
The data usage will also be subtracted from your account's data cap.
|
|
||||||
Keep in mind that large images can take a very long time to load over
|
|
||||||
cellular connections. I recommend keeping the header and footer images
|
|
||||||
below 100 kB, and the background image below 1 MB. Allowed image types
|
|
||||||
are PNG, JPEG, GIF and WebP. If you want to use an animated banner you
|
|
||||||
should use APNG or WebP. Avoid using animated GIFs as they are very slow
|
|
||||||
to load.
|
|
||||||
</p>
|
|
||||||
<h3>Theme</h3>
|
|
||||||
<p>
|
|
||||||
Choose a theme for your download pages. This theme will override the
|
|
||||||
theme preference of the person viewing the file. Set to 'None' to let
|
|
||||||
the viewer choose their own theme.
|
|
||||||
</p>
|
|
||||||
<ThemePicker
|
|
||||||
theme={theme}
|
|
||||||
on:theme_change={e => {theme = e.detail; changes_made = true}}>
|
|
||||||
</ThemePicker>
|
|
||||||
|
|
||||||
<h3>Header image</h3>
|
|
||||||
<p>
|
|
||||||
Will be shown above the file. Maximum height is 90px. Will be shrunk if
|
|
||||||
larger.
|
|
||||||
</p>
|
|
||||||
<button on:click={() => {select_file("header")}}>
|
|
||||||
<i class="icon">add_photo_alternate</i>
|
|
||||||
Select header image
|
|
||||||
</button>
|
|
||||||
<button on:click={() => {header_image = ""}}>
|
|
||||||
<i class="icon">close</i>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
{#if header_image}
|
|
||||||
<div class="highlight_shaded">
|
|
||||||
<img class="banner_preview" src="/api/file/{header_image}" alt="Custom file viewer header"/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<h3>Background image</h3>
|
|
||||||
<p>
|
|
||||||
This image will be shown behind the file which is being viewed. I
|
|
||||||
recommend choosing something dark and not too distracting. Try to keep
|
|
||||||
the file below 1 MB to not harm page loading times. Using a JPEG image
|
|
||||||
with a quality value of 60 is usually good enough.
|
|
||||||
</p>
|
|
||||||
<button on:click={() => {select_file("background")}}>
|
|
||||||
<i class="icon">add_photo_alternate</i>
|
|
||||||
Select background image
|
|
||||||
</button>
|
|
||||||
<button on:click={() => {background_image = ""}}>
|
|
||||||
<i class="icon">close</i>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
{#if background_image}
|
|
||||||
<div class="highlight_shaded">
|
|
||||||
<img class="background_preview" src="/api/file/{background_image}" alt="Custom file viewer background"/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<h3>Footer image</h3>
|
|
||||||
<p>
|
|
||||||
Will be shown below the file. Maximum height is 90px. Will be shrunk if
|
|
||||||
larger.
|
|
||||||
</p>
|
|
||||||
<button on:click={() => {select_file("footer")}}>
|
|
||||||
<i class="icon">add_photo_alternate</i>
|
|
||||||
Select footer image
|
|
||||||
</button>
|
|
||||||
<button on:click={() => {footer_image = ""}}>
|
|
||||||
<i class="icon">close</i>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
{#if footer_image}
|
|
||||||
<div class="highlight_shaded">
|
|
||||||
<img class="banner_preview" src="/api/file/{footer_image}" alt="Custom file viewer footer"/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
<button on:click={save} class:button_highlight={changes_made}>
|
|
||||||
<i class="icon">save</i> Save
|
|
||||||
</button>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<FilePicker bind:this={file_picker} on:files={e => {add_file(e.detail)}} multi_select={false} title="Select image file"></FilePicker>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.banner_preview {
|
|
||||||
max-height: 90px;
|
|
||||||
max-width: 100%;
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
.background_preview {
|
|
||||||
max-height: 200px;
|
|
||||||
max-width: 100%;
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@@ -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.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
|
|
||||||
@@ -59,11 +59,7 @@ onMount(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Account activity log</h2>
|
<h2>Account activity log</h2>
|
||||||
@@ -134,14 +130,6 @@ onMount(() => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
import { copy_text } from "../util/Util.svelte";
|
import { copy_text } from "../util/Util.svelte";
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
@@ -55,11 +55,7 @@ onMount(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<!-- Show a back button if an app is selected -->
|
<!-- Show a back button if an app is selected -->
|
||||||
@@ -200,15 +196,6 @@ onMount(() => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app_icon {
|
.app_icon {
|
||||||
height: 1.6em;
|
height: 1.6em;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
@@ -7,6 +7,7 @@ import Transactions from "./Transactions.svelte";
|
|||||||
import Subscription from "./Subscription.svelte";
|
import Subscription from "./Subscription.svelte";
|
||||||
import ConnectApp from "./ConnectApp.svelte";
|
import ConnectApp from "./ConnectApp.svelte";
|
||||||
import ActivityLog from "./ActivityLog.svelte";
|
import ActivityLog from "./ActivityLog.svelte";
|
||||||
|
import SharingSettings from "./SharingSettings.svelte";
|
||||||
|
|
||||||
let page = ""
|
let page = ""
|
||||||
|
|
||||||
@@ -52,6 +53,13 @@ onMount(() => {
|
|||||||
<i class="icon">settings</i><br/>
|
<i class="icon">settings</i><br/>
|
||||||
Settings
|
Settings
|
||||||
</a>
|
</a>
|
||||||
|
<a class="button"
|
||||||
|
href="/user/sharing"
|
||||||
|
class:button_highlight={page === "sharing"}
|
||||||
|
on:click|preventDefault={() => {navigate("sharing", "Sharing")}}>
|
||||||
|
<i class="icon">share</i><br/>
|
||||||
|
Sharing
|
||||||
|
</a>
|
||||||
<a class="button"
|
<a class="button"
|
||||||
href="/user/connect_app"
|
href="/user/connect_app"
|
||||||
class:button_highlight={page === "connect_app"}
|
class:button_highlight={page === "connect_app"}
|
||||||
@@ -97,6 +105,8 @@ onMount(() => {
|
|||||||
<Home/>
|
<Home/>
|
||||||
{:else if page === "settings"}
|
{:else if page === "settings"}
|
||||||
<AccountSettings/>
|
<AccountSettings/>
|
||||||
|
{:else if page === "sharing"}
|
||||||
|
<SharingSettings/>
|
||||||
{:else if page === "api_keys"}
|
{:else if page === "api_keys"}
|
||||||
<APIKeys/>
|
<APIKeys/>
|
||||||
{:else if page === "activity"}
|
{:else if page === "activity"}
|
||||||
|
197
svelte/src/user_home/SharingSettings.svelte
Normal file
197
svelte/src/user_home/SharingSettings.svelte
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import FilePicker from "../file_viewer/FilePicker.svelte";
|
||||||
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
import SuccessMessage from "../util/SuccessMessage.svelte";
|
||||||
|
import ThemePicker from "../util/ThemePicker.svelte";
|
||||||
|
|
||||||
|
let loading = false
|
||||||
|
let success_message
|
||||||
|
|
||||||
|
let file_picker
|
||||||
|
let currently_selecting = "" // header, background or footer
|
||||||
|
|
||||||
|
let theme = ""
|
||||||
|
let header_image = ""
|
||||||
|
let background_image = ""
|
||||||
|
let footer_image = ""
|
||||||
|
|
||||||
|
let select_file = t => {
|
||||||
|
currently_selecting = t
|
||||||
|
file_picker.open()
|
||||||
|
}
|
||||||
|
let add_file = files => {
|
||||||
|
let type = files[0].type
|
||||||
|
if (type != "image/png" && type != "image/jpeg" && type != "image/gif" && type != "image/webp") {
|
||||||
|
success_message.set(false, "File must be an image type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (files[0].size > 10e6) {
|
||||||
|
success_message.set(false, "Files larger than 10 MB are not allowed. Recommended size is below 1 MB")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currently_selecting === "header") {
|
||||||
|
header_image = files[0].id
|
||||||
|
} else if (currently_selecting === "background") {
|
||||||
|
background_image = files[0].id
|
||||||
|
} else if (currently_selecting === "footer") {
|
||||||
|
footer_image = files[0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
save()
|
||||||
|
}
|
||||||
|
|
||||||
|
let save = async () => {
|
||||||
|
loading = true
|
||||||
|
const form = new FormData()
|
||||||
|
form.append("theme", theme)
|
||||||
|
form.append("header_image", header_image)
|
||||||
|
form.append("background_image", background_image)
|
||||||
|
form.append("footer_image", footer_image)
|
||||||
|
|
||||||
|
const resp = await fetch(
|
||||||
|
window.api_endpoint+"/user/file_customization",
|
||||||
|
{ method: "PUT", body: form }
|
||||||
|
);
|
||||||
|
if(resp.status >= 400) {
|
||||||
|
let json = await resp.json()
|
||||||
|
console.debug(json)
|
||||||
|
success_message.set(false, json.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
success_message.set(true, "Changes saved")
|
||||||
|
loading = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (window.user.file_viewer_branding) {
|
||||||
|
let b = window.user.file_viewer_branding
|
||||||
|
theme = b.theme ? b.theme : ""
|
||||||
|
header_image = b.header_image ? b.header_image : ""
|
||||||
|
background_image = b.background_image ? b.background_image : ""
|
||||||
|
footer_image = b.footer_image ? b.footer_image : ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<LoadingIndicator loading={loading}/>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>File viewer branding</h2>
|
||||||
|
{#if !window.user.subscription.file_viewer_branding}
|
||||||
|
<div class="highlight_red">
|
||||||
|
File viewer branding is not available for your account. Subscribe to
|
||||||
|
the Persistence plan or higher to enable this feature.
|
||||||
|
</div>
|
||||||
|
{:else if !window.user.hotlinking_enabled}
|
||||||
|
<div class="highlight_red">
|
||||||
|
To use the branding feature bandwidth sharing needs to be enabled.
|
||||||
|
Without this the custom images will not be able to load. Enable
|
||||||
|
bandwidth sharing on the
|
||||||
|
<a href="/user/subscription">subscription page</a>.
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<SuccessMessage bind:this={success_message}></SuccessMessage>
|
||||||
|
<p>
|
||||||
|
You can change the appearance of your file viewer pages. The images you
|
||||||
|
choose here will be loaded each time someone visits one of your files.
|
||||||
|
The data usage will also be subtracted from your account's data cap.
|
||||||
|
Keep in mind that large images can take a very long time to load over
|
||||||
|
cellular connections. I recommend keeping the header and footer images
|
||||||
|
below 100 kB, and the background image below 1 MB. Allowed image types
|
||||||
|
are PNG, JPEG, GIF and WebP. If you want to use an animated banner you
|
||||||
|
should use APNG or WebP. Avoid using animated GIFs as they are very slow
|
||||||
|
to load.
|
||||||
|
</p>
|
||||||
|
<h3>Theme</h3>
|
||||||
|
<p>
|
||||||
|
Choose a theme for your download pages. This theme will override the
|
||||||
|
theme preference of the person viewing the file. Set to 'None' to let
|
||||||
|
the viewer choose their own theme.
|
||||||
|
</p>
|
||||||
|
<ThemePicker
|
||||||
|
theme={theme}
|
||||||
|
on:theme_change={e => {theme = e.detail; save()}}>
|
||||||
|
</ThemePicker>
|
||||||
|
|
||||||
|
<h3>Header image</h3>
|
||||||
|
<p>
|
||||||
|
Will be shown above the file. Maximum height is 90px. Will be shrunk if
|
||||||
|
larger.
|
||||||
|
</p>
|
||||||
|
<button on:click={() => {select_file("header")}}>
|
||||||
|
<i class="icon">add_photo_alternate</i>
|
||||||
|
Select header image
|
||||||
|
</button>
|
||||||
|
<button on:click={() => {header_image = ""; save()}}>
|
||||||
|
<i class="icon">close</i>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
{#if header_image}
|
||||||
|
<div class="highlight_shaded">
|
||||||
|
<img class="banner_preview" src="/api/file/{header_image}" alt="Custom file viewer header"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<h3>Background image</h3>
|
||||||
|
<p>
|
||||||
|
This image will be shown behind the file which is being viewed. I
|
||||||
|
recommend choosing something dark and not too distracting. Try to keep
|
||||||
|
the file below 1 MB to not harm page loading times. Using a JPEG image
|
||||||
|
with a quality value of 60 is usually good enough.
|
||||||
|
</p>
|
||||||
|
<button on:click={() => {select_file("background")}}>
|
||||||
|
<i class="icon">add_photo_alternate</i>
|
||||||
|
Select background image
|
||||||
|
</button>
|
||||||
|
<button on:click={() => {background_image = ""; save()}}>
|
||||||
|
<i class="icon">close</i>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
{#if background_image}
|
||||||
|
<div class="highlight_shaded">
|
||||||
|
<img class="background_preview" src="/api/file/{background_image}" alt="Custom file viewer background"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<h3>Footer image</h3>
|
||||||
|
<p>
|
||||||
|
Will be shown below the file. Maximum height is 90px. Will be shrunk if
|
||||||
|
larger.
|
||||||
|
</p>
|
||||||
|
<button on:click={() => {select_file("footer")}}>
|
||||||
|
<i class="icon">add_photo_alternate</i>
|
||||||
|
Select footer image
|
||||||
|
</button>
|
||||||
|
<button on:click={() => {footer_image = ""; save()}}>
|
||||||
|
<i class="icon">close</i>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
{#if footer_image}
|
||||||
|
<div class="highlight_shaded">
|
||||||
|
<img class="banner_preview" src="/api/file/{footer_image}" alt="Custom file viewer footer"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<FilePicker bind:this={file_picker} on:files={e => {add_file(e.detail)}} multi_select={false} title="Select image file"></FilePicker>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.banner_preview {
|
||||||
|
max-height: 90px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.background_preview {
|
||||||
|
max-height: 200px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,9 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import Spinner from "../util/Spinner.svelte";
|
|
||||||
import Euro from "../util/Euro.svelte"
|
import Euro from "../util/Euro.svelte"
|
||||||
import ProgressBar from "../util/ProgressBar.svelte";
|
import ProgressBar from "../util/ProgressBar.svelte";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDataVolume } from "../util/Formatting.svelte";
|
import { formatDataVolume } from "../util/Formatting.svelte";
|
||||||
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
let subscription = window.user.subscription.id
|
let subscription = window.user.subscription.id
|
||||||
@@ -73,11 +73,8 @@ onMount(load_tranfer_used)
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if loading}
|
<LoadingIndicator loading={loading}/>
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Manage subscription</h2>
|
<h2>Manage subscription</h2>
|
||||||
{#if window.user.subscription.type !== "patreon"}
|
{#if window.user.subscription.type !== "patreon"}
|
||||||
@@ -237,15 +234,6 @@ onMount(load_tranfer_used)
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.green {
|
.green {
|
||||||
color: var(--highlight_color);
|
color: var(--highlight_color);
|
||||||
}
|
}
|
||||||
@@ -257,15 +245,6 @@ onMount(load_tranfer_used)
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.feat_table {
|
.feat_table {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { formatDataVolume, formatDate } from "../util/Formatting.svelte";
|
import { formatDataVolume, formatDate } from "../util/Formatting.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
|
||||||
import Euro from "../util/Euro.svelte"
|
import Euro from "../util/Euro.svelte"
|
||||||
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
|
|
||||||
@@ -135,12 +135,9 @@ onMount(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<LoadingIndicator loading={loading}/>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
{#if loading}
|
|
||||||
<div class="spinner_container">
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<h2>Deposit credits</h2>
|
<h2>Deposit credits</h2>
|
||||||
<p>
|
<p>
|
||||||
You can deposit credit on your pixeldrain account with Bitcoin,
|
You can deposit credit on your pixeldrain account with Bitcoin,
|
||||||
@@ -301,14 +298,6 @@ onMount(() => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner_container {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
22
svelte/src/util/LoadingIndicator.svelte
Normal file
22
svelte/src/util/LoadingIndicator.svelte
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script>
|
||||||
|
import Spinner from "./Spinner.svelte";
|
||||||
|
|
||||||
|
export let loading = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<div class="container">
|
||||||
|
<Spinner/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
position: fixed;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -181,6 +181,7 @@ func New(
|
|||||||
{GET, "user" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
{GET, "user" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
||||||
{GET, "user/home" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
{GET, "user/home" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
||||||
{GET, "user/settings" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
{GET, "user/settings" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
||||||
|
{GET, "user/sharing" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
||||||
{GET, "user/api_keys" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
{GET, "user/api_keys" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
||||||
{GET, "user/activity" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
{GET, "user/activity" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
||||||
{GET, "user/connect_app" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
{GET, "user/connect_app" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
|
||||||
|
Reference in New Issue
Block a user