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}