add projects
page that uses gitea api
This commit is contained in:
parent
24d5798d8a
commit
9690372b01
12 changed files with 252 additions and 103 deletions
15
build.js
15
build.js
|
@ -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);
|
||||
|
|
|
@ -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
83
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-beautify": "^1.14.0"
|
||||
"js-beautify": "^1.14.0",
|
||||
"node-fetch": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>`;
|
|
@ -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>
|
||||
|
|
|
@ -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
24
src/env/index.js
vendored
|
@ -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."
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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
25
src/projects.page.js
Normal 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")
|
||||
}
|
||||
`);
|
Loading…
Reference in a new issue