163 lines
4.8 KiB
JavaScript
163 lines
4.8 KiB
JavaScript
|
const fs = require("node:fs/promises");
|
||
|
const path = require("node:path");
|
||
|
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
||
|
const { html: beautifyHtml } = require('js-beautify');
|
||
|
|
||
|
const data = {
|
||
|
outputDirectory: "./out",
|
||
|
navigationLinks: [
|
||
|
{link: "index.html", text: "home", name: "home"},
|
||
|
{link: "projects.html", text: "projects", name: "projects"},
|
||
|
{link: "https://git.hippoz.xyz", text: "git", name: "__ext_git"},
|
||
|
],
|
||
|
postProcessing: {
|
||
|
beautifyOutput: true,
|
||
|
beautifyOutputOptions: {
|
||
|
indent_size: 2,
|
||
|
preserve_newlines: false
|
||
|
},
|
||
|
minifyOutputOptions: {
|
||
|
indent_size: 0,
|
||
|
preserve_newlines: false,
|
||
|
end_with_newline: false,
|
||
|
eol: ""
|
||
|
}
|
||
|
},
|
||
|
repositoryList: {
|
||
|
gitTargetUsername: "hippoz",
|
||
|
repositoryFetchUrl: `https://git.hippoz.xyz/api/v1/users/hippoz/repos?page=1&limit=100`,
|
||
|
_cache: null,
|
||
|
fetchProjects: async function() {
|
||
|
if (this._cache) return this._cache;
|
||
|
|
||
|
const response = await fetch(this.repositoryFetchUrl);
|
||
|
const json = await response.json();
|
||
|
this._cache = json;
|
||
|
|
||
|
return json;
|
||
|
}
|
||
|
},
|
||
|
navigationBrandingText: "hippoz."
|
||
|
};
|
||
|
|
||
|
const linkButton = ({ link, text, selected=false }) => `
|
||
|
<a href="${link}" class="button-default${selected ? " button-selected" : ""}">${text}</a>
|
||
|
`;
|
||
|
|
||
|
const navigation = ({currentName}) => `
|
||
|
<div class="card layout-card noselect">
|
||
|
<div class="float-left">
|
||
|
<b class="navigation-branding-text">${data.navigationBrandingText}</b>
|
||
|
</div>
|
||
|
<div class="align-right">
|
||
|
${data.navigationLinks.map(e => linkButton({ ...e, selected: currentName === e.name })).join("")}
|
||
|
</div>
|
||
|
</div>
|
||
|
`;
|
||
|
|
||
|
const makePage = ({ name, description, title }) => content => [`
|
||
|
<!DOCTYPE html>
|
||
|
<html lang="en">
|
||
|
<head>
|
||
|
<meta charset="UTF-8">
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
<meta name="description" content="${description}">
|
||
|
<title>${title}</title>
|
||
|
<link rel="stylesheet" href="res/style.css">
|
||
|
</head>
|
||
|
<body>
|
||
|
${navigation({currentName: name})}
|
||
|
<section class="card layout-card" id="content">
|
||
|
${content}
|
||
|
</section>
|
||
|
|
||
|
<script src="res/fastnav.js"></script>
|
||
|
</body>
|
||
|
</html>
|
||
|
`, content];
|
||
|
|
||
|
const indexPage = () => makePage({
|
||
|
title: "hippoz",
|
||
|
description: "hippoz website homepage",
|
||
|
name: "home",
|
||
|
})(`
|
||
|
<h2>hippoz's website</h2>
|
||
|
<p>i think</p>
|
||
|
`);
|
||
|
|
||
|
const projectsPage = async () => makePage({
|
||
|
title: "hippoz",
|
||
|
description: "hippoz projects",
|
||
|
name: "projects",
|
||
|
})(`
|
||
|
${
|
||
|
(await data.repositoryList.fetchProjects())
|
||
|
.sort((a, b) => b.size - a.size) // biggest projects first
|
||
|
.filter(a => !a.archived)
|
||
|
.map(
|
||
|
repo =>`
|
||
|
<div class="card inner-card">
|
||
|
<div>
|
||
|
<b>${repo.fork ? "🍴" : "📘"} ${repo.name}</b>
|
||
|
<a class="button-default float-right" href=${repo.html_url}>view >></a>
|
||
|
</div>
|
||
|
${repo.description ? `<p>${repo.description}</p>` : `<p class="grayed-out">Mysterious! This project has no description.</p>`}
|
||
|
</div>`
|
||
|
)
|
||
|
.join("\n")
|
||
|
}
|
||
|
`);
|
||
|
|
||
|
const pages = {
|
||
|
"projects.html": projectsPage,
|
||
|
"index.html": indexPage
|
||
|
};
|
||
|
let renderedPageCache = null;
|
||
|
|
||
|
const renderPages = async () => {
|
||
|
if (renderedPageCache) return renderedPageCache;
|
||
|
|
||
|
renderedPageCache = {};
|
||
|
for (const [pageName, builder] of Object.entries(pages)) {
|
||
|
renderedPageCache[pageName] = await builder();
|
||
|
}
|
||
|
return renderedPageCache;
|
||
|
};
|
||
|
|
||
|
const deployNavScript = async () => {
|
||
|
let script = await fs.readFile("./src/assets/fastnav.js");
|
||
|
if (script) script = script.toString();
|
||
|
|
||
|
const renderedPages = await renderPages();
|
||
|
let navMap = {};
|
||
|
for (let [pageName, content] of Object.entries(renderedPages)) {
|
||
|
if (data.postProcessing.beautifyOutput) {
|
||
|
content = beautifyHtml(content[1], data.postProcessing.minifyOutputOptions);
|
||
|
}
|
||
|
|
||
|
navMap[pageName] = content;
|
||
|
}
|
||
|
|
||
|
const content = script.replace(`"{{NAV_DATA}}"`, JSON.stringify(navMap));
|
||
|
|
||
|
await fs.writeFile("./out/res/fastnav.js", content);
|
||
|
};
|
||
|
|
||
|
const deployPages = async () => {
|
||
|
const renderedPages = await renderPages();
|
||
|
for (let [pageName, content] of Object.entries(renderedPages)) {
|
||
|
if (data.postProcessing.beautifyOutput) {
|
||
|
content = beautifyHtml(content[0], data.postProcessing.beautifyOutputOptions);
|
||
|
}
|
||
|
|
||
|
await fs.writeFile(path.join(data.outputDirectory, pageName), content);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const deployAll = async () => {
|
||
|
await deployNavScript();
|
||
|
await deployPages();
|
||
|
};
|
||
|
|
||
|
deployAll();
|