ENRE_WEB/calendario.html
sito 8bcaf1644c Rediseño de la enredadera y páginas nuevas
Portada
- La bajada del título pasa de un trazo de grosor constante a dos cintas
  trenzadas que se afilan, con la punta rematada en zarcillo. El viewBox es
  1000x72 y la caja mide el 7.2% del ancho de la rejilla, así que la escala
  sale uniforme y el dibujo no se deforma en ninguna pantalla.
- El giro de la esquina es una Bézier cúbica de salida vertical y la franja
  entra también vertical: radio mínimo 26 unidades en vez de 15.
- La franja entera pasa de trazos a cintas. La cola deja de ser un lazo y
  abre un bucle afilado que remata una espiral logarítmica verde, con centro
  y sentido derivados de la tangente del tallo.
- El rabillo de la hoja pasa de 24 a 42 unidades (recuadro 100x132) para que
  el limbo no cruce la raíz. Con él, el origen del giro (1.52%) y la etiqueta
  (62%), que se miden sobre ese alto.
- Letra de las etiquetas un 10% mayor. "La Enre" a 164 grados y tamaño 1.16;
  "Calendario", a 1.00.

Móvil
- El tallo pasa de una recta a una onda de coseno, media vuelta por celda, en
  un recuadro cuadrado para que la escala sea uniforme. Tres dibujos: la onda,
  su espejo para las celdas pares y el remate en espiral de la última.
- Las seis hojas entran sin deslizar de 320x568 en adelante: la celda reparte
  el alto disponible en vez de medir lo que mide la hoja, --ancho-hoja se mide
  contra las dos dimensiones y la cabecera baja de 104 a 68px.
- El abanico de REDES se recoloca (centro -0.25r, apertura 0.50r) para caber
  en el hueco nuevo.

Páginas
- colectivos.html, calendario.html, eventos.html, tatus.html, panel.html y
  404.html.
- El calendario semanal esconde la semana entera vacía que dibujaba de más.

Comprobado con qa.py: 0 fallos y 0 avisos en 150 mediciones (10 páginas por
15 pantallas), con contraste, foco, brotes y HTML roto incluidos.
2026-09-09 00:34:53 +02:00

