revert: color palette for calendar (#118)

This commit is contained in:
Razboy20
2024-03-07 18:09:46 -06:00
parent 346b9ced97
commit 51bbd6590b
6 changed files with 0 additions and 567 deletions

View File

@@ -1,20 +0,0 @@
import type { ThemeColor } from '@shared/util/themeColors';
import type { Meta, StoryObj } from '@storybook/react';
import CourseCellColorPicker from '@views/components/common/CourseCellColorPicker/CourseCellColorPicker';
import React, { useState } from 'react';
const meta = {
title: 'Components/Common/CourseCellColorPicker',
component: CourseCellColorPicker,
} satisfies Meta<typeof CourseCellColorPicker>;
export default meta;
type Story = StoryObj<typeof CourseCellColorPicker>;
export const Default: Story = {
render: () => {
// TODO
const [selectedColor, setSelectedColor] = useState<ThemeColor | null>(null);
return <CourseCellColorPicker setSelectedColor={setSelectedColor} />;
},
};

View File

@@ -1,48 +0,0 @@
import type { ThemeColor } from '@shared/util/themeColors';
import { Button } from '@views/components/common/Button/Button';
import React from 'react';
import CheckIcon from '~icons/material-symbols/check';
/**
* Props for the ColorPatch component
*/
interface ColorPatchProps {
color: ThemeColor;
index: number;
selectedColor: number;
handleSetSelectedColorPatch: (colorPatchIndex: number) => void;
}
/**
*
* @param {ColorPatchProps} props - the props for the component
* @param {ThemeColor} props.color - the color to display
* @param {number} props.index - the index of this color patch in the parent color palette
* @param {number} props.selectedColor - the index of the selected color patch in the parent color palette
* @param {(colorPatchIndex: number) => void} props.handleSetSelectedColorPatch - fn called when a color patch is selected. This function
* is passed from the parent and updates the necessary parent state when this color patch is selected.
* @returns {JSX.Element} - the color patch component
*/
export default function ColorPatch({
color,
index,
selectedColor,
handleSetSelectedColorPatch,
}: ColorPatchProps): JSX.Element {
const isSelected = selectedColor === index;
const handleClick = () => {
handleSetSelectedColorPatch(isSelected ? -1 : index);
};
return (
<Button
style={{ backgroundColor: color }}
className='h-[22px] w-[22px] p-0'
variant='filled'
onClick={handleClick}
color={color}
>
{isSelected && <CheckIcon className='h-[20px] w-[20px]' />}
</Button>
);
}

View File

@@ -1,392 +0,0 @@
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 InvertColorsOffIcon from '~icons/material-symbols/invert-colors-off';
import Divider from '../Divider/Divider';
import ColorPatch from './ColorPatch';
import DivWrapper from './DivWrapper';
import HexColorEditor from './HexColorEditor';
import HuePicker from './HuePicker';
interface Color {
baseColor: ThemeColor;
shades: ThemeColor[];
}
// 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])
);
const hexCodeToShadeColorPatchIndex = new Map(
colorPatches.flatMap((color: Color, index: number) =>
color.shades.map(shade => [getThemeColorHexByName(shade), index])
)
);
/**
* Props for the CourseCellColorPicker component.
*/
export interface CourseCellColorPickerProps {
setSelectedColor: React.Dispatch<React.SetStateAction<string | null>>;
}
/**
* @param {CourseCellColorPickerProps} props - the props for the component
* @param {React.Dispatch<React.SetStateAction<string | null>>} props.setSelectedColor - set state function passed down from the parent component
* that will be called when a color is selected. The user can set any valid hex color they want.
*
* @example
* ```
* const CourseCell = () => {
* const [selectedColor, setSelectedColor] = useState<string | null>(null);
* ...
* return (
* <div style={{ backgroundColor: selectedColor }}>
...
* <CourseCellColorPicker setSelectedColor={setSelectedColor} />
* );
* };
* ```
*
* @returns {JSX.Element} - the color picker component that displays a color palette with a list of color patches.
* 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.
*/
export default function CourseCellColorPicker({
setSelectedColor: setFinalColor,
}: CourseCellColorPickerProps): JSX.Element {
const [selectedBaseColorPatch, setSelectedBaseColorPatch] = React.useState<number>(-1);
const [selectedShadeColorPatch, setSelectShadeColorPatch] = React.useState<number>(-1);
const [hexCode, setHexCode] = React.useState<string>('');
const numColumns = 6;
const numFullRows = 3;
const handleSelectBaseColorPatch = (baseColorPatchIndex: number) => {
const color = baseColorPatchIndex > -1 ? colorPatches[baseColorPatchIndex].baseColor : 'ut-gray';
const newHexCode = baseColorPatchIndex > -1 ? getThemeColorHexByName(color).slice(1) : '';
setHexCode(newHexCode);
setSelectedBaseColorPatch(baseColorPatchIndex);
setSelectShadeColorPatch(3);
};
const handleSelectShadeColorPatch = (shadeColorPatchIndex: number) => {
const color = colorPatches[selectedBaseColorPatch].shades[shadeColorPatchIndex];
const newHexCode = getThemeColorHexByName(color).slice(1);
setHexCode(newHexCode);
setSelectShadeColorPatch(shadeColorPatchIndex);
};
React.useEffect(() => {
const hexCodeWithHash = `#${hexCode}`;
if (hexCodeToBaseColorPatchIndex.has(hexCodeWithHash)) {
setSelectedBaseColorPatch(hexCodeToBaseColorPatchIndex.get(hexCodeWithHash));
}
if (hexCodeToShadeColorPatchIndex.has(hexCodeWithHash)) {
setSelectedBaseColorPatch(hexCodeToShadeColorPatchIndex.get(hexCodeWithHash));
}
if (!hexCodeToBaseColorPatchIndex.has(hexCodeWithHash) && !hexCodeToShadeColorPatchIndex.has(hexCodeWithHash)) {
setSelectedBaseColorPatch(-1);
}
}, [hexCode]);
React.useEffect(() => {
let finalColor: string | null = null;
if (selectedBaseColorPatch === -1 && hexCode.length === 6) {
finalColor = `#${hexCode}`;
} else if (selectedBaseColorPatch > -1 && selectedShadeColorPatch === -1) {
finalColor = getThemeColorHexByName(colorPatches[selectedBaseColorPatch].baseColor);
} else if (selectedBaseColorPatch > -1 && selectedShadeColorPatch > -1) {
finalColor = getThemeColorHexByName(colorPatches[selectedBaseColorPatch].shades[selectedShadeColorPatch]);
} else {
finalColor = null;
}
console.log('finalColor', finalColor);
setFinalColor(finalColor);
}, [hexCode, selectedBaseColorPatch, selectedShadeColorPatch, setFinalColor]);
return (
<div className='inline-flex flex-col border border-1 border-ut-offwhite rounded-1 p-[5px]'>
{Array.from({ length: numFullRows }, (_, rowIndex) => (
<div className='flex gap-0 flex-content-between' key={rowIndex}>
{colorPatches.map((color: Color, index) => {
if (index >= rowIndex * numColumns && index < (rowIndex + 1) * numColumns) {
return (
<DivWrapper key={color.baseColor}>
<ColorPatch
color={color.baseColor}
index={index}
selectedColor={selectedBaseColorPatch}
handleSetSelectedColorPatch={handleSelectBaseColorPatch}
/>
</DivWrapper>
);
}
return null;
})}
</div>
))}
<div className='flex gap-0 flex-content-between'>
<DivWrapper>
<ColorPatch
color={colorPatches[colorPatches.length - 2].baseColor}
index={colorPatches.length - 2}
selectedColor={selectedBaseColorPatch}
handleSetSelectedColorPatch={handleSelectBaseColorPatch}
/>
</DivWrapper>
<DivWrapper>
<ColorPatch
color={colorPatches[colorPatches.length - 1].baseColor}
index={colorPatches.length - 1}
selectedColor={selectedBaseColorPatch}
handleSetSelectedColorPatch={handleSelectBaseColorPatch}
/>
</DivWrapper>
<div className='flex items-center justify-center overflow-hidden p-[2px]'>
<HexColorEditor hexCode={hexCode} setHexCode={setHexCode} />
</div>
<DivWrapper>
{/* TODO (achadaga): Not really sure what this button is actually supposed to do */}
<Button className='h-[22px] w-[22px] p-0' variant='filled' color='ut-black' onClick={() => {}}>
<InvertColorsOffIcon className='h-[14px] w-[14px]' />
</Button>
</DivWrapper>
</div>
<Divider orientation='horizontal' size='100%' className='my-1' />
{selectedBaseColorPatch !== -1 && (
<HuePicker
shades={colorPatches[selectedBaseColorPatch].shades}
selectedColor={selectedShadeColorPatch}
setSelectedColor={handleSelectShadeColorPatch}
/>
)}
</div>
);
}

