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.
This commit is contained in:
@@ -5,7 +5,8 @@ import { roomMoves } from "./rooms.js";
|
||||
// whole text as the subject. These checks find such cells after parsing, so a new format or a
|
||||
// typo in Word shows up as soon as the document is published instead of when a student notices.
|
||||
|
||||
const MONTHS = /(?<![а-яё])(?:январ|феврал|март|апрел|ма[йя]|июн|июл|август|сентябр|октябр|ноябр|декабр)[а-яё]*/iu;
|
||||
// "мая" is a month, "Майнор" is not.
|
||||
const MONTHS = /(?<![а-яё])(?:(?:январ|феврал|март|апрел|июн|июл|август|сентябр|октябр|ноябр|декабр)[а-яё]*|ма[йя](?![а-яё]))/iu;
|
||||
// The longest semester has about twenty weeks; "27н." is a typo, not a week.
|
||||
const LAST_WEEK = 24;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { parseWeekRanges, parseTextDates, DATE_LIST, weekday } from "../shared/w
|
||||
import { roomMoves, onlyPlace, weekPlan, partsByWeek } from "./rooms.js";
|
||||
import { placeNote, lessonPlace, placeOf } from "./places.js";
|
||||
const run = promisify(execFile);
|
||||
export const PARSER_VERSION = 18;
|
||||
export const PARSER_VERSION = 19;
|
||||
const days = [
|
||||
"понедельник",
|
||||
"вторник",
|
||||
@@ -20,10 +20,17 @@ const days = [
|
||||
"суббота",
|
||||
"воскресенье",
|
||||
];
|
||||
const clean = (value) =>
|
||||
export const clean = (value) =>
|
||||
value
|
||||
.replace(/\u00a0/g, " ")
|
||||
// "Ф и з и ч е с к а я к у л ь т у р а": letters spaced out for show, words apart by
|
||||
// several spaces. Joined back before the spaces collapse: "Физическая культура".
|
||||
.replace(/(?<![\p{L}\d])(?:\p{L} ){3,}\p{L}(?![\p{L}\d])/gu, (word) => word.replace(/ /g, ""))
|
||||
// "со 2 по 14 нед.": the usual "2-14 нед.".
|
||||
.replace(/(?<![\p{L}\d])(?:с|со)\s*(\d{1,2})\s*по\s*(\d{1,2})(?=\s*н(?:ед)?\.?)/giu, "$1-$2")
|
||||
.replace(/[\t ]+/g, " ")
|
||||
.replace(/«\s+/g, "«")
|
||||
.replace(/\s+»/g, "»")
|
||||
.replace(/\s*\n\s*/g, "\n")
|
||||
.trim();
|
||||
// A group is a two-digit year and a capitalised abbreviation: "23-БА", "24-ДОи", "23-ИНС-1",
|
||||
@@ -595,7 +602,9 @@ export function parseDocx(buffer, source = {}) {
|
||||
date = null,
|
||||
time = null,
|
||||
pair = null,
|
||||
timeCol = null;
|
||||
timeCol = null,
|
||||
// The day's first lesson time: a town note further down holds from its own row on.
|
||||
dayStart = null;
|
||||
// Session schedules use separate room, subject and teacher columns.
|
||||
const session = rows[header].some((cell) => /пара/i.test(cell.text));
|
||||
let sessionColumns = null;
|
||||
@@ -625,6 +634,7 @@ export function parseDocx(buffer, source = {}) {
|
||||
: null;
|
||||
time = null;
|
||||
pair = null;
|
||||
dayStart = null;
|
||||
}
|
||||
if (!day) continue;
|
||||
// Credits and exams give only the start ("8.30"); the bell table supplies the end.
|
||||
@@ -637,6 +647,7 @@ export function parseDocx(buffer, source = {}) {
|
||||
pair = session ? row.find((c) => c.col === 1)?.text : null;
|
||||
}
|
||||
if (!time) continue;
|
||||
dayStart ??= time.start;
|
||||
seenRows++;
|
||||
const continuedTime =
|
||||
row.find((c) => c.col === timeCol)?.merge === "continue";
|
||||
@@ -667,7 +678,9 @@ export function parseDocx(buffer, source = {}) {
|
||||
// are in that town. A lesson may follow it in the same cell.
|
||||
const note = placeNote(raw);
|
||||
if (note) {
|
||||
places.push({ day, date, groups: targetGroups, subgroups: columnSubgroups, place: note.place, text: note.text });
|
||||
// "Занятия в Полоцке" in the 13:40 row of 25-ИТ: the morning is in Novopolotsk.
|
||||
const from = time.start > dayStart ? time.start : null;
|
||||
places.push({ day, date, groups: targetGroups, subgroups: columnSubgroups, place: note.place, text: note.text, ...(from && { from }) });
|
||||
raw = note.rest;
|
||||
if (!raw.trim()) return;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,12 @@ export function placeOf(lesson, places, labelsOf) {
|
||||
let found = null;
|
||||
for (const group of lesson.groups) {
|
||||
const notes = places.filter(
|
||||
(p) => p.day === lesson.day && (!p.date || p.date === lesson.date) && p.groups.includes(group),
|
||||
(p) =>
|
||||
p.day === lesson.day &&
|
||||
(!p.date || p.date === lesson.date) &&
|
||||
p.groups.includes(group) &&
|
||||
// A note from the middle of the day holds from its row on.
|
||||
(!p.from || lesson.start >= p.from),
|
||||
);
|
||||
if (!notes.length) return null;
|
||||
const label = lesson.subgroups.find((s) => s.group === group)?.label;
|
||||
|
||||
Reference in New Issue
Block a user