This commit is contained in:
Andre Staltz 2023-06-06 14:04:32 +03:00
commit 854e376a6a
No known key found for this signature in database
GPG Key ID: 9EDE23EA7E8A4890
8 changed files with 332 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
node_modules
pnpm-lock.yaml
package-lock.json
yarn.lock
TODO

13
HOMEPAGE.md Normal file
View File

@ -0,0 +1,13 @@
# My Hub
Welcome to this hub!
> Blockquote
This is **bold** while this is _italic_.
This is a [link](https://staltz.com).
- This is a list
- With items
- And more items

44
lib/index.js Normal file
View File

@ -0,0 +1,44 @@
const fastify = require('fastify');
const fastifyView = require('@fastify/view');
const fastifyMarkdown = require('fastify-markdown');
const fastifyStatic = require('@fastify/static');
const ejs = require('ejs');
const fs = require('fs');
const path = require('path');
const staticsPath = path.join(__dirname, 'public');
const viewsPath = path.join(__dirname, 'views');
const homepagePath = path.join(__dirname, '..', 'HOMEPAGE.md');
const homepageMD = fs.readFileSync(homepagePath, 'utf8');
const app = fastify({logger: true});
app.register(fastifyView, {
engine: {ejs},
root: viewsPath,
});
app.register(fastifyMarkdown, {
src: false,
});
app.register(fastifyStatic, {
root: staticsPath,
});
app.get('/', (req, reply) => {
const markdown = reply.markdown().parse(homepageMD);
reply.view('index.ejs', {markdown});
});
app.get('/invite', (req, reply) => {
reply.view('invite.ejs');
});
app.listen({port: 3000}, (err, address) => {
app.log.info(`server listening on ${address}`);
if (err) {
app.log.error(err);
process.exit(1);
}
});

41
lib/public/invite.js Normal file
View File

@ -0,0 +1,41 @@
let hasFocus = true;
window.addEventListener('blur', () => {
hasFocus = false;
});
window.addEventListener('focus', () => {
hasFocus = true;
});
const inviteLinkElem = document.getElementById('invite');
const failureElem = document.getElementById('failure');
const hash = window.location.hash;
if (hash) {
let uri = decodeURIComponent(hash.slice(1));
if (!uri.startsWith('ppppp:')) uri = 'ppppp://invite' + uri;
inviteLinkElem.href = uri;
// Autoredirect to the PPPPP URI as soon as possible
setTimeout(() => {
console.log(uri);
// window.location.replace(uri);
}, 100);
// Redirect to uri or show failure state
// FIXME:
// inviteLinkElem.onclick = function handleURI(ev) {
// ev.preventDefault();
// const uri = inviteLinkElem.href;
// inviteLinkElem.classList.remove('hidden');
// setTimeout(function () {
// if (hasFocus) {
// inviteLinkElem.classList.add('hidden');
// failureElem.classList.remove('hidden');
// }
// }, 5000);
// window.location.replace(uri);
// };
} else {
inviteLinkElem.classList.add('hidden');
failureElem.classList.remove('hidden');
}

152
lib/public/style.css Normal file
View File

@ -0,0 +1,152 @@
:root {
--color-bg-void: #f6f5f5;
--color-bg-text: #fff;
--color-bg-text-border: #e8e8e8;
--color-text: #111;
--color-text-weak: #777;
--color-text-very-weak: #ddd;
--color-button: hsl(350, 87%, 65%);
--color-button-hover: hsl(350, 87%, 70%);
--color-link: hsl(350, 87%, 55%);
--space-tiny: 4px;
--space-small: 10px;
--space-normal: 20px;
--space-big: 32px;
color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
:root {
/* Colors */
--color-bg-void: #111114;
--color-bg-text: #333337;
--color-bg-text-border: #414145;
--color-text: #f3f3f3;
--color-text-weak: #ababab;
--color-text-very-weak: #666;
--color-button: hsl(350, 87%, 65%);
--color-button-hover: hsl(350, 87%, 70%);
--color-link: hsl(350, 87%, 70%);
color-scheme: light dark;
}
}
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
color: var(--color-text);
background-color: var(--color-bg-void);
padding: 0;
margin: 0;
}
article {
max-width: 600px;
margin: var(--space-normal) auto;
background-color: var(--color-bg-text);
padding: var(--space-normal);
border-radius: var(--space-small);
box-shadow: 0 var(--space-normal) var(--space-big) rgba(0, 0, 0, 0.03);
border: 1px solid var(--color-bg-text-border);
}
a {
color: var(--color-link);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: var(--space-small);
font-weight: 500;
line-height: 1.1;
}
h1 {
font-size: 32px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 20px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 12px;
}
p {
margin-top: 0;
margin-bottom: var(--space-small);
}
blockquote {
margin: 0 0 var(--space-small);
padding: 0 var(--space-small);
color: var(--color-text-weak);
border-left: var(--space-tiny) solid var(--color-text-very-weak);
}
img {
max-width: 100%;
}
hr {
height: 4px;
padding: 0;
margin: 20px 0;
background-color: #ddd;
border: 0 none;
}
ul {
padding-left: var(--space-normal);
}
a.btn {
background: var(--color-button);
border-radius: 999px;
box-shadow: var(--color-button) 0 10px 20px -10px;
box-sizing: border-box;
color: #fff;
cursor: pointer;
font-size: 16px;
font-weight: 700;
line-height: 24px;
opacity: 1;
outline: 0 solid transparent;
padding: 8px 18px;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
width: fit-content;
word-break: break-word;
border: 0;
}
a.btn:hover {
text-decoration: none;
background: var(--color-button-hover);
}
.hidden {
display: none;
}

9
lib/views/index.ejs Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<article><%- markdown %></article>
</body>
</html>

17
lib/views/invite.ejs Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<article>
<h1>Join PPPPP</h1>
<a id="invite" class="btn" href="#">Claim invite</a>
<p id="failure" class="hidden">
Sorry, it seems like you have no actual invite code in the link you
opened.
</p>
</article>
<script src="/invite.js"></script>
</body>
</html>

51
package.json Normal file
View File

@ -0,0 +1,51 @@
{
"name": "ppppp-hub",
"version": "0.0.1",
"description": "PPPPP hub server",
"author": "Andre Staltz <contact@staltz.com>",
"license": "MIT",
"homepage": "https://github.com/staltz/ppppp-hub",
"repository": {
"type": "git",
"url": "git@github.com:staltz/ppppp-hub.git"
},
"main": "index.js",
"files": [
"*.js",
"lib/*.js"
],
"exports": {
".": {
"require": "./lib/index.js"
}
},
"type": "commonjs",
"engines": {
"node": ">=16"
},
"dependencies": {
"@fastify/static": "6.10.2",
"@fastify/view": "7.4.1",
"ejs": "3.1.9",
"fastify": "4.17.0",
"fastify-markdown": "0.4.0"
},
"devDependencies": {
"c8": "7",
"prettier": "^2.6.2",
"pretty-quick": "^3.1.3",
"tap-arc": "^0.3.5",
"tape": "^5.6.3"
},
"scripts": {
"test": "tape test/*.js | tap-arc --bail",
"format-code": "prettier --write \"(lib|test)/**/*.js\"",
"format-code-staged": "pretty-quick --staged --pattern \"(lib|test)/**/*.js\"",
"coverage": "c8 --reporter=lcov npm run test"
},
"husky": {
"hooks": {
"pre-commit": "npm run format-code-staged"
}
}
}