refactor(ui): tile photo list

This commit is contained in:
2026-06-12 14:51:08 +02:00
parent fe7787d1ef
commit bb1d388af6

View File

@@ -498,47 +498,47 @@ function htmlPage(): string {
.list { .list {
display: grid; display: grid;
gap: 6px; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
gap: 8px;
align-content: start;
min-height: 0; min-height: 0;
overflow: auto; overflow: auto;
padding-right: 2px; padding-right: 2px;
} }
.photo { .photo {
display: grid; display: block;
grid-template-columns: 38px 1fr; position: relative;
gap: 8px; aspect-ratio: 1 / 1;
align-items: center; padding: 0;
padding: 8px;
border-radius: var(--radius-md); border-radius: var(--radius-md);
background: var(--timeline-surface-soft); background: var(--timeline-surface-soft);
border: 1px solid var(--timeline-border); border: 1px solid var(--timeline-border);
color: var(--timeline-text); color: var(--timeline-text);
min-width: 0; min-width: 0;
overflow: hidden;
} }
.photo img { .photo img {
width: 38px; width: 100%;
height: 38px; height: 100%;
object-fit: cover; object-fit: cover;
border-radius: 0; border-radius: 0;
display: block;
} }
.photo strong { .photo::after {
display: block; content: "";
font-size: 0.8rem; position: absolute;
overflow: hidden; inset: 0;
text-overflow: ellipsis; background: linear-gradient(to top, rgba(15, 23, 42, 0.34), transparent 42%);
white-space: nowrap; opacity: 0;
transition: opacity 140ms ease;
} }
.photo span { .photo:hover::after,
color: var(--timeline-text-muted); .photo.active::after {
font-size: 0.7rem; opacity: 1;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.photo.active { .photo.active {
@@ -858,6 +858,7 @@ function htmlPage(): string {
.list { .list {
max-height: min(52vh, 420px); max-height: min(52vh, 420px);
grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
} }
main { main {
@@ -1638,11 +1639,11 @@ function htmlPage(): string {
const item = document.createElement("article"); const item = document.createElement("article");
item.className = "photo" + (photo.id === state.activePhotoId ? " active" : ""); item.className = "photo" + (photo.id === state.activePhotoId ? " active" : "");
const photoTitle = photo.name + "\n" + formatDate(photo.capturedAt);
item.title = photoTitle;
item.setAttribute("aria-label", photoTitle);
item.innerHTML = item.innerHTML =
'<img src="' + escapeHtml(photo.thumbUrl) + '" alt="' + escapeHtml(photo.name) + '" />' + '<img src="' + escapeHtml(photo.thumbUrl) + '" alt="' + escapeHtml(photo.name) + '" />';
'<div><strong>' + escapeHtml(photo.name) + '</strong><span>' +
escapeHtml(formatDate(photo.capturedAt)) +
'</span></div>';
item.addEventListener("click", () => { item.addEventListener("click", () => {
state.activePhotoId = photo.id; state.activePhotoId = photo.id;
renderVisiblePhotos({ fitMap: false }); renderVisiblePhotos({ fitMap: false });