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}