redirecter for ao3 that adds opengraph metadata

remove extra copies of files, implement ratings/categories/warnings

-498
src/app/baseFonts.js
···
-
const baseFonts = {
-
opensans: {
-
displayName: 'Open Sans',
-
defs: [
-
{
-
path: '/fonts/OpenSans-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/OpenSans-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/OpenSans-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/OpenSans-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
bricolagegrotesque: {
-
displayName: 'Bricolage Grotesque',
-
defs: [
-
{
-
path: '/fonts/BricolageGrotesque-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/BricolageGrotesque-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
spacemono: {
-
displayName: 'Space Mono',
-
defs: [
-
{
-
path: '/fonts/SpaceMono-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/SpaceMono-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/SpaceMono-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/SpaceMono-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
inconsolata: {
-
displayName: 'Inconsolata',
-
defs: [
-
{
-
path: '/fonts/Inconsolata.otf',
-
style: 'normal'
-
}
-
]
-
},
-
bitter: {
-
displayName: 'Bitter',
-
defs: [
-
{
-
path: '/fonts/Bitter-Regular.otf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Bitter-Italic.otf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Bitter-Bold.otf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Bitter-BoldItalic.otf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
archivo: {
-
displayName: 'Archivo',
-
defs: [
-
{
-
path: '/fonts/Archivo-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Archivo-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Archivo-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Archivo-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
outfit: {
-
displayName: 'Outfit',
-
defs: [
-
{
-
path: '/fonts/outfit-regular-webfont.woff2',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/outfit-italic-webfont.woff2',
-
style: 'italic',
-
weight: 400
-
}
-
]
-
},
-
notosans: {
-
displayName: 'Noto Sans',
-
defs: [
-
{
-
path: '/fonts/NotoSans-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/NotoSans-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/NotoSans-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/NotoSans-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
alegreya: {
-
displayName: 'Alegreya',
-
defs: [
-
{
-
path: '/fonts/Alegreya-Regular.otf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Alegreya-Italic.otf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Alegreya-Bold.otf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Alegreya-BoldItalic.otf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
alegreyasans: {
-
displayName: 'Alegreya Sans',
-
defs: [
-
{
-
path: '/fonts/AlegreyaSans-Regular.otf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/AlegreyaSans-Italic.otf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/AlegreyaSans-Bold.otf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/AlegreyaSans-BoldItalic.otf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
stacksanstext: {
-
displayName: 'Stack Sans Text',
-
defs: [
-
{
-
path: '/fonts/StackSansText-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/StackSansText-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
],
-
},
-
momotrustsans: {
-
displayName: 'Momo Trust Sans',
-
defs: [
-
{
-
path: '/fonts/MomoTrustSans-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/MomoTrustSans-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
montserrat: {
-
displayName: 'Montserrat',
-
defs: [
-
{
-
path: '/fonts/Montserrat-Regular.otf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Montserrat-Italic.otf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Montserrat-Bold.otf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Montserrat-BoldItalic.otf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
robotoslab: {
-
displayName: 'Roboto Slab',
-
defs: [
-
{
-
path: '/fonts/RobotoSlab-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/RobotoSlab-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
quicksand: {
-
displayName: 'Quicksand',
-
defs: [
-
{
-
path: '/fonts/Quicksand-Regular.otf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Quicksand-Italic.otf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Quicksand-Bold.otf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Quicksand-BoldItalic.otf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
worksans: {
-
displayName: 'Work Sans',
-
defs: [
-
{
-
path: '/fonts/WorkSans-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/WorkSans-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/WorkSans-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/WorkSans-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
notosans: {
-
displayName: 'Noto Sans',
-
defs: [
-
{
-
path: '/fonts/NotoSans-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/NotoSans-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/NotoSans-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/NotoSans-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
notoserif: {
-
displayName: 'Noto Serif',
-
defs: [
-
{
-
path: '/fonts/NotoSerif-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/NotoSerif-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/NotoSerif-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/NotoSerif-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
librebaskerville: {
-
displayName: 'Libre Baskerville',
-
defs: [
-
{
-
path: '/fonts/LibreBaskerville-Regular.otf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/LibreBaskerville-Italic.otf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/LibreBaskerville-Bold.otf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
ubuntu: {
-
displayName: 'Ubuntu',
-
defs: [
-
{
-
path: '/fonts/Ubuntu-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Ubuntu-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Ubuntu-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Ubuntu-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
parkinsans: {
-
displayName: 'Parkinsans',
-
defs: [
-
{
-
path: '/fonts/Parkinsans-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Parkinsans-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
lora: {
-
displayName: 'Lora',
-
defs: [
-
{
-
path: '/fonts/Lora-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Lora-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Lora-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Lora-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
josefinsans: {
-
displayName: 'Josefin Sans',
-
defs: [
-
{
-
path: '/fonts/JosefinSans-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/JosefinSans-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/JosefinSans-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/JosefinSans-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
}
-
}
-
-
export default baseFonts
+4 -4
src/app/generator/page.js
···
"use client"
import { useEffect, useState } from "react"
-
import themes from "./themes.js"
-
import baseFonts from "../baseFonts.js"
-
import titleFonts from "../titleFonts.js"
+
import themes from "@/lib/themes.js"
+
import baseFonts from "@/lib/baseFonts.js"
+
import titleFonts from "@/lib/titleFonts.js"
import styles from "./page.module.css"
export default function Generator() {
···
<li><label><input type="checkbox" name="features[]" value="warnings" defaultChecked={props.warnings} onChange={e => updateProp(e.target.value, e.target.checked)} /> Archive Warnings</label></li>
<li><label><input type="checkbox" name="features[]" value="charTags" defaultChecked={props.charTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Character Tags</label></li>
<li><label><input type="checkbox" name="features[]" value="relTags" defaultChecked={props.relTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Relationship Tags</label></li>
-
<li><label><input type="checkbox" name="features[]" value="freetags" defaultChecked={props.freeTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Free Tags</label></li>
+
<li><label><input type="checkbox" name="features[]" value="freeTags" defaultChecked={props.freeTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Free Tags</label></li>
<li><label><input type="checkbox" name="features[]" value="summary" defaultChecked={props.summary} onChange={e => updateProp(e.target.value, e.target.checked)} /> Summary</label></li>
<li><label><input type="checkbox" name="features[]" value="wordcount" defaultChecked={props.wordcount} onChange={e => updateProp(e.target.value, e.target.checked)} /> Wordcount</label></li>
<li><label><input type="checkbox" name="features[]" value="chapters" defaultChecked={props.chapters} onChange={e => updateProp(e.target.value, e.target.checked)} /> Chapters</label></li>
+3 -2
src/app/layout.js
···
export const metadata = {
title: process.env.SITENAME,
-
description: process.env.DESCRIPTION,
-
viewport: "width=device-width, initial-scale=1.0"
+
description: process.env.DESCRIPTION
};
+
+
export const viewport = "width=device-width, initial-scale=1.0"
export default function RootLayout({ children }) {
return (
-94
src/app/themes.js
···
-
const themes = {
-
ao3: {
-
name: 'AO3',
-
background: '#990000',
-
color: '#FFFFFF',
-
descBackground: '#FFFFFF',
-
descColor: '#000000',
-
accent: '#FFFFFF',
-
accent2: '#990000'
-
},
-
softEra: {
-
name: 'Soft Era',
-
background: '#F9F5F5',
-
color: '#C8B3B3',
-
descBackground: '#F9F5F5',
-
descColor: '#414141',
-
accent: '#DB90A7',
-
accent2: '#EEAABE'
-
},
-
wildCherry: {
-
name: 'Wild Cherry',
-
background: '#2B1F32',
-
color: '#FFFFFF',
-
descBackground: '#FFFFFF',
-
descColor: '#2B1F32',
-
accent: '#E15D97',
-
accent2: '#0AACC5'
-
},
-
rosePine: {
-
name: 'Rosé Pine',
-
background: '#191724',
-
color: '#e0def4',
-
descBackground: '#1f1d2e',
-
descColor: '#e0def4',
-
accent: '#eb6f92',
-
accent2: '#31748f'
-
},
-
rosePineDawn: {
-
name: 'Rosé Pine Dawn',
-
background: '#faf4ed',
-
color: '#575279',
-
descBackground: '#fffaf3',
-
descColor: '#575279',
-
accent: '#eb6f92',
-
accent2: '#286983'
-
},
-
rosePineMoon: {
-
name: 'Rosé Pine Moon',
-
background: '#232136',
-
color: '#e0def4',
-
descBackground: '#2a273f',
-
descColor: '#e0def4',
-
accent: '#b4637a',
-
accent2: '#3e8fb0'
-
},
-
solarizedLight: {
-
name: 'Solarized Light',
-
background: '#fdf6e3',
-
color: '#b58900',
-
descBackground: '#eee8d5',
-
descColor: '#002b36',
-
accent: '#d33682',
-
accent2: '#2aa198'
-
},
-
solarizedDark: {
-
name: 'Solarized Dark',
-
background: '#002b36',
-
color: '#b58900',
-
descBackground: '#073642',
-
descColor: '#fdf6e3',
-
accent: '#d33682',
-
accent2: '#2aa198'
-
},
-
squidgeworld: {
-
name: 'Squidgeworld',
-
background: '#b8860b',
-
color: '#f5f5dc',
-
descBackground: '#f5f5dc',
-
color: '#2a2a2a',
-
accent: '#fece3f',
-
accent2: '#818D4C'
-
},
-
superlove: {
-
name: 'Superlove',
-
background: '#df6191',
-
color: '#ffffff',
-
descBackground: '#FFFFFF',
-
color: '#2a2a2a',
-
accent: '#F9E4E6',
-
accent2: '#a33961'
-
}
-
}
-
-
export default themes
-226
src/app/titleFonts.js
···
-
import baseFonts from "./baseFonts.js"
-
-
const titleFonts = {
-
...baseFonts,
-
playfairdisplay: {
-
displayName: 'Playfair Display',
-
defs: [
-
{
-
path: '/fonts/Playfair-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Playfair-Italic.ttf',
-
style: 'italic',
-
weight: 400
-
},
-
{
-
path: '/fonts/Playfair-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
},
-
{
-
path: '/fonts/Playfair-BoldItalic.ttf',
-
style: 'italic',
-
weight: 700
-
}
-
]
-
},
-
ultra: {
-
displayName: 'Ultra',
-
defs: [
-
{
-
path: '/fonts/Ultra-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
stacksansheadline: {
-
displayName: 'Stack Sans Headline',
-
defs: [
-
{
-
path: '/fonts/StackSansHeadline-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/StackSansHeadline-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
stacksansnotch: {
-
displayName: 'Stack Sans Notch',
-
defs: [
-
{
-
path: '/fonts/StackSansNotch-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/StackSansNotch-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
titanone: {
-
displayName: 'Titan One',
-
defs: []
-
},
-
momotrustdisplay: {
-
displayName: 'Momo Trust Display',
-
defs: [
-
{
-
path: '/fonts/MomoTrustDisplay-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/MomoTrustDisplay-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
momosignature: {
-
displayName: 'Momo Signature',
-
defs: [
-
{
-
path: '/fonts/MomoSignature-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
londrinasketch: {
-
displayName: 'Londrina Sketch',
-
defs: [
-
{
-
path: '/fonts/LondrinaSketch-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
londrinashadow: {
-
displayName: 'Londrina Shadow',
-
defs: [
-
{
-
path: '/fonts/LondrinaShadow-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
londrinasolid: {
-
displayName: 'Londrina Solid',
-
defs: [
-
{
-
path: '/fonts/LondrinaSolid-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/LondrinaSolid-Black.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
bebasneue: {
-
displayName: 'Bebas Neue',
-
defs: [
-
{
-
path: '/fonts/BebasNeue-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
oswald: {
-
displayName: 'Oswald',
-
defs: [
-
{
-
path: '/fonts/Oswald-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Oswald-Bold.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
archivoblack: {
-
displayName: 'Archivo Black',
-
defs: [
-
{
-
path: '/fonts/ArchivoBlack.otf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
alfaslabone: {
-
displayName: 'Alfa Slab One',
-
defs: [
-
{
-
path: '/fonts/AlfaSlabOne-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
sixtyfour: {
-
displayName: 'SixtyFour',
-
defs: [
-
{
-
path: '/fonts/Sixtyfour-Regular.ttf',
-
style: 'normal',
-
weight: 400
-
},
-
{
-
path: '/fonts/Sixtyfour-Regular.ttf',
-
style: 'normal',
-
weight: 700
-
}
-
]
-
},
-
datalegreyathin: {
-
displayName: 'Datalegreya Thin',
-
defs: [
-
{
-
path: '/fonts/Datalegreya-Thin.otf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
datalegreyadot: {
-
displayName: 'Datalegreya Dot',
-
defs: [
-
{
-
path: '/fonts/Datalegreya-Dot.otf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
},
-
datalegreyagradient: {
-
displayName: 'Datalegreya Gradient',
-
defs: [
-
{
-
path: '/fonts/Datalegreya-Gradient.otf',
-
style: 'normal',
-
weight: 400
-
}
-
]
-
}
-
}
-
-
export default titleFonts
+141 -9
src/lib/ogimage.js
···
backgroundColor: theme.background,
fontFamily: baseFont,
fontSize: 24,
-
padding: 40,
+
padding: 20,
width: "100%",
height: "100%",
}}
···
textTransform: "uppercase",
display: "flex",
justifyContent: "center",
-
color: theme.accent
+
gap: 10,
+
color: theme.accent,
+
alignItems: "stretch"
}}
>
-
{image.topLine}
+
<div
+
style={{
+
display: "flex"
+
}}
+
>
+
{image.topLine}
+
</div>
+
{image.rating && (<div
+
style={{
+
borderRadius: '100%',
+
backgroundColor: theme.accent,
+
color: theme.background,
+
padding: "0 10px",
+
display: "flex",
+
minWidth: 28,
+
justifyContent: "center",
+
alignItems: "center",
+
fontWeight: "bold"
+
}}
+
>
+
{image.rating}
+
</div>)}
+
{image.warnings && (
+
<div
+
style={{
+
borderRadius: '100%',
+
backgroundColor: theme.accent2,
+
color: theme.background,
+
padding: "0 5px",
+
display: "flex",
+
minWidth: 28,
+
justifyContent: "center",
+
alignItems: "center",
+
fontWeight: "bold"
+
}}
+
>
+
{image.warning}
+
</div>
+
)}
+
{image.category && (
+
<div
+
style={{
+
borderRadius: '100%',
+
backgroundColor: theme.accent3,
+
color: theme.background,
+
padding: "0 10px",
+
display: "flex",
+
minWidth: 28,
+
justifyContent: "center",
+
alignItems: "center",
+
fontWeight: "bold"
+
}}
+
>
+
{image.category}
+
</div>
+
)}
</div>
<div
style={{
fontSize: 54,
justifyContent: "center",
fontFamily: titleFont,
-
fontWeight: "bold"
+
fontWeight: "bold",
+
color: theme.color
}}
>
{image.titleLine}
···
fontSize: 42,
display: "flex",
justifyContent: "center",
-
fontFamily: titleFont
+
fontFamily: titleFont,
+
color: theme.color
}}
>
{`by ${image.authorLine}`}
···
fontSize: 36,
fontFamily: titleFont,
display: "flex",
-
justifyContent: "center"
+
justifyContent: "center",
+
color: theme.color
}}
>
{image.chapterLine}
···
alignItems: "flex-end"
}}
>
-
<div
+
{image.props.get("charTags") === 'true' && (<div
+
style={{
+
display: "flex",
+
flexWrap: "wrap",
+
gap: 5,
+
fontSize: 18,
+
width: "100%",
+
marginBottom: 5
+
}}
+
>
+
{image.charTags.map(c => (
+
<span
+
style={{
+
backgroundColor: theme.accent2,
+
color: theme.descBackground,
+
padding: "3px 5px",
+
borderRadius: 5
+
}}
+
>
+
{c}
+
</span>
+
))}
+
</div>)}
+
{image.props.get("relTags") === 'true' && (<div
+
style={{
+
display: "flex",
+
flexWrap: "wrap",
+
gap: 5,
+
fontSize: 18,
+
width: "100%",
+
marginBottom: 5
+
}}
+
>
+
{image.relTags.map(r => (
+
<span
+
style={{
+
backgroundColor: theme.accent3,
+
color: theme.descBackground,
+
padding: "3px 5px",
+
borderRadius: 5
+
}}
+
>
+
{r}
+
</span>
+
))}
+
</div>)}
+
{image.props.get("freeTags") === 'true' && (<div
+
style={{
+
display: "flex",
+
flexWrap: "wrap",
+
gap: 5,
+
fontSize: 18,
+
width: "100%",
+
marginBottom: 5
+
}}
+
>
+
{image.freeTags.map(f => (
+
<span
+
style={{
+
backgroundColor: theme.accent4,
+
color: theme.descBackground,
+
padding: "3px 5px",
+
borderRadius: 5
+
}}
+
>
+
{f}
+
</span>
+
))}
+
</div>)}
+
{image.props.get("summary") === 'true' && (<div
style={{
display: "flex",
flexDirection: "column",
···
{l}
</div>
))}
-
</div>
+
</div>)}
<div
style={{
textAlign: "right",
fontSize: 18,
+
display: "flex",
+
justifyContent: "flex-end",
+
alignItems: "center",
color: theme.accent2
}}
>
-
{`https://archiveofourown.org/${addr}`}
+
{image.props.get("wordcount") === 'true' && `${image.words} words • `}{(image.props.get("chapters") === 'true' && image.chapterCount !== null) && `${image.chapterCount} chapters • `}https://archiveofourown.org/{addr}
</div>
</div>
</div>
+74 -7
src/lib/sanitizeData.js
···
import baseFonts from '@/lib/baseFonts.js'
import titleFonts from '@/lib/titleFonts.js'
+
const getHighestRating = async (works) => {
+
const ratings = await Promise.all(works.map(async (w) => {
+
const work = await getWork({workId: w.id})
+
return work.rating
+
}))
+
if (ratings.includes("Not Rated")) {
+
return "NR"
+
} else if (ratings.includes("Explicit")) {
+
return "E"
+
} else if (ratings.includes("Mature")) {
+
return "M"
+
} else if (ratings.includes("Teen")) {
+
return "T"
+
}
+
return "G"
+
}
+
+
const getHighestWarning = async (works) => {
+
const warnings = await Promise.all(works.map(async (w) => {
+
const work = await getWork({workId: w.id})
+
return work.tags.warnings
+
}))
+
const warningsUnique = warnings.reduce((a, b) => { return a.concat(b) }).filter((w, i) => { return i === warnings.indexOf(w) })
+
if (warningsUnique.length === 1 && warningsUnique[0] === "Creator Chose Not To Use Archive Warnings") {
+
return "⁉️"
+
} else if (warningsUnique.length === 1 && warningsUnique[0] === "No Archive Warnings Apply") {
+
return "⭕️"
+
}
+
return "⚠️"
+
}
+
+
const getCategory = async (works) => {
+
const categories = await Promise.all(works.map(async (w) => {
+
const work = await getWork({workId: w.id})
+
return work.category
+
}))
+
const categoriesUnique = categories.reduce((a, b) => { return a.concat(b) }).filter((w, i) => { return i === categories.indexOf(w) })
+
if (categoriesUnique.length === 1) {
+
if (categoriesUnique[0] === "F/F") return "⚢"
+
if (categoriesUnique[0] === "M/M") return "⚣"
+
if (categoriesUnique[0] === "F/M") return "⚤"
+
if (categoriesUnique[0] === "Gen") return "◦"
+
if (categoriesUnique[0] === "Multi") return "⁕"
+
if (categoriesUnique[0] === "Other") return "⚧"
+
}
+
return "⁕"
+
}
+
export default async function sanitizeData ({ type, data, props}) {
const baseFont = props.has('baseFont') ? props.get('baseFont') : process.env.DEFAULT_BASE_FONT
const baseFontData = baseFonts[baseFont]
···
return a.username
})
: []
+
const rating = type === 'work' ? data.rating : await getHighestRating(data.works)
+
const warning = type === 'work' ? await getHighestWarning([data]) : await getHighestWarning(data.works)
+
const category = type === 'work' ? await getCategory([data]) : await getCategory(data.works)
const authorString = authorsFormatted.length > 1
? authorsFormatted.slice(0, -1).join(", ") + " & " +
authorsFormatted.slice(-1)[0]
···
const summaryContent = type === 'work'
? (props.get('summaryType') === 'chapter' && data.chapterInfo && data.chapterInfo.summary ? data.chapterInfo.summary : (props.get('summaryType') === 'custom' && props.has('customSummary') ? props.get('customSummary') : (data.summary ? data.summary : (parentWork ? parentWork.summary : ''))))
: (props.get('summaryType') === 'custom' && props.has('customSummary') ? props.get('customSummary') : data.notes)
+
const formatter = new Intl.NumberFormat('en-US')
+
const words = formatter.format(data.words)
const summaryDOM = new DOM(summaryContent, {decodeEntities: true});
const summaryFormatted = summaryDOM.innerHTML.replace(/\<br(?: \/)?\>/g, "\n").replace(
/(<([^>]+)>)/ig,
···
const chapterString = data.chapterInfo ? (data.chapterInfo.name
? data.chapterInfo.name
: "Chapter " + data.chapterInfo.index) : null
-
const chapterCountString = data.chapters
-
? ' | <b>Chapters:</b> '+data.chapters.published+' / '+(
+
const chapterCountString = type === 'work' ? (data.chapters
+
? data.chapters.published+'/'+(
data.chapters.total
? data.chapters.total
: '?'
)
-
: ''
+
: '') : null
const fandomString = type === 'work' ? (
data.fandoms.length > 1
? (
-
data.fandoms.length <= 5
+
data.fandoms.length <= 2
? data.fandoms.slice(0, -1).join(", ")+" & "+data.fandoms.slice(-1)
-
: data.fandoms.join(", ")+" (+"+(data.fandoms.length - 4)+")"
+
: data.fandoms.join(", ")+" (+"+(data.fandoms.length - 2)+")"
)
: data.fandoms[0]
) : (
-
data.works.map(w => w.fandoms).reduce((a, b) => { return a.concat(b) }).filter((w, i) => { return i === data.works.indexOf(w) })
+
''
)
+
const charTags = type === 'work' ? data.tags.characters : data.works.map(w => w.tags.characters).reduce((a, b) => { return b ? (a ? a.concat(b) : []) : (a ? a : []) }).filter((w, i) => { return i === data.works.indexOf(w) })
+
const relTags = type === 'work' ? data.tags.relationships : data.works.map(w => w.tags.relationships).reduce((a, b) => { return b ? (a ? a.concat(b) : []) : (a ? a : []) }).filter((w, i) => { return i === data.works.indexOf(w) })
+
const freeTags = type === 'work' ? data.tags.additional : data.works.map(w => w.tags.additional).reduce((a, b) => { return b ? (a ? a.concat(b) : []) : (a ? a : []) }).filter((w, i) => { return i === data.works.indexOf(w) })
+
const warnings = type === 'work' ? data.tags.warnings : data.works.map(w => w.tags.warnings).reduce((a, b) => { return b ? (a ? a.concat(b) : []) : (a ? a : []) }).filter((w, i) => { return i === data.works.indexOf(w) })
+
return {
topLine: fandomString,
titleLine: titleString,
authorLine: authorString,
chapterLine: chapterString,
+
chapterCount: chapterCountString,
+
words: words,
+
rating: rating,
+
warning: warning,
+
category: category,
summary: summaryFormatted,
-
url: 'https://archiveofourown.org/',
theme: themeData,
+
charTags: charTags,
+
relTags: relTags,
+
freeTags: freeTags,
+
warnings: warnings,
baseFont: baseFont,
titleFont: titleFont,
+
props: props,
opts: {
fonts: bfs.concat(tfs)
}
+32 -12
src/lib/themes.js
···
descBackground: '#FFFFFF',
descColor: '#000000',
accent: '#FFFFFF',
-
accent2: '#990000'
+
accent2: '#990000',
+
accent3: '#009900',
+
accent4: '#000099'
},
softEra: {
name: 'Soft Era',
···
descBackground: '#F9F5F5',
descColor: '#414141',
accent: '#DB90A7',
-
accent2: '#EEAABE'
+
accent2: '#EEAABE',
+
accent3: '#82B4E3',
+
accent4: '#a29acb'
},
wildCherry: {
name: 'Wild Cherry',
···
descBackground: '#FFFFFF',
descColor: '#2B1F32',
accent: '#E15D97',
-
accent2: '#0AACC5'
+
accent2: '#0AACC5',
+
accent3: '#FFB86C',
+
accent4: '#35BA66'
},
rosePine: {
name: 'Rosé Pine',
···
descBackground: '#1f1d2e',
descColor: '#e0def4',
accent: '#eb6f92',
-
accent2: '#31748f'
+
accent2: '#31748f',
+
accent3: '#f6c177',
+
accent4: '#c4a7e7'
},
rosePineDawn: {
name: 'Rosé Pine Dawn',
···
descBackground: '#fffaf3',
descColor: '#575279',
accent: '#eb6f92',
-
accent2: '#286983'
+
accent2: '#286983',
+
accent3: '#ea9d34',
+
accent4: '#907aa9'
},
rosePineMoon: {
name: 'Rosé Pine Moon',
···
descBackground: '#2a273f',
descColor: '#e0def4',
accent: '#b4637a',
-
accent2: '#3e8fb0'
+
accent2: '#3e8fb0',
+
accent3: '#f6c177',
+
accent4: '#c4a7e7'
},
solarizedLight: {
name: 'Solarized Light',
···
descBackground: '#eee8d5',
descColor: '#002b36',
accent: '#d33682',
-
accent2: '#2aa198'
+
accent2: '#2aa198',
+
accent3: '#859900',
+
accent4: '#6c71c4'
},
solarizedDark: {
name: 'Solarized Dark',
···
descBackground: '#073642',
descColor: '#fdf6e3',
accent: '#d33682',
-
accent2: '#2aa198'
+
accent2: '#2aa198',
+
accent3: '#859900',
+
accent4: '#6c71c4'
},
squidgeworld: {
name: 'Squidgeworld',
background: '#b8860b',
color: '#f5f5dc',
descBackground: '#f5f5dc',
-
color: '#2a2a2a',
+
descColor: '#2a2a2a',
accent: '#fece3f',
-
accent2: '#818D4C'
+
accent2: '#818D4C',
+
accent3: '#6D7A34',
+
accent4: '#556121'
},
superlove: {
name: 'Superlove',
background: '#df6191',
color: '#ffffff',
descBackground: '#FFFFFF',
-
color: '#2a2a2a',
+
descColor: '#2a2a2a',
accent: '#F9E4E6',
-
accent2: '#a33961'
+
accent2: '#a33961',
+
accent3: '#87254A',
+
accent4: '#6A1133'
}
}