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