View File

@@ -1,20 +0,0 @@
import React from 'react';
/**
* Props for the DivWrapper component
*/
interface ItemWrapperProps {
children: React.ReactNode;
}
/**
* Utility component to space all the color patches in the color picker component
*
*
* @param {ItemWrapperProps} props - the props for the component
* @param {React.ReactNode} props.children - the children to be wrapped in the div
* @returns {JSX.Element} - the div wrapper component
*/
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,46 +0,0 @@
import { getThemeColorHexByName } from '@shared/util/themeColors';
import React from 'react';
import TagIcon from '~icons/material-symbols/tag';
/**
* Props for the HexColorEditor component
*/
export interface HexColorEditorProps {
hexCode: string;
setHexCode: React.Dispatch<React.SetStateAction<string>>;
}
/**
* Utility component to allow the user to enter a valid hex color code
*
* @param {HexColorEditorProps} props - the props for the component
* @param {string} props.hexCode - the current hex color code displayed in this component. Note that this code does not
* include the leading '#' character since it is already included in the component. Passed down from the parent component.
* @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
*/
export default function HexColorEditor({ hexCode, setHexCode }: HexColorEditorProps): JSX.Element {
const baseColor = React.useMemo(() => getThemeColorHexByName('ut-gray'), []);
const previewColor = hexCode.length === 6 ? `#${hexCode}` : baseColor;
return (
<div className='h-[22px] w-[74px] flex items-center border-[0.5px] border-ut-gray/50 rounded-1'>
<div
style={{ backgroundColor: previewColor }}
className='h-[22px] w-[21px] flex items-center justify-center rounded-l-1 -m-[0.5px]'
>
<TagIcon className='h-[16px] w-[16px] text-ut-white' />
</div>
<div className='flex flex-1 items-center justify-center p-[5px]'>
<input
type='text'
maxLength={6}
className='box-border w-full border-none bg-transparent font-size-[11px] font-400 font-normal outline-none focus:outline-none'
value={hexCode}
onChange={e => setHexCode(e.target.value)}
/>
</div>
</div>
);
}

View File

@@ -1,41 +0,0 @@
import type { ThemeColor } from '@shared/util/themeColors';
import React from 'react';
import ColorPatch from './ColorPatch';
import DivWrapper from './DivWrapper';
/**
* Props for the HuePicker component
*/
interface HuePickerProps {
shades: ThemeColor[];
selectedColor: number;
setSelectedColor: React.Dispatch<React.SetStateAction<number>>;
}
/**
* Bottom row of the color picker component that displays all the shades of a base color
*
* @param {HuePickerProps} props - the props for the component
* @param {ThemeColor[]} props.shades - the list of shades of the base color
* @param {number} props.selectedColor - the index of the selected color patch in the parent color palette
* @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
*/
export default function HuePicker({ shades, selectedColor, setSelectedColor }: HuePickerProps): JSX.Element {
const numColumns = 6;
return (
<div className='flex gap-0 flex-content-between'>
{Array.from({ length: numColumns }, (_, index) => (
<DivWrapper key={shades[index]}>
<ColorPatch
color={shades[index]}
index={index}
selectedColor={selectedColor}
handleSetSelectedColorPatch={setSelectedColor}
/>
</DivWrapper>
))}
</div>
);
}