Tenir un journal des nouveautés sur l'accueil
La page annonçait l'existence des services, jamais leur arrivée : un visiteur régulier n'avait aucun moyen de voir ce qui avait bougé depuis sa dernière visite. Une section « Nouveautés » s'en charge, dessinée à partir de site/nouveautes.json — ajouter une entrée ne demande plus de toucher au HTML. Les six entrées de départ sont reconstituées depuis l'historique git, ici et dans le monorepo d'où la page vient. La page trie sur la date, l'ordre du fichier est donc libre, et n'affiche que les six plus récentes ; les anciennes restent dans le fichier comme mémoire. Fichier absent ou illisible : la section se masque, comme l'agenda et le wiki le font déjà de leur côté. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JYfYUZRcJmmEWJwAxZb4o2
This commit is contained in:
parent
f0a0c96e75
commit
e383368906
3 changed files with 193 additions and 1 deletions
26
README.md
26
README.md
|
|
@ -7,7 +7,8 @@ Elle affiche deux choses qu'elle ne contient pas : l'**agenda**, lu dans le cale
|
||||||
public Nextcloud, et les **dernières pages du wiki**, lues dans
|
public Nextcloud, et les **dernières pages du wiki**, lues dans
|
||||||
[`derniers-articles.json`](https://wiki.alpinux.org/derniers-articles.json) que le wiki
|
[`derniers-articles.json`](https://wiki.alpinux.org/derniers-articles.json) que le wiki
|
||||||
publie à chaque build. Si l'une ou l'autre source est injoignable, la section
|
publie à chaque build. Si l'une ou l'autre source est injoignable, la section
|
||||||
correspondante se masque et le reste de la page tient debout.
|
correspondante se masque et le reste de la page tient debout. Le **journal des
|
||||||
|
nouveautés**, lui, vit dans le dépôt : `site/nouveautes.json`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -16,6 +17,7 @@ correspondante se masque et le reste de la page tient debout.
|
||||||
| Ce que vous voulez faire | Ce que vous faites |
|
| Ce que vous voulez faire | Ce que vous faites |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Modifier la page | Éditer `site/index.html`, pousser sur `main` — la mise en ligne suit |
|
| Modifier la page | Éditer `site/index.html`, pousser sur `main` — la mise en ligne suit |
|
||||||
|
| Annoncer une nouveauté | Ajouter une entrée en tête de `site/nouveautes.json` (voir plus bas) |
|
||||||
| Voir le rendu avant de pousser | `python3 -m http.server -d site` puis http://localhost:8000 |
|
| Voir le rendu avant de pousser | `python3 -m http.server -d site` puis http://localhost:8000 |
|
||||||
| Comprendre pourquoi ça n'est pas en ligne | `tail -20 /var/log/www-deploy.log` sur le serveur |
|
| Comprendre pourquoi ça n'est pas en ligne | `tail -20 /var/log/www-deploy.log` sur le serveur |
|
||||||
| Republier sans nouveau commit | `sudo -u abonnelc /opt/www-alpinux/deploy-www.sh` |
|
| Republier sans nouveau commit | `sudo -u abonnelc /opt/www-alpinux/deploy-www.sh` |
|
||||||
|
|
@ -32,6 +34,7 @@ serveur, pas par `http.server`. Les articles du wiki, eux, s'affichent normaleme
|
||||||
alpinux-www/
|
alpinux-www/
|
||||||
├── site/ ce qui part en ligne, tel quel
|
├── site/ ce qui part en ligne, tel quel
|
||||||
│ ├── index.html
|
│ ├── index.html
|
||||||
|
│ ├── nouveautes.json le journal des nouveautés, lu par la page
|
||||||
│ ├── robots.txt
|
│ ├── robots.txt
|
||||||
│ └── sitemap.xml
|
│ └── sitemap.xml
|
||||||
└── deploiement/ la chaîne, versionnée avec le site
|
└── deploiement/ la chaîne, versionnée avec le site
|
||||||
|
|
@ -44,6 +47,27 @@ alpinux-www/
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Annoncer une nouveauté
|
||||||
|
|
||||||
|
La section « Nouveautés » de l'accueil est dessinée à partir de `site/nouveautes.json` —
|
||||||
|
un tableau d'entrées, `url` facultative :
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"date": "2026-09-23",
|
||||||
|
"titre": "Listes de diffusion",
|
||||||
|
"texte": "Une phrase ou deux, à hauteur de visiteur.",
|
||||||
|
"url": "https://messagerie.alpinux.org"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
L'ordre du fichier n'a pas d'importance : la page trie sur `date` et n'affiche que les
|
||||||
|
six entrées les plus récentes. Les plus anciennes restent dans le fichier, comme
|
||||||
|
mémoire. Une entrée sans `titre` ou sans `date` au format `AAAA-MM-JJ` est ignorée ;
|
||||||
|
si le fichier disparaît ou devient illisible, la section se masque comme les deux autres.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Ce qui se passe après un push
|
## Ce qui se passe après un push
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
132
site/index.html
132
site/index.html
|
|
@ -552,6 +552,65 @@
|
||||||
.wiki-more a { color: #1a6bbf; text-decoration: none; }
|
.wiki-more a { color: #1a6bbf; text-decoration: none; }
|
||||||
.wiki-more a:hover { text-decoration: underline; }
|
.wiki-more a:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
/* ── Nouveautés ─────────────────────────────────────────────── */
|
||||||
|
#news-section { margin-top: 3rem; }
|
||||||
|
|
||||||
|
.news {
|
||||||
|
list-style: none;
|
||||||
|
border-left: 2px solid #dce8f5;
|
||||||
|
margin-left: .5rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news li {
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news li:last-child { padding-bottom: 0; }
|
||||||
|
|
||||||
|
.news li::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: calc(-1.5rem - 6px);
|
||||||
|
top: .35rem;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #9fc5e8;
|
||||||
|
box-shadow: 0 0 0 3px #f3f6fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news li:first-child::before { background: #1a6bbf; }
|
||||||
|
|
||||||
|
.news-when {
|
||||||
|
font-size: .78rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #7a8ba0;
|
||||||
|
letter-spacing: .06em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: .2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.35;
|
||||||
|
color: #1a1a2e;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.news-title:hover { color: #1a6bbf; text-decoration: underline; }
|
||||||
|
|
||||||
|
.news-text {
|
||||||
|
font-size: .92rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #4a5a6a;
|
||||||
|
margin-top: .25rem;
|
||||||
|
max-width: 62ch;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Services ───────────────────────────────────────────────── */
|
/* ── Services ───────────────────────────────────────────────── */
|
||||||
.services {
|
.services {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
@ -733,6 +792,11 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<section id="news-section" hidden>
|
||||||
|
<h2 class="section-title">Nouveautés</h2>
|
||||||
|
<ol class="news" id="news-list"></ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
|
|
@ -1233,5 +1297,73 @@
|
||||||
document.addEventListener('DOMContentLoaded', charger);
|
document.addEventListener('DOMContentLoaded', charger);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- ── Nouveautés : le journal des évolutions du site ───────────────── -->
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var URL_JSON = 'nouveautes.json';
|
||||||
|
var NB_MAX = 6; /* entrées affichées ; les plus anciennes restent dans le fichier */
|
||||||
|
|
||||||
|
function echappe(texte) {
|
||||||
|
var d = document.createElement('div');
|
||||||
|
d.textContent = texte;
|
||||||
|
return d.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* '2026-09-23' lu comme une date locale : passer par le constructeur
|
||||||
|
décalerait l'affichage d'un jour selon le fuseau. */
|
||||||
|
function enDate(iso) {
|
||||||
|
var m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(iso || ''));
|
||||||
|
return m ? new Date(+m[1], +m[2] - 1, +m[3]) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function quand(d) {
|
||||||
|
return d.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function ligne(item, d) {
|
||||||
|
var li = document.createElement('li');
|
||||||
|
var titre = item.url
|
||||||
|
? '<a class="news-title" href="' + echappe(item.url) + '">' + echappe(item.titre) + '</a>'
|
||||||
|
: '<span class="news-title">' + echappe(item.titre) + '</span>';
|
||||||
|
|
||||||
|
li.innerHTML =
|
||||||
|
'<time class="news-when" datetime="' + echappe(item.date) + '">' + echappe(quand(d)) + '</time>' +
|
||||||
|
titre +
|
||||||
|
(item.texte ? '<p class="news-text">' + echappe(item.texte) + '</p>' : '');
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function charger() {
|
||||||
|
var items;
|
||||||
|
try {
|
||||||
|
var r = await fetch(URL_JSON, { cache: 'no-cache' });
|
||||||
|
if (!r.ok) return;
|
||||||
|
items = await r.json();
|
||||||
|
} catch (_) { return; } /* fichier absent ou illisible : la section reste masquée */
|
||||||
|
|
||||||
|
if (!Array.isArray(items)) return;
|
||||||
|
|
||||||
|
var valides = items
|
||||||
|
.map(function (item) {
|
||||||
|
var d = item && item.titre ? enDate(item.date) : null;
|
||||||
|
return d ? { item: item, d: d } : null;
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort(function (a, b) { return b.d - a.d; });
|
||||||
|
|
||||||
|
if (!valides.length) return;
|
||||||
|
|
||||||
|
var liste = document.getElementById('news-list');
|
||||||
|
valides.slice(0, NB_MAX).forEach(function (v) { liste.appendChild(ligne(v.item, v.d)); });
|
||||||
|
|
||||||
|
document.getElementById('news-section').hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', charger);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
36
site/nouveautes.json
Normal file
36
site/nouveautes.json
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"date": "2026-09-23",
|
||||||
|
"titre": "Listes de diffusion",
|
||||||
|
"texte": "messagerie.alpinux.org ouvre ses portes : on s'abonne aux annonces de l'association en indiquant son adresse, et on relit tout ce qui a déjà été envoyé dans les archives publiques.",
|
||||||
|
"url": "https://messagerie.alpinux.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-20",
|
||||||
|
"titre": "Le wiki s'affiche sur l'accueil",
|
||||||
|
"texte": "Les dernières pages créées ou mises à jour dans le wiki apparaissent désormais directement ici, sans qu'on ait à aller les chercher.",
|
||||||
|
"url": "https://wiki.alpinux.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-20",
|
||||||
|
"titre": "Le planning des seize prochaines semaines",
|
||||||
|
"texte": "L'agenda gagne une vue d'ensemble : une case par jour sur quatre mois, les jours chargés en couleur, et le détail d'une journée d'un simple clic."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-09-20",
|
||||||
|
"titre": "Ce que nous faisons de vos données",
|
||||||
|
"texte": "Une page explique quelles données l'association conserve, pourquoi, et comment en demander la suppression. Son lien vit en pied de page.",
|
||||||
|
"url": "https://wiki.alpinux.org/alpinux/donnees-personnelles/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-05-03",
|
||||||
|
"titre": "Jeux & quiz",
|
||||||
|
"texte": "dynamic.alpinux.org rassemble les mini-jeux et les questionnaires interactifs préparés pour nos rencontres.",
|
||||||
|
"url": "https://dynamic.alpinux.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2026-05-03",
|
||||||
|
"titre": "Un agenda qui se tient à jour tout seul",
|
||||||
|
"texte": "Les rendez-vous affichés sur l'accueil sont lus dans le calendrier public de l'association : ce qui y est inscrit apparaît ici sans intervention."
|
||||||
|
}
|
||||||
|
]
|
||||||
Loading…
Reference in a new issue