Replace CSS classes with semantic HTML

This commit is contained in:
2022-01-11 13:28:22 +01:00
parent c6f0421ad3
commit 8719d9b0f9
37 changed files with 1215 additions and 1279 deletions

View File

@@ -46,8 +46,11 @@ a > svg { vertical-align: middle; }
*, *::before, *::after {
box-sizing: border-box;
}
html, body { overflow-x: hidden; }
body{
html, body {
/* This makes sure that no scrollbar shows up when the menu is open on small screens*/
overflow-x: hidden;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
font-size: 17px;
@@ -56,20 +59,26 @@ body{
background-color: var(--layer_1_color);
padding: 0;
}
.checkers {
header, footer, .checkers {
background-image: url("{{bgPattern}}");
background-color: #111111; /* Fallback */
background-color: var(--layer_1_color);
background-repeat: repeat;
background-blend-mode: luminosity;
}
.inset {
header, footer {
padding-top: 70px;
box-shadow: inset 1px 1px 10px 0 var(--shadow_color);
border-radius: 12px;
text-align: center;
overflow: hidden;
}
header > h1 {
text-shadow: 1px 1px 10px var(--shadow_color);
}
footer {
padding: 200px 8px 40px 8px;
}
/* Page layout elements */
@@ -131,7 +140,7 @@ body{
padding: 4px;
}
}
.limit_width {
section {
position: relative;
display: inline-block;
max-width: 1000px;
@@ -141,10 +150,6 @@ body{
text-align: left;
clear: both;
}
.page_body > h1 {
text-shadow: 1px 1px 25px #000000;
text-shadow: 1px 1px 25px var(--shadow_color);
}
/* Page contents */

View File

@@ -7,10 +7,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>This page does not exist!</h1>
</div>
<div class="limit_width">
</header>
<section>
<p>
If you came here by a link from this very same website you can
tell me about it on
@@ -23,7 +23,7 @@
<p>
Bye!
</p>
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -7,15 +7,15 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>451, Unavailable For Legal Reasons</h1>
</div>
<div class="limit_width">
</header>
<section>
<p>
Hello. This file has received an abuse report and has been taken
down. It cannot be shared anymore.
</p>
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -7,10 +7,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>You broke pixeldrain</h1>
</div>
<div class="limit_width">
</header>
<section>
<p>
Great job.
</p>
@@ -24,7 +24,7 @@
try again in a few minutes (or hours), or go back to the <a
href='/'>home page</a> and start over.
</p>
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -7,10 +7,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>Change website appearance</h1>
</div>
<div class="limit_width">
</header>
<section>
<p>
You can change how pixeldrain looks! Your theme choice will
be saved in a cookie.
@@ -30,7 +30,7 @@
(Inspired by <a href="https://www.gnome-look.org/p/1441725/" target="_blank">Skeuos GTK</a>)<br/>
<!--<input type="radio" id="style_sunny" name="style"><label for="style_sunny">Sunny Style</label>-->
</div>
</div>
</section>
<script>
// Style selector

View File

@@ -14,10 +14,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>Apps</h1>
</div>
<div class="limit_width">
</header>
<section>
<h2>ShareX</h2>
<div class="specs">
Platform: Windows 7, 8.1 and 10 |
@@ -110,7 +110,7 @@
please send them to
<a href="mailto:support@pixeldrain.com">support@pixeldrain.com</a>.
</p>
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -7,27 +7,38 @@
<body>
{{template "page_top" .}}
<div class="limit_width">
{{if eq .Other "success"}}
{{if eq .Other "success"}}
<header>
<h1>Success!</h1>
</header>
<section>
<p>
Your account's e-mail address has been updated.
</p>
{{else if eq .Other "not_found"}}
</section>
{{else if eq .Other "not_found"}}
<header>
<h1>E-mail change failed</h1>
</header>
<section>
<p>
This e-mail change request does not exist or has expired.
Please try again if you still want to change your e-mail
address.
</p>
{{else}}
</section>
{{else}}
<header>
<h1>Error</h1>
</header>
<section>
<p>
Something went wrong while processing this request. Please
try again later.
</p>
{{end}}
</div>
</section>
{{end}}
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -7,10 +7,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>404, File Not Found!</h1>
</div>
<div class="limit_width">
</header>
<section>
<p>
This file does not exist, or it has been removed. Possible
reasons for this are:
@@ -34,7 +34,7 @@
<p>
I'm sorry for the inconvenience.
</p>
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>
@@ -49,10 +49,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>404, List Not Found!</h1>
</div>
<div class="limit_width">
</header>
<section>
<p>
This list does not exist, or it has been removed. Possible
reasons for this are:
@@ -70,7 +70,7 @@
<p>
I'm sorry for the inconvenience.
</p>
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -25,10 +25,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>{{.Title}}</h1>
</div>
<div class="limit_width">
</header>
<section>
{{if eq .Other.Type "file"}}
Download <a href="{{.APIEndpoint}}/file/{{.Other.APIResponse.ID}}?download">{{.Other.APIResponse.Name}}</a> here.
{{else}}
@@ -66,7 +66,7 @@
<li><a href="https://www.apple.com/safari/">Safari</a> (Mac OS)</li>
<li><a href="https://www.microsoft.com/en-us/edge">Edge</a> (Windows)</li>
</ul>
</div>
</section>
{{template "analytics"}}
</body>
</html>

View File

@@ -110,14 +110,14 @@
<body>
<div id='body' class="body">
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>{{.Form.Title}}</h1>
</div>
</header>
<br/>
<div class="limit_width">
<section>
{{template "form" .Form}}
<br/>
</div>
</section>
{{template "page_bottom" .}}
</div>

View File

@@ -7,12 +7,12 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>{{.Title}}</h1>
</div>
<div class="limit_width">
</header>
<section>
{{.Other}}
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -1,6 +1,6 @@
{{define "page_menu"}}
<button id="button_toggle_navigation" class="button_toggle_navigation" onclick="toggleMenu();"></button>
<div id="page_navigation" class="page_navigation">
<nav id="page_navigation" class="page_navigation">
<a href="/">Home</a>
<hr />
{{if .Authenticated}}<a href="/user">{{.User.Username}}</a>
@@ -26,7 +26,7 @@
{{if eq .User.Subscription.ID ""}}
<a href="https://pixeldrain.com/vouchercodes">Shopping discounts</a>
{{end}}
</div>
</nav>
<script>
function toggleMenu() {
var nav = document.getElementById("page_navigation");
@@ -54,7 +54,7 @@ function resetMenu() {
{{end}}
{{define "page_bottom"}}
<div class="inset checkers" style="padding-top: 150px">
<footer>
<div style="display: inline-block; margin: 0 8px 0 8px;">
Pixeldrain is a product by <a href="//fornaxian.tech" target="_blank">Fornaxian Technologies</a>
</div>
@@ -71,8 +71,6 @@ function resetMenu() {
<span class="small_footer_text" style="font-size: .75em; line-height: .75em;">
page rendered by {{.Hostname}}
</span>
<br/>
<br/>
</div>
</footer>
</div><!-- end page_body -->
{{end}}

View File

@@ -5,24 +5,23 @@
{{template "user_style" .}}
</head>
<body>
<div id='body' class="body">
{{template "page_top" .}}
{{template "page_top" .}}
<div class="checkers inset">
<h1>Upload History</h1>
</div>
<header>
<h1>Upload History</h1>
</header>
<div class="limit_width">
<p>
Here are all files you have previously uploaded to pixeldrain using this computer.
This data is saved locally in your web browser and gets updated every time you upload a file through your current browser.
</p>
<br/>
<section>
<p>
Here are all files you have previously uploaded to pixeldrain using this computer.
This data is saved locally in your web browser and gets updated every time you upload a file through your current browser.
</p>
<br/>
<div id="uploaded_files" class="highlight_dark"></div>
</section>
{{template "page_bottom" .}}
<div id="uploaded_files" class="highlight_dark"></div>
</div>
{{template "page_bottom" .}}
</div>
<script>
let apiEndpoint = '{{.APIEndpoint}}';
{{template `util.js`}}

View File

@@ -93,21 +93,21 @@
</head>
<body>
{{template "page_top" .}}
<div class="checkers inset" style="padding-bottom: 60px;">
<header style="padding-bottom: 60px;">
<picture>
<source media="(max-width: 800px)" srcset="/res/img/header_orbitron.png">
<img class="header_image" src="/res/img/header_orbitron_wide.png" alt="Header image">
</picture>
</div>
</header>
<!-- Svelte element -->
<div id="uploader" class="page_content"></div>
<div class="checkers inset">
<header>
<h1>What is pixeldrain?</h1>
</div>
</header>
<div class="limit_width">
<section>
<p>
Pixeldrain is a file sharing website built for speed and ease of
use. You can upload files you want to share online to our
@@ -475,7 +475,7 @@
logging in head to the <a href="/user/transactions">transactions
page</a> to deposit your coins.
</p>
</div>
</section>
<template id="tpl_file_expiry">
<p>

View File

@@ -10,9 +10,9 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>My Buckets</h1>
</div>
</header>
<div id="page_content" class="page_content"></div>
{{template "page_bottom" .}}

View File

@@ -6,15 +6,14 @@
</head>
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header>
<h1>Please confirm that you want to log out of your pixeldrain account</h1>
<br/>
</div>
</header>
<br/>
<form method="POST" action="/logout">
<input type="submit" value="I want to log out of pixeldrain on this computer" class="button_highlight"/>
</form>
<div class="limit_width">
<section>
<br/>
<h2>Why do I need to confirm my logout?</h2>
<p>
@@ -31,7 +30,7 @@
page visit we can confirm that you really want to log out.
</p>
<br/>
</div>
</section>
{{template "page_bottom" .}}
{{template "analytics"}}
</body>

View File

@@ -8,10 +8,10 @@
<body>
{{template "page_top" .}}
<div class="checkers inset">
<header">
<h1>Widget showcase</h1>
</div>
<div class="limit_width">
</header>
<section>
<h2>Size 2 header</h2>
<h3>Size 3 header</h3>
<h4>Size 4 header</h4>
@@ -64,7 +64,7 @@
<br/><br/>
<iframe src="https://pixeldrain.com/u/Nygt1on4?embed" style="border: none; width: 800px; max-width: 100%; height: 600px; max-height: 100%; border-radius: 16px;"></iframe>
</div>
</section>
{{template "page_bottom" .}}
</body>
</html>

View File

@@ -82,85 +82,83 @@ const delete_reporter = async (email) => {
onMount(get_reporters);
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<section>
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<button class:button_highlight={creating} on:click={() => {creating = !creating}}>
<i class="icon">create</i> Add abuse reporter
</button>
</div>
{#if creating}
<div class="highlight_light">
<form on:submit|preventDefault={create_reporter}>
<table class="form">
<tr>
<td>E-mail address</td>
<td><input type="text" bind:this={new_reporter_email}/></td>
</tr>
<tr>
<td>Name</td>
<td><input type="text" bind:this={new_reporter_name} value="Anonymous tip"/></td>
</tr>
<tr>
<td>Type</td>
<td>
<input id="reporter_type_individual" name="reporter_type" type="radio" bind:group={new_reporter_type} value="individual" />
<label for="reporter_type_individual">Individual</label>
<br/>
<input id="reporter_type_org" name="reporter_type" type="radio" bind:group={new_reporter_type} value="org" />
<label for="reporter_type_org">Organisation</label>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
{/if}
</section>
<div class="limit_width">
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<button class:button_highlight={creating} on:click={() => {creating = !creating}}>
<i class="icon">create</i> Add abuse reporter
</button>
</div>
{#if creating}
<div class="highlight_light">
<form on:submit|preventDefault={create_reporter}>
<table class="form">
<tr>
<td>E-mail address</td>
<td><input type="text" bind:this={new_reporter_email}/></td>
</tr>
<tr>
<td>Name</td>
<td><input type="text" bind:this={new_reporter_name} value="Anonymous tip"/></td>
</tr>
<tr>
<td>Type</td>
<td>
<input id="reporter_type_individual" name="reporter_type" type="radio" bind:group={new_reporter_type} value="individual" />
<label for="reporter_type_individual">Individual</label>
<br/>
<input id="reporter_type_org" name="reporter_type" type="radio" bind:group={new_reporter_type} value="org" />
<label for="reporter_type_org">Organisation</label>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
{/if}
</div>
<br/>
<br/>
<div class="table_scroll">
<table style="text-align: left;">
<div class="table_scroll">
<table style="text-align: left;">
<tr>
<td>E-mail</td>
<td>Name</td>
<td>Blocked</td>
<td>Type</td>
<td>Last used</td>
<td>Created</td>
<td></td>
</tr>
{#each reporters as reporter (reporter.email)}
<tr>
<td>E-mail</td>
<td>Name</td>
<td>Blocked</td>
<td>Type</td>
<td>Last used</td>
<td>Created</td>
<td></td>
<td>{reporter.email}</td>
<td>{reporter.name}</td>
<td>{reporter.files_blocked}</td>
<td>{reporter.type}</td>
<td>{formatDate(reporter.last_used, true, true, false)}</td>
<td>{formatDate(reporter.created, false, false, false)}</td>
<td>
<button on:click|preventDefault={() => {delete_reporter(reporter.email)}} class="button button_red round">
<i class="icon">delete</i>
</button>
</td>
</tr>
{#each reporters as reporter (reporter.email)}
<tr>
<td>{reporter.email}</td>
<td>{reporter.name}</td>
<td>{reporter.files_blocked}</td>
<td>{reporter.type}</td>
<td>{formatDate(reporter.last_used, true, true, false)}</td>
<td>{formatDate(reporter.created, false, false, false)}</td>
<td>
<button on:click|preventDefault={() => {delete_reporter(reporter.email)}} class="button button_red round">
<i class="icon">delete</i>
</button>
</td>
</tr>
{/each}
</table>
</div>
{/each}
</table>
</div>
<style>

View File

@@ -91,38 +91,36 @@ onMount(() => {
});
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<div class="limit_width">
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<div>Start:</div>
<input type="date" bind:this={startPicker}/>
<div>End:</div>
<input type="date" bind:this={endPicker}/>
<button on:click={get_reports}>Go</button>
</div>
<h2>Pending</h2>
{#each reports_pending as report (report.id)}
{#if report.status === "pending"}
<AbuseReport report={report} on:refresh={get_reports}/>
{/if}
{/each}
<h2>Resolved</h2>
{#each reports_processed as report (report.id)}
{#if report.status !== "pending"}
<AbuseReport report={report} on:refresh={get_reports}/>
{/if}
{/each}
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
</div>
{/if}
<section>
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<div>Start:</div>
<input type="date" bind:this={startPicker}/>
<div>End:</div>
<input type="date" bind:this={endPicker}/>
<button on:click={get_reports}>Go</button>
</div>
<h2>Pending</h2>
{#each reports_pending as report (report.id)}
{#if report.status === "pending"}
<AbuseReport report={report} on:refresh={get_reports}/>
{/if}
{/each}
<h2>Resolved</h2>
{#each reports_processed as report (report.id)}
{#if report.status !== "pending"}
<AbuseReport report={report} on:refresh={get_reports}/>
{/if}
{/each}
</section>
<style>
.spinner_container {

View File

@@ -65,17 +65,12 @@ onMount(() => {
})
</script>
<div>
<div class="limit_width">
<h2>File removal</h2>
<p>
Paste any pixeldrain file links in here to remove them
</p>
<div class="highlight_dark">
<Form config={block_form}></Form>
</div>
<section>
<h2>File removal</h2>
<p>
Paste any pixeldrain file links in here to remove them
</p>
<div class="highlight_dark">
<Form config={block_form}></Form>
</div>
</div>
<style>
</style>
</section>

View File

@@ -159,168 +159,160 @@ onDestroy(() => {
})
</script>
<div>
<div class="limit_width">
<h3>Bandwidth usage and file views</h3>
</div>
<div class="highlight_dark" style="margin-bottom: 6px;">
<button on:click={() => { loadGraph(1440, 1, true) }}>Day</button>
<button on:click={() => { loadGraph(10080, 10, false) }}>Week</button>
<button on:click={() => { loadGraph(20160, 60, false) }}>Two Weeks</button>
<button on:click={() => { loadGraph(43200, 60, false) }}>Month</button>
<button on:click={() => { loadGraph(131400, 1440, false) }}>Quarter</button>
<button on:click={() => { loadGraph(262800, 1440, false) }}>Half-year</button>
<button on:click={() => { loadGraph(525600, 1440, false) }}>Year</button>
<button on:click={() => { loadGraph(1051200, 1440, false) }}>Two Years</button>
</div>
<Chart bind:this={graphBandwidth} data_type="bytes" legend={false} />
<Chart bind:this={graphViews} data_type="number" legend={false} />
<div class="highlight_dark">
Total usage from {start_time} to {end_time}<br/>
{formatDataVolume(total_bandwidth, 3)} bandwidth,
{formatDataVolume(total_bandwidth_paid, 3)} paid bandwidth,
{formatThousands(total_views, 3)} views and
{formatThousands(total_downloads, 3)} downloads
</div>
<br/>
<a class="button" href="/api/admin/call_stack">Call stack</a>
<a class="button" href="/api/admin/heap_profile">Heap profile</a>
<a class="button" href="/api/admin/cpu_profile">CPU profile (wait 1 min)</a>
<br/>
<div class="limit_width">
<table>
<tr>
<td>DB Time</td>
<td>{formatDate(new Date(status.db_time), true, true, true)}</td>
<td>DB Latency</td>
<td>{formatNumber(status.db_latency / 1000, 3)} ms</td>
</tr>
</table>
<h3>Pixelstore peers</h3>
<div class="table_scroll">
<table>
<thead>
<tr>
<td>Address</td>
<td>Pos</td>
<td>Alive</td>
<td>Err</td>
<td>1m</td>
<td>5m</td>
<td>15m</td>
<td>Ping</td>
<td>Free</td>
<td>Min free</td>
</tr>
</thead>
<tbody>
{#each status.peers as peer}
<tr class="peer_row"
class:highlight_red={peer.free_space < peer.min_free_space / 2 || !peer.reachable}
class:highlight_yellow={peer.free_space < peer.min_free_space}
class:highlight_green={peer.reachable}
>
<td>{peer.address}</td>
<td>{peer.position}</td>
<td>{peer.reachable}</td>
<td>{peer.unreachable_count}</td>
<td>{peer.load_1_min.toFixed(1)}</td>
<td>{peer.load_5_min.toFixed(1)}</td>
<td>{peer.load_15_min.toFixed(1)}</td>
<td>{formatDuration(peer.latency, 3)}</td>
<td>{formatDataVolume(peer.free_space, 4)}</td>
<td>{formatDataVolume(peer.min_free_space, 3)}</td>
</tr>
{/each}
</tbody>
</table>
</div>
<h3>Pixelstore stats</h3>
<table>
<thead>
<tr>
<td>Local reads</td>
<td>Local read size</td>
<td>Remote reads</td>
<td>Remote read size</td>
</tr>
</thead>
<tbody>
<tr>
<td>{status.local_reads}</td>
<td>{formatDataVolume(status.local_read_size, 4)}</td>
<td>{status.remote_reads}</td>
<td>{formatDataVolume(status.remote_read_size, 4)}</td>
</tr>
<tr>
<td>{status.local_reads_per_sec.toPrecision(4)} / s</td>
<td>{formatDataVolume(status.local_read_size_per_sec, 4)} / s</td>
<td>{status.remote_reads_per_sec.toPrecision(4)} / s</td>
<td>{formatDataVolume(status.remote_read_size_per_sec, 4)} /s</td>
</tr>
</tbody>
</table>
<h3>Socket statistics</h3>
<table>
<thead>
<tr>
<td>Watcher</td>
<td>Threads</td>
<td>Listeners</td>
<td>Avg</td>
</tr>
</thead>
<tbody>
<tr>
<td>File statistics</td>
<td>{status.stats_watcher_threads}</td>
<td>{status.stats_watcher_listeners}</td>
<td>{(status.stats_watcher_listeners / status.stats_watcher_threads).toPrecision(3)}</td>
</tr>
<tr>
<td>Downloads</td>
<td>{status.download_clients}</td>
<td>{status.download_connections}</td>
<td>{(status.download_connections / status.download_clients).toPrecision(3)}</td>
</tr>
</tbody>
</table>
<h3>Query statistics</h3>
<div class="table_scroll" style="text-align: left;">
<table>
<thead>
<tr>
<td style="cursor: pointer;" on:click={() => { getStats('query_name') }}>Query</td>
<td style="cursor: pointer;" on:click={() => { getStats('calls') }}>Calls</td>
<td style="cursor: pointer;" on:click={() => { getStats('average_duration') }}>Avg dur</td>
<td style="cursor: pointer;" on:click={() => { getStats('total_duration') }}>Total dur</td>
<td>Callers</td>
</tr>
</thead>
<tbody id="tstat_body">
{#each status.query_statistics as q}
<tr>
<td>{q.query_name}</td>
<td>{q.calls}</td>
<td>{q.average_duration}ms</td>
<td>{formatDuration(q.total_duration, 0)}</td>
<td>
{#each q.callers as caller}
{caller.count}x {caller.name}<br/>
{/each}
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
<section>
<h3>Bandwidth usage and file views</h3>
</section>
<div class="highlight_dark" style="margin-bottom: 6px;">
<button on:click={() => { loadGraph(1440, 1, true) }}>Day</button>
<button on:click={() => { loadGraph(10080, 10, false) }}>Week</button>
<button on:click={() => { loadGraph(20160, 60, false) }}>Two Weeks</button>
<button on:click={() => { loadGraph(43200, 60, false) }}>Month</button>
<button on:click={() => { loadGraph(131400, 1440, false) }}>Quarter</button>
<button on:click={() => { loadGraph(262800, 1440, false) }}>Half-year</button>
<button on:click={() => { loadGraph(525600, 1440, false) }}>Year</button>
<button on:click={() => { loadGraph(1051200, 1440, false) }}>Two Years</button>
</div>
<Chart bind:this={graphBandwidth} data_type="bytes" legend={false} />
<Chart bind:this={graphViews} data_type="number" legend={false} />
<div class="highlight_dark">
Total usage from {start_time} to {end_time}<br/>
{formatDataVolume(total_bandwidth, 3)} bandwidth,
{formatDataVolume(total_bandwidth_paid, 3)} paid bandwidth,
{formatThousands(total_views, 3)} views and
{formatThousands(total_downloads, 3)} downloads
</div>
<style>
.peer_row {
text-align: left;
}
</style>
<br/>
<a class="button" href="/api/admin/call_stack">Call stack</a>
<a class="button" href="/api/admin/heap_profile">Heap profile</a>
<a class="button" href="/api/admin/cpu_profile">CPU profile (wait 1 min)</a>
<br/>
<section>
<table>
<tr>
<td>DB Time</td>
<td>{formatDate(new Date(status.db_time), true, true, true)}</td>
<td>DB Latency</td>
<td>{formatNumber(status.db_latency / 1000, 3)} ms</td>
</tr>
</table>
<h3>Pixelstore peers</h3>
<div class="table_scroll">
<table>
<thead>
<tr>
<td>Address</td>
<td>Pos</td>
<td>Alive</td>
<td>Err</td>
<td>1m</td>
<td>5m</td>
<td>15m</td>
<td>Ping</td>
<td>Free</td>
<td>Min free</td>
</tr>
</thead>
<tbody>
{#each status.peers as peer}
<tr style="text-align: left"
class:highlight_red={peer.free_space < peer.min_free_space / 2 || !peer.reachable}
class:highlight_yellow={peer.free_space < peer.min_free_space}
class:highlight_green={peer.reachable}
>
<td>{peer.address}</td>
<td>{peer.position}</td>
<td>{peer.reachable}</td>
<td>{peer.unreachable_count}</td>
<td>{peer.load_1_min.toFixed(1)}</td>
<td>{peer.load_5_min.toFixed(1)}</td>
<td>{peer.load_15_min.toFixed(1)}</td>
<td>{formatDuration(peer.latency, 3)}</td>
<td>{formatDataVolume(peer.free_space, 4)}</td>
<td>{formatDataVolume(peer.min_free_space, 3)}</td>
</tr>
{/each}
</tbody>
</table>
</div>
<h3>Pixelstore stats</h3>
<table>
<thead>
<tr>
<td>Local reads</td>
<td>Local read size</td>
<td>Remote reads</td>
<td>Remote read size</td>
</tr>
</thead>
<tbody>
<tr>
<td>{status.local_reads}</td>
<td>{formatDataVolume(status.local_read_size, 4)}</td>
<td>{status.remote_reads}</td>
<td>{formatDataVolume(status.remote_read_size, 4)}</td>
</tr>
<tr>
<td>{status.local_reads_per_sec.toPrecision(4)} / s</td>
<td>{formatDataVolume(status.local_read_size_per_sec, 4)} / s</td>
<td>{status.remote_reads_per_sec.toPrecision(4)} / s</td>
<td>{formatDataVolume(status.remote_read_size_per_sec, 4)} /s</td>
</tr>
</tbody>
</table>
<h3>Socket statistics</h3>
<table>
<thead>
<tr>
<td>Watcher</td>
<td>Threads</td>
<td>Listeners</td>
<td>Avg</td>
</tr>
</thead>
<tbody>
<tr>
<td>File statistics</td>
<td>{status.stats_watcher_threads}</td>
<td>{status.stats_watcher_listeners}</td>
<td>{(status.stats_watcher_listeners / status.stats_watcher_threads).toPrecision(3)}</td>
</tr>
<tr>
<td>Downloads</td>
<td>{status.download_clients}</td>
<td>{status.download_connections}</td>
<td>{(status.download_connections / status.download_clients).toPrecision(3)}</td>
</tr>
</tbody>
</table>
<h3>Query statistics</h3>
<div class="table_scroll" style="text-align: left;">
<table>
<thead>
<tr>
<td style="cursor: pointer;" on:click={() => { getStats('query_name') }}>Query</td>
<td style="cursor: pointer;" on:click={() => { getStats('calls') }}>Calls</td>
<td style="cursor: pointer;" on:click={() => { getStats('average_duration') }}>Avg dur</td>
<td style="cursor: pointer;" on:click={() => { getStats('total_duration') }}>Total dur</td>
<td>Callers</td>
</tr>
</thead>
<tbody id="tstat_body">
{#each status.query_statistics as q}
<tr>
<td>{q.query_name}</td>
<td>{q.calls}</td>
<td>{q.average_duration}ms</td>
<td>{formatDuration(q.total_duration, 0)}</td>
<td>
{#each q.callers as caller}
{caller.count}x {caller.name}<br/>
{/each}
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</section>

View File

@@ -80,91 +80,89 @@ const delete_ban = async (addr) => {
onMount(get_bans);
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<section>
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<button class:button_highlight={creating} on:click={() => {creating = !creating}}>
<i class="icon">create</i> Add IP ban
</button>
</div>
{#if creating}
<div class="highlight_light">
<form on:submit|preventDefault={create_ban}>
<table class="form">
<tr>
<td>IP address</td>
<td><input type="text" bind:this={new_ban_address}/></td>
</tr>
<tr>
<td>Reason</td>
<td>
<input id="reason_unknown" name="reporter_type" type="radio" bind:group={new_ban_reason} value="unknown" />
<label for="reason_unknown">unknown</label>
<br/>
<input id="reason_copyright" name="reporter_type" type="radio" bind:group={new_ban_reason} value="copyright" />
<label for="reason_copyright">copyright</label>
<br/>
<input id="reason_child_abuse" name="reporter_type" type="radio" bind:group={new_ban_reason} value="child_abuse" />
<label for="reason_child_abuse">child_abuse</label>
<br/>
<input id="reason_terrorism" name="reporter_type" type="radio" bind:group={new_ban_reason} value="terorrism" />
<label for="reason_terrorism">terrorism</label>
<br/>
<input id="reason_gore" name="reporter_type" type="radio" bind:group={new_ban_reason} value="gore" />
<label for="reason_gore">gore</label>
<br/>
<input id="reason_malware" name="reporter_type" type="radio" bind:group={new_ban_reason} value="malware" />
<label for="reason_malware">malware</label>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
{/if}
</section>
<div class="limit_width">
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<button class:button_highlight={creating} on:click={() => {creating = !creating}}>
<i class="icon">create</i> Add IP ban
</button>
</div>
{#if creating}
<div class="highlight_light">
<form on:submit|preventDefault={create_ban}>
<table class="form">
<tr>
<td>IP address</td>
<td><input type="text" bind:this={new_ban_address}/></td>
</tr>
<tr>
<td>Reason</td>
<td>
<input id="reason_unknown" name="reporter_type" type="radio" bind:group={new_ban_reason} value="unknown" />
<label for="reason_unknown">unknown</label>
<br/>
<input id="reason_copyright" name="reporter_type" type="radio" bind:group={new_ban_reason} value="copyright" />
<label for="reason_copyright">copyright</label>
<br/>
<input id="reason_child_abuse" name="reporter_type" type="radio" bind:group={new_ban_reason} value="child_abuse" />
<label for="reason_child_abuse">child_abuse</label>
<br/>
<input id="reason_terrorism" name="reporter_type" type="radio" bind:group={new_ban_reason} value="terorrism" />
<label for="reason_terrorism">terrorism</label>
<br/>
<input id="reason_gore" name="reporter_type" type="radio" bind:group={new_ban_reason} value="gore" />
<label for="reason_gore">gore</label>
<br/>
<input id="reason_malware" name="reporter_type" type="radio" bind:group={new_ban_reason} value="malware" />
<label for="reason_malware">malware</label>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
{/if}
</div>
<br/>
<br/>
<div class="table_scroll">
<table style="text-align: left;">
<div class="table_scroll">
<table style="text-align: left;">
<tr>
<td>Address</td>
<td>Reason</td>
<td>Ban time</td>
<td>Expire time</td>
<td>Offences</td>
<td></td>
</tr>
{#each rows as row (row.address)}
<tr>
<td>Address</td>
<td>Reason</td>
<td>Ban time</td>
<td>Expire time</td>
<td>Offences</td>
<td></td>
<td>{row.address}</td>
<td>{row.reason}</td>
<td>{formatDate(row.ban_time, true, true, false)}</td>
<td>{formatDate(row.expire_time, true, true, false)}</td>
<td>{row.offences}</td>
<td>
<button on:click|preventDefault={() => {delete_ban(row.address)}} class="button button_red round">
<i class="icon">delete</i>
</button>
</td>
</tr>
{#each rows as row (row.address)}
<tr>
<td>{row.address}</td>
<td>{row.reason}</td>
<td>{formatDate(row.ban_time, true, true, false)}</td>
<td>{formatDate(row.expire_time, true, true, false)}</td>
<td>{row.offences}</td>
<td>
<button on:click|preventDefault={() => {delete_ban(row.address)}} class="button button_red round">
<i class="icon">delete</i>
</button>
</td>
</tr>
{/each}
</table>
</div>
{/each}
</table>
</div>
<style>

View File

@@ -26,7 +26,7 @@ onMount(() => {
})
</script>
<div class="checkers inset">
<header>
<h1>Admin Panel</h1>
<div class="tab_bar">
@@ -77,7 +77,7 @@ onMount(() => {
Update global settings
</a>
</div>
</div>
</header>
{#if page === "status"}
<Home></Home>

View File

@@ -173,7 +173,7 @@ onMount(get_coupons)
</script>
<div class="limit_width">
<section>
{#if loading}
<div class="spinner_container">
<Spinner />
@@ -221,7 +221,7 @@ onMount(get_coupons)
{/each}
</table>
</div>
</div>
</section>
<style>
.spinner_container {

View File

@@ -386,18 +386,18 @@ const keydown = (e) => {
<div>
<!-- If the user is logged in and has used more than 50% of their storage space we will show a progress bar -->
{#if window.user.username !== "" && window.user.storage_space_used/window.user.subscription.storage_space > 0.5}
<div class="limit_width">
<section>
<StorageProgressBar used={window.user.storage_space_used} total={window.user.subscription.storage_space}></StorageProgressBar>
</div>
</section>
{/if}
<div class="instruction limit_width" style="margin-top: 0; border-top: none;">
<section class="instruction" style="margin-top: 0; border-top: none;">
<span class="big_number">1</span>
<span class="instruction_text">Select files to upload</span>
<br/>
You can also drop files on this page from your file manager or
paste an image from your clipboard
</div>
</section>
<br/>
<input bind:this={file_input_field} on:change={file_input_change} type="file" name="file" multiple="multiple"/>
@@ -416,7 +416,7 @@ const keydown = (e) => {
<a href="/about#content-policy">content policy</a>.
<p>
<div class="instruction limit_width" style="margin-bottom: 0;">
<section class="instruction" style="margin-bottom: 0;">
<span class="big_number">2</span>
<span class="instruction_text">Wait for the files to finish uploading</span>
<br/>
@@ -426,7 +426,7 @@ const keydown = (e) => {
<div>ETA {formatDuration(remaining_time, 0)}</div>
<div>Rate {formatDataVolume(total_rate, 3)}/s</div>
</div>
</div>
</section>
<div class="progress_bar_outer" style="margin-bottom: 1.5em;">
<div bind:this={progress_bar_inner} class="progress_bar_inner"></div>
</div>
@@ -441,10 +441,10 @@ const keydown = (e) => {
<UploadProgressBar bind:this={file.component} job={file}></UploadProgressBar>
{/each}
<div class="instruction limit_width">
<section class="instruction">
<span class="big_number">3</span>
<span class="instruction_text">Share the files</span>
</div>
</section>
<br/>
{#if upload_queue.length > 1}
@@ -518,11 +518,11 @@ const keydown = (e) => {
<br/>
{#if window.user.subscription.name === ""}
<div class="instruction limit_width">
<span class="big_number">4</span>
<span class="instruction_text">Support me on Patreon!</span>
</div>
<div class="limit_width">
<section>
<div class="instruction">
<span class="big_number">4</span>
<span class="instruction_text">Support me on Patreon!</span>
</div>
<p>
Pixeldrain is struggling to get by financially. Because anyone
can upload anything it's hard to find reputable advertisers who
@@ -537,13 +537,15 @@ const keydown = (e) => {
help with making pixeldrain the easiest and fastest way to share
files online!
</p>
</div>
<br/>
<a href="#pro" class="button big_button" style="min-width: 350px;">
<i class="icon">arrow_downward</i>
Check out Pro
<i class="icon">arrow_downward</i>
</a>
<br/>
<div style="text-align: center;">
<a href="#pro" class="button big_button" style="min-width: 350px;">
<i class="icon">arrow_downward</i>
Check out Pro
<i class="icon">arrow_downward</i>
</a>
</div>
</section>
{/if}
</div>

View File

@@ -1,13 +1,10 @@
<script>
import { fs_delete_bucket } from "../filesystem/FilesystemAPI.svelte";
import { createEventDispatcher } from "svelte";
import Expandable from "../util/Expandable.svelte";
let dispatch = createEventDispatcher()
export let bucket
let details_hidden = true
const expand_bucket = () => {
details_hidden = !details_hidden
}
const save_bucket = () => {
alert("save")
@@ -32,21 +29,14 @@ const delete_bucket = async () => {
</script>
<div class="bucket">
<div class="bucket_header">
<Expandable>
<div slot="header">
<a href={'/d/' + bucket.id} class="bucket_title">
<img class="bucket_icon" src="/res/img/mime/folder-remote.png" alt="Bucket icon"/>
{bucket.name}
</a>
<button class="bucket_expand" on:click={expand_bucket}>
{#if details_hidden}
<i class="icon">expand_more</i>
{:else}
<i class="icon">expand_less</i>
{/if}
</button>
</div>
<div class="bucket_details" class:hidden={details_hidden}>
<div>
<form on:submit|preventDefault={save_bucket}>
<table class="form">
<tr class="form">
@@ -66,26 +56,9 @@ const delete_bucket = async () => {
</table>
</form>
</div>
</div>
</Expandable>
<style>
.bucket {
text-decoration: none;
background-color: var(--layer_3_color);
transition: box-shadow 0.5s;
box-shadow: 1px 1px 5px 0 var(--shadow_color);
margin: 1em 0;
border-radius: 8px;
overflow: hidden;
}
.bucket_header {
display: flex;
flex-direction: row;
color: var(--text_color);
}
.bucket_header:hover {
background-color: var(--input_color_dark)
}
.bucket_title {
flex: 1 1 auto;
align-self: center;
@@ -98,18 +71,4 @@ const delete_bucket = async () => {
margin: 4px;
vertical-align: middle;
}
.bucket_expand {
flex: 0 0 auto;
}
.bucket_details {
display: flex;
padding: 0.4em;
flex-direction: column;
text-decoration: none;
border-top: 1px solid var(--layer_3_color_border);
color: var(--text_color);
}
.hidden {
display: none;
}
</style>

View File

@@ -41,51 +41,49 @@ const create_bucket = async () => {
onMount(get_buckets);
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<section>
<div class="toolbar" style="text-align: right;">
<button
class:button_highlight={creating_bucket}
on:click={() => {creating_bucket = !creating_bucket}}
>
<i class="icon">create_new_folder</i> New bucket
</button>
</div>
{#if creating_bucket}
<div class="highlight_light">
<form on:submit|preventDefault={create_bucket}>
<table class="form">
<tr>
<td>
Name
</td>
<td>
<input type="text" bind:this={new_bucket_name}/>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
{/if}
<div class="limit_width">
<div class="toolbar" style="text-align: right;">
<button
class:button_highlight={creating_bucket}
on:click={() => {creating_bucket = !creating_bucket}}
>
<i class="icon">create_new_folder</i> New bucket
</button>
</div>
{#if creating_bucket}
<div class="highlight_light">
<form on:submit|preventDefault={create_bucket}>
<table class="form">
<tr>
<td>
Name
</td>
<td>
<input type="text" bind:this={new_bucket_name}/>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button_highlight" type="submit" style="float: right;">
<i class="icon">save</i> Save
</button>
</td>
</tr>
</table>
</form>
</div>
{/if}
{#each buckets as bucket}
<UserBucket bucket={bucket} on:refresh={get_buckets}></UserBucket>
{/each}
</div>
</div>
{#each buckets as bucket (bucket.id)}
<UserBucket bucket={bucket} on:refresh={get_buckets}></UserBucket>
{/each}
</section>
<style>
.spinner_container {

View File

@@ -82,87 +82,85 @@ const logout = async (key) => {
}
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<section>
{#if !loaded}
<div class="highlight_yellow">
<h2>Warning</h2>
<p>
API keys are sensitive information. They can be used to gain
full control over your account. Do not show your API keys to
someone or something you don't trust!
</p>
<button class="button_red" on:click={load_keys}>
<i class="icon">lock_open</i> Show API keys
</button>
</div>
{:else}
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<button on:click={create_key}>
<i class="icon">add</i> Create new API key
</button>
</div>
{/if}
<div class="limit_width">
{#if !loaded}
<div class="highlight_yellow">
<h2>Warning</h2>
<p>
API keys are sensitive information. They can be used to gain
full control over your account. Do not show your API keys to
someone or something you don't trust!
</p>
<button class="button_red" on:click={load_keys}>
<i class="icon">lock_open</i> Show API keys
</button>
</div>
{:else}
<div class="toolbar" style="text-align: left;">
<div class="toolbar_spacer"></div>
<button on:click={create_key}>
<i class="icon">add</i> Create new API key
</button>
</div>
{/if}
<p>
If you delete the API key that you are currently using you will be
logged out of your account. API keys expire 90 days after the last
time they're used. If you think someone is using your account
without your authorization it's probably a good idea to delete all
your keys.
</p>
</div>
<div class="table_scroll">
<table style="text-align: left;">
<tr>
<td>Key</td>
<td>Created</td>
<td>Last used ▼</td>
<td>IP address</td>
<td></td>
<p>
If you delete the API key that you are currently using you will be
logged out of your account. API keys expire 90 days after the last
time they're used. If you think someone is using your account
without your authorization it's probably a good idea to delete all
your keys.
</p>
</section>
<div class="table_scroll">
<table style="text-align: left;">
<tr>
<td>Key</td>
<td>Created</td>
<td>Last used ▼</td>
<td>IP address</td>
<td></td>
</tr>
{#each rows as row (row.auth_key)}
<tr style="border-bottom: none;">
<td>{row.auth_key}</td>
<td>{formatDate(row.creation_time, true, true, false)}</td>
<td>{formatDate(row.last_used_time, true, true, false)}</td>
<td>{row.creation_ip_address}</td>
<td>
<button on:click|preventDefault={() => {logout(row.auth_key)}} class="button button_red round">
<i class="icon">delete</i>
</button>
</td>
</tr>
{#each rows as row (row.auth_key)}
<tr style="border-bottom: none;">
<td>{row.auth_key}</td>
<td>{formatDate(row.creation_time, true, true, false)}</td>
<td>{formatDate(row.last_used_time, true, true, false)}</td>
<td>{row.creation_ip_address}</td>
<td>
<button on:click|preventDefault={() => {logout(row.auth_key)}} class="button button_red round">
<i class="icon">delete</i>
</button>
</td>
</tr>
<tr>
<td colspan="1">
{#if row.app_name === "website login"}
<img src="/res/img/pixeldrain_32.png" alt="Pixeldrain logo" class="app_icon"/>
Pixeldrain website
{:else if row.app_name === "website keys page"}
<i class="icon">vpn_key</i>
Pixeldrain keys page
{:else if row.app_name === "sharex"}
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon"/>
ShareX
{:else if row.app_name === "jdownloader"}
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon"/>
JDownloader
{:else}
Unknown app: {row.app_name}
{/if}
</td>
<td colspan="4">User-Agent: {row.user_agent}</td>
</tr>
{/each}
</table>
</div>
<tr>
<td colspan="1">
{#if row.app_name === "website login"}
<img src="/res/img/pixeldrain_32.png" alt="Pixeldrain logo" class="app_icon"/>
Pixeldrain website
{:else if row.app_name === "website keys page"}
<i class="icon">vpn_key</i>
Pixeldrain keys page
{:else if row.app_name === "sharex"}
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon"/>
ShareX
{:else if row.app_name === "jdownloader"}
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon"/>
JDownloader
{:else}
Unknown app: {row.app_name}
{/if}
</td>
<td colspan="4">User-Agent: {row.user_agent}</td>
</tr>
{/each}
</table>
</div>
<style>

View File

@@ -137,29 +137,24 @@ let delete_account = {
}
</script>
<div>
<div class="limit_width">
<h2>Change password</h2>
<div class="highlight_dark">
<Form config={password_change}></Form>
</div>
<h2>Change e-mail address</h2>
<div class="highlight_dark">
<Form config={email_change}></Form>
</div>
<h2>Change name</h2>
<div class="highlight_dark">
<Form config={name_change}></Form>
</div>
<h2>Delete account</h2>
<div class="highlight_dark">
<Form config={delete_account}></Form>
</div>
<section>
<h2>Change password</h2>
<div class="highlight_dark">
<Form config={password_change}></Form>
</div>
</div>
<style>
</style>
<h2>Change e-mail address</h2>
<div class="highlight_dark">
<Form config={email_change}></Form>
</div>
<h2>Change name</h2>
<div class="highlight_dark">
<Form config={name_change}></Form>
</div>
<h2>Delete account</h2>
<div class="highlight_dark">
<Form config={delete_account}></Form>
</div>
</section>

View File

@@ -56,114 +56,113 @@ onMount(() => {
})
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<div class="limit_width">
{#if app_name === "jdownloader"}
<h2>
Connect
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon_small"/>
JDownloader to your pixeldrain account
</h2>
<p>
To connect JDownloader to pixeldrain you need to generate an API
key and enter it in JDownloader's Account Manager.
<br/>
<strong>Do not show the generated key to anyone</strong>, it can
be used to gain access to your pixeldrain account!
</p>
{#if !api_key}
<div class="center">
<button class="button_highlight" on:click={create_key}>
<i class="icon">add</i>
Generate key
</button>
</div>
{:else}
<h3>Key created</h3>
<div class="copy_container">
<button on:click={copy_key} class="copy_button" class:button_highlight={copied}>
<i class="icon">content_copy</i>
{#if copied}
Copied!
{:else}
Copy key to clipboard
{/if}
</button>
<button on:click={toggle_show_key} class="copy_button" class:button_highlight={show_key !== ""}>
<i class="icon">visibility</i>
{#if show_key === ""}
Show key
{/if}
</button>
<input bind:value={show_key} class="copy_textarea" type="text" placeholder="Your key will show up here" disabled={show_key === ""}/>
</div>
{/if}
<p>
Paste the key in JDownloader to authenticate the app.
</p>
{:else if app_name === "sharex"}
<h2>
Connect
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon_small"/>
ShareX to your pixeldrain account
</h2>
<p>
ShareX is a Screen capture, file sharing and productivity tool.
Pixeldrain is supported as a custom uploader. You can <a
href="https://getsharex.com/" target="_blank">get ShareX
here</a>.
</p>
<p>
Here you can download our custom ShareX uploader which uses
pixeldrain to upload your files. This uploader is configured to
upload files to your personal pixeldrain account. <strong>Do not
share the configuration file with anyone</strong>, it contains
your account credentials.
</p>
<div class="center">
<a href="/misc/sharex/pixeldrain.com.sxcu" class="button button_highlight">
<i class="icon small">save</i>
Download ShareX Uploader
</a>
</div>
<h3>Setting pixeldrain as default uploader</h3>
<p>
Download the uploader config and choose 'Open file'
<br/>
<img src="/res/img/sharex_download.png" style="max-width: 100%;" alt=""/><br/>
Set pixeldrain.com as active uploader. Choose Yes
<br/>
<img src="/res/img/sharex_default.png" style="max-width: 100%;" alt=""/><br/>
</p>
{:else}
<h2>Connect an app to your pixeldrain account</h2>
<ul>
<li>
<button on:click={() => {app_name = "jdownloader"}}>
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon"/>
Connect JDownloader
</button>
</li>
<li>
<button on:click={() => {app_name = "sharex"}}>
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon"/>
Connect ShareX
</button>
</li>
</ul>
{/if}
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
</div>
{/if}
<section>
{#if app_name === "jdownloader"}
<h2>
Connect
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon_small"/>
JDownloader to your pixeldrain account
</h2>
<p>
To connect JDownloader to pixeldrain you need to generate an API
key and enter it in JDownloader's Account Manager.
<br/>
<strong>Do not show the generated key to anyone</strong>, it can
be used to gain access to your pixeldrain account!
</p>
{#if !api_key}
<div class="center">
<button class="button_highlight" on:click={create_key}>
<i class="icon">add</i>
Generate key
</button>
</div>
{:else}
<h3>Key created</h3>
<div class="copy_container">
<button on:click={copy_key} class="copy_button" class:button_highlight={copied}>
<i class="icon">content_copy</i>
{#if copied}
Copied!
{:else}
Copy key to clipboard
{/if}
</button>
<button on:click={toggle_show_key} class="copy_button" class:button_highlight={show_key !== ""}>
<i class="icon">visibility</i>
{#if show_key === ""}
Show key
{/if}
</button>
<input bind:value={show_key} class="copy_textarea" type="text" placeholder="Your key will show up here" disabled={show_key === ""}/>
</div>
{/if}
<p>
Paste the key in JDownloader to authenticate the app.
</p>
{:else if app_name === "sharex"}
<h2>
Connect
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon_small"/>
ShareX to your pixeldrain account
</h2>
<p>
ShareX is a Screen capture, file sharing and productivity tool.
Pixeldrain is supported as a custom uploader. You can <a
href="https://getsharex.com/" target="_blank">get ShareX
here</a>.
</p>
<p>
Here you can download our custom ShareX uploader which uses
pixeldrain to upload your files. This uploader is configured to
upload files to your personal pixeldrain account. <strong>Do not
share the configuration file with anyone</strong>, it contains
your account credentials.
</p>
<div class="center">
<a href="/misc/sharex/pixeldrain.com.sxcu" class="button button_highlight">
<i class="icon small">save</i>
Download ShareX Uploader
</a>
</div>
<h3>Setting pixeldrain as default uploader</h3>
<p>
Download the uploader config and choose 'Open file'
<br/>
<img src="/res/img/sharex_download.png" style="max-width: 100%;" alt=""/><br/>
Set pixeldrain.com as active uploader. Choose Yes
<br/>
<img src="/res/img/sharex_default.png" style="max-width: 100%;" alt=""/><br/>
</p>
{:else}
<h2>Connect an app to your pixeldrain account</h2>
<ul>
<li>
<button on:click={() => {app_name = "jdownloader"}}>
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon"/>
Connect JDownloader
</button>
</li>
<li>
<button on:click={() => {app_name = "sharex"}}>
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon"/>
Connect ShareX
</button>
</li>
</ul>
{/if}
</section>
<style>
.spinner_container {

View File

@@ -174,142 +174,142 @@ onDestroy(() => {
})
</script>
<div>
<div class="limit_width">
<h2>Account information</h2>
<ul>
<li>Username: {window.user.username}</li>
<li>E-mail address: {window.user.email}</li>
<li>
Supporter level: {window.user.subscription.name}
{#if window.user.subscription.type === "patreon"}
(<a href="https://www.patreon.com/join/pixeldrain/checkout?edit=1">Manage subscription</a>)
{/if}
<ul>
<li>
Max file size: {formatDataVolume(window.user.subscription.file_size_limit, 3)}
</li>
{#if window.user.subscription.file_expiry_days > 0}
<li>Files expire after {window.user.subscription.file_expiry_days} days</li>
{:else}
<li>Files never expire</li>
{/if}
</ul>
</li>
{#if window.user.balance_micro_eur !== 0}
<li>
Current account balance: <Euro amount={window.user.balance_micro_eur}></Euro>
</li>
<section>
<h2>Account information</h2>
<ul>
<li>Username: {window.user.username}</li>
<li>E-mail address: {window.user.email}</li>
<li>
Supporter level: {window.user.subscription.name}
{#if window.user.subscription.type === "patreon"}
(<a href="https://www.patreon.com/join/pixeldrain/checkout?edit=1">Manage subscription</a>)
{/if}
</ul>
{#if window.user.subscription.storage_space === -1}
Storage space used: {formatDataVolume(storage_space_used, 3)}<br/>
{:else}
<StorageProgressBar used={storage_space_used} total={window.user.subscription.storage_space}></StorageProgressBar>
<ul>
<li>
Max file size: {formatDataVolume(window.user.subscription.file_size_limit, 3)}
</li>
{#if window.user.subscription.file_expiry_days > 0}
<li>Files expire after {window.user.subscription.file_expiry_days} days</li>
{:else}
<li>Files never expire</li>
{/if}
</ul>
</li>
{#if window.user.balance_micro_eur !== 0}
<li>
Current account balance: <Euro amount={window.user.balance_micro_eur}></Euro>
</li>
{/if}
</ul>
{#if transfer_cap === -1}
Paid transfers in the last 30 days: {formatDataVolume(transfer_used, 3)}<br/>
{:else}
Paid transfers:
{formatDataVolume(transfer_used, 3)}
out of
{formatDataVolume(transfer_cap, 3)}
(<a href="/user/subscription">Set your transfer limit on the subscription page</a>)
<HotlinkProgressBar used={transfer_used} total={transfer_cap}></HotlinkProgressBar>
{/if}
{#if window.user.subscription.storage_space === -1}
Storage space used: {formatDataVolume(storage_space_used, 3)}<br/>
{:else}
<StorageProgressBar used={storage_space_used} total={window.user.subscription.storage_space}></StorageProgressBar>
{/if}
<h3>Exports</h3>
<div style="text-align: center;">
<a href="/user/export/files" class="button">
<i class="icon">list</i>
Export uploaded files to CSV
</a>
<a href="/user/export/lists" class="button">
<i class="icon">list</i>
Export created lists to CSV
</a>
</div>
{#if transfer_cap === -1}
Paid transfers in the last 30 days: {formatDataVolume(transfer_used, 3)}<br/>
{:else}
Paid transfers:
{formatDataVolume(transfer_used, 3)}
out of
{formatDataVolume(transfer_cap, 3)}
(<a href="/user/subscription">Set your transfer limit on the subscription page</a>)
<HotlinkProgressBar used={transfer_used} total={transfer_cap}></HotlinkProgressBar>
{/if}
<h2>Statistics</h2>
<p>
Here you can see how often your files are viewed, downloaded
and how much bandwidth they consume. The buttons at the top
can be pressed to adjust the timeframe. If you choose 'Day'
the statistics will be updated periodically. No need to
refresh the page.
</p>
<h3>Exports</h3>
<div style="text-align: center;">
<a href="/user/export/files" class="button">
<i class="icon">list</i>
Export uploaded files to CSV
</a>
<a href="/user/export/lists" class="button">
<i class="icon">list</i>
Export created lists to CSV
</a>
</div>
<div class="highlight_light">
<button
on:click={() => { update_graphs(1440, 1, true) }}
class:button_highlight={graph_timespan == 1440}>
Day (1m)
</button>
<button
on:click={() => { update_graphs(10080, 10, false) }}
class:button_highlight={graph_timespan == 10080}>
Week (10m)
</button>
<button
on:click={() => { update_graphs(20160, 60, false) }}
class:button_highlight={graph_timespan == 20160}>
Two Weeks (1h)
</button>
<button
on:click={() => { update_graphs(43200, 1440, false) }}
class:button_highlight={graph_timespan == 43200}>
Month (1d)
</button>
<button
on:click={() => { update_graphs(131400, 1440, false) }}
class:button_highlight={graph_timespan == 131400}>
Quarter (1d)
</button>
<button
on:click={() => { update_graphs(525600, 1440, false) }}
class:button_highlight={graph_timespan == 525600}>
Year (1d)
</button>
<button
on:click={() => { update_graphs(1051200, 1440, false) }}
class:button_highlight={graph_timespan == 1051200}>
Two Years (1d)
</button>
<br/>
Total usage from {time_start} to {time_end}<br/>
{formatThousands(total_views)} views,
{formatThousands(total_downloads)} downloads,
{formatDataVolume(total_bandwidth, 3)} bandwidth and
{formatDataVolume(total_transfer_paid, 3)} paid transfers
</div>
<div class="limit_width">
<h3>Premium transfers and total bandwidth usage</h3>
<p>
A premium transfer is when a file is downloaded using the data cap
on your subscription plan. These can be files you downloaded from
other people, or other people downloading your files if you have
bandwidth sharing enabled. Bandwidth sharing can be changed on
<a href="/user/subscription">the subscription page</a>.
</p>
<p>
Total bandwidth usage is the combined bandwidth usage of all the
files on your account. This includes paid transfers.
</p>
</div>
<Chart bind:this={graph_bandwidth} data_type="bytes"/>
<div class="limit_width">
<h3>Views and downloads</h3>
<p>
A view is counted when someone visits the download page of one of
your files. Views are unique per user per file.
</p>
<p>
Downloads are counted when a user clicks the download button on one
of your files. It does not matter whether the download is completed
or not, only the start of the download is counted.
</p>
</div>
<Chart bind:this={graph_views_downloads} data_type="number"/>
<h2>Statistics</h2>
<p>
Here you can see how often your files are viewed, downloaded
and how much bandwidth they consume. The buttons at the top
can be pressed to adjust the timeframe. If you choose 'Day'
the statistics will be updated periodically. No need to
refresh the page.
</p>
</section>
<div class="highlight_light">
<button
on:click={() => { update_graphs(1440, 1, true) }}
class:button_highlight={graph_timespan == 1440}>
Day (1m)
</button>
<button
on:click={() => { update_graphs(10080, 10, false) }}
class:button_highlight={graph_timespan == 10080}>
Week (10m)
</button>
<button
on:click={() => { update_graphs(20160, 60, false) }}
class:button_highlight={graph_timespan == 20160}>
Two Weeks (1h)
</button>
<button
on:click={() => { update_graphs(43200, 1440, false) }}
class:button_highlight={graph_timespan == 43200}>
Month (1d)
</button>
<button
on:click={() => { update_graphs(131400, 1440, false) }}
class:button_highlight={graph_timespan == 131400}>
Quarter (1d)
</button>
<button
on:click={() => { update_graphs(525600, 1440, false) }}
class:button_highlight={graph_timespan == 525600}>
Year (1d)
</button>
<button
on:click={() => { update_graphs(1051200, 1440, false) }}
class:button_highlight={graph_timespan == 1051200}>
Two Years (1d)
</button>
<br/>
Total usage from {time_start} to {time_end}<br/>
{formatThousands(total_views)} views,
{formatThousands(total_downloads)} downloads,
{formatDataVolume(total_bandwidth, 3)} bandwidth and
{formatDataVolume(total_transfer_paid, 3)} paid transfers
</div>
<section>
<h3>Premium transfers and total bandwidth usage</h3>
<p>
A premium transfer is when a file is downloaded using the data cap
on your subscription plan. These can be files you downloaded from
other people, or other people downloading your files if you have
bandwidth sharing enabled. Bandwidth sharing can be changed on
<a href="/user/subscription">the subscription page</a>.
</p>
<p>
Total bandwidth usage is the combined bandwidth usage of all the
files on your account. This includes paid transfers.
</p>
</section>
<Chart bind:this={graph_bandwidth} data_type="bytes"/>
<section>
<h3>Views and downloads</h3>
<p>
A view is counted when someone visits the download page of one of
your files. Views are unique per user per file.
</p>
<p>
Downloads are counted when a user clicks the download button on one
of your files. It does not matter whether the download is completed
or not, only the start of the download is counted.
</p>
</section>
<Chart bind:this={graph_views_downloads} data_type="number"/>

View File

@@ -8,29 +8,27 @@ export let used = 0
$: frac = used / total
</script>
<div>
<ProgressBar total={total} used={used}></ProgressBar>
<ProgressBar total={total} used={used}></ProgressBar>
{#if frac > 0.99}
<div class="highlight_red">
You have used all of your data cap. People can still download your
files, but not directly from the API anymore. The file viewer shows
ads on your files and download speeds are limited.
<br/>
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</div>
{:else if frac > 0.8}
<div class="highlight_yellow">
You have used {(frac*100).toFixed(0)}% of your data cap. If your
data runs out people won't be able to download your files directly
from the API anymore, ads will be shown on the file viewer and
transfer rates will be limited.
<br/>
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</div>
{/if}
</div>
{#if frac > 0.99}
<div class="highlight_red">
You have used all of your data cap. People can still download your
files, but not directly from the API anymore. The file viewer shows
ads on your files and download speeds are limited.
<br/>
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</div>
{:else if frac > 0.8}
<div class="highlight_yellow">
You have used {(frac*100).toFixed(0)}% of your data cap. If your
data runs out people won't be able to download your files directly
from the API anymore, ads will be shown on the file viewer and
transfer rates will be limited.
<br/>
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</div>
{/if}

View File

@@ -33,7 +33,7 @@ onMount(() => {
<svelte:window on:popstate={get_page} />
<div class="checkers inset">
<header>
<h1>Welcome home, {window.user.username}!</h1>
<div class="tab_bar">
@@ -75,7 +75,7 @@ onMount(() => {
</a>
{/if}
</div>
</div>
</header>
<br/>
{#if page === "home"}

View File

@@ -7,56 +7,54 @@ export let used = 0
$: frac = used / total
</script>
<div>
Storage:
{formatDataVolume(used, 3)}
out of
{formatDataVolume(total, 3)}
<br/>
<ProgressBar total={total} used={used}></ProgressBar>
Storage:
{formatDataVolume(used, 3)}
out of
{formatDataVolume(total, 3)}
<br/>
<ProgressBar total={total} used={used}></ProgressBar>
{#if frac > 2.0}
<div class="highlight_red">
<span class="warn_text">You are using more than 200% of your allowed storage space!</span>
<p>
We have started deleting your files to free up space. If you do
not want to lose any more files please upgrade to a storage plan
which supports the volume of storage which you need:
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</p>
</div>
{:else if frac > 0.99}
<div class="highlight_red">
<p>
You have used all of your storage space. You won't be able to
upload new files anymore. Please upgrade to a higher support
tier to continue uploading files:
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</p>
<p>
Your files will not be deleted any sooner than normal at this
moment. When your storage usage is over 200% we will start
deleting your files to free up the space.
</p>
</div>
{:else if frac > 0.8}
<div class="highlight_yellow">
<p>
You have used {(frac*100).toFixed(0)}% of your
storage space. If your storage space runs out you won't be able
to upload new files anymore. Please upgrade to a higher support
tier to continue uploading files:
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</p>
</div>
{/if}
</div>
{#if frac > 2.0}
<div class="highlight_red">
<span class="warn_text">You are using more than 200% of your allowed storage space!</span>
<p>
We have started deleting your files to free up space. If you do
not want to lose any more files please upgrade to a storage plan
which supports the volume of storage which you need:
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</p>
</div>
{:else if frac > 0.99}
<div class="highlight_red">
<p>
You have used all of your storage space. You won't be able to
upload new files anymore. Please upgrade to a higher support
tier to continue uploading files:
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</p>
<p>
Your files will not be deleted any sooner than normal at this
moment. When your storage usage is over 200% we will start
deleting your files to free up the space.
</p>
</div>
{:else if frac > 0.8}
<div class="highlight_yellow">
<p>
You have used {(frac*100).toFixed(0)}% of your
storage space. If your storage space runs out you won't be able
to upload new files anymore. Please upgrade to a higher support
tier to continue uploading files:
<a class="button button_highlight" href="https://www.patreon.com/join/pixeldrain">
Upgrade options
</a>
</p>
</div>
{/if}
<style>
.warn_text {

View File

@@ -74,170 +74,169 @@ onMount(load_tranfer_used)
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<div class="limit_width">
<h2>Manage subscription</h2>
{#if window.user.subscription.type !== "patreon"}
<p>
Current account balance: <Euro amount={window.user.balance_micro_eur}></Euro>
</p>
<p>
When your prepaid subscription is active you will be charged daily
based on usage. Hotlink bandwidth is charged per TB based on the
usage of the previous day. The amount charged for storage each day
is your storage usage at the end of the day multiplied by the
storage price (€4 / TB) and divided by the average number of days in
a month (30.4375). So if you have exactly 1 TB on your account you
will be charged €0.131416838 per day.
</p>
<p>
The prepaid subscription will stay active for as long as you have
credit on your account. When you reach negative balance the
subscription will automatically end. You will need a positive
balance to activate the subscription again.
</p>
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<h3>Prepaid plans</h3>
{#if result !== ""}
<div class:highlight_green={result_success} class:highlight_red={!result_success}>
{result}
</div>
{/if}
<section>
<h2>Manage subscription</h2>
{#if window.user.subscription.type !== "patreon"}
<p>
Current account balance: <Euro amount={window.user.balance_micro_eur}></Euro>
</p>
<p>
When your prepaid subscription is active you will be charged daily
based on usage. Hotlink bandwidth is charged per TB based on the
usage of the previous day. The amount charged for storage each day
is your storage usage at the end of the day multiplied by the
storage price (€4 / TB) and divided by the average number of days in
a month (30.4375). So if you have exactly 1 TB on your account you
will be charged €0.131416838 per day.
</p>
<p>
The prepaid subscription will stay active for as long as you have
credit on your account. When you reach negative balance the
subscription will automatically end. You will need a positive
balance to activate the subscription again.
</p>
<div class="feat_table">
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid"}>
Prepaid<br/>
{#if subscription === "prepaid"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid"; update("subscription")}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal round_tr">
<ul>
<li>Base price of €1 per month</li>
<li>€4 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files never expire as long as subscription is active</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid_temp_storage_120d"}>
120 days storage<br/>
{#if subscription === "prepaid_temp_storage_120d"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid_temp_storage_120d"; update("subscription")}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€2 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files expire 120 days after the last time they're viewed</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid_temp_storage_60d"}>
60 days storage<br/>
{#if subscription === "prepaid_temp_storage_60d"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid_temp_storage_60d"; update("subscription")}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€1 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files expire 60 days after the last time they're viewed</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === ""}>
Free<br/>
{#if subscription === ""}
Currently active
{:else}
<button on:click={() => {subscription = ""; update("subscription")}}>
<i class="icon">money_off</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal round_br">
<ul>
<li>Standard free plan, files expire after 30 days.</li>
</ul>
</div>
</div>
<h3>Prepaid plans</h3>
{#if result !== ""}
<div class:highlight_green={result_success} class:highlight_red={!result_success}>
{result}
</div>
{/if}
<h3>Bandwidth sharing</h3>
{#if hotlinking}
<button on:click={() => { hotlinking = false; update("limits") }}>
<i class="icon green">check</i> ON (click to turn off)
</button>
{:else}
<button on:click={() => { hotlinking = true; update("limits") }}>
<i class="icon red">close</i> OFF (click to turn on)
</button>
{/if}
<p>
When bandwidth sharing is enabled all the bandwidth that your files
use will be subtracted from your data cap. Advertisements will be
disabled on the download pages for your files and download speed
will be unlimited. The rate limiting captcha for files is also
disabled when bandwidth sharing is on. You can directly embed your
file's download link anywhere, you don't need to use the file viewer
page.
</p>
<div class="feat_table">
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid"}>
Prepaid<br/>
{#if subscription === "prepaid"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid"; update("subscription")}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal round_tr">
<ul>
<li>Base price of €1 per month</li>
<li>€4 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files never expire as long as subscription is active</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid_temp_storage_120d"}>
120 days storage<br/>
{#if subscription === "prepaid_temp_storage_120d"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid_temp_storage_120d"; update("subscription")}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€2 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files expire 120 days after the last time they're viewed</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === "prepaid_temp_storage_60d"}>
60 days storage<br/>
{#if subscription === "prepaid_temp_storage_60d"}
Currently active
{:else}
<button on:click={() => {subscription = "prepaid_temp_storage_60d"; update("subscription")}}>
<i class="icon">attach_money</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal">
<ul>
<li>Base price of €1 per month</li>
<li>€1 per TB per month for storage</li>
<li>€2 per TB for data transfer</li>
<li>Files expire 60 days after the last time they're viewed</li>
</ul>
</div>
</div>
<div>
<div class="feat_label" class:feat_highlight={subscription === ""}>
Free<br/>
{#if subscription === ""}
Currently active
{:else}
<button on:click={() => {subscription = ""; update("subscription")}}>
<i class="icon">money_off</i>
Activate
</button>
{/if}
</div>
<div class="feat_normal round_br">
<ul>
<li>Standard free plan, files expire after 30 days.</li>
</ul>
</div>
</div>
</div>
{/if}
<h3>Bill shock limit</h3>
<p>
Billshock limit in gigabytes per month (1 TB = 1000 GB). Set to 0 to disable.
</p>
<form on:submit|preventDefault={() => {update("limits")}} class="billshock_container">
<input type="number" bind:value={transfer_cap} step="100" min="0"/>
<div style="margin: 0.5em;">GB</div>
<button type="submit">
<i class="icon">save</i> Save
</button>
</form>
<h3>Bandwidth sharing</h3>
{#if hotlinking}
<button on:click={() => { hotlinking = false; update("limits") }}>
<i class="icon green">check</i> ON (click to turn off)
</button>
{:else}
<button on:click={() => { hotlinking = true; update("limits") }}>
<i class="icon red">close</i> OFF (click to turn on)
</button>
{/if}
<p>
When bandwidth sharing is enabled all the bandwidth that your files
use will be subtracted from your data cap. Advertisements will be
disabled on the download pages for your files and download speed
will be unlimited. The rate limiting captcha for files is also
disabled when bandwidth sharing is on. You can directly embed your
file's download link anywhere, you don't need to use the file viewer
page.
</p>
Bandwidth used in the last 30 days: {formatDataVolume(transfer_used, 3)},
new limit: {formatDataVolume(transfer_cap*1e9, 3)}
<ProgressBar used={transfer_used} total={transfer_cap*1e9}></ProgressBar>
<p>
The billshock limit limits how much bandwidth your account can use
in a 30 day window. When this limit is reached files will show ads
again and can only be downloaded from the file viewer page. This is
mostly useful for prepaid plans, but it works for patreon plans too.
Set to 0 to disable the limit.
</p>
</div>
</div>
<h3>Bill shock limit</h3>
<p>
Billshock limit in gigabytes per month (1 TB = 1000 GB). Set to 0 to disable.
</p>
<form on:submit|preventDefault={() => {update("limits")}} class="billshock_container">
<input type="number" bind:value={transfer_cap} step="100" min="0"/>
<div style="margin: 0.5em;">GB</div>
<button type="submit">
<i class="icon">save</i> Save
</button>
</form>
Bandwidth used in the last 30 days: {formatDataVolume(transfer_used, 3)},
new limit: {formatDataVolume(transfer_cap*1e9, 3)}
<ProgressBar used={transfer_used} total={transfer_cap*1e9}></ProgressBar>
<p>
The billshock limit limits how much bandwidth your account can use
in a 30 day window. When this limit is reached files will show ads
again and can only be downloaded from the file viewer page. This is
mostly useful for prepaid plans, but it works for patreon plans too.
Set to 0 to disable the limit.
</p>
</section>
<style>
.spinner_container {

View File

@@ -120,157 +120,156 @@ onMount(() => {
})
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<div class="limit_width">
<h2>Deposit credits</h2>
<p>
You can deposit credit on your pixeldrain account with Bitcoin,
Lightning network (<a
href="https://btcpay.pixeldrain.com/embed/uS2mbWjXUuaAqMh8XLjkjwi8oehFuxeBZxekMxv68LN/BTC/ln"
target="_blank">node info</a>) and Dogecoin. You must pay the full
amount as stated on the invoice, else your payment will fail.
</p>
<p>
Do note that it is not possible to withdraw coins from your
pixeldrain account. It's not a wallet. Any amount of money you
deposit has to be used up.
</p>
<div style="text-align: center;">
Deposit amount €
<input type="number" bind:value={credit_amount} min="1"/>
<br/>
Pay with:<br/>
<button on:click={() => {checkout("btc")}}>
<span class="icon_unicode"></span> Bitcoin
</button>
<button on:click={() => {checkout("btc_lightning")}}>
<i class="icon">bolt</i> Lightning network
</button>
<button on:click={() => {checkout("doge")}}>
<span class="icon_unicode">Ð</span> Dogecoin
</button>
</div>
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<section>
<h2>Deposit credits</h2>
<p>
You can deposit credit on your pixeldrain account with Bitcoin,
Lightning network (<a
href="https://btcpay.pixeldrain.com/embed/uS2mbWjXUuaAqMh8XLjkjwi8oehFuxeBZxekMxv68LN/BTC/ln"
target="_blank">node info</a>) and Dogecoin. You must pay the full
amount as stated on the invoice, else your payment will fail.
</p>
<p>
Do note that it is not possible to withdraw coins from your
pixeldrain account. It's not a wallet. Any amount of money you
deposit has to be used up.
</p>
<div style="text-align: center;">
Deposit amount €
<input type="number" bind:value={credit_amount} min="1"/>
<br/>
Pay with:<br/>
<button on:click={() => {checkout("btc")}}>
<span class="icon_unicode"></span> Bitcoin
</button>
<button on:click={() => {checkout("btc_lightning")}}>
<i class="icon">bolt</i> Lightning network
</button>
<button on:click={() => {checkout("doge")}}>
<span class="icon_unicode">Ð</span> Dogecoin
</button>
</div>
<h3>Open invoices</h3>
<div class="table_scroll">
<table style="text-align: left;">
<thead>
<tr>
<td>Created</td>
<td>Amount</td>
<td>Status</td>
<td></td>
</tr>
</thead>
<tbody>
{#each invoices as row (row.id)}
{#if row.status === "New" ||
row.status === "InvoiceCreated" ||
row.status === "InvoiceProcessing" ||
show_expired
}
<tr>
<td>{formatDate(row.time, true, true, false)}</td>
<td><Euro amount={row.amount}></Euro></td>
<td>
{#if row.status === "InvoiceCreated"}
New (waiting for payment)
{:else if row.status === "InvoiceProcessing"}
Payment received, waiting for confirmations
{:else if row.status === "InvoiceSettled"}
Paid
{:else if row.status === "InvoiceExpired"}
Expired
{:else}
{row.status}
{/if}
</td>
<td>
{#if row.status === "New" || row.status === "InvoiceCreated"}
<a href={row.checkout_url} class="button button_highlight">
<i class="icon">paid</i> Pay
</a>
{/if}
</td>
</tr>
{/if}
{/each}
</tbody>
</table>
<div style="text-align: center;">
<button on:click={() => {show_expired = !show_expired}}>
{#if show_expired}
Hide
{:else}
Show
{/if}
expired and settled invoices
</button>
</div>
</div>
<h2>Transaction log</h2>
<p>
Here is a log of all transactions on your account balance.
</p>
{#each months as month}
<h3>{month.month}</h3>
<ul>
<li>Subscription charge: <Euro amount={month.total_subscription_charge}></Euro></li>
<li>Storage charge: <Euro amount={month.total_storage_charge}></Euro></li>
<li>Bandwidth charge: <Euro amount={month.total_bandwidth_charge}></Euro></li>
<li>Total charge: <Euro amount={month.total_deducted}></Euro></li>
<li>Deposited: <Euro amount={month.total_deposited}></Euro></li>
</ul>
<h3>Open invoices</h3>
<div class="table_scroll">
<table style="text-align: left;">
<thead>
<tr>
<td>Created</td>
<td>Amount</td>
<td>Status</td>
<td>Time</td>
<td>Balance</td>
<td>Subscription</td>
<td colspan="2">Storage</td>
<td colspan="2">Bandwidth</td>
<td>Deposited</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Charged</td>
<td>Charged</td>
<td>Used</td>
<td>Charged</td>
<td>Used</td>
<td></td>
</tr>
</thead>
<tbody>
{#each invoices as row (row.id)}
{#if row.status === "New" ||
row.status === "InvoiceCreated" ||
row.status === "InvoiceProcessing" ||
show_expired
}
<tr>
<td>{formatDate(row.time, true, true, false)}</td>
<td><Euro amount={row.amount}></Euro></td>
<td>
{#if row.status === "InvoiceCreated"}
New (waiting for payment)
{:else if row.status === "InvoiceProcessing"}
Payment received, waiting for confirmations
{:else if row.status === "InvoiceSettled"}
Paid
{:else if row.status === "InvoiceExpired"}
Expired
{:else}
{row.status}
{/if}
</td>
<td>
{#if row.status === "New" || row.status === "InvoiceCreated"}
<a href={row.checkout_url} class="button button_highlight">
<i class="icon">paid</i> Pay
</a>
{/if}
</td>
</tr>
{/if}
{#each month.rows as row}
<tr>
<td>{formatDate(row.time, true, true, false)}</td>
<td><Euro amount={row.new_balance}></Euro></td>
<td><Euro amount={row.subscription_charge} precision="4"></Euro></td>
<td><Euro amount={row.storage_charge} precision="4"></Euro></td>
<td>{formatDataVolume(row.storage_used, 3)}</td>
<td><Euro amount={row.bandwidth_charge} precision="4"></Euro></td>
<td>{formatDataVolume(row.bandwidth_used, 3)}</td>
<td><Euro amount={row.deposit_amount}></Euro></td>
</tr>
{/each}
</tbody>
</table>
<div style="text-align: center;">
<button on:click={() => {show_expired = !show_expired}}>
{#if show_expired}
Hide
{:else}
Show
{/if}
expired and settled invoices
</button>
</div>
</div>
<h2>Transaction log</h2>
<p>
Here is a log of all transactions on your account balance.
</p>
{#each months as month}
<h3>{month.month}</h3>
<ul>
<li>Subscription charge: <Euro amount={month.total_subscription_charge}></Euro></li>
<li>Storage charge: <Euro amount={month.total_storage_charge}></Euro></li>
<li>Bandwidth charge: <Euro amount={month.total_bandwidth_charge}></Euro></li>
<li>Total charge: <Euro amount={month.total_deducted}></Euro></li>
<li>Deposited: <Euro amount={month.total_deposited}></Euro></li>
</ul>
<div class="table_scroll">
<table style="text-align: left;">
<thead>
<tr>
<td>Time</td>
<td>Balance</td>
<td>Subscription</td>
<td colspan="2">Storage</td>
<td colspan="2">Bandwidth</td>
<td>Deposited</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Charged</td>
<td>Charged</td>
<td>Used</td>
<td>Charged</td>
<td>Used</td>
<td></td>
</tr>
</thead>
<tbody>
{#each month.rows as row}
<tr>
<td>{formatDate(row.time, true, true, false)}</td>
<td><Euro amount={row.new_balance}></Euro></td>
<td><Euro amount={row.subscription_charge} precision="4"></Euro></td>
<td><Euro amount={row.storage_charge} precision="4"></Euro></td>
<td>{formatDataVolume(row.storage_used, 3)}</td>
<td><Euro amount={row.bandwidth_charge} precision="4"></Euro></td>
<td>{formatDataVolume(row.bandwidth_used, 3)}</td>
<td><Euro amount={row.deposit_amount}></Euro></td>
</tr>
{/each}
</tbody>
</table>
</div>
{/each}
</div>
</div>
{/each}
</section>
<style>
.spinner_container {

View File

@@ -28,10 +28,8 @@ export const toggle = () => {
.expandable {
text-decoration: none;
background-color: var(--layer_3_color);
transition: box-shadow 0.5s;
box-shadow: 1px 1px 6px -2px var(--shadow_color);
margin: 1em 0;
border-radius: 8px;
margin: 0.8em 0;
border-radius: 6px;
overflow: hidden;
}
.header {