/* ═══════════════════════════════════════════════════════════ JORNADA DE TALLERES LPDE — sábado 15 de agosto de 2026 Página de inscripción (?page=talleres). Reemplaza al "II Encuentro Amistoso" en el calendario 2026. Fuente del programa: Sheet "Talleres 15 de agosto" (1NblmLSdBOsH3ho5Bhgg7wGzZf6oZ4OJrOg8N_kxFU0g). Dos bloques de 2 horas, tres talleres simultáneos por bloque: cada participante elige UNO por bloque. ═══════════════════════════════════════════════════════════ */ const TALLERES_FORM_URL = 'https://forms.gle/QZXwo1ELJ1EwjaE26'; const TALLERES_FECHA = { day: 15, mesNum: 8, year: 2026 }; /* Los seis talleres. `publico`: 'escolares' | 'docentes' (filtro de la página). `descBorrador`: la fila del Sheet llegó incompleta; el texto es un borrador de la LPDE pendiente de confirmación con el tallerista. */ const TALLERES_PROGRAMA = [ { bloque: 'I', horario: '8:30 – 10:30', title: 'Estrategia', title_en: 'Strategy', desc: '¿Qué entendemos por estrategia en el formato WSDC? En este taller definiremos la estrategia en el formato, expondremos herramientas de toma de decisión durante los debates y construiremos en conjunto filtros de estrategia.', desc_en: 'What do we mean by strategy in the WSDC format? In this workshop we define strategy within the format, present decision-making tools to use during debates and build strategy filters together.', tallerista: 'Felipe Zenteno Pacheco', publico: 'escolares', }, { bloque: 'I', horario: '8:30 – 10:30', title: 'Análisis probatorio', title_en: 'Burden of proof analysis', desc: 'Este taller da la base para entender el debate desde una mirada analítica. Argumentar, refutar, ponderar y todas las demás estrategias de debate parten de entender premisas y cargas probatorias. El taller explicará paso a paso qué debemos probar como cierto, cómo hacerlo y qué tanto hacerlo.', desc_en: 'This workshop lays the groundwork for understanding debate analytically. Arguing, refuting, weighing and every other debate skill starts from understanding premises and burdens of proof. Step by step, the workshop covers what we must prove true, how to do it and how far we have to go.', tallerista: 'Roberto Urquieta', publico: 'escolares', }, { bloque: 'I', horario: '8:30 – 10:30', title: '¿Cómo selecciono debatientes para los diferentes torneos?', title_en: 'How do I select debaters for each tournament?', desc: 'En este taller exploraremos criterios de selección, tipos de procesos de selección y perfiles de debatientes. Asimismo, exploraremos algunas nociones para establecer un calendario de torneos de debate.', desc_en: 'In this workshop we explore selection criteria, types of selection processes and debater profiles. We also look at how to set up a tournament calendar for the year.', tallerista: 'Dante León Saavedra', publico: 'docentes', }, { bloque: 'II', horario: '11:00 – 13:00', title: 'Ponderaciones', title_en: 'Weighing', desc: 'Ponderar no solo se basa en hacer mención de criterios clásicos: es una estrategia argumentativa que implica un análisis más profundo de aquello que buscamos comparar. Este taller explicará cómo ponderar impactos de una misma métrica del debate, cómo ponderar impactos de métricas distintas y, por último, cómo ponderar la probabilidad de que un escenario sea más probable que otro.', desc_en: 'Weighing is not just naming the classic criteria: it is an argumentative strategy that demands deeper analysis of whatever we are comparing. This workshop covers how to weigh impacts within a single debate metric, how to weigh impacts across different metrics and, finally, how to weigh the likelihood of one scenario over another.', tallerista: 'Roberto Urquieta', publico: 'escolares', }, { bloque: 'II', horario: '11:00 – 13:00', title: '¿Cómo debato sobre temas que no conozco mucho?', title_en: 'How do I debate topics I barely know?', desc: 'En este taller exploraremos cómo enfrentar mociones sobre temas poco familiares: qué hacer con la información que sí tenemos, cómo razonar desde principios y analogías cuando falta evidencia específica, y cómo aprovechar el tiempo de preparación para cubrir vacíos de conocimiento sin improvisar.', desc_en: 'In this workshop we explore how to face motions on unfamiliar topics: what to do with the information we do have, how to reason from principles and analogies when specific evidence is missing, and how to use prep time to cover knowledge gaps without improvising.', descBorrador: true, tallerista: 'Dante León Saavedra', publico: 'escolares', }, { bloque: 'II', horario: '11:00 – 13:00', title: '¿Cómo se evalúa un debate?: ser un buen juez en el formato WSDC', title_en: 'How is a debate judged?: being a good adjudicator in WSDC', desc: 'Taller sobre los criterios y técnicas para juzgar debates en el formato WSDC, desde cómo tomar notas hasta cómo justificar una decisión. Ideal para nuevos docentes o entrenadores que quieren entender el debate desde la otra silla.', desc_en: 'A workshop on the criteria and techniques for judging WSDC debates, from how to take notes to how to justify a decision. Ideal for new teachers or coaches who want to understand debate from the other chair.', tallerista: 'Luis Valverde', publico: 'docentes', }, ]; const TALLERES_BLOQUES = [ { id: 'I', num: '01', horario: '8:30 – 10:30', label: 'Bloque I', label_en: 'Block I' }, { id: 'II', num: '02', horario: '11:00 – 13:00', label: 'Bloque II', label_en: 'Block II' }, ]; /* Fichas de quienes no están en el directorio del equipo (data.js) */ const TALLERISTAS_INVITADOS = { 'Roberto Urquieta': { name: 'Roberto Urquieta', role: 'Tallerista invitado', img: 'assets/equipo/roberto-urquieta.jpg', bio: '', }, }; /* Ficha de cada tallerista: primero el directorio del equipo, luego los invitados. */ const talleristaFicha = (name) => { const D = (window.LPDE_DATA && window.LPDE_DATA.team) || []; const hit = D.find((m) => m.name === name); if (hit) return hit; return TALLERISTAS_INVITADOS[name] || { name, role: 'Tallerista invitado', short: '', bio: '', img: null }; }; const TALLERISTAS = ['Felipe Zenteno Pacheco', 'Roberto Urquieta', 'Dante León Saavedra', 'Luis Valverde']; /* Iniciales para el monograma cuando no hay foto */ const talleristaIniciales = (name) => String(name || '').split(/\s+/).slice(0, 2).map((w) => w[0]).join('').toUpperCase(); /* ─── Descarga del cronograma completo como JPG (1080×1350) ─── Mismo lenguaje gráfico que la tarjeta de evento del calendario: papel crema, rojo LPDE, serif para la fecha, mono para las etiquetas. Reutiliza _fitCanvasLines / _wrapCanvasText de pages-main.jsx. */ const downloadCronogramaJPG = (lang) => { const css = getComputedStyle(document.body); const RED = (css.getPropertyValue('--red') || '#E30613').trim(); const INK = (css.getPropertyValue('--ink') || '#0F0F12').trim(); const CREAM = (css.getPropertyValue('--bg-alt') || '#F7F5EF').trim(); const W = 1080, H = 1350, M = 72, CW = W - M * 2; const SERIF = '"Instrument Serif", Georgia, serif'; const SANS = '"Source Sans 3", Arial, sans-serif'; const MONO = '"JetBrains Mono", monospace'; const sub = '#4B4B53'; const mute = '#6B7280'; const L = (es, en) => (lang === 'en' ? en : es); const draw = (logoImg) => { const canvas = document.createElement('canvas'); canvas.width = W; canvas.height = H; const ctx = canvas.getContext('2d'); const CONTENT_TOP = 268; const CONTENT_BOTTOM = H - 168; // el pie es fijo: nada lo invade // Dibuja (o solo mide, con dry=true) el cuerpo a escala S; devuelve la y final. // `offset` centra verticalmente el cuerpo cuando sobra aire. const render = (S, dry, offset) => { const rowTitle = Math.round(29 * S), rowTitleLH = Math.round(36 * S); const rowMeta = Math.round(21 * S); const rowPad = Math.round(22 * S); const blockGap = Math.round(34 * S); let y = CONTENT_TOP + (offset || 0); TALLERES_BLOQUES.forEach((b, bi) => { // Cabecera del bloque: banda oscura con nombre + horario const bandH = Math.round(52 * S); if (!dry) { ctx.fillStyle = INK; ctx.fillRect(M, y, CW, bandH); ctx.fillStyle = '#FFFFFF'; ctx.font = '700 ' + Math.round(22 * S) + 'px ' + MONO; ctx.fillText((lang === 'en' ? b.label_en : b.label).toUpperCase(), M + 20, y + bandH * 0.66); ctx.textAlign = 'right'; ctx.fillStyle = '#FFFFFF'; ctx.font = '500 ' + Math.round(22 * S) + 'px ' + MONO; ctx.fillText(b.horario, W - M - 20, y + bandH * 0.66); ctx.textAlign = 'left'; } y += bandH; TALLERES_PROGRAMA.filter((w) => w.bloque === b.id).forEach((w) => { const x = M + 20; const innerW = CW - 40 - Math.round(120 * S); let ry = y + rowPad; ctx.font = '700 ' + rowTitle + 'px ' + SANS; const titleLines = _fitCanvasLines(ctx, lang === 'en' ? w.title_en : w.title, innerW, 2); titleLines.forEach((l) => { if (!dry) { ctx.fillStyle = INK; ctx.fillText(l, x, ry + rowTitle * 0.78); } ry += rowTitleLH; }); ry += Math.round(6 * S); if (!dry) { ctx.fillStyle = sub; ctx.font = '400 ' + rowMeta + 'px ' + SANS; ctx.fillText(w.tallerista, x, ry + rowMeta * 0.78); // Etiqueta de público, alineada a la derecha const tag = w.publico === 'docentes' ? L('DOCENTES / ENTRENADORES', 'TEACHERS / COACHES') : L('ESCOLARES', 'STUDENTS'); ctx.font = '500 ' + Math.round(17 * S) + 'px ' + MONO; ctx.textAlign = 'right'; ctx.fillStyle = w.publico === 'docentes' ? RED : mute; ctx.fillText(tag, W - M - 20, ry + rowMeta * 0.78); ctx.textAlign = 'left'; } ry += rowMeta + rowPad; if (!dry) { ctx.strokeStyle = '#D4D2CC'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(M, ry); ctx.lineTo(W - M, ry); ctx.stroke(); } y = ry; }); if (bi < TALLERES_BLOQUES.length - 1) y += blockGap; }); return y; }; // 1) Medir y bajar de escala hasta que quepa; el aire sobrante se reparte // arriba y abajo para que el cuerpo quede ópticamente centrado. const scales = [1, 0.94, 0.88, 0.82, 0.76, 0.7]; let S = scales[scales.length - 1]; for (const s of scales) { if (render(s, true, 0) <= CONTENT_BOTTOM) { S = s; break; } } const sobra = Math.max(0, CONTENT_BOTTOM - render(S, true, 0)); const offsetY = Math.round(sobra / 2); // 2) Fondo y cabecera fija ctx.fillStyle = CREAM; ctx.fillRect(0, 0, W, H); try { ctx.letterSpacing = '3px'; } catch (e) {} if (logoImg) { const lh = 50, lw = lh * (logoImg.width / logoImg.height); ctx.drawImage(logoImg, M, M - 4, lw, lh); } else { ctx.fillStyle = RED; ctx.font = '900 42px ' + SANS; ctx.fillText('LPDE', M, M + 36); } ctx.fillStyle = mute; ctx.font = '500 21px ' + MONO; ctx.textAlign = 'right'; ctx.fillText(L('TALLERES GRATUITOS · VIRTUAL', 'FREE WORKSHOPS · ONLINE'), W - M, M + 32); ctx.textAlign = 'left'; ctx.fillStyle = RED; ctx.font = 'italic 400 54px ' + SERIF; ctx.fillText(L('Sábado 15 de agosto de 2026', 'Saturday, 15 August 2026'), M, 168); ctx.fillStyle = INK; ctx.font = '900 40px ' + SANS; ctx.fillText(L('Jornada de Talleres LPDE', 'LPDE Workshop Day'), M, 218); ctx.strokeStyle = '#D4D2CC'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(M, 244); ctx.lineTo(W - M, 244); ctx.stroke(); // 3) Cuerpo render(S, false, offsetY); // 4) Pie fijo ctx.fillStyle = RED; ctx.fillRect(M, H - 130, 56, 4); ctx.fillStyle = sub; ctx.font = '500 21px ' + MONO; ctx.fillText(L('ELIGE UN TALLER POR BLOQUE · GRATUITO', 'CHOOSE ONE WORKSHOP PER BLOCK · FREE'), M, H - 92); ctx.fillStyle = mute; ctx.fillText('lpdebate.org/?page=talleres', M, H - 56); ctx.font = '500 17px ' + MONO; ctx.textAlign = 'right'; ctx.fillText(L('LIGA PERUANA DE DEBATE ESCOLAR', 'PERUVIAN SCHOOL DEBATE LEAGUE'), W - M, H - 56); ctx.textAlign = 'left'; canvas.toBlob((blob) => { if (!blob) return; const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'lpde-jornada-talleres-15-agosto.jpg'; a.click(); setTimeout(() => URL.revokeObjectURL(a.href), 4000); }, 'image/jpeg', 0.92); }; const start = () => { const logo = new Image(); logo.onload = () => draw(logo); logo.onerror = () => draw(null); logo.src = 'assets/logo-lpde-red.png'; }; if (document.fonts && document.fonts.ready) document.fonts.ready.then(start); else start(); }; const TalleresPage = ({ setPage }) => { const { t, lang } = useLang(); const [publico, setPublico] = React.useState('todos'); const [perfil, setPerfil] = React.useState(null); const filtros = [ { id: 'todos', label: t('Todos', 'All') }, { id: 'escolares', label: t('Escolares', 'Students') }, { id: 'docentes', label: t('Docentes y entrenadores', 'Teachers and coaches') }, ]; const visibles = TALLERES_PROGRAMA.filter((w) => publico === 'todos' || w.publico === publico); const publicoLabel = (p) => (p === 'docentes' ? t('Docentes / Entrenadores', 'Teachers / Coaches') : t('Escolares', 'Students')); return ( {/* Hero */}
{t('Jornada de talleres · Sábado 15 de agosto de 2026', 'Workshop day · Saturday 15 August 2026')}

{t('Seis talleres, ', 'Six workshops, ')}{t('una mañana', 'one morning')}

{t('Una mañana de formación abierta y gratuita para la comunidad LPDE. Dos bloques de dos horas, tres talleres simultáneos en cada uno: estrategia, análisis probatorio y ponderaciones para escolares; selección de debatientes y adjudicación para docentes y entrenadores. Cada participante elige un taller por bloque.', 'A free, open morning of training for the LPDE community. Two two-hour blocks with three simultaneous workshops each: strategy, burden of proof and weighing for students; debater selection and adjudication for teachers and coaches. Each participant chooses one workshop per block.')}

{t('Inscríbete gratis', 'Sign up for free')}
{t('Gratuito · Virtual vía Zoom', 'Free · Online via Zoom')}
{t('8:30 a. m. a 1:00 p. m.', '8:30 a.m. to 1:00 p.m.')}
{/* Datos clave */}
{[ { num: , label: t('Talleres', 'Workshops') }, { num: '2', label: t('Bloques de 2 horas', 'Two-hour blocks') }, { num: '4', label: t('Talleristas', 'Instructors') }, { num: '15 AGO', label: t('Sábado · Virtual', 'Saturday · Online'), it: true }, { num: t('Gratis', 'Free'), label: t('Inscripción abierta', 'Open registration'), red: true, it: true }, ].map((s, i) => (
{s.num}
{s.label}
))}
{/* Cómo funciona */}
{t('Cómo funciona', 'How it works')}

{t('Eliges ', 'You choose ')}{t('un taller por bloque', 'one workshop per block')}

{t('Los tres talleres de cada bloque se dictan a la misma hora, en salas distintas de Zoom. Al inscribirte marcas tu opción del Bloque I y tu opción del Bloque II; el enlace de tu sala llega por correo el día previo.', 'The three workshops in each block run at the same time, in separate Zoom rooms. When you register you pick your option for Block I and your option for Block II; the link to your room arrives by email the day before.')}

{[ t('Inscríbete en el formulario y marca un taller del Bloque I y uno del Bloque II', 'Fill in the form and pick one workshop from Block I and one from Block II'), t('Recibirás por correo el enlace de Zoom de cada sala que elegiste', 'You will receive by email the Zoom link for each room you chose'), t('Entre bloques hay 30 minutos de pausa (10:30 a 11:00 a. m.)', 'There is a 30-minute break between blocks (10:30 to 11:00 a.m.)'), t('La jornada es gratuita y abierta a la comunidad LPDE', 'The day is free and open to the LPDE community'), ].map((txt, i) => (
{txt}
))}
{/* Programa */}
{t('El programa', 'The programme')}

{t('Dos bloques, ', 'Two blocks, ')}{t('seis talleres', 'six workshops')}

{/* Filtro por público */}
{t('Dirigido a', 'For')} {filtros.map((f) => ( ))}
{TALLERES_BLOQUES.map((b) => { const lista = visibles.filter((w) => w.bloque === b.id); if (!lista.length) return null; return (
{b.num}

{lang === 'en' ? b.label_en : b.label}

{b.horario}
{lista.map((w, i) => (
{ e.currentTarget.style.transform = 'translateY(-3px)'; e.currentTarget.style.boxShadow = '0 12px 32px rgba(0,0,0,0.06)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }} >
{w.horario} {publicoLabel(w.publico)}

{lang === 'en' ? w.title_en : w.title}

{lang === 'en' ? w.desc_en : w.desc}

{t('Tallerista', 'Instructor')}
{w.tallerista}
))}
); })} {/* Descarga del cronograma */}
{t('Cronograma en imagen', 'Schedule as an image')}

{t('Descarga el cronograma completo de la jornada en JPG para compartirlo con tu equipo, tu colegio o por redes.', 'Download the full schedule as a JPG to share it with your team, your school or on social media.')}

{/* Talleristas */}
{t('Quiénes dictan', 'Who teaches')}

{t('Cuatro ', 'Four ')}{t('talleristas', 'instructors')}

{TALLERISTAS.map((name, i) => { const m = talleristaFicha(name); const dicta = TALLERES_PROGRAMA.filter((w) => w.tallerista === name); const clickable = !!m.bio; return (
clickable && setPerfil(m)} style={{ border: '1px solid var(--line)', background: 'var(--bg)', display: 'flex', flexDirection: 'column', cursor: clickable ? 'pointer' : 'default', transition: 'all 280ms ease', }} onMouseEnter={(e) => { e.currentTarget.style.boxShadow = '0 12px 32px rgba(0,0,0,0.06)'; }} onMouseLeave={(e) => { e.currentTarget.style.boxShadow = 'none'; }} >
{m.img ? {name} : {talleristaIniciales(name)}}
{m.role || t('Tallerista', 'Instructor')}

{name}

    {dicta.map((w) => (
  • {w.bloque} {lang === 'en' ? w.title_en : w.title}
  • ))}
{clickable && (
{t('Ver perfil', 'View profile')}
)}
); })}
{/* CTA final */}
{t('Inscripciones abiertas', 'Registration open')}

{t('Nos vemos el ', 'See you on ')}{t('15 de agosto', '15 August')}

{t('La jornada es gratuita, virtual y abierta a escolares, docentes y entrenadores de la comunidad LPDE. Escríbenos a contacto@lpdebate.org si tienes dudas.', 'The workshop day is free, online and open to students, teachers and coaches in the LPDE community. Write to contacto@lpdebate.org if you have any questions.')}

{t('Inscríbete gratis', 'Sign up for free')}
{/* Perfil del tallerista — mismo modal del directorio del equipo */} setPerfil(null)} />
); };