1
Fork 0
mirror of https://github.com/RGBCube/Site synced 2025-07-29 12:07:47 +00:00
Site/site.ts
2025-06-11 20:12:29 +03:00

254 lines
6.1 KiB
TypeScript

import lume from "lume/mod.ts";
import checkUrls from "lume/plugins/check_urls.ts";
import codeHighlight from "lume/plugins/code_highlight.ts";
import extractDate from "lume/plugins/extract_date.ts";
import feed from "lume/plugins/feed.ts";
import inline from "lume/plugins/inline.ts";
import lightningcss from "lume/plugins/lightningcss.ts";
// import minifyHtml from "lume/plugins/minify_html.ts";
import nav from "lume/plugins/nav.ts";
import redirects from "lume/plugins/redirects.ts";
import resolveUrls from "lume/plugins/resolve_urls.ts";
import sitemap from "lume/plugins/sitemap.ts";
import slugifyUrls from "lume/plugins/slugify_urls.ts";
import tailwindcss from "lume/plugins/tailwindcss.ts";
const siteName = "RGBCube";
const siteDescription =
"The home directory and journal of RGBCube and his work.";
const author = "RGBCube";
const color = "#00FFFF";
const pathAssets = "/assets";
const site = lume({
src: "./site",
server: {
debugBar: false,
},
});
site.data("layout", "default.vto");
site.data("site_name", siteName);
site.data("title", siteName);
site.data("description", siteDescription);
site.data("author", author);
site.data("color", color);
site.add(".");
site.preprocess([".html"], (pages) =>
pages.forEach((page) => {
page.data.title = page.data.title ??
page.data.basename
.replace(/-/g, " ")
.replace(/\b\w/g, (char) => char.toUpperCase());
}));
site.process([".html"], (pages) =>
pages.forEach((page) => {
const { document } = page;
document.querySelectorAll("table").forEach((element) => {
const wrapper = document.createElement("div");
element.classList.add("transform-[rotateX(180deg)]");
wrapper.classList.add(
"transform-[rotateX(180deg)]",
"overflow-x-auto",
);
element.parentNode!.insertBefore(wrapper, element);
wrapper.appendChild(element);
});
document.querySelectorAll("pre code").forEach((code) => {
const element = code.parentElement!;
const wrapper = document.createElement("div");
element.classList.add("transform-[rotateX(180deg)]");
wrapper.classList.add(
"transform-[rotateX(180deg)]",
"overflow-x-auto",
);
element.parentNode!.insertBefore(wrapper, element);
wrapper.appendChild(element);
});
document
.querySelectorAll(".text-content :where(h1, h2, h3, h4, h5, h6)")
.forEach((header) => {
if (header.id || header.closest("a") || header.querySelector("a")) {
return;
}
const textNormalized = header
.textContent!
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, "")
.replace(/\s+/g, "-")
.replace(/-+/g, "-")
.trim();
let textUnique = textNormalized;
let counter = 1;
while (document.getElementById(textUnique)) {
counter += 1;
textUnique = `${textNormalized}-${counter}`;
}
header.id = textUnique;
const link = document.createElement("a");
link.setAttribute("href", "#" + textUnique);
header.parentNode!.insertBefore(link, header);
link.appendChild(header);
});
const footnotes = document.querySelector("#footnotes");
if (footnotes) {
let counter = 0;
document.querySelectorAll("p").forEach((paragraph) => {
const matches = paragraph.innerHTML.match(/\[\^([^\]]*)\]/g);
if (!matches) return;
let newHTML = paragraph.innerHTML;
matches.forEach((match) => {
const footnoteText = match.slice(2, -1);
let number;
let addFooter;
if (footnoteText.match(/^[1-9]+$/g)) {
number = parseInt(footnoteText);
addFooter = false;
} else {
counter += 1;
number = counter;
addFooter = true;
}
const anchorId = `ref:${counter}`;
const footnoteId = `fn:${counter}`;
const link =
`<sup><a id="${anchorId}" href="#${footnoteId}">^${number}</a></sup>`;
newHTML = newHTML.replace(match, link);
if (addFooter) {
const hr = document.createElement("hr");
const li = document.createElement("li");
li.id = footnoteId;
li.innerHTML =
`${footnoteText}<sub><a href="#${anchorId}">..?</a></sub>`;
footnotes.appendChild(hr);
footnotes.appendChild(li);
}
});
paragraph.innerHTML = newHTML;
});
if (counter === 0) {
footnotes.remove();
}
}
}));
site.use(extractDate());
site.use(redirects());
site.use(tailwindcss());
site.use(codeHighlight({
options: {
classPrefix: "token-",
noHighlightRe: /^no-highlight$/,
},
}));
site.process([".html"], (pages) =>
pages.forEach((page) => {
const { document } = page;
document.querySelectorAll("pre code").forEach((code) => {
const matches = code.innerHTML.match(/\{\[\([^\)]+\)\]\}/g);
if (!matches) return;
let newHTML = code.innerHTML;
matches.forEach((match) => {
newHTML = newHTML.replace(
match,
`<span class="callout">${match.replaceAll(/[^\d]/g, "")}</span>`,
);
});
code.innerHTML = newHTML;
});
}));
site.use(resolveUrls());
site.use(slugifyUrls({
extensions: "*",
}));
site.use(checkUrls({
strict: true,
throw: true,
}));
site.use(nav());
site.use(feed({
output: ["/blog.rss", "/blog.json"],
query: "url^=/blog/ url!=/blog/ unlisted!=true",
sort: "date=asc",
limit: Infinity,
info: {
title: siteName,
description: siteDescription,
authorName: author,
image: `${pathAssets}/icons/icon.webp`,
icon: `${pathAssets}/icons/icon.webp`,
color,
generator: false,
},
items: {
content: "$ .text-content",
},
}));
site.use(sitemap({
items: {
// @ts-ignore: We don't want lastmods.
lastmod: null,
},
}));
site.use(lightningcss()); // TODO: LightningCSS doesn't handle inline styles.
site.use(inline());
// site.use(minifyHtml({
// options: {
// // TODO: This breaks tailwind.
// // minify_css: true,
// minify_js: true,
// },
// }));
export default site;