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