add projects page that uses gitea api

This commit is contained in:
hippoz 2021-10-18 21:54:41 +03:00
parent 24d5798d8a
commit 9690372b01
No known key found for this signature in database
GPG key ID: 7C52899193467641
12 changed files with 252 additions and 103 deletions

View file

@ -46,10 +46,11 @@ const specialCharacter = (c) => {
return "";
}
const processPageOutput = (out) => {
if (typeof out !== "string") {
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();
@ -69,13 +70,13 @@ const findAllPages = async (directory) =>
)
.map(f => directory + "/" + f); // TODO: hack
const buildPage = (pagePath) => processPageOutput(require(pagePath));
const buildPage = async (pagePath) => await processPageOutput(require(pagePath));
const buildAllPages = async (directory) =>
(await findAllPages(directory))
await Promise.all((await findAllPages(directory))
.map(
p => [p, buildPage(p)]
);
async p => [p, (await buildPage(p))]
));
const exportAllPages = async (sourcePath, outputPath) => {
const pages = await buildAllPages(sourcePath);

View file

@ -1,106 +1,133 @@
:root {
--body-bg-color: #2E2E2E;
--accent-bg-color: #d4d3d3;
--button-accent-color: #3d3d3d;
--selected-bg-color: #2E2E2E;
--hover-bg-color: #4d4d4d;
--card-border-radius: 8px;
--button-border-radius: 6px;
--main-font-weight: 500;
--cards-length: 600px;
--body-bg-color: #2e2e2e;
--accent-bg-color: #d4d3d3;
--accent-color: #949494;
--grayed-text-color: #949494;
--button-accent-color: #3d3d3d;
--selected-bg-color: #2e2e2e;
--hover-bg-color: #4d4d4d;
--card-border-radius: 8px;
--button-border-radius: 8px;
--main-font-weight: 500;
--cards-length: 675px;
--fonts-regular: "Noto Sans","Liberation Sans",sans-serif;
--fonts-regular: "Noto Sans", "Liberation Sans", sans-serif;
}
body {
background-color: var(--body-bg-color);
background-image: url(wave.svg);
background-size: 100% auto;
background-repeat: no-repeat;
font-family: var(--fonts-regular);
font-weight: var(--main-font-weight);
background-color: var(--body-bg-color);
background-image: url(wave.svg);
background-size: 100% auto;
background-repeat: no-repeat;
font-family: var(--fonts-regular);
font-weight: var(--main-font-weight);
color: #000000;
}
br {
display: block;
content: "";
margin-top: 2px;
display: block;
content: "";
margin-top: 2px;
}
.card {
margin: 36px auto;
padding: 26px;
background: var(--accent-bg-color);
border-radius: var(--card-border-radius);
margin: 6px;
padding: 8px;
background: var(--accent-bg-color);
border-radius: var(--card-border-radius);
}
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.45);
.card.inner-card {
margin: 4px;
margin-bottom: 28px;
padding: 18px;
border: solid var(--accent-color) 1px;
}
.card.layout-card {
width: var(--cards-length);
margin: 36px auto;
padding: 26px;
width: var(--cards-length);
box-shadow: 0 0 28px 3px rgba(0, 0, 0, 0.40);
}
.navigation-buttons {
text-align: right;
.grayed-out {
color: var(--grayed-text-color);
}
.navigation-branding {
float: left;
.align-right {
text-align: right;
}
.float-right {
float: right;
}
.float-left {
float: left;
}
.navigation-branding-text {
text-decoration: none;
display: inline-block;
padding: 8px;
font-size: 18px;
white-space: nowrap;
margin-left: 10px;
margin-right: 10px;
text-decoration: none;
display: inline-block;
padding: 8px;
font-size: 18px;
white-space: nowrap;
margin-left: 10px;
margin-right: 10px;
}
.noselect {
user-select: none;
user-select: none;
}
.button-default {
display: inline-block;
text-decoration: none;
font-weight: 500;
border: none;
background-color: var(--accent-bg-color);
border-radius: var(--button-border-radius);
padding: 8px;
font-size: 18px;
white-space: nowrap;
margin-left: 10px;
margin-right: 10px;
color: var(--button-accent-color);
cursor: pointer;
outline: none;
min-width: 56px;
text-align: center;
display: inline-block;
text-decoration: none;
border: none;
background-color: var(--accent-bg-color);
border-radius: var(--button-border-radius);
padding: 8px;
font-size: 18px;
white-space: nowrap;
margin-left: 10px;
margin-right: 10px;
color: var(--button-accent-color);
cursor: pointer;
outline: none;
min-width: 56px;
text-align: center;
}
.button-default:hover:not(.button-selected) {
color: var(--accent-bg-color);
background-color: var(--hover-bg-color);
color: var(--accent-bg-color);
background-color: var(--hover-bg-color);
}
.button-selected {
color: var(--accent-bg-color);
background-color: var(--selected-bg-color);
color: var(--accent-bg-color);
background-color: var(--selected-bg-color);
}
.input {
border: none;
outline: none;
border-radius: 2px;
padding: 3px;
margin: 8px;
border: none;
outline: none;
border-radius: 2px;
padding: 3px;
margin: 8px;
}
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.column {
flex-basis: 100%;
}
@media screen and (max-width: 768px) {
.card.layout-card {
width: 85%;
}
}
.card.layout-card {
width: 80%;
}
}

83
package-lock.json generated
View file

@ -9,7 +9,8 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"js-beautify": "^1.14.0"
"js-beautify": "^1.14.0",
"node-fetch": "^3.0.0"
}
},
"node_modules/abbrev": {
@ -50,6 +51,14 @@
"proto-list": "~1.2.1"
}
},
"node_modules/data-uri-to-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
"integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
"engines": {
"node": ">= 6"
}
},
"node_modules/editorconfig": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
@ -64,6 +73,27 @@
"editorconfig": "bin/editorconfig"
}
},
"node_modules/fetch-blob": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.2.tgz",
"integrity": "sha512-hunJbvy/6OLjCD0uuhLdp0mMPzP/yd2ssd1t2FCJsaA7wkWhpbp9xfuNVpv7Ll4jFhzp6T4LAupSiV9uOeg0VQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -146,6 +176,22 @@
"node": "*"
}
},
"node_modules/node-fetch": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0.tgz",
"integrity": "sha512-bKMI+C7/T/SPU1lKnbQbwxptpCrG9ashG+VkytmXCPZyuM9jB6VU+hY0oi4lC8LxTtAeWdckNCTa3nrGsAdA3Q==",
"dependencies": {
"data-uri-to-buffer": "^3.0.1",
"fetch-blob": "^3.1.2"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@ -199,6 +245,14 @@
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"node_modules/web-streams-polyfill": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.1.1.tgz",
"integrity": "sha512-Czi3fG883e96T4DLEPRvufrF2ydhOOW1+1a6c3gNjH2aIh50DNFBdfwh2AKoOf1rXvpvavAoA11Qdq9+BKjE0Q==",
"engines": {
"node": ">= 8"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@ -249,6 +303,11 @@
"proto-list": "~1.2.1"
}
},
"data-uri-to-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
"integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og=="
},
"editorconfig": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
@ -260,6 +319,14 @@
"sigmund": "^1.0.1"
}
},
"fetch-blob": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.2.tgz",
"integrity": "sha512-hunJbvy/6OLjCD0uuhLdp0mMPzP/yd2ssd1t2FCJsaA7wkWhpbp9xfuNVpv7Ll4jFhzp6T4LAupSiV9uOeg0VQ==",
"requires": {
"web-streams-polyfill": "^3.0.3"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -325,6 +392,15 @@
"brace-expansion": "^1.1.7"
}
},
"node-fetch": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0.tgz",
"integrity": "sha512-bKMI+C7/T/SPU1lKnbQbwxptpCrG9ashG+VkytmXCPZyuM9jB6VU+hY0oi4lC8LxTtAeWdckNCTa3nrGsAdA3Q==",
"requires": {
"data-uri-to-buffer": "^3.0.1",
"fetch-blob": "^3.1.2"
}
},
"nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@ -366,6 +442,11 @@
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"web-streams-polyfill": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.1.1.tgz",
"integrity": "sha512-Czi3fG883e96T4DLEPRvufrF2ydhOOW1+1a6c3gNjH2aIh50DNFBdfwh2AKoOf1rXvpvavAoA11Qdq9+BKjE0Q=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

