feat: polish UI

Signed-off-by: Sphericalkat <me@kat.bio>
This commit is contained in:
Amogh Lele 2024-06-18 11:12:31 +05:30
parent 0e4eeb5f19
commit 767b0417c8
Signed by: sphericalkat
GPG Key ID: 1C022B9CED2425B4
6 changed files with 158 additions and 52 deletions

View File

@ -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",

View File

@ -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

View File

@ -1,3 +1,9 @@
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
html,
body {
height: 100%;
width: 100%;
}

31
src/app.d.ts vendored
View File

@ -8,6 +8,37 @@ declare global {
// 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 {};

View File

@ -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 -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
on:dragenter={handleDragEnter}
on:dragleave={handleDragLeave}
on:drop={handleDrop}
on:dragover={handleDragOver}
on:click={handleFormClick}
class:border-dashed={percent === 0}
class:cursor-pointer={percent === 0 && !completeURL}
class="h-48 w-[650px] mt-40 border-2 border-slate-500 rounded-lg flex items-center justify-center cursor-pointer"
>
<div class="block">
{#if percent > 0 && !completeURL}
<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}
</div>
<form bind:this={form} method="POST"> </div>
<label class="block">
<span class="sr-only"></span>
<input
bind:this={file}
on:change={handleFileChange}
type="file"
id="file"
class="file:hidden file:px-4 block w-full h-full text-sm text-slate-500"
/>
{#if percent > 0}
<div>{percent}%</div>
{/if}
</label>
</form>
</main> </main>

View File

@ -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';