completely refactor website generator and add experimental fast nav system
This commit is contained in:
parent
4fbdace446
commit
797c47b4a0
18 changed files with 414 additions and 591 deletions
100
build.js
100
build.js
|
@ -1,100 +0,0 @@
|
|||
const { promises: fs } = require("fs");
|
||||
const path = require("path");
|
||||
const { html: beautifyHtml } = require('js-beautify');
|
||||
|
||||
const buildConfig = require("./buildconfig");
|
||||
|
||||
// source: https://stackoverflow.com/a/41407246
|
||||
const escapeCodes = {
|
||||
reset: "\x1b[0m",
|
||||
bright: "\x1b[1m",
|
||||
dim: "\x1b[2m",
|
||||
underscore: "\x1b[4m",
|
||||
blink: "\x1b[5m",
|
||||
reverse: "\x1b[7m",
|
||||
hidden: "\x1b[8m",
|
||||
|
||||
fgBlack: "\x1b[30m",
|
||||
fgRed: "\x1b[31m",
|
||||
fgGreen: "\x1b[32m",
|
||||
fgYellow: "\x1b[33m",
|
||||
fgBlue: "\x1b[34m",
|
||||
fgMagenta: "\x1b[35m",
|
||||
fgCyan: "\x1b[36m",
|
||||
fgWhite: "\x1b[37m",
|
||||
|
||||
bgBlack: "\x1b[40m",
|
||||
bgRed: "\x1b[41m",
|
||||
bgGreen: "\x1b[42m",
|
||||
bgYellow: "\x1b[43m",
|
||||
bgBlue: "\x1b[44m",
|
||||
bgMagenta: "\x1b[45m",
|
||||
bgCyan: "\x1b[46m",
|
||||
bgWhite: "\x1b[47m",
|
||||
};
|
||||
|
||||
if (!buildConfig.allowSpecialCharacters) {
|
||||
for (i in escapeCodes) {
|
||||
escapeCodes[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
const specialCharacter = (c) => {
|
||||
if (buildConfig.allowSpecialCharacters) {
|
||||
return c;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const processPageOutput = async (out) => {
|
||||
if (typeof out === "function")
|
||||
out = await out();
|
||||
if (typeof out !== "string")
|
||||
throw new Error("got non-string page output (maybe one of the pages isn't exporting a string?)");
|
||||
|
||||
if (buildConfig.postProcessing.trimOutput) {
|
||||
out = out.trim();
|
||||
}
|
||||
|
||||
if (buildConfig.postProcessing.beautifyOutput) {
|
||||
out = beautifyHtml(out, buildConfig.postProcessing.beautifyOutputOptions);
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
const findAllPages = async (directory) =>
|
||||
(await fs.readdir(directory))
|
||||
.filter(
|
||||
f => f.endsWith(buildConfig.pageExtension)
|
||||
)
|
||||
.map(f => directory + "/" + f); // TODO: hack
|
||||
|
||||
const buildPage = async (pagePath) => {
|
||||
const processed = await processPageOutput(require(pagePath));
|
||||
console.log(`${escapeCodes.fgGreen}${specialCharacter("→")}${escapeCodes.reset} Built ${escapeCodes.fgBlue}${path.parse(path.basename(pagePath, buildConfig.pageExtension)).name}${escapeCodes.reset}`);
|
||||
return processed
|
||||
};
|
||||
|
||||
const buildAllPages = async (directory) =>
|
||||
await Promise.all((await findAllPages(directory))
|
||||
.map(
|
||||
async p => [p, (await buildPage(p))]
|
||||
));
|
||||
|
||||
const exportAllPages = async (sourcePath, outputPath) => {
|
||||
const pages = await buildAllPages(sourcePath);
|
||||
for (const [pagePath, pageContent] of pages) {
|
||||
const pageName = path.parse(path.basename(pagePath, buildConfig.pageExtension)).name;
|
||||
await fs.writeFile(path.join(outputPath, pageName + ".html"), pageContent);
|
||||
}
|
||||
return pages.length;
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
const startTime = new Date();
|
||||
const builtPages = await exportAllPages(buildConfig.sourceDirectory, buildConfig.outputDirectory);
|
||||
console.log(`${escapeCodes.fgGreen}${specialCharacter("✓")} Done! ${escapeCodes.fgBlue}Built ${builtPages} pages in ${((new Date()) - startTime)}ms.${escapeCodes.reset}`);
|
||||
};
|
||||
|
||||
main();
|
|
@ -1,14 +0,0 @@
|
|||
module.exports = {
|
||||
sourceDirectory: "./src",
|
||||
outputDirectory: "./out",
|
||||
pageExtension: ".page.js",
|
||||
postProcessing: {
|
||||
trimOutput: false,
|
||||
beautifyOutput: true,
|
||||
beautifyOutputOptions: {
|
||||
indent_size: 2,
|
||||
preserve_newlines: false
|
||||
}
|
||||
},
|
||||
allowSpecialCharacters: true
|
||||
};
|
|
@ -1,105 +0,0 @@
|
|||
window.modules.register("GatewayClient", () => {
|
||||
const messageSchema = { t: "number", d: "object" };
|
||||
const messageTypes = {
|
||||
HELLO: 0,
|
||||
YOO: 1,
|
||||
READY: 2,
|
||||
EVENT: 3
|
||||
};
|
||||
|
||||
class GatewayClient {
|
||||
constructor(gatewayPath) {
|
||||
this.gatewayPath = gatewayPath;
|
||||
this.ws = null;
|
||||
this.token = null;
|
||||
this.user = null;
|
||||
this.onEvent = (e) => {};
|
||||
this.onConnected = () => {};
|
||||
this.onDisconnected = () => {};
|
||||
}
|
||||
|
||||
connect(token) {
|
||||
if (!token)
|
||||
token = this.token;
|
||||
|
||||
console.log("gateway: connecting");
|
||||
|
||||
this.ws = new WebSocket(this.gatewayPath);
|
||||
|
||||
this.ws.addEventListener("message", ({ data }) => {
|
||||
if (typeof data !== "string") {
|
||||
console.warn("gateway: got non-string data from server, ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
let message;
|
||||
try {
|
||||
message = JSON.parse(data);
|
||||
} catch(e) {
|
||||
console.warn("gateway: got invalid JSON from server (failed to parse), ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._checkMessageSchema(message)) {
|
||||
console.warn("gateway: got invalid JSON from server (does not match schema), ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.t) {
|
||||
case messageTypes.HELLO: {
|
||||
console.log("gateway: HELLO");
|
||||
this.ws.send(JSON.stringify({
|
||||
t: messageTypes.YOO,
|
||||
d: {
|
||||
token
|
||||
}
|
||||
}));
|
||||
break;
|
||||
}
|
||||
case messageTypes.READY: {
|
||||
console.log("gateway: READY");
|
||||
this.user = message.d.user;
|
||||
this.onConnected();
|
||||
break;
|
||||
}
|
||||
case messageTypes.EVENT: {
|
||||
this.onEvent(message.d);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.warn("gateway: got invalid JSON from server (invalid type), ignoring...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.ws.addEventListener("open", () => {
|
||||
console.log("gateway: open");
|
||||
});
|
||||
this.ws.addEventListener("close", ({ code }) => {
|
||||
console.log("gateway: closed");
|
||||
this.onDisconnected(code);
|
||||
if (code === 4001) {
|
||||
console.log(`gateway: disconnect code is ${code} (bad auth), will not attempt reconnect`);
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
console.log("gateway: reconnecting");
|
||||
this.connect(token);
|
||||
}, 4000);
|
||||
});
|
||||
}
|
||||
|
||||
_checkMessageSchema(message) {
|
||||
for (const [key, value] of Object.entries(message)) {
|
||||
if (!messageSchema[key])
|
||||
return false;
|
||||
|
||||
if (typeof value !== messageSchema[key])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return GatewayClient;
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
window.modules.register("$app", () => {
|
||||
const App = window.modules.require("App");
|
||||
|
||||
if (!window._APP_ENV)
|
||||
throw new Error("$app: could not find window._APP_ENV");
|
||||
if (!App)
|
||||
throw new Error("$app: require('App') returned undefined");
|
||||
|
||||
const initialLoading = document.getElementById("initial-loading");
|
||||
if (initialLoading) {
|
||||
initialLoading.parentElement.removeChild(initialLoading);
|
||||
}
|
||||
|
||||
const appMountElement = document.createElement("div");
|
||||
document.body.appendChild(appMountElement);
|
||||
|
||||
const app = new App(appMountElement);
|
||||
app.mount();
|
||||
|
||||
return app;
|
||||
});
|
|
@ -1,185 +0,0 @@
|
|||
window.modules.register("AuthPromptRoute", () => {
|
||||
class AuthPromptRoute {
|
||||
constructor() {
|
||||
this.element = null;
|
||||
}
|
||||
|
||||
mountOn(target) {
|
||||
if (this.element)
|
||||
return; // Already mounted
|
||||
|
||||
this.element = document.createRange().createContextualFragment(`
|
||||
<div>
|
||||
<input type="password" id="code-input">
|
||||
<button id="continue-button">enter</button>
|
||||
</div>
|
||||
`).children[0];
|
||||
|
||||
this.element.querySelector("#continue-button").addEventListener("click", () => {
|
||||
if (this.onPasswordSubmitted)
|
||||
this.onPasswordSubmitted(this.element.querySelector("#code-input").value);
|
||||
});
|
||||
|
||||
target.appendChild(this.element);
|
||||
}
|
||||
|
||||
unmount() {
|
||||
if (!this.element)
|
||||
return; // Already unmounted
|
||||
this.element.parentElement.removeChild(this.element);
|
||||
this.element = null;
|
||||
}
|
||||
}
|
||||
|
||||
return AuthPromptRoute;
|
||||
});
|
||||
|
||||
window.modules.register("MainChatView", () => {
|
||||
class MainChatView {
|
||||
constructor() {
|
||||
this.element = null;
|
||||
}
|
||||
|
||||
mountOn(target) {
|
||||
if (this.element)
|
||||
return; // Already mounted
|
||||
|
||||
this.element = document.createRange().createContextualFragment(`
|
||||
<div>
|
||||
<div id="messages-container" style="width: 300px; height: 250px; overflow: auto;"></div>
|
||||
<br>
|
||||
<input type="text" id="message-input">
|
||||
<button id="message-submit">send</button>
|
||||
</div>
|
||||
`).children[0];
|
||||
|
||||
const textInput = this.element.querySelector("#message-input");
|
||||
this.element.querySelector("#message-submit").addEventListener("click", () => {
|
||||
const message = textInput.value;
|
||||
if (this.onSendMessage)
|
||||
this.onSendMessage(message);
|
||||
|
||||
textInput.value = "";
|
||||
});
|
||||
|
||||
target.appendChild(this.element);
|
||||
}
|
||||
|
||||
appendMessage(messageObject) {
|
||||
const { author, content } = messageObject;
|
||||
if (!this.element)
|
||||
return;
|
||||
|
||||
const usernameLetters = author.username
|
||||
.split("");
|
||||
let authorUsernameNumber = 150;
|
||||
usernameLetters.forEach(l => {
|
||||
authorUsernameNumber += l.charCodeAt(0);
|
||||
});
|
||||
|
||||
const messageElement = document.createRange().createContextualFragment(`
|
||||
<div>
|
||||
<b>[author could not be loaded] </b>
|
||||
<span>[content could not be loaded]</span>
|
||||
</div>
|
||||
`).children[0];
|
||||
|
||||
messageElement.querySelector("b").innerText = `User ${authorUsernameNumber} `;
|
||||
messageElement.querySelector("span").innerText = content;
|
||||
|
||||
const container = this.element.querySelector("#messages-container");
|
||||
container.appendChild(messageElement);
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
|
||||
unmount() {
|
||||
if (!this.element)
|
||||
return; // Already unmounted
|
||||
this.element.parentElement.removeChild(this.element);
|
||||
this.element = null;
|
||||
}
|
||||
}
|
||||
|
||||
return MainChatView;
|
||||
});
|
||||
|
||||
|
||||
window.modules.register("App", () => {
|
||||
const AuthPromptRoute = window.modules.require("AuthPromptRoute");
|
||||
const MainChatView = window.modules.require("MainChatView");
|
||||
const GatewayClient = window.modules.require("GatewayClient");
|
||||
|
||||
|
||||
class App {
|
||||
constructor(mountElement) {
|
||||
this.mountElement = mountElement;
|
||||
this.currentMountedElement = null;
|
||||
|
||||
this.authPromptRoute = new AuthPromptRoute();
|
||||
this.mainChatView = new MainChatView();
|
||||
this.gatewayClient = new GatewayClient(window._APP_ENV.gatewayBase);
|
||||
}
|
||||
|
||||
_mountElement(element) {
|
||||
if (this.currentMountedElement) {
|
||||
this.currentMountedElement.unmount();
|
||||
}
|
||||
this.currentMountedElement = element;
|
||||
this.currentMountedElement.mountOn(this.mountElement);
|
||||
}
|
||||
|
||||
_unmountAll() {
|
||||
if (this.currentMountedElement) {
|
||||
this.currentMountedElement.unmount();
|
||||
}
|
||||
}
|
||||
|
||||
mount() {
|
||||
let serverId;
|
||||
let channelId;
|
||||
let token;
|
||||
|
||||
this._mountElement(this.authPromptRoute);
|
||||
|
||||
this.gatewayClient.onEvent = (e) => {
|
||||
if (e.eventType === "MESSAGE_CREATE" && e.message && e.message.guild_id === serverId && e.message.channel_id === channelId) {
|
||||
this.mainChatView.appendMessage(e.message);
|
||||
}
|
||||
};
|
||||
this.gatewayClient.onConnected = () => {
|
||||
this._mountElement(this.mainChatView);
|
||||
};
|
||||
this.gatewayClient.onDisconnected = () => {
|
||||
this._mountElement(this.authPromptRoute);
|
||||
};
|
||||
this.authPromptRoute.onPasswordSubmitted = (auth) => {
|
||||
const parts = auth.split(",,");
|
||||
if (parts.length !== 3)
|
||||
return;
|
||||
|
||||
const [userToken, userServerId, userChannelId] = parts;
|
||||
serverId = userServerId;
|
||||
channelId = userChannelId;
|
||||
token = userToken
|
||||
this.gatewayClient.connect(token);
|
||||
};
|
||||
this.mainChatView.onSendMessage = async (message) => {
|
||||
if (typeof message === "string" && message.trim() === "")
|
||||
return;
|
||||
|
||||
await fetch(`${window._APP_ENV.apiBase}/guilds/${serverId}/channels/${channelId}/messages/create`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
content: message
|
||||
}),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"authorization": token
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return App;
|
||||
});
|
|
@ -1,23 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>.</title>
|
||||
<script>
|
||||
window._APP_ENV = {
|
||||
gatewayBase: "wss://kittycatnetwork.hippoz.xyz/services/thebridge/gateway/",
|
||||
apiBase: "https://kittycatnetwork.hippoz.xyz/services/thebridge/api/v1"
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="initial-loading">loading</p>
|
||||
|
||||
<script src="moduleruntime.js"></script>
|
||||
<script src="GatewayClient.js"></script>
|
||||
<script src="components.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,26 +0,0 @@
|
|||
const modules = {
|
||||
_cache: {},
|
||||
_registry: {},
|
||||
require(moduleName) {
|
||||
if (this._cache[moduleName]) {
|
||||
return this._cache[moduleName];
|
||||
}
|
||||
|
||||
if (this._registry[moduleName]) {
|
||||
const loaderFunction = this._registry[moduleName];
|
||||
this._cache[moduleName] = loaderFunction(1);
|
||||
return this._cache[moduleName];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
register(moduleName, loaderFunction) {
|
||||
this._registry[moduleName] = loaderFunction;
|
||||
this._cache[moduleName] = loaderFunction(0);
|
||||
},
|
||||
registerLazy(moduleName, loaderFunction) {
|
||||
this._registry[moduleName] = loaderFunction;
|
||||
}
|
||||
};
|
||||
|
||||
window.modules = modules;
|
26
out/res/fastnav.js
Normal file
26
out/res/fastnav.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
const map = {"projects.html":"<div class=\"card inner-card\"><div><b>📘 waffle</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/waffle>view >></a></div><p class=\"grayed-out\">Mysterious! This project has no description.</p></div><div class=\"card inner-card\"><div><b>📘 brainlet-react</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/brainlet-react>view >></a></div><p>a react frontend for waffle (brainlet)</p></div><div class=\"card inner-card\"><div><b>📘 raven</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/raven>view >></a></div><p>Simple experimental low-level UI library written in C++.</p></div><div class=\"card inner-card\"><div><b>📘 bridgecord</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/bridgecord>view >></a></div><p>bridge bot api for discord servers</p></div><div class=\"card inner-card\"><div><b>📘 rice</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/rice>view >></a></div><p>my personal forks of various software and my dotfiles</p></div><div class=\"card inner-card\"><div><b>📘 hippOS</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/hippOS>view >></a></div><p>simple osdev testing</p></div><div class=\"card inner-card\"><div><b>📘 homepage</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/homepage>view >></a></div><p class=\"grayed-out\">Mysterious! This project has no description.</p></div><div class=\"card inner-card\"><div><b>📘 brainlet</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/brainlet>view >></a></div><p>🎤🐢 An open source, self-hosted alternative to Discord</p></div><div class=\"card inner-card\"><div><b>📘 portal</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/portal>view >></a></div><p>waffletv's interface app</p></div><div class=\"card inner-card\"><div><b>📘 capybara</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/capybara>view >></a></div><p>simple and fast remote touchpad</p></div><div class=\"card inner-card\"><div><b>📘 rotcpu</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/rotcpu>view >></a></div><p class=\"grayed-out\">Mysterious! This project has no description.</p></div><div class=\"card inner-card\"><div><b>📘 quad-j</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/quad-j>view >></a></div><p>a simple upload server</p></div><div class=\"card inner-card\"><div><b>📘 blocklists</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/blocklists>view >></a></div><p>Some pi-hole blocklists</p></div><div class=\"card inner-card\"><div><b>📘 wormhole</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/wormhole>view >></a></div><p>A simple websocket abstraction.</p></div><div class=\"card inner-card\"><div><b>📘 mcli</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/mcli>view >></a></div><p>a command-line minecraft launcher written in rust</p></div><div class=\"card inner-card\"><div><b>📘 must</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/must>view >></a></div><p>Helper program for deploying protocol associations needed for running Roblox on Linux</p></div><div class=\"card inner-card\"><div><b>🍴 brainlet-client</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/brainlet-client>view >></a></div><p class=\"grayed-out\">Mysterious! This project has no description.</p></div><div class=\"card inner-card\"><div><b>📘 luapage</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/luapage>view >></a></div><p class=\"grayed-out\">Mysterious! This project has no description.</p></div><div class=\"card inner-card\"><div><b>📘 page-simplify</b><a class=\"button-default float-right\" href=https://git.hippoz.xyz/hippoz/page-simplify>view >></a></div><p>turn pages into pure html</p></div>","index.html":"<h2>hippoz's website</h2><p>i think</p>"};
|
||||
const content = document.getElementById("content");
|
||||
|
||||
const load = (page) => content.innerHTML = map[page.substring(1, page.length) || "_notfound"];
|
||||
const navigate = (page) => {
|
||||
history.pushState(null, "", page);
|
||||
load(page);
|
||||
};
|
||||
|
||||
const populate = () => {
|
||||
const elements = document.querySelectorAll("[href]");
|
||||
elements.forEach(element => {
|
||||
const existingLink = element.getAttribute("href");
|
||||
if (map[existingLink]) {
|
||||
element.setAttribute("href", "#");
|
||||
element.onclick = () => navigate(existingLink);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
populate();
|
||||
window.onpopstate = () => {load(location.pathname); console.log("a");};
|
||||
};
|
||||
|
||||
main();
|
29
src/assets/fastnav.js
Normal file
29
src/assets/fastnav.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
const map = "{{NAV_DATA}}";
|
||||
const content = document.getElementById("content");
|
||||
|
||||
const load = (page) => {
|
||||
content.innerHTML = map[page.substring(1, page.length) || "_notfound"];
|
||||
console.log("a");
|
||||
};
|
||||
const navigate = (page) => {
|
||||
history.pushState(null, "", page);
|
||||
load(page);
|
||||
};
|
||||
|
||||
const populate = () => {
|
||||
const elements = document.querySelectorAll("[href]");
|
||||
elements.forEach(element => {
|
||||
const existingLink = element.getAttribute("href");
|
||||
if (map[existingLink]) {
|
||||
element.setAttribute("href", "");
|
||||
element.onclick = () => navigate(existingLink);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
populate();
|
||||
window.onpopstate = () => load(location.pathname);
|
||||
};
|
||||
|
||||
main();
|
|
@ -1,13 +0,0 @@
|
|||
const Page = require("./components/Page.component");
|
||||
|
||||
module.exports = Page({
|
||||
title: "hippoz blog",
|
||||
description: "hippoz blog",
|
||||
name: "blog",
|
||||
})(`
|
||||
<h2>hippoz's blog</h2>
|
||||
<p>i think</p>
|
||||
<br>
|
||||
<br>
|
||||
<p>no articles yet</p>
|
||||
`);
|
|
@ -1,2 +0,0 @@
|
|||
module.exports = ({ link, text, selected=false }) =>
|
||||
`<a href="${link}" class="button-default${selected ? " button-selected" : ""}">${text}</a>`;
|
|
@ -1,21 +0,0 @@
|
|||
const { navigationLinks, navigationBrandingText } = require("../env");
|
||||
const LinkButtonComponent = require("./LinkButton.component");
|
||||
|
||||
module.exports = ({ pageName }) => `
|
||||
<div class="card layout-card noselect">
|
||||
<div class="float-left">
|
||||
<b class="navigation-branding-text">${navigationBrandingText}</b>
|
||||
</div>
|
||||
<div class="align-right">
|
||||
${
|
||||
navigationLinks.map(
|
||||
({link, text, name}) =>
|
||||
LinkButtonComponent({
|
||||
link,
|
||||
text,
|
||||
selected: name === pageName
|
||||
})
|
||||
).join("")
|
||||
}
|
||||
</div>
|
||||
</div>`;
|
|
@ -1,21 +0,0 @@
|
|||
const NavigationComponent = require("./Navigation.component");
|
||||
|
||||
module.exports = ({ title="page", description="a page", name="page" }) => (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>
|
||||
${NavigationComponent({
|
||||
pageName: name
|
||||
})}
|
||||
<div class="card layout-card">
|
||||
${content}
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
25
src/env/index.js
vendored
25
src/env/index.js
vendored
|
@ -1,25 +0,0 @@
|
|||
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
||||
|
||||
module.exports = {
|
||||
navigationLinks: [
|
||||
{link: "index.html", text: "home", name: "home"},
|
||||
{link: "blog.html", text: "blog", name: "blog"},
|
||||
{link: "projects.html", text: "projects", name: "projects"},
|
||||
{link: "https://git.hippoz.xyz", text: "git", name: "__ext_git"},
|
||||
],
|
||||
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."
|
||||
}
|
162
src/index.js
Normal file
162
src/index.js
Normal file
|
@ -0,0 +1,162 @@
|
|||
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();
|
|
@ -1,10 +0,0 @@
|
|||
const Page = require("./components/Page.component");
|
||||
|
||||
module.exports = Page({
|
||||
title: "hippoz",
|
||||
description: "hippoz website homepage",
|
||||
name: "home",
|
||||
})(`
|
||||
<h2>hippoz's website</h2>
|
||||
<p>i think</p>
|
||||
`);
|
|
@ -1,25 +0,0 @@
|
|||
const { repositoryList } = require("./env");
|
||||
const Page = require("./components/Page.component");
|
||||
|
||||
module.exports = async () => Page({
|
||||
title: "hippoz",
|
||||
description: "hippoz website homepage",
|
||||
name: "projects",
|
||||
})(`
|
||||
${
|
||||
(await 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")
|
||||
}
|
||||
`);
|
197
yarn.lock
Normal file
197
yarn.lock
Normal file
|
@ -0,0 +1,197 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
commander@^2.19.0:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
config-chain@^1.1.13:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
|
||||
integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
|
||||
dependencies:
|
||||
ini "^1.3.4"
|
||||
proto-list "~1.2.1"
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
|
||||
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
|
||||
|
||||
editorconfig@^0.15.3:
|
||||
version "0.15.3"
|
||||
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5"
|
||||
integrity sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==
|
||||
dependencies:
|
||||
commander "^2.19.0"
|
||||
lru-cache "^4.1.5"
|
||||
semver "^5.6.0"
|
||||
sigmund "^1.0.1"
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.5.tgz#0077bf5f3fcdbd9d75a0b5362f77dbb743489863"
|
||||
integrity sha512-N64ZpKqoLejlrwkIAnb9iLSA3Vx/kjgzpcDhygcqJ2KKjky8nCgUQ+dzXtbrLaWZGZNmNfQTsiQ0weZ1svglHg==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.2.tgz#29deb38e1ef90f132d5958abe9c3ee8e87f3c318"
|
||||
integrity sha512-NzDgHDiJwKYByLrL5lONmQFpK/2G78SMMfo+E9CuGlX4IkvfKDsiQSNPwAYxEy+e6p7ZQ3uslSLlwlJcqezBmQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.1.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ini@^1.3.4:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
|
||||
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
||||
|
||||
js-beautify@^1.14.0:
|
||||
version "1.14.3"
|
||||
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.3.tgz#3dd11c949178de7f3bdf3f6f752778d3bed95150"
|
||||
integrity sha512-f1ra8PHtOEu/70EBnmiUlV8nJePS58y9qKjl4JHfYWlFH6bo7ogZBz//FAZp7jDuXtYnGYKymZPlrg2I/9Zo4g==
|
||||
dependencies:
|
||||
config-chain "^1.1.13"
|
||||
editorconfig "^0.15.3"
|
||||
glob "^7.1.3"
|
||||
nopt "^5.0.0"
|
||||
|
||||
lru-cache@^4.1.5:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
|
||||
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
|
||||
dependencies:
|
||||
pseudomap "^1.0.2"
|
||||
yallist "^2.1.2"
|
||||
|
||||
minimatch@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@^3.0.0:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.4.tgz#3fbca2d8838111048232de54cb532bd3cf134947"
|
||||
integrity sha512-WvYJRN7mMyOLurFR2YpysQGuwYrJN+qrrpHjJDuKMcSPdfFccRUla/kng2mz6HWSBxJcqPbvatS6Gb4RhOzCJw==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
nopt@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
|
||||
integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
proto-list@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
|
||||
integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
|
||||
|
||||
pseudomap@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||
|
||||
semver@^5.6.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
sigmund@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
|
||||
integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
|
||||
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
yallist@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
|
Loading…
Reference in a new issue