og-image.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { ImageResponse } from "next/og";
  2. import { readFile } from "node:fs/promises";
  3. import { join } from "node:path";
  4. export { getPageTitle } from "@/lib/page-titles";
  5. // Cache font data in memory after first load
  6. let fontCache: { geistRegular: Buffer } | null = null;
  7. async function loadFonts() {
  8. if (fontCache) return fontCache;
  9. const geistRegular = await readFile(
  10. join(process.cwd(), "public/Geist-Regular.ttf"),
  11. );
  12. fontCache = { geistRegular };
  13. return fontCache;
  14. }
  15. export async function renderOgImage(title: string) {
  16. const { geistRegular } = await loadFonts();
  17. return new ImageResponse(
  18. <div
  19. style={{
  20. width: "100%",
  21. height: "100%",
  22. display: "flex",
  23. flexDirection: "column",
  24. backgroundColor: "black",
  25. padding: "60px 80px",
  26. }}
  27. >
  28. <div
  29. style={{
  30. display: "flex",
  31. alignItems: "center",
  32. gap: "16px",
  33. }}
  34. >
  35. <svg width="36" height="36" viewBox="0 0 16 16" fill="white">
  36. <path fillRule="evenodd" clipRule="evenodd" d="M8 1L16 15H0L8 1Z" />
  37. </svg>
  38. <span
  39. style={{
  40. fontSize: 36,
  41. color: "#666",
  42. fontFamily: "Geist",
  43. fontWeight: 400,
  44. }}
  45. >
  46. /
  47. </span>
  48. <span
  49. style={{
  50. fontSize: 36,
  51. fontFamily: "Geist",
  52. fontWeight: 400,
  53. color: "white",
  54. }}
  55. >
  56. json-render
  57. </span>
  58. </div>
  59. <div
  60. style={{
  61. display: "flex",
  62. flex: 1,
  63. flexDirection: "column",
  64. alignItems: "center",
  65. justifyContent: "center",
  66. }}
  67. >
  68. {title.split("\n").map((line, i) => (
  69. <span
  70. key={i}
  71. style={{
  72. fontSize: 72,
  73. fontFamily: "Geist",
  74. fontWeight: 400,
  75. color: "white",
  76. letterSpacing: "-0.02em",
  77. textAlign: "center",
  78. lineHeight: 1.2,
  79. }}
  80. >
  81. {line}
  82. </span>
  83. ))}
  84. </div>
  85. </div>,
  86. {
  87. width: 1200,
  88. height: 630,
  89. fonts: [
  90. {
  91. name: "Geist",
  92. data: geistRegular.buffer as ArrayBuffer,
  93. style: "normal",
  94. weight: 400,
  95. },
  96. ],
  97. },
  98. );
  99. }