Files
psu-schedule/scripts/snapshot-lines.js
Zakhar Timoshenko 297091cb0e feat: Add Settings and Subjects screens with theme reveal functionality
- Implemented SettingsScreen for user preferences including theme selection, reminders, and notifications.
- Created SubjectsScreen to display subjects with upcoming lessons and associated details.
- Introduced ThemeReveal for a smooth transition between light and dark themes.
- Added support for managing notes and tasks related to subjects.
- Enhanced UI components for better user experience and accessibility.
2026-10-24 02:47:37 +03:00

51 lines
2.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// One readable line per parsed lesson, the form both snapshots compare: what a student sees
// (day, time, weeks or dates, subject, kind, room, teacher, groups), not ids or source colours.
const DAYS = ["", "пн", "вт", "ср", "чт", "пт", "сб", "вс"];
const weeks = (ranges) =>
ranges?.map(([a, b]) => (b === null ? `с ${a}` : a === b ? `${a}` : `${a}-${b}`)).join(",") || "";
export const lessonLine = (l) =>
[
`${l.date || DAYS[l.day]} ${l.start}${l.end ? `–${l.end}` : ""}`,
(l.date ? "один раз" : l.dates?.length ? `даты ${l.dates.join(",")}` : l.weekRanges ? `нед. ${weeks(l.weekRanges)}` : "каждую неделю") +
(l.variant === "upper" ? ", верхняя строка" : l.variant === "lower" ? ", нижняя строка" : ""),
l.subject,
l.type,
// The town only when the cell names one or the day's note puts the lesson there.
[l.room, l.place].filter(Boolean).join(", "),
l.teacher,
[...l.groups, ...l.subgroups.map((s) => `${s.group}/${s.label.replace("Подгруппа ", "п")}`)].join(",") +
// "Немецкий язык" or "Французский язык": a part of the group takes one of them.
(l.option ? " · на выбор" : "") +
// Russian for foreign students while the others have physical education.
(l.audience === "foreign" ? " · иностранцам" : l.audience === "local" ? " · кроме иностранцев" : ""),
]
.map((part) => String(part ?? "").replace(/\s+/g, " ").trim())
.join(" | ");
// "Занятия в Полоцке": a day of a group or subgroup in another town, not a lesson.
const placeLine = (p) =>
[
`@ ${p.date || DAYS[p.day]}${p.from ? ` с ${p.from}` : ""}`,
p.text,
[...p.groups, ...p.subgroups.map((s) => `${s.group}/${s.label.replace("Подгруппа ", "п")}`)].join(","),
].join(" | ");
/** Sorted lesson lines of a parsed document, with its groups and period on top. */
export const snapshotOf = (schedule) => [
`# ${schedule.period} · ${schedule.groups.join(", ")}`,
...(schedule.places || []).map(placeLine).sort(),
...schedule.lessons.map(lessonLine).sort(),
];
/** Lines only in `before` (removed) and only in `after` (added), duplicates counted. */
export function diffLines(before, after) {
const count = (lines) => lines.reduce((m, x) => m.set(x, (m.get(x) || 0) + 1), new Map());
const a = count(before), b = count(after);
const removed = [], added = [];
for (const [line, n] of a) for (let i = b.get(line) || 0; i < n; i++) removed.push(line);
for (const [line, n] of b) for (let i = a.get(line) || 0; i < n; i++) added.push(line);
return { removed, added };
}