|
| 1 | +import { readFile } from "node:fs/promises"; |
| 2 | +import { join } from "node:path"; |
1 | 3 | import { ImageResponse } from "next/og"; |
2 | 4 |
|
3 | 5 | export const dynamic = "force-static"; |
4 | 6 | export const size = { width: 1200, height: 630 }; |
5 | 7 | export const contentType = "image/png"; |
6 | 8 | export const alt = "FIRST FLUKE — Make Your First Win"; |
7 | 9 |
|
| 10 | +async function loadMascotDataUrl(): Promise<string> { |
| 11 | + const buf = await readFile( |
| 12 | + join(process.cwd(), "public", "firstfluke-mascot.png"), |
| 13 | + ); |
| 14 | + return `data:image/png;base64,${buf.toString("base64")}`; |
| 15 | +} |
| 16 | + |
8 | 17 | export default async function OpengraphImage() { |
| 18 | + const mascotSrc = await loadMascotDataUrl(); |
| 19 | + |
9 | 20 | return new ImageResponse( |
10 | 21 | ( |
11 | 22 | <div |
12 | 23 | style={{ |
13 | 24 | width: "100%", |
14 | 25 | height: "100%", |
15 | 26 | display: "flex", |
16 | | - flexDirection: "column", |
17 | | - justifyContent: "space-between", |
18 | 27 | padding: "80px", |
19 | 28 | background: |
20 | | - "linear-gradient(135deg, #0f4c3a 0%, #1a6048 50%, #7ab94c 100%)", |
| 29 | + "linear-gradient(135deg, #0f4c3a 0%, #1a6048 55%, #7ab94c 100%)", |
21 | 30 | color: "#fafaf7", |
22 | 31 | fontFamily: "system-ui, sans-serif", |
23 | 32 | }} |
24 | 33 | > |
25 | 34 | <div |
26 | 35 | style={{ |
27 | 36 | display: "flex", |
28 | | - fontSize: 28, |
29 | | - letterSpacing: 4, |
30 | | - opacity: 0.85, |
| 37 | + flexDirection: "column", |
| 38 | + justifyContent: "space-between", |
| 39 | + flex: 1, |
| 40 | + paddingRight: 40, |
31 | 41 | }} |
32 | 42 | > |
33 | | - FIRST FLUKE |
34 | | - </div> |
35 | | - <div style={{ display: "flex", flexDirection: "column", gap: 24 }}> |
36 | 43 | <div |
37 | 44 | style={{ |
38 | | - fontSize: 96, |
39 | | - fontWeight: 700, |
40 | | - lineHeight: 1.05, |
41 | | - letterSpacing: -2, |
| 45 | + display: "flex", |
| 46 | + fontSize: 28, |
| 47 | + letterSpacing: 4, |
| 48 | + opacity: 0.85, |
42 | 49 | }} |
43 | 50 | > |
44 | | - Make Your First Win |
| 51 | + FIRST FLUKE |
| 52 | + </div> |
| 53 | + <div style={{ display: "flex", flexDirection: "column", gap: 20 }}> |
| 54 | + <div |
| 55 | + style={{ |
| 56 | + fontSize: 88, |
| 57 | + fontWeight: 700, |
| 58 | + lineHeight: 1.05, |
| 59 | + letterSpacing: -2, |
| 60 | + }} |
| 61 | + > |
| 62 | + Make Your First Win |
| 63 | + </div> |
| 64 | + <div style={{ fontSize: 32, opacity: 0.9, lineHeight: 1.3 }}> |
| 65 | + AI와 기술로 더 나은 일상을 만드는 팀 |
| 66 | + </div> |
45 | 67 | </div> |
46 | 68 | <div |
47 | 69 | style={{ |
48 | | - fontSize: 36, |
49 | | - opacity: 0.9, |
50 | | - lineHeight: 1.3, |
| 70 | + display: "flex", |
| 71 | + justifyContent: "space-between", |
| 72 | + alignItems: "flex-end", |
| 73 | + fontSize: 22, |
| 74 | + opacity: 0.85, |
51 | 75 | }} |
52 | 76 | > |
53 | | - AI와 기술로 더 나은 일상을 만드는 팀 |
| 77 | + <div style={{ display: "flex" }}>모두의 창업 2026 선정</div> |
| 78 | + <div style={{ display: "flex" }}>firstfluke.com</div> |
54 | 79 | </div> |
55 | 80 | </div> |
56 | 81 | <div |
57 | 82 | style={{ |
58 | 83 | display: "flex", |
59 | | - justifyContent: "space-between", |
60 | | - alignItems: "flex-end", |
61 | | - fontSize: 24, |
62 | | - opacity: 0.85, |
| 84 | + alignItems: "center", |
| 85 | + justifyContent: "center", |
| 86 | + width: 440, |
| 87 | + height: 440, |
63 | 88 | }} |
64 | 89 | > |
65 | | - <div style={{ display: "flex" }}>모두의 창업 2026 선정</div> |
66 | | - <div style={{ display: "flex" }}>firstfluke.com</div> |
| 90 | + {/** biome-ignore lint/performance/noImgElement: ImageResponse only supports img */} |
| 91 | + <img |
| 92 | + src={mascotSrc} |
| 93 | + alt="" |
| 94 | + width={420} |
| 95 | + height={420} |
| 96 | + style={{ |
| 97 | + objectFit: "cover", |
| 98 | + borderRadius: 210, |
| 99 | + background: "#fafaf7", |
| 100 | + boxShadow: "0 24px 60px rgba(0,0,0,0.25)", |
| 101 | + }} |
| 102 | + /> |
67 | 103 | </div> |
68 | 104 | </div> |
69 | 105 | ), |
|
0 commit comments