Updated scripts to produce also a gemini capsule.
This commit is contained in:
parent
9420adb44a
commit
578cad3351
7 changed files with 229 additions and 34 deletions
10
layouts/gemini-comment.njk
Normal file
10
layouts/gemini-comment.njk
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% extends "gemini.njk" %}{% block content %}# {{ book.title }}
|
||||
|
||||
{{ contents | safe }}
|
||||
|
||||
({{ comment.size }} signes. Première publication {% if comment.issue %}sur {{ comment.medium | safe }} n°{{ comment.issue }}){% else %}le {{ comment.date.format('LL')}} sur {{ comment.medium | safe }}){% endif %}
|
||||
|
||||
{% if comment.source %}=> {{ comment.source }} Document original{% endif %}
|
||||
=> {{ filepath(comment.medium, ['/chroniques']) }} Toutes les chroniques sur {{ comment.medium | safe }}
|
||||
=> /chroniques Toutes les chroniques
|
||||
{% endblock %}
|
1
layouts/gemini.njk
Normal file
1
layouts/gemini.njk
Normal file
|
@ -0,0 +1 @@
|
|||
{% block content %}{{ contents | safe }}{% endblock %}
|
|
@ -5,11 +5,11 @@
|
|||
"description": "The sources for <http://david.soulayrol.name>",
|
||||
"main": "",
|
||||
"scripts": {
|
||||
"build": "DEBUG=metalsmith* npm run clean && npm run build:metalsmith",
|
||||
"build": "npm run clean && npm run build:metalsmith",
|
||||
"build:prod": "NODE_ENV=production npm run build",
|
||||
"build:metalsmith": "node scripts/run.js build",
|
||||
"clean": "rimraf dist",
|
||||
"dev": "npm run build && DEBUG=metalsmith* nodemon scripts/run.js serve",
|
||||
"dev": "npm run build && nodemon scripts/run.js serve",
|
||||
"server": "npm run build && http-server dist",
|
||||
"lint": "npm run lint:js && npm run lint:css",
|
||||
"lint:js": "eslint scripts",
|
||||
|
@ -45,7 +45,7 @@
|
|||
"moment": "^2.29.1",
|
||||
"nodemon": "^2.0.12",
|
||||
"rimraf": "^3.0.2",
|
||||
"slug": "^5.1.0",
|
||||
"slug": "^8.0.0",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-standard": "^22.0.0"
|
||||
},
|
||||
|
|
|
@ -11,10 +11,11 @@ module.exports = {
|
|||
projectRoot,
|
||||
/* Nodes */
|
||||
nodeModules: join(projectRoot, 'node_modules'),
|
||||
/* Metalsmith */
|
||||
metalsmithSource: 'content',
|
||||
metalsmithDestination: distribution,
|
||||
/* Server */
|
||||
serverRoot: distribution
|
||||
/* Gemini Distribution */
|
||||
geminiSource: 'gemini',
|
||||
geminiDestination: join(distribution, 'public_gemini'),
|
||||
/* Web Distribution */
|
||||
webSource: 'content',
|
||||
webDestination: join(distribution, 'public_html')
|
||||
}
|
||||
}
|
||||
|
|
173
scripts/metalsmith-gemini.js
Normal file
173
scripts/metalsmith-gemini.js
Normal file
|
@ -0,0 +1,173 @@
|
|||
const config = require('./config.js')
|
||||
const debug = require('debug')('gemini')
|
||||
const Metalsmith = require('metalsmith')
|
||||
const layouts = require('@metalsmith/layouts')
|
||||
const moment = require('moment')
|
||||
const path = require('path')
|
||||
const slug = require('slug')
|
||||
const statistics = require('./metalsmith-statistics-plugin')
|
||||
|
||||
const __PROD__ = process.env.NODE_ENV === 'production'
|
||||
|
||||
moment.locale('fr')
|
||||
|
||||
function store (collection, key, value) {
|
||||
if (collection[key] === undefined) { collection[key] = [] }
|
||||
collection[key].push(value)
|
||||
}
|
||||
|
||||
function isGemText (filename) {
|
||||
return /\.gmi$|\.gemini$/.test(path.extname(filename))
|
||||
}
|
||||
|
||||
function filepath (filename, segments) {
|
||||
const name = slug(filename, { mode: 'rfc3986' }) + '.gemini'
|
||||
return path.join.apply(null, (segments || ['./']).concat([name]))
|
||||
}
|
||||
|
||||
function sortedComments (metalsmith, index) {
|
||||
const sortedComments = {}
|
||||
|
||||
metalsmith.metadata().comments.forEach(entry => {
|
||||
if (index instanceof Function) {
|
||||
store(sortedComments, index(entry.comment), entry)
|
||||
} else {
|
||||
store(sortedComments, entry.comment[index], entry)
|
||||
}
|
||||
})
|
||||
|
||||
return sortedComments
|
||||
}
|
||||
|
||||
function createIndex (files, filename, body) {
|
||||
const entry = Object.assign({
|
||||
contents: Buffer.from(body)
|
||||
})
|
||||
|
||||
files[filename] = entry
|
||||
}
|
||||
|
||||
function createCommentsIndex (index, entries) {
|
||||
let body = '# ' + index + '\n\n'
|
||||
|
||||
entries.forEach(entry => {
|
||||
body += '=> /' + entry.filename + ' ' + entry.book.title + ', ' + entry.book.author
|
||||
|
||||
if (index === entry.comment.medium) {
|
||||
body += ' (' + entry.comment.date.year() + ')\n'
|
||||
} else {
|
||||
body += ' (sur ' + entry.comment.medium + ')\n'
|
||||
body += entry.comment.excerpt
|
||||
}
|
||||
})
|
||||
|
||||
body += '\n=> /chroniques Retour à la liste complète\n'
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
function rootIndexPlugin (files, metalsmith, done) {
|
||||
let body = '# Chroniques\n'
|
||||
|
||||
body += '\n## Par support\n\n'
|
||||
Object.keys(sortedComments(metalsmith, 'medium')).forEach((medium) => {
|
||||
body += '=> ' + filepath(medium, ['/chroniques']) + ' ' + medium + '\n'
|
||||
})
|
||||
|
||||
body += '\n## Par année\n\n'
|
||||
Object.keys(sortedComments(metalsmith, (c) => c.date.year())).forEach((year) => {
|
||||
body += '=> /chroniques/' + year + ' ' + year + '\n'
|
||||
})
|
||||
|
||||
createIndex(files, 'chroniques/index.gemini', body)
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
function mediaIndexPlugin (files, metalsmith, done) {
|
||||
Object.entries(sortedComments(metalsmith, 'medium')).forEach(([medium, comments]) => {
|
||||
createIndex(files, filepath(medium, ['chroniques']), createCommentsIndex(medium, comments))
|
||||
})
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
function yearsIndexPlugin (files, metalsmith, done) {
|
||||
Object.entries(sortedComments(metalsmith, (c) => c.date.year())).forEach(([year, comments]) => {
|
||||
createIndex(files, filepath('index', ['chroniques', year]), createCommentsIndex(year, comments))
|
||||
})
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
function buildCommentsMetadata (files, metalsmith, done) {
|
||||
const EXCERPT_MAX_LENGTH = 300
|
||||
|
||||
const comments = []
|
||||
|
||||
// TODO: The excerpt should take care of words boundaries
|
||||
const buildExcerpt = function (contents) {
|
||||
let length = contents.indexOf('\n')
|
||||
|
||||
if (length === -1) {
|
||||
length = contents.length
|
||||
}
|
||||
|
||||
let excerpt = contents.substr(0, Math.min(length, EXCERPT_MAX_LENGTH))
|
||||
if (length > EXCERPT_MAX_LENGTH) {
|
||||
excerpt += '…'
|
||||
}
|
||||
|
||||
return excerpt + '\n'
|
||||
}
|
||||
|
||||
Object.keys(files).forEach(filename => {
|
||||
if (isGemText(filename)) {
|
||||
const data = files[filename]
|
||||
|
||||
if (data.comment !== undefined) {
|
||||
data.comment.date = moment(data.comment.date)
|
||||
data.comment.excerpt = buildExcerpt(data.contents.toString())
|
||||
data.comment.size = data.contents.length
|
||||
data.layout = 'gemini-comment.njk'
|
||||
|
||||
comments.push({
|
||||
book: data.book,
|
||||
comment: data.comment,
|
||||
filename
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
debug('Identified %d comments: %s', comments.length)
|
||||
|
||||
/* Comment are ordered by title by default. */
|
||||
comments.sort((a, b) => a.book.title.localeCompare(b.book.title))
|
||||
metalsmith.metadata().comments = comments
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
module.exports = new Metalsmith(config.paths.projectRoot)
|
||||
.clean(__PROD__)
|
||||
.metadata({
|
||||
filepath
|
||||
})
|
||||
.source(config.paths.geminiSource)
|
||||
.destination(config.paths.geminiDestination)
|
||||
.use(buildCommentsMetadata)
|
||||
.use(rootIndexPlugin)
|
||||
.use(mediaIndexPlugin)
|
||||
.use(yearsIndexPlugin)
|
||||
// TODO: atom.xml (et lien depuis l'index)
|
||||
.use(layouts({
|
||||
default: 'gemini.njk',
|
||||
pattern: '**/*.gemini',
|
||||
engineOptions: {
|
||||
globals: {
|
||||
production: __PROD__
|
||||
}
|
||||
}
|
||||
}))
|
||||
.use(statistics())
|
|
@ -24,12 +24,12 @@ module.exports = new Metalsmith(config.paths.projectRoot)
|
|||
title: 'David Soulayrol'
|
||||
}
|
||||
})
|
||||
.source(config.paths.metalsmithSource)
|
||||
.destination(config.paths.metalsmithDestination)
|
||||
.source(config.paths.webSource)
|
||||
.destination(config.paths.webDestination)
|
||||
.use(cleanCSS({}))
|
||||
.use(assets({
|
||||
source: './assets/' + (process.env.NODE_ENV || 'dev'),
|
||||
destination: './'
|
||||
destination: config.paths.webDestination
|
||||
}))
|
||||
.use(groff({
|
||||
preprocessors: ['tbl'],
|
|
@ -1,36 +1,45 @@
|
|||
const bs = require('browser-sync').create('Metalsmith')
|
||||
const config = require('./config.js')
|
||||
const debug = require('debug')('Run')
|
||||
const metalsmith = require('./metalsmith')
|
||||
const metalsmithGemini = require('./metalsmith-gemini')
|
||||
const metalsmithWeb = require('./metalsmith-web')
|
||||
const path = require('path')
|
||||
const strip = require('strip-ansi')
|
||||
|
||||
function build (sync) {
|
||||
debug('Building Metalsmith')
|
||||
metalsmith.build((err) => {
|
||||
if (err) {
|
||||
debug('Metalsmith build error:')
|
||||
debug(err)
|
||||
if (sync) {
|
||||
return bs.sockets.emit('fullscreen:message', {
|
||||
title: 'Metalsmith Error:',
|
||||
body: strip(`${err.message}\n\n${err.stack}`),
|
||||
timeout: 100000
|
||||
})
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
debug('Metalsmith build finished!')
|
||||
function complete (dist, sync, err) {
|
||||
if (err) {
|
||||
debug(dist + ' build error:')
|
||||
debug(err)
|
||||
if (sync) {
|
||||
bs.reload()
|
||||
return bs.sockets.emit('fullscreen:message', {
|
||||
title: 'Metalsmith Error:',
|
||||
body: strip(`${err.message}\n\n${err.stack}`),
|
||||
timeout: 100000
|
||||
})
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
})
|
||||
} else {
|
||||
debug(dist + ' build finished!')
|
||||
}
|
||||
if (sync) {
|
||||
bs.reload()
|
||||
}
|
||||
}
|
||||
|
||||
function buildGemini () {
|
||||
debug('Building Gemini distribution')
|
||||
metalsmithGemini.build((err) => { complete('Gemini', false, err) })
|
||||
}
|
||||
|
||||
function buildWeb (sync) {
|
||||
debug('Building Web distribution')
|
||||
metalsmithWeb.build((err) => { complete('Web', sync, err) })
|
||||
}
|
||||
|
||||
function serve () {
|
||||
bs.init({
|
||||
server: config.paths.serverRoot,
|
||||
server: config.paths.webDestination,
|
||||
port: 8080,
|
||||
ui: {
|
||||
port: 9000
|
||||
|
@ -47,7 +56,7 @@ function serve () {
|
|||
path.resolve(config.paths.projectRoot, 'layouts', '**', '*.njk')
|
||||
],
|
||||
fn: function (event, file) {
|
||||
build(true)
|
||||
buildWeb(true)
|
||||
},
|
||||
options: {
|
||||
ignored: ['**/.#*', '**/*~', '**/#*#']
|
||||
|
@ -61,7 +70,8 @@ const args = process.argv.slice(2)
|
|||
|
||||
switch (args[0]) {
|
||||
case 'build':
|
||||
build()
|
||||
buildGemini()
|
||||
buildWeb()
|
||||
break
|
||||
case 'serve':
|
||||
serve()
|
||||
|
|
Loading…
Reference in a new issue