Initial commit
This commit is contained in:
parent
e19790b891
commit
170431ff3e
11
README.md
11
README.md
|
@ -1,11 +0,0 @@
|
||||||
# oasis
|
|
||||||
oasis
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
Command | Description |
|
|
||||||
-----------------------|--------------------------------------------------|
|
|
||||||
`$ npm start` | Start the development server
|
|
||||||
`$ npm test` | Lint, validate deps & run tests
|
|
||||||
`$ npm run build` | Compile all files into `dist/`
|
|
||||||
`$ npm run create` | Generate a scaffold file
|
|
||||||
`$ npm run inspect` | Inspect the bundle's dependencies
|
|
BIN
assets/icon.png
BIN
assets/icon.png
Binary file not shown.
Before Width: | Height: | Size: 302 B |
98
index.js
98
index.js
|
@ -1,18 +1,88 @@
|
||||||
var css = require('sheetify')
|
const Koa = require('koa')
|
||||||
var choo = require('choo')
|
const path = require('path')
|
||||||
|
const pull = require('pull-stream')
|
||||||
|
const router = require('koa-router')()
|
||||||
|
const views = require('koa-views')
|
||||||
|
const cooler = require('./lib/cooler')
|
||||||
|
const md = require('ssb-markdown')
|
||||||
|
const lodash = require('lodash')
|
||||||
|
const prettyMs = require('pretty-ms')
|
||||||
|
|
||||||
css('tachyons')
|
const app = module.exports = new Koa()
|
||||||
|
|
||||||
var app = choo()
|
app.use(views(path.join(__dirname, 'views'), {
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
map: { html: 'swig' }
|
||||||
app.use(require('choo-devtools')())
|
}))
|
||||||
} else {
|
|
||||||
app.use(require('choo-service-worker')())
|
router
|
||||||
|
.get('/', home)
|
||||||
|
|
||||||
|
app.use(router.routes())
|
||||||
|
|
||||||
|
async function home (ctx) {
|
||||||
|
var ssb = await cooler.connect()
|
||||||
|
var whoami = await cooler.get(ssb.whoami)
|
||||||
|
|
||||||
|
const userName = await cooler.get(
|
||||||
|
ssb.about.socialValue, {
|
||||||
|
key: 'name',
|
||||||
|
dest: whoami.id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var msgSource = await cooler.read(
|
||||||
|
ssb.messagesByType, {
|
||||||
|
type: 'post',
|
||||||
|
reverse: true,
|
||||||
|
limit: 32
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const rawMsgs = await new Promise((resolve, reject) => {
|
||||||
|
pull(
|
||||||
|
msgSource,
|
||||||
|
pull.collect((err, msgs) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(msgs)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const msgs = await Promise.all(rawMsgs.map(async (msg) => {
|
||||||
|
lodash.set(msg, 'value.meta.md.block', () =>
|
||||||
|
md.block(msg.value.content.text)
|
||||||
|
)
|
||||||
|
|
||||||
|
const name = await cooler.get(
|
||||||
|
ssb.about.socialValue, { key: 'name',
|
||||||
|
dest: msg.value.author
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const avatarMsg = await cooler.get(
|
||||||
|
ssb.about.socialValue, { key: 'image',
|
||||||
|
dest: msg.value.author
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const avatarId = avatarMsg != null && typeof avatarMsg.link === 'string'
|
||||||
|
? avatarMsg.link
|
||||||
|
: avatarMsg
|
||||||
|
|
||||||
|
const avatarUrl = `http://localhost:8989/blobs/get/${avatarId}`
|
||||||
|
|
||||||
|
const ts = new Date(msg.value.timestamp)
|
||||||
|
lodash.set(msg, 'value.meta.timestamp.received.iso8601', ts.toISOString())
|
||||||
|
lodash.set(msg, 'value.meta.timestamp.received.since', prettyMs(Date.now() - ts, { compact: true }))
|
||||||
|
lodash.set(msg, 'value.meta.author.name', name)
|
||||||
|
lodash.set(msg, 'value.meta.author.avatar', {
|
||||||
|
id: avatarId,
|
||||||
|
url: avatarUrl
|
||||||
|
})
|
||||||
|
|
||||||
|
return msg
|
||||||
|
}))
|
||||||
|
|
||||||
|
await ctx.render('home', { whoami, msgs, userName })
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(require('./stores/clicks'))
|
if (!module.parent) app.listen(3000)
|
||||||
|
|
||||||
app.route('/', require('./views/main'))
|
|
||||||
app.route('/*', require('./views/404'))
|
|
||||||
|
|
||||||
module.exports = app.mount('body')
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
const ssbClient = require('ssb-client')
|
||||||
|
|
||||||
|
// a water cooler API
|
||||||
|
module.exports = {
|
||||||
|
connect: function () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
ssbClient((err, api) => {
|
||||||
|
if (err) reject(err)
|
||||||
|
resolve(api)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
get: function (method, ...opts) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
method(...opts, (err, val) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(val)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
read: function (method, ...args) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
resolve(method(...args))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"name": "oasis",
|
|
||||||
"short_name": "oasis",
|
|
||||||
"description": "oasis",
|
|
||||||
"start_url": "/",
|
|
||||||
"display": "standalone",
|
|
||||||
"background_color": "#000",
|
|
||||||
"theme_color": "#000",
|
|
||||||
"icons": [{
|
|
||||||
"src": "/assets/icon.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "512x512"
|
|
||||||
}]
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
35
package.json
35
package.json
|
@ -1,26 +1,21 @@
|
||||||
{
|
{
|
||||||
"name": "oasis",
|
"name": "oasis",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"main": "index.js",
|
||||||
"scripts": {
|
"author": "Christian Bundy <christianbundy@fraction.io>",
|
||||||
"build": "bankai build index.js",
|
"license": "MIT",
|
||||||
"create": "choo-scaffold",
|
|
||||||
"inspect": "bankai inspect index.js",
|
|
||||||
"start": "bankai start index.js",
|
|
||||||
"test": "standard && npm run test-deps",
|
|
||||||
"test-deps": "dependency-check . && dependency-check . --extra --no-dev -i tachyons"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"choo": "^6.13.3",
|
"ejs": "^2.6.2",
|
||||||
"choo-service-worker": "^3.0.0",
|
"handlebars": "^4.1.2",
|
||||||
"sheetify": "^7.4.0",
|
"hbs": "^4.0.4",
|
||||||
"tachyons": "^4.11.1"
|
"koa": "^2.7.0",
|
||||||
},
|
"koa-router": "^7.4.0",
|
||||||
"devDependencies": {
|
"koa-views": "^6.2.0",
|
||||||
"bankai": "^9.15.0",
|
"lodash": "^4.17.11",
|
||||||
"choo-devtools": "^3.0.0",
|
"pretty-ms": "^5.0.0",
|
||||||
"choo-scaffold": "^1.2.0",
|
"pull-stream": "^3.6.12",
|
||||||
"dependency-check": "^3.3.0",
|
"ssb-client": "^4.7.7",
|
||||||
"standard": "^12.0.1"
|
"ssb-markdown": "^5.0.1",
|
||||||
|
"swig": "^1.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
module.exports = store
|
|
||||||
|
|
||||||
function store (state, emitter) {
|
|
||||||
state.totalClicks = 0
|
|
||||||
|
|
||||||
emitter.on('DOMContentLoaded', function () {
|
|
||||||
emitter.on('clicks:add', function (count) {
|
|
||||||
state.totalClicks += count
|
|
||||||
emitter.emit(state.events.RENDER)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
28
sw.js
28
sw.js
|
@ -1,28 +0,0 @@
|
||||||
/* eslint-env serviceworker */
|
|
||||||
|
|
||||||
var VERSION = require('./package.json').version
|
|
||||||
var URLS = process.env.FILE_LIST
|
|
||||||
|
|
||||||
// Respond with cached resources
|
|
||||||
self.addEventListener('fetch', function (e) {
|
|
||||||
e.respondWith(self.caches.match(e.request).then(function (request) {
|
|
||||||
if (request) return request
|
|
||||||
else return self.fetch(e.request)
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
// Register worker
|
|
||||||
self.addEventListener('install', function (e) {
|
|
||||||
e.waitUntil(self.caches.open(VERSION).then(function (cache) {
|
|
||||||
return cache.addAll(URLS)
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
// Remove outdated resources
|
|
||||||
self.addEventListener('activate', function (e) {
|
|
||||||
e.waitUntil(self.caches.keys().then(function (keyList) {
|
|
||||||
return Promise.all(keyList.map(function (key, i) {
|
|
||||||
if (keyList[i] !== VERSION) return self.caches.delete(keyList[i])
|
|
||||||
}))
|
|
||||||
}))
|
|
||||||
})
|
|
15
views/404.js
15
views/404.js
|
@ -1,15 +0,0 @@
|
||||||
var html = require('choo/html')
|
|
||||||
|
|
||||||
var TITLE = 'oasis - route not found'
|
|
||||||
|
|
||||||
module.exports = view
|
|
||||||
|
|
||||||
function view (state, emit) {
|
|
||||||
if (state.title !== TITLE) emit(state.events.DOMTITLECHANGE, TITLE)
|
|
||||||
return html`
|
|
||||||
<body class="sans-serif pa3">
|
|
||||||
<h1>Route not found.</h1>
|
|
||||||
<a class="pt2" href="/">Back to main.</a>
|
|
||||||
</body>
|
|
||||||
`
|
|
||||||
}
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% for msg in msgs %}
|
||||||
|
<section class="message">
|
||||||
|
<header>
|
||||||
|
<img class="avatar" src="{{ msg.value.meta.author.avatar.url }}">
|
||||||
|
|
||||||
|
<span class="text">
|
||||||
|
<span class="author">
|
||||||
|
{{ msg.value.meta.author.name}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="timestamp">
|
||||||
|
({{ msg.value.meta.timestamp.received.since }})
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if msg.value.content.root == null %}
|
||||||
|
🌱
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="content">
|
||||||
|
{{ msg.value.meta.md.block() }}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<a href="ssb:{{ msg.key }}">link</a>
|
||||||
|
{% if msg.value.content.root %}
|
||||||
|
<a href="ssb:{{ msg.value.content.root }}">root</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if msg.value.content.fork %}
|
||||||
|
<a href="ssb:{{ msg.value.content.fork }}">fork</a>
|
||||||
|
{% endif %}
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Blog</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,90 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{% block title %}Oasis{% endblock %}</title>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
font-family: system-ui,
|
||||||
|
-apple-system, BlinkMacSystemFont,
|
||||||
|
"Segoe UI", "Roboto", "Oxygen",
|
||||||
|
"Ubuntu", "Cantarell", "Fira Sans",
|
||||||
|
"Droid Sans", "Helvetica Neue", sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 12pt;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
/* https://www.desmos.com/calculator/3elcf5cwhn */
|
||||||
|
h1 { font-size: 150%; }
|
||||||
|
h2 { font-size: 128%; }
|
||||||
|
h3 { font-size: 120%; }
|
||||||
|
h4 { font-size: 116%; }
|
||||||
|
h5 { font-size: 113%; }
|
||||||
|
h6 { font-size: 111%; }
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
border-bottom: 1px solid #0000001a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message pre {
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message code {
|
||||||
|
color: hsl(330, 75%, 50%)
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen {
|
||||||
|
html {
|
||||||
|
min-height: 100%;
|
||||||
|
background: hsl(240, 100%, 99%);
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
max-width: 40rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
background: #fff;
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin: 2rem 0;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
|
||||||
|
}
|
||||||
|
.message > header {
|
||||||
|
height: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.message > header > .avatar {
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
}
|
||||||
|
.message > header > .text > .author {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.message > footer > a {
|
||||||
|
color: #888;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section id="content">
|
||||||
|
{% block content %}
|
||||||
|
<p>Missing content!</p>
|
||||||
|
{% endblock %}
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
158
views/main.js
158
views/main.js
|
@ -1,158 +0,0 @@
|
||||||
var html = require('choo/html')
|
|
||||||
|
|
||||||
var TITLE = 'oasis - main'
|
|
||||||
|
|
||||||
module.exports = view
|
|
||||||
|
|
||||||
function view (state, emit) {
|
|
||||||
if (state.title !== TITLE) emit(state.events.DOMTITLECHANGE, TITLE)
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<body class="code lh-copy">
|
|
||||||
<main class="pa3 cf center">
|
|
||||||
<section class="fl mw6 w-50-m w-third-l pa3">
|
|
||||||
<h2>1.</h2>
|
|
||||||
<p>
|
|
||||||
Welcome to your new Choo application.
|
|
||||||
We're very happy you've made it this far.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
You're now in control of your own Choo app. The moment you decide to
|
|
||||||
deploy it, it'll work offline and on any device.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="fl mw6 w-50-m w-third-l pa3">
|
|
||||||
<h2>2.</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
We've outfitted your project with a small selection of commands to
|
|
||||||
help you achieve results faster:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>npm start</strong><br>
|
|
||||||
start your project for local development.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>npm run build</strong><br>
|
|
||||||
compile your project for production.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>npm run inspect</strong><br>
|
|
||||||
visualize your project's dependencies.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>npm run create</strong><br>
|
|
||||||
scaffold a new file.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="fl mw6 w-50-m w-third-l pa3">
|
|
||||||
<h2>3.</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Your project also comes with a few directories. These names have
|
|
||||||
special meanings for the build tool, so it's good to know what they
|
|
||||||
do.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>assets/</strong><br>
|
|
||||||
Static files that can be served up, such as images and fonts.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>components/</strong><br>
|
|
||||||
Reusable fragments that can be composed into views.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>stores/</strong><br>
|
|
||||||
Pieces of logic that are shared by multiple components.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>views/</strong><br>
|
|
||||||
Combinations of components that are mapped to routes.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="fl mw6 w-50-m w-third-l pa3">
|
|
||||||
<h2>4.</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
So far we've provided you with one base view, <a
|
|
||||||
href="/oh-no">one fallback view</a>, and one store. This serves
|
|
||||||
as an example. A place to start from. It's your project now, so
|
|
||||||
go ahead and delete them once you know how they work.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Number of clicks stored: ${state.totalClicks}</p>
|
|
||||||
|
|
||||||
<button class="dim ph3 ba bw1 pv2 b--black pointer bg-white"
|
|
||||||
onclick=${handleClick}>
|
|
||||||
Emit a click event
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<br><br>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="fl mw6 w-50-m w-third-l pa3">
|
|
||||||
<h2>5.</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To make your development journey more pleasant, we've also
|
|
||||||
included <a
|
|
||||||
href="https://github.com/choojs/choo-devtools">devtools</a>. If
|
|
||||||
you open your browser console, here's a selection of the
|
|
||||||
commands that are at your disposal:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>choo.state</strong><br>
|
|
||||||
Log the current application state.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>choo.log</strong><br>
|
|
||||||
Log the last 150 events received by the event bus.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>choo.emit</strong><br>
|
|
||||||
Emit an event inside the application event bus.
|
|
||||||
</li>
|
|
||||||
<li class="mb3">
|
|
||||||
<strong>choo.help</strong><br>
|
|
||||||
See an overview of all available commands.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="fl mw6 w-50-m w-third-l pa3">
|
|
||||||
<h2>6.</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
And that's about it! Thanks for reading. If you have any
|
|
||||||
questions, check out the <a href="https://choo.io">docs</a> or reach
|
|
||||||
out on <a href="https://github.com/choojs/choo">GitHub</a> or <a
|
|
||||||
href="https://www.irccloud.com/irc/freenode/channel/choo">IRC</a>.
|
|
||||||
We're online everyday, and always around to help. Happy hacking!
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
`
|
|
||||||
|
|
||||||
function handleClick () {
|
|
||||||
emit('clicks:add', 1)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue