feature: calendar
All checks were successful
Build and Push Docker Image / build-and-push (release) Successful in 9m41s
All checks were successful
Build and Push Docker Image / build-and-push (release) Successful in 9m41s
This commit is contained in:
107
src/index.css
107
src/index.css
@@ -76,8 +76,8 @@ H1 {
|
|||||||
|
|
||||||
.time-row {
|
.time-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 20px;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#currentTime {
|
#currentTime {
|
||||||
@@ -86,6 +86,91 @@ H1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.calendar-container {
|
||||||
|
margin-top: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-container .hblock {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#currentDate {
|
||||||
|
font-size: 2em;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #ffffff;
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table thead tr {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table tbody {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table tbody tr {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th,
|
||||||
|
.calendar-table td {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 65px;
|
||||||
|
height: 45px;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 1em;
|
||||||
|
border: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th {
|
||||||
|
background-color: #3a3a3a;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th.weekend-text {
|
||||||
|
color: #6b9ac0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td.weekend-text {
|
||||||
|
color: #6b9ac0;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td.today-text {
|
||||||
|
color: #d4a017;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
font-weight: 700;
|
||||||
|
border: 2px solid #d4a017;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td.other-month {
|
||||||
|
opacity: 0.4;
|
||||||
|
background-color: #232323;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.time-blocks {
|
.time-blocks {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
@@ -95,4 +180,24 @@ H1 {
|
|||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.calendar-container {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th,
|
||||||
|
.calendar-table td {
|
||||||
|
width: 50px;
|
||||||
|
height: 38px;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table {
|
||||||
|
border-spacing: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table thead tr,
|
||||||
|
.calendar-table tbody tr {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>w-timerer</title>
|
<title>w-timerer</title>
|
||||||
<link rel="stylesheet" type="text/css" href="index.css">
|
<link rel="stylesheet" type="text/css" href="index.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="parent">
|
<div class="parent">
|
||||||
<div class="vblock">
|
<div class="vblock">
|
||||||
@@ -36,6 +33,13 @@
|
|||||||
<div class="time-blocks jetbrains-mono" id="timeDifferences"></div>
|
<div class="time-blocks jetbrains-mono" id="timeDifferences"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="vblock calendar-container">
|
||||||
|
<div class="hblock">
|
||||||
|
<div class="jetbrains-mono" id="currentDate"></div>
|
||||||
|
<table class="jetbrains-mono calendar-table" id="calendar"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
|
|||||||
93
src/index.js
93
src/index.js
@@ -72,6 +72,8 @@ function updateTimes() {
|
|||||||
distributeBlocks(targetTimesElement, targetTimeBlocks);
|
distributeBlocks(targetTimesElement, targetTimeBlocks);
|
||||||
distributeBlocks(leaveTimesElement, leaveTimeBlocks);
|
distributeBlocks(leaveTimesElement, leaveTimeBlocks);
|
||||||
distributeBlocks(timeDifferencesElement, diffTimeBlocks);
|
distributeBlocks(timeDifferencesElement, diffTimeBlocks);
|
||||||
|
|
||||||
|
updateCalendar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -112,7 +114,98 @@ function distributeBlocks(container, blocks) {
|
|||||||
container.appendChild(rowsContainer);
|
container.appendChild(rowsContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateCalendar() {
|
||||||
|
const now = new Date();
|
||||||
|
const currentDateElement = document.getElementById('currentDate');
|
||||||
|
|
||||||
|
const day = now.getDate().toString().padStart(2, '0');
|
||||||
|
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
const year = now.getFullYear();
|
||||||
|
currentDateElement.textContent = `${day}.${month}.${year}`;
|
||||||
|
|
||||||
|
const calendarElement = document.getElementById('calendar');
|
||||||
|
calendarElement.innerHTML = '';
|
||||||
|
|
||||||
|
const daysOfWeek = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
|
||||||
|
|
||||||
|
const firstDayOfMonth = new Date(year, now.getMonth(), 1);
|
||||||
|
let firstDayWeek = firstDayOfMonth.getDay();
|
||||||
|
firstDayWeek = firstDayWeek === 0 ? 7 : firstDayWeek;
|
||||||
|
|
||||||
|
const lastDayOfMonth = new Date(year, now.getMonth() + 1, 0);
|
||||||
|
const daysInMonth = lastDayOfMonth.getDate();
|
||||||
|
|
||||||
|
const lastDayOfPrevMonth = new Date(year, now.getMonth(), 0);
|
||||||
|
const daysInPrevMonth = lastDayOfPrevMonth.getDate();
|
||||||
|
|
||||||
|
const thead = document.createElement('thead');
|
||||||
|
const headerRow = document.createElement('tr');
|
||||||
|
daysOfWeek.forEach((day, index) => {
|
||||||
|
const th = document.createElement('th');
|
||||||
|
th.textContent = day;
|
||||||
|
th.className = 'calendar-weekday';
|
||||||
|
if (index === 5 || index === 6) {
|
||||||
|
th.classList.add('weekend-text');
|
||||||
|
}
|
||||||
|
headerRow.appendChild(th);
|
||||||
|
});
|
||||||
|
thead.appendChild(headerRow);
|
||||||
|
calendarElement.appendChild(thead);
|
||||||
|
|
||||||
|
const tbody = document.createElement('tbody');
|
||||||
|
|
||||||
|
let dayCounter = 1;
|
||||||
|
let nextMonthDayCounter = 1;
|
||||||
|
|
||||||
|
let startDay = daysInPrevMonth - firstDayWeek + 2;
|
||||||
|
|
||||||
|
for (let row = 0; row < 5; row++) {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
|
||||||
|
for (let col = 0; col < 7; col++) {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.className = 'calendar-cell';
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
calendarElement.appendChild(tbody);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Init
|
||||||
updateTimes();
|
updateTimes();
|
||||||
setInterval(updateTimes, 200);
|
setInterval(updateTimes, 200);
|
||||||
window.addEventListener('resize', updateTimes);
|
window.addEventListener('resize', updateTimes);
|
||||||
|
|||||||
Reference in New Issue
Block a user