love/source/scripts/pages.ts

157 lines
4.7 KiB
TypeScript

import fs, {promises as fsp} from 'fs';
import {join} from 'path';
import cpy from 'cpy';
// @ts-ignore
import htmlclean from 'htmlclean';
import marked from 'marked';
import nunjucks from 'nunjucks';
import refractor from 'refractor';
// @ts-ignore
import rehype from 'rehype';
import sass from 'sass';
import tar from 'tar';
import {generateLove, LoveVariant} from './love';
import {getVersions, Versions} from './version';
export async function entry(): Promise<void> {
// Create all required directories for the website.
await fsp.mkdir(join(__dirname, '../../public/css/'), {recursive: true});
await fsp.mkdir(join(__dirname, '../../public/fonts/'), {recursive: true});
await fsp.mkdir(join(__dirname, '../../public/images/'), {recursive: true});
// Configure Nunjucks to use the templates for `source/pages/`.
nunjucks.configure(join(__dirname, '../pages/'), {
lstripBlocks: true,
trimBlocks: true,
throwOnUndefined: true
});
const love: LoveVariant[] = generateLove();
const versions: Versions = await getVersions();
// Write the colors to file.
await writeJSON(join(__dirname, '../../public/love.json'), love);
// Render the Sass to CSS.
let css: string = sass
.renderSync({
file: join(__dirname, '../pages/scss/style.scss'),
sourceMap: false
})
.css.toString();
// Generate the CSS custom properties.
const cssProperties = `:root {
--foreground-1: ${love[0].colors.foreground1};
--foreground-2: ${love[0].colors.foreground2};
--background-1: ${love[0].colors.background1};
--background-2: ${love[0].colors.background2};
${love[0].colors.accents
.map((value, index) => ` --dark-accent-${index + 1}: ${value};`)
.join('\n')}
${love[0].colors.grays
.map((value, index) => ` --dark-gray-${index + 1}: ${value};`)
.join('\n')}
${love[1].colors.accents
.map((value, index) => ` --light-accent-${index + 1}: ${value};`)
.join('\n')}
${love[1].colors.grays
.map((value, index) => ` --light-gray-${index + 1}: ${value};`)
.join('\n')}
}\n`;
// Replace the predefined `:root` location with our properties.
css = css.replace(/\/\* :root-insert \*\//, cssProperties);
// Write the CSS to file.
await fsp.writeFile(join(__dirname, '../../public/css/style.css'), css);
// Render and write the `index.html` file.
await fsp.writeFile(
join(__dirname, '../../public/index.html'),
htmlclean(nunjucks.render('index.html', {love}))
);
// Extract the fonts to file.
await tar.extract({
file: join(__dirname, '../pages/assets/Inter.tar'),
cwd: join(__dirname, '../../public/fonts/')
});
await tar.extract({
file: join(__dirname, '../pages/assets/Hasklig.tar'),
cwd: join(__dirname, '../../public/fonts/')
});
const renderer: marked.Renderer = new marked.Renderer();
renderer.code = (code: string, language: string | undefined): string => {
if (language === undefined) {
throw new Error('Markdown code block with no language detected');
}
const codeHTML: string = rehype()
.stringify({type: 'root', children: refractor.highlight(code, language)})
.toString();
return `<pre><code class="language-${language}">${codeHTML}</code></pre>`;
};
await fsp.mkdir(join(__dirname, '../../public/get/'), {recursive: true});
const pagesToCreate: string[] = (
await fsp.readdir(join(__dirname, '../'))
).filter(value => !['pages', 'scripts'].includes(value));
for (const page of pagesToCreate) {
const markdown: string = marked(
nunjucks.renderString(
await fsp.readFile(
join(__dirname, `../${page}/Site ReadMe.md`),
'utf8'
),
{versions}
),
{renderer}
);
await fsp.mkdir(join(__dirname, `../../public/images/${page}/`), {
recursive: true
});
if (fs.existsSync(join(__dirname, `../${page}/images/`))) {
await cpy(
join(__dirname, `../${page}/images/*`),
join(__dirname, `../../public/images/${page}/`)
);
}
let title = `Love for ${page
.replace(/-/g, ' ')
.split(' ')
.map(capitalize)
.join(' ')}`;
switch (page) {
case 'vscode':
title = 'Love for VS Code';
break;
default:
break;
}
await fsp.writeFile(
join(__dirname, `../../public/get/${page}.html`),
htmlclean(nunjucks.render('get.html', {love, markdown, title}))
);
}
}
export function capitalize(word: string): string {
return `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`;
}
// Utility helper function to write some data to file as JSON.
export async function writeJSON(path: string, data: unknown): Promise<void> {
await fsp.writeFile(path, JSON.stringify(data, null, 2));
}
if (require.main === module) {
entry();
}