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