text highlight and og image

This commit is contained in:
gosangam
2026-05-06 00:40:24 +05:30
parent 237840148f
commit 0a82a12580
16 changed files with 1611 additions and 890 deletions
+218
View File
@@ -0,0 +1,218 @@
import { ImageResponse } from "next/og";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
export const runtime = "nodejs";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const title = searchParams.get("title") || "Prabhupāda Says";
const detail = searchParams.get("detail") || "";
const quote = searchParams.get("quote") || "";
// Truncate for readability and to prevent overflow
const displayTitle = title.length > 60 ? title.slice(0, 57) + "..." : title;
const displayDetail =
detail.length > 80 ? detail.slice(0, 77) + "..." : detail;
const displayQuote = quote.length > 220 ? quote.slice(0, 217) + "..." : quote;
// Load the Prabhupāda image as base64
const imgData = await readFile(
join(process.cwd(), "public/images/og-left-prabhupada-reading.png"),
"base64",
);
const imgSrc = `data:image/png;base64,${imgData}`;
return new ImageResponse(
<div
style={{
width: "1200",
height: "630",
display: "flex",
flexDirection: "row",
backgroundColor: "#faf5f0",
fontFamily: "sans-serif",
overflow: "hidden",
position: "relative",
}}
>
{/* Left side — image + branding */}
<div
style={{
width: "460",
height: "630",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "flex-end",
position: "relative",
flexShrink: 0,
}}
>
{/* Decorative quote mark */}
<div
style={{
position: "absolute",
top: "30",
left: "30",
fontSize: "180",
fontWeight: "900",
color: "#e8b4b8",
lineHeight: "1",
display: "flex",
}}
>
&#x201C;
</div>
{/* Prabhupāda image */}
<img
src={imgSrc}
width="420"
height="500"
style={{
objectFit: "contain",
objectPosition: "bottom",
marginBottom: "0",
}}
/>
{/* Branding at the bottom */}
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
paddingBottom: "24",
marginTop: "-10",
}}
>
<span
style={{
fontSize: "36",
color: "#d4929a",
fontStyle: "italic",
fontWeight: "600",
}}
>
Prabhupāda
</span>
<span
style={{
fontSize: "20",
color: "#d4929a",
fontWeight: "700",
letterSpacing: "2",
marginTop: "-2",
}}
>
says
</span>
</div>
</div>
{/* Right side — content */}
<div
style={{
flex: "1",
display: "flex",
flexDirection: "column",
justifyContent: "center",
padding: "50 60 50 30",
gap: "16",
}}
>
{/* Title */}
<div
style={{
fontSize: "44",
fontWeight: "800",
color: "#2d2418",
lineHeight: "1.15",
display: "flex",
overflow: "hidden",
maxHeight: "102",
}}
>
{displayTitle}
</div>
{/* Detail (chapter, verse, etc.) */}
{displayDetail && (
<div
style={{
fontSize: "22",
fontWeight: "600",
color: "#5a4a3a",
lineHeight: "1.3",
display: "flex",
overflow: "hidden",
maxHeight: "30",
}}
>
{displayDetail}
</div>
)}
{/* Quote text */}
{displayQuote && (
<div
style={{
display: "flex",
flexDirection: "column",
marginTop: "16",
overflow: "hidden",
maxHeight: "180",
}}
>
<div
style={{
fontSize: "24",
color: "#3d3228",
lineHeight: "1.5",
display: "flex",
overflow: "hidden",
}}
>
{displayQuote}
</div>
</div>
)}
{/* Read more */}
<div
style={{
display: "flex",
alignItems: "center",
gap: "6",
marginTop: "16",
}}
>
<span
style={{
fontSize: "18",
fontWeight: "700",
color: "#5a4a3a",
}}
>
Read more at
</span>
<span
style={{
fontSize: "18",
fontWeight: "700",
color: "#c47a5a",
}}
>
prabhupadasays.org
</span>
</div>
</div>
</div>,
{
width: 1200,
height: 630,
},
);
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

+7
View File
@@ -1,9 +1,12 @@
import type { Metadata } from "next";
import { Suspense } from "react";
import { Geist, Geist_Mono } from "next/font/google";
import { ogDefault } from "@/lib/og";
import { ThemeProvider } from "@/components/theme-provider";
import { TooltipProvider } from "@/components/ui/tooltip";
import { SiteFooter } from "@/components/site-footer";
import { TextSelectionToolbar } from "@/components/text-selection-toolbar";
import { TextHighlighter } from "@/components/text-highlighter";
import "./globals.css";
const geistSans = Geist({
@@ -20,6 +23,7 @@ export const metadata: Metadata = {
title: "Prabhupāda Says",
description:
"Browse the books and teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda",
...ogDefault(),
};
export default function RootLayout({
@@ -43,6 +47,9 @@ export default function RootLayout({
<TooltipProvider>
{children}
<TextSelectionToolbar />
<Suspense fallback={null}>
<TextHighlighter />
</Suspense>
<SiteFooter />
</TooltipProvider>
</ThemeProvider>
+15
View File
@@ -1,14 +1,29 @@
export const dynamic = "force-dynamic";
import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getLetter, getAdjacentLetters } from "@/lib/letters";
import { ogForLetter } from "@/lib/og";
import { PageHeader } from "@/components/page-header";
import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { cn } from "@/lib/utils";
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;
const letter = await getLetter(slug);
if (!letter) return {};
const meta = [letter.date, letter.location].filter(Boolean).join(" · ");
return ogForLetter(letter.recipientDisplay, meta || undefined);
}
export default async function LetterPage({
params,
}: {