diff --git a/compose.yml b/compose.yml index 6b61f37..c67073a 100644 --- a/compose.yml +++ b/compose.yml @@ -1,6 +1,6 @@ services: work-timerer: - image: git.frik.su/Beesquit/work-timerer:latest + build: . container_name: work-timerer ports: - 4000:80 diff --git a/src/index.css b/src/index.css index 6a01491..2244ac9 100644 --- a/src/index.css +++ b/src/index.css @@ -43,6 +43,11 @@ H1 { margin: auto; } +#currentTime { + font-size: 3em; + margin: 20px 0; +} + .time-blocks { display: flex; gap: 20px; @@ -80,11 +85,22 @@ H1 { gap: 20px; } -#currentTime { - font-size: 3em; +.next-break { + font-size: 2em; + text-align: center; margin: 20px 0; } +.time-block.break-current { + border: 2px solid #d4a017; + color: #d4a017; +} + +.time-block.break-next { + border: 2px solid #6b9ac0; + color: #6b9ac0; +} + .calendar-container { margin-top: 30px; diff --git a/src/index.html b/src/index.html index d35eec8..2af29dc 100644 --- a/src/index.html +++ b/src/index.html @@ -16,19 +16,13 @@
-
+
-
-
-
- -
-
-
+
diff --git a/src/index.js b/src/index.js index fd68996..268460f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,21 @@ -const TRAVEL_TIME_HOURS = 1; -const FIRST_HOUR = 13; -const LAST_HOUR = 22; +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" }, +]; -let clockEl, dateEl; -let diffNodes = []; -let resizeTimer = null; +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) { @@ -19,98 +30,29 @@ function formatDate(d) { return pad2(d.getDate()) + "." + pad2(d.getMonth() + 1) + "." + d.getFullYear(); } -function diffText(targetMs, nowMs) { - const diffMs = targetMs - nowMs; - if (diffMs < 0) { - const diffHours = -1 * Math.ceil(diffMs / 3600000); - const diffMinutes = -1 * Math.ceil((diffMs % 3600000) / 60000); - return "-" + pad2(diffHours) + ":" + pad2(diffMinutes); - } - const diffHours = Math.floor(diffMs / 3600000); - const diffMinutes = Math.ceil((diffMs % 3600000) / 60000); - return pad2(diffHours) + ":" + pad2(diffMinutes); +function breakTimeToMinutes(t) { + const parts = t.split(":"); + return parseInt(parts[0], 10) * 60 + parseInt(parts[1], 10); } -function buildLabel(text) { - const span = document.createElement("span"); - span.className = "time-block label-block"; - span.textContent = text; - return span; +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 buildTimeBlock(text) { - const span = document.createElement("span"); - span.className = "time-block"; - span.textContent = text; - return span; +function getBreaksForToday(now) { + const day = now.getDay(); + return day === 0 || day === 6 ? WEEKEND_BREAKS : WEEKDAY_BREAKS; } -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 buildTargetBlocks() { - const targetTimesElement = document.getElementById("targetTimes"); - const leaveTimesElement = document.getElementById("leaveTimes"); - const timeDifferencesElement = document.getElementById("timeDifferences"); - - targetTimesElement.appendChild(buildLabel("TT")); - leaveTimesElement.appendChild(buildLabel("LT")); - timeDifferencesElement.appendChild(buildLabel("TD")); - - const targetBlocks = []; - const leaveBlocks = []; - const diffBlocks = []; - - for (let hour = FIRST_HOUR; hour <= LAST_HOUR; hour++) { - const leaveHour = hour - TRAVEL_TIME_HOURS; - - targetBlocks.push(buildTimeBlock(pad2(hour) + ":00")); - leaveBlocks.push(buildTimeBlock(pad2(leaveHour) + ":00")); - diffBlocks.push(buildTimeBlock("")); - } - - distributeBlocks(targetTimesElement, targetBlocks); - distributeBlocks(leaveTimesElement, leaveBlocks); - distributeBlocks(timeDifferencesElement, diffBlocks); - - diffNodes = diffBlocks; +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() { @@ -197,21 +139,123 @@ function scheduleNextClockTick() { setTimeout(updateClock, delay); } -function updateDiffs() { - const now = new Date(); - for (let hour = FIRST_HOUR; hour <= LAST_HOUR; hour++) { - const target = new Date(); - target.setHours(hour - TRAVEL_TIME_HOURS, 0, 0, 0); - diffNodes[hour - FIRST_HOUR].textContent = diffText(target.getTime(), now.getTime()); - } - scheduleNextDiffTick(); +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 scheduleNextDiffTick() { +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 msUntilNextMinute = - (60 - now.getSeconds()) * 1000 - now.getMilliseconds(); - setTimeout(updateDiffs, msUntilNextMinute); + 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() { @@ -222,14 +266,16 @@ function checkDayChange() { lastDayKey = key; dateEl.textContent = formatDate(now); buildCalendar(); + buildBreakBlocks(); } } function init() { clockEl = document.getElementById("currentTime"); dateEl = document.getElementById("currentDate"); + nextBreakEl = document.getElementById("nextBreak"); - buildTargetBlocks(); + buildBreakBlocks(); buildCalendar(); const now = new Date(); @@ -237,34 +283,9 @@ function init() { dateEl.textContent = formatDate(now); updateClock(); - updateDiffs(); + updateNextBreak(); setInterval(checkDayChange, 60000); } -function onResize() { - if (resizeTimer !== null) clearTimeout(resizeTimer); - resizeTimer = setTimeout(function () { - resizeTimer = null; - const targetTimesElement = document.getElementById("targetTimes"); - const leaveTimesElement = document.getElementById("leaveTimes"); - const timeDifferencesElement = document.getElementById("timeDifferences"); - - const allBlocks = [].slice.call( - timeDifferencesElement.querySelectorAll(".time-block:not(.label-block)") - ); - const targetBlocks = [].slice.call( - targetTimesElement.querySelectorAll(".time-block:not(.label-block)") - ); - const leaveBlocks = [].slice.call( - leaveTimesElement.querySelectorAll(".time-block:not(.label-block)") - ); - - distributeBlocks(targetTimesElement, targetBlocks); - distributeBlocks(leaveTimesElement, leaveBlocks); - distributeBlocks(timeDifferencesElement, allBlocks); - }, 150); -} - init(); -window.addEventListener("resize", onResize);