File viewer gallery view

This commit is contained in:
2021-11-23 23:45:42 +01:00
parent 3a77f8c13a
commit 55f7cf7307
9 changed files with 533 additions and 169 deletions

View File

@@ -286,7 +286,7 @@ h3 {
}
h4 {
font-size: 1.25em;
font-family: sans-serif;
font-family: "light", sans-serif;
border-bottom: 1px var(--layer_2_color_border) solid;
}
h5 {

View File

@@ -11,6 +11,7 @@ export let file = {
size: 0,
downloads: 0,
bandwidth_used: 0,
bandwidth_used_paid: 0,
description: "",
timeseries_href: "",
}
@@ -20,6 +21,9 @@ let view_chart
$: update_charts(file.id)
let update_charts = () => {
if (file.id === "") {
return
}
console.log("updating graph")
let today = new Date()

View File

@@ -1,21 +1,41 @@
<script>
import { createEventDispatcher } from "svelte";
import Spinner from "../util/Spinner.svelte"
let dispatch = createEventDispatcher()
export let file = {
id: "",
name: "",
get_href: "",
can_edit: false,
}
export let list = {
id: "",
title: "",
files: [],
can_edit: false,
info_href: "",
}
let file_name = ""
let loading = false
let result_success = false
let result_text = ""
let file_name = ""
$: update_file(file.id)
let update_file = () => {
file_name = file.name
}
let list_name = ""
$: update_list(list.id)
let update_list = () => {
list_name = list.title
}
let rename_file = async e => {
e.preventDefault()
loading = true
const form = new FormData()
form.append("action", "rename")
@@ -32,6 +52,9 @@ let rename_file = async e => {
} catch (err) {
result_success = false
result_text = "Could not change file name: " + err
} finally {
loading = false
dispatch("reload")
}
}
@@ -39,6 +62,7 @@ let delete_file = async e => {
if (!confirm("Are you sure you want to delete '" + file.name + "'?")) {
return
}
loading = true
try {
const resp = await fetch(file.get_href, { method: "DELETE" });
@@ -51,39 +75,132 @@ let delete_file = async e => {
} catch (err) {
result_success = false
result_text = "Could not delete file: " + err
} finally {
loading = false
}
}
let rename_list = async e => {
e.preventDefault()
loading = true
let listjson = {
title: list_name,
files: [],
}
list.files.forEach(f => {
listjson.files.push({
id: f.id,
})
})
try {
const resp = await fetch(
list.info_href,
{ method: "PUT", body: JSON.stringify(listjson) },
);
if (resp.status >= 400) {
throw (await resp.json()).message
}
result_success = true
result_text = "Album name has been changed. Reload the page to see the changes"
} catch (err) {
result_success = false
result_text = "Could not change album name: " + err
} finally {
loading = false
dispatch("reload")
}
}
let delete_list = async e => {
if (!confirm("Are you sure you want to delete '" + list.title + "'?")) {
return
}
loading = true
try {
const resp = await fetch(list.info_href, { method: "DELETE" });
if (resp.status >= 400) {
throw (await resp.json()).message
}
result_success = true
result_text = "This album has been deleted, you can close the page"
} catch (err) {
result_success = false
result_text = "Could not delete album: " + err
} finally {
loading = false
}
}
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner></Spinner>
</div>
{/if}
{#if result_text !== ""}
<div class:highlight_green={result_success} class:highligt_red={!result_success}>
{result_text}
</div>
{/if}
<h3>Rename</h3>
<form on:submit={rename_file} style="display: flex; width: 100%">
<input bind:value={file_name} type="text" style="flex: 1 1 auto"/>
<button type="submit" style="flex: 0 0 auto">
<i class="icon">save</i> Save
</button>
</form>
<h3>Delete</h3>
<p>
When you delete a file it cannot be recovered.
Nobody will be able to download it and the link will
stop working. The file will also disappear from any
lists it's contained in.
</p>
<div style="text-align: center;">
<button on:click={delete_file} class="button_red">
<i class="icon small">delete</i> Delete this file
</button>
</div>
{#if list.can_edit}
<h3>Edit album</h3>
<h4>Rename</h4>
<form on:submit={rename_list} class="indent" style="display: flex;">
<input bind:value={list_name} type="text" style="flex: 1 1 auto"/>
<button type="submit" style="flex: 0 0 auto">
<i class="icon">save</i> Save
</button>
</form>
<h4>Delete</h4>
<p>
When you delete an album the files in the album will not be deleted,
only the album itself.
</p>
<div class="indent">
<button on:click={delete_list} class="button_red">
<i class="icon small">delete</i> Delete album
</button>
</div>
{/if}
{#if file.can_edit}
<h3>Edit file</h3>
<h4>Rename</h4>
<form on:submit={rename_file} class="indent" style="display: flex;">
<input bind:value={file_name} type="text" style="flex: 1 1 auto"/>
<button type="submit" style="flex: 0 0 auto">
<i class="icon">save</i> Save
</button>
</form>
<h4>Delete</h4>
<p>
When you delete a file it cannot be recovered.
Nobody will be able to download it and the link will
stop working. The file will also disappear from any
lists it's contained in.
</p>
<div class="indent">
<button on:click={delete_file} class="button_red">
<i class="icon small">delete</i> Delete file
</button>
</div>
{/if}
</div>
<style>
.spinner_container {
position: absolute;
top: 10px;
left: 10px;
height: 100px;
width: 100px;
}
</style>

View File

@@ -15,46 +15,60 @@ import AdHead from "./AdHead.svelte";
import AdLeaderboard from "./AdLeaderboard.svelte";
import AdSkyscraper from "./AdSkyscraper.svelte";
import Sharebar from "./Sharebar.svelte";
import GalleryView from "./GalleryView.svelte";
import Spinner from "../util/Spinner.svelte";
let is_list = false
let embedded = false
let view_token = ""
let current_file = {
const file_struct = {
id: "",
name: "loading...",
name: "",
size: 0,
bandwidth_used: 0,
bandwidth_used_paid: 0,
downloads: 0,
views: 0,
mime_type: "",
availability: "",
abuse_type: "",
show_ads: false,
can_edit: false,
get_href: "",
info_href: "",
download_href: "",
icon_href: "",
}
let current_list = {
const list_struct = {
id: "",
title: "",
files: [],
download_href: "",
info_href: "",
can_edit: false,
}
let loading = true
let embedded = false
let view_token = ""
let ads_enabled = false
let view = "" // file or gallery
let file = file_struct
let list = list_struct
let is_list = false
let button_home
let list_navigator
let list_shuffle = false
let toggle_shuffle = () => {
list_shuffle = !list_shuffle
list_navigator.set_shuffle(list_shuffle)
}
let sharebar
let sharebar_visible = false
let toggle_sharebar = () => {
if (navigator.share) {
let name = current_file.name
let name = file.name
if (is_list) {
name = current_list.title
name = list.title
}
navigator.share({
@@ -104,40 +118,109 @@ onMount(() => {
if (viewer_data.type === "list") {
open_list(viewer_data.api_response)
} else {
open_file(viewer_data.api_response)
list.files = [viewer_data.api_response]
open_file_index(0)
}
})
const open_list = (list) => {
list.download_href = window.api_endpoint+"/list/"+list.id+"/zip"
list.files.forEach(file => {
file_set_href(file)
ads_enabled = list.files[0].show_ads
loading = false
})
const reload = async () => {
loading = true
if (is_list) {
try {
const resp = await fetch(list.info_href);
if (resp.status >= 400) {
throw (await resp.json()).message
}
open_list(await resp.json())
} catch (err) {
alert(err)
}
} else {
try {
const resp = await fetch(file.info_href);
if (resp.status >= 400) {
throw (await resp.json()).message
}
list.files = [await resp.json()]
open_file_index(0)
} catch (err) {
alert(err)
}
}
loading = false
}
const open_list = async l => {
l.download_href = window.api_endpoint+"/list/"+l.id+"/zip"
l.info_href = window.api_endpoint+"/list/"+l.id
l.files.forEach(f => {
file_set_href(f)
})
current_list = list
list = l
// Setting is_list to true activates the ListNavgator, which makes sure the
// correct file is opened
is_list = true
}
const open_file = (file) => {
file_set_href(file)
current_file = file
// Skip to the file defined in the link hash
let matches = location.hash.match(new RegExp('item=([^&]*)'))
let hashID = parseInt(matches ? matches[1] : null)
if (Number.isInteger(hashID)) {
// The URL contains an item number. Navigate to that item
view = "file"
open_file_index(parseInt(hashID))
} else {
view = "gallery"
}
}
const open_file_index = async index => {
if (index >= list.files.length) {
index = 0
} else if (index < 0) {
index = list.files.length - 1
}
console.debug("received request to open file", index)
file_set_href(list.files[index])
file = list.files[index]
view = "file"
if (is_list) {
// Wait for the ListNavigator to render
await tick()
// Update the URL
location.replace("#item=" + index)
list_navigator.set_item(index)
}
// Register a file view
fetch(window.api_endpoint + "/file/" + current_file.id + "/view", {
fetch(window.api_endpoint + "/file/" + file.id + "/view", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "token=" + view_token
})
}
const file_set_href = file => {
file.get_href = window.api_endpoint+"/file/"+file.id
file.download_href = window.api_endpoint+"/file/"+file.id+"?download"
file.icon_href = window.api_endpoint+"/file/"+file.id+"/thumbnail"
file.timeseries_href = window.api_endpoint+"/file/"+file.id+"/timeseries"
const file_set_href = f => {
f.get_href = window.api_endpoint+"/file/"+f.id
f.info_href = window.api_endpoint+"/file/"+f.id+"/info"
f.download_href = window.api_endpoint+"/file/"+f.id+"?download"
f.icon_href = window.api_endpoint+"/file/"+f.id+"/thumbnail"
f.timeseries_href = window.api_endpoint+"/file/"+f.id+"/timeseries"
}
const toggle_gallery = () => {
if (view === "gallery") {
open_file_index(0)
} else {
location.replace("#gallery")
view = "gallery"
file = file_struct // Empty the file struct
}
}
let download_frame
@@ -149,12 +232,12 @@ let captcha_container
const download = () => {
if (!window.viewer_data.captcha_key) {
console.debug("Server doesn't support captcha, starting download")
download_frame.src = current_file.download_href
download_frame.src = file.download_href
return
}
if (current_file.availability === "") {
if (file.availability === "") {
console.debug("File is available, starting download")
download_frame.src = current_file.download_href
download_frame.src = file.download_href
return
}
@@ -164,7 +247,7 @@ const download = () => {
// we trigger the download using the captcha token Google provided us with
let captcha_complete_callback = token => {
// Download the file using the recaptcha token
download_frame.src = current_file.download_href + "&recaptcha_response=" + token
download_frame.src = file.download_href + "&recaptcha_response=" + token
download_captcha_window.hide()
}
@@ -180,10 +263,10 @@ const download = () => {
})
}
if (current_file.availability === "file_rate_limited_captcha_required") {
if (file.availability === "file_rate_limited_captcha_required") {
captcha_type = "rate_limit"
captcha_window_title = "Rate limiting enabled!"
} else if (current_file.availability === "virus_detected_captcha_required") {
} else if (file.availability === "virus_detected_captcha_required") {
captcha_type = "malware"
captcha_window_title = "Malware warning!"
}
@@ -202,7 +285,7 @@ const download = () => {
}
const download_list = () => {
if (is_list) {
download_frame.src = current_list.download_href
download_frame.src = list.download_href
}
}
@@ -233,12 +316,12 @@ const copy_url = () => {
}
const grab_file = async () => {
if (!window.user_authenticated || current_file.can_edit) {
if (!window.user_authenticated || file.can_edit) {
return
}
const form = new FormData()
form.append("grab_file", current_file.id)
form.append("grab_file", file.id)
try {
const resp = await fetch(
@@ -297,7 +380,7 @@ const keyboard_event = evt => {
details_window.toggle()
break
case 69: // E to open the edit window
if (current_file.can_edit) {
if (file.can_edit) {
edit_window.toggle()
}
break
@@ -321,6 +404,12 @@ const keyboard_event = evt => {
<!-- Head elements for the ads -->
<AdHead></AdHead>
{#if loading}
<div class="spinner_container">
<Spinner></Spinner>
</div>
{/if}
<div id="headerbar" class="headerbar" class:embedded>
<button on:click={toolbar_toggle} class="button_toggle_toolbar round" class:button_highlight={toolbar_visible}>
<i class="icon">menu</i>
@@ -329,8 +418,8 @@ const keyboard_event = evt => {
<PixeldrainLogo style="height: 1.6em; width: 1.6em; margin: 0 4px 0 0;"></PixeldrainLogo>
</a>
<div id="file_viewer_headerbar_title" class="file_viewer_headerbar_title">
<div id="list_title">{current_list.title}</div>
<div id="lile_title">{current_file.name}</div>
{#if list.title !== ""}{list.title}<br/>{/if}
{#if file.name !== ""}{file.name}{/if}
</div>
{#if embedded && supports_fullscreen}
<button class="round" on:click={toggle_fullscreen}>
@@ -339,27 +428,43 @@ const keyboard_event = evt => {
{/if}
</div>
{#if is_list}
<ListNavigator bind:this={list_navigator} files={current_list.files} on:set_file={(e) => { open_file(e.detail) }}></ListNavigator>
{#if is_list && view === "file"}
<ListNavigator
bind:this={list_navigator}
files={list.files}
shuffle={list_shuffle}
on:set_file={e => { open_file_index(e.detail) }}>
</ListNavigator>
{/if}
<div id="file_preview_window" class="file_preview_window">
<div id="toolbar" class="toolbar" class:toolbar_visible><div><div>
<FileStats file={current_file}></FileStats>
{#if is_list}
<button on:click={toggle_gallery} class="toolbar_button button_full_width" class:button_highlight={view === "gallery"}>
<i class="icon">photo_library</i>
Gallery
</button>
<hr/>
{/if}
<hr/>
{#if current_file.abuse_type === ""}
{#if view === "file"}
<FileStats file={file}></FileStats>
<hr/>
{/if}
{#if file.abuse_type === "" && view === "file"}
<button on:click={download} class="toolbar_button button_full_width">
<i class="icon">save</i>
<i class="icon">download</i>
<span>Download</span>
</button>
{#if is_list}
<button on:click={download_list} class="toolbar_button button_full_width">
<i class="icon">save</i>
<span>DL all files</span>
</button>
{/if}
{/if}
{#if file.abuse_type === "" && is_list}
<button on:click={download_list} class="toolbar_button button_full_width">
<i class="icon">download</i>
<span>DL all files</span>
</button>
{/if}
<button on:click={copy_url}
class="toolbar_button button_full_width"
class:button_highlight={copy_url_status === "copied"}
@@ -375,21 +480,23 @@ const keyboard_event = evt => {
{/if}
</span>
</button>
<button on:click={toggle_sharebar} class="toolbar_button button_full_width" class:button_highlight={sharebar_visible}>
<i class="icon">share</i>
<span>Share</span>
</button>
<button class="toolbar_button button_full_width" on:click={qr_window.toggle} class:button_highlight={qr_visible}>
<i class="icon">qr_code</i>
<span>QR code</span>
</button>
{#if is_list}
<button
class="toolbar_button button_full_width"
title="Randomize the order of the files in this list"
class:button_highlight={list_shuffle}
on:click={toggle_shuffle}
>
on:click={toggle_shuffle}>
<i class="icon">shuffle</i>
{#if list_shuffle}
<span>Shuffle&nbsp;&#x2611;</span>
@@ -398,46 +505,65 @@ const keyboard_event = evt => {
{/if}
</button>
{/if}
<button class="toolbar_button button_full_width" on:click={details_window.toggle} class:button_highlight={details_visible}>
<i class="icon">help</i>
<span>Deta<u>i</u>ls</span>
</button>
{#if view === "file"}
<button class="toolbar_button button_full_width" on:click={details_window.toggle} class:button_highlight={details_visible}>
<i class="icon">help</i>
<span>Deta<u>i</u>ls</span>
</button>
{/if}
<hr/>
{#if current_file.can_edit}
{#if file.can_edit || list.can_edit}
<button class="toolbar_button button_full_width" on:click={edit_window.toggle} class:button_highlight={edit_visible}>
<i class="icon">edit</i>
<span><u>E</u>dit</span>
</button>
{/if}
{#if window.user_authenticated && !current_file.can_edit}
{#if view === "file" && window.user_authenticated && !file.can_edit}
<button on:click={grab_file} class="toolbar_button button_full_width" title="Copy this file to your own pixeldrain account">
<i class="icon">save_alt</i>
<span><u>G</u>rab file</span>
</button>
{/if}
<button class="toolbar_button button_full_width" title="Include this file in your own webpages" on:click={embed_window.toggle} class:button_highlight={embed_visible}>
<i class="icon">code</i>
<span>E<u>m</u>bed</span>
</button>
<button class="toolbar_button button_full_width" title="Report abuse in this file" on:click={report_window.toggle} class:button_highlight={report_visible}>
<i class="icon">flag</i>
<span>Report</span>
</button>
{#if view === "file"}
<button class="toolbar_button button_full_width" title="Report abuse in this file" on:click={report_window.toggle} class:button_highlight={report_visible}>
<i class="icon">flag</i>
<span>Report</span>
</button>
{/if}
<br/>
</div></div></div>
<Sharebar bind:this={sharebar}></Sharebar>
<div id="file_preview" class="file_preview checkers" class:toolbar_visible class:skyscraper_visible>
<FilePreview
file={current_file}
on:download={download}
on:prev={() => { if (list_navigator) { list_navigator.prev() }}}
on:next={() => { if (list_navigator) { list_navigator.next() }}}>
</FilePreview>
{#if view === "file"}
<FilePreview
file={file}
on:download={download}
on:prev={() => { if (list_navigator) { list_navigator.prev() }}}
on:next={() => { if (list_navigator) { list_navigator.next() }}}>
</FilePreview>
{:else if view === "gallery"}
<GalleryView
list={list}
on:set_file={e => { open_file_index(e.detail) }}
on:reload={reload}
on:loading={e => {loading = e.detail}}>
</GalleryView>
{/if}
</div>
{#if current_file.show_ads}
{#if ads_enabled}
<AdSkyscraper on:visibility={e => {skyscraper_visible = e.detail}}></AdSkyscraper>
{/if}
@@ -445,36 +571,36 @@ const keyboard_event = evt => {
<iframe bind:this={download_frame} title="File download frame" style="display: none; width: 1px; height: 1px;"></iframe>
</div>
{#if current_file.show_ads}
{#if ads_enabled}
<AdLeaderboard></AdLeaderboard>
{:else if !window.viewer_data.user_ads_enabled && !embedded}
<div style="text-align: center; line-height: 1.3em; font-size: 13px;">
Thank you for supporting pixeldrain!
</div>
{:else if !current_file.show_ads && !embedded}
{:else if !ads_enabled && !embedded}
<div style="text-align: center; line-height: 1.3em; font-size: 13px;">
The uploader of this file disabled advertisements. You can do the same for <a href="/#pro">only €2 per month</a>!
</div>
{/if}
<Modal bind:this={details_window} on:is_visible={e => {details_visible = e.detail}} title="File details" width="1200px">
<DetailsWindow file={current_file}></DetailsWindow>
<DetailsWindow file={file}></DetailsWindow>
</Modal>
<Modal bind:this={qr_window} on:is_visible={e => {qr_visible = e.detail}} title="QR code" width="500px">
<img src="{window.api_endpoint}/misc/qr?text={encodeURIComponent(window.location.href)}" alt="QR code" style="display: block; width: 100%;"/>
</Modal>
<Modal bind:this={edit_window} on:is_visible={e => {edit_visible = e.detail}} title={"Editing "+current_file.name}>
<EditWindow file={current_file} list={current_list}></EditWindow>
<Modal bind:this={edit_window} on:is_visible={e => {edit_visible = e.detail}} title={"Editing "+file.name}>
<EditWindow file={file} list={list} on:reload={reload}></EditWindow>
</Modal>
<Modal bind:this={embed_window} on:is_visible={e => {embed_visible = e.detail}} title="Embed file" width="850px">
<EmbedWindow file={current_file} list={current_list}></EmbedWindow>
<EmbedWindow file={file} list={list}></EmbedWindow>
</Modal>
<Modal bind:this={report_window} on:is_visible={e => {report_visible = e.detail}} title="Report abuse" width="800px">
<ReportWindow file={current_file} list={current_list}></ReportWindow>
<ReportWindow file={file} list={list}></ReportWindow>
</Modal>
<Modal bind:this={download_captcha_window} title={captcha_window_title} width="500px">
@@ -498,17 +624,22 @@ const keyboard_event = evt => {
<IntroPopup target={button_home}></IntroPopup>
</div>
<style>
/* Viewer container */
.spinner_container {
position: absolute;
top: 10px;
right: 10px;
height: 100px;
width: 100px;
z-index: 10000;
}
.file_viewer {
position: absolute;
display: flex;
flex-direction: column;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: var(--layer_2_color);
}
@@ -582,7 +713,7 @@ const keyboard_event = evt => {
text-align: center;
vertical-align: middle;
transition: left 0.5s, right 0.5s;
overflow: hidden;
overflow: auto;
box-shadow: inset 2px 2px 10px 2px var(--shadow_color);
border-radius: 16px;
}

View File

@@ -0,0 +1,120 @@
<script>
import { createEventDispatcher } from "svelte";
let dispatch = createEventDispatcher()
export let list = {
id: "",
title: "",
files: [],
download_href: "",
info_href: "",
can_edit: false,
}
const click_file = index => {
dispatch("set_file", index)
}
const delete_file = async index => {
dispatch("loading", true)
let listjson = {
title: list.title,
files: [],
}
list.files.forEach((f, idx) => {
if (idx !== index) {
listjson.files.push({
id: f.id,
})
}
})
try {
const resp = await fetch(
list.info_href,
{ method: "PUT", body: JSON.stringify(listjson) },
);
if (resp.status >= 400) {
throw (await resp.json()).message
}
} catch (err) {
alert("Failed to update album: "+err)
} finally {
dispatch("reload")
}
}
</script>
<div class="gallery">
{#each list.files as file, index}
<div class="file" on:click={() => {click_file(index)}}>
<div
class="icon_container"
class:editing={list.can_edit}
style="background-image: url('{file.icon_href}?width=256&height=256');">
{#if list.can_edit}
<!-- <i class="icon" style="cursor: grab;">drag_indicator</i>
<i class="icon">chevron_left</i>
<i class="icon">chevron_right</i> -->
<i class="icon" on:click|stopPropagation={() => {delete_file(index)}}>delete</i>
{/if}
</div>
{file.name}
</div>
{/each}
<!-- {#if list.can_edit}
<div class="file" style="font-size: 1.5em; padding-top: 2.5em; cursor: pointer;">
<i class="icon">add</i>
<br/>
Add files
</div>
{/if} -->
</div>
<style>
.gallery{
padding: 16px;
box-sizing: border-box;
}
.file{
position: relative;
box-sizing: border-box;
width: 200px;
max-width: 90%;
height: 200px;
margin: 8px;
padding: 0;
overflow: hidden;
border-radius: 8px;
box-shadow: 2px 2px 8px 0 var(--shadow_color);
background-color: var(--layer_3_color);
word-break: break-all;
text-align: center;
line-height: 1.2em;
display: inline-block;
text-overflow: ellipsis;
text-decoration: none;
vertical-align: top;
}
.file:hover {
box-shadow: 0 0 2px 2px var(--highlight_color);
text-decoration: none;
}
.icon_container {
width: 100%;
height: 136px;
background-position: center;
background-size: cover;
font-size: 20px;
text-align: left;
}
.icon_container.editing {
box-shadow: inset 0 60px 40px -40px #000000;
}
.icon_container > i:hover {
color: var(--highlight_color);
cursor: pointer;
}
</style>

View File

@@ -1,5 +1,5 @@
<script>
import { createEventDispatcher, onMount } from "svelte";
import { createEventDispatcher } from "svelte";
let dispatch = createEventDispatcher()
@@ -7,27 +7,17 @@ export let files = []
let file_list_div
let selected_file_index = 0
onMount(() => {
// Skip to the file defined in the link hash
let matches = location.hash.match(new RegExp('item=([^&]*)'))
let hashID = matches ? matches[1] : null
let idx = 0
if (Number.isInteger(parseInt(hashID))) {
idx = parseInt(hashID)
}
set_item(idx)
})
export const next = () => {
if (shuffle) {
rand_item()
return
}
set_item(selected_file_index+1)
select_item_event(selected_file_index+1)
}
export const prev = () => {
select_item_event(selected_file_index-1)
}
export const prev = () => { set_item(selected_file_index-1) }
let history = []
export const rand_item = () => {
@@ -41,23 +31,15 @@ export const rand_item = () => {
set_item(rand)
}
let shuffle = false
export const set_shuffle = s => { shuffle = s }
export let shuffle = false
export const set_item = idx => {
if (idx >= files.length) {
idx = 0
} else if (idx < 0) {
idx = files.length - 1
}
// Remove the class from the previous selected file
files[selected_file_index].selected = false
selected_file_index = idx
files[idx].selected = true
// Update the URL
location.hash = "item=" + idx
files.forEach((f, i) => {
f.selected = selected_file_index === i
})
files = files
// Add item to history
if(history.length >= (files.length - 6)){
@@ -65,8 +47,6 @@ export const set_item = idx => {
}
history.push(idx)
dispatch("set_file", files[idx])
// Smoothly scroll the navigator to the correct element
let selected_file = file_list_div.children[idx]
let cst = window.getComputedStyle(selected_file)
@@ -88,11 +68,20 @@ export const set_item = idx => {
}
animateScroll(start, 0)
}
// select_item signals to the FileViewer that the file needs to be changed. The
// FileViewer then calls set_item if the change has been approved. ListNavigator
// cannot call set_item itself because it will cause a loop.
const select_item_event = idx => {
dispatch("set_file", idx)
}
</script>
<div bind:this={file_list_div} class="list_navigator">
{#each files as file, index}
<div class="list_item file_button" class:file_button_selected={file.selected} on:click={() => { set_item(index) }}>
<div class="list_item file_button"
class:file_button_selected={file.selected}
on:click={() => { select_item_event(index) }}>
<img src={file.icon_href+"?width=48&height=48"} alt={file.name} class="list_item_thumbnail" />
{file.name}
</div>

View File

@@ -23,16 +23,22 @@ export let file = {
<button class="button_highlight" on:click={() => {dispatch("download")}}>
<i class="icon">save</i> Download
</button>
{#if file.size > 1e9}
<hr/>
Your download speed is currently limited to 4 MiB/s. Downloading this
file for free will take {formatDuration((file.size/4194304)*1000)}.
<a href="https://www.patreon.com/join/pixeldrain/checkout?rid=5291427&cadence=12" class="button">
Upgrade to Pro
</a>
to download at the fastest speed available.
{/if}
</div>
{#if file.size > 5e8}
<br/>
<div class="description" style="max-width: 700px; text-align: center;">
<!-- If the file is larger than 500 MB-->
<hr/>
Your download speed is currently limited to 4 MiB/s. Downloading this
file for free will take at least
{formatDuration((file.size/4194304)*1000)}.
You can
<a href="https://www.patreon.com/join/pixeldrain/checkout?rid=5291427&cadence=12">
upgrade to Pro
</a>
to download at the fastest speed available.
</div>
{/if}
</div>
<style>

View File

@@ -72,7 +72,7 @@ let download = () => { dispatch("download", {}) }
{:else}
<h1>This is a video file on pixeldrain</h1>
<img src={file.icon_href} alt="Video icon" style="display: inline-block; vertical-align: top;">
<div style="display: inline-block; text-align: left; padding-left: 8px; vertical-align: middle; max-width: 600px;">
<div class="description">
The online video player on pixeldrain has been disabled due to
repeated abuse. You can still watch videos online by upgrading to
Pro. Or download the video and watch it locally on your computer.
@@ -83,16 +83,22 @@ let download = () => { dispatch("download", {}) }
<button on:click={download}>
<i class="icon">save</i> Download
</button>
{#if file.size > 1e9}
</div>
{#if file.size > 5e8}
<br/>
<div class="description" style="max-width: 700px; text-align: center;">
<!-- If the file is larger than 500 MB-->
<hr/>
Your download speed is currently limited to 4 MiB/s. Downloading this
file for free will take {formatDuration((file.size/4194304)*1000)}.
<a href="https://www.patreon.com/join/pixeldrain/checkout?rid=5291427&cadence=12" class="button">
Upgrade to Pro
file for free will take at least
{formatDuration((file.size/4194304)*1000)}.
You can
<a href="https://www.patreon.com/join/pixeldrain/checkout?rid=5291427&cadence=12">
upgrade to Pro
</a>
to download at the fastest speed available.
{/if}
</div>
</div>
{/if}
{/if}
</div>
@@ -114,4 +120,11 @@ let download = () => { dispatch("download", {}) }
top: 50%;
transform: translateY(-50%);
}
.description {
display: inline-block;
text-align: left;
padding-left: 8px;
vertical-align: middle;
max-width: 600px;
}
</style>

View File

@@ -34,19 +34,3 @@ $: frac = used / total
</div>
{/if}
</div>
<style>
.progress_bar_outer {
display: block;
background-color: var(--layer_1_color);
width: 100%;
height: 3px;
margin: 6px 0 12px 0;
}
.progress_bar_inner {
background-color: var(--highlight_color);
height: 100%;
width: 0;
transition: width 1s;
}
</style>