161 lines
5.7 KiB
HTML
161 lines
5.7 KiB
HTML
<!doctype html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{title}}</title>
|
|
<link rel="stylesheet" href="{{cssPath}}">
|
|
</head>
|
|
<body>
|
|
<main class="upload-page">
|
|
<section class="wedding-card" aria-labelledby="archive-title">
|
|
<div class="poster">
|
|
<img class="poster__art" src="/assets/wedding-illustration.png?v=single-illustration-1" alt="">
|
|
|
|
<div class="poster__plate">
|
|
<h1 id="archive-title">{{title}}</h1>
|
|
<p class="poster__date">2026.05.24 SUN</p>
|
|
<p class="poster__subtitle">OUR WEDDING ARCHIVE</p>
|
|
</div>
|
|
</div>
|
|
|
|
<form class="upload-panel" method="post" action="/r/{{slug}}" enctype="multipart/form-data">
|
|
<p class="upload-panel__today">오늘의 순간</p>
|
|
|
|
<label class="select-button file-picker">
|
|
<span>사진 선택하기</span>
|
|
<input type="file" name="files" accept="{{accept}}" multiple required>
|
|
</label>
|
|
|
|
<div class="file-summary" hidden>
|
|
<p class="file-summary__title">선택한 파일</p>
|
|
<ul class="file-list"></ul>
|
|
</div>
|
|
|
|
<button class="upload-button" type="submit" aria-label="업로드">
|
|
<span>업로드하기</span>
|
|
</button>
|
|
|
|
<p class="upload-status" aria-live="polite"></p>
|
|
</form>
|
|
|
|
<section class="thank-you" hidden>
|
|
<p class="thank-you__eyebrow">THANK YOU</p>
|
|
<h2>감사합니다</h2>
|
|
<p>소중한 오늘을 함께 남겨주셔서 감사드립니다.</p>
|
|
<a class="upload-again" href="/r/{{slug}}">사진 더 올리기</a>
|
|
</section>
|
|
</section>
|
|
</main>
|
|
<script>
|
|
document.querySelectorAll(".upload-panel").forEach((form) => {
|
|
const input = form.querySelector('input[type="file"][name="files"]');
|
|
const submit = form.querySelector('button[type="submit"][aria-label="업로드"]');
|
|
const summary = form.querySelector(".file-summary");
|
|
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) => {
|
|
if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
return `${bytes} B`;
|
|
};
|
|
|
|
const setStatus = (message, type = "") => {
|
|
status.textContent = message;
|
|
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) {
|
|
summary.hidden = true;
|
|
submit.disabled = true;
|
|
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;
|
|
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);
|
|
});
|
|
|
|
summary.hidden = false;
|
|
submit.disabled = false;
|
|
setStatus(`${files.length}개 파일을 선택했어요.`);
|
|
});
|
|
|
|
form.addEventListener("submit", async (event) => {
|
|
event.preventDefault();
|
|
if (!input.files || input.files.length === 0) {
|
|
setStatus("먼저 사진을 선택해 주세요.", "error");
|
|
return;
|
|
}
|
|
|
|
submit.disabled = true;
|
|
form.dataset.uploading = "true";
|
|
setStatus("업로드 중이에요. 화면을 닫지 말아 주세요.");
|
|
|
|
try {
|
|
const response = await fetch(form.action, {
|
|
method: "POST",
|
|
body: new FormData(form),
|
|
headers: { "Accept": "application/json" }
|
|
});
|
|
const result = await response.json().catch(() => ({}));
|
|
if (!response.ok || !result.ok) throw new Error(result.message || "업로드 중 오류가 났어요.");
|
|
|
|
form.hidden = true;
|
|
thanks.hidden = false;
|
|
thanks.querySelector("p:last-of-type").innerHTML =
|
|
`${result.count || input.files.length}개의 파일 잘 받았습니다.<br>소중한 오늘을 함께 남겨주셔서 감사드립니다.`;
|
|
} catch (error) {
|
|
submit.disabled = false;
|
|
form.dataset.uploading = "false";
|
|
setStatus(error.message || "업로드 중 오류가 났어요. 다시 시도해 주세요.", "error");
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|