228 lines
6.2 KiB
TypeScript
228 lines
6.2 KiB
TypeScript
import { ImageResponse } from "next/og";
|
|
import { tripService } from "@/server/services/trip.service";
|
|
import { formatRupiah } from "@/lib/utils";
|
|
import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates";
|
|
import { siteConfig } from "@/lib/site";
|
|
|
|
export const alt = `${siteConfig.name} — Open Trip & Aktivitas Bareng`;
|
|
export const size = { width: 1200, height: 630 };
|
|
export const contentType = "image/png";
|
|
|
|
export default async function TripOgImage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ id: string }>;
|
|
}) {
|
|
const { id } = await params;
|
|
|
|
let trip;
|
|
try {
|
|
trip = await tripService.getTripById(id);
|
|
} catch {
|
|
return new ImageResponse(
|
|
(
|
|
<div
|
|
style={{
|
|
width: "100%",
|
|
height: "100%",
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
background:
|
|
"linear-gradient(135deg, #14532d 0%, #16a34a 60%, #0c4a6e 100%)",
|
|
color: "white",
|
|
fontSize: 96,
|
|
fontWeight: 800,
|
|
letterSpacing: -2,
|
|
}}
|
|
>
|
|
{siteConfig.name}
|
|
</div>
|
|
),
|
|
{ ...size }
|
|
);
|
|
}
|
|
|
|
const cover = trip.images[0]?.url;
|
|
const dateLabel = formatTripCalendarDateRangeLong(trip.date, trip.endDate);
|
|
const price = formatRupiah(trip.price);
|
|
|
|
return new ImageResponse(
|
|
(
|
|
<div
|
|
style={{
|
|
width: "100%",
|
|
height: "100%",
|
|
display: "flex",
|
|
position: "relative",
|
|
background: "#0a0a0a",
|
|
color: "white",
|
|
fontFamily: "sans-serif",
|
|
}}
|
|
>
|
|
{cover && (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img
|
|
src={cover}
|
|
alt=""
|
|
width={1200}
|
|
height={630}
|
|
style={{
|
|
position: "absolute",
|
|
top: 0,
|
|
left: 0,
|
|
width: "100%",
|
|
height: "100%",
|
|
objectFit: "cover",
|
|
filter: "brightness(0.45) saturate(1.05)",
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
<div
|
|
style={{
|
|
position: "absolute",
|
|
inset: 0,
|
|
background:
|
|
"linear-gradient(135deg, rgba(20,83,45,0.88) 0%, rgba(10,10,10,0.5) 55%, rgba(12,74,110,0.85) 100%)",
|
|
display: "flex",
|
|
}}
|
|
/>
|
|
|
|
<div
|
|
style={{
|
|
position: "relative",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
justifyContent: "space-between",
|
|
padding: 64,
|
|
width: "100%",
|
|
height: "100%",
|
|
}}
|
|
>
|
|
{/* Top: brand badge */}
|
|
<div style={{ display: "flex", alignItems: "center", gap: 14 }}>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 10,
|
|
background: "rgba(22,163,74,0.25)",
|
|
border: "1px solid rgba(74,222,128,0.45)",
|
|
borderRadius: 999,
|
|
padding: "10px 22px",
|
|
fontSize: 24,
|
|
fontWeight: 600,
|
|
color: "#86efac",
|
|
}}
|
|
>
|
|
<span style={{ fontSize: 28 }}>🤝</span>
|
|
<span>Open Trip Bareng</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Middle: title + mountain */}
|
|
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
|
<div
|
|
style={{
|
|
fontSize: trip.title.length > 40 ? 64 : 76,
|
|
fontWeight: 800,
|
|
letterSpacing: -2,
|
|
lineHeight: 1.05,
|
|
display: "flex",
|
|
maxWidth: 1050,
|
|
}}
|
|
>
|
|
{trip.title}
|
|
</div>
|
|
<div
|
|
style={{
|
|
fontSize: 32,
|
|
color: "#bbf7d0",
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 10,
|
|
}}
|
|
>
|
|
<span>📍</span>
|
|
<span>
|
|
{trip.mountain} · {trip.location}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom: date / price / brand */}
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "flex-end",
|
|
justifyContent: "space-between",
|
|
gap: 32,
|
|
}}
|
|
>
|
|
<div style={{ display: "flex", flexDirection: "column", gap: 22 }}>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: 16,
|
|
fontSize: 26,
|
|
color: "#e0f2fe",
|
|
}}
|
|
>
|
|
<span style={{ fontSize: 30 }}>📅</span>
|
|
<span>{dateLabel}</span>
|
|
</div>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "baseline",
|
|
gap: 14,
|
|
}}
|
|
>
|
|
<span style={{ fontSize: 22, color: "#86efac" }}>Mulai</span>
|
|
<span
|
|
style={{
|
|
fontSize: 56,
|
|
fontWeight: 800,
|
|
color: "#4ade80",
|
|
letterSpacing: -1,
|
|
}}
|
|
>
|
|
{price}
|
|
</span>
|
|
<span style={{ fontSize: 22, color: "#86efac" }}>/ orang</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "flex-end",
|
|
gap: 6,
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
fontSize: 48,
|
|
fontWeight: 800,
|
|
letterSpacing: -2,
|
|
display: "flex",
|
|
}}
|
|
>
|
|
<span>Se</span>
|
|
<span style={{ color: "#4ade80" }}>Trip</span>
|
|
</div>
|
|
<div style={{ fontSize: 18, color: "#a3a3a3" }}>
|
|
{siteConfig.slogan}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
),
|
|
{ ...size }
|
|
);
|
|
}
|