fix: og image fix for collections

This commit is contained in:
gosangam
2026-06-14 01:49:44 +05:30
parent 3accc753d0
commit 23d06a3db5
3 changed files with 132 additions and 77 deletions
+65 -54
View File
@@ -76,6 +76,10 @@ export async function GET(
return new ImageResponse( return new ImageResponse(
( (
// Root carries NO padding — absolutely-positioned children measure
// from the padding box, so any root padding would inset the full-bleed
// cover image and leave the bg colour showing as a strip. Padding lives
// on the inner content layer instead.
<div <div
style={{ style={{
width: 1200, width: 1200,
@@ -85,7 +89,6 @@ export async function GET(
backgroundColor: hasImage ? "#1a1410" : "#faf5f0", backgroundColor: hasImage ? "#1a1410" : "#faf5f0",
fontFamily: "Noto Sans, sans-serif", fontFamily: "Noto Sans, sans-serif",
position: "relative", position: "relative",
padding: 80,
}} }}
> >
{hasImage ? ( {hasImage ? (
@@ -119,72 +122,80 @@ export async function GET(
</> </>
) : null} ) : null}
{/* Eyebrow */} {/* Content layer — holds the padding so the bg image stays full-bleed. */}
<div <div
style={{ style={{
display: "flex", position: "relative",
fontSize: 24,
fontWeight: 700,
letterSpacing: 6,
textTransform: "uppercase",
color: accent,
zIndex: 1, zIndex: 1,
flex: 1,
display: "flex",
flexDirection: "column",
padding: 80,
}} }}
> >
Collection {/* Eyebrow */}
</div>
{/* Title — the centrepiece */}
<div
style={{
display: "flex",
fontSize: title.length > 48 ? 60 : 76,
fontWeight: 700,
color: textPrimary,
lineHeight: 1.15,
marginTop: 24,
maxHeight: 320,
overflow: "hidden",
zIndex: 1,
}}
>
{title}
</div>
{description ? (
<div <div
style={{ style={{
display: "flex", display: "flex",
fontSize: 28, fontSize: 24,
color: textSecondary, fontWeight: 700,
lineHeight: 1.4, letterSpacing: 6,
marginTop: 24, textTransform: "uppercase",
maxHeight: 120, color: accent,
overflow: "hidden",
zIndex: 1,
}} }}
> >
{description} Collection
</div> </div>
) : null}
<div style={{ flex: 1, display: "flex" }} /> {/* Title — the centrepiece */}
<div
{/* Footer: count + branding */} style={{
<div display: "flex",
style={{ fontSize: title.length > 48 ? 60 : 76,
display: "flex", fontWeight: 700,
flexDirection: "row", color: textPrimary,
alignItems: "center", lineHeight: 1.15,
justifyContent: "space-between", marginTop: 24,
zIndex: 1, maxHeight: 320,
}} overflow: "hidden",
> }}
<div style={{ fontSize: 24, color: textSecondary, display: "flex" }}> >
{count} {title}
</div> </div>
<div style={{ fontSize: 22, color: accent, fontWeight: 700 }}>
prabhupadasays.org {description ? (
<div
style={{
display: "flex",
fontSize: 28,
color: textSecondary,
lineHeight: 1.4,
marginTop: 24,
maxHeight: 120,
overflow: "hidden",
}}
>
{description}
</div>
) : null}
<div style={{ flex: 1, display: "flex" }} />
{/* Footer: count + branding */}
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<div style={{ fontSize: 24, color: textSecondary, display: "flex" }}>
{count}
</div>
<div style={{ fontSize: 22, color: accent, fontWeight: 700 }}>
prabhupadasays.org
</div>
</div> </div>
</div> </div>
</div> </div>
+14 -1
View File
@@ -102,7 +102,6 @@ export async function GET(
backgroundColor: hasImage ? "#1a1410" : "#faf5f0", backgroundColor: hasImage ? "#1a1410" : "#faf5f0",
fontFamily: "Noto Sans, sans-serif", fontFamily: "Noto Sans, sans-serif",
position: "relative", position: "relative",
padding: 80,
}} }}
> >
{/* Background image + dimming overlay */} {/* Background image + dimming overlay */}
@@ -138,6 +137,19 @@ export async function GET(
</> </>
) : null} ) : null}
{/* Content layer — holds the padding so the bg image stays
full-bleed (absolute children measure from the padding box, so
padding on the root would inset the image and show a strip). */}
<div
style={{
position: "relative",
zIndex: 1,
flex: 1,
display: "flex",
flexDirection: "column",
padding: 80,
}}
>
{/* Caption — the centrepiece */} {/* Caption — the centrepiece */}
<div <div
style={{ style={{
@@ -254,6 +266,7 @@ export async function GET(
prabhupadasays.org prabhupadasays.org
</div> </div>
</div> </div>
</div>
</div> </div>
), ),
{ {
+53 -22
View File
@@ -152,29 +152,60 @@ export function PostCardMenu({
// Copy the post's caption + source citation + a (short) link to the post — // Copy the post's caption + source citation + a (short) link to the post —
// the same payload the share sheet / footer produce. Available to every // the same payload the share sheet / footer produce. Available to every
// viewer. // viewer.
async function copyCaption() { // Build the copy payload — caption + citation + a short link to the post.
setOpen(false); // The short link is a network round-trip, so we must NOT await it before
try { // touching the clipboard or we lose the click's transient user activation
const origin = window.location.origin; // (the write then fails on the first click and only lands on the second,
let url = ""; // once the link is cached). See `useCopyFeedback` for the same fix.
if (authorHandle) { async function buildCaptionText(): Promise<string> {
const longPath = `/u/${encodeURIComponent(authorHandle)}/posts#post-${post.id}`; const origin = window.location.origin;
const code = await createShortLink(longPath); let url = "";
url = code if (authorHandle) {
? new URL(`/share/${code}`, origin).toString() const longPath = `/u/${encodeURIComponent(authorHandle)}/posts#post-${post.id}`;
: new URL(longPath, origin).toString(); const code = await createShortLink(longPath);
} url = code
const ref = structuredReferenceForPost(post.source_url, post.source_title); ? new URL(`/share/${code}`, origin).toString()
const lines: string[] = []; : new URL(longPath, origin).toString();
if (post.caption) lines.push(`“${post.caption}”`, "");
lines.push("Source:", ref.title);
if (ref.detail) lines.push(ref.detail);
if (url) lines.push(url);
await navigator.clipboard.writeText(lines.join("\n"));
toast.success("Caption copied");
} catch {
toast.error("Could not copy");
} }
const ref = structuredReferenceForPost(post.source_url, post.source_title);
const lines: string[] = [];
if (post.caption) lines.push(`“${post.caption}”`, "");
lines.push("Source:", ref.title);
if (ref.detail) lines.push(ref.detail);
if (url) lines.push(url);
return lines.join("\n");
}
function copyCaption() {
setOpen(false);
// Hand the clipboard a *Promise* of the text via ClipboardItem so the
// browser keeps the gesture alive while the short link resolves — one
// click copies cleanly.
if (typeof ClipboardItem !== "undefined" && navigator.clipboard?.write) {
try {
const item = new ClipboardItem({
"text/plain": buildCaptionText().then(
(s) => new Blob([s], { type: "text/plain" }),
),
});
navigator.clipboard.write([item]).then(
() => toast.success("Caption copied"),
() => toast.error("Could not copy"),
);
return;
} catch {
// ClipboardItem-with-promise unsupported → fall through to the
// await + writeText path below.
}
}
void buildCaptionText().then(async (text) => {
try {
await navigator.clipboard.writeText(text);
toast.success("Caption copied");
} catch {
toast.error("Could not copy");
}
});
} }
// Build the items list AFTER all hooks have run so a conditional // Build the items list AFTER all hooks have run so a conditional