Rust (axum + sqlx) API and worker sharing a Postgres-backed job queue (SKIP LOCKED, heartbeat, reaper, typed statuses), S3 storage with derived keys and a fully private bucket, OIDC photographer login with per-request allowlist checks, client share links with argon2 passwords and lockout, cookie-based image authorization with sliding expiry, hand-rolled spec-compliant streaming ZIP downloads with exact Content-Length, React + Vite gallery frontend, single Docker image, Helm chart for external S3 + Postgres, and Gitea CI. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
export function fmtBytes(bytes) {
|
||||
if (!bytes) return '0 B'
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||
const i = Math.min(Math.floor(Math.log2(bytes) / 10), units.length - 1)
|
||||
const value = bytes / 2 ** (10 * i)
|
||||
return `${value >= 100 || i === 0 ? Math.round(value) : value.toFixed(1)} ${units[i]}`
|
||||
}
|
||||
|
||||
export default function SelectionBar({
|
||||
count,
|
||||
total,
|
||||
selectedBytes,
|
||||
totalBytes,
|
||||
onSelectAll,
|
||||
onClear,
|
||||
onDownload,
|
||||
onDownloadAll,
|
||||
}) {
|
||||
if (total === 0) return null
|
||||
|
||||
if (count === 0) {
|
||||
return (
|
||||
<div className="select-bar">
|
||||
<span className="select-count">
|
||||
{total} photo{total === 1 ? '' : 's'} · {fmtBytes(totalBytes)}
|
||||
</span>
|
||||
<button className="btn btn-primary" onClick={onDownloadAll}>
|
||||
Download all as ZIP
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="select-bar">
|
||||
<span className="select-count">
|
||||
{count} of {total} selected
|
||||
</span>
|
||||
{count < total && (
|
||||
<button className="btn" onClick={onSelectAll}>
|
||||
Select all
|
||||
</button>
|
||||
)}
|
||||
<button className="btn" onClick={onClear}>
|
||||
Clear
|
||||
</button>
|
||||
<button className="btn btn-primary" onClick={onDownload}>
|
||||
Download {count} as ZIP ({fmtBytes(selectedBytes)})
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user