feat: Wabenhain Honig-Shop Anwendung
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.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
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 }
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user