redirecter for ao3 that adds opengraph metadata
1import { ImageResponse } from "next/og"
2import General from "@/icons/general.js"
3import Teen from "@/icons/teen.js"
4import Mature from "@/icons/mature.js"
5import Explicit from "@/icons/explicit.js"
6import NotRated from "@/icons/notrated.js"
7import Gen from "@/icons/gen.js"
8import Yaoi from "@/icons/yaoi.js"
9import Yuri from "@/icons/yuri.js"
10import Het from "@/icons/het.js"
11import OtherShip from "@/icons/other.js"
12import MultiShip from "@/icons/multi.js"
13import NoWarnings from "@/icons/nowarnings.js"
14import Warnings from "@/icons/warnings.js"
15import ChoseNotToWarn from "@/icons/chosenottowarn.js"
16
17export default async function OGImage ({ theme, baseFont, titleFont, image, addr, opts }) {
18 console.log(image)
19 return new ImageResponse(
20 (
21 <div
22 style={{
23 display: "flex",
24 flexDirection: "column",
25 color: theme.color,
26 backgroundColor: theme.background,
27 fontFamily: baseFont,
28 fontSize: 24,
29 padding: 20,
30 width: "100%",
31 height: "100%",
32 }}
33 >
34 <div
35 style={{
36 display: "flex",
37 flexDirection: "column",
38 marginBottom: 20
39 }}
40 >
41 <div
42 style={{
43 textTransform: "uppercase",
44 display: "flex",
45 justifyContent: "center",
46 color: theme.accent,
47 alignItems: "center",
48 display: "flex",
49 justifyContent: "center",
50 alignItems: "center",
51 textAlign: "center"
52 }}
53 >
54 {image.topLine}
55 </div>
56 <div
57 style={{
58 display: "flex",
59 justifyContent: "center",
60 alignItems: "center",
61 gap: 10
62 }}
63 >
64 {image.props.rating && image.rating === 'E' && (<Explicit fg={theme.accentColor} bg={theme.accent} width={28} height={28} />)}
65 {image.props.rating && image.rating === 'M' && (<Mature fg={theme.accentColor} bg={theme.accent} width={28} height={28} />)}
66 {image.props.rating && image.rating === 'T' && (<Teen fg={theme.accentColor} bg={theme.accent} width={28} height={28} />)}
67 {image.props.rating && image.rating === 'G' && (<General fg={theme.accentColor} bg={theme.accent} width={28} height={28} />)}
68 {image.props.rating && image.rating === 'NR' && (<NotRated fg={theme.accentColor} bg={theme.accent} width={28} height={28} />)}
69
70 {image.props.warnings && image.warning === 'NW' && (<NoWarnings fg={theme.accent2Color} bg={theme.accent2} width={28} height={28} />)}
71 {image.props.warnings && image.warning === 'CNTW' && (<ChoseNotToWarn fg={theme.accent2Color} bg={theme.accent2} width={28} height={28} />)}
72 {image.props.warnings && image.warning === 'W' && (<Warnings fg={theme.accent2Color} bg={theme.accent2} width={28} height={28} />)}
73
74 {image.props.category && image.category === 'F' && (<Yuri fg={theme.accent3Color} bg={theme.accent3} width={28} height={28} />)}
75 {image.props.category && image.category === 'M' && (<Yaoi fg={theme.accent3Color} bg={theme.accent3} width={28} height={28} />)}
76 {image.props.category && image.category === 'FM' && (<Het fg={theme.accent3Color} bg={theme.accent3} width={28} height={28} />)}
77 {image.props.category && image.category === 'G' && (<Gen fg={theme.accent3Color} bg={theme.accent3} width={28} height={28} />)}
78 {image.props.category && image.category === 'MX' && (<MultiShip fg={theme.accent3Color} bg={theme.accent3} width={28} height={28} />)}
79 {image.props.category && image.category === 'O' && (<OtherShip fg={theme.accent3Color} bg={theme.accent3} width={28} height={28} />)}
80 </div>
81 <div
82 style={{
83 fontSize: 54,
84 justifyContent: "center",
85 textAlign: "center",
86 fontFamily: titleFont,
87 fontWeight: "bold",
88 color: theme.color,
89 textTransform: (image.props.uppercaseTitle ? 'uppercase' : 'none')
90 }}
91 >
92 {image.titleLine}
93 </div>
94 <div
95 style={{
96 fontSize: 42,
97 display: "flex",
98 justifyContent: "center",
99 fontFamily: titleFont,
100 color: theme.color
101 }}
102 >
103 {`by ${image.authorLine}`}
104 </div>
105 {image.chapterLine !== '' && (<div
106 style={{
107 fontStyle: "italic",
108 fontSize: 36,
109 fontFamily: titleFont,
110 display: "flex",
111 justifyContent: "center",
112 color: theme.color,
113 textTransform: (image.props.uppercaseChapterName ? 'uppercase' : 'none')
114 }}
115 >
116 {image.chapterLine}
117 </div>)}
118 </div>
119 <div
120 style={{
121 backgroundColor: theme.descBackground,
122 padding: 20,
123 display: "flex",
124 flexDirection: "column",
125 flexGrow: 1,
126 color: theme.descColor,
127 alignItems: "flex-end"
128 }}
129 >
130 {image.props.charTags && (<div
131 style={{
132 display: "flex",
133 flexWrap: "wrap",
134 gap: 5,
135 fontSize: 18,
136 width: "100%",
137 marginBottom: 5
138 }}
139 >
140 {image.charTags.map(c => (
141 <span
142 style={{
143 backgroundColor: theme.accent2,
144 color: theme.accent2Color,
145 padding: "3px 5px",
146 borderRadius: 5
147 }}
148 >
149 {c}
150 </span>
151 ))}
152 </div>)}
153 {image.props.relTags && (<div
154 style={{
155 display: "flex",
156 flexWrap: "wrap",
157 gap: 5,
158 fontSize: 18,
159 width: "100%",
160 marginBottom: 5
161 }}
162 >
163 {image.relTags.map(r => (
164 <span
165 style={{
166 backgroundColor: theme.accent3,
167 color: theme.accent3Color,
168 padding: "3px 5px",
169 borderRadius: 5
170 }}
171 >
172 {r}
173 </span>
174 ))}
175 </div>)}
176 {image.props.freeTags && (<div
177 style={{
178 display: "flex",
179 flexWrap: "wrap",
180 gap: 5,
181 fontSize: 18,
182 width: "100%",
183 marginBottom: 5
184 }}
185 >
186 {image.freeTags.map(f => (
187 <span
188 style={{
189 backgroundColor: theme.accent4,
190 color: theme.accent4Color,
191 padding: "3px 5px",
192 borderRadius: 5
193 }}
194 >
195 {f}
196 </span>
197 ))}
198 </div>)}
199 {image.props.summary && (<div
200 style={{
201 display: "flex",
202 flexDirection: "column",
203 flexGrow: 1,
204 width: '100%'
205 }}
206 >
207 {image.summary.map(l => (
208 <div
209 style={{
210 width: "100%",
211 marginBottom: 10
212 }}
213 >
214 {l}
215 </div>
216 ))}
217 </div>)}
218 <div
219 style={{
220 textAlign: "right",
221 fontSize: 18,
222 display: "flex",
223 justifyContent: "flex-end",
224 alignItems: "center",
225 color: theme.accent2
226 }}
227 >
228 {image.props.wordcount && `${image.words} words • `}{(image.props.chapters && image.chapterCount !== null) && `${image.chapterCount} chapters • `}{image.props.postedAt && `posted on ${image.postedAt} • `}{image.props.updatedAt && `updated on ${image.updatedAt} • `}{addr}
229 </div>
230 </div>
231 </div>
232 ),
233 opts
234 )
235}