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>",
|
"description": "The sources for <http://david.soulayrol.name>",
|
||||||
"main": "",
|
"main": "",
|
||||||
"scripts": {
|
"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:prod": "NODE_ENV=production npm run build",
|
||||||
"build:metalsmith": "node scripts/run.js build",
|
"build:metalsmith": "node scripts/run.js build",
|
||||||
"clean": "rimraf dist",
|
"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",
|
"server": "npm run build && http-server dist",
|
||||||
"lint": "npm run lint:js && npm run lint:css",
|
"lint": "npm run lint:js && npm run lint:css",
|
||||||
"lint:js": "eslint scripts",
|
"lint:js": "eslint scripts",
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"nodemon": "^2.0.12",
|
"nodemon": "^2.0.12",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"slug": "^5.1.0",
|
"slug": "^8.0.0",
|
||||||
"stylelint": "^13.13.1",
|
"stylelint": "^13.13.1",
|
||||||
"stylelint-config-standard": "^22.0.0"
|
"stylelint-config-standard": "^22.0.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,10 +11,11 @@ module.exports = {
|
||||||
projectRoot,
|
projectRoot,
|
||||||
/* Nodes */
|
/* Nodes */
|
||||||
nodeModules: join(projectRoot, 'node_modules'),
|
nodeModules: join(projectRoot, 'node_modules'),
|
||||||
/* Metalsmith */
|
/* Gemini Distribution */
|
||||||
metalsmithSource: 'content',
|
geminiSource: 'gemini',
|
||||||
metalsmithDestination: distribution,
|
geminiDestination: join(distribution, 'public_gemini'),
|
||||||
/* Server */
|
/* Web Distribution */
|
||||||
serverRoot: 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'
|
title: 'David Soulayrol'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.source(config.paths.metalsmithSource)
|
.source(config.paths.webSource)
|
||||||
.destination(config.paths.metalsmithDestination)
|
.destination(config.paths.webDestination)
|
||||||
.use(cleanCSS({}))
|
.use(cleanCSS({}))
|
||||||
.use(assets({
|
.use(assets({
|
||||||
source: './assets/' + (process.env.NODE_ENV || 'dev'),
|
source: './assets/' + (process.env.NODE_ENV || 'dev'),
|
||||||
destination: './'
|
destination: config.paths.webDestination
|
||||||
}))
|
}))
|
||||||
.use(groff({
|
.use(groff({
|
||||||
preprocessors: ['tbl'],
|
preprocessors: ['tbl'],
|
|
@ -1,15 +1,14 @@
|
||||||
const bs = require('browser-sync').create('Metalsmith')
|
const bs = require('browser-sync').create('Metalsmith')
|
||||||
const config = require('./config.js')
|
const config = require('./config.js')
|
||||||
const debug = require('debug')('Run')
|
const debug = require('debug')('Run')
|
||||||
const metalsmith = require('./metalsmith')
|
const metalsmithGemini = require('./metalsmith-gemini')
|
||||||
|
const metalsmithWeb = require('./metalsmith-web')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const strip = require('strip-ansi')
|
const strip = require('strip-ansi')
|
||||||
|
|
||||||
function build (sync) {
|
function complete (dist, sync, err) {
|
||||||
debug('Building Metalsmith')
|
|
||||||
metalsmith.build((err) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
debug('Metalsmith build error:')
|
debug(dist + ' build error:')
|
||||||
debug(err)
|
debug(err)
|
||||||
if (sync) {
|
if (sync) {
|
||||||
return bs.sockets.emit('fullscreen:message', {
|
return bs.sockets.emit('fullscreen:message', {
|
||||||
|
@ -20,17 +19,27 @@ function build (sync) {
|
||||||
} else {
|
} else {
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
debug(dist + ' build finished!')
|
||||||
}
|
}
|
||||||
debug('Metalsmith build finished!')
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
bs.reload()
|
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 () {
|
function serve () {
|
||||||
bs.init({
|
bs.init({
|
||||||
server: config.paths.serverRoot,
|
server: config.paths.webDestination,
|
||||||
port: 8080,
|
port: 8080,
|
||||||
ui: {
|
ui: {
|
||||||
port: 9000
|
port: 9000
|
||||||
|
@ -47,7 +56,7 @@ function serve () {
|
||||||
path.resolve(config.paths.projectRoot, 'layouts', '**', '*.njk')
|
path.resolve(config.paths.projectRoot, 'layouts', '**', '*.njk')
|
||||||
],
|
],
|
||||||
fn: function (event, file) {
|
fn: function (event, file) {
|
||||||
build(true)
|
buildWeb(true)
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
ignored: ['**/.#*', '**/*~', '**/#*#']
|
ignored: ['**/.#*', '**/*~', '**/#*#']
|
||||||
|
@ -61,7 +70,8 @@ const args = process.argv.slice(2)
|
||||||
|
|
||||||
switch (args[0]) {
|
switch (args[0]) {
|
||||||
case 'build':
|
case 'build':
|
||||||
build()
|
buildGemini()
|
||||||
|
buildWeb()
|
||||||
break
|
break
|
||||||
case 'serve':
|
case 'serve':
|
||||||
serve()
|
serve()
|
||||||
|
|
Loading…
Reference in a new issue