Initial commit

This commit is contained in:
Christian Bundy 2019-06-23 11:46:22 -07:00
parent e19790b891
commit 170431ff3e
No known key found for this signature in database
GPG Key ID: EB541AAEF4366237
15 changed files with 1630 additions and 9160 deletions

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

View File

@ -1,18 +1,88 @@
var css = require('sheetify')
var choo = require('choo')
const Koa = require('koa')
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()
if (process.env.NODE_ENV !== 'production') {
app.use(require('choo-devtools')())
} else {
app.use(require('choo-service-worker')())
app.use(views(path.join(__dirname, 'views'), {
map: { html: 'swig' }
}))
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'))
app.route('/', require('./views/main'))
app.route('/*', require('./views/404'))
module.exports = app.mount('body')
if (!module.parent) app.listen(3000)

26
lib/cooler.js Normal file
View File

@ -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))
})
}
}

View File

@ -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"
}]
}

8888
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,21 @@
{
"name": "oasis",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "bankai build index.js",
"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"
},
"main": "index.js",
"author": "Christian Bundy <christianbundy@fraction.io>",
"license": "MIT",
"dependencies": {
"choo": "^6.13.3",
"choo-service-worker": "^3.0.0",
"sheetify": "^7.4.0",
"tachyons": "^4.11.1"
},
"devDependencies": {
"bankai": "^9.15.0",
"choo-devtools": "^3.0.0",
"choo-scaffold": "^1.2.0",
"dependency-check": "^3.3.0",
"standard": "^12.0.1"
"ejs": "^2.6.2",
"handlebars": "^4.1.2",
"hbs": "^4.0.4",
"koa": "^2.7.0",
"koa-router": "^7.4.0",
"koa-views": "^6.2.0",
"lodash": "^4.17.11",
"pretty-ms": "^5.0.0",
"pull-stream": "^3.6.12",
"ssb-client": "^4.7.7",
"ssb-markdown": "^5.0.1",
"swig": "^1.4.2"
}
}

View File

@ -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
View File

@ -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])
}))
}))
})

View File

@ -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>
`
}

42
views/home.html Normal file
View File

@ -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 %}

7
views/index.html Normal file
View File

@ -0,0 +1,7 @@
<html>
<head>
<title>Blog</title>
</head>
<body>
</body>
</html>

90
views/layout.html Normal file
View File

@ -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>

View File

@ -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)
}
}

1366
yarn.lock Normal file

File diff suppressed because it is too large Load Diff