diff --git a/assets/main.js b/assets/main.js
index 045004f..4b13010 100644
--- a/assets/main.js
+++ b/assets/main.js
@@ -89,46 +89,179 @@ function chargerAlbums() {
});
}
-/* === FEED DEPECHES (depeches.html) === */
+/* ═══════════════════════════════════════════════════
+ DEPECHES — VERSION ENRICHIE
+ ═══════════════════════════════════════════════════ */
+
+/* ── helpers texte ───────────────────────────────── */
+function escapeHtml(str) {
+ return str
+ .replace(/&/g, '&')
+ .replace(//g, '>');
+}
+
+function parseMarkdown(text) {
+ // gras
+ text = text.replace(/\*\*([^*]+)\*\*/g, '$1');
+ // italique
+ text = text.replace(/\*([^*]+)\*/g, '$1');
+ // barré
+ text = text.replace(/~~([^~]+)~~/g, '$1');
+ // code inline
+ text = text.replace(/`([^`]+)`/g, '$1');
+ return text;
+}
+
+function parseHashtags(text) {
+ return text.replace(/(^|\s)(#[\wÀ-ÿ]+)/g, (m, before, tag) => {
+ const q = encodeURIComponent(tag);
+ return `${before}${tag}`;
+ });
+}
+
+function parseMentions(text) {
+ return text.replace(/(^|\s)(@[\w.]+)/g, (m, before, mention) => {
+ return `${before}${mention}`;
+ });
+}
+
+function timeAgo(dateStr) {
+ const m = dateStr.match(/(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2})/);
+ if (!m) return dateStr;
+ const [, d, mo, y, H, Mi] = m;
+ const date = new Date(`${y}-${mo}-${d}T${H}:${Mi}:00`);
+ const sec = Math.floor((Date.now() - date) / 1000);
+ if (sec < 60) return "à l'instant";
+ if (sec < 3600) return `il y a ${Math.floor(sec / 60)} min`;
+ if (sec < 86400)return `il y a ${Math.floor(sec / 3600)} h`;
+ if (sec < 604800)return `il y a ${Math.floor(sec / 86400)} j`;
+ if (sec < 2592000)return `il y a ${Math.floor(sec / 604800)} sem`;
+ return dateStr;
+}
+
+/* ── split texte / urls ──────────────────────────── */
+function splitTextAndUrls(text) {
+ const re = /(https?:\/\/[^\s]+)/g;
+ const parts = [];
+ let last = 0, m;
+ while ((m = re.exec(text)) !== null) {
+ if (m.index > last) parts.push({ type: 'text', value: text.slice(last, m.index) });
+ parts.push({ type: 'url', value: m[1] });
+ last = m.index + m[0].length;
+ }
+ if (last < text.length) parts.push({ type: 'text', value: text.slice(last) });
+ return parts;
+}
+
+/* ── embeds ──────────────────────────────────────── */
+function styledLink(url) {
+ try {
+ const domain = new URL(url).hostname.replace(/^www\./, '');
+ return `${escapeHtml(domain)}${escapeHtml(url)}`;
+ } catch {
+ return `${escapeHtml(url)}`;
+ }
+}
+
+async function resolveEmbed(url) {
+ /* vidéo 16:9 */
+ const yt = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
+ if (yt) return `
impossible de charger les dépêches.
'; } } -/* === LIGHTBOX (images dans les entrées) === */ +/* ═══════════════════════════════════════════════════ + LIGHTBOX + ═══════════════════════════════════════════════════ */ function initLightbox() { const contenu = document.querySelector('.fenetre-contenu'); if (!contenu) return; contenu.addEventListener('click', e => { const img = e.target.closest('img:not(.thanks)'); - if (!img) return; + if (!img || img.closest('.depeche-link') || img.closest('.embed-container')) return; const overlay = document.createElement('div'); overlay.className = 'lightbox'; @@ -203,7 +372,9 @@ function initLightbox() { }); } -/* === INIT === */ +/* ═══════════════════════════════════════════════════ + INIT + ═══════════════════════════════════════════════════ */ document.addEventListener('DOMContentLoaded', () => { animerTitreNav(); diff --git a/assets/styles.css b/assets/styles.css index 6ff1205..ae1572e 100644 --- a/assets/styles.css +++ b/assets/styles.css @@ -256,20 +256,54 @@ body { gap: 0; } +@keyframes fadeInUp { + from { opacity: 0; transform: translateY(12px); } + to { opacity: 1; transform: translateY(0); } +} + .depeche { border-top: 1px solid #ddd; padding: 1rem 0; + scroll-margin-top: 1rem; + animation: fadeInUp 0.45s ease-out both; } .depeche:last-child { border-bottom: 1px solid #ddd; } +.depeche-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 0.4rem; +} + .depeche-date { font-size: 0.75rem; font-style: italic; color: #999; - margin-bottom: 0.4rem; +} + +.depeche-actions { + display: flex; + gap: 0.3rem; +} + +.depeche-action { + font-family: 'IM Fell English', serif; + font-size: 0.8rem; + background: none; + border: none; + color: #bbb; + cursor: pointer; + padding: 0 0.2rem; + line-height: 1; + transition: color 0.2s; +} + +.depeche-action:hover { + color: #111; } .depeche-texte { @@ -277,6 +311,102 @@ body { color: #111; } +.depeche-texte strong { font-weight: bold; } +.depeche-texte em { font-style: italic; } +.depeche-texte del { text-decoration: line-through; opacity: 0.6; } + +.inline-code { + font-family: 'Courier New', monospace; + font-size: 0.8em; + background: #f4f4f4; + padding: 0.1em 0.35em; + border: 1px solid #e0e0e0; + border-radius: 2px; + color: #333; +} + +.hashtag { + color: hsl(180, 50%, 40%); + text-decoration: none; + border-bottom: 1px dotted hsl(180, 50%, 60%); +} + +.hashtag:hover { + color: hsl(180, 60%, 25%); + border-bottom-style: solid; +} + +.mention { + color: hsl(270, 40%, 50%); + font-weight: bold; +} + +.depeche-link { + display: inline-flex; + align-items: baseline; + gap: 0.35rem; + text-decoration: none; + color: inherit; + border-bottom: 1px dotted #bbb; + max-width: 100%; + overflow-wrap: anywhere; +} + +.depeche-link:hover { + border-bottom-style: solid; + border-bottom-color: #111; +} + +.link-domain { + font-size: 0.65rem; + text-transform: uppercase; + letter-spacing: 0.03em; + background: #111; + color: #fff; + padding: 0.05em 0.4em; + border-radius: 2px; + white-space: nowrap; + flex-shrink: 0; +} + +.link-url { + font-size: 0.85rem; + font-style: italic; + color: #555; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 300px; + display: inline-block; + vertical-align: bottom; +} + +.embed-container { + margin-top: 0.8rem; + width: 100%; + overflow: hidden; + border: 1px solid #ddd; + background: #fafafa; +} + +.embed-container iframe { + width: 100%; + display: block; + border: none; +} + +.embed-container.video { + aspect-ratio: 16 / 9; +} + +.embed-container.video iframe { + height: 100%; +} + +.embed-container.music iframe { + height: 152px; +} + .depeche-image { margin-top: 0.8rem; max-height: 400px;