Add file picker for adding files to albums
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<hr />
|
||||
{{if .Authenticated}}<a href="/user">{{.User.Username}}</a>
|
||||
<a href="/user/filemanager#files">My Files</a>
|
||||
<a href="/user/filemanager#lists">My Lists</a>
|
||||
<a href="/user/filemanager#lists">My Albums</a>
|
||||
{{if .User.IsAdmin}}
|
||||
<a href="/user/buckets">Buckets</a>
|
||||
<a href="/admin">Admin Panel</a>
|
||||
@@ -28,7 +28,7 @@
|
||||
{{end}}
|
||||
</div>
|
||||
<script>
|
||||
function toggleMenu() {
|
||||
function toggleMenu() {
|
||||
var nav = document.getElementById("page_navigation");
|
||||
var body = document.getElementById("page_body");
|
||||
if (nav.offsetLeft === 0) {
|
||||
@@ -40,7 +40,11 @@
|
||||
nav.style.left = "0";
|
||||
body.style.left = nav.offsetWidth + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
function resetMenu() {
|
||||
document.getElementById("page_navigation").style.left = "";
|
||||
document.getElementById("page_body").style.left = "";
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
|
||||
|
@@ -136,8 +136,10 @@ let update_charts = () => {
|
||||
</p>
|
||||
|
||||
<h3>About</h3>
|
||||
<p>
|
||||
Pixeldrain is a file sharing platform.
|
||||
<a href="/" target="_blank">Visit the home page for more information.</a>
|
||||
</p>
|
||||
|
||||
<h3>Keyboard Controls</h3>
|
||||
<table style="max-width: 100%;">
|
||||
|
@@ -55,9 +55,9 @@ const example = () => {
|
||||
file will also show advertisements.
|
||||
</p>
|
||||
<h3>Code</h3>
|
||||
<textarea bind:value={embed_html} style="width: 100%; height: 4em; margin: 0;"></textarea>
|
||||
<textarea bind:value={embed_html} style="width: 100%; height: 4em;" class="indent"></textarea>
|
||||
<br/>
|
||||
<button on:click={copy} class:button_highlight={copy_status === "success"} class:button_red={copy_status === "error"}>
|
||||
<button on:click={copy} class="indent" class:button_highlight={copy_status === "success"} class:button_red={copy_status === "error"}>
|
||||
<i class="icon">content_copy</i>
|
||||
{#if copy_status === "success"}
|
||||
Copied!
|
||||
|
137
svelte/src/file_viewer/FilePicker.svelte
Normal file
137
svelte/src/file_viewer/FilePicker.svelte
Normal file
@@ -0,0 +1,137 @@
|
||||
<script>
|
||||
import { createEventDispatcher, tick } from "svelte";
|
||||
import { formatDataVolume } from "../util/Formatting.svelte";
|
||||
import DirectoryElement from "../user_file_manager/DirectoryElement.svelte";
|
||||
import Modal from "../util/Modal.svelte";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
let modal;
|
||||
let directory_element;
|
||||
let input_search;
|
||||
|
||||
export const open = async () => {
|
||||
modal.show()
|
||||
await tick()
|
||||
directory_element.setSelectionMode(true)
|
||||
get_files()
|
||||
}
|
||||
|
||||
let get_files = () => {
|
||||
fetch(window.api_endpoint + "/user/files").then(resp => {
|
||||
if (!resp.ok) { Promise.reject("yo") }
|
||||
return resp.json()
|
||||
}).then(resp => {
|
||||
directory_element.reset()
|
||||
|
||||
for (let i in resp.files) {
|
||||
directory_element.addFile(
|
||||
resp.files[i].id,
|
||||
window.api_endpoint + "/file/" + resp.files[i].id + "/thumbnail?width=32&height=32",
|
||||
resp.files[i].name,
|
||||
"/u/" + resp.files[i].id,
|
||||
resp.files[i].mime_type,
|
||||
resp.files[i].size,
|
||||
formatDataVolume(resp.files[i].size, 4),
|
||||
resp.files[i].date_upload,
|
||||
)
|
||||
}
|
||||
|
||||
directory_element.renderFiles()
|
||||
}).catch((err) => {
|
||||
throw (err)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const search = (e) => {
|
||||
if (e.keyCode === 27) { // Escape
|
||||
e.preventDefault()
|
||||
input_search.value = ""
|
||||
input_search.blur()
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
directory_element.search(input_search.value)
|
||||
})
|
||||
}
|
||||
|
||||
let done = () => {
|
||||
dispatch("files", directory_element.getSelectedFiles())
|
||||
modal.hide()
|
||||
}
|
||||
|
||||
|
||||
const keydown = (e) => {
|
||||
if (e.ctrlKey || e.altKey || e.metaKey) {
|
||||
return // prevent custom shortcuts from interfering with system shortcuts
|
||||
}
|
||||
if (document.activeElement.type && document.activeElement.type === "text") {
|
||||
return // Prevent shortcuts from interfering with input fields
|
||||
}
|
||||
if (e.key === "/") {
|
||||
e.preventDefault()
|
||||
input_search.focus()
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={keydown} />
|
||||
|
||||
<Modal bind:this={modal} width="1400px" height="1200px">
|
||||
<div class="header" slot="title">
|
||||
<button class="button round" on:click={modal.hide}>
|
||||
<i class="icon">close</i> Cancel
|
||||
</button>
|
||||
<div class="title">Select files to add to album</div>
|
||||
<input bind:this={input_search} on:keyup={search} class="search" type="text" placeholder="press / to search"/>
|
||||
<button class="button button_highlight round" on:click={done}>
|
||||
<i class="icon">done</i> Add
|
||||
</button>
|
||||
</div>
|
||||
<div class="dir_container">
|
||||
<DirectoryElement bind:this={directory_element}></DirectoryElement>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.dir_container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
@media(max-width: 800px) {
|
||||
.title {
|
||||
/* display: none; */
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
.search {
|
||||
min-width: 100px;
|
||||
max-width: 300px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.button {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
@@ -1,3 +1,39 @@
|
||||
<script context="module">
|
||||
export const file_struct = {
|
||||
id: "",
|
||||
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: "",
|
||||
}
|
||||
export const list_struct = {
|
||||
id: "",
|
||||
title: "",
|
||||
files: [],
|
||||
download_href: "",
|
||||
info_href: "",
|
||||
can_edit: false,
|
||||
}
|
||||
export 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"
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount, tick } from "svelte";
|
||||
import { copy_text } from "../util/Util.svelte";
|
||||
@@ -19,33 +55,6 @@ import GalleryView from "./GalleryView.svelte";
|
||||
import Spinner from "../util/Spinner.svelte";
|
||||
import Downloader from "./Downloader.svelte";
|
||||
|
||||
const file_struct = {
|
||||
id: "",
|
||||
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: "",
|
||||
}
|
||||
const list_struct = {
|
||||
id: "",
|
||||
title: "",
|
||||
files: [],
|
||||
download_href: "",
|
||||
info_href: "",
|
||||
can_edit: false,
|
||||
}
|
||||
|
||||
let loading = true
|
||||
let embedded = false
|
||||
let view_token = ""
|
||||
@@ -209,13 +218,6 @@ const open_file_index = async index => {
|
||||
body: "token=" + view_token
|
||||
})
|
||||
}
|
||||
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)
|
||||
@@ -479,8 +481,6 @@ const keyboard_event = evt => {
|
||||
<br/>
|
||||
</div></div></div>
|
||||
|
||||
<Sharebar bind:this={sharebar}></Sharebar>
|
||||
|
||||
<div id="file_preview" class="file_preview checkers" class:toolbar_visible class:skyscraper_visible>
|
||||
{#if view === "file"}
|
||||
<FilePreview
|
||||
@@ -499,6 +499,8 @@ const keyboard_event = evt => {
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<Sharebar bind:this={sharebar}></Sharebar>
|
||||
|
||||
{#if ads_enabled}
|
||||
<AdSkyscraper on:visibility={e => {skyscraper_visible = e.detail}}></AdSkyscraper>
|
||||
{/if}
|
||||
@@ -568,7 +570,6 @@ const keyboard_event = evt => {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
text-align: left;
|
||||
z-index: 10;
|
||||
box-shadow: none;
|
||||
padding: 4px;
|
||||
}
|
||||
@@ -616,7 +617,6 @@ const keyboard_event = evt => {
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
z-index: 9;
|
||||
}
|
||||
.file_preview {
|
||||
position: absolute;
|
||||
@@ -639,7 +639,6 @@ const keyboard_event = evt => {
|
||||
.toolbar {
|
||||
position: absolute;
|
||||
width: 8em;
|
||||
z-index: 49;
|
||||
overflow: hidden;
|
||||
left: -8em;
|
||||
bottom: 0;
|
||||
@@ -648,6 +647,7 @@ const keyboard_event = evt => {
|
||||
text-align: left;
|
||||
transition: left 0.5s, right 0.5s;
|
||||
background-color: var(--layer_2_color);
|
||||
z-index: 1;
|
||||
}
|
||||
.toolbar.toolbar_visible { left: 0; }
|
||||
.file_preview.toolbar_visible { left: 8em; }
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { flip } from "svelte/animate"
|
||||
import FilePicker from "./FilePicker.svelte"
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let list = {
|
||||
@@ -12,6 +13,8 @@ export let list = {
|
||||
can_edit: false,
|
||||
}
|
||||
|
||||
let file_picker;
|
||||
|
||||
const click_file = index => {
|
||||
dispatch("set_file", index)
|
||||
}
|
||||
@@ -19,8 +22,6 @@ const click_file = index => {
|
||||
const update_list = async new_files => {
|
||||
dispatch("loading", true)
|
||||
|
||||
list.files = new_files
|
||||
|
||||
// If the list is empty we simply delete it
|
||||
if (list.files.length === 0) {
|
||||
try {
|
||||
@@ -62,27 +63,39 @@ const update_list = async new_files => {
|
||||
}
|
||||
}
|
||||
|
||||
const delete_file = async index => {
|
||||
let list_files = list.files
|
||||
list_files.splice(index, 1)
|
||||
update_list(list_files)
|
||||
const add_files = async files => {
|
||||
let list_files = list.files;
|
||||
files.forEach(f => {
|
||||
list_files.push(f)
|
||||
})
|
||||
await update_list(list_files)
|
||||
dispatch("reload")
|
||||
}
|
||||
|
||||
const move_left = index => {
|
||||
const delete_file = async index => {
|
||||
const list_files = list.files
|
||||
list_files.splice(index, 1)
|
||||
await update_list(list_files)
|
||||
list.files = list_files
|
||||
}
|
||||
|
||||
const move_left = async index => {
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
let f = list.files;
|
||||
const f = list.files;
|
||||
[f[index], f[index-1]] = [f[index-1], f[index]];
|
||||
update_list(f);
|
||||
await update_list(f)
|
||||
list.files = f
|
||||
}
|
||||
const move_right = index => {
|
||||
const move_right = async index => {
|
||||
if (index >= list.files.length-1) {
|
||||
return;
|
||||
}
|
||||
let f = list.files;
|
||||
const f = list.files;
|
||||
[f[index], f[index+1]] = [f[index+1], f[index]];
|
||||
update_list(f);
|
||||
await update_list(f)
|
||||
list.files = f
|
||||
}
|
||||
|
||||
let hovering = -1
|
||||
@@ -99,18 +112,19 @@ const drop = (e, index) => {
|
||||
if (start < index) {
|
||||
list_files.splice(index + 1, 0, list_files[start]);
|
||||
list_files.splice(start, 1);
|
||||
} else {
|
||||
} else if (start > index) {
|
||||
list_files.splice(index, 0, list_files[start]);
|
||||
list_files.splice(start + 1, 1);
|
||||
} else {
|
||||
return; // Nothing changed
|
||||
}
|
||||
hovering = -1
|
||||
|
||||
update_list(list_files)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="gallery">
|
||||
{#each list.files as file, index (file.id)}
|
||||
{#each list.files as file, index (file)}
|
||||
<div
|
||||
class="file"
|
||||
on:click={() => {click_file(index)}}
|
||||
@@ -119,6 +133,7 @@ const drop = (e, index) => {
|
||||
on:drop|preventDefault={e => drop(e, index)}
|
||||
on:dragover|preventDefault|stopPropagation
|
||||
on:dragenter={() => {hovering = index}}
|
||||
on:dragend={() => {hovering = -1}}
|
||||
class:highlight={hovering === index}
|
||||
animate:flip={{duration: 500}}>
|
||||
<div
|
||||
@@ -136,13 +151,15 @@ const drop = (e, index) => {
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<!-- {#if list.can_edit}
|
||||
<div class="file" style="font-size: 1.5em; padding-top: 2.5em; cursor: pointer;">
|
||||
{#if list.can_edit}
|
||||
<div class="file" on:click={file_picker.open} style="font-size: 1.5em; padding-top: 2.5em; cursor: pointer;">
|
||||
<i class="icon">add</i>
|
||||
<br/>
|
||||
Add files
|
||||
</div>
|
||||
{/if} -->
|
||||
{/if}
|
||||
|
||||
<FilePicker bind:this={file_picker} on:files={e => {add_files(e.detail)}}></FilePicker>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
@@ -74,7 +74,6 @@ const share_tumblr = () => {
|
||||
background-color: var(--layer_1_color);
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
z-index: 48;
|
||||
overflow: hidden;
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
@@ -82,7 +82,6 @@ export const search = (term) => {
|
||||
allFiles[i].filtered = false
|
||||
} else {
|
||||
allFiles[i].filtered = true
|
||||
allFiles[i].selected = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -97,10 +97,12 @@ let hashChange = () => {
|
||||
contentType = "lists"
|
||||
document.title = "My Lists"
|
||||
getUserLists()
|
||||
resetMenu()
|
||||
} else {
|
||||
contentType = "files"
|
||||
document.title = "My Files"
|
||||
getUserFiles()
|
||||
resetMenu()
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -32,8 +32,12 @@ export const set_visible = vis => {
|
||||
}
|
||||
|
||||
const keydown = e => {
|
||||
if (document.activeElement.type && document.activeElement.type === "text") {
|
||||
return // Prevent shortcuts from interfering with input fields
|
||||
}
|
||||
if (e.key === 'Escape') {
|
||||
set_visible(false);
|
||||
e.preventDefault()
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -114,6 +118,5 @@ const keydown = e => {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user