feat: enable TS strict mode (#168)
* feat: enable TS strict mode * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: colors bug with default * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: text type errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors - add definite assignment assertion * fix: strict TS errors - add definite assignment assertion * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix(ESLint): error on no-explicit-any * fix: type annotations for any types * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors (and remove packages) * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * fix: strict TS errors * feat: enable React.StrictMode * fix: strict TS errors (done!) * fix: build error * fix: replace no-explicit-any assertions * refactor: cleanup * refactor: more cleanup * style: prettier --------- Co-authored-by: Lukas Zenick <lukas@utexas.edu> Co-authored-by: Razboy20 <razboy20@gmail.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { theme } from 'unocss/preset-mini';
|
||||
import type { HexColor, Lab, RGB, sRGB } from '../types/Color';
|
||||
import { isHexColor } from '../types/Color';
|
||||
import type { Course } from '../types/Course';
|
||||
import type { CourseColors, TWColorway } from '../types/ThemeColors';
|
||||
import type { CourseColors, TWColorway, TWIndex } from '../types/ThemeColors';
|
||||
import { colorwayIndexes } from '../types/ThemeColors';
|
||||
import type { UserSchedule } from '../types/UserSchedule';
|
||||
|
||||
@@ -14,18 +14,21 @@ import type { UserSchedule } from '../types/UserSchedule';
|
||||
* @param hex - The hexadecimal color value.
|
||||
* @returns An array containing the RGB values.
|
||||
*/
|
||||
export function hexToRGB(hex: HexColor): RGB {
|
||||
export function hexToRGB(hex: HexColor): RGB | undefined {
|
||||
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
||||
let shorthandRegex: RegExp = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
const parsedHex: string = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
|
||||
let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
const parsedHex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
|
||||
|
||||
let result: RegExpExecArray = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(parsedHex);
|
||||
return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : null;
|
||||
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(parsedHex);
|
||||
|
||||
if (!result || !(result.length > 3)) return undefined;
|
||||
|
||||
return [parseInt(result[1]!, 16), parseInt(result[2]!, 16), parseInt(result[3]!, 16)];
|
||||
}
|
||||
|
||||
export const useableColorways = Object.keys(theme.colors)
|
||||
// check that the color is a colorway (is an object)
|
||||
.filter(color => typeof theme.colors[color] === 'object')
|
||||
.filter(color => typeof theme.colors[color as keyof typeof theme.colors] === 'object')
|
||||
.slice(0, 17) as TWColorway[];
|
||||
|
||||
/**
|
||||
@@ -33,12 +36,16 @@ export const useableColorways = Object.keys(theme.colors)
|
||||
* @param bgColor the hex color of the background
|
||||
*/
|
||||
export function pickFontColor(bgColor: HexColor): 'text-white' | 'text-black' | 'text-theme-black' {
|
||||
const coefficients = [0.2126729, 0.7151522, 0.072175];
|
||||
const coefficients = [0.2126729, 0.7151522, 0.072175] as const;
|
||||
|
||||
const flipYs = 0.342; // based on APCA™ 0.98G middle contrast BG color
|
||||
|
||||
const trc = 2.4; // 2.4 exponent for emulating actual monitor perception
|
||||
let Ys = hexToRGB(bgColor).reduce((acc, c, i) => acc + (c / 255.0) ** trc * coefficients[i], 0);
|
||||
const rgb = hexToRGB(bgColor);
|
||||
if (!rgb) throw new Error('bgColor: Invalid hex.');
|
||||
|
||||
// coefficients and rgb are both 3 elements long, so this is safe
|
||||
let Ys = rgb.reduce((acc, c, i) => acc + (c / 255.0) ** trc * coefficients[i]!, 0);
|
||||
|
||||
if (Ys < flipYs) {
|
||||
return 'text-white';
|
||||
@@ -54,13 +61,13 @@ export function pickFontColor(bgColor: HexColor): 'text-white' | 'text-black' |
|
||||
export function getCourseColors(colorway: TWColorway, index?: number, offset: number = 300): CourseColors {
|
||||
if (index === undefined) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
index = colorway in colorwayIndexes ? colorwayIndexes[colorway] : 500;
|
||||
index = colorway in colorwayIndexes ? colorwayIndexes[colorway as keyof typeof colorwayIndexes] : 500;
|
||||
}
|
||||
|
||||
return {
|
||||
primaryColor: theme.colors[colorway][index],
|
||||
secondaryColor: theme.colors[colorway][index + offset],
|
||||
} satisfies CourseColors;
|
||||
primaryColor: theme.colors[colorway][index as TWIndex] as HexColor,
|
||||
secondaryColor: theme.colors[colorway][(index + offset) as TWIndex] as HexColor,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,7 +94,12 @@ export function getColorwayFromColor(color: HexColor): TWColorway {
|
||||
continue;
|
||||
}
|
||||
|
||||
const distance = oklabDistance(rgbToOKlab(hexToRGB(shadeColor)), rgbToOKlab(hexToRGB(color)));
|
||||
const shadeColorRGB = hexToRGB(shadeColor);
|
||||
if (!shadeColorRGB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const distance = oklabDistance(rgbToOKlab(shadeColorRGB), rgbToOKlab(shadeColorRGB));
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
closestColor = shade;
|
||||
@@ -148,7 +160,8 @@ export function getUnusedColor(
|
||||
|
||||
if (sameDepartment.length > 0) {
|
||||
// check to see if any adjacent colorways are available
|
||||
const centerCourse = sameDepartment[Math.floor(Math.random() * sameDepartment.length)];
|
||||
const centerCourse = sameDepartment[Math.floor(Math.random() * sameDepartment.length)]!;
|
||||
|
||||
let nextColorway = getNextColorway(centerCourse.colorway);
|
||||
let prevColorway = getPreviousColorway(centerCourse.colorway);
|
||||
|
||||
@@ -175,11 +188,18 @@ export function getUnusedColor(
|
||||
|
||||
if (shortenedColorways.size > 0) {
|
||||
// TODO: make this go by 3's to leave future spaces open
|
||||
const randomColorway = Array.from(shortenedColorways)[Math.floor(Math.random() * shortenedColorways.size)];
|
||||
const randomColorway = Array.from(shortenedColorways)[Math.floor(Math.random() * shortenedColorways.size)]!;
|
||||
|
||||
return getCourseColors(randomColorway, index, offset);
|
||||
}
|
||||
// no colorways are at least 2 indexes away from any used colors, just get a random colorway
|
||||
const randomColorway = Array.from(availableColorways)[Math.floor(Math.random() * availableColorways.size)];
|
||||
const randomColorway: TWColorway | undefined =
|
||||
Array.from(availableColorways)[Math.floor(Math.random() * availableColorways.size)];
|
||||
|
||||
if (!randomColorway) {
|
||||
throw new Error('randomColorway is undefined');
|
||||
}
|
||||
|
||||
return getCourseColors(randomColorway, index, offset);
|
||||
}
|
||||
// TODO: get just a random color idk
|
||||
|
||||
@@ -10,9 +10,9 @@ import CancelledIcon from '~icons/material-symbols/warning';
|
||||
/**
|
||||
* Get Icon component based on status
|
||||
* @param props.status status
|
||||
* @returns React.ReactElement - the icon component
|
||||
* @returns the icon component
|
||||
*/
|
||||
export function StatusIcon(props: SVGProps<SVGSVGElement> & { status: StatusType }): React.ReactElement {
|
||||
export function StatusIcon(props: SVGProps<SVGSVGElement> & { status: StatusType }): JSX.Element | null {
|
||||
const { status, ...rest } = props;
|
||||
|
||||
switch (props.status) {
|
||||
@@ -23,5 +23,6 @@ export function StatusIcon(props: SVGProps<SVGSVGElement> & { status: StatusType
|
||||
case Status.CANCELLED:
|
||||
return <CancelledIcon {...rest} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,11 @@ import { hexToRGB } from './colors';
|
||||
|
||||
/**
|
||||
* Flattened colors object.
|
||||
* @type {Record<ThemeColor, string>}
|
||||
*/
|
||||
export const colorsFlattened = Object.entries(colors).reduce(
|
||||
(acc, [prefix, group]) => {
|
||||
export const colorsFlattened: Record<ThemeColor, string> = Object.entries(colors).reduce(
|
||||
(acc: Record<ThemeColor, string>, [prefix, group]) => {
|
||||
for (const [name, hex] of Object.entries(group)) {
|
||||
acc[`${prefix}-${name}`] = hex;
|
||||
acc[`${prefix}-${name}` as ThemeColor] = hex;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
@@ -19,9 +18,8 @@ export const colorsFlattened = Object.entries(colors).reduce(
|
||||
|
||||
/**
|
||||
* Represents the flattened RGB values of the colors.
|
||||
* @type {Record<ThemeColor, ReturnType<typeof hexToRgb>>}
|
||||
*/
|
||||
const colorsFlattenedRgb = Object.fromEntries(
|
||||
const colorsFlattenedRgb: Record<ThemeColor, ReturnType<typeof hexToRGB>> = Object.fromEntries(
|
||||
Object.entries(colorsFlattened).map(([name, hex]) => [name, hexToRGB(hex as HexColor)])
|
||||
) as Record<ThemeColor, ReturnType<typeof hexToRGB>>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user