1import lume from "lume/mod.ts";
2import date from "lume/plugins/date.ts";
3import toml from "lume/plugins/toml.ts";
4
5// Images
6import picture from "lume/plugins/picture.ts";
7import transformImages from "lume/plugins/transform_images.ts";
8
9// URL Management
10import slugifyUrls from "lume/plugins/slugify_urls.ts";
11import resolveUrls from "lume/plugins/resolve_urls.ts";
12
13// File Generation
14import feed from "lume/plugins/feed.ts";
15import metas from "lume/plugins/metas.ts";
16import readingInfo from "lume/plugins/reading_info.ts";
17import robots from "lume/plugins/robots.ts";
18import sitemap from "lume/plugins/sitemap.ts";
19import sourceMaps from "lume/plugins/source_maps.ts";
20
21// Optimization
22import brotli from "lume/plugins/brotli.ts";
23import gzip from "lume/plugins/gzip.ts";
24import minifyHTML from "lume/plugins/minify_html.ts";
25import svgo from "lume/plugins/svgo.ts";
26
27// Markdown-it plugins
28import { BiDirectionalLinks } from "@nolebase/markdown-it-bi-directional-links";
29import { default as mdItObsidianCallouts } from "markdown-it-obsidian-callouts";
30
31// Additional external plugins
32import toc from "lume_markdown_plugins/toc.ts";
33import slugify from "npm:@sindresorhus/slugify";
34
35// CSS
36// // Base dependencies
37import tailwindcss from "lume/plugins/tailwindcss.ts";
38// // Fonts
39import googleFonts from "lume/plugins/google_fonts.ts";
40// // Optimization
41import lightningcss from "lume/plugins/lightningcss.ts";
42
43// Custom Plugins
44import validateHTML from "./plugins/validateHTML.ts";
45import openInEditor from "./plugins/openInEditor.ts";
46import footnotes from "./plugins/footnotes.ts";
47// import checkAccessibility from "./plugins/checkAccessibility.ts";
48
49// Disabled Plugins:
50// import nav from "lume/plugins/nav.ts";
51// import og_images from "lume/plugins/og_images.ts";
52// import pagefind from "lume/plugins/pagefind.ts";
53// import purgecss from "lume/plugins/purgecss.ts";
54// import relations from "lume/plugins/relations.ts";
55// import sri from "lume/plugins/sri.ts";
56
57// To Add:
58// https://deno.land/x/lume_shiki@0.0.16
59
60const markdown = {
61 plugins: [
62 BiDirectionalLinks({
63 dir: Deno.cwd() + "/src/",
64 stillRenderNoMatched: false,
65 debug: false,
66 }),
67 mdItObsidianCallouts,
68 footnotes,
69 ],
70};
71
72const site = lume({
73 src: "./src",
74 location: new URL("https://pyrox.dev"),
75 cssFile: "/styles.css",
76}, { markdown });
77
78// Ensure all URLs are to the final page links
79site.use(resolveUrls());
80// Copy Static Files
81// site.ignore("/static/mocha.css");
82site.add("static/.well-known", ".well-known");
83
84// Fonts
85site.use(
86 googleFonts({
87 subsets: ["latin", "latin-ext"],
88 fontsFolder: "/static/fonts/",
89 fonts:
90 "https://fonts.googleapis.com/css2?family=IBM+Plex+Serif:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900",
91 }),
92);
93
94// Tailwind CSS
95site.use(tailwindcss());
96site.use(lightningcss({
97 options: {
98 minify: true,
99 },
100}));
101site.add([".css", ".woff2"]);
102
103// Source Map Generation
104// Applies to CSS and JS
105site.use(sourceMaps());
106
107site.use(slugifyUrls());
108site.use(picture());
109site.use(transformImages());
110site.add([".png"]);
111// site.use(relations());
112site.use(svgo());
113site.use(toml());
114
115// Metadata
116site.use(
117 date({
118 formats: {
119 SHORT_DATE: "yyyy-MM-dd",
120 POST_DATE: "dd MMM, yyyy",
121 },
122 }),
123);
124site.use(metas());
125site.use(readingInfo({
126 // Number taken from:
127 // https://reader.ku.edu/sites/reader/files/2024-01/How%20many%20words%20do%20we%20read%20per%20minute%20(1).pdf
128 wordsPerMinute: 238,
129}));
130site.use(toc({
131 slugify: (s: string) => slugify(s),
132}));
133
134// RSS/JSON Feed Generation
135site.use(
136 feed({
137 output: ["/blog.rss", "/blog.json"],
138 query: "category=blog",
139 info: {
140 title: "dish blog",
141 description: "dish's thoughts on many things",
142 published: new Date(),
143 lang: "en",
144 generator: true,
145 authorName: "dish",
146 authorUrl: "https://blog.pyrox.dev",
147 },
148 items: {
149 title: "=title",
150 description: "=summary",
151 published: "=published",
152 updated: "=updated",
153 content: "$.e-content",
154 lang: "=lang",
155 image: "=banner",
156 authorName: "=author.name",
157 authorUrl: "=author.url",
158 },
159 }),
160);
161
162// CSS postprocessing
163site.use(sitemap());
164
165// site.use(checkAccessibility());
166site.use(validateHTML());
167
168site.data("production", Deno.env.get("PRODUCTION") == "true");
169// This only applies in dev mode
170if (Deno.env.get("PRODUCTION") == "false") {
171 site.use(openInEditor());
172 site.add("static/scripts/open-in-editor.js");
173 site.add("static/scripts/highlight-accessibility.js");
174}
175
176// This only applies in prod mode
177if (Deno.env.get("PRODUCTION") == "true") {
178 // Minify HTML
179 site.use(minifyHTML({
180 options: {
181 do_not_minify_doctype: true,
182 keep_closing_tags: false,
183 keep_html_and_head_opening_tags: true,
184 keep_spaces_between_attributes: true,
185 ensure_spec_compliant_unquoted_attribute_values: true,
186 keep_comments: false,
187 },
188 }));
189}
190
191// robots.txt generation
192site.use(
193 robots({
194 disallow: [
195 "AI2Bot",
196 "Amazonbot",
197 "Applebot-Extended",
198 "Bytespider",
199 "ChatGPT-User",
200 "ClaudeBot",
201 "Diffbot",
202 "DuckAssistBot",
203 "FacebookBot",
204 "GPTBot",
205 "Google-Extended",
206 "Meta-ExternalAgent",
207 "Meta-ExternalFetcher",
208 "OAI-SearchBot",
209 "Operator",
210 "PanguBot",
211 "PerplexityBot",
212 "SemrushBot",
213 "SemrushBot-OCOB",
214 "Timpibot",
215 "Webzio-Extended",
216 "YouBot",
217 "cohere-training-data-crawler",
218 "omgili",
219 "t3versions",
220 ],
221 }),
222);
223
224// Compress everything with Brotli/Gzip
225site.use(
226 brotli({
227 quality: 11,
228 extensions: [
229 ".html",
230 ".css",
231 ".js",
232 ".mjs",
233 ".svg",
234 ".json",
235 ".xml",
236 ".txt",
237 ".rss",
238 ".map",
239 ],
240 }),
241);
242site.use(
243 gzip({
244 extensions: [
245 ".html",
246 ".css",
247 ".js",
248 ".mjs",
249 ".svg",
250 ".json",
251 ".xml",
252 ".txt",
253 ".rss",
254 ".map",
255 ],
256 }),
257);
258
259// Open in Editor in Dev mode
260// Get current commit as a version number
261// Taken from https://github.com/pixeldesu/pixelde.su/blob/main/_config.ts
262const commitCmd = new Deno.Command("git", { args: ["rev-parse", "HEAD"] });
263const { stdout } = await commitCmd.output();
264const commitHash = new TextDecoder().decode(stdout);
265site.data("commit", commitHash);
266
267export default site;