diff --git a/src/public/upload.css b/src/public/upload.css index 4c49123..8505643 100644 --- a/src/public/upload.css +++ b/src/public/upload.css @@ -190,6 +190,10 @@ h1 { font-size: clamp(24px, 4.6vw, 32px); } +.upload-button { + margin-bottom: 14px; +} + .file-picker input[type="file"] { position: absolute; inset: 0; @@ -200,6 +204,7 @@ h1 { } .file-summary { + position: relative; margin: 0 0 14px; padding: 16px 18px; border: 1px solid rgba(137, 166, 158, 0.35); @@ -218,47 +223,23 @@ h1 { } .file-list { - display: grid; - gap: 8px; + display: flex; + flex-wrap: wrap; + gap: 7px; margin: 0; padding: 0; list-style: none; - max-height: 265px; + max-height: 161px; overflow-y: auto; overscroll-behavior: contain; padding-right: 4px; } .file-list li { - display: grid; - grid-template-columns: minmax(0, 1fr) 40px; - min-height: 43px; - gap: 14px; - align-items: center; + flex: 0 0 40px; + width: 40px; + height: 40px; padding: 0; - color: #4f4f4f; - font-family: "Apple SD Gothic Neo", "Malgun Gothic", system-ui, sans-serif; - font-size: 13px; -} - -.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__meta span:last-child { - margin-top: 5px; - color: #87928f; - font-size: 12px; } .file-list__preview { @@ -282,6 +263,32 @@ h1 { object-fit: cover; } +.file-list__top { + position: absolute; + right: 12px; + bottom: 12px; + width: 42px; + height: 42px; + border: 0; + border-radius: 50%; + background: var(--deep); + box-shadow: none; + cursor: pointer; +} + +.file-list__top::before { + content: ""; + position: absolute; + left: 50%; + top: 50%; + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 10px solid #ffffff; + transform: translate(-50%, -62%); +} + .upload-status { min-height: 22px; margin: 12px 0 0; diff --git a/src/public/upload.html b/src/public/upload.html index a933726..2132b3f 100644 --- a/src/public/upload.html +++ b/src/public/upload.html @@ -22,6 +22,10 @@
@@ -53,10 +54,12 @@ const submit = form.querySelector('button[type="submit"][aria-label="업로드"]'); const summary = form.querySelector(".file-summary"); const list = form.querySelector(".file-list"); + const scrollTopButton = form.querySelector(".file-list__top"); const status = form.querySelector(".upload-status"); const thanks = document.querySelector(".thank-you"); let previewUrls = []; submit.disabled = true; + submit.hidden = true; const formatBytes = (bytes) => { if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`; @@ -74,6 +77,11 @@ previewUrls = []; }; + const updateScrollTopButton = () => { + if (!scrollTopButton) return; + scrollTopButton.hidden = list.scrollHeight <= list.clientHeight || list.scrollTop < 8; + }; + input?.addEventListener("change", () => { const files = Array.from(input.files || []); clearPreviews(); @@ -82,23 +90,19 @@ if (files.length === 0) { summary.hidden = true; submit.disabled = true; + submit.hidden = true; + updateScrollTopButton(); setStatus(""); return; } 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); if (file.type.startsWith("video/")) { const video = document.createElement("video"); video.src = previewUrl; @@ -114,16 +118,23 @@ } else { preview.textContent = "FILE"; } - meta.append(name, size); - item.append(meta, preview); + item.append(preview); list.append(item); }); summary.hidden = false; submit.disabled = false; + submit.hidden = false; + list.scrollTop = 0; + requestAnimationFrame(updateScrollTopButton); setStatus(`${files.length}개 파일을 선택했어요.`); }); + list.addEventListener("scroll", updateScrollTopButton); + scrollTopButton?.addEventListener("click", () => { + list.scrollTo({ top: 0, behavior: "smooth" }); + }); + form.addEventListener("submit", async (event) => { event.preventDefault(); if (!input.files || input.files.length === 0) {