const WEEKDAY_BREAKS = [ { start: "10:15", end: "10:30" }, { start: "12:00", end: "12:30" }, { start: "14:00", end: "14:15" }, { start: "16:30", end: "17:00" }, { start: "19:45", end: "20:00" }, { start: "21:00", end: "21:15" }, ]; const WEEKEND_BREAKS = [ { start: "11:00", end: "11:15" }, { start: "14:30", end: "15:00" }, { start: "17:30", end: "17:45" }, { start: "20:00", end: "20:15" }, ]; let clockEl, dateEl, nextBreakEl; let breakNodes = []; let lastDayKey = ""; function pad2(n) { return n < 10 ? "0" + n : "" + n; } function formatClock(d) { return pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds()); } function formatDate(d) { return pad2(d.getDate()) + "." + pad2(d.getMonth() + 1) + "." + d.getFullYear(); } function breakTimeToMinutes(t) { const parts = t.split(":"); return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10); } function breakMsForToday(t, now) { const d = new Date(now); const parts = t.split(":"); d.setHours(parseInt(parts[0], 10), parseInt(parts[1], 10), 0, 0); return d.getTime(); } function getBreaksForToday(now) { const day = now.getDay(); return day === 0 || day === 6 ? WEEKEND_BREAKS : WEEKDAY_BREAKS; } function formatDuration(ms) { const totalSeconds = Math.floor(ms / 1000); const h = Math.floor(totalSeconds / 3600); const m = Math.floor((totalSeconds % 3600) / 60); const s = totalSeconds % 60; return pad2(h) + ":" + pad2(m) + ":" + pad2(s); } function buildCalendar() { const calendar = document.getElementById("calendar"); calendar.innerHTML = ""; const now = new Date(); const daysOfWeek = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]; const thead = document.createElement("thead"); const headerRow = document.createElement("tr"); daysOfWeek.forEach(function (day, index) { const th = document.createElement("th"); th.textContent = day; if (index === 5 || index === 6) { th.classList.add("weekend-text"); } headerRow.appendChild(th); }); thead.appendChild(headerRow); calendar.appendChild(thead); const tbody = document.createElement("tbody"); const year = now.getFullYear(); const month = now.getMonth(); const firstDayOfMonth = new Date(year, month, 1); let firstDayWeek = firstDayOfMonth.getDay(); firstDayWeek = firstDayWeek === 0 ? 7 : firstDayWeek; const daysInMonth = new Date(year, month + 1, 0).getDate(); const daysInPrevMonth = new Date(year, month, 0).getDate(); let dayCounter = 1; let nextMonthDayCounter = 1; let startDay = daysInPrevMonth - firstDayWeek + 2; const totalRows = Math.ceil((firstDayWeek - 1 + daysInMonth) / 7); for (let row = 0; row < totalRows; row++) { const tr = document.createElement("tr"); for (let col = 0; col < 7; col++) { const td = document.createElement("td"); let cellDay; let isCurrentMonth = true; if (row === 0 && col < firstDayWeek - 1) { cellDay = startDay + col; isCurrentMonth = false; } else if (dayCounter <= daysInMonth) { cellDay = dayCounter; dayCounter++; } else { cellDay = nextMonthDayCounter; nextMonthDayCounter++; isCurrentMonth = false; } td.textContent = cellDay; if (isCurrentMonth && cellDay === now.getDate()) { td.classList.add("today-text"); } if (col === 5 || col === 6) { td.classList.add("weekend-text"); } if (!isCurrentMonth) { td.classList.add("other-month"); } tr.appendChild(td); } tbody.appendChild(tr); } calendar.appendChild(tbody); } function updateClock() { const now = new Date(); clockEl.textContent = formatClock(now); scheduleNextClockTick(); } function scheduleNextClockTick() { const delay = 1000 - new Date().getMilliseconds(); setTimeout(updateClock, delay); } function buildBreakBlocks() { const breakTimesElement = document.getElementById("breakTimes"); breakTimesElement.innerHTML = ""; breakTimesElement.appendChild(buildLabel("BK")); const blocks = []; getBreaksForToday(new Date()).forEach(function (b) { blocks.push(buildTimeBlock(b.start + "-" + b.end)); }); breakNodes = blocks; distributeBlocks(breakTimesElement, blocks); } function buildLabel(text) { const span = document.createElement("span"); span.className = "time-block label-block"; span.textContent = text; return span; } function buildTimeBlock(text) { const span = document.createElement("span"); span.className = "time-block"; span.textContent = text; return span; } function distributeBlocks(container, blocks) { const screenWidth = window.innerWidth; const blockWidth = 120; const labelWidth = 40; const availableWidth = screenWidth - labelWidth; const blocksPerRow = Math.floor(availableWidth / blockWidth); while (container.childNodes.length > 1) { container.removeChild(container.lastChild); } if (blocksPerRow > blocks.length) { blocks.forEach(function (b) { container.appendChild(b); }); return; } const totalBlocks = blocks.length; const halfBlocks = Math.ceil(totalBlocks / 2); const rowsContainer = document.createElement("div"); rowsContainer.className = "multi-rows-container"; const topRow = document.createElement("div"); topRow.className = "time-row"; for (let i = 0; i < halfBlocks; i++) { topRow.appendChild(blocks[i]); } rowsContainer.appendChild(topRow); const bottomRow = document.createElement("div"); bottomRow.className = "time-row"; for (let i = halfBlocks; i < totalBlocks; i++) { bottomRow.appendChild(blocks[i]); } rowsContainer.appendChild(bottomRow); container.appendChild(rowsContainer); } function updateNextBreak() { const now = new Date(); const nowMinutes = now.getHours() * 60 + now.getMinutes() + now.getSeconds() / 60; const breaks = getBreaksForToday(now); let current = null; let next = null; breaks.forEach(function (b, index) { const startM = breakTimeToMinutes(b.start); const endM = breakTimeToMinutes(b.end); if (nowMinutes >= startM && nowMinutes < endM) { current = index; } else if (endM > nowMinutes && next === null) { next = index; } }); breakNodes.forEach(function (node, index) { node.classList.remove("break-current", "break-next"); if (index === current) { node.classList.add("break-current"); } else if (index === next) { node.classList.add("break-next"); } }); if (current !== null) { const b = breaks[current]; const endMs = breakMsForToday(b.end, now); nextBreakEl.textContent = "Перерыв " + b.start + "-" + b.end + " · до конца " + formatDuration(endMs - now.getTime()); } else if (next !== null) { const b = breaks[next]; const startMs = breakMsForToday(b.start, now); nextBreakEl.textContent = "До перерыва " + b.start + "-" + b.end + " · " + formatDuration(startMs - now.getTime()); } else { nextBreakEl.textContent = "Перерывов больше нет"; } scheduleNextBreakTick(); } function scheduleNextBreakTick() { const delay = 1000 - new Date().getMilliseconds(); setTimeout(updateNextBreak, delay); } function checkDayChange() { const now = new Date(); const key = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate(); if (key !== lastDayKey) { lastDayKey = key; dateEl.textContent = formatDate(now); buildCalendar(); buildBreakBlocks(); } } function init() { clockEl = document.getElementById("currentTime"); dateEl = document.getElementById("currentDate"); nextBreakEl = document.getElementById("nextBreak"); buildBreakBlocks(); buildCalendar(); const now = new Date(); lastDayKey = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate(); dateEl.textContent = formatDate(now); updateClock(); updateNextBreak(); setInterval(checkDayChange, 60000); } init();