From 179bb0a8502c770e33cf41961841b8d7d09f2a38 Mon Sep 17 00:00:00 2001 From: David Soulayrol Date: Sun, 24 Mar 2024 21:29:27 +0100 Subject: [PATCH] Ajout de la rubrique rencontres. --- README.md | 18 ++++-- content/rencontres/index.md | 7 +++ layouts/base.njk | 1 + package.json | 4 +- scripts/config.js | 1 + scripts/metalsmith-copy.js | 18 ++++-- scripts/metalsmith-tinuage-talks.js | 97 +++++++++++++++++++++++++++++ scripts/metalsmith.js | 23 +++++++ 8 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 content/rencontres/index.md create mode 100644 scripts/metalsmith-tinuage-talks.js diff --git a/README.md b/README.md index d156266..350a9aa 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,11 @@ Le site est créé à l'aide du logiciel libre [MetalSmith](http://www.metalsmit ### Préparation des sources -**Metalsmith** requiert la disponibilité de **NodeJS** et **npm**. L'installation de ces logiciels dépend du système d'exploitation utilisé. - -Les sources peuvent être téléchargées depuis le dépôt **Gitea** ou bien copiées localement à l'aide de **git** avec la commande suivante. +Les sources du site peuvent être téléchargées depuis le dépôt **Gitea** ou bien copiées localement à l'aide de **git** avec la commande suivante. git clone https://apps.ti-nuage.fr/gitea/ti-nuage/site.git -Le projet s'appuie sur un certain nombre de dépendances, utiles au développement ou à la génération du site lui-même. Pour installer ces dépendances : +Le projet s'appuie sur un certain nombre de dépendances, utiles au développement ou à la génération du site lui-même. Il est tout d'abord nécessaire d'installer **NodeJS** et **npm**. L'installation de ces logiciels dépend du système d'exploitation utilisé. Le reste des dépendances peut alors être assemblé avec la commande suivante. npm install @@ -32,9 +30,17 @@ La liste des commandes existantes est disponible avec `npm run`. Il est possible ## Structure -Le site de l'association est essentiellement composé de pages statiques. Les billets d'actualité et les comptes-rendus de réunion sont eux-mêmes générés ou assemblés avec le reste des pages du site. +Sauf les exceptions détaillées plus bas, l'ensemble du site de l'association est composé de pages statiques dont les sources figurent dans ce projet. Les billets d'actualité et les comptes-rendus de réunion sont eux-mêmes générés ou assemblés avec le reste des pages du site. -Cependant, afin d'être réactif, l'affichage des événements du calendrier partagé de l'association est effectué depuis le navigateur. Si le navigateur dispose d'un support Javascript actif, alors : +### Supports de conférences + +Les documents hébergés dans le projet [ti-nuage/talks](https://forge.ti-nuage.fr/gitea/ti-nuage/talks) peuvent être publiés sur la page /rencontres. Pour ce faire, il faut renseigner la variable d'environnement PATH_TALKS. Par exemple : + + PATH_TALKS=../tinuage-talks/documents npm run server + +### Intégration du calendrier + +Afin d'être réactif, l'affichage des événements du calendrier partagé de l'association est effectué depuis le navigateur. Si le navigateur dispose d'un support Javascript actif, alors : - les événements à venir sont mixés avec les billets récents du blog dans la rubrique Actualité de la page d'accueil ; - le menu propose une entrée « Calendrier » à la suite de « Actualité ». Cette nouvelle page présente plus largement les événements récents ou à venir. diff --git a/content/rencontres/index.md b/content/rencontres/index.md new file mode 100644 index 0000000..76f266e --- /dev/null +++ b/content/rencontres/index.md @@ -0,0 +1,7 @@ +--- +permalink: false +title: Rencontres +--- +Outre l'accueil offert par l'association le premier jeudi de chaque mois, Ti Nuage va aussi à la rencontre d'autres lieux pour présenter et discuter les thèmes qui lui sont chers : la liberté de l'utilisateur de services numériques et la protection de ses données. + +Voici les documents utilisés comme support lors des rencontres, conférences et autres causeries faites par l'association. Tous sont disponibles selon la licence [CC-BY-SA version 2.0 ou ultérieure](https://creativecommons.org/licenses/by-sa/2.0/fr/). Leurs fichiers sources sont disponibles sur notre [forge logicielle](https://forge.ti-nuage.fr/gitea/ti-nuage/talks). diff --git a/layouts/base.njk b/layouts/base.njk index 316cee1..9d83a87 100644 --- a/layouts/base.njk +++ b/layouts/base.njk @@ -21,6 +21,7 @@
diff --git a/package.json b/package.json index 37ed1fb..24382c8 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,9 @@ "main": "", "scripts": { "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", + "build:prod": "NODE_ENV=production npm run build", + "clean": "rimraf dist && rm -rf content/talks", "dev": "npm run build && nodemon scripts/run.js serve", "server": "npm run build && http-server dist", "deploy": "npm run build:prod && cd dist && rsync -v -rlptz --relative -e \"ssh -p $SERVER_PORT\" ./ $SERVER_PATH", diff --git a/scripts/config.js b/scripts/config.js index 2601aad..aaabc32 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -9,6 +9,7 @@ module.exports = { hostname, paths: { projectRoot, + talksRoot: process.env.PATH_TALKS, /* Nodes */ leaflet: join(projectRoot, 'node_modules', 'leaflet', 'dist'), /* Metalsmith */ diff --git a/scripts/metalsmith-copy.js b/scripts/metalsmith-copy.js index 2a04575..e3279ed 100644 --- a/scripts/metalsmith-copy.js +++ b/scripts/metalsmith-copy.js @@ -10,10 +10,9 @@ function plugin (options) { return function (files, metalsmith, done) { const dest = options.destination - const items = options.files.length const promises = [] - const addTask = function (promise) { + const addTask = function (items, promise) { promises.push(promise) if (items === promises.length) { debug('Waiting for ' + items + 'copy operations.') @@ -27,8 +26,19 @@ function plugin (options) { } } - options.files.forEach((filename) => { - addTask(new Promise(function (resolve, reject) { + const iterateFiles = function (options, action) { + if (options.files != null) { + options.files.forEach((filename) => action(filename, options.files.length)) + } + if (options.generator != null) { + options.generator(documents => { + documents.forEach((filename) => action(filename, documents.length)) + }) + } + } + + iterateFiles(options, (filename, items) => { + addTask(items, new Promise(function (resolve, reject) { fs.stat(filename, function (err, stats) { if (err) return reject(err) fs.readFile(filename, function (err, buffer) { diff --git a/scripts/metalsmith-tinuage-talks.js b/scripts/metalsmith-tinuage-talks.js new file mode 100644 index 0000000..bf63435 --- /dev/null +++ b/scripts/metalsmith-tinuage-talks.js @@ -0,0 +1,97 @@ +const { Buffer } = require('node:buffer') +const config = require('./config.js') +const debug = require('debug')('metalsmith-tinuage-talks') +const path = require('path') + +module.exports = plugin + +/** + * Un plugin pour Metalsmith qui lit une collection de fichiers PDF la section + * rencontres du site. + * + * @return {Function} + */ +function plugin () { + const IndexCreator = { + setup: function (page) { + this.page = page + this.talks = [] + }, + + add: function (filename) { + const basename = path.basename(filename) + const names = basename.substring(0, basename.lastIndexOf('.')).split('__') + + if (names.length >= 2) { + const name = names[0].replaceAll('_', ' ') + const location = names[1].substring(0, names[1].lastIndexOf('_')).replaceAll('_', ' ') + const year = names[1].substring(names[1].lastIndexOf('_') + 1) + + const talk = this.getEntry(year, location, name) + + if (names.length === 3 && names[2] === ('notes')) { + talk.notes = filename + } else { + talk.doc = filename + } + } else { + console.log('Ignoring talk ' + filename) + } + }, + + fill: function (files) { + let html = '' + + this.talks + .reduce( + (map, talk) => { + (map.get(talk.year) || map.set(talk.year, []).get(talk.year)).push(talk) + return map + }, + new Map()) + .forEach((talks, year) => { + html += '

' + year + '

\n' + talks + .sort((a, b) => a.year - b.year || a.title - b.title) + .forEach(talk => { + html += '

' + talk.title + ', ' + talk.location + ' : Présentation, Notes

\n' + }) + }) + + this.page.contents = Buffer.concat([ + this.page.contents, + Buffer.from(html) + ]) + }, + + getEntry: function (year, location, title) { + let talk = this.talks.find(t => t.year === year && t.location === location && t.title === title) + + if (talk == null) { + talk = { location, title, year } + this.talks.push(talk) + } + + return talk + } + } + + return function (files, metalsmith, done) { + if (config.paths.talksRoot) { + const creator = Object.create(IndexCreator) + + creator.setup(files['rencontres/index.html']) + + Object.keys(files).forEach(filename => { + if (/^rencontres\/.*\.pdf$/.test(filename)) { + debug('Handling', filename) + creator.add(filename) + } + }) + + creator.fill() + } + + done() + } +} diff --git a/scripts/metalsmith.js b/scripts/metalsmith.js index 5340e54..b0499fa 100644 --- a/scripts/metalsmith.js +++ b/scripts/metalsmith.js @@ -7,6 +7,7 @@ const config = require('./config.js') const collections = require('@metalsmith/collections') const copy = require('./metalsmith-copy') const excerpts = require('@metalsmith/excerpts') +const fs = require('node:fs') const groff = require('metalsmith-groff') const layouts = require('@metalsmith/layouts') const Metalsmith = require('metalsmith') @@ -15,6 +16,7 @@ const marked = require('marked') const permalinks = require('@metalsmith/permalinks') const rename = require('metalsmith-rename') const services = require('./metalsmith-tinuage-services') +const talks = require('./metalsmith-tinuage-talks') const sitemap = require('metalsmith-sitemap') const slug = require('slug') const statistics = require('./metalsmith-statistics-plugin') @@ -77,6 +79,26 @@ module.exports = new Metalsmith(config.paths.projectRoot) files: [join(config.paths.leaflet, 'leaflet.css')], destination: './css' })) + .use(copy({ + generator: (callback) => { + if (config.paths.talksRoot != null) { + return fs.readdir(config.paths.talksRoot, (err, filenames) => { + let documents = [] + + if (err) { + console.error('%s: %s', config.paths.talksRoot, err) + } else { + documents = filenames + .filter(f => { return f.indexOf('.pdf') !== -1 }) + .map(f => { return join(config.paths.talksRoot, f) }) + } + + callback(documents) + }) + } + }, + destination: './rencontres' + })) .use(copy({ files: [ join(config.paths.leaflet, 'images', 'marker-icon.png'), @@ -106,6 +128,7 @@ module.exports = new Metalsmith(config.paths.projectRoot) })) .use(chatons()) .use(services()) + .use(talks()) .use(excerpts()) .use(permalinks({ pattern: 'blog/:date/:title',