275 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calendario · La Enredadera de Tetuán</title>
<meta name="description" content="Horarios semanales de los colectivos del CSO La Enredadera de Tetuán.">
<!-- Vista previa al compartir el enlace (Mastodon, Telegram, WhatsApp). -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="CSO La Enredadera de Tetuán">
<meta property="og:locale" content="es_ES">
<meta property="og:title" content="Calendario · La Enredadera de Tetuán">
<meta property="og:description" content="Horarios semanales de los colectivos del CSO La Enredadera de Tetuán.">
<meta property="og:image" content="/INFO/cso_laenre.jpeg">
<meta property="og:image:alt" content="Fachada del CSO La Enredadera: el cartel «La Enredadera» pintado a mano letra a letra sobre la puerta, y encima el mural «El último tesoro que le queda a la ciudad, es el barrio»">
<meta name="twitter:card" content="summary_large_image">
<link rel="preload" href="/Code462WPink-Regular.ttf" as="font" type="font/ttf" crossorigin>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Anton&family=Rock+Salt&display=swap">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="stylesheet" href="/index.css">
</head>
<body>
<input type="checkbox" id="nav-toggle" class="sr-only">
<label for="nav-toggle" class="sb-toggle" aria-label="Abrir o cerrar el menú">☰</label>
<label for="nav-toggle" class="sb-overlay" aria-hidden="true"></label>
<div class="container">
<aside class="sidebar">
<img src="/INFO/logo_enre_negro.png" alt="" class="logo" width="96" height="96">
<!-- Es la marca del panel, no un encabezado de sección: como el panel
va ANTES del <main>, un <h2> aquí hacía que el primer encabezado
del documento fuera de nivel 2 y el <h1> viniera después. -->
<p class="sb-marca">La Enredadera</p>
<p class="lema">Centro Social Autogestionado en Tetuán. Haciendo barrio desde 2009.</p>
<nav class="sidebar-nav" aria-label="Secciones">
<ul>
<li><a href="/colectivos.html">Colectivos</a></li>
<li><a href="/calendario.html" aria-current="page">Calendario</a></li>
<li><a href="/eventos.html">Eventos</a></li>
<li><a href="/subdir/campa.html">Campañas</a></li>
<li><a href="/subdir/sobre_nosotrxs.html">La Enre</a></li>
<li><a href="/subdir/contacto.html">Contacto</a></li>
<li><a href="https://okupanel.laenre.net">Actividades</a></li>
<li><a href="https://www.instagram.com/la_enredadera_de_tetuan/">Instagram</a></li>
<li><a href="https://masto.es/@csolaenre">Mastodon</a></li>
</ul>
</nav>
</aside>
<main class="main">
<header class="cabecera">
<h1>CALENDARIO</h1>
<p class="sub">Qué pasa cada semana en la Enre</p>
</header>
<a class="volver" href="/index.html">← Volver a la enredadera</a>
<section class="pantalla" aria-label="Horarios semanales de colectivos">
<h2>Horarios semanales</h2>
<p class="pie">Las asambleas y talleres fijos de cada colectivo. Pulsa cualquier etiqueta para ver los eventos publicados en convoca.la.</p>
<!-- Sin JavaScript la rejilla se queda en un marco vacío, con dos flechas
que no hacen nada. Se esconden los tres trozos que dibuja el script y
se explica dónde está la información. No toca el IIFE. -->
<noscript>
<style>
#semanal-controls, #semanal-root, #semanal-legend-root{ display:none; }
</style>
<div class="gancio-fallback">
<p><strong>El horario se dibuja con JavaScript y lo tienes desactivado.</strong></p>
<p>Los horarios de cada colectivo están también en su ficha, en
<a href="/colectivos.html">Colectivos</a>, y los eventos concretos en
<a href="/eventos.html">Eventos</a>.</p>
</div>
</noscript>
<div class="cal-controls" id="semanal-controls" role="group" aria-label="Navegación de mes">
<button class="button semanal-prev" type="button" aria-label="Mes anterior">&larr;</button>
<div class="cal-title semanal-title" aria-live="polite"></div>
<button class="button semanal-next" type="button" aria-label="Mes siguiente">&rarr;</button>
</div>
<div class="cal" id="semanal-root"></div>
<div class="cal-legend" id="semanal-legend-root"></div>
<script>
(function () {
const monthNames = ['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'];
const weekdayNames = ['L','M','X','J','V','S','D'];
const ENRE_EVENTS_URL = 'https://mad.convoca.la/place/42/CSO%20La%20Enredadera';
const COLORS = {
hacklab: { bg:'#39FF14', fg:'#000', label:'Hacklab' },
artlab: { bg:'#39FF14', fg:'#ff00aa', label:'Art-Lab' },
feminismos: { bg:'#6A0DAD', fg:'#fff', label:'Feminismos' },
vivienda: { bg:'#000000', fg:'#ff00aa', label:'Vivienda' },
bicilab: { bg:'#FF7A00', fg:'#000', label:'Bicilab' },
autodefensa: { bg:'#00BCD4', fg:'#fff', label:'Autodefensa' },
fridays: { bg:'#2E8B57', fg:'#fff', label:'Fridays for Future' },
euskera: { bg:'#FF0000', fg:'#00ff00', label:'Euskera' },
asamblea_enre: { bg:'#ff00ff', fg:'#fff', label:'Asamblea Enre' },
asamblea_externas: { bg:'#fff', fg:'#ff00ff', label:'Asamblea ext.' },
montana: { bg:'#8B4513', fg:'#fff', label:'Montaña' },
teatro: { bg:'#4169E1', fg:'#fff', label:'Teatro' }
};
const WEEKLY = [
{ group:'asamblea_externas', dow:0, start:'19:00' },
{ group:'asamblea_enre', dow:0, start:'20:00' },
{ group:'autodefensa', dow:1, start:'20:00' },
{ group:'teatro', dow:2, start:'11:00' },
{ group:'autodefensa', dow:2, start:'20:00' },
{ group:'euskera', dow:2, start:'18:15' },
{ group:'vivienda', dow:3, start:'19:00' },
{ group:'feminismos', dow:3, start:'20:00' },
{ group:'bicilab', dow:6, start:'19:00' },
{ group:'montana', dow:6, start:'10:00' }
];
function createPill(text, bg, fg) {
const pill = document.createElement('div');
pill.className = 'cal-pill';
pill.style.setProperty('--bg', bg);
pill.style.setProperty('--fg', fg);
pill.textContent = text;
pill.setAttribute('role', 'link');
pill.setAttribute('tabindex', '0');
pill.addEventListener('click', () => { window.location.href = ENRE_EVENTS_URL; });
pill.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); window.location.href = ENRE_EVENTS_URL; }
});
return pill;
}
function renderWeeklyPills(cell, wd) {
const todays = WEEKLY.filter(e => e.dow === wd);
if (!todays.length) return;
const wrap = document.createElement('div');
wrap.className = 'cal-pills';
todays.forEach(e => {
const c = COLORS[e.group] || { bg:'#eee', fg:'#000', label: e.group };
wrap.appendChild(createPill(c.label + (e.start ? ' ' + e.start : ''), c.bg, c.fg));
});
cell.appendChild(wrap);
}
const root = document.getElementById('semanal-root');
const legend = document.getElementById('semanal-legend-root');
const title = document.querySelector('.semanal-title');
const btnPrev = document.querySelector('.semanal-prev');
const btnNext = document.querySelector('.semanal-next');
const today = new Date();
let view = new Date();
view.setDate(1);
function buildCalendar(date) {
root.innerHTML = '';
const year = date.getFullYear();
const month = date.getMonth();
title.textContent = monthNames[month] + ' ' + year;
const startIndex = (new Date(year, month, 1).getDay() + 6) % 7;
const daysInMonth = new Date(year, month + 1, 0).getDate();
const fridays = [];
for (let d = 1; d <= daysInMonth; d++) {
if ((new Date(year, month, d).getDay() + 6) % 7 === 4) fridays.push(d);
}
const secondFri = fridays[1];
const lastFri = fridays[fridays.length - 1];
const head = document.createElement('div');
head.className = 'cal-row cal-head';
weekdayNames.forEach(w => {
const cell = document.createElement('div');
cell.className = 'cal-cell cal-head-cell';
cell.textContent = w;
head.appendChild(cell);
});
root.appendChild(head);
let day = 1 - startIndex;
for (let r = 0; r < 6; r++) {
const row = document.createElement('div');
row.className = 'cal-row';
for (let c = 0; c < 7; c++) {
const cell = document.createElement('div');
cell.className = 'cal-cell';
if (day >= 1 && day <= daysInMonth) {
if (year === today.getFullYear() && month === today.getMonth() && day === today.getDate())
cell.classList.add('cal-today');
const num = document.createElement('span');
num.className = 'cal-daynum';
num.textContent = day;
cell.appendChild(num);
const wd = (new Date(year, month, day).getDay() + 6) % 7;
if (wd === 4) {
const wrap = document.createElement('div');
wrap.className = 'cal-pills';
if (day === secondFri)
wrap.appendChild(createPill('Art-Lab', COLORS.artlab.bg, COLORS.artlab.fg));
else
wrap.appendChild(createPill('Hacklab', COLORS.hacklab.bg, COLORS.hacklab.fg));
if (day === secondFri || day === lastFri)
wrap.appendChild(createPill('Fridays 🌱', COLORS.fridays.bg, COLORS.fridays.fg));
cell.appendChild(wrap);
} else {
renderWeeklyPills(cell, wd);
}
} else {
cell.classList.add('cal-empty');
}
row.appendChild(cell);
day++;
}
root.appendChild(row);
}
}
function buildLegend() {
legend.innerHTML = '';
['hacklab','artlab','feminismos','vivienda','bicilab','autodefensa','fridays','euskera','asamblea_enre','montana','teatro']
.forEach(key => {
const c = COLORS[key];
if (!c) return;
const item = document.createElement('div');
item.className = 'cal-legend-item';
const dot = document.createElement('span');
dot.className = 'cal-legend-dot';
dot.style.background = c.bg;
if (c.bg === '#fff') dot.style.border = '1px solid #ff00aa';
const txt = document.createElement('span');
txt.textContent = c.label;
item.appendChild(dot);
item.appendChild(txt);
legend.appendChild(item);
});
}
btnPrev.addEventListener('click', () => { view.setMonth(view.getMonth() - 1); buildCalendar(view); });
btnNext.addEventListener('click', () => { view.setMonth(view.getMonth() + 1); buildCalendar(view); });
buildCalendar(view);
buildLegend();
})();
</script>
</section>
<footer class="pie-pagina">
<p>
Calle de la Coruña nº 5, Madrid ·
<a href="mailto:enredadera@riseup.net">enredadera@riseup.net</a> ·
<a href="https://masto.es/@csolaenre">@csolaenre</a>
</p>
</footer>
</main>
</div>
</body>
</html>