feat: awesome ipfs website

This commit is contained in:
Henrique Dias 2018-04-23 15:22:21 +01:00
parent b26e566cb0
commit 5304c279f5
43 changed files with 1068 additions and 161 deletions

23
scripts/data.js Normal file
View file

@ -0,0 +1,23 @@
const fs = require('fs')
const path = require('path')
const yaml = require('node-yaml')
const { sortAbc } = require('./utils')
const dataDir = path.join(__dirname, '../data')
const trimIfExists = (str) => str ? str.trim() : undefined
const files = fs.readdirSync(dataDir)
.map(file => path.join(dataDir, file))
.map(file => yaml.readSync(file))
.map(file => {
file.content = file.content.map(({ title, description, ...file }) => ({
title: trimIfExists(title),
description: trimIfExists(description),
...file
}))
return file
})
.sort((a, b) => sortAbc(a.title, b.title))
module.exports = files

60
scripts/dev.js Normal file
View file

@ -0,0 +1,60 @@
const chokidar = require('chokidar')
const path = require('path')
const runAll = require('npm-run-all')
const dataFolder = path.join(__dirname, '../data')
const srcFolder = path.join(__dirname, '../src')
const cssPath = path.join(__dirname, '../src/css')
const jsPath = path.join(__dirname, '../src/js')
const http = require('http')
const runHugo = () => runAll(['build:hugo'])
const handler = (path) => {
if (path.startsWith(dataFolder)) {
runAll(['build:data'], {parallel: false}).then(runHugo)
} else if (path.startsWith(cssPath)) {
runAll(['build:css'], {parallel: false}).then(runHugo)
} else if (path.startsWith(jsPath)) {
runAll(['build:js'], {parallel: false}).then(runHugo)
} else {
runHugo()
}
}
async function run () {
console.log('Preparing fonts, css, js and data...')
await runAll(['build:fonts', 'build:css', 'build:js', 'build:data'], {parallel: true})
console.log('Running Hugo once...')
await runHugo()
console.log('Starting server...')
const ecstatic = require('ecstatic')({
root: `${__dirname}/../public`,
showDir: true,
autoIndex: true
})
http.createServer(ecstatic).listen(8080)
const watcher = chokidar.watch([dataFolder, srcFolder], {
ignored: (string) => string.indexOf('src/content') !== -1 ||
string.indexOf('src/data') !== -1 ||
string.indexOf('src/resources') !== -1 ||
string.indexOf('src/layouts/partials/indexes') !== -1 ||
string.indexOf('src/static/fonts') !== -1 ||
string.indexOf('src/static/app.css') !== -1 ||
string.indexOf('src/static/app.js') !== -1,
persistent: true,
ignoreInitial: true,
awaitWriteFinish: true
})
watcher
.on('ready', () => console.log('Listening on :8080'))
.on('add', handler)
.on('change', handler)
.on('unlink', handler)
}
run()

130
scripts/make-data.js Normal file
View file

@ -0,0 +1,130 @@
const lunr = require('lunr')
const fs = require('fs-extra')
const path = require('path')
const { slugify, capitalize, sortAbc } = require('./utils')
const dataDir = path.join(__dirname, '../src/data')
const contentDir = path.join(__dirname, '../src/content')
const indexesDir = path.join(__dirname, '../src/layouts/partials/indexes')
const processDataType = (data) => {
const content = data.content.map((info, index) => {
const { website, ...more } = info
if (data.title === 'Videos' && website.includes('youtube')) {
more.youtube = website.replace('https://www.youtube.com/watch?v=', '')
}
return {
website: website,
categories: [data.title.toLowerCase()],
...more
}
})
delete data.content
return {
info: { ...data },
content: content
}
}
const writeContentFile = (data) => {
const basename = slugify(data.title)
const filename = path.join(contentDir, `${basename}.md`)
fs.writeFileSync(filename, JSON.stringify(data))
}
const makeIndex = (data) => {
const indexes = { 'index': [] }
const checkField = (field, el) => {
if (Array.isArray(el[field])) {
el[field].forEach(t => {
const key = `${field}_${t}`
if (indexes[key]) {
indexes[key].push(el.index)
} else {
indexes[key] = [el.index]
}
})
}
}
data.forEach(el => {
indexes.index.push(el.index)
checkField('tags', el)
checkField('categories', el)
})
data = data.map(({index, title, description = '', tags = [], categories = []}) => ({
ref: index,
data: `${title} ${description} ${tags.join(' ')} ${categories.join(' ')}`
}))
for (const index in indexes) {
const idx = lunr(function () {
this.ref('ref')
this.field('data')
indexes[index].map(i => data[i]).forEach(this.add.bind(this))
})
const file = path.join(indexesDir, index + '.html')
const json = JSON.stringify(idx).replace(`'`, `\\'`)
fs.writeFileSync(file, `<script>var idx = JSON.parse(\`${json}\`);</script>`)
}
}
const process = () => {
fs.ensureDirSync(dataDir)
fs.ensureDirSync(contentDir)
fs.ensureDirSync(indexesDir)
fs.emptyDirSync(dataDir)
fs.emptyDirSync(contentDir)
fs.emptyDirSync(indexesDir)
let data = []
let types = []
let typesObj = {}
require('./data')
.map(processDataType)
.forEach(({info, content}) => {
types.push(info)
data.push(content)
})
data = data.reduce((a, v) => a.concat(v), [])
.sort((a, b) => sortAbc(a.title, b.title))
.map((v, i) => { v.index = i; return v })
data.forEach(writeContentFile)
makeIndex(data)
types = types.map(t => {
t.title = capitalize(t.title)
return t
}).sort((a, b) => {
if (a.weight < b.weight) {
return -1
}
if (a.weight > b.weight) {
return 1
}
return 0
}).forEach(type => {
typesObj[type.title.toLowerCase()] = type
})
const pt = path.join(dataDir, 'categories.json')
fs.writeFileSync(pt, JSON.stringify(typesObj))
}
process()

