Compare commits
3 commits
e383368906
...
ddf3f79e7a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddf3f79e7a | ||
|
|
3baa10db65 | ||
|
|
d740c2c900 |
8 changed files with 753 additions and 28 deletions
57
README.md
57
README.md
|
|
@ -1,7 +1,8 @@
|
|||
# www.alpinux.org
|
||||
|
||||
La page d'accueil de l'association — du HTML statique, une seule page, servie sur
|
||||
`https://alpinux.org` et `https://www.alpinux.org`.
|
||||
Le site public de l'association — du HTML statique, servi sur `https://alpinux.org` et
|
||||
`https://www.alpinux.org` : la page d'accueil, la page des mises à jour du wiki, et la
|
||||
page d'erreur 404.
|
||||
|
||||
Elle affiche deux choses qu'elle ne contient pas : l'**agenda**, lu dans le calendrier
|
||||
public Nextcloud, et les **dernières pages du wiki**, lues dans
|
||||
|
|
@ -16,12 +17,13 @@ nouveautés**, lui, vit dans le dépôt : `site/nouveautes.json`.
|
|||
|
||||
| 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 l'accueil | É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 |
|
||||
| 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` |
|
||||
| Réinstaller la chaîne de déploiement | `sudo bash deploiement/installer.sh` |
|
||||
| Reprendre une modification de `deploiement/` | Relancer `installer.sh` : le serveur exécute sa copie dans `/opt/www-alpinux`, pas celle du dépôt |
|
||||
|
||||
En local, l'agenda reste vide : `/public-calendars/…` est relayé vers Nextcloud par le
|
||||
serveur, pas par `http.server`. Les articles du wiki, eux, s'affichent normalement.
|
||||
|
|
@ -33,8 +35,11 @@ serveur, pas par `http.server`. Les articles du wiki, eux, s'affichent normaleme
|
|||
```
|
||||
alpinux-www/
|
||||
├── site/ ce qui part en ligne, tel quel
|
||||
│ ├── index.html
|
||||
│ ├── nouveautes.json le journal des nouveautés, lu par la page
|
||||
│ ├── index.html l'accueil, son style et ses scripts en ligne
|
||||
│ ├── modifications.html toutes les pages du wiki, datées
|
||||
│ ├── 404.html la page d'erreur
|
||||
│ ├── commun.css la charte des deux pages secondaires
|
||||
│ ├── nouveautes.json le journal des nouveautés, lu par l'accueil
|
||||
│ ├── robots.txt
|
||||
│ └── sitemap.xml
|
||||
└── deploiement/ la chaîne, versionnée avec le site
|
||||
|
|
@ -68,6 +73,48 @@ si le fichier disparaît ou devient illisible, la section se masque comme les de
|
|||
|
||||
---
|
||||
|
||||
## Les mises à jour du wiki
|
||||
|
||||
`site/modifications.html` liste **toutes** les pages de wiki.alpinux.org, de la plus
|
||||
récemment retouchée à la plus ancienne, avec un filtre par titre ou rubrique. Elle lit
|
||||
`https://wiki.alpinux.org/toutes-les-pages.json`, que le build du wiki publie à chaque
|
||||
fois — comme il publie déjà `derniers-articles.json` pour l'accueil.
|
||||
|
||||
Si ce fichier manque, la page se rabat sur `derniers-articles.json` et le dit : on
|
||||
obtient les vingt dernières pages au lieu de toutes, plutôt qu'une page vide. Les deux
|
||||
sources injoignables, elle affiche un message et renvoie vers le wiki.
|
||||
|
||||
Le contenu se change donc **dans le dépôt du wiki**, pas ici : ajouter une page à la
|
||||
navigation du wiki suffit à la faire apparaître.
|
||||
|
||||
---
|
||||
|
||||
## La page 404
|
||||
|
||||
`site/404.html` reprend la charte du site, annonce clairement l'erreur et propose
|
||||
l'accueil, le wiki, les mises à jour et les listes de diffusion. Elle porte
|
||||
`noindex, follow` : une page d'erreur n'a rien à faire dans un moteur de recherche,
|
||||
mais ses liens restent bons à suivre.
|
||||
|
||||
**Elle ne sert à rien sans la directive Apache qui va avec.** Le `.htaccess` du
|
||||
DocumentRoot — qui vit sur le serveur, pas dans ce dépôt public — doit porter :
|
||||
|
||||
```apache
|
||||
ErrorDocument 404 /404.html
|
||||
```
|
||||
|
||||
et **ne pas** renvoyer les adresses inconnues vers l'accueil. Une règle du type
|
||||
`RewriteRule . /index.html [L]` produit un « soft 404 » : le visiteur voit l'accueil,
|
||||
le moteur de recherche enregistre une page valide, et personne ne sait que l'adresse
|
||||
était fausse.
|
||||
|
||||
```bash
|
||||
# ce qu'on doit lire une fois la directive en place
|
||||
curl -o /dev/null -w '%{http_code}\n' https://alpinux.org/adresse-qui-nexiste-pas # 404
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ce qui se passe après un push
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -13,12 +13,15 @@ echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deploy started" >> "$LOG"
|
|||
cd "$REPO_DIR"
|
||||
git pull origin main >> "$LOG" 2>&1
|
||||
|
||||
# Garde-fou : un index.html tronqué ne part pas en ligne. C'est l'équivalent, pour un
|
||||
# site sans build, du « mkdocs build --strict » du wiki.
|
||||
if ! grep -q "</html>" "$SOURCE/index.html"; then
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ABANDON : index.html incomplet" >> "$LOG"
|
||||
exit 1
|
||||
fi
|
||||
# Garde-fou : une page tronquée ne part pas en ligne. C'est l'équivalent, pour un
|
||||
# site sans build, du « mkdocs build --strict » du wiki. Toutes les pages y passent,
|
||||
# pas seulement l'accueil : la 404 servie à moitié serait aussi laide qu'une erreur.
|
||||
for page in "$SOURCE"/*.html; do
|
||||
if ! grep -q "</html>" "$page"; then
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ABANDON : $(basename "$page") incomplet" >> "$LOG"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Pas de --delete, volontairement : le DocumentRoot contient aussi des fichiers qui ne
|
||||
# sont pas dans ce dépôt — le .htaccess qui relaie /public-calendars vers Nextcloud, les
|
||||
|
|
|
|||
135
site/404.html
Normal file
135
site/404.html
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, follow">
|
||||
<title>Page introuvable — Alpinux</title>
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="https://static.alpinux.org/logo/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="https://static.alpinux.org/logo/favicon-32.png">
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="https://static.alpinux.org/logo/favicon-192.png">
|
||||
|
||||
<link rel="stylesheet" href="/commun.css">
|
||||
<style>
|
||||
.code-erreur {
|
||||
font-size: 4.5rem;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
color: #9fc5e8;
|
||||
letter-spacing: -.03em;
|
||||
margin-bottom: .6rem;
|
||||
}
|
||||
|
||||
.actions { margin-top: 2rem; }
|
||||
|
||||
.pistes {
|
||||
margin-top: 2.8rem;
|
||||
border-top: 2px solid #e8f1fb;
|
||||
padding-top: 1.6rem;
|
||||
}
|
||||
|
||||
.pistes h2 {
|
||||
font-size: 1rem;
|
||||
color: #0f4e8f;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pistes-liste {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
|
||||
gap: .9rem;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.pistes-liste a {
|
||||
display: block;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: .9rem 1.1rem;
|
||||
box-shadow: 0 2px 10px rgba(26,107,191,.08);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: transform .15s, box-shadow .15s;
|
||||
}
|
||||
|
||||
.pistes-liste a:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 20px rgba(26,107,191,.18);
|
||||
}
|
||||
|
||||
.pistes-liste a:hover strong { color: #1a6bbf; }
|
||||
|
||||
.pistes-liste strong { display: block; font-size: .95rem; margin-bottom: .15rem; }
|
||||
.pistes-liste span { font-size: .84rem; color: #7a8ba0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<a href="/" class="logo-wrap">
|
||||
<img src="https://static.alpinux.org/logo/alpinux-logo.png"
|
||||
alt="Logo Alpinux — LUG de Savoie"
|
||||
class="logo-img" width="66" height="66">
|
||||
<span class="logo-text">
|
||||
<span class="brand">
|
||||
<span class="light">A</span><span class="bold">l</span><span class="light">p</span><span class="bold">inux</span>
|
||||
</span>
|
||||
<span class="tagline">le LUG de Savoie</span>
|
||||
</span>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<nav aria-label="Navigation principale">
|
||||
<a href="/">Accueil</a>
|
||||
<a href="https://wiki.alpinux.org">Wiki</a>
|
||||
<a href="https://portail.alpinux.org">Portail membres</a>
|
||||
<a href="https://installparty.alpinux.org">Install Party</a>
|
||||
<a href="https://gitea.alpinux.org">Gitea</a>
|
||||
<a href="https://messagerie.alpinux.org">Listes de diffusion</a>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<p class="code-erreur" aria-hidden="true">404</p>
|
||||
<h1>Cette page n'existe pas… ou plus</h1>
|
||||
<p class="chapeau">
|
||||
L'adresse demandée ne correspond à rien sur ce site. Un lien qui a vieilli, une
|
||||
coquille dans l'adresse, ou une page que nous avons déplacée — dans tous les cas,
|
||||
l'accueil vous remettra sur les rails.
|
||||
</p>
|
||||
|
||||
<p class="actions">
|
||||
<a href="/" class="bouton">Retour à l'accueil</a>
|
||||
</p>
|
||||
|
||||
<section class="pistes">
|
||||
<h2>Ou bien, directement :</h2>
|
||||
<ul class="pistes-liste">
|
||||
<li><a href="https://wiki.alpinux.org">
|
||||
<strong>📖 Le wiki</strong>
|
||||
<span>Guides, tutoriels et présentations</span></a></li>
|
||||
<li><a href="/modifications.html">
|
||||
<strong>🕒 Les mises à jour du wiki</strong>
|
||||
<span>Toutes les pages, de la plus récente à la plus ancienne</span></a></li>
|
||||
<li><a href="https://messagerie.alpinux.org">
|
||||
<strong>✉️ Les listes de diffusion</strong>
|
||||
<span>S'abonner aux annonces, relire les archives</span></a></li>
|
||||
<li><a href="https://installparty.alpinux.org">
|
||||
<strong>🐧 Les Install Party</strong>
|
||||
<span>Événements & inscriptions</span></a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>© Alpinux — Association loi 1901 · Chambéry, Savoie</p>
|
||||
<p style="margin-top:.4rem;">
|
||||
<a href="https://wiki.alpinux.org/alpinux/">À propos</a> ·
|
||||
<a href="https://wiki.alpinux.org/alpinux/faq/">FAQ</a> ·
|
||||
<a href="https://wiki.alpinux.org/alpinux/donnees-personnelles/">Vos données</a> ·
|
||||
<a href="https://www.helloasso.com/associations/alpinux-le-lug-de-savoie">Adhérer</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
128
site/commun.css
Normal file
128
site/commun.css
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/* Charte partagée par les pages secondaires — 404, mises à jour du wiki.
|
||||
L'accueil garde son style en ligne : une page, une requête, rien à attendre. */
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
|
||||
background: #f3f6fb;
|
||||
color: #1a1a2e;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* ── En-tête ──────────────────────────────────────────────────────── */
|
||||
header {
|
||||
background: #1a6bbf;
|
||||
color: #fff;
|
||||
padding: 2.2rem 1.5rem 1.8rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1.1rem;
|
||||
flex-wrap: wrap;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.logo-img { width: 66px; height: 66px; border-radius: 10px; }
|
||||
|
||||
.logo-text { text-align: left; }
|
||||
|
||||
.brand {
|
||||
display: block;
|
||||
font-size: 2.1rem;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
letter-spacing: -.02em;
|
||||
}
|
||||
|
||||
.brand .light { font-weight: 300; }
|
||||
.brand .bold { font-weight: 800; }
|
||||
|
||||
.tagline {
|
||||
display: block;
|
||||
font-size: .82rem;
|
||||
font-weight: 300;
|
||||
letter-spacing: .18em;
|
||||
color: rgba(255,255,255,.8);
|
||||
margin-top: .25rem;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
/* ── Navigation ───────────────────────────────────────────────────── */
|
||||
nav {
|
||||
background: #0f4e8f;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: .2rem;
|
||||
flex-wrap: wrap;
|
||||
padding: .4rem 1rem;
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: rgba(255,255,255,.85);
|
||||
text-decoration: none;
|
||||
font-size: .88rem;
|
||||
padding: .45rem .9rem;
|
||||
border-radius: 4px;
|
||||
transition: background .15s;
|
||||
}
|
||||
|
||||
nav a:hover { background: rgba(255,255,255,.15); color: #fff; }
|
||||
nav a[aria-current="page"] { background: rgba(255,255,255,.18); color: #fff; }
|
||||
|
||||
/* ── Corps ────────────────────────────────────────────────────────── */
|
||||
main {
|
||||
max-width: 860px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 3rem 1.5rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.6rem;
|
||||
color: #0f4e8f;
|
||||
line-height: 1.25;
|
||||
margin-bottom: .8rem;
|
||||
}
|
||||
|
||||
.chapeau {
|
||||
font-size: 1rem;
|
||||
line-height: 1.7;
|
||||
color: #4a5a6a;
|
||||
max-width: 62ch;
|
||||
}
|
||||
|
||||
.chapeau a { color: #1a6bbf; }
|
||||
|
||||
.bouton {
|
||||
display: inline-block;
|
||||
background: #1a6bbf;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: .95rem;
|
||||
padding: .7rem 1.4rem;
|
||||
border-radius: 8px;
|
||||
transition: background .15s, transform .15s;
|
||||
}
|
||||
|
||||
.bouton:hover { background: #0f4e8f; transform: translateY(-2px); }
|
||||
|
||||
/* ── Pied de page ─────────────────────────────────────────────────── */
|
||||
footer {
|
||||
background: #0f4e8f;
|
||||
color: rgba(255,255,255,.75);
|
||||
text-align: center;
|
||||
padding: 1.6rem 1.5rem;
|
||||
font-size: .85rem;
|
||||
}
|
||||
|
||||
footer a { color: rgba(255,255,255,.9); text-decoration: none; }
|
||||
footer a:hover { text-decoration: underline; }
|
||||
|
|
@ -437,6 +437,8 @@
|
|||
}
|
||||
|
||||
.ev-modal-body { font-size: .92rem; line-height: 1.6; color: #444; }
|
||||
.ev-modal-body a { color: #1a6bbf; word-break: break-word; }
|
||||
.ev-modal-body a:hover { text-decoration: none; }
|
||||
|
||||
.event-date {
|
||||
font-size: .82rem;
|
||||
|
|
@ -636,6 +638,36 @@
|
|||
color: #1a6bbf;
|
||||
}
|
||||
|
||||
/* Un service annoncé mais pas encore ouvert : visible, pas cliquable. */
|
||||
.service-card.a-venir {
|
||||
background: #fbfcfe;
|
||||
border: 1px dashed #c9d8e8;
|
||||
box-shadow: none;
|
||||
color: #8a99aa;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.service-card.a-venir:hover {
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
color: #8a99aa;
|
||||
}
|
||||
|
||||
.service-card.a-venir .service-icon { filter: grayscale(1); opacity: .6; }
|
||||
|
||||
.service-bientot {
|
||||
display: inline-block;
|
||||
margin-top: .5rem;
|
||||
font-size: .68rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .06em;
|
||||
color: #7a8ba0;
|
||||
background: #eef3f9;
|
||||
border-radius: 3px;
|
||||
padding: .15rem .5rem;
|
||||
}
|
||||
|
||||
.service-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: .6rem;
|
||||
|
|
@ -702,6 +734,7 @@
|
|||
<a href="https://portail.alpinux.org">Portail membres</a>
|
||||
<a href="https://installparty.alpinux.org">Install Party</a>
|
||||
<a href="https://gitea.alpinux.org">Gitea</a>
|
||||
<a href="/modifications.html">Mises à jour du wiki</a>
|
||||
<a href="https://messagerie.alpinux.org">Listes de diffusion</a>
|
||||
<a href="https://www.helloasso.com/associations/alpinux-le-lug-de-savoie">Adhérer</a>
|
||||
</nav>
|
||||
|
|
@ -755,6 +788,8 @@
|
|||
<div class="wiki-list" id="wiki-list"></div>
|
||||
<p class="wiki-more">
|
||||
<a href="https://wiki.alpinux.org">Parcourir tout le wiki →</a>
|
||||
·
|
||||
<a href="/modifications.html">Toutes les mises à jour →</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
|
@ -785,11 +820,12 @@
|
|||
<div class="service-name">Listes de diffusion</div>
|
||||
<div class="service-desc">S'abonner aux annonces, relire les archives</div>
|
||||
</a>
|
||||
<a href="https://dynamic.alpinux.org" class="service-card">
|
||||
<div class="service-card a-venir" aria-disabled="true">
|
||||
<div class="service-icon">🎮</div>
|
||||
<div class="service-name">Jeux & quiz</div>
|
||||
<div class="service-desc">Mini-jeux et questionnaires interactifs</div>
|
||||
</a>
|
||||
<span class="service-bientot">Bientôt</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="news-section" hidden>
|
||||
|
|
@ -1054,6 +1090,30 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Le calendrier est saisi par des humains : son texte est du texte, jamais du HTML. */
|
||||
function echapper(texte) {
|
||||
return String(texte == null ? '' : texte)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
/* Rend cliquables les adresses écrites dans un descriptif. Le texte reçu est déjà
|
||||
échappé — le motif s'arrête donc avant une balise — et la ponctuation qui termine
|
||||
une phrase reste en dehors du lien. */
|
||||
function avecLiens(texteEchappe) {
|
||||
return texteEchappe.replace(/https?:\/\/[^\s<]+/g, function(url) {
|
||||
var queue = '';
|
||||
var fin = /[.,;:!?»)\]]+$/.exec(url);
|
||||
if (fin) {
|
||||
queue = fin[0];
|
||||
url = url.slice(0, url.length - queue.length);
|
||||
}
|
||||
return '<a href="' + url + '" target="_blank" rel="noopener">' + url + '</a>' + queue;
|
||||
});
|
||||
}
|
||||
|
||||
function showDetail(date, evs, el) {
|
||||
el.hidden = false;
|
||||
el.innerHTML = '<strong>' +
|
||||
|
|
@ -1063,9 +1123,9 @@
|
|||
var time = e.allDay ? '' :
|
||||
' <span class="ev-loc">' +
|
||||
e.start.toLocaleTimeString('fr-FR', { hour:'2-digit', minute:'2-digit' }) + '</span>';
|
||||
return '<li>' + e.title + time +
|
||||
return '<li>' + echapper(e.title) + time +
|
||||
(e.desc ? ' <span class="ev-has-desc" title="Descriptif disponible">ℹ</span>' : '') +
|
||||
(e.location ? '<span class="ev-loc"> — ' + e.location + '</span>' : '') +
|
||||
(e.location ? '<span class="ev-loc"> — ' + echapper(e.location) + '</span>' : '') +
|
||||
'</li>';
|
||||
}).join('') + '</ul>';
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
|
|
@ -1086,11 +1146,11 @@
|
|||
var descHtml = '';
|
||||
if (ev.desc) {
|
||||
descHtml = '<p style="margin-top:.8rem;color:#555;font-size:.88rem;white-space:pre-line">' +
|
||||
ev.desc.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') + '</p>';
|
||||
avecLiens(echapper(ev.desc)) + '</p>';
|
||||
}
|
||||
body.innerHTML =
|
||||
'<p>📅 ' + dateStr + '</p>' +
|
||||
(ev.location ? '<p style="margin-top:.4rem">📍 ' + ev.location + '</p>' : '') +
|
||||
(ev.location ? '<p style="margin-top:.4rem">📍 ' + avecLiens(echapper(ev.location)) + '</p>' : '') +
|
||||
descHtml;
|
||||
modal.hidden = false;
|
||||
document.getElementById('ev-modal').querySelector('.ev-modal-close').focus();
|
||||
|
|
@ -1122,8 +1182,8 @@
|
|||
: ev.start.toLocaleTimeString('fr-FR', { hour:'2-digit', minute:'2-digit' }) +
|
||||
(ev.end ? ' – ' + ev.end.toLocaleTimeString('fr-FR', { hour:'2-digit', minute:'2-digit' }) : '')) +
|
||||
'</div>' +
|
||||
'<div class="event-title">' + ev.title + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + ev.location + '</div>' : '');
|
||||
'<div class="event-title">' + echapper(ev.title) + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + echapper(ev.location) + '</div>' : '');
|
||||
card.addEventListener('click', function() { openModal(ev); });
|
||||
container.appendChild(card);
|
||||
});
|
||||
|
|
@ -1145,8 +1205,8 @@
|
|||
card.innerHTML =
|
||||
(ev.desc ? '<span class="ev-has-desc" title="Descriptif disponible">ℹ</span>' : '') +
|
||||
'<div class="event-date">' + fmtDate(ev.start, ev.allDay) + '</div>' +
|
||||
'<div class="event-title">' + ev.title + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + ev.location + '</div>' : '');
|
||||
'<div class="event-title">' + echapper(ev.title) + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + echapper(ev.location) + '</div>' : '');
|
||||
card.addEventListener('click', function() { openModal(ev); });
|
||||
container.appendChild(card);
|
||||
});
|
||||
|
|
|
|||
352
site/modifications.html
Normal file
352
site/modifications.html
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="Toutes les pages du wiki d'Alpinux, de la plus récemment mise à jour à la plus ancienne.">
|
||||
<meta name="robots" content="index, follow">
|
||||
<title>Les mises à jour du wiki — Alpinux</title>
|
||||
|
||||
<link rel="canonical" href="https://alpinux.org/modifications.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="https://static.alpinux.org/logo/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="https://static.alpinux.org/logo/favicon-32.png">
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="https://static.alpinux.org/logo/favicon-192.png">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Alpinux">
|
||||
<meta property="og:title" content="Les mises à jour du wiki — Alpinux">
|
||||
<meta property="og:description" content="Toutes les pages du wiki d'Alpinux, de la plus récemment mise à jour à la plus ancienne.">
|
||||
<meta property="og:url" content="https://alpinux.org/modifications.html">
|
||||
<meta property="og:image" content="https://static.alpinux.org/logo/alpinux-logo-512.png">
|
||||
<meta property="og:locale" content="fr_FR">
|
||||
|
||||
<link rel="stylesheet" href="/commun.css">
|
||||
<style>
|
||||
.barre {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
margin: 1.8rem 0 1.2rem;
|
||||
}
|
||||
|
||||
.barre input {
|
||||
flex: 1 1 260px;
|
||||
font: inherit;
|
||||
font-size: .95rem;
|
||||
padding: .6rem .9rem;
|
||||
border: 2px solid #dce8f5;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
color: inherit;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.barre input:focus {
|
||||
outline: none;
|
||||
border-color: #1a6bbf;
|
||||
}
|
||||
|
||||
.compte {
|
||||
font-size: .85rem;
|
||||
color: #7a8ba0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mois {
|
||||
font-size: .78rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .08em;
|
||||
text-transform: uppercase;
|
||||
color: #0f4e8f;
|
||||
background: #e8f1fb;
|
||||
border-radius: 4px;
|
||||
padding: .3rem .6rem;
|
||||
display: inline-block;
|
||||
margin: 1.8rem 0 .8rem;
|
||||
}
|
||||
|
||||
.pages { list-style: none; }
|
||||
|
||||
.page-ligne {
|
||||
display: grid;
|
||||
grid-template-columns: 5.5rem 1fr;
|
||||
gap: 1rem;
|
||||
align-items: baseline;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
border-left: 4px solid #9fc5e8;
|
||||
box-shadow: 0 2px 10px rgba(26,107,191,.08);
|
||||
padding: .85rem 1.1rem;
|
||||
margin-bottom: .6rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: transform .15s, box-shadow .15s;
|
||||
}
|
||||
|
||||
.page-ligne:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(26,107,191,.18);
|
||||
}
|
||||
|
||||
.page-ligne:hover .page-titre { color: #1a6bbf; }
|
||||
|
||||
.page-date {
|
||||
font-size: .8rem;
|
||||
font-weight: 700;
|
||||
color: #7a8ba0;
|
||||
letter-spacing: .04em;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.page-titre {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.page-rubrique {
|
||||
display: block;
|
||||
font-size: .8rem;
|
||||
color: #7a8ba0;
|
||||
margin-top: .15rem;
|
||||
}
|
||||
|
||||
.badge {
|
||||
background: #f5a623;
|
||||
color: #fff;
|
||||
font-size: .66rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .06em;
|
||||
padding: .1rem .45rem;
|
||||
border-radius: 3px;
|
||||
margin-left: .5rem;
|
||||
vertical-align: .1em;
|
||||
}
|
||||
|
||||
.etat {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(26,107,191,.08);
|
||||
padding:1.4rem;
|
||||
font-size: .95rem;
|
||||
color: #4a5a6a;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.etat a { color: #1a6bbf; }
|
||||
|
||||
.genere {
|
||||
margin-top: 2rem;
|
||||
font-size: .8rem;
|
||||
color: #93a2b3;
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
.page-ligne { grid-template-columns: 1fr; gap: .25rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<a href="/" class="logo-wrap">
|
||||
<img src="https://static.alpinux.org/logo/alpinux-logo.png"
|
||||
alt="Logo Alpinux — LUG de Savoie"
|
||||
class="logo-img" width="66" height="66">
|
||||
<span class="logo-text">
|
||||
<span class="brand">
|
||||
<span class="light">A</span><span class="bold">l</span><span class="light">p</span><span class="bold">inux</span>
|
||||
</span>
|
||||
<span class="tagline">le LUG de Savoie</span>
|
||||
</span>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<nav aria-label="Navigation principale">
|
||||
<a href="/">Accueil</a>
|
||||
<a href="https://wiki.alpinux.org">Wiki</a>
|
||||
<a href="/modifications.html" aria-current="page">Mises à jour</a>
|
||||
<a href="https://portail.alpinux.org">Portail membres</a>
|
||||
<a href="https://installparty.alpinux.org">Install Party</a>
|
||||
<a href="https://messagerie.alpinux.org">Listes de diffusion</a>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<h1>Les mises à jour du wiki</h1>
|
||||
<p class="chapeau">
|
||||
Toutes les pages de <a href="https://wiki.alpinux.org">wiki.alpinux.org</a>, de la
|
||||
plus récemment retouchée à la plus ancienne. Les dates viennent de l'historique du
|
||||
dépôt : c'est le jour où le texte a changé, pas celui où le fichier a été recopié.
|
||||
Déplacer une page ne la fait donc pas remonter ici.
|
||||
</p>
|
||||
|
||||
<div class="barre">
|
||||
<label for="filtre" class="sr-only" hidden>Filtrer les pages</label>
|
||||
<input id="filtre" type="search" placeholder="Filtrer par titre ou rubrique…"
|
||||
autocomplete="off" hidden>
|
||||
<span class="compte" id="compte"></span>
|
||||
</div>
|
||||
|
||||
<div id="etat" class="etat">Chargement de la liste…</div>
|
||||
<ol class="pages" id="pages"></ol>
|
||||
<p class="genere" id="genere" hidden></p>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>© Alpinux — Association loi 1901 · Chambéry, Savoie</p>
|
||||
<p style="margin-top:.4rem;">
|
||||
<a href="https://wiki.alpinux.org/alpinux/">À propos</a> ·
|
||||
<a href="https://wiki.alpinux.org/alpinux/faq/">FAQ</a> ·
|
||||
<a href="https://wiki.alpinux.org/alpinux/donnees-personnelles/">Vos données</a> ·
|
||||
<a href="https://messagerie.alpinux.org/archives">Archives des listes</a> ·
|
||||
<a href="https://www.helloasso.com/associations/alpinux-le-lug-de-savoie">Adhérer</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* Le wiki publie l'inventaire complet à chaque build. Le second fichier est celui
|
||||
que lit l'accueil : il ne porte que vingt entrées, mais il existe depuis plus
|
||||
longtemps — s'en contenter vaut mieux qu'une page vide. */
|
||||
var SOURCES = [
|
||||
{ url: 'https://wiki.alpinux.org/toutes-les-pages.json', clef: 'pages', partiel: false },
|
||||
{ url: 'https://wiki.alpinux.org/derniers-articles.json', clef: 'articles', partiel: true }
|
||||
];
|
||||
|
||||
var etat = document.getElementById('etat');
|
||||
var liste = document.getElementById('pages');
|
||||
var compte = document.getElementById('compte');
|
||||
var filtre = document.getElementById('filtre');
|
||||
var genere = document.getElementById('genere');
|
||||
|
||||
var MOIS = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',
|
||||
'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'];
|
||||
|
||||
var toutes = [];
|
||||
|
||||
function echappe(texte) {
|
||||
var d = document.createElement('div');
|
||||
d.textContent = texte;
|
||||
return d.innerHTML;
|
||||
}
|
||||
|
||||
function sansAccent(texte) {
|
||||
return texte.normalize ? texte.normalize('NFD').replace(/[̀-ͯ]/g, '') : texte;
|
||||
}
|
||||
|
||||
function ligne(page) {
|
||||
var a = document.createElement('a');
|
||||
a.className = 'page-ligne';
|
||||
a.href = page.url;
|
||||
a.innerHTML =
|
||||
'<time class="page-date" datetime="' + echappe(page.date) + '">' +
|
||||
page.d.getDate() + ' ' + MOIS[page.d.getMonth()].slice(0, 4) + '.' +
|
||||
'</time>' +
|
||||
'<span>' +
|
||||
'<span class="page-titre">' + echappe(page.titre) +
|
||||
(page.nouveau ? '<span class="badge">Nouveau</span>' : '') +
|
||||
'</span>' +
|
||||
(page.rubrique ? '<span class="page-rubrique">' + echappe(page.rubrique) + '</span>' : '') +
|
||||
'</span>';
|
||||
return a;
|
||||
}
|
||||
|
||||
function dessiner(pages) {
|
||||
liste.textContent = '';
|
||||
var moisCourant = '';
|
||||
|
||||
pages.forEach(function (page) {
|
||||
var cle = page.d.getFullYear() + '-' + page.d.getMonth();
|
||||
if (cle !== moisCourant) {
|
||||
moisCourant = cle;
|
||||
var titre = document.createElement('li');
|
||||
titre.className = 'mois';
|
||||
titre.textContent = MOIS[page.d.getMonth()] + ' ' + page.d.getFullYear();
|
||||
liste.appendChild(titre);
|
||||
}
|
||||
var li = document.createElement('li');
|
||||
li.appendChild(ligne(page));
|
||||
liste.appendChild(li);
|
||||
});
|
||||
|
||||
compte.textContent = pages.length + (pages.length > 1 ? ' pages' : ' page') +
|
||||
(pages.length !== toutes.length ? ' sur ' + toutes.length : '');
|
||||
}
|
||||
|
||||
function appliquerLeFiltre() {
|
||||
var q = sansAccent(filtre.value.trim().toLowerCase());
|
||||
if (!q) return dessiner(toutes);
|
||||
dessiner(toutes.filter(function (page) {
|
||||
return sansAccent((page.titre + ' ' + (page.rubrique || '')).toLowerCase()).indexOf(q) !== -1;
|
||||
}));
|
||||
}
|
||||
|
||||
async function lire(source) {
|
||||
var r = await fetch(source.url, { cache: 'no-cache' });
|
||||
if (!r.ok) throw new Error(r.status);
|
||||
var data = await r.json();
|
||||
var brut = data[source.clef];
|
||||
if (!Array.isArray(brut) || !brut.length) throw new Error('vide');
|
||||
return { data: data, brut: brut };
|
||||
}
|
||||
|
||||
async function charger() {
|
||||
var lu = null, source = null;
|
||||
|
||||
for (var i = 0; i < SOURCES.length && !lu; i++) {
|
||||
try {
|
||||
lu = await lire(SOURCES[i]);
|
||||
source = SOURCES[i];
|
||||
} catch (_) { /* on essaie la source suivante */ }
|
||||
}
|
||||
|
||||
if (!lu) {
|
||||
etat.innerHTML = 'La liste n\'a pas pu être chargée. ' +
|
||||
'Le wiki reste consultable sur <a href="https://wiki.alpinux.org">wiki.alpinux.org</a>.';
|
||||
return;
|
||||
}
|
||||
|
||||
toutes = lu.brut
|
||||
.map(function (page) {
|
||||
var d = new Date(page.date);
|
||||
return (page && page.titre && page.url && !isNaN(d)) ?
|
||||
{ titre: page.titre, url: page.url, date: page.date,
|
||||
nouveau: !!page.nouveau, rubrique: page.rubrique || '', d: d } : null;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.sort(function (a, b) { return b.d - a.d; });
|
||||
|
||||
if (!toutes.length) {
|
||||
etat.textContent = 'Le wiki n\'annonce aucune page pour le moment.';
|
||||
return;
|
||||
}
|
||||
|
||||
etat.hidden = true;
|
||||
filtre.hidden = false;
|
||||
filtre.addEventListener('input', appliquerLeFiltre);
|
||||
dessiner(toutes);
|
||||
|
||||
var quand = new Date(lu.data.genere);
|
||||
genere.textContent =
|
||||
(source.partiel
|
||||
? 'Le wiki ne publie pour l\'instant que ses vingt dernières pages. '
|
||||
: '') +
|
||||
(isNaN(quand) ? '' : 'Liste publiée par le wiki le ' +
|
||||
quand.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' }) +
|
||||
' à ' + quand.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }) + '.');
|
||||
genere.hidden = !genere.textContent;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', charger);
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -22,12 +22,6 @@
|
|||
"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",
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@
|
|||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://alpinux.org/</loc>
|
||||
<lastmod>2026-05-03</lastmod>
|
||||
<lastmod>2026-09-23</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://alpinux.org/modifications.html</loc>
|
||||
<lastmod>2026-09-23</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
|
|
|
|||
Loading…
Reference in a new issue