mirror of https://codeberg.org/pzp/pzp-hub.git
init
This commit is contained in:
commit
854e376a6a
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules
|
||||||
|
pnpm-lock.yaml
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
TODO
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
});
|
|
@ -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');
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<article><%- markdown %></article>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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>
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue