From bded7ff597ddd891d9c8d7cc2243990b6889e413 Mon Sep 17 00:00:00 2001 From: zzstoatzz Date: Wed, 17 Jun 2026 14:51:21 -0500 Subject: [PATCH] enrich latest-post card and match it to the event card height MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit render the data the appview already returns but we discarded: the post's embedded link card (thumb/title/description/domain) and an engagement row (likes · reposts · replies). on wide screens both cards stretch to equal height — the event image absorbs its slack, the post pins its stats to the bottom — so the columns read as a balanced pair. Co-Authored-By: Claude Fable 5 --- site/index.html | 4 +-- site/script.js | 67 ++++++++++++++++++++++++++++++++------ site/styles.css | 86 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 140 insertions(+), 17 deletions(-) diff --git a/site/index.html b/site/index.html index d243073..d4142dc 100644 --- a/site/index.html +++ b/site/index.html @@ -15,8 +15,8 @@ - - + + diff --git a/site/script.js b/site/script.js index 8e8db0c..91e40c8 100644 --- a/site/script.js +++ b/site/script.js @@ -339,20 +339,69 @@ const postUrlFor = (viewer, rkey, did) => body.appendChild(textEl); } - card.appendChild(body); - - // ── thumbnail: first image, or an external link card's preview ── + // ── embed: post image, or an external link card ── const embed = post.embed || {}; - const thumb = embed.images?.[0]?.thumb || embed.external?.thumb; - if (thumb) { + if (embed.images?.length) { const img = document.createElement('img'); - img.className = 'post-thumb'; - img.src = thumb; - img.alt = embed.images?.[0]?.alt || ''; + img.className = 'post-media'; + img.src = embed.images[0].thumb; + img.alt = embed.images[0].alt || ''; img.loading = 'lazy'; - card.appendChild(img); + body.appendChild(img); + } else if (embed.external) { + const ext = embed.external; + const linkCard = document.createElement('div'); // non-interactive: the whole card is already a link + linkCard.className = 'post-embed'; + + if (ext.thumb) { + const t = document.createElement('img'); + t.className = 'post-embed-thumb'; + t.src = ext.thumb; + t.alt = ''; + t.loading = 'lazy'; + linkCard.appendChild(t); + } + + const meta = document.createElement('div'); + meta.className = 'post-embed-meta'; + if (ext.title) { + const ti = document.createElement('p'); + ti.className = 'post-embed-title'; + ti.textContent = ext.title; + meta.appendChild(ti); + } + if (ext.description) { + const de = document.createElement('p'); + de.className = 'post-embed-desc'; + de.textContent = ext.description; + meta.appendChild(de); + } + const dom = document.createElement('p'); + dom.className = 'post-embed-domain'; + try { dom.textContent = new URL(ext.uri).hostname.replace(/^www\./, ''); } + catch { dom.textContent = ext.uri; } + meta.appendChild(dom); + + linkCard.appendChild(meta); + body.appendChild(linkCard); + } + + // ── engagement, pinned to the bottom (margin-top:auto) so equal-height + // cards read as intentional rather than as empty space ── + const stat = (n, one, many) => n > 0 ? `${n} ${n === 1 ? one : many}` : null; + const stats = [ + stat(post.likeCount, 'like', 'likes'), + stat(post.repostCount, 'repost', 'reposts'), + stat(post.replyCount, 'reply', 'replies'), + ].filter(Boolean); + if (stats.length) { + const statsEl = document.createElement('p'); + statsEl.className = 'post-stats'; + statsEl.textContent = stats.join(' · '); + body.appendChild(statsEl); } + card.appendChild(body); section.appendChild(card); section.hidden = false; } catch (_) { diff --git a/site/styles.css b/site/styles.css index e55bb9f..6ad60c3 100644 --- a/site/styles.css +++ b/site/styles.css @@ -197,6 +197,15 @@ a:focus-visible { text-decoration-color: var(--accent); outline: none; } box-shadow: 0 8px 24px -10px rgba(14, 17, 22, 0.25); } +/* both cards are flex columns so, when stretched to equal height on wide + * screens, each can let one region absorb the slack — the event image + * grows, the post pins its stats to the bottom. */ +.event-card, +.post-card { + display: flex; + flex-direction: column; +} + /* ── event card ── */ .event-thumb { @@ -236,6 +245,10 @@ a:focus-visible { text-decoration-color: var(--accent); outline: none; } /* ── post card ── */ .post-body { + flex: 1 1 auto; + display: flex; + flex-direction: column; + gap: 0.6rem; padding: 0.9rem 1rem 1rem; text-align: left; } @@ -244,7 +257,6 @@ a:focus-visible { text-decoration-color: var(--accent); outline: none; } display: flex; align-items: center; gap: 0.5rem; - margin-bottom: 0.6rem; } .post-avatar { @@ -275,14 +287,67 @@ a:focus-visible { text-decoration-color: var(--accent); outline: none; } overflow-wrap: anywhere; } -.post-thumb { +/* inline post image */ +.post-media { display: block; width: 100%; height: auto; max-height: 45vh; max-height: 45svh; object-fit: cover; - border-top: 1px solid var(--rule); + border-radius: 8px; +} + +/* external link card (matches bluesky's preview structure) */ +.post-embed { + border: 1px solid var(--rule); + border-radius: 8px; + overflow: hidden; +} + +.post-embed-thumb { + display: block; + width: 100%; + height: auto; + max-height: 12rem; + object-fit: cover; +} + +.post-embed-meta { + padding: 0.6rem 0.75rem; +} + +.post-embed-title { + margin: 0; + font-size: 0.9rem; + line-height: 1.35; + color: var(--ink); +} + +.post-embed-desc { + margin: 0.25rem 0 0; + font-size: 0.8rem; + line-height: 1.4; + color: var(--muted); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.post-embed-domain { + margin: 0.4rem 0 0; + font-size: 0.75rem; + color: var(--muted); +} + +/* engagement row, pinned to the bottom of the body */ +.post-stats { + margin: 0.2rem 0 0; + margin-top: auto; + padding-top: 0.6rem; + font-size: 0.8rem; + color: var(--muted); } /* ─── footer (find us in the atmosphere) ─────────── */ @@ -440,7 +505,7 @@ footer { .cards { flex-direction: row; - align-items: flex-start; + align-items: stretch; justify-content: center; gap: 1.5rem; padding-top: 0; @@ -460,8 +525,17 @@ footer { border-radius: 10px; } + /* cards fill their column so the two match height */ + .event-card, + .post-card { + flex: 1 1 auto; + } + + /* the event image takes up any slack so the card has no dead space */ .event-thumb { - max-height: 16rem; + flex: 1 1 auto; + min-height: 14rem; + max-height: 20rem; } footer { @@ -483,7 +557,7 @@ footer { .cards { padding-top: 1.5rem; gap: 1.75rem; } .section-label { margin-bottom: 0.75rem; } .event-thumb, - .post-thumb { + .post-media { max-height: 25vh; max-height: 25svh; } -- 2.51.2