From 854e376a6af8fe7206324db9b2bef6156cf94a4c Mon Sep 17 00:00:00 2001 From: Andre Staltz Date: Tue, 6 Jun 2023 14:04:32 +0300 Subject: [PATCH] init --- .gitignore | 5 ++ HOMEPAGE.md | 13 ++++ lib/index.js | 44 +++++++++++++ lib/public/invite.js | 41 ++++++++++++ lib/public/style.css | 152 +++++++++++++++++++++++++++++++++++++++++++ lib/views/index.ejs | 9 +++ lib/views/invite.ejs | 17 +++++ package.json | 51 +++++++++++++++ 8 files changed, 332 insertions(+) create mode 100644 .gitignore create mode 100644 HOMEPAGE.md create mode 100644 lib/index.js create mode 100644 lib/public/invite.js create mode 100644 lib/public/style.css create mode 100644 lib/views/index.ejs create mode 100644 lib/views/invite.ejs create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3566222 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +pnpm-lock.yaml +package-lock.json +yarn.lock +TODO \ No newline at end of file diff --git a/HOMEPAGE.md b/HOMEPAGE.md new file mode 100644 index 0000000..293c170 --- /dev/null +++ b/HOMEPAGE.md @@ -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 diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..4356861 --- /dev/null +++ b/lib/index.js @@ -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); + } +}); diff --git a/lib/public/invite.js b/lib/public/invite.js new file mode 100644 index 0000000..df69afc --- /dev/null +++ b/lib/public/invite.js @@ -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'); +} diff --git a/lib/public/style.css b/lib/public/style.css new file mode 100644 index 0000000..f330823 --- /dev/null +++ b/lib/public/style.css @@ -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; +} \ No newline at end of file diff --git a/lib/views/index.ejs b/lib/views/index.ejs new file mode 100644 index 0000000..49363a4 --- /dev/null +++ b/lib/views/index.ejs @@ -0,0 +1,9 @@ + + + + + + +
<%- markdown %>
+ + diff --git a/lib/views/invite.ejs b/lib/views/invite.ejs new file mode 100644 index 0000000..d8dd915 --- /dev/null +++ b/lib/views/invite.ejs @@ -0,0 +1,17 @@ + + + + + + +
+

Join PPPPP

+ Claim invite + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..ff3a262 --- /dev/null +++ b/package.json @@ -0,0 +1,51 @@ +{ + "name": "ppppp-hub", + "version": "0.0.1", + "description": "PPPPP hub server", + "author": "Andre Staltz ", + "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" + } + } +}