diff --git a/webapp/app.js b/webapp/app.js
index 544536b..36ede1e 100644
--- a/webapp/app.js
+++ b/webapp/app.js
@@ -207,25 +207,29 @@
const hasEvent = eventSummaries.length > 0;
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 titleAttr(list) { return list.length ? escapeHtml(list.map(function (x) { return x.full_name; }).join(", ")) : ""; }
- let markers = "" + d.getDate() + "";
- if (dutyList.length) {
- markers += "Д";
+ let html = "" + d.getDate() + "
";
+ if (showMarkers) {
+ if (dutyList.length) {
+ html += "Д";
+ }
+ if (unavailableList.length) {
+ html += "Н";
+ }
+ if (vacationList.length) {
+ html += "О";
+ }
+ if (hasEvent) {
+ html += "";
+ }
}
- if (unavailableList.length) {
- markers += "Н";
- }
- if (vacationList.length) {
- markers += "О";
- }
- if (hasEvent) {
- markers += "";
- }
- cell.innerHTML = markers;
+ html += "
";
+ cell.innerHTML = html;
calendarEl.appendChild(cell);
d.setDate(d.getDate() + 1);
}
@@ -470,8 +474,12 @@
setNavEnabled(false);
loadingEl.classList.remove("hidden");
errorEl.hidden = true;
- const from = localDateString(firstDayOfMonth(current));
- const to = localDateString(lastDayOfMonth(current));
+ const first = firstDayOfMonth(current);
+ const start = getMonday(first);
+ const gridEnd = new Date(start);
+ gridEnd.setDate(gridEnd.getDate() + 41);
+ const from = localDateString(start);
+ const to = localDateString(gridEnd);
try {
const dutiesPromise = fetchDuties(from, to);
const eventsPromise = fetchCalendarEvents(from, to);
@@ -480,7 +488,16 @@
const byDate = dutiesByDate(duties);
const calendarByDate = calendarEventsByDate(events);
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) {
if (e.message === "ACCESS_DENIED") {
showAccessDenied(e.serverDetail);
diff --git a/webapp/style.css b/webapp/style.css
index 8a1a8a4..73eccc7 100644
--- a/webapp/style.css
+++ b/webapp/style.css
@@ -143,6 +143,17 @@ body {
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 {
position: fixed;
z-index: 1000;
@@ -170,10 +181,9 @@ body {
display: inline-flex;
align-items: center;
justify-content: center;
- width: 16px;
- height: 16px;
- margin-top: 2px;
- font-size: 0.65rem;
+ width: 14px;
+ height: 14px;
+ font-size: 0.6rem;
font-weight: 700;
border-radius: 50%;
flex-shrink: 0;
@@ -205,6 +215,10 @@ body {
}
.duty-item {
+ display: grid;
+ grid-template-columns: 5.5em 1fr;
+ gap: 0 8px;
+ align-items: baseline;
padding: 8px 10px;
margin-bottom: 6px;
border-radius: 8px;
@@ -221,16 +235,23 @@ body {
}
.duty-item .duty-item-type {
+ grid-column: 1;
+ grid-row: 1;
font-size: 0.75rem;
color: var(--muted);
- margin-right: 4px;
}
.duty-item .name {
+ grid-column: 2;
+ grid-row: 1 / -1;
+ min-width: 0;
font-weight: 600;
}
.duty-item .time {
+ grid-column: 1;
+ grid-row: 2;
+ align-self: start;
font-size: 0.8rem;
color: var(--muted);
}