177 lines
5.2 KiB
JavaScript
177 lines
5.2 KiB
JavaScript
const { Buffer } = require('node:buffer')
|
|
const debug = require('debug')('metalsmith-tinuage-services')
|
|
const config = require('./config.js')
|
|
const fs = require('node:fs')
|
|
const path = require('path')
|
|
|
|
module.exports = plugin
|
|
|
|
/**
|
|
* Un plugin pour Metalsmith qui lit une collection de fichiers JSON décrivant
|
|
* les services de l'association pour composer la page services.html du site.
|
|
*
|
|
* @return {Function}
|
|
*/
|
|
function plugin () {
|
|
const Sections = Object.freeze({
|
|
OPEN: Symbol('open'),
|
|
MEMBERS: Symbol('members')
|
|
})
|
|
|
|
const PageFiller = {
|
|
setup: function (page, services) {
|
|
this.page = page
|
|
this.registry = services.reduce((registry, service) => {
|
|
registry[service.section].push(service)
|
|
return registry
|
|
}, {
|
|
[Sections.OPEN]: [],
|
|
[Sections.MEMBERS]: []
|
|
})
|
|
|
|
return this
|
|
},
|
|
|
|
fill: function () {
|
|
let html = ''
|
|
|
|
html += this.createSection('Services réservés aux adhérents', Sections.MEMBERS)
|
|
html += this.createSection('Services en libre accès, sans adhésion', Sections.OPEN)
|
|
|
|
this.page.contents = Buffer.concat([
|
|
this.page.contents,
|
|
Buffer.from(html)
|
|
])
|
|
},
|
|
|
|
createSection: function (title, section) {
|
|
let html = '<section class="Services">\n' +
|
|
'<h2 class="tac mt128 mb64">' + title + '</h2>\n' +
|
|
'<div class="Two-cols-One-row">\n'
|
|
|
|
this.registry[section].forEach((service) => { html += service.html })
|
|
html += '</section>'
|
|
|
|
return html
|
|
}
|
|
}
|
|
|
|
const Parser = {
|
|
/**
|
|
* Traduit la description JSON du service donné en paramètre en un extrait
|
|
* HTML.
|
|
*/
|
|
parseService: function (service) {
|
|
let html = '<div class="services">\n' +
|
|
'<h3 class="services-title services-icon-' + service.icon + '">' + service.title + '</h3>\n' +
|
|
'<p>' + service.description + '</p>\n'
|
|
|
|
if (service.buttons !== undefined) {
|
|
html += '<p class="tac">\n'
|
|
service.buttons.forEach((b) => { html += this.createButton(b) })
|
|
html += '</p>'
|
|
}
|
|
|
|
if (service.softwares !== undefined) {
|
|
html += '<div class="services-software">\n'
|
|
service.softwares.forEach((s) => { html += this.createSoftwareDescription(s) })
|
|
html += '</div>\n'
|
|
}
|
|
|
|
if (service.links !== undefined) {
|
|
html += '<div><p>Autres liens :</p>\n<ul>'
|
|
service.links.forEach((l) => { html += this.createListLink(l) })
|
|
html += '</ul></div>\n'
|
|
}
|
|
html += '</div>'
|
|
|
|
debug('Parsed ' + service.title + '(' + service.order + ')')
|
|
service.html = html
|
|
service.section = service.open ? Sections.OPEN : Sections.MEMBERS
|
|
|
|
return service
|
|
},
|
|
|
|
createButton: function (button) {
|
|
const cls = button.class || ''
|
|
return '<a class="button ' + cls + '" href="' + button.url + '">' + button.label + '</a>\n'
|
|
},
|
|
|
|
createListLink: function (link) {
|
|
return '<li><a class="external" href="' + link.url + '">' + link.label + '</a></li>\n'
|
|
},
|
|
|
|
createSoftwareDescription: function (soft) {
|
|
let html = '<p>' + soft.description + '</p>\n' +
|
|
'<div>'
|
|
|
|
if (soft.url !== undefined) {
|
|
html += this.createSoftwareLink('home.svg', 'Page Web', soft.url)
|
|
}
|
|
if (soft.sources !== undefined) {
|
|
html += this.createSoftwareLink('files.svg', 'Sources du logiciel', soft.sources)
|
|
}
|
|
soft.licenses.forEach((l) => { html += this.createSoftwareLink('copyright.svg', 'Licence', l.url, l.name) })
|
|
|
|
html += '</div>\n'
|
|
|
|
return html
|
|
},
|
|
|
|
createSoftwareLink: function (icon, alt, url, title) {
|
|
let element = '<div class="services-link">\n' +
|
|
'<a href="' + url + '"><img src="/images/uicons/' + icon + '" alt="' + alt + '"/></a>\n'
|
|
|
|
if (title !== undefined) {
|
|
element += '<br><p>' + title + '</p>'
|
|
}
|
|
|
|
element += '</div>'
|
|
|
|
return element
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lit de manière asynchrone l'ensemble des fichiers JSON décrivant les services.
|
|
*
|
|
* Seuls les fichiers ayant .json comme extension sont chargés depuis le répertoire fourni.
|
|
*/
|
|
function loadServices (root, filenames) {
|
|
const promises = filenames
|
|
.filter(f => { return f.indexOf('.json') !== -1 })
|
|
.map(function (f) {
|
|
debug('Loading ' + f)
|
|
return fs.promises
|
|
.readFile(path.join(root, f), 'utf8')
|
|
.then((data) => { return JSON.parse(data) })
|
|
})
|
|
|
|
return Promise.all(promises)
|
|
}
|
|
|
|
return function (files, metalsmith, done) {
|
|
const root = path.join(config.paths.projectRoot, 'services')
|
|
|
|
debug('Looking for services in ' + root)
|
|
fs.readdir(root, (err, filenames) => {
|
|
if (err) {
|
|
console.error('%s: %s', root, err)
|
|
} else {
|
|
loadServices(root, filenames)
|
|
.then(function (services) {
|
|
const p = Object.create(Parser)
|
|
const parsed = services
|
|
.sort((a, b) => { return a.order - b.order })
|
|
.map((s) => p.parseService(s))
|
|
Object.create(PageFiller).setup(files['services.html'], parsed).fill()
|
|
done()
|
|
})
|
|
.catch(function (err) {
|
|
console.log(err)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|