diff --git a/css/planning.css b/css/planning.css new file mode 100644 index 0000000..08a4cb8 --- /dev/null +++ b/css/planning.css @@ -0,0 +1,82 @@ +.calendar-grid { + display: grid; + grid-template-columns: repeat(7, minmax(0, 1fr)); + gap: 0.75rem; + margin-top: 1.5rem; +} + +.weekday-header, +.day { + padding: 1rem; + border-radius: 0.5rem; + background: var(--bg-alt); + border: 1px solid var(--border); +} + +.weekday-header { + text-align: center; + color: var(--text-muted); + text-transform: uppercase; + font-size: 0.78rem; + letter-spacing: 0.08em; + background: linear-gradient(180deg, rgba(255,255,255,0.02), transparent); +} + +.day { + min-height: 5rem; + display: flex; + flex-direction: column; + justify-content: flex-start; + color: var(--text); +} + +.day.empty { + background: transparent; + box-shadow: none; + border: none; +} + +.day-number { + font-weight: 700; + margin-bottom: 0.5rem; + color: var(--text); +} + +.day.today { + border: 2px solid var(--accent); + background: rgba(0,0,0,0.12); +} + +.day.other-month { + opacity: 0.45; +} + +.day-content { + flex: 1; +} + +.topic { + display: block; + padding: 0.4rem 0.6rem; + margin-bottom: 0.4rem; + background: var(--bg); + border-left: 3px solid var(--accent); + color: var(--text); + font-size: 0.85rem; + border-radius: 4px; + box-shadow: inset 0 -1px 0 rgba(255,255,255,0.02); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +@media (max-width: 720px) { + .calendar-grid { + gap: 0.5rem; + } + + .weekday-header, + .day { + padding: 0.75rem; + } +} diff --git a/js/planning.js b/js/planning.js new file mode 100644 index 0000000..342883d --- /dev/null +++ b/js/planning.js @@ -0,0 +1,159 @@ + +document.addEventListener('DOMContentLoaded', () => { + const calendarGrid = document.getElementById('calendarGrid'); + const monthTitle = document.getElementById('monthTitle'); + const prevMonthBtn = document.getElementById('prevMonth'); + const nextMonthBtn = document.getElementById('nextMonth'); + const autoScheduleBtn = document.getElementById('autoScheduleBtn'); + + const monthNames = [ + 'enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', + 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre' + ]; + + const weekdayNames = ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom']; + const today = new Date(); + let currentYear = today.getFullYear(); + let currentMonth = today.getMonth(); + const STORAGE_KEY = 'tatvil_scheduled_topics_v1'; + + function renderCalendar(year, month) { + calendarGrid.innerHTML = ''; + + weekdayNames.forEach(name => { + const headerCell = document.createElement('div'); + headerCell.className = 'weekday-header'; + headerCell.textContent = name; + calendarGrid.appendChild(headerCell); + }); + + const firstDay = new Date(year, month, 1); + const startWeekday = (firstDay.getDay() + 6) % 7; // Lunes = 0 + const daysInMonth = new Date(year, month + 1, 0).getDate(); + const isCurrentMonth = year === today.getFullYear() && month === today.getMonth(); + + for (let i = 0; i < startWeekday; i += 1) { + const emptyCell = document.createElement('div'); + emptyCell.className = 'day empty'; + calendarGrid.appendChild(emptyCell); + } + + for (let day = 1; day <= daysInMonth; day += 1) { + const dayCell = document.createElement('div'); + dayCell.className = 'day'; + if (isCurrentMonth && day === today.getDate()) { + dayCell.classList.add('today'); + } + + const dateStr = `${year}-${pad(month+1)}-${pad(day)}`; + dayCell.dataset.date = dateStr; + + const dayNumber = document.createElement('div'); + dayNumber.className = 'day-number'; + dayNumber.textContent = day; + dayCell.appendChild(dayNumber); + + const content = document.createElement('div'); + content.className = 'day-content'; + // populate scheduled topic if exists + const scheduled = loadScheduledTopics(); + if (scheduled[dateStr]) { + const t = document.createElement('div'); + t.className = 'topic'; + t.textContent = scheduled[dateStr]; + content.appendChild(t); + } + + dayCell.appendChild(content); + calendarGrid.appendChild(dayCell); + } + + const totalCells = startWeekday + daysInMonth; + const remaining = totalCells % 7; + if (remaining !== 0) { + const fillers = 7 - remaining; + for (let i = 0; i < fillers; i += 1) { + const emptyCell = document.createElement('div'); + emptyCell.className = 'day empty'; + calendarGrid.appendChild(emptyCell); + } + } + + const title = `${monthNames[month].charAt(0).toUpperCase() + monthNames[month].slice(1)} ${year}`; + monthTitle.textContent = title; + } + + function pad(n) { return String(n).padStart(2, '0'); } + + function loadScheduledTopics() { + try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); } catch (e) { return {}; } + } + + function saveScheduledTopics(obj) { localStorage.setItem(STORAGE_KEY, JSON.stringify(obj)); } + + function generateTopics() { + const blocks = [9,5,9,10]; + const topics = []; + blocks.forEach((count, idx) => { + for (let i = 1; i <= count; i++) topics.push(`Bloque ${idx+1} — Tema ${i}`); + }); + return topics; + } + + function getNextMonday(fromDate) { + const d = new Date(fromDate); + const day = d.getDay(); // 0 Sun, 1 Mon + let diff = (1 + 7 - day) % 7; + if (diff === 0) diff = 7; + d.setDate(d.getDate() + diff); + return d; + } + + function scheduleOnePerWeek(topics) { + const scheduled = loadScheduledTopics(); + let date = getNextMonday(new Date()); + for (let i = 0; i < topics.length; i++) { + const ds = date.toISOString().slice(0,10); + scheduled[ds] = topics[i]; + date.setDate(date.getDate() + 7); + } + saveScheduledTopics(scheduled); + } + + autoScheduleBtn?.addEventListener('click', () => { + if (!confirm('Programar 1 tema por semana empezando el próximo lunes?')) return; + const topics = generateTopics(); + scheduleOnePerWeek(topics); + renderCalendar(currentYear, currentMonth); + alert('Temas programados. Navega meses para verlos.'); + }); + + function goToPreviousMonth() { + currentMonth -= 1; + if (currentMonth < 0) { + currentMonth = 11; + currentYear -= 1; + } + renderCalendar(currentYear, currentMonth); + } + + function goToNextMonth() { + currentMonth += 1; + if (currentMonth > 11) { + currentMonth = 0; + currentYear += 1; + } + renderCalendar(currentYear, currentMonth); + } + + prevMonthBtn.addEventListener('click', goToPreviousMonth); + nextMonthBtn.addEventListener('click', goToNextMonth); + + // If there is no scheduling stored yet, auto-schedule topics once + if (Object.keys(loadScheduledTopics()).length === 0) { + scheduleOnePerWeek(generateTopics()); + } + + renderCalendar(currentYear, currentMonth); +}); + diff --git a/planning.html b/planning.html new file mode 100644 index 0000000..16c69ca --- /dev/null +++ b/planning.html @@ -0,0 +1,45 @@ + + + + + + Planning TAI — Agenda + + + + + + +
+

Mi Planning 2026

+ + +
+
+ +
+ +
+ + +
+ + +
+ + +
+ + +
+
+ + + + \ No newline at end of file