Allow drag-and-drop uploading in album viewer
This commit is contained in:
@@ -21,6 +21,7 @@ import CustomBanner from "./CustomBanner.svelte";
|
|||||||
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
import LoadingIndicator from "../util/LoadingIndicator.svelte";
|
||||||
import TransferLimit from "./TransferLimit.svelte";
|
import TransferLimit from "./TransferLimit.svelte";
|
||||||
import ListStats from "./ListStats.svelte";
|
import ListStats from "./ListStats.svelte";
|
||||||
|
import ListUpdater from "./ListUpdater.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let embedded = false
|
let embedded = false
|
||||||
@@ -73,6 +74,7 @@ let toolbar_toggle = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let downloader
|
let downloader
|
||||||
|
let list_updater
|
||||||
let details_window
|
let details_window
|
||||||
let details_visible = false
|
let details_visible = false
|
||||||
let qr_window
|
let qr_window
|
||||||
@@ -354,6 +356,10 @@ const keyboard_event = evt => {
|
|||||||
case "q": // Q to close the window
|
case "q": // Q to close the window
|
||||||
window.close()
|
window.close()
|
||||||
break
|
break
|
||||||
|
case "u": // U to upload new files
|
||||||
|
if (list_updater) {
|
||||||
|
list_updater.pick_files()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,22 +567,20 @@ const keyboard_event = evt => {
|
|||||||
on:prev={() => { if (list_navigator) { list_navigator.prev() }}}
|
on:prev={() => { if (list_navigator) { list_navigator.prev() }}}
|
||||||
on:next={() => { if (list_navigator) { list_navigator.next() }}}
|
on:next={() => { if (list_navigator) { list_navigator.next() }}}
|
||||||
on:loading={e => {loading = e.detail}}
|
on:loading={e => {loading = e.detail}}
|
||||||
on:reload={reload}>
|
on:reload={reload}
|
||||||
</FilePreview>
|
/>
|
||||||
{:else if view === "gallery"}
|
{:else if view === "gallery"}
|
||||||
<GalleryView
|
<GalleryView
|
||||||
list={list}
|
list={list}
|
||||||
on:reload={reload}
|
on:reload={reload}
|
||||||
on:loading={e => {loading = e.detail}}>
|
on:update_list={e => list_updater.update(e.detail)}
|
||||||
</GalleryView>
|
on:pick_files={() => list_updater.pick_files()}
|
||||||
|
on:upload_files={e => list_updater.upload_files(e.detail)}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Sharebar bind:this={sharebar}></Sharebar>
|
<Sharebar bind:this={sharebar}></Sharebar>
|
||||||
|
|
||||||
<!-- {#if ads_enabled}
|
|
||||||
<AdSkyscraper on:visibility={e => {skyscraper_visible = e.detail}}></AdSkyscraper>
|
|
||||||
{/if} -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if ads_enabled}
|
{#if ads_enabled}
|
||||||
@@ -611,6 +615,15 @@ const keyboard_event = evt => {
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Downloader bind:this={downloader} file={file} list={list}></Downloader>
|
<Downloader bind:this={downloader} file={file} list={list}></Downloader>
|
||||||
|
|
||||||
|
{#if is_list && list.can_edit}
|
||||||
|
<ListUpdater
|
||||||
|
bind:this={list_updater}
|
||||||
|
list={list}
|
||||||
|
on:reload={reload}
|
||||||
|
on:loading={e => {loading = e.detail}}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@@ -6,74 +6,28 @@ import { file_type } from "./FileUtilities.svelte";
|
|||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let list = {
|
export let list = {
|
||||||
id: "",
|
|
||||||
title: "",
|
|
||||||
files: [],
|
files: [],
|
||||||
download_href: "",
|
|
||||||
info_href: "",
|
|
||||||
can_edit: false,
|
can_edit: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_picker;
|
let file_picker;
|
||||||
|
|
||||||
const update_list = async new_files => {
|
|
||||||
dispatch("loading", true)
|
|
||||||
|
|
||||||
// If the list is empty we simply delete it
|
|
||||||
if (list.files.length === 0) {
|
|
||||||
try {
|
|
||||||
let resp = await fetch(list.info_href, {method: "DELETE"})
|
|
||||||
if (resp.status >= 400) {
|
|
||||||
throw (await resp.json()).message
|
|
||||||
}
|
|
||||||
window.close()
|
|
||||||
} catch (err) {
|
|
||||||
alert("Failed to delete album: "+err)
|
|
||||||
} finally {
|
|
||||||
dispatch("loading", false)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let listjson = {
|
|
||||||
title: list.title,
|
|
||||||
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
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
alert("Failed to update album: "+err)
|
|
||||||
} finally {
|
|
||||||
dispatch("loading", false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const add_files = async files => {
|
const add_files = async files => {
|
||||||
let list_files = list.files;
|
let list_files = list.files;
|
||||||
files.forEach(f => {
|
files.forEach(f => {
|
||||||
list_files.push(f)
|
list_files.push(f)
|
||||||
})
|
})
|
||||||
await update_list(list_files)
|
|
||||||
dispatch("reload")
|
list.files = list_files // Update the view (and play animation)
|
||||||
|
dispatch("update_list", list_files)
|
||||||
}
|
}
|
||||||
|
|
||||||
const delete_file = async index => {
|
const delete_file = async index => {
|
||||||
let list_files = list.files
|
let list_files = list.files
|
||||||
list_files.splice(index, 1)
|
list_files.splice(index, 1)
|
||||||
await update_list(list_files)
|
|
||||||
list.files = list_files
|
list.files = list_files // Update the view (and play animation)
|
||||||
|
dispatch("update_list", list_files)
|
||||||
}
|
}
|
||||||
|
|
||||||
const move_left = async index => {
|
const move_left = async index => {
|
||||||
@@ -82,8 +36,9 @@ const move_left = async index => {
|
|||||||
}
|
}
|
||||||
let f = list.files;
|
let f = list.files;
|
||||||
[f[index], f[index-1]] = [f[index-1], f[index]];
|
[f[index], f[index-1]] = [f[index-1], f[index]];
|
||||||
await update_list(f)
|
|
||||||
list.files = f
|
list.files = f // Update the view (and play animation)
|
||||||
|
dispatch("update_list", f)
|
||||||
}
|
}
|
||||||
const move_right = async index => {
|
const move_right = async index => {
|
||||||
if (index >= list.files.length-1) {
|
if (index >= list.files.length-1) {
|
||||||
@@ -91,17 +46,33 @@ const move_right = async index => {
|
|||||||
}
|
}
|
||||||
let f = list.files;
|
let f = list.files;
|
||||||
[f[index], f[index+1]] = [f[index+1], f[index]];
|
[f[index], f[index+1]] = [f[index+1], f[index]];
|
||||||
await update_list(f)
|
|
||||||
list.files = f
|
list.files = f // Update the view (and play animation)
|
||||||
|
dispatch("update_list", f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Index of the file which is being hovered over. -1 is nothing and -2 is the
|
||||||
|
// Add files button
|
||||||
let hovering = -1
|
let hovering = -1
|
||||||
|
let dragging = false
|
||||||
const drag = (e, index) => {
|
const drag = (e, index) => {
|
||||||
|
dragging = true
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
e.dataTransfer.dropEffect = 'move';
|
e.dataTransfer.dropEffect = 'move';
|
||||||
e.dataTransfer.setData('text/plain', index);
|
e.dataTransfer.setData('text/plain', index);
|
||||||
}
|
}
|
||||||
const drop = (e, index) => {
|
const drop = (e, index) => {
|
||||||
|
hovering = -1
|
||||||
|
dragging = false
|
||||||
|
|
||||||
|
if (e.dataTransfer.files.length !== 0) {
|
||||||
|
// This is not a rearrangement, this is a file upload
|
||||||
|
dispatch("upload_files", e.dataTransfer.files)
|
||||||
|
return
|
||||||
|
} else if (index === -2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
e.dataTransfer.dropEffect = 'move';
|
e.dataTransfer.dropEffect = 'move';
|
||||||
let start = parseInt(e.dataTransfer.getData("text/plain"));
|
let start = parseInt(e.dataTransfer.getData("text/plain"));
|
||||||
let list_files = list.files
|
let list_files = list.files
|
||||||
@@ -116,11 +87,32 @@ const drop = (e, index) => {
|
|||||||
return; // Nothing changed
|
return; // Nothing changed
|
||||||
}
|
}
|
||||||
|
|
||||||
update_list(list_files)
|
dispatch("update_list", list_files)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="gallery">
|
<div class="gallery">
|
||||||
|
{#if list.can_edit}
|
||||||
|
<div class="add_button"
|
||||||
|
on:drop|preventDefault={e => drop(e, -2)}
|
||||||
|
on:dragover|preventDefault|stopPropagation
|
||||||
|
on:dragenter={() => hovering = -2}
|
||||||
|
on:dragend={() => {hovering = -1}}
|
||||||
|
class:highlight={!dragging && hovering === -2}
|
||||||
|
>
|
||||||
|
<button on:click={e => dispatch("pick_files")} style="font-size: 1.5em; cursor: pointer;">
|
||||||
|
<i class="icon">cloud_upload</i>
|
||||||
|
<br/>
|
||||||
|
Upload files
|
||||||
|
</button>
|
||||||
|
<button on:click={file_picker.open} style="font-size: 1.5em; cursor: pointer;">
|
||||||
|
<i class="icon">add</i>
|
||||||
|
<br/>
|
||||||
|
Add files
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#each list.files as file, index (file)}
|
{#each list.files as file, index (file)}
|
||||||
<a
|
<a
|
||||||
href="#item={index}"
|
href="#item={index}"
|
||||||
@@ -129,10 +121,10 @@ const drop = (e, index) => {
|
|||||||
on:dragstart={e => drag(e, index)}
|
on:dragstart={e => drag(e, index)}
|
||||||
on:drop|preventDefault={e => drop(e, index)}
|
on:drop|preventDefault={e => drop(e, index)}
|
||||||
on:dragover|preventDefault|stopPropagation
|
on:dragover|preventDefault|stopPropagation
|
||||||
on:dragenter={() => {hovering = index}}
|
on:dragenter={() => hovering = index}
|
||||||
on:dragend={() => {hovering = -1}}
|
on:dragend={() => {hovering = -1; dragging = false}}
|
||||||
class:highlight={hovering === index}
|
class:highlight={dragging && hovering === index}
|
||||||
animate:flip={{duration: 500}}>
|
animate:flip={{duration: 400}}>
|
||||||
<div
|
<div
|
||||||
class="icon_container"
|
class="icon_container"
|
||||||
class:editing={list.can_edit}
|
class:editing={list.can_edit}
|
||||||
@@ -159,14 +151,6 @@ const drop = (e, index) => {
|
|||||||
{file.name}
|
{file.name}
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if list.can_edit}
|
|
||||||
<button class="file" on:click={file_picker.open} style="font-size: 1.5em; cursor: pointer;">
|
|
||||||
<i class="icon">add</i>
|
|
||||||
<br/>
|
|
||||||
Add files
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FilePicker
|
<FilePicker
|
||||||
@@ -242,4 +226,23 @@ const drop = (e, index) => {
|
|||||||
.button_row>.separator {
|
.button_row>.separator {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
.add_button{
|
||||||
|
width: 200px;
|
||||||
|
max-width: 42%;
|
||||||
|
height: 200px;
|
||||||
|
margin: 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--body_color);
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.2em;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
color: var(--body_text_color);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.add_button > * {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
82
svelte/src/file_viewer/ListUpdater.svelte
Normal file
82
svelte/src/file_viewer/ListUpdater.svelte
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
import UploadWidget from "../util/upload_widget/UploadWidget.svelte";
|
||||||
|
|
||||||
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
export let list = {
|
||||||
|
title: "",
|
||||||
|
files: [],
|
||||||
|
info_href: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const update = async new_files => {
|
||||||
|
dispatch("loading", true)
|
||||||
|
|
||||||
|
// If the list is empty we simply delete it
|
||||||
|
if (list.files.length === 0) {
|
||||||
|
try {
|
||||||
|
let resp = await fetch(list.info_href, {method: "DELETE"})
|
||||||
|
if (resp.status >= 400) {
|
||||||
|
throw (await resp.json()).message
|
||||||
|
}
|
||||||
|
window.close()
|
||||||
|
} catch (err) {
|
||||||
|
alert("Failed to delete album: "+err)
|
||||||
|
} finally {
|
||||||
|
dispatch("loading", false)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let listjson = {
|
||||||
|
title: list.title,
|
||||||
|
files: [],
|
||||||
|
}
|
||||||
|
new_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
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert("Failed to update album: "+err)
|
||||||
|
} finally {
|
||||||
|
dispatch("loading", false)
|
||||||
|
dispatch("reload")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let upload_widget
|
||||||
|
export const pick_files = () => upload_widget.pick_files()
|
||||||
|
export const upload_files = files => upload_widget.upload_files(files)
|
||||||
|
|
||||||
|
const uploads_finished = async (file_ids) => {
|
||||||
|
let list_files = list.files;
|
||||||
|
file_ids.forEach(id => {
|
||||||
|
list_files.push({id: id})
|
||||||
|
})
|
||||||
|
|
||||||
|
await update(list_files)
|
||||||
|
}
|
||||||
|
|
||||||
|
const paste = (e) => {
|
||||||
|
if (e.clipboardData.files.length !== 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
upload_widget.upload_files(e.clipboardData.files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:paste={paste}/>
|
||||||
|
|
||||||
|
<UploadWidget bind:this={upload_widget} on:uploads_finished={e => uploads_finished(e.detail)}/>
|
@@ -257,8 +257,6 @@ onMount(() => {
|
|||||||
|
|
||||||
<svelte:window on:keydown={keydown} on:hashchange={hashChange} />
|
<svelte:window on:keydown={keydown} on:hashchange={hashChange} />
|
||||||
|
|
||||||
<UploadWidget bind:this={upload_widget} drop_upload on:uploads_finished={hashChange}/>
|
|
||||||
|
|
||||||
<div id="file_manager" class="file_manager">
|
<div id="file_manager" class="file_manager">
|
||||||
<div id="nav_bar" class="nav_bar">
|
<div id="nav_bar" class="nav_bar">
|
||||||
<button id="btn_menu" onclick="toggleMenu()"><i class="icon">menu</i></button>
|
<button id="btn_menu" onclick="toggleMenu()"><i class="icon">menu</i></button>
|
||||||
@@ -340,6 +338,8 @@ onMount(() => {
|
|||||||
<iframe bind:this={downloadFrame} title="File download frame" style="display: none; width: 1px; height: 1px;"></iframe>
|
<iframe bind:this={downloadFrame} title="File download frame" style="display: none; width: 1px; height: 1px;"></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<UploadWidget bind:this={upload_widget} drop_upload on:uploads_finished={hashChange}/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:global(#page_body) {
|
:global(#page_body) {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
@@ -14,10 +14,10 @@ const drop = (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const paste = (e) => {
|
const paste = (e) => {
|
||||||
if (e.clipboardData.files[0]) {
|
if (e.clipboardData.files.length !== 0) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
dispatch("upload", e.dataTransfer.files)
|
dispatch("upload", e.clipboardData.files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -39,8 +39,6 @@ const paste = (e) => {
|
|||||||
<style>
|
<style>
|
||||||
.drag_target {
|
.drag_target {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
height: auto;
|
|
||||||
margin: auto;
|
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
|
import { fade } from "svelte/transition";
|
||||||
import ProgressBar from "../ProgressBar.svelte";
|
import ProgressBar from "../ProgressBar.svelte";
|
||||||
import { upload_file } from "./UploadFunc";
|
import { upload_file } from "./UploadFunc";
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ export const start = () => {
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="upload_progress" class:error={job.status === "error"}>
|
<div class="upload_progress" transition:fade={{duration: 200}} class:error={job.status === "error"}>
|
||||||
{job.name}<br/>
|
{job.name}<br/>
|
||||||
{#if error_code !== ""}
|
{#if error_code !== ""}
|
||||||
{error_message}<br/>
|
{error_message}<br/>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher, tick } from "svelte";
|
import { createEventDispatcher, tick } from "svelte";
|
||||||
|
import { fade } from "svelte/transition";
|
||||||
import DropUpload from "./DropUpload.svelte";
|
import DropUpload from "./DropUpload.svelte";
|
||||||
import UploadProgress from "./UploadProgress.svelte";
|
import UploadProgress from "./UploadProgress.svelte";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
@@ -103,12 +104,8 @@ const finish_upload = (e) => {
|
|||||||
class="upload_input" type="file" name="file" multiple="multiple"
|
class="upload_input" type="file" name="file" multiple="multiple"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if drop_upload}
|
|
||||||
<DropUpload on:upload={e => upload_files(e.detail)}/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if visible}
|
{#if visible}
|
||||||
<div class="upload_widget">
|
<div class="upload_widget" transition:fade={{duration: 200}}>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{#if state === "idle"}
|
{#if state === "idle"}
|
||||||
Waiting for files
|
Waiting for files
|
||||||
@@ -128,10 +125,14 @@ const finish_upload = (e) => {
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if drop_upload}
|
||||||
|
<DropUpload on:upload={e => upload_files(e.detail)}/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.upload_input {
|
.upload_input {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
position: static;
|
position: fixed;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
@@ -139,16 +140,15 @@ const finish_upload = (e) => {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 400px;
|
width: 500px;
|
||||||
max-width: 90%;
|
max-width: 80%;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: 500px;
|
max-height: 50%;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
border-radius: 20px 20px 8px 8px;
|
border-radius: 20px 20px 8px 8px;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
overflow-y: auto;
|
box-shadow: 1px 1px 8px var(--shadow_color);
|
||||||
box-shadow: 1px 1px 10px -2px var(--shadow_color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
@@ -166,5 +166,7 @@ const finish_upload = (e) => {
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
background: var(--body_color);
|
background: var(--body_color);
|
||||||
color: var(--body_text_color);
|
color: var(--body_text_color);
|
||||||
|
overflow-y: auto;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Reference in New Issue
Block a user