@taprootio/rollup-plugin-taproot
Version:
Simple static site generation
137 lines (115 loc) • 4.12 kB
text/typescript
import { cloneable } from "./helpers.ts/cloneable"
import { PageData } from "./models/TaprootPageRenderer"
import { Author, Publisher } from "./models/TaprootPluginOptions"
interface SocialImage {
Url: string
Width: number
Height: number
MediaType: string
}
interface HeadData extends Omit<PageData, "Author"> {
Author?: Author
CharSet?: string
Locale?: string
NoRobots?: boolean
PageType?: string
Publisher: Publisher
SocialImage: SocialImage
}
// NOTE: Flash of unstyled content can happen when resources,
// such as fonts and other styles, are loaded after
// initial render. This waits for things to load before
// showing the page. Template body needs an initial
// class of "loading" for it to work.
const FUCFix = [
`<style>
body {
transition: opacity ease-in 500ms;
}
body.loading {
opacity: 0;
}
body.loading.loaded {
opacity: 100;
}
</style>`,
`<script type="text/javascript">
window.onload = () => {
document.body.classList.add("loaded")
}
</script>`,
]
const BuildHead = (data: HeadData): string => {
if (!data.Canonical) {
throw "No canonical specified"
}
// Clone it so any changes made here do not bubble up.
data = cloneable.deepCopy(data)
console.log(JSON.stringify(data))
data.Canonical = data.Canonical?.replace("index.html", "")
data.CharSet = data.CharSet ?? "UTF-8"
data.Locale = data.Locale ?? "en_US"
data.PageType = data.PageType?.toLowerCase() ?? "article"
if (!data.Title) {
throw `No title for ${data.Canonical}`
}
if (!data.Description) {
throw `No description for ${data.Canonical}`
}
const validPageTypes = ["article", "website"]
if (validPageTypes.indexOf(data.PageType) < 0) {
throw `Invalid page type for ${data.Canonical}`
}
if (data.PageType == "article" && !data.Author) {
throw `Article must have an author for ${data.Canonical}`
}
const tags = [
`<meta charset="${data.CharSet}" />`,
`<meta name="viewport" content="width=device-width, initial-scale=1" />`,
]
if (!data.NoRobots) {
tags.push(
`<meta name="robots" content="index, follow, max-image-preview:large" />`
)
}
tags.push(...FUCFix)
tags.push(
`<title>${data.Title} → ${data.Publisher.Name}</title>`,
`<meta name="description" content="${data.Description}" />`,
`<link rel="canonical" href="${data.Canonical}" />`,
`<meta property="og:locale" content="${data.Locale}" />`,
`<meta property="og:type" content="${data.PageType}" />`,
`<meta property="og:title" content="${data.Title}" />`,
`<meta property="og:description" content="${data.Description}" />`,
`<meta property="og:url" content="${data.Canonical}" />`,
`<meta property="og:site_name" content="${data.Publisher.Name}" />`,
`<meta property="article:publisher" content="${data.Publisher.FacebookPage}" />`,
`<meta property="og:image" content="${data.SocialImage.Url}" />`,
`<meta property="og:image:width" content="${data.SocialImage.Width}" />`,
`<meta property="og:image:height" content="${data.SocialImage.Height}" />`,
`<meta property="og:image:type" content="${data.SocialImage.MediaType}" />`, // e.g. "image/png"
`<meta name="twitter:card" content="summary_large_image" />`,
`<meta name="twitter:site" content="${data.Publisher.TwitterHandle}" />`
)
if (data.DatePublished) {
tags.push(
`<meta property="article:published_time" content="${data.DatePublished}" />`
)
}
if (data.DateModified) {
tags.push(
`<meta property="article:modified_time" content="${data.DateModified}" />`
)
}
if (data.Author) {
tags.push(
`<meta property="article:author" content="${data.Author.FacebookPage}" />`,
`<meta name="author" content="${data.Author.Name}" />`,
`<meta name="twitter:creator" content="${data.Author.TwitterHandle}" />`,
`<meta name="twitter:label1" content="Written by" />`,
`<meta name="twitter:data1" content="${data.Author.Name}" />`
)
}
return tags.join("\n")
}
export { BuildHead, type HeadData, type SocialImage }