style: unify ui copy and naming

This commit is contained in:
2026-06-07 20:38:03 +02:00
parent faeecfae89
commit 96ef037d8b

View File

@@ -799,7 +799,7 @@ function htmlPage(): string {
<div class="layout"> <div class="layout">
<aside> <aside>
<section class="card"> <section class="card">
<h2>Nextcloud Share</h2> <h2>Nextcloud Import</h2>
<p>Paste a public share link to import images directly in the browser.</p> <p>Paste a public share link to import images directly in the browser.</p>
<label> <label>
Share URL Share URL
@@ -866,7 +866,7 @@ function htmlPage(): string {
<h2>Timeline</h2> <h2>Timeline</h2>
<div class="timeline-summary" id="timeline-summary">No photos imported yet.</div> <div class="timeline-summary" id="timeline-summary">No photos imported yet.</div>
</div> </div>
<button class="secondary" id="timeline-clear" type="button" disabled>Clear range</button> <button class="secondary" id="timeline-clear" type="button" disabled>Reset range</button>
</div> </div>
<div class="timeline-chart" id="timeline-chart"> <div class="timeline-chart" id="timeline-chart">
<div class="timeline-bars" id="timeline-bars"></div> <div class="timeline-bars" id="timeline-bars"></div>
@@ -876,7 +876,7 @@ function htmlPage(): string {
<div class="timeline-axis" id="timeline-axis"></div> <div class="timeline-axis" id="timeline-axis"></div>
<div class="timeline-footer"> <div class="timeline-footer">
<span id="timeline-range">All photos</span> <span id="timeline-range">All photos</span>
<span id="timeline-unit">Scale: day</span> <span id="timeline-unit">Scale: Day</span>
</div> </div>
</section> </section>
</main> </main>
@@ -946,7 +946,7 @@ function htmlPage(): string {
const progressDetail = mustGet("progress-detail"); const progressDetail = mustGet("progress-detail");
const activitySpinner = mustGet("activity-spinner"); const activitySpinner = mustGet("activity-spinner");
const timelineSummary = mustGet("timeline-summary"); const timelineSummary = mustGet("timeline-summary");
const timelineClear = mustGet("timeline-clear"); const timelineClearButton = mustGet("timeline-clear");
const timelineChart = mustGet("timeline-chart"); const timelineChart = mustGet("timeline-chart");
const timelineBars = mustGet("timeline-bars"); const timelineBars = mustGet("timeline-bars");
const timelineSelection = mustGet("timeline-selection"); const timelineSelection = mustGet("timeline-selection");
@@ -957,10 +957,10 @@ function htmlPage(): string {
const themeToggle = mustGet("theme-toggle"); const themeToggle = mustGet("theme-toggle");
const themeToggleIcon = mustGet("theme-toggle-icon"); const themeToggleIcon = mustGet("theme-toggle-icon");
const themeToggleLabel = mustGet("theme-toggle-label"); const themeToggleLabel = mustGet("theme-toggle-label");
const shareUrl = mustGet("share-url"); const importUrlInput = mustGet("share-url");
const shareStatus = mustGet("share-status"); const importStatus = mustGet("share-status");
const loadShare = mustGet("load-share"); const importButton = mustGet("load-share");
const cancelShare = mustGet("cancel-share"); const stopImportButton = mustGet("cancel-share");
function mustGet(id) { function mustGet(id) {
const element = document.getElementById(id); const element = document.getElementById(id);
@@ -1266,9 +1266,9 @@ function htmlPage(): string {
}; };
} }
function updateStatus(message, tone = "info") { function setImportStatus(message, tone = "info") {
shareStatus.textContent = message; importStatus.textContent = message;
shareStatus.style.color = tone === "error" ? "#9d174d" : "var(--muted)"; importStatus.style.color = tone === "error" ? "#9d174d" : "var(--muted)";
} }
function setProgress(processed, total, detail) { function setProgress(processed, total, detail) {
@@ -1281,8 +1281,8 @@ function htmlPage(): string {
function setImporting(isImporting) { function setImporting(isImporting) {
activitySpinner.classList.toggle("active", isImporting); activitySpinner.classList.toggle("active", isImporting);
loadShare.disabled = isImporting; importButton.disabled = isImporting;
cancelShare.disabled = !isImporting; stopImportButton.disabled = !isImporting;
} }
function clearObjectUrls() { function clearObjectUrls() {
@@ -1311,15 +1311,15 @@ function htmlPage(): string {
photoCount.textContent = "0 photos"; photoCount.textContent = "0 photos";
timelineSummary.textContent = "No photos imported yet."; timelineSummary.textContent = "No photos imported yet.";
timelineRange.textContent = "All photos"; timelineRange.textContent = "All photos";
timelineUnit.textContent = "Scale: day"; timelineUnit.textContent = "Scale: Day";
timelineClear.disabled = true; timelineClearButton.disabled = true;
timelineBars.replaceChildren(); timelineBars.replaceChildren();
timelineAxis.replaceChildren(); timelineAxis.replaceChildren();
timelineSelection.classList.remove("visible"); timelineSelection.classList.remove("visible");
timelineSelection.style.left = "0"; timelineSelection.style.left = "0";
timelineSelection.style.width = "0"; timelineSelection.style.width = "0";
timelineBrush.classList.remove("visible"); timelineBrush.classList.remove("visible");
setProgress(0, 0, "ready"); setProgress(0, 0, "idle");
} }
function openOverlay(photo) { function openOverlay(photo) {
@@ -1414,7 +1414,7 @@ function htmlPage(): string {
if (start === null || end === null) { if (start === null || end === null) {
state.timelineSelection = null; state.timelineSelection = null;
state.timelineViewport = null; state.timelineViewport = null;
timelineClear.disabled = true; timelineClearButton.disabled = true;
} else { } else {
const normalizedStart = Math.min(start, end); const normalizedStart = Math.min(start, end);
const normalizedEnd = Math.max(start, end); const normalizedEnd = Math.max(start, end);
@@ -1426,7 +1426,7 @@ function htmlPage(): string {
start: normalizedStart, start: normalizedStart,
end: normalizedEnd end: normalizedEnd
}; };
timelineClear.disabled = false; timelineClearButton.disabled = false;
} }
renderVisiblePhotos({ fitMap: true }); renderVisiblePhotos({ fitMap: true });
@@ -1441,7 +1441,11 @@ function htmlPage(): string {
const timeline = buildTimeline(timelinePhotos, state.timelineViewport); const timeline = buildTimeline(timelinePhotos, state.timelineViewport);
state.timeline = timeline; state.timeline = timeline;
timelineSummary.textContent = formatTimelineSummary(state.photos, timeline.unit); timelineSummary.textContent = formatTimelineSummary(state.photos, timeline.unit);
timelineUnit.textContent = "Scale: " + timeline.unit + (state.timelineSelection ? " · zoomed" : ""); timelineUnit.textContent =
"Scale: " +
timeline.unit.charAt(0).toUpperCase() +
timeline.unit.slice(1) +
(state.timelineSelection ? " · zoomed" : "");
timelineBars.replaceChildren(); timelineBars.replaceChildren();
timelineAxis.replaceChildren(); timelineAxis.replaceChildren();
@@ -1699,7 +1703,7 @@ function htmlPage(): string {
timelineChart.addEventListener("pointerup", finishTimelinePointer); timelineChart.addEventListener("pointerup", finishTimelinePointer);
timelineChart.addEventListener("pointercancel", finishTimelinePointer); timelineChart.addEventListener("pointercancel", finishTimelinePointer);
timelineClear.addEventListener("click", clearTimelineSelection); timelineClearButton.addEventListener("click", clearTimelineSelection);
function appendPhoto(photo) { function appendPhoto(photo) {
state.photos.push(photo); state.photos.push(photo);
@@ -1745,7 +1749,7 @@ function htmlPage(): string {
}); });
} }
async function loadShareListing(shareUrlValue, signal) { async function loadImportListing(shareUrlValue, signal) {
const davBaseUrl = resolveDavBaseUrl(shareUrlValue); const davBaseUrl = resolveDavBaseUrl(shareUrlValue);
const response = await fetch( const response = await fetch(
"/api/nextcloud/list?share=" + encodeURIComponent(shareUrlValue.trim()), "/api/nextcloud/list?share=" + encodeURIComponent(shareUrlValue.trim()),
@@ -1761,7 +1765,7 @@ function htmlPage(): string {
return parseListing(await response.text(), davBaseUrl); return parseListing(await response.text(), davBaseUrl);
} }
async function readRemotePhoto(entry, signal) { async function readRemoteImage(entry, signal) {
const response = await fetch("/api/nextcloud/blob?url=" + encodeURIComponent(entry.href), { const response = await fetch("/api/nextcloud/blob?url=" + encodeURIComponent(entry.href), {
signal signal
}); });
@@ -1789,7 +1793,7 @@ function htmlPage(): string {
}; };
} }
async function importFromNextcloud() { async function importFromShare() {
if (activeImportController) { if (activeImportController) {
return; return;
} }
@@ -1801,11 +1805,11 @@ function htmlPage(): string {
try { try {
clearObjectUrls(); clearObjectUrls();
clearGallery(); clearGallery();
updateStatus("Importing..."); setImportStatus("Importing...");
const listing = await loadShareListing(shareUrl.value, controller.signal); const listing = await loadImportListing(importUrlInput.value, controller.signal);
if (!listing.length) { if (!listing.length) {
throw new Error("No images were found in the share."); throw new Error("No images found in the share.");
} }
setProgress(0, listing.length, "checking files"); setProgress(0, listing.length, "checking files");
@@ -1820,7 +1824,7 @@ function htmlPage(): string {
} }
try { try {
const photo = await readRemotePhoto(entry, controller.signal); const photo = await readRemoteImage(entry, controller.signal);
if (photo.latitude !== null && photo.longitude !== null) { if (photo.latitude !== null && photo.longitude !== null) {
appendPhoto(photo); appendPhoto(photo);
loaded += 1; loaded += 1;
@@ -1833,33 +1837,27 @@ function htmlPage(): string {
} }
processed += 1; processed += 1;
setProgress( setProgress(processed, listing.length, "processed " + processed + " / " + listing.length);
processed, setImportStatus("Importing: " + loaded + " shown, " + skipped + " skipped.");
listing.length,
"processed " + processed + " / " + listing.length
);
updateStatus(
"Importing: " + loaded + " shown, " + skipped + " skipped."
);
} }
if (!loaded) { if (!loaded) {
throw new Error("No images with GPS data were found."); throw new Error("No images with GPS data found.");
} }
updateStatus( setImportStatus(
"Import complete: " + loaded + " images imported" + (skipped ? ", " + skipped + " skipped" : "") + "." "Import complete: " + loaded + " images imported" + (skipped ? ", " + skipped + " skipped" : "") + "."
); );
setProgress(listing.length, listing.length, "complete"); setProgress(listing.length, listing.length, "complete");
} catch (error) { } catch (error) {
if (controller.signal.aborted) { if (controller.signal.aborted) {
updateStatus("Import canceled."); setImportStatus("Import stopped.");
setProgress(state.processed, state.total, "canceled"); setProgress(state.processed, state.total, "canceled");
return; return;
} }
console.error(error); console.error(error);
updateStatus( setImportStatus(
"Import failed: " + (error instanceof Error ? error.message : "unknown error"), "Import failed: " + (error instanceof Error ? error.message : "unknown error"),
"error" "error"
); );
@@ -1879,18 +1877,18 @@ function htmlPage(): string {
} }
}); });
loadShare.addEventListener("click", () => { importButton.addEventListener("click", () => {
void importFromNextcloud(); void importFromShare();
}); });
cancelShare.addEventListener("click", () => { stopImportButton.addEventListener("click", () => {
if (activeImportController) { if (activeImportController) {
activeImportController.abort("Import canceled by user"); activeImportController.abort("Import canceled by user");
} }
}); });
clearGallery(); clearGallery();
updateStatus("Ready to import."); setImportStatus("Ready to import.");
</script> </script>
</body> </body>
</html>`; </html>`;