440 lines
14 KiB
HTML
440 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="description" content="Alpinux — Le LUG de Savoie. Groupe d'utilisateurs de Linux et logiciels libres à Chambéry. Réunions tous les 1er et 3e jeudis du mois.">
|
|
<meta name="robots" content="index, follow">
|
|
<title>Alpinux — Le LUG de Savoie</title>
|
|
|
|
<!-- Canonical -->
|
|
<link rel="canonical" href="https://alpinux.org/">
|
|
|
|
<!-- Favicons -->
|
|
<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="icon" type="image/png" sizes="96x96" href="https://static.alpinux.org/logo/favicon-96.png">
|
|
<link rel="apple-touch-icon" sizes="192x192" href="https://static.alpinux.org/logo/favicon-192.png">
|
|
|
|
<!-- Open Graph -->
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:site_name" content="Alpinux">
|
|
<meta property="og:title" content="Alpinux — Le LUG de Savoie">
|
|
<meta property="og:description" content="Association dédiée à Linux et aux logiciels libres en Savoie. Réunions à la Dynamo Chambéry tous les 1er et 3e jeudis du mois.">
|
|
<meta property="og:url" content="https://alpinux.org/">
|
|
<meta property="og:image" content="https://static.alpinux.org/logo/alpinux-logo-512.png">
|
|
<meta property="og:locale" content="fr_FR">
|
|
|
|
<!-- Twitter Card -->
|
|
<meta name="twitter:card" content="summary">
|
|
<meta name="twitter:title" content="Alpinux — Le LUG de Savoie">
|
|
<meta name="twitter:description" content="Association dédiée à Linux et aux logiciels libres en Savoie.">
|
|
<meta name="twitter:image" content="https://static.alpinux.org/logo/alpinux-logo-512.png">
|
|
<meta name="twitter:site" content="@alpinux">
|
|
|
|
<!-- Structured data -->
|
|
<script type="application/ld+json">
|
|
{
|
|
"@context": "https://schema.org",
|
|
"@type": "Organization",
|
|
"name": "Alpinux",
|
|
"alternateName": "Alpinux — LUG de Savoie",
|
|
"url": "https://alpinux.org",
|
|
"logo": "https://static.alpinux.org/logo/alpinux-logo-512.png",
|
|
"description": "Association loi 1901 dédiée à Linux et aux logiciels libres en Savoie. Groupe d'utilisateurs Linux (LUG) basé à Chambéry.",
|
|
"foundingLocation": {
|
|
"@type": "Place",
|
|
"name": "Chambéry",
|
|
"address": {
|
|
"@type": "PostalAddress",
|
|
"addressLocality": "Chambéry",
|
|
"addressRegion": "Savoie",
|
|
"addressCountry": "FR"
|
|
}
|
|
},
|
|
"location": {
|
|
"@type": "Place",
|
|
"name": "Dynamo Chambéry",
|
|
"address": {
|
|
"@type": "PostalAddress",
|
|
"addressLocality": "Chambéry",
|
|
"addressRegion": "Savoie",
|
|
"addressCountry": "FR"
|
|
}
|
|
},
|
|
"sameAs": [
|
|
"https://mamot.fr/@alpinux",
|
|
"https://www.helloasso.com/associations/alpinux-le-lug-de-savoie",
|
|
"https://gitea.alpinux.org/alpinux.cedrica5l"
|
|
]
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
*, *::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;
|
|
}
|
|
|
|
/* ── Header ────────────────────────────────────────────────── */
|
|
header {
|
|
background: #1a6bbf;
|
|
color: #fff;
|
|
padding: 3rem 1.5rem 2.5rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.logo-wrap {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 1.2rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.logo-img {
|
|
width: 90px;
|
|
height: 90px;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.logo-text {
|
|
text-align: left;
|
|
}
|
|
|
|
.brand {
|
|
font-size: 2.8rem;
|
|
line-height: 1;
|
|
color: #fff;
|
|
letter-spacing: -.02em;
|
|
}
|
|
|
|
.brand .light { font-weight: 300; }
|
|
.brand .bold { font-weight: 800; }
|
|
|
|
.tagline {
|
|
font-size: 1rem;
|
|
font-weight: 300;
|
|
letter-spacing: .18em;
|
|
color: rgba(255,255,255,.8);
|
|
margin-top: .3rem;
|
|
text-transform: lowercase;
|
|
}
|
|
|
|
.hero-text {
|
|
max-width: 640px;
|
|
margin: 1.8rem auto 0;
|
|
font-size: 1.05rem;
|
|
color: rgba(255,255,255,.88);
|
|
line-height: 1.7;
|
|
}
|
|
|
|
/* ── Nav links ──────────────────────────────────────────────── */
|
|
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; }
|
|
|
|
/* ── Main ───────────────────────────────────────────────────── */
|
|
main {
|
|
max-width: 960px;
|
|
margin: 0 auto;
|
|
padding: 3rem 1.5rem;
|
|
}
|
|
|
|
/* ── Events ─────────────────────────────────────────────────── */
|
|
.section-title {
|
|
font-size: 1.15rem;
|
|
font-weight: 700;
|
|
color: #0f4e8f;
|
|
margin-bottom: 1.2rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .6rem;
|
|
}
|
|
|
|
.section-title::after {
|
|
content: '';
|
|
flex: 1;
|
|
height: 2px;
|
|
background: #e8f1fb;
|
|
}
|
|
|
|
.events {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
gap: 1rem;
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
.event-card {
|
|
background: #fff;
|
|
border-radius: 10px;
|
|
padding: 1.2rem 1.4rem;
|
|
box-shadow: 0 2px 10px rgba(26,107,191,.1);
|
|
border-left: 4px solid #1a6bbf;
|
|
}
|
|
|
|
.event-date {
|
|
font-size: .82rem;
|
|
font-weight: 700;
|
|
color: #1a6bbf;
|
|
letter-spacing: .06em;
|
|
text-transform: uppercase;
|
|
margin-bottom: .3rem;
|
|
}
|
|
|
|
.event-title { font-size: 1rem; font-weight: 600; }
|
|
.event-where { font-size: .88rem; color: #666; margin-top: .3rem; }
|
|
|
|
/* ── Services ───────────────────────────────────────────────── */
|
|
.services {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
|
|
.service-card {
|
|
background: #fff;
|
|
border-radius: 10px;
|
|
padding: 1.4rem;
|
|
box-shadow: 0 2px 10px rgba(26,107,191,.08);
|
|
text-align: center;
|
|
text-decoration: none;
|
|
color: #1a1a2e;
|
|
transition: transform .15s, box-shadow .15s;
|
|
display: block;
|
|
}
|
|
|
|
.service-card:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 6px 20px rgba(26,107,191,.18);
|
|
color: #1a6bbf;
|
|
}
|
|
|
|
.service-icon {
|
|
font-size: 2rem;
|
|
margin-bottom: .6rem;
|
|
}
|
|
|
|
.service-name {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
margin-bottom: .3rem;
|
|
}
|
|
|
|
.service-desc {
|
|
font-size: .84rem;
|
|
color: #666;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* ── Footer ─────────────────────────────────────────────────── */
|
|
footer {
|
|
background: #0f4e8f;
|
|
color: rgba(255,255,255,.7);
|
|
text-align: center;
|
|
padding: 1.5rem;
|
|
font-size: .85rem;
|
|
}
|
|
|
|
footer a { color: rgba(255,255,255,.85); text-decoration: none; }
|
|
footer a:hover { color: #fff; }
|
|
|
|
@media (max-width: 480px) {
|
|
.brand { font-size: 2.2rem; }
|
|
.logo-img { width: 70px; height: 70px; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<div class="logo-wrap">
|
|
<img src="https://static.alpinux.org/logo/alpinux-logo.png"
|
|
alt="Logo Alpinux — LUG de Savoie"
|
|
class="logo-img"
|
|
width="90" height="90">
|
|
<div class="logo-text">
|
|
<div class="brand">
|
|
<span class="light">A</span><span class="bold">l</span><span class="light">p</span><span class="bold">inux</span>
|
|
</div>
|
|
<div class="tagline">le LUG de Savoie</div>
|
|
</div>
|
|
</div>
|
|
<p class="hero-text">
|
|
Association loi 1901 dédiée à <strong>Linux et aux logiciels libres</strong> en Savoie.
|
|
Réunions tous les 1<sup>er</sup> et 3<sup>e</sup> jeudis du mois à la <strong>Dynamo Chambéry</strong>.
|
|
</p>
|
|
</header>
|
|
|
|
<nav aria-label="Navigation principale">
|
|
<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://mamot.fr/@alpinux" rel="me">Mastodon</a>
|
|
<a href="https://www.helloasso.com/associations/alpinux-le-lug-de-savoie">Adhérer</a>
|
|
</nav>
|
|
|
|
<main>
|
|
|
|
<h2 class="section-title">Prochains événements</h2>
|
|
<div class="events" id="events-container">
|
|
<div class="event-card" id="static-reunion">
|
|
<div class="event-date">1<sup>er</sup> & 3<sup>e</sup> jeudis</div>
|
|
<div class="event-title">Réunion mensuelle</div>
|
|
<div class="event-where">📍 Dynamo Chambéry — 18h00</div>
|
|
</div>
|
|
<div class="event-card" id="static-installparty">
|
|
<div class="event-date">Voir le calendrier</div>
|
|
<div class="event-title">Install Party & ateliers</div>
|
|
<div class="event-where">📅 <a href="https://installparty.alpinux.org" style="color:#1a6bbf;">installparty.alpinux.org</a></div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2 class="section-title">Nos services</h2>
|
|
<div class="services">
|
|
<a href="https://wiki.alpinux.org" class="service-card">
|
|
<div class="service-icon">📖</div>
|
|
<div class="service-name">Wiki</div>
|
|
<div class="service-desc">Guides, tutoriels et présentations</div>
|
|
</a>
|
|
<a href="https://portail.alpinux.org" class="service-card">
|
|
<div class="service-icon">🔐</div>
|
|
<div class="service-name">Portail membres</div>
|
|
<div class="service-desc">Espace adhérent, Nextcloud, Dolibarr</div>
|
|
</a>
|
|
<a href="https://installparty.alpinux.org" class="service-card">
|
|
<div class="service-icon">🐧</div>
|
|
<div class="service-name">Install Party</div>
|
|
<div class="service-desc">Événements & inscriptions</div>
|
|
</a>
|
|
<a href="https://gitea.alpinux.org" class="service-card">
|
|
<div class="service-icon">💻</div>
|
|
<div class="service-name">Gitea</div>
|
|
<div class="service-desc">Dépôts de code de l'association</div>
|
|
</a>
|
|
<a href="https://dynamic.alpinux.org" class="service-card">
|
|
<div class="service-icon">🎮</div>
|
|
<div class="service-name">Jeux & quiz</div>
|
|
<div class="service-desc">Mini-jeux et questionnaires interactifs</div>
|
|
</a>
|
|
</div>
|
|
|
|
</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://mamot.fr/@alpinux" rel="me">Mastodon</a> ·
|
|
<a href="https://www.helloasso.com/associations/alpinux-le-lug-de-savoie">Adhérer</a>
|
|
</p>
|
|
</footer>
|
|
|
|
|
|
<script>
|
|
(function () {
|
|
const CAL_URL = '/public-calendars/n5BWPYsxw7FCYozM';
|
|
|
|
function unfold(ics) {
|
|
return ics.replace(/\r\n[ \t]/g, '').replace(/\n[ \t]/g, '');
|
|
}
|
|
|
|
function parseDate(line) {
|
|
const ci = line.indexOf(':');
|
|
const params = line.substring(0, ci).toUpperCase();
|
|
const val = line.substring(ci + 1).trim();
|
|
const y = +val.substring(0, 4), mo = +val.substring(4, 6) - 1, d = +val.substring(6, 8);
|
|
if (params.includes('VALUE=DATE') || /^\d{8}$/.test(val))
|
|
return { date: new Date(y, mo, d), allDay: true };
|
|
const h = +val.substring(9, 11), mi = +val.substring(11, 13), s = +val.substring(13, 15);
|
|
const dt = val.endsWith('Z')
|
|
? new Date(Date.UTC(y, mo, d, h, mi, s))
|
|
: new Date(y, mo, d, h, mi, s);
|
|
return { date: dt, allDay: false };
|
|
}
|
|
|
|
function parseICS(text) {
|
|
const lines = unfold(text).split(/\r?\n/);
|
|
const events = [], cap = /^(.+?)(;[^:]*)?:(.*)$/;
|
|
let cur = null;
|
|
for (const line of lines) {
|
|
if (line === 'BEGIN:VEVENT') { cur = {}; continue; }
|
|
if (line === 'END:VEVENT') { if (cur && cur.start) events.push(cur); cur = null; continue; }
|
|
if (!cur) continue;
|
|
const m = cap.exec(line);
|
|
if (!m) continue;
|
|
const key = m[1].toUpperCase();
|
|
const val = m[3];
|
|
if (key === 'SUMMARY') cur.title = val.replace(/\\,/g, ',').replace(/\\n/g, ' ');
|
|
if (key === 'LOCATION') cur.location = val.replace(/\\,/g, ',');
|
|
if (key === 'DTSTART') cur.start = parseDate(line);
|
|
}
|
|
return events;
|
|
}
|
|
|
|
function fmtDate(d, allDay) {
|
|
const opts = { weekday: 'long', day: 'numeric', month: 'long' };
|
|
if (!allDay) opts.hour = '2-digit', opts.minute = '2-digit';
|
|
return d.toLocaleDateString('fr-FR', opts);
|
|
}
|
|
|
|
function makeCard(ev) {
|
|
const card = document.createElement('div');
|
|
card.className = 'event-card';
|
|
card.innerHTML =
|
|
'<div class="event-date">' + fmtDate(ev.start.date, ev.start.allDay) + '</div>' +
|
|
'<div class="event-title">' + ev.title + '</div>' +
|
|
(ev.location ? '<div class="event-where">📍 ' + ev.location + '</div>' : '');
|
|
return card;
|
|
}
|
|
|
|
async function load() {
|
|
try {
|
|
const r = await fetch(CAL_URL);
|
|
if (!r.ok) return;
|
|
const text = await r.text();
|
|
if (!text.trim()) return;
|
|
const now = new Date();
|
|
now.setHours(0, 0, 0, 0);
|
|
const upcoming = parseICS(text)
|
|
.filter(e => e.start.date >= now)
|
|
.sort((a, b) => a.start.date - b.start.date)
|
|
.slice(0, 6);
|
|
if (!upcoming.length) return;
|
|
|
|
const container = document.getElementById('events-container');
|
|
const anchor = document.getElementById('static-installparty');
|
|
const staticReunion = document.getElementById('static-reunion');
|
|
if (staticReunion) staticReunion.remove();
|
|
upcoming.forEach(ev => container.insertBefore(makeCard(ev), anchor));
|
|
} catch (_) { /* silently keep static tiles */ }
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', load);
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|