49
scripts/make-readme.js Normal file
View file

@ -0,0 +1,49 @@
const fs = require('fs')
const path = require('path')
const files = require('./data')
const readme = path.join(__dirname, '../README.md')
const template = path.join(__dirname, 'readme-template.md')
const { slugify, sortInv, sortAbc } = require('./utils')
const toc = files.map(cat => `- [${cat.title}](#${slugify(cat.title)})`).join('\n')
const sections = files.map(category => {
let sort = (a, b) => sortAbc(a.title, b.title)
if (category.title === 'Articles') {
sort = (a, b) => sortInv(a.date, b.date)
}
const content = category.content.sort(sort).map(item => {
let block = '- '
let mainUrl = ''
if (item.website) {
mainUrl = item.website
} else if (item.source) {
mainUrl = item.source
} else if (item.demo) {
mainUrl = item.demo
}
if (item.date) block += item.date + ': '
block += `[${item.title}](${mainUrl}) `
if (item.description) block += `- ${item.description.trim()}`
if (item.demo && mainUrl !== item.demo) {
if (!item.description) block += '-'
block += ` [Demo](${item.demo})`
}
if (item.source && mainUrl !== item.source) {
block += ` [Source](${item.source})`
}
return block
}).join('\n')
return `## ${category.title}\n\n${content}`
}).join('\n\n')
fs.writeFileSync(readme, fs.readFileSync(template)
.toString()
.replace('#PLACEHOLDER_TOC#', toc)
.replace('#PLACEHOLDER_CATEGORIES#', sections))

View file

@ -0,0 +1,40 @@
# Awesome IPFS [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome)
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
> Useful resources for using [IPFS](https://ipfs.io) and building things on top of it
_This list is for projects, tools, or pretty much any things related to IPFS that
are totally_ **awesome**_. This is for products which are already awesome - if
you have plans for cool stuff to do with IPFS, you should build it, and then
link it here. If you have an idea for an awesome thing to do with IPFS, a good
place to ask about it might be in [ipfs/apps](https://github.com/ipfs/apps) or
[ipfs/notes](https://github.com/ipfs/notes)._
## Table of Contents
#PLACEHOLDER_TOC#
- [Discussions](#discussions)
- [Contribute](#contribute)
- [Want to hack on IPFS?](#want-to-hack-on-ipfs)
- [License](#license)
#PLACEHOLDER_CATEGORIES#
## Discussions
* [CRDTs discussion](https://github.com/ipfs/notes/issues/23)
## Contribute
Please add (or remove) stuff from this list if you see anything awesome! [Open an issue](https://github.com/ipfs/awesome-ipfs/issues) or a PR.
### Want to hack on IPFS?
[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md)
## License
[![CC0](https://licensebuttons.net/p/zero/1.0/88x31.png)](https://creativecommons.org/publicdomain/zero/1.0/)

31
scripts/utils.js Normal file
View file

@ -0,0 +1,31 @@
const sort = (a, b) => {
if (a < b) return -1
if (a > b) return 1
return 0
}
const sortInv = (a, b) => -sort(a, b)
const sortAbc = (a, b) => {
a = a.toLowerCase()
b = b.toLowerCase()
return sort(a, b)
}
const slugify = (text) => text.toString()
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^\w-]+/g, '')
.replace(/--+/g, '-')
.replace(/^-+/, '')
.replace(/-+$/, '')
const capitalize = (text) => `${text.charAt(0).toUpperCase()}${text.slice(1).toLowerCase()}`
module.exports = {
sort,
sortInv,
sortAbc,
slugify,
capitalize
}