line height text, refactored course schedule, added string representation functions to course meeting
This commit is contained in:
@@ -72,7 +72,7 @@ export class Course {
|
||||
/** Which semester is the course from */
|
||||
semester: Semester;
|
||||
|
||||
constructor(course: Course | Serialized<Course>) {
|
||||
constructor(course: Serialized<Course>) {
|
||||
Object.assign(this, course);
|
||||
this.schedule = new CourseSchedule(course.schedule);
|
||||
}
|
||||
|
||||
128
src/shared/types/CourseMeeting.ts
Normal file
128
src/shared/types/CourseMeeting.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Serialized } from 'chrome-extension-toolkit';
|
||||
|
||||
/**
|
||||
* a map of the days of the week that a class is taught, and the corresponding abbreviation
|
||||
*/
|
||||
export const DAY_MAP = {
|
||||
M: 'Monday',
|
||||
T: 'Tuesday',
|
||||
W: 'Wednesday',
|
||||
TH: 'Thursday',
|
||||
F: 'Friday',
|
||||
S: 'Saturday',
|
||||
SU: 'Sunday',
|
||||
} as const;
|
||||
|
||||
/** A day of the week that a class is taught */
|
||||
export type Day = typeof DAY_MAP[keyof typeof DAY_MAP];
|
||||
|
||||
/** A physical room that a class is taught in */
|
||||
export type Room = {
|
||||
/** The UT building code for where the class is taught */
|
||||
building: string;
|
||||
/** The room number for where the class is taught */
|
||||
number: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* This represents one "Meeting Time" for a course, which includes the day of the week that the course is taught, the time that the course is taught, and the location that the course is taught
|
||||
*/
|
||||
export class CourseMeeting {
|
||||
/** The day of the week that the course is taught */
|
||||
days: Day[];
|
||||
/** The start time of the course, in minutes since midnight */
|
||||
startTime: number;
|
||||
/** The end time of the course, in minutes since midnight */
|
||||
endTime: number;
|
||||
/** The location that the course is taught */
|
||||
room?: Room;
|
||||
|
||||
constructor(meeting: Serialized<CourseMeeting>) {
|
||||
Object.assign(this, meeting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string representation of the days of the week that this meeting is taught
|
||||
* @param options options for the string representation
|
||||
* @returns string representation of the days of the week that this meeting is taught
|
||||
*/
|
||||
getDaysString(options: DaysStringOptions): string {
|
||||
let { format, separator } = options;
|
||||
let { days } = this;
|
||||
|
||||
if (format === 'short') {
|
||||
days = Object.keys(DAY_MAP).filter(day => days.includes(DAY_MAP[day as keyof typeof DAY_MAP])) as Day[];
|
||||
}
|
||||
if (separator === 'none') {
|
||||
return days.join('');
|
||||
}
|
||||
const listFormat = new Intl.ListFormat('en-US', {
|
||||
style: separator,
|
||||
type: 'conjunction',
|
||||
});
|
||||
return listFormat.format(days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string representation of the time range for the course
|
||||
* @param options options for the string representation
|
||||
* @returns string representation of the time range for the course
|
||||
*/
|
||||
getTimeString(options: TimeStringOptions): string {
|
||||
const { startTime, endTime } = this;
|
||||
const startHour = Math.floor(startTime / 60);
|
||||
const startMinute = startTime % 60;
|
||||
const endHour = Math.floor(endTime / 60);
|
||||
const endMinute = endTime % 60;
|
||||
|
||||
let startTimeString = '';
|
||||
let endTimeString = '';
|
||||
|
||||
if (startHour === 0) {
|
||||
startTimeString = '12';
|
||||
} else if (startHour > 12) {
|
||||
startTimeString = `${startHour - 12}`;
|
||||
} else {
|
||||
startTimeString = `${startHour}`;
|
||||
}
|
||||
|
||||
startTimeString += startMinute === 0 ? ':00' : `:${startMinute}`;
|
||||
startTimeString += startHour >= 12 ? 'pm' : 'am';
|
||||
|
||||
if (endHour === 0) {
|
||||
endTimeString = '12';
|
||||
} else if (endHour > 12) {
|
||||
endTimeString = `${endHour - 12}`;
|
||||
} else {
|
||||
endTimeString = `${endHour}`;
|
||||
}
|
||||
endTimeString += endMinute === 0 ? ':00' : `:${endMinute}`;
|
||||
endTimeString += endHour >= 12 ? 'pm' : 'am';
|
||||
|
||||
if (options.capitalize) {
|
||||
startTimeString = startTimeString.toUpperCase();
|
||||
endTimeString = endTimeString.toUpperCase();
|
||||
}
|
||||
|
||||
return `${startTimeString} ${options.separator} ${endTimeString}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to control the format of the time string
|
||||
*/
|
||||
type TimeStringOptions = {
|
||||
/** the separator between the start and end times */
|
||||
separator: string;
|
||||
/** capitalizes the AM/PM */
|
||||
capitalize?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to control the format of the days string
|
||||
*/
|
||||
type DaysStringOptions = {
|
||||
/** The format of the days string, short = MWF, long = Monday, Wednesday, Friday */
|
||||
format: 'short' | 'long';
|
||||
separator: Intl.ListFormatStyle | 'none';
|
||||
};
|
||||
@@ -1,61 +1,27 @@
|
||||
import { Serialized } from 'chrome-extension-toolkit';
|
||||
|
||||
/**
|
||||
* a map of the days of the week that a class is taught, and the corresponding abbreviation
|
||||
*/
|
||||
const DAY_MAP = {
|
||||
M: 'Monday',
|
||||
T: 'Tuesday',
|
||||
W: 'Wednesday',
|
||||
TH: 'Thursday',
|
||||
F: 'Friday',
|
||||
S: 'Saturday',
|
||||
SU: 'Sunday',
|
||||
} as const;
|
||||
|
||||
/** A day of the week that a class is taught */
|
||||
export type Day = typeof DAY_MAP[keyof typeof DAY_MAP];
|
||||
|
||||
/** A physical room that a class is taught in */
|
||||
export type Room = {
|
||||
/** The UT building code for where the class is taught */
|
||||
building: string;
|
||||
/** The room number for where the class is taught */
|
||||
number: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* This represents one "Meeting Time" for a course, which includes the day of the week that the course is taught, the time that the course is taught, and the location that the course is taught
|
||||
*/
|
||||
export type CourseMeeting = {
|
||||
/** The day of the week that the course is taught */
|
||||
day: Day;
|
||||
/** The start time of the course, in minutes since midnight */
|
||||
startTime: number;
|
||||
/** The end time of the course, in minutes since midnight */
|
||||
endTime: number;
|
||||
/** The location that the course is taught */
|
||||
room?: Room;
|
||||
};
|
||||
import { CourseMeeting, Day, DAY_MAP } from './CourseMeeting';
|
||||
|
||||
/**
|
||||
* This represents the schedule for a course, which includes all the meeting times for the course, as well as helper functions for parsing, serializing, and deserializing the schedule
|
||||
*/
|
||||
export class CourseSchedule {
|
||||
meetings: CourseMeeting[];
|
||||
meetings: CourseMeeting[] = [];
|
||||
|
||||
constructor(courseSchedule: CourseSchedule | Serialized<CourseSchedule>) {
|
||||
constructor(courseSchedule?: Serialized<CourseSchedule>) {
|
||||
if (!courseSchedule) {
|
||||
return;
|
||||
}
|
||||
Object.assign(this, courseSchedule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string representation of a schedule, parse it into a CourseSchedule object
|
||||
* Given a string representation of the meeting information for a class, parse it into a CourseMeeting object
|
||||
* @param dayLine a string representation of the days of the week that the course is taught: MWF, TR, etc.
|
||||
* @param timeLine a string representation of a time-range that the course is taught: 10:00 am - 11:00 am, 1:00 pm - 2:00 pm, etc.
|
||||
* @param roomLine a string representation of the room that the course is taught in: JGB 2.302, etc.
|
||||
* @returns an array of CourseMeeting objects, which represent the schedule for the course
|
||||
* @returns CourseMeeting object representing the meeting information
|
||||
*/
|
||||
static parse(dayLine: string, timeLine: string, roomLine: string): CourseMeeting[] {
|
||||
static parse(dayLine: string, timeLine: string, roomLine: string): CourseMeeting {
|
||||
try {
|
||||
let days: Day[] = dayLine
|
||||
.split('')
|
||||
@@ -87,15 +53,15 @@ export class CourseSchedule {
|
||||
|
||||
const [building, number] = roomLine.split(' ');
|
||||
|
||||
return days.map(day => ({
|
||||
day,
|
||||
return new CourseMeeting({
|
||||
days,
|
||||
startTime,
|
||||
endTime,
|
||||
room: {
|
||||
building,
|
||||
number,
|
||||
},
|
||||
}));
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to parse schedule: ${dayLine} ${timeLine} ${roomLine}`);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ export default function Text(props: PropsWithChildren<TextProps>) {
|
||||
style.color ??= colors?.[props.color ?? 'charcoal'];
|
||||
style.fontSize ??= fonts?.[`${props.size ?? 'medium'}_size`];
|
||||
style.fontWeight ??= fonts?.[`${props.weight ?? 'regular'}_weight`];
|
||||
style.lineHeight ??= fonts?.[`${props.size ?? 'medium'}_line_height`];
|
||||
|
||||
if (props.span) {
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,7 @@ interface Props {
|
||||
* The popup that appears when the user clicks on a course for more details.
|
||||
*/
|
||||
export default function CoursePopup({ course, onClose }: Props) {
|
||||
console.log(course);
|
||||
return (
|
||||
<Popup className={styles.popup} overlay>
|
||||
<Icon className={styles.close} size='large' name='close' onClick={onClose} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Course, Instructor, Status, InstructionMode, ScrapedRow } from 'src/shared/types/Course';
|
||||
import { CourseSchedule, CourseMeeting } from 'src/shared/types/CourseSchedule';
|
||||
import { CourseSchedule } from 'src/shared/types/CourseSchedule';
|
||||
import { SiteSupport } from 'src/views/lib/getSiteSupport';
|
||||
|
||||
/**
|
||||
@@ -289,17 +289,18 @@ export class CourseCatalogScraper {
|
||||
throw new Error('Schedule data is malformed');
|
||||
}
|
||||
|
||||
const meetings: CourseMeeting[] = [];
|
||||
const schedule = new CourseSchedule();
|
||||
|
||||
for (let i = 0; i < dayLines.length; i += 1) {
|
||||
const lineMeetings = CourseSchedule.parse(
|
||||
schedule.meetings.push(
|
||||
CourseSchedule.parse(
|
||||
dayLines[i].textContent || '',
|
||||
hourLines[i].textContent || '',
|
||||
roomLines[i].textContent || ''
|
||||
)
|
||||
);
|
||||
meetings.push(...lineMeetings);
|
||||
}
|
||||
|
||||
return new CourseSchedule({ meetings });
|
||||
return schedule;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,13 @@ $large_size: 24px;
|
||||
$x_large_size: 32px;
|
||||
$xx_large_size: 48px;
|
||||
|
||||
$x_small_line_height: 12px;
|
||||
$small_line_height: 16px;
|
||||
$medium_line_height: 20px;
|
||||
$large_line_height: 28px;
|
||||
$x_large_line_height: 36px;
|
||||
$xx_large_line_height: 52px;
|
||||
|
||||
:export {
|
||||
light_weight: $light_weight;
|
||||
regular_weight: $regular_weight;
|
||||
@@ -44,4 +51,12 @@ $xx_large_size: 48px;
|
||||
large_size: $large_size;
|
||||
x_large_size: $x_large_size;
|
||||
xx_large_size: $xx_large_size;
|
||||
|
||||
x_small_line_height: $x_small_line_height;
|
||||
small_line_height: $small_line_height;
|
||||
medium_line_height: $medium_line_height;
|
||||
large_line_height: $large_line_height;
|
||||
x_large_line_height: $x_large_line_height;
|
||||
xx_large_line_height: $xx_large_line_height;
|
||||
|
||||
}
|
||||
|
||||
14
src/views/styles/fonts.module.scss.d.ts
vendored
14
src/views/styles/fonts.module.scss.d.ts
vendored
@@ -22,6 +22,18 @@ export interface ISizes {
|
||||
xx_large_size: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* the type for all the line height scss variables exported from fonts.module.scss
|
||||
*/
|
||||
export interface LineHeight {
|
||||
x_small_line_height: number;
|
||||
small_line_height: number;
|
||||
medium_line_height: number;
|
||||
large_line_height: number;
|
||||
x_large_line_height: number;
|
||||
xx_large_line_height: number;
|
||||
}
|
||||
|
||||
/** A utility type that removes the _weight postfix from the variable names for weights */
|
||||
export type Weight = keyof IWeights extends `${infer U}_weight` ? U : never;
|
||||
|
||||
@@ -32,7 +44,7 @@ export type Size = keyof ISizes extends `${infer U}_size` ? U : never;
|
||||
* This is a file that we need to create to tell typescript what the shape of the css modules is
|
||||
* when we import them into ts/tsx files
|
||||
*/
|
||||
export type IFonts = IWeights & ISizes;
|
||||
export type IFonts = IWeights & ISizes & LineHeight;
|
||||
|
||||
declare const fonts: IFonts;
|
||||
export default fonts;
|
||||
|
||||
2
todo.md
2
todo.md
@@ -42,7 +42,9 @@ Last Updated: 03/4/2023
|
||||
- [ ] see who else is looking at certain classes (waitlist, or has it in their schedule)
|
||||
- [ ] github contributors displayed somewhere
|
||||
- [ ] Links to discord/github
|
||||
- [ ] my twitter handle for support
|
||||
- [ ] on CS/ECE/MIS pages, show some banner somewhere for students to join the dev team!
|
||||
- [ ] suggest fun classes to take? or classes that are easy A's? or classes that have not a lot of people / lot of people in them?
|
||||
- [ ] CHECK ALL THE TODOs in CODE BEFORE LAUNCHING
|
||||
|
||||
## LEGACY FROM UTRP-V1
|
||||
|
||||
Reference in New Issue
Block a user