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);