Фронт: без бейджа «Обе недели», недели на страницах преподов/аудиторий, иконка приложения
- пары с одинаковыми ч/з показываются одним списком без пометки недели (группы, преподаватели, аудитории); раньше на страницах преподавателей и аудиторий такое занятие дублировалось в обеих колонках - бейдж «Обе недели» убран как информационный шум (отсутствие пометки и означает «любая неделя») - favicon: квадрат с градиентом боковой панели (#1b2dd8 → #167cf2) и совой - PWA: manifest.json, sw.js, apple-touch-icon и иконки 192/512 — при добавлении на главный экран смартфона появляется логотип - tools/make_icons.py — генерация иконок из логотипа (rsvg-convert) - удалён неиспользуемый roomPeriodCell и мёртвый favicon.png
This commit is contained in:
@@ -227,7 +227,9 @@ function addPeriodRow(block, num, time, lessonsHTML) {
|
||||
}
|
||||
|
||||
function entityLessonHTML(parity, entry) {
|
||||
const active = parity === currentParity ? " active" : "";
|
||||
const badge = parity
|
||||
? `<span class="${PARITY_CLASS[parity]}${parity === currentParity ? " active" : ""}">${PARITY_LABEL[parity]}</span>`
|
||||
: "";
|
||||
const details = [];
|
||||
if (entry.room) details.push(entry.room);
|
||||
if (entry.teacher) details.push(entry.teacher);
|
||||
@@ -235,7 +237,7 @@ function entityLessonHTML(parity, entry) {
|
||||
return `
|
||||
<div class="lesson">
|
||||
<div>
|
||||
<span class="${PARITY_CLASS[parity]}${active}">${PARITY_LABEL[parity]}</span>
|
||||
${badge}
|
||||
${entry.marker ? `<span class="badge badge-kv">${escapeHTML(entry.marker)}</span>` : ""}
|
||||
<span class="subject">${escapeHTML(entry.subject)}</span>
|
||||
</div>
|
||||
@@ -244,19 +246,36 @@ function entityLessonHTML(parity, entry) {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/** Занятия числителя и знаменателя совпадают: неделя не важна. */
|
||||
function sameEntries(chEntries, znEntries) {
|
||||
return chEntries.length > 0 && JSON.stringify(chEntries) === JSON.stringify(znEntries);
|
||||
}
|
||||
|
||||
/** Колонки занятий для страниц преподавателя и аудитории. */
|
||||
function lessonsColHTML(chEntries, znEntries) {
|
||||
if (sameEntries(chEntries, znEntries)) {
|
||||
// не зависит от недели — одним списком, без бейджа недели
|
||||
return `<div class="parities">${alwaysColHTML(chEntries.map((e) => entityLessonHTML(null, e)).join(""))}</div>`;
|
||||
}
|
||||
const chHtml = chEntries.map((e) => entityLessonHTML("ч", e)).join("");
|
||||
const znHtml = znEntries.map((e) => entityLessonHTML("з", e)).join("");
|
||||
return `<div class="parities">${parityColHTML("", chHtml || OKNO_HTML)}${parityColHTML("", znHtml || OKNO_HTML)}</div>`;
|
||||
}
|
||||
|
||||
function singleLessonHTML(badgeKey, lesson, full) {
|
||||
const config = {
|
||||
always: { label: "Обе недели", cls: "badge badge-always" },
|
||||
always: { label: "", cls: "badge badge-always" },
|
||||
ч: { label: "Числитель", cls: "badge badge-ch" },
|
||||
з: { label: "Знаменатель", cls: "badge badge-zn" },
|
||||
};
|
||||
const { label, cls } = config[badgeKey];
|
||||
const active = badgeKey !== "always" && badgeKey === currentParity ? " active" : "";
|
||||
const badge = label ? `<span class="${cls}${active}">${label}</span>` : "";
|
||||
const details = [lesson.teacher, lesson.room].filter(Boolean).join(" · ");
|
||||
return `
|
||||
<div class="lesson${full ? " full" : ""}">
|
||||
<div>
|
||||
<span class="${cls}${active}">${label}</span>
|
||||
${badge}
|
||||
${lesson.marker ? `<span class="badge badge-kv">${escapeHTML(lesson.marker)}</span>` : ""}
|
||||
<span class="subject">${escapeHTML(lesson.subject)}</span>
|
||||
</div>
|
||||
@@ -368,11 +387,11 @@ function renderTeacher(data, status) {
|
||||
Object.entries(periods)
|
||||
.sort(([a], [b]) => Number(a) - Number(b))
|
||||
.forEach(([num, slot]) => {
|
||||
const chHtml = (slot.ч || []).map((entry) => { hasAny = true; return entityLessonHTML("ч", entry); }).join("");
|
||||
const znHtml = (slot.з || []).map((entry) => { hasAny = true; return entityLessonHTML("з", entry); }).join("");
|
||||
if (!chHtml && !znHtml) return;
|
||||
const inner = `<div class="parities">${parityColHTML("Числитель", chHtml || OKNO_HTML)}${parityColHTML("Знаменатель", znHtml || OKNO_HTML)}</div>`;
|
||||
addPeriodRow(block, num, slot.time, inner);
|
||||
const chEntries = slot.ч || [];
|
||||
const znEntries = slot.з || [];
|
||||
if (!chEntries.length && !znEntries.length) return;
|
||||
hasAny = true;
|
||||
addPeriodRow(block, num, slot.time, lessonsColHTML(chEntries, znEntries));
|
||||
});
|
||||
daysContainer.appendChild(block);
|
||||
});
|
||||
@@ -457,9 +476,7 @@ function buildRoomsList(data, periodNums) {
|
||||
if (!chEntries.length && !znEntries.length) {
|
||||
body.innerHTML = `<div class="parities">${parityColHTML("", OKNO_HTML)}</div>`;
|
||||
} else {
|
||||
const chHtml = chEntries.map((e) => entityLessonHTML("ч", e)).join("");
|
||||
const znHtml = znEntries.map((e) => entityLessonHTML("з", e)).join("");
|
||||
body.innerHTML = `<div class="parities">${parityColHTML("", chHtml || OKNO_HTML)}${parityColHTML("", znHtml || OKNO_HTML)}</div>`;
|
||||
body.innerHTML = lessonsColHTML(chEntries, znEntries);
|
||||
}
|
||||
row.appendChild(body);
|
||||
card.appendChild(row);
|
||||
@@ -469,33 +486,6 @@ function buildRoomsList(data, periodNums) {
|
||||
return list;
|
||||
}
|
||||
|
||||
function roomPeriodCell(slot) {
|
||||
const td = document.createElement("td");
|
||||
td.className = "r-cell";
|
||||
const all = [...((slot && slot.ч) || []), ...((slot && slot.з) || [])];
|
||||
if (!all.length) {
|
||||
td.classList.add("r-free");
|
||||
td.textContent = "окно";
|
||||
return td;
|
||||
}
|
||||
td.classList.add("r-busy");
|
||||
const seen = new Set();
|
||||
const lines = [];
|
||||
all.forEach((e) => {
|
||||
if (!e.subject || seen.has(e.subject)) return;
|
||||
seen.add(e.subject);
|
||||
lines.push(e.subject);
|
||||
});
|
||||
lines.forEach((x) => {
|
||||
const div = document.createElement("div");
|
||||
div.className = "r-subj";
|
||||
div.textContent = x;
|
||||
td.appendChild(div);
|
||||
});
|
||||
td.title = lines.join("; ");
|
||||
return td;
|
||||
}
|
||||
|
||||
function escapeHTML(s) {
|
||||
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
|
||||
}
|
||||
@@ -547,3 +537,10 @@ loadWeek().finally(() => {
|
||||
errorEl.classList.remove("hidden");
|
||||
});
|
||||
});
|
||||
|
||||
// PWA: ярлык «на главный экран» с иконкой приложения (манифест + service worker)
|
||||
if ("serviceWorker" in navigator) {
|
||||
window.addEventListener("load", () => {
|
||||
navigator.serviceWorker.register("/sw.js").catch(() => {});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user