feat: polish UI
Signed-off-by: Sphericalkat <me@kat.bio>
This commit is contained in:
parent
0e4eeb5f19
commit
767b0417c8
@ -20,6 +20,7 @@
|
|||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-svelte": "^2.36.0",
|
"eslint-plugin-svelte": "^2.36.0",
|
||||||
|
"filesize": "^10.1.2",
|
||||||
"globals": "^15.0.0",
|
"globals": "^15.0.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"prettier": "^3.1.1",
|
"prettier": "^3.1.1",
|
||||||
|
@ -36,6 +36,9 @@ importers:
|
|||||||
eslint-plugin-svelte:
|
eslint-plugin-svelte:
|
||||||
specifier: ^2.36.0
|
specifier: ^2.36.0
|
||||||
version: 2.39.4(eslint@9.5.0)(svelte@4.2.18)
|
version: 2.39.4(eslint@9.5.0)(svelte@4.2.18)
|
||||||
|
filesize:
|
||||||
|
specifier: ^10.1.2
|
||||||
|
version: 10.1.2
|
||||||
globals:
|
globals:
|
||||||
specifier: ^15.0.0
|
specifier: ^15.0.0
|
||||||
version: 15.5.0
|
version: 15.5.0
|
||||||
@ -770,6 +773,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||||
engines: {node: '>=16.0.0'}
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
||||||
|
filesize@10.1.2:
|
||||||
|
resolution: {integrity: sha512-Dx770ai81ohflojxhU+oG+Z2QGvKdYxgEr9OSA8UVrqhwNHjfH9A8f5NKfg83fEH8ZFA5N5llJo5T3PIoZ4CRA==}
|
||||||
|
engines: {node: '>= 10.4.0'}
|
||||||
|
|
||||||
fill-range@7.1.1:
|
fill-range@7.1.1:
|
||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -2182,6 +2189,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flat-cache: 4.0.1
|
flat-cache: 4.0.1
|
||||||
|
|
||||||
|
filesize@10.1.2: {}
|
||||||
|
|
||||||
fill-range@7.1.1:
|
fill-range@7.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
45
src/app.d.ts
vendored
45
src/app.d.ts
vendored
@ -1,13 +1,44 @@
|
|||||||
// See https://kit.svelte.dev/docs/types#app
|
// See https://kit.svelte.dev/docs/types#app
|
||||||
// for information about these interfaces
|
// for information about these interfaces
|
||||||
declare global {
|
declare global {
|
||||||
namespace App {
|
namespace App {
|
||||||
// interface Error {}
|
// interface Error {}
|
||||||
// interface Locals {}
|
// interface Locals {}
|
||||||
// interface PageData {}
|
// interface PageData {}
|
||||||
// interface PageState {}
|
// interface PageState {}
|
||||||
// interface Platform {}
|
// interface Platform {}
|
||||||
}
|
}
|
||||||
|
declare type FileDropEvent = import('filedrop-svelte/event').FileDropEvent;
|
||||||
|
declare type FileDropSelectEvent = import('filedrop-svelte/event').FileDropSelectEvent;
|
||||||
|
declare type FileDropDragEvent = import('filedrop-svelte/event').FileDropDragEvent;
|
||||||
|
declare namespace svelte.JSX {
|
||||||
|
interface HTMLAttributes<T> {
|
||||||
|
onfiledrop?: (event: CustomEvent<FileDropSelectEvent> & { target: EventTarget & T }) => void;
|
||||||
|
onfiledragenter?: (
|
||||||
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
onfiledragleave?: (
|
||||||
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
onfiledragover?: (
|
||||||
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
onfiledialogcancel?: (
|
||||||
|
event: CustomEvent<FileDropEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
onfiledialogclose?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
||||||
|
onfiledialogopen?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
||||||
|
onwindowfiledragenter?: (
|
||||||
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
onwindowfiledragleave?: (
|
||||||
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
onwindowfiledragover?: (
|
||||||
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
@ -1,61 +1,120 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PUBLIC_POCKETBASE_URL } from '$env/static/public';
|
import { PUBLIC_POCKETBASE_URL } from '$env/static/public';
|
||||||
|
import { filesize } from 'filesize';
|
||||||
|
|
||||||
let file;
|
let file: File | undefined = undefined;
|
||||||
let form;
|
|
||||||
let percent = 0;
|
let percent = 0;
|
||||||
|
let isDragging = false;
|
||||||
|
|
||||||
let completeMessage: string | undefined
|
let completeURL: string | undefined;
|
||||||
|
|
||||||
const handleFileChange = (event: Event & { currentTarget: HTMLInputElement }) => {
|
const handleFormClick = () => {
|
||||||
const target = event.target as unknown as { files: File[] }
|
if (percent > 0) {
|
||||||
const file = target.files[0]
|
return;
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('file', file)
|
|
||||||
|
|
||||||
let xhr = new XMLHttpRequest()
|
|
||||||
xhr.upload.onprogress = function(event) {
|
|
||||||
percent = Math.round(100 * event.loaded / event.total);
|
|
||||||
// do something with the percentage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = '*';
|
||||||
|
input.onchange = (e) => {
|
||||||
|
if (input.files) {
|
||||||
|
file = input.files[0];
|
||||||
|
handleFileChange(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFileChange = (file: File) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.upload.onprogress = function (event) {
|
||||||
|
percent = Math.round((100 * event.loaded) / event.total);
|
||||||
|
// do something with the percentage
|
||||||
|
};
|
||||||
|
|
||||||
xhr.onreadystatechange = (event) => {
|
xhr.onreadystatechange = (event) => {
|
||||||
if (xhr.readyState === 4 && xhr.status < 400) {
|
if (xhr.readyState === 4 && xhr.status < 400) {
|
||||||
const response = JSON.parse(xhr.responseText)
|
const response = JSON.parse(xhr.responseText);
|
||||||
completeMessage = `Upload complete! Access your file at http://localhost:5173/${response.id}`
|
completeURL = `${window.location.origin}/files/${response.id}`;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.open('POST', `${PUBLIC_POCKETBASE_URL}/api/collections/uploads/records`)
|
xhr.open('POST', `${PUBLIC_POCKETBASE_URL}/api/collections/uploads/records`);
|
||||||
xhr.send(formData)
|
xhr.send(formData);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const handleDrop = (
|
||||||
|
e: DragEvent & {
|
||||||
|
currentTarget: EventTarget & HTMLDivElement;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.dataTransfer?.files) {
|
||||||
|
file = e.dataTransfer.files[0];
|
||||||
|
handleFileChange(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDragEnter = (
|
||||||
|
e: DragEvent & {
|
||||||
|
currentTarget: EventTarget & HTMLDivElement;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
isDragging = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDragLeave = (
|
||||||
|
e: DragEvent & {
|
||||||
|
currentTarget: EventTarget & HTMLDivElement;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
isDragging = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDragOver = (
|
||||||
|
e: DragEvent & {
|
||||||
|
currentTarget: EventTarget & HTMLDivElement;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="flex flex-col items-center">
|
<main class="flex flex-col items-center h-full w-full">
|
||||||
<h1 class="text-4xl font-bold mt-4">KatStash</h1>
|
<h1 class="text-4xl font-bold mt-4">KatStash</h1>
|
||||||
|
|
||||||
<h2 class="text-2xl font-semibold mt-2">
|
<h2 class="text-2xl font-semibold mt-2">
|
||||||
Uploads up to 200 MB are allowed. Contact SphericalKat for more details
|
Uploads up to 200 MB are allowed. Contact SphericalKat for more details
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{#if completeMessage}
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
<h2 class="text-2xl font-semibold mt-2">Upload complete1</h2>
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
{/if}
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
|
<div
|
||||||
<form bind:this={form} method="POST">
|
on:dragenter={handleDragEnter}
|
||||||
<label class="block">
|
on:dragleave={handleDragLeave}
|
||||||
<span class="sr-only"></span>
|
on:drop={handleDrop}
|
||||||
<input
|
on:dragover={handleDragOver}
|
||||||
bind:this={file}
|
on:click={handleFormClick}
|
||||||
on:change={handleFileChange}
|
class:border-dashed={percent === 0}
|
||||||
type="file"
|
class:cursor-pointer={percent === 0 && !completeURL}
|
||||||
id="file"
|
class="h-48 w-[650px] mt-40 border-2 border-slate-500 rounded-lg flex items-center justify-center cursor-pointer"
|
||||||
class="file:hidden file:px-4 block w-full h-full text-sm text-slate-500"
|
>
|
||||||
/>
|
<div class="block">
|
||||||
{#if percent > 0}
|
{#if percent > 0 && !completeURL}
|
||||||
<div>{percent}%</div>
|
<span class="text-slate-500 px-16">Uploading {percent}%</span>
|
||||||
|
{:else if percent < 100 && !completeURL}
|
||||||
|
<span class="text-slate-500 px-16">Select or drop a file</span>
|
||||||
|
{:else}
|
||||||
|
<div class="text-slate-500 px-16">
|
||||||
|
Upload complete! Access your file at <a class="underline text-blue-500" href={completeURL}
|
||||||
|
>{completeURL}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { json, redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
import Pocketbase from 'pocketbase';
|
import Pocketbase from 'pocketbase';
|
||||||
import { PUBLIC_POCKETBASE_URL } from '$env/static/public';
|
import { PUBLIC_POCKETBASE_URL } from '$env/static/public';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user