Refactor calendar rendering and duty list display
- Updated the calendar cell rendering to conditionally show duty and event markers based on the month view. - Introduced a new HTML structure for day markers to improve layout and styling. - Enhanced the duty list rendering to filter duties based on the current month, ensuring only relevant duties are displayed. - Added CSS styles for day markers to improve visual presentation and alignment.
This commit is contained in:
@@ -207,25 +207,29 @@
|
|||||||
const hasEvent = eventSummaries.length > 0;
|
const hasEvent = eventSummaries.length > 0;
|
||||||
|
|
||||||
const cell = document.createElement("div");
|
const cell = document.createElement("div");
|
||||||
cell.className = "day" + (isOther ? " other-month" : "") + (isToday ? " today" : "") + (hasAny ? " has-duty" : "") + (hasEvent ? " holiday" : "");
|
const showMarkers = !isOther;
|
||||||
|
cell.className = "day" + (isOther ? " other-month" : "") + (isToday ? " today" : "") + (showMarkers && hasAny ? " has-duty" : "") + (showMarkers && hasEvent ? " holiday" : "");
|
||||||
|
|
||||||
function namesAttr(list) { return list.length ? escapeHtml(list.map(function (x) { return x.full_name; }).join("\n")) : ""; }
|
function namesAttr(list) { return list.length ? escapeHtml(list.map(function (x) { return x.full_name; }).join("\n")) : ""; }
|
||||||
function titleAttr(list) { return list.length ? escapeHtml(list.map(function (x) { return x.full_name; }).join(", ")) : ""; }
|
function titleAttr(list) { return list.length ? escapeHtml(list.map(function (x) { return x.full_name; }).join(", ")) : ""; }
|
||||||
|
|
||||||
let markers = "<span class=\"num\">" + d.getDate() + "</span>";
|
let html = "<span class=\"num\">" + d.getDate() + "</span><div class=\"day-markers\">";
|
||||||
if (dutyList.length) {
|
if (showMarkers) {
|
||||||
markers += "<span class=\"duty-marker\" data-names=\"" + namesAttr(dutyList) + "\" title=\"" + titleAttr(dutyList) + "\" aria-label=\"Дежурные\">Д</span>";
|
if (dutyList.length) {
|
||||||
|
html += "<span class=\"duty-marker\" data-names=\"" + namesAttr(dutyList) + "\" title=\"" + titleAttr(dutyList) + "\" aria-label=\"Дежурные\">Д</span>";
|
||||||
|
}
|
||||||
|
if (unavailableList.length) {
|
||||||
|
html += "<span class=\"unavailable-marker\" data-names=\"" + namesAttr(unavailableList) + "\" title=\"" + titleAttr(unavailableList) + "\" aria-label=\"Недоступен\">Н</span>";
|
||||||
|
}
|
||||||
|
if (vacationList.length) {
|
||||||
|
html += "<span class=\"vacation-marker\" data-names=\"" + namesAttr(vacationList) + "\" title=\"" + titleAttr(vacationList) + "\" aria-label=\"Отпуск\">О</span>";
|
||||||
|
}
|
||||||
|
if (hasEvent) {
|
||||||
|
html += "<button type=\"button\" class=\"info-btn\" aria-label=\"Информация о дне\" data-summary=\"" + escapeHtml(eventSummaries.join("\n")) + "\">i</button>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (unavailableList.length) {
|
html += "</div>";
|
||||||
markers += "<span class=\"unavailable-marker\" data-names=\"" + namesAttr(unavailableList) + "\" title=\"" + titleAttr(unavailableList) + "\" aria-label=\"Недоступен\">Н</span>";
|
cell.innerHTML = html;
|
||||||
}
|
|
||||||
if (vacationList.length) {
|
|
||||||
markers += "<span class=\"vacation-marker\" data-names=\"" + namesAttr(vacationList) + "\" title=\"" + titleAttr(vacationList) + "\" aria-label=\"Отпуск\">О</span>";
|
|
||||||
}
|
|
||||||
if (hasEvent) {
|
|
||||||
markers += "<button type=\"button\" class=\"info-btn\" aria-label=\"Информация о дне\" data-summary=\"" + escapeHtml(eventSummaries.join("\n")) + "\">i</button>";
|
|
||||||
}
|
|
||||||
cell.innerHTML = markers;
|
|
||||||
calendarEl.appendChild(cell);
|
calendarEl.appendChild(cell);
|
||||||
d.setDate(d.getDate() + 1);
|
d.setDate(d.getDate() + 1);
|
||||||
}
|
}
|
||||||
@@ -470,8 +474,12 @@
|
|||||||
setNavEnabled(false);
|
setNavEnabled(false);
|
||||||
loadingEl.classList.remove("hidden");
|
loadingEl.classList.remove("hidden");
|
||||||
errorEl.hidden = true;
|
errorEl.hidden = true;
|
||||||
const from = localDateString(firstDayOfMonth(current));
|
const first = firstDayOfMonth(current);
|
||||||
const to = localDateString(lastDayOfMonth(current));
|
const start = getMonday(first);
|
||||||
|
const gridEnd = new Date(start);
|
||||||
|
gridEnd.setDate(gridEnd.getDate() + 41);
|
||||||
|
const from = localDateString(start);
|
||||||
|
const to = localDateString(gridEnd);
|
||||||
try {
|
try {
|
||||||
const dutiesPromise = fetchDuties(from, to);
|
const dutiesPromise = fetchDuties(from, to);
|
||||||
const eventsPromise = fetchCalendarEvents(from, to);
|
const eventsPromise = fetchCalendarEvents(from, to);
|
||||||
@@ -480,7 +488,16 @@
|
|||||||
const byDate = dutiesByDate(duties);
|
const byDate = dutiesByDate(duties);
|
||||||
const calendarByDate = calendarEventsByDate(events);
|
const calendarByDate = calendarEventsByDate(events);
|
||||||
renderCalendar(current.getFullYear(), current.getMonth(), byDate, calendarByDate);
|
renderCalendar(current.getFullYear(), current.getMonth(), byDate, calendarByDate);
|
||||||
renderDutyList(duties);
|
const last = lastDayOfMonth(current);
|
||||||
|
const firstKey = localDateString(first);
|
||||||
|
const lastKey = localDateString(last);
|
||||||
|
const dutiesInMonth = duties.filter(function (d) {
|
||||||
|
const byDateLocal = dutiesByDate([d]);
|
||||||
|
return Object.keys(byDateLocal).some(function (key) {
|
||||||
|
return key >= firstKey && key <= lastKey;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
renderDutyList(dutiesInMonth);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === "ACCESS_DENIED") {
|
if (e.message === "ACCESS_DENIED") {
|
||||||
showAccessDenied(e.serverDetail);
|
showAccessDenied(e.serverDetail);
|
||||||
|
|||||||
@@ -143,6 +143,17 @@ body {
|
|||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.day-markers {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2px;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 2px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.calendar-event-hint {
|
.calendar-event-hint {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
@@ -170,10 +181,9 @@ body {
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 16px;
|
width: 14px;
|
||||||
height: 16px;
|
height: 14px;
|
||||||
margin-top: 2px;
|
font-size: 0.6rem;
|
||||||
font-size: 0.65rem;
|
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -205,6 +215,10 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.duty-item {
|
.duty-item {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 5.5em 1fr;
|
||||||
|
gap: 0 8px;
|
||||||
|
align-items: baseline;
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -221,16 +235,23 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.duty-item .duty-item-type {
|
.duty-item .duty-item-type {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
margin-right: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.duty-item .name {
|
.duty-item .name {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1 / -1;
|
||||||
|
min-width: 0;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.duty-item .time {
|
.duty-item .time {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 2;
|
||||||
|
align-self: start;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user