progress bar + better ui

This commit is contained in:
Ludwig Lehnert
2026-03-27 20:08:40 +01:00
parent 31c7f92d7c
commit 83fbeff16c
8 changed files with 474 additions and 29 deletions

View File

@@ -1,15 +1,16 @@
import {
deleteOwnUploadAction,
extendOwnUploadAction,
uploadFileAction,
userLogoutAction,
} from '@/src/lib/actions.js';
import { all, runCleanupIfNeeded } from '@/src/lib/db.js';
import { sharedLinkName } from '@/src/lib/files.js';
import { formatBytes, formatCountdown, formatTimestamp, readSearchParam } from '@/src/lib/format.js';
import { ensureCsrfToken, requireAuthenticatedUser } from '@/src/lib/security.js';
import { CopyLinkButton } from '../_components/copy-link-button.js';
import { StatusMessage } from '../_components/status-message.js';
import { UploadProgressForm } from '../_components/upload-progress-form.js';
export const dynamic = 'force-dynamic';
@@ -26,6 +27,7 @@ export default async function DashboardPage({ searchParams }) {
const resolvedSearchParams = await searchParams;
const error = readSearchParam(resolvedSearchParams, 'error');
const success = readSearchParam(resolvedSearchParams, 'success');
const totalBytes = uploads.reduce((total, item) => total + (Number(item.size_bytes) || 0), 0);
return (
<main className="page-shell">
@@ -51,28 +53,33 @@ export default async function DashboardPage({ searchParams }) {
</div>
</header>
<section className="panel">
<h2>Neue Datei hochladen</h2>
<StatusMessage error={error} success={success} />
<StatusMessage error={error} success={success} />
<form className="form-grid" action={uploadFileAction} encType="multipart/form-data">
<input type="hidden" name="csrfToken" value={csrfToken} />
<div className="dashboard-top-grid">
<section className="panel panel-spotlight">
<h2>Neue Datei hochladen</h2>
<p className="muted">Der Fortschritt wird während des Uploads live angezeigt.</p>
<UploadProgressForm csrfToken={csrfToken} />
</section>
<label className="field">
Datei
<input className="input" name="file" type="file" required />
</label>
<label className="field">
Aufbewahrung in Stunden
<input className="input" name="retentionHours" placeholder="168" />
</label>
<button className="btn" type="submit">
Hochladen
</button>
</form>
</section>
<aside className="panel panel-soft">
<h2>Schnellüberblick</h2>
<div className="info-stack">
<div className="info-card">
<strong>{uploads.length}</strong>
<span className="muted">aktive Uploads</span>
</div>
<div className="info-card">
<strong>{totalBytes > 0 ? formatBytes(totalBytes) : '0 B'}</strong>
<span className="muted">genutzter Speicher</span>
</div>
<div className="info-card">
<strong>/_share/&lt;id&gt;</strong>
<span className="muted">Kurzlinks ohne Dateiendung</span>
</div>
</div>
</aside>
</div>
<section className="panel">
<h2>Aktuelle Uploads</h2>
@@ -92,7 +99,8 @@ export default async function DashboardPage({ searchParams }) {
</thead>
<tbody>
{uploads.map((item) => {
const sharePath = `/_share/${encodeURIComponent(item.stored_name)}`;
const shareName = sharedLinkName(item.stored_name);
const sharePath = `/_share/${encodeURIComponent(shareName)}`;
return (
<tr key={item.id}>
<td>