Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei: Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich (Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung, PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma- Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
import { ImageResponse } from "next/og";
|
|
import { getProductBySlug } from "@/lib/data";
|
|
import { formatPrice } from "@/lib/format";
|
|
|
|
export const alt = "Wabenhain Produkt";
|
|
export const size = { width: 1200, height: 630 };
|
|
export const contentType = "image/png";
|
|
|
|
/**
|
|
* Produktspezifisches Social-Preview-Bild statt des generischen
|
|
* Seiten-Fallbacks (app/opengraph-image.tsx) — wer einen Honig-Link teilt,
|
|
* soll den tatsaechlichen Produktnamen und Preis in der Vorschau sehen statt
|
|
* nur des Wabenhain-Markenbilds.
|
|
*/
|
|
export default async function Image({ params }: { params: Promise<{ slug: string }> }) {
|
|
const { slug } = await params;
|
|
const product = await getProductBySlug(slug);
|
|
|
|
const title = product?.name ?? "Wabenhain";
|
|
const tags = product?.tasteTags.slice(0, 3).join(" · ") ?? "";
|
|
const price = product ? formatPrice(product.priceCents, product.currency) : "";
|
|
|
|
return new ImageResponse(
|
|
(
|
|
<div
|
|
style={{
|
|
width: "100%",
|
|
height: "100%",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
background: "linear-gradient(135deg, #1a271f 0%, #24352b 55%, #3a4d3f 100%)",
|
|
padding: "80px",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
fontSize: 20,
|
|
letterSpacing: 6,
|
|
color: "#b88a44",
|
|
marginBottom: 24,
|
|
}}
|
|
>
|
|
WABENHAIN
|
|
</div>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
fontSize: 76,
|
|
letterSpacing: 1,
|
|
color: "#f4efe5",
|
|
textAlign: "center",
|
|
lineHeight: 1.1,
|
|
}}
|
|
>
|
|
{title}
|
|
</div>
|
|
{tags ? (
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
fontSize: 26,
|
|
color: "#f4efe5",
|
|
opacity: 0.7,
|
|
marginTop: 28,
|
|
letterSpacing: 1,
|
|
}}
|
|
>
|
|
{tags}
|
|
</div>
|
|
) : null}
|
|
{price ? (
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
fontSize: 34,
|
|
color: "#b88a44",
|
|
marginTop: 36,
|
|
}}
|
|
>
|
|
{price}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
),
|
|
{ ...size }
|
|
);
|
|
}
|