chore: lint-format-docs-tests-bugfixes (#105)
* docs: add jsdoc * feat: change enums to as const objects * chore(test): add themeColors.test.ts * fix: fix tests and bugs with strings.ts util * fix: path alias imports and tsconfig file bug * fix: remove --max-warnings 0
This commit is contained in:
@@ -1,11 +1,19 @@
|
||||
import { theme } from 'unocss/preset-mini';
|
||||
|
||||
/**
|
||||
* Represents the colors for a course.
|
||||
*/
|
||||
export interface CourseColors {
|
||||
primaryColor: string;
|
||||
secondaryColor: string;
|
||||
}
|
||||
|
||||
// calculates luminance of a hex string
|
||||
/**
|
||||
* Calculates the luminance of a given hexadecimal color.
|
||||
*
|
||||
* @param hex - The hexadecimal color value.
|
||||
* @returns The luminance value between 0 and 1.
|
||||
*/
|
||||
export function getLuminance(hex: string): number {
|
||||
let r = parseInt(hex.substring(1, 3), 16);
|
||||
let g = parseInt(hex.substring(3, 5), 16);
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import React, { SVGProps } from 'react';
|
||||
import type { StatusType } from '@shared/types/Course';
|
||||
import { Status } from '@shared/types/Course';
|
||||
import type { SVGProps } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import ClosedIcon from '~icons/material-symbols/lock';
|
||||
import WaitlistIcon from '~icons/material-symbols/timelapse';
|
||||
import CancelledIcon from '~icons/material-symbols/warning';
|
||||
import { Status } from '../types/Course';
|
||||
|
||||
/**
|
||||
* Get Icon component based on status
|
||||
* @param props.status status
|
||||
* @returns React.ReactElement - the icon component
|
||||
*/
|
||||
export function StatusIcon(props: SVGProps<SVGSVGElement> & { status: Status }): React.ReactElement {
|
||||
export function StatusIcon(props: SVGProps<SVGSVGElement> & { status: StatusType }): React.ReactElement {
|
||||
const { status, ...rest } = props;
|
||||
|
||||
switch (props.status) {
|
||||
|
||||
@@ -18,6 +18,8 @@ export function capitalize(input: string): string {
|
||||
}
|
||||
capitalized += ' ';
|
||||
}
|
||||
capitalized = capitalized.trim(); // Remove extra space
|
||||
|
||||
return capitalized;
|
||||
}
|
||||
|
||||
@@ -31,7 +33,7 @@ export function capitalizeFirstLetter(input: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cuts the
|
||||
* Cuts the input string to the specified length and adds an ellipsis if the string is longer than the specified length.
|
||||
* @param input The string to ellipsify.
|
||||
* @param length The length of the string to return.
|
||||
* @returns The ellipsified string.
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { capitalize } from '../string';
|
||||
import { capitalize, capitalizeFirstLetter, ellipsify } from '../string';
|
||||
|
||||
// TODO: Fix `string.ts` and `string.test.ts` to make the tests pass
|
||||
// `capitalize` is adding an extra space at the end of the word.
|
||||
describe('capitalize', () => {
|
||||
it('should capitalize the first letter of each word', () => {
|
||||
// Debug
|
||||
const word = 'hello world';
|
||||
const capitalized = capitalize(word);
|
||||
console.log(capitalize(word));
|
||||
console.log(capitalized.length);
|
||||
console.log(capitalized.split(''));
|
||||
// const word = 'hello world';
|
||||
// const capitalized = capitalize(word);
|
||||
// console.log(capitalize(word));
|
||||
// console.log(capitalized.length);
|
||||
// console.log(capitalized.split(''));
|
||||
|
||||
// Test case 1: Single word
|
||||
expect(capitalize('hello')).toBe('Hello');
|
||||
@@ -25,15 +25,40 @@ describe('capitalize', () => {
|
||||
// Test case 4: Words with hyphens and spaces
|
||||
expect(capitalize('hello-world test')).toBe('Hello-World Test');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not change the capitalization of the remaining letters', () => {
|
||||
// Test case 1: All lowercase
|
||||
expect(capitalize('hello')).toBe('Hello');
|
||||
describe('capitalizeFirstLetter', () => {
|
||||
it('should return a string with the first letter capitalized', () => {
|
||||
// Test case 1: Single word
|
||||
expect(capitalizeFirstLetter('hello')).toBe('Hello');
|
||||
|
||||
// Test case 2: All uppercase
|
||||
expect(capitalize('WORLD')).toBe('WORLD');
|
||||
// Test case 2: Word with all lowercase letters
|
||||
expect(capitalizeFirstLetter('world')).toBe('World');
|
||||
|
||||
// Test case 3: Mixed case
|
||||
expect(capitalize('HeLLo WoRLd')).toBe('Hello World');
|
||||
// Test case 3: Word with all uppercase letters
|
||||
expect(capitalizeFirstLetter('EXAMPLE')).toBe('Example');
|
||||
|
||||
// Test case 4: Word with mixed case letters
|
||||
expect(capitalizeFirstLetter('tEsT')).toBe('Test');
|
||||
});
|
||||
|
||||
it('should handle empty string input', () => {
|
||||
expect(capitalizeFirstLetter('')).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ellipsify', () => {
|
||||
it('should add ellipsis if the input string exceeds the specified character limit', () => {
|
||||
// Test case 1: Input string is shorter than the character limit
|
||||
expect(ellipsify('Hello', 10)).toBe('Hello');
|
||||
|
||||
// Test case 2: Input string is equal to the character limit
|
||||
expect(ellipsify('Hello World', 11)).toBe('Hello World');
|
||||
|
||||
// Test case 3: Input string is longer than the character limit
|
||||
expect(ellipsify('Hello World', 5)).toBe('Hello...');
|
||||
|
||||
// Test case 4: Input string is empty
|
||||
expect(ellipsify('', 5)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
51
src/shared/util/tests/themeColors.test.ts
Normal file
51
src/shared/util/tests/themeColors.test.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { getThemeColorHexByName, getThemeColorRgbByName, hexToRgb } from '../themeColors';
|
||||
|
||||
describe('hexToRgb', () => {
|
||||
it('should convert hex color to RGB', () => {
|
||||
expect(hexToRgb('#BF5700')).toEqual([191, 87, 0]);
|
||||
expect(hexToRgb('#333F48')).toEqual([51, 63, 72]);
|
||||
expect(hexToRgb('#f8971f')).toEqual([248, 151, 31]);
|
||||
expect(hexToRgb('#ffd600')).toEqual([255, 214, 0]);
|
||||
expect(hexToRgb('#a6cd57')).toEqual([166, 205, 87]);
|
||||
expect(hexToRgb('#579d42')).toEqual([87, 157, 66]);
|
||||
expect(hexToRgb('#00a9b7')).toEqual([0, 169, 183]);
|
||||
expect(hexToRgb('#005f86')).toEqual([0, 95, 134]);
|
||||
expect(hexToRgb('#9cadb7')).toEqual([156, 173, 183]);
|
||||
expect(hexToRgb('#d6d2c4')).toEqual([214, 210, 196]);
|
||||
expect(hexToRgb('#95a5a6')).toEqual([149, 165, 166]);
|
||||
expect(hexToRgb('#B91C1C')).toEqual([185, 28, 28]);
|
||||
expect(hexToRgb('#af2e2d')).toEqual([175, 46, 45]);
|
||||
expect(hexToRgb('#1a2024')).toEqual([26, 32, 36]);
|
||||
expect(hexToRgb('#22c55e')).toEqual([34, 197, 94]);
|
||||
expect(hexToRgb('#a3e635')).toEqual([163, 230, 53]);
|
||||
expect(hexToRgb('#84CC16')).toEqual([132, 204, 22]);
|
||||
expect(hexToRgb('#FDE047')).toEqual([253, 224, 71]);
|
||||
expect(hexToRgb('#FACC15')).toEqual([250, 204, 21]);
|
||||
expect(hexToRgb('#F59E0B')).toEqual([245, 158, 11]);
|
||||
expect(hexToRgb('#FB923C')).toEqual([251, 146, 60]);
|
||||
expect(hexToRgb('#F97316')).toEqual([249, 115, 22]);
|
||||
expect(hexToRgb('#EA580C')).toEqual([234, 88, 12]);
|
||||
expect(hexToRgb('#DC2626')).toEqual([220, 38, 38]);
|
||||
expect(hexToRgb('#B91C1C')).toEqual([185, 28, 28]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getThemeColorHexByName', () => {
|
||||
it('should return the hex color value by name', () => {
|
||||
expect(getThemeColorHexByName('ut-burntorange')).toEqual('#BF5700');
|
||||
expect(getThemeColorHexByName('ut-offwhite')).toEqual('#D6D2C4');
|
||||
expect(getThemeColorHexByName('ut-black')).toEqual('#333F48');
|
||||
// Add more test cases for other theme color names
|
||||
});
|
||||
});
|
||||
|
||||
describe('getThemeColorRgbByName', () => {
|
||||
it('should return the RGB color value by name', () => {
|
||||
expect(getThemeColorRgbByName('ut-burntorange')).toEqual([191, 87, 0]);
|
||||
expect(getThemeColorRgbByName('ut-offwhite')).toEqual([214, 210, 196]);
|
||||
expect(getThemeColorRgbByName('ut-black')).toEqual([51, 63, 72]);
|
||||
// Add more test cases for other theme color names
|
||||
});
|
||||
});
|
||||
@@ -2,24 +2,24 @@ export const colors = {
|
||||
ut: {
|
||||
burntorange: '#BF5700',
|
||||
black: '#333F48',
|
||||
orange: '#f8971f',
|
||||
yellow: '#ffd600',
|
||||
lightgreen: '#a6cd57',
|
||||
green: '#579d42',
|
||||
teal: '#00a9b7',
|
||||
blue: '#005f86',
|
||||
gray: '#9cadb7',
|
||||
offwhite: '#d6d2c4',
|
||||
concrete: '#95a5a6',
|
||||
red: '#B91C1C' // Not sure if this should be here, but it's used for remove course, and add course is ut-green
|
||||
orange: '#F8971F',
|
||||
yellow: '#FFD600',
|
||||
lightgreen: '#A6CD57',
|
||||
green: '#579D42',
|
||||
teal: '#00A9B7',
|
||||
blue: '#005F86',
|
||||
gray: '#9CADB7',
|
||||
offwhite: '#D6D2C4',
|
||||
concrete: '#95A5A6',
|
||||
red: '#B91C1C', // Not sure if this should be here, but it's used for remove course, and add course is ut-green
|
||||
},
|
||||
theme: {
|
||||
red: '#af2e2d',
|
||||
black: '#1a2024',
|
||||
red: '#AF2E2D',
|
||||
black: '#1A2024',
|
||||
},
|
||||
gradeDistribution: {
|
||||
a: '#22c55e',
|
||||
aminus: '#a3e635',
|
||||
a: '#22C55E',
|
||||
aminus: '#A3E635',
|
||||
bplus: '#84CC16',
|
||||
b: '#FDE047',
|
||||
bminus: '#FACC15',
|
||||
@@ -31,7 +31,7 @@ export const colors = {
|
||||
dminus: '#B91C1C',
|
||||
f: '#B91C1C',
|
||||
},
|
||||
} as const;
|
||||
} as const satisfies Record<string, Record<string, string>>;
|
||||
|
||||
type NestedKeys<T> = {
|
||||
[K in keyof T]: T[K] extends Record<string, any> ? `${string & K}-${string & keyof T[K]}` : never;
|
||||
@@ -42,6 +42,10 @@ type NestedKeys<T> = {
|
||||
*/
|
||||
export type ThemeColor = NestedKeys<typeof colors>;
|
||||
|
||||
/**
|
||||
* Flattened colors object.
|
||||
* @type {Record<ThemeColor, string>}
|
||||
*/
|
||||
export const colorsFlattened = Object.entries(colors).reduce(
|
||||
(acc, [prefix, group]) => {
|
||||
for (const [name, hex] of Object.entries(group)) {
|
||||
@@ -52,9 +56,18 @@ export const colorsFlattened = Object.entries(colors).reduce(
|
||||
{} as Record<ThemeColor, string>
|
||||
);
|
||||
|
||||
const hexToRgb = (hex: string) =>
|
||||
/**
|
||||
* Converts a hexadecimal color code to an RGB color array.
|
||||
* @param hex The hexadecimal color code to convert.
|
||||
* @returns An array representing the RGB color values.
|
||||
*/
|
||||
export const hexToRgb = (hex: string) =>
|
||||
hex.match(/[0-9a-f]{2}/gi).map(partialHex => parseInt(partialHex, 16)) as [number, number, number];
|
||||
|
||||
/**
|
||||
* Represents the flattened RGB values of the colors.
|
||||
* @type {Record<ThemeColor, ReturnType<typeof hexToRgb>>}
|
||||
*/
|
||||
const colorsFlattenedRgb = Object.fromEntries(
|
||||
Object.entries(colorsFlattened).map(([name, hex]) => [name, hexToRgb(hex)])
|
||||
) as Record<ThemeColor, ReturnType<typeof hexToRgb>>;
|
||||
|
||||
@@ -5,7 +5,9 @@ export const HOUR = 60 * MINUTE;
|
||||
export const DAY = 24 * HOUR;
|
||||
|
||||
/**
|
||||
*
|
||||
* Pauses the execution for the specified number of milliseconds.
|
||||
* @param milliseconds - The number of milliseconds to sleep.
|
||||
* @returns A promise that resolves after the specified number of milliseconds.
|
||||
*/
|
||||
export const sleep = (milliseconds: number): Promise<void> => new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user