View file

@ -13,6 +13,7 @@
"author": "",
"license": "MIT",
"dependencies": {
"js-beautify": "^1.14.0"
"js-beautify": "^1.14.0",
"node-fetch": "^3.0.0"
}
}

View file

@ -2,7 +2,8 @@ const Page = require("./components/Page.component");
module.exports = Page({
title: "hippoz blog",
description: "hippoz blog"
description: "hippoz blog",
name: "blog",
})(`
<h2>hippoz's blog</h2>
<p>i think</p>

View file

@ -1 +1,2 @@
module.exports = ({ link, text }) => `<a href="${link}" class="button-default">${text}</a>`;
module.exports = ({ link, text, selected=false }) =>
`<a href="${link}" class="button-default${selected ? " button-selected" : ""}">${text}</a>`;

View file

@ -1,15 +1,20 @@
const { navigationLinks, navigationBrandingText } = require("../env");
const LinkButton = require("./LinkButton.component");
const LinkButtonComponent = require("./LinkButton.component");
module.exports = () => `
module.exports = ({ pageName }) => `
<div class="card layout-card noselect">
<div class="navigation-branding">
<div class="float-left">
<b class="navigation-branding-text">${navigationBrandingText}</b>
</div>
<div class="navigation-buttons">
<div class="align-right">
${
navigationLinks.map(
([link, text]) => LinkButton({ link, text })
({link, text, name}) =>
LinkButtonComponent({
link,
text,
selected: name === pageName
})
).join("")
}
</div>

View file

@ -1,6 +1,6 @@
const Navigation = require("./Navigation.component");
const NavigationComponent = require("./Navigation.component");
module.exports = ({ title="page", description="a page" }) => (content) =>
module.exports = ({ title="page", description="a page", name="page" }) => (content) =>
`<!DOCTYPE html>
<html lang="en">
<head>
@ -11,7 +11,9 @@ module.exports = ({ title="page", description="a page" }) => (content) =>
<link rel="stylesheet" href="res/style.css">
</head>
<body>
${Navigation()}
${NavigationComponent({
pageName: name
})}
<div class="card layout-card">
${content}
</div>

24
src/env/index.js vendored
View file

@ -1,9 +1,25 @@
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
module.exports = {
navigationLinks: [
["index.html", "home"],
["blog.html", "blog"],
["me.html", "me"],
["https://git.hippoz.xyz", "git"],
{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."
}

View file

@ -2,7 +2,8 @@ const Page = require("./components/Page.component");
module.exports = Page({
title: "hippoz",
description: "hippoz website homepage"
description: "hippoz website homepage",
name: "home",
})(`
<h2>hippoz's website</h2>
<p>i think</p>

View file

@ -1,12 +0,0 @@
const Page = require("./components/Page.component");
module.exports = Page({
title: "about",
description: "hippoz about page"
})(`
<h2>hello</h2>
<p>i think</p>
<br>
<br>
<p>i'm hippoz. that's about it.</p>
`);

25
src/projects.page.js Normal file
View file

@ -0,0 +1,25 @@
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")
}
`);