From 31316f1bd9b4dfb738469fbb7a8f5c1021a87fed Mon Sep 17 00:00:00 2001 From: "DESKTOP-KSVGT20\\shkim" Date: Mon, 11 May 2026 00:01:48 +0900 Subject: [PATCH] Add selected file thumbnails --- src/public/upload.css | 44 ++++++++++++++++++++++++++++++++++++++---- src/public/upload.html | 32 +++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/public/upload.css b/src/public/upload.css index 4e73a5e..1831ec7 100644 --- a/src/public/upload.css +++ b/src/public/upload.css @@ -223,29 +223,65 @@ h1 { margin: 0; padding: 0; list-style: none; + max-height: 265px; + overflow-y: auto; + overscroll-behavior: contain; + padding-right: 4px; } .file-list li { display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 12px; + grid-template-columns: minmax(0, 1fr) 64px; + min-height: 68px; + gap: 14px; align-items: center; + padding: 6px 0; color: #4f4f4f; font-family: "Apple SD Gothic Neo", "Malgun Gothic", system-ui, sans-serif; font-size: 13px; } -.file-list span:first-child { +.file-list__meta { + min-width: 0; +} + +.file-list__meta span { + display: block; +} + +.file-list__meta span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.file-list span:last-child { +.file-list__meta span:last-child { + margin-top: 5px; color: #87928f; font-size: 12px; } +.file-list__preview { + display: grid; + place-items: center; + width: 64px; + aspect-ratio: 1; + overflow: hidden; + border-radius: 6px; + background: #f7f8f6; + color: #8aa69f; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.08em; +} + +.file-list__preview img, +.file-list__preview video { + width: 100%; + height: 100%; + object-fit: cover; +} + .upload-status { min-height: 22px; margin: 12px 0 0; diff --git a/src/public/upload.html b/src/public/upload.html index e3f2e4e..a933726 100644 --- a/src/public/upload.html +++ b/src/public/upload.html @@ -55,6 +55,7 @@ const list = form.querySelector(".file-list"); const status = form.querySelector(".upload-status"); const thanks = document.querySelector(".thank-you"); + let previewUrls = []; submit.disabled = true; const formatBytes = (bytes) => { @@ -68,8 +69,14 @@ status.dataset.type = type; }; + const clearPreviews = () => { + previewUrls.forEach((url) => URL.revokeObjectURL(url)); + previewUrls = []; + }; + input?.addEventListener("change", () => { const files = Array.from(input.files || []); + clearPreviews(); list.replaceChildren(); if (files.length === 0) { @@ -81,11 +88,34 @@ files.forEach((file) => { const item = document.createElement("li"); + const meta = document.createElement("div"); const name = document.createElement("span"); const size = document.createElement("span"); + const preview = document.createElement("div"); + const previewUrl = URL.createObjectURL(file); + + previewUrls.push(previewUrl); + meta.className = "file-list__meta"; + preview.className = "file-list__preview"; name.textContent = file.name; size.textContent = formatBytes(file.size); - item.append(name, size); + if (file.type.startsWith("video/")) { + const video = document.createElement("video"); + video.src = previewUrl; + video.muted = true; + video.playsInline = true; + video.preload = "metadata"; + preview.append(video); + } else if (file.type.startsWith("image/")) { + const image = document.createElement("img"); + image.src = previewUrl; + image.alt = ""; + preview.append(image); + } else { + preview.textContent = "FILE"; + } + meta.append(name, size); + item.append(meta, preview); list.append(item); });