feat: refactor all components in common

This commit is contained in:
doprz
2024-03-04 14:41:34 -06:00
parent 28f192472b
commit e5443122b4
18 changed files with 281 additions and 288 deletions

View File

@@ -3,6 +3,7 @@ import { getThemeColorHexByName, getThemeColorRgbByName } from '@shared/util/the
import Text from '@views/components/common/Text/Text';
import clsx from 'clsx';
import React from 'react';
import { satisfies } from 'semver';
import type IconComponent from '~icons/material-symbols';
@@ -44,7 +45,7 @@ export function Button({
...style,
color: colorHex,
backgroundColor: `rgb(${colorRgb} / var(--un-bg-opacity)`,
} as React.CSSProperties
} satisfies React.CSSProperties
}
className={clsx(
'btn',

View File

@@ -5,14 +5,14 @@ import React from 'react';
* A type that represents the flags that a course can have.
*/
export type Flag = 'WR' | 'QR' | 'GC' | 'CD' | 'E' | 'II';
export const flagMap: Record<string, Flag> = {
export const flagMap = {
Writing: 'WR',
'Quantitative Reasoning': 'QR',
'Global Cultures': 'GC',
'Cultural Diversity in the United States': 'CD',
Ethics: 'E',
'Independent Inquiry': 'II',
};
} as const satisfies Record<string, Flag>;
interface Props {
label: Flag;

View File

@@ -1,6 +1,6 @@
import type { ThemeColor } from '@shared/util/themeColors';
import { Button } from '@views/components/common/Button/Button';
import React from 'react';
import type { ThemeColor } from 'src/shared/util/themeColors';
import CheckIcon from '~icons/material-symbols/check';
@@ -24,12 +24,12 @@ interface ColorPatchProps {
* is passed from the parent and updates the necessary parent state when this color patch is selected.
* @returns {JSX.Element} - the color patch component
*/
const ColorPatch: React.FC<ColorPatchProps> = ({
export default function ColorPatch({
color,
index,
selectedColor,
handleSetSelectedColorPatch,
}: ColorPatchProps): JSX.Element => {
}: ColorPatchProps): JSX.Element {
const isSelected = selectedColor === index;
const handleClick = () => {
handleSetSelectedColorPatch(isSelected ? -1 : index);
@@ -45,6 +45,4 @@ const ColorPatch: React.FC<ColorPatchProps> = ({
{isSelected && <CheckIcon className='h-[20px] w-[20px]' />}
</Button>
);
};
export default ColorPatch;
}

View File

@@ -1,7 +1,7 @@
import type { ThemeColor } from '@shared/util/themeColors';
import { getThemeColorHexByName } from '@shared/util/themeColors';
import { Button } from '@views/components/common/Button/Button';
import React from 'react';
import type { ThemeColor } from 'src/shared/util/themeColors';
import { getThemeColorHexByName } from 'src/shared/util/themeColors';
import InvertColorsOffIcon from '~icons/material-symbols/invert-colors-off';
@@ -16,228 +16,229 @@ interface Color {
shades: ThemeColor[];
}
const colorPatches: Color[] = [
{
baseColor: 'palette-slateBase',
shades: [
'palette-slate200',
'palette-slate300',
'palette-slate400',
'palette-slateBase',
'palette-slate600',
'palette-slate700',
],
},
{
baseColor: 'palette-grayBase',
shades: [
'palette-gray200',
'palette-gray300',
'palette-gray400',
'palette-grayBase',
'palette-gray600',
'palette-gray700',
],
},
{
baseColor: 'palette-stoneBase',
shades: [
'palette-stone200',
'palette-stone300',
'palette-stone400',
'palette-stoneBase',
'palette-stone600',
'palette-stone700',
],
},
{
baseColor: 'palette-redBase',
shades: [
'palette-red200',
'palette-red300',
'palette-red400',
'palette-redBase',
'palette-red600',
'palette-red700',
],
},
{
baseColor: 'palette-orangeBase',
shades: [
'palette-orange200',
'palette-orange300',
'palette-orange400',
'palette-orangeBase',
'palette-orange600',
'palette-orange700',
],
},
{
baseColor: 'palette-amberBase',
shades: [
'palette-amber200',
'palette-amber300',
'palette-amber400',
'palette-amberBase',
'palette-amber600',
'palette-amber700',
],
},
{
baseColor: 'palette-yellowBase',
shades: [
'palette-yellow200',
'palette-yellow300',
'palette-yellow400',
'palette-yellowBase',
'palette-yellow600',
'palette-yellow700',
],
},
{
baseColor: 'palette-limeBase',
shades: [
'palette-lime200',
'palette-lime300',
'palette-lime400',
'palette-limeBase',
'palette-lime600',
'palette-lime700',
],
},
{
baseColor: 'palette-greenBase',
shades: [
'palette-green200',
'palette-green300',
'palette-green400',
'palette-greenBase',
'palette-green600',
'palette-green700',
],
},
{
baseColor: 'palette-emeraldBase',
shades: [
'palette-emerald200',
'palette-emerald300',
'palette-emerald400',
'palette-emeraldBase',
'palette-emerald600',
'palette-emerald700',
],
},
{
baseColor: 'palette-tealBase',
shades: [
'palette-teal200',
'palette-teal300',
'palette-teal400',
'palette-tealBase',
'palette-teal600',
'palette-teal700',
],
},
{
baseColor: 'palette-cyanBase',
shades: [
'palette-cyan200',
'palette-cyan300',
'palette-cyan400',
'palette-cyanBase',
'palette-cyan600',
'palette-cyan700',
],
},
{
baseColor: 'palette-skyBase',
shades: [
'palette-sky200',
'palette-sky300',
'palette-sky400',
'palette-skyBase',
'palette-sky600',
'palette-sky700',
],
},
{
baseColor: 'palette-blueBase',
shades: [
'palette-blue200',
'palette-blue300',
'palette-blue400',
'palette-blueBase',
'palette-blue600',
'palette-blue700',
],
},
{
baseColor: 'palette-indigoBase',
shades: [
'palette-indigo200',
'palette-indigo300',
'palette-indigo400',
'palette-indigoBase',
'palette-indigo600',
'palette-indigo700',
],
},
{
baseColor: 'palette-violetBase',
shades: [
'palette-violet200',
'palette-violet300',
'palette-violet400',
'palette-violetBase',
'palette-violet600',
'palette-violet700',
],
},
{
baseColor: 'palette-purpleBase',
shades: [
'palette-purple200',
'palette-purple300',
'palette-purple400',
'palette-purpleBase',
'palette-purple600',
'palette-purple700',
],
},
{
baseColor: 'palette-fuschiaBase',
shades: [
'palette-fuschia200',
'palette-fuschia300',
'palette-fuschia400',
'palette-fuschiaBase',
'palette-fuschia600',
'palette-fuschia700',
],
},
{
baseColor: 'palette-pinkBase',
shades: [
'palette-pink200',
'palette-pink300',
'palette-pink400',
'palette-pinkBase',
'palette-pink600',
'palette-pink700',
],
},
{
baseColor: 'palette-roseBase',
shades: [
'palette-rose200',
'palette-rose300',
'palette-rose400',
'palette-roseBase',
'palette-rose600',
'palette-rose700',
],
},
];
// TODO: Replace with UnoCSS theme
// const colorPatches: Color[] = [
// {
// baseColor: 'palette-slateBase',
// shades: [
// 'palette-slate200',
// 'palette-slate300',
// 'palette-slate400',
// 'palette-slateBase',
// 'palette-slate600',
// 'palette-slate700',
// ],
// },
// {
// baseColor: 'palette-grayBase',
// shades: [
// 'palette-gray200',
// 'palette-gray300',
// 'palette-gray400',
// 'palette-grayBase',
// 'palette-gray600',
// 'palette-gray700',
// ],
// },
// {
// baseColor: 'palette-stoneBase',
// shades: [
// 'palette-stone200',
// 'palette-stone300',
// 'palette-stone400',
// 'palette-stoneBase',
// 'palette-stone600',
// 'palette-stone700',
// ],
// },
// {
// baseColor: 'palette-redBase',
// shades: [
// 'palette-red200',
// 'palette-red300',
// 'palette-red400',
// 'palette-redBase',
// 'palette-red600',
// 'palette-red700',
// ],
// },
// {
// baseColor: 'palette-orangeBase',
// shades: [
// 'palette-orange200',
// 'palette-orange300',
// 'palette-orange400',
// 'palette-orangeBase',
// 'palette-orange600',
// 'palette-orange700',
// ],
// },
// {
// baseColor: 'palette-amberBase',
// shades: [
// 'palette-amber200',
// 'palette-amber300',
// 'palette-amber400',
// 'palette-amberBase',
// 'palette-amber600',
// 'palette-amber700',
// ],
// },
// {
// baseColor: 'palette-yellowBase',
// shades: [
// 'palette-yellow200',
// 'palette-yellow300',
// 'palette-yellow400',
// 'palette-yellowBase',
// 'palette-yellow600',
// 'palette-yellow700',
// ],
// },
// {
// baseColor: 'palette-limeBase',
// shades: [
// 'palette-lime200',
// 'palette-lime300',
// 'palette-lime400',
// 'palette-limeBase',
// 'palette-lime600',
// 'palette-lime700',
// ],
// },
// {
// baseColor: 'palette-greenBase',
// shades: [
// 'palette-green200',
// 'palette-green300',
// 'palette-green400',
// 'palette-greenBase',
// 'palette-green600',
// 'palette-green700',
// ],
// },
// {
// baseColor: 'palette-emeraldBase',
// shades: [
// 'palette-emerald200',
// 'palette-emerald300',
// 'palette-emerald400',
// 'palette-emeraldBase',
// 'palette-emerald600',
// 'palette-emerald700',
// ],
// },
// {
// baseColor: 'palette-tealBase',
// shades: [
// 'palette-teal200',
// 'palette-teal300',
// 'palette-teal400',
// 'palette-tealBase',
// 'palette-teal600',
// 'palette-teal700',
// ],
// },
// {
// baseColor: 'palette-cyanBase',
// shades: [
// 'palette-cyan200',
// 'palette-cyan300',
// 'palette-cyan400',
// 'palette-cyanBase',
// 'palette-cyan600',
// 'palette-cyan700',
// ],
// },
// {
// baseColor: 'palette-skyBase',
// shades: [
// 'palette-sky200',
// 'palette-sky300',
// 'palette-sky400',
// 'palette-skyBase',
// 'palette-sky600',
// 'palette-sky700',
// ],
// },
// {
// baseColor: 'palette-blueBase',
// shades: [
// 'palette-blue200',
// 'palette-blue300',
// 'palette-blue400',
// 'palette-blueBase',
// 'palette-blue600',
// 'palette-blue700',
// ],
// },
// {
// baseColor: 'palette-indigoBase',
// shades: [
// 'palette-indigo200',
// 'palette-indigo300',
// 'palette-indigo400',
// 'palette-indigoBase',
// 'palette-indigo600',
// 'palette-indigo700',
// ],
// },
// {
// baseColor: 'palette-violetBase',
// shades: [
// 'palette-violet200',
// 'palette-violet300',
// 'palette-violet400',
// 'palette-violetBase',
// 'palette-violet600',
// 'palette-violet700',
// ],
// },
// {
// baseColor: 'palette-purpleBase',
// shades: [
// 'palette-purple200',
// 'palette-purple300',
// 'palette-purple400',
// 'palette-purpleBase',
// 'palette-purple600',
// 'palette-purple700',
// ],
// },
// {
// baseColor: 'palette-fuschiaBase',
// shades: [
// 'palette-fuschia200',
// 'palette-fuschia300',
// 'palette-fuschia400',
// 'palette-fuschiaBase',
// 'palette-fuschia600',
// 'palette-fuschia700',
// ],
// },
// {
// baseColor: 'palette-pinkBase',
// shades: [
// 'palette-pink200',
// 'palette-pink300',
// 'palette-pink400',
// 'palette-pinkBase',
// 'palette-pink600',
// 'palette-pink700',
// ],
// },
// {
// baseColor: 'palette-roseBase',
// shades: [
// 'palette-rose200',
// 'palette-rose300',
// 'palette-rose400',
// 'palette-roseBase',
// 'palette-rose600',
// 'palette-rose700',
// ],
// },
// ];
const hexCodeToBaseColorPatchIndex = new Map(
colorPatches.map((color: Color, index: number) => [getThemeColorHexByName(color.baseColor), index])
@@ -278,9 +279,9 @@ export interface CourseCellColorPickerProps {
* This component is available when a user hovers over a course cell in their calendar to
* color for the course cell. The user can set any valid hex color they want.
*/
const CourseCellColorPicker: React.FC<CourseCellColorPickerProps> = ({
export default function CourseCellColorPicker({
setSelectedColor: setFinalColor,
}: CourseCellColorPickerProps): JSX.Element => {
}: CourseCellColorPickerProps): JSX.Element {
const [selectedBaseColorPatch, setSelectedBaseColorPatch] = React.useState<number>(-1);
const [selectedShadeColorPatch, setSelectShadeColorPatch] = React.useState<number>(-1);
const [hexCode, setHexCode] = React.useState<string>('');
@@ -387,7 +388,4 @@ const CourseCellColorPicker: React.FC<CourseCellColorPickerProps> = ({
/>
)}
</div>
);
};
export default CourseCellColorPicker;
}

View File

@@ -15,8 +15,6 @@ interface ItemWrapperProps {
* @param {React.ReactNode} props.children - the children to be wrapped in the div
* @returns {JSX.Element} - the div wrapper component
*/
const DivWrapper: React.FC<ItemWrapperProps> = ({ children }: ItemWrapperProps) => (
<div className='h-[26px] w-[26px] flex items-center justify-center p-[2px]'>{children}</div>
);
export default DivWrapper;
export default function DivWrapper({ children }: ItemWrapperProps): JSX.Element {
return <div className='h-[26px] w-[26px] flex items-center justify-center p-[2px]'>{children}</div>;
}

View File

@@ -1,5 +1,5 @@
import { getThemeColorHexByName } from '@shared/util/themeColors';
import React from 'react';
import { getThemeColorHexByName } from 'src/shared/util/themeColors';
import TagIcon from '~icons/material-symbols/tag';
@@ -20,7 +20,7 @@ export interface HexColorEditorProps {
* @param {React.Dispatch<React.SetStateAction<string>>} props.setHexCode - set state fn to control the hex color code from parent
* @returns {JSX.Element} - the hex color editor component
*/
const HexColorEditor: React.FC<HexColorEditorProps> = ({ hexCode, setHexCode }: HexColorEditorProps): JSX.Element => {
export default function HexColorEditor({ hexCode, setHexCode }: HexColorEditorProps): JSX.Element {
const baseColor = React.useMemo(() => getThemeColorHexByName('ut-gray'), []);
const previewColor = hexCode.length === 6 ? `#${hexCode}` : baseColor;
@@ -43,6 +43,4 @@ const HexColorEditor: React.FC<HexColorEditorProps> = ({ hexCode, setHexCode }:
</div>
</div>
);
};
export default HexColorEditor;
}

View File

@@ -1,5 +1,5 @@
import type { ThemeColor } from '@shared/util/themeColors';
import React from 'react';
import type { ThemeColor } from 'src/shared/util/themeColors';
import ColorPatch from './ColorPatch';
import DivWrapper from './DivWrapper';
@@ -22,11 +22,7 @@ interface HuePickerProps {
* @param {React.Dispatch<React.SetStateAction<number>>} props.setSelectedColor - set state fn to control the selected color patch from parent
* @returns {JSX.Element} - the hue picker component
*/
const HuePicker: React.FC<HuePickerProps> = ({
shades,
selectedColor,
setSelectedColor,
}: HuePickerProps): JSX.Element => {
export default function HuePicker({ shades, selectedColor, setSelectedColor }: HuePickerProps): JSX.Element {
const numColumns = 6;
return (
<div className='flex gap-0 flex-content-between'>
@@ -42,6 +38,4 @@ const HuePicker: React.FC<HuePickerProps> = ({
))}
</div>
);
};
export default HuePicker;
}

View File

@@ -1,4 +1,3 @@
import type { Color } from '@views/styles/colors.module.scss';
import clsx from 'clsx';
import React from 'react';
@@ -32,7 +31,7 @@ export type DividerProps = {
* <Divider size="19px" orientation="horizontal" />
* ```
*/
export default function Divider({ className, testId, size, orientation }: DividerProps) {
export default function Divider({ className, testId, size, orientation }: DividerProps): JSX.Element {
const style: React.CSSProperties =
orientation === 'horizontal'
? { width: size, borderBottomWidth: '1px' }

View File

@@ -32,6 +32,7 @@ export default function Dropdown(props: Props) {
const schedules = props.dummySchedules;
if (schedules == null) {
// TODO
// if no dummy values passed in
// useSchedules hook here
}
@@ -40,6 +41,7 @@ export default function Dropdown(props: Props) {
toggle(!expanded);
};
// TODO
// WIP function to swap schedules. Prefer to use the hook when in production
const switchSchedule = (index: number) => {
const scheduleToSwitchTo = schedules[index];
@@ -91,12 +93,8 @@ export default function Dropdown(props: Props) {
leave='transition duration-75 ease-out'
leaveFrom='transform scale-100 opacity-100'
leaveTo='transform scale-95 opacity-0'
beforeEnter={() => {
toggleSwitch();
}}
afterLeave={() => {
toggleSwitch();
}}
beforeEnter={toggleSwitch}
afterLeave={toggleSwitch}
>
<Disclosure.Panel>
<List

View File

@@ -11,7 +11,7 @@ interface Props {
/**
* A wrapper component for the extension elements that adds some basic styling to them
*/
export default function ExtensionRoot(props: React.PropsWithChildren<Props>) {
export default function ExtensionRoot(props: React.PropsWithChildren<Props>): JSX.Element {
return (
<div className={styles.extensionRoot} data-testid={props.testId}>
{props.children}

View File

@@ -9,7 +9,7 @@ import styles from './Icon.module.scss';
import type { MaterialIconCode } from './MaterialIcons';
/**
*
* Props for the Icon component.
*/
export type Props = {
name: MaterialIconCode;
@@ -27,7 +27,7 @@ export type Props = {
* This is a reusable Icon component that uses the Material Icons Round font internally
* You can find the list of icons here: https://fonts.google.com/icons?selected=Material+Icons+Round
*/
export default function Icon(props: Props) {
export default function Icon(props: Props): JSX.Element {
const style = props.style || {};
style.color ??= colors?.[props.color ?? 'charcoal'];

View File

@@ -10,7 +10,7 @@ interface Props {
* A maybe reusable InfoCard component that follows the design system of the extension.
* @returns
*/
export function InfoCard({ titleText, bodyText }: React.PropsWithChildren<Props>): JSX.Element {
export default function InfoCard({ titleText, bodyText }: React.PropsWithChildren<Props>): JSX.Element {
return (
<div
className='w-50 flex flex-col items-start justify-center border rounded p-4'

View File

@@ -16,7 +16,7 @@ type Props = Omit<TextProps, 'span'> & {
/**
* A reusable Text component with props that build on top of the design system for the extension
*/
export default function Link(props: PropsWithChildren<Props>) {
export default function Link(props: PropsWithChildren<Props>): JSX.Element {
let passedProps = {
...props,
};

View File

@@ -1,6 +1,7 @@
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
import type { ReactElement } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { satisfies } from 'semver';
/*
* Ctrl + f dragHandleProps on PopupCourseBlock.tsx for example implementation of drag handle (two lines of code)
@@ -11,7 +12,7 @@ import React, { useCallback, useEffect, useState } from 'react';
* Props for the List component.
*/
export interface ListProps {
draggableElements: any[]; // Will later define draggableElements based on what types
draggableElements: any[]; // TODO: Will later define draggableElements based on what types
// of components are draggable.
itemHeight: number;
listHeight: number;
@@ -82,7 +83,13 @@ const Row: React.FC<RowProps> = React.memo(({ data: { items, gap }, index, style
* @example
* <List draggableElements={elements} />
*/
const List: React.FC<ListProps> = ({ draggableElements, itemHeight, listHeight, listWidth, gap = 12 }: ListProps) => {
export default function List({
draggableElements,
itemHeight,
listHeight,
listWidth,
gap = 12,
}: ListProps): JSX.Element {
const [items, setItems] = useState(() => initial(0, draggableElements));
useEffect(() => {
@@ -105,7 +112,7 @@ const List: React.FC<ListProps> = ({ draggableElements, itemHeight, listHeight,
const newItems = reorder(items, result.source.index, result.destination.index);
setItems(newItems as { id: string; content: React.ReactElement }[]);
setItems(newItems satisfies { id: string; content: React.ReactElement }[]);
},
[items]
);
@@ -170,6 +177,4 @@ const List: React.FC<ListProps> = ({ draggableElements, itemHeight, listHeight,
</DragDropContext>
</div>
);
};
export default List;
}

View File

@@ -15,9 +15,15 @@ interface Props {
/**
* A reusable popup component that can be used to display content on the page
* @returns
*/
export default function Popup({ onClose, children, className, style, testId, overlay }: PropsWithChildren<Props>) {
export default function Popup({
onClose,
children,
className,
style,
testId,
overlay,
}: PropsWithChildren<Props>): JSX.Element {
const containerRef = React.useRef<HTMLDivElement>(null);
const bodyRef = React.useRef<HTMLDivElement>(null);

View File

@@ -18,11 +18,9 @@ export type Props = {
/**
* This is a reusable dropdown component that can be used to toggle the visiblity of information
*/
export default function ScheduleListItem(props: Props) {
const { dragHandleProps, onClick } = props;
export default function ScheduleListItem({ style, active, name, dragHandleProps, onClick }: Props): JSX.Element {
return (
<div style={{ ...props.style }} className='items-center'>
<div style={{ ...style }} className='items-center'>
<li className='w-100% flex cursor-pointer items-center self-stretch justify-left text-ut-burntorange'>
<div className='group flex justify-center'>
<div
@@ -40,12 +38,12 @@ export default function ScheduleListItem(props: Props) {
className={clsx(
'bg-current h-3 w-3 rounded-full transition tansform scale-100 ease-out-expo duration-250',
{
'scale-0! opacity-0 ease-in-out! duration-200!': !props.active,
'scale-0! opacity-0 ease-in-out! duration-200!': !active,
}
)}
/>
</div>
<Text variant='p'>{props.name}</Text>
<Text variant='p'>{name}</Text>
</div>
</div>
</li>

View File

@@ -12,6 +12,6 @@ type Props = {
/**
* A simple spinner component that can be used to indicate loading.
*/
export default function Spinner({ className, testId, style }: Props) {
export default function Spinner({ className, testId, style }: Props): JSX.Element {
return <div data-testid={testId} style={style} className={clsx(styles.spinner, className)} />;
}

View File

@@ -5,7 +5,7 @@ import React from 'react';
import styles from './Text.module.scss';
/**
*
* Props for the Text component.
*/
export type TextProps = {
variant?: Variant;
@@ -21,7 +21,7 @@ type Variant = (typeof variants)[number];
/**
* A reusable Text component with props that build on top of the design system for the extension
*/
export default function Text({ variant, as, className, ...props }: PropsWithChildren<TextProps>) {
export default function Text({ variant, as, className, ...props }: PropsWithChildren<TextProps>): JSX.Element {
const mergedClassName = clsx(styles.text, styles[variant], className);
if (as === 'div') return <div className={mergedClassName} {...props} />;