增加颜色对比功能。
This commit is contained in:
		| @@ -3,6 +3,7 @@ import { ColorFunctionProvider } from './ColorFunctionContext'; | ||||
| import { Notifications } from './components/Notifications'; | ||||
| import { ColorCards } from './pages/Cards'; | ||||
| import { CardsDetail } from './pages/CardsDetail'; | ||||
| import { ColorCompare } from './pages/Compare'; | ||||
| import { Harmonies } from './pages/Harmonies'; | ||||
| import { Home } from './pages/Home'; | ||||
| import { LightenDarken } from './pages/LightenDarken'; | ||||
| @@ -39,6 +40,7 @@ const routes = createBrowserRouter([ | ||||
|       { path: 'lighten-darken', element: <LightenDarken /> }, | ||||
|       { path: 'mixer', element: <Mixer /> }, | ||||
|       { path: 'wacg', element: <WACGCheck /> }, | ||||
|       { path: 'compare', element: <ColorCompare /> }, | ||||
|       { | ||||
|         path: 'cards', | ||||
|         element: <ColorCards />, | ||||
|   | ||||
							
								
								
									
										25
									
								
								src/page-components/color-compare/CompareLayout.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/page-components/color-compare/CompareLayout.module.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| @layer pages { | ||||
|   .elements { | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|     align-items: stretch; | ||||
|     gap: var(--spacing-m); | ||||
|     .element { | ||||
|       display: flex; | ||||
|       flex-direction: row; | ||||
|       align-items: center; | ||||
|       gap: var(--spacing-xs); | ||||
|       .element_name { | ||||
|         font-size: var(--font-size-xxl); | ||||
|         font-weight: bold; | ||||
|       } | ||||
|       .element_values { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         gap: var(--spacing-xs); | ||||
|         font-size: var(--font-size-xs); | ||||
|         line-height: var(--font-size-xs); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										74
									
								
								src/page-components/color-compare/HCTCompare.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/page-components/color-compare/HCTCompare.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| import { useMemo } from 'react'; | ||||
| import { HctDiffference } from '../../color_functions/color_module'; | ||||
| import { useColorFunction } from '../../ColorFunctionContext'; | ||||
| import styles from './CompareLayout.module.css'; | ||||
| import { CompareMethodProps } from './share-props'; | ||||
|  | ||||
| const defaultCompareResult: HctDiffference = { | ||||
|   hue: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   chroma: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   lightness: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export function HCTCompare({ basic = '000000', compare = '000000' }: CompareMethodProps) { | ||||
|   const { colorFn } = useColorFunction(); | ||||
|   const differ = useMemo(() => { | ||||
|     if (!colorFn) { | ||||
|       return defaultCompareResult; | ||||
|     } | ||||
|     try { | ||||
|       const diff = colorFn.differ_in_hct(basic, compare); | ||||
|       return diff; | ||||
|     } catch (e) { | ||||
|       console.error('[Compare in HCT]', e); | ||||
|     } | ||||
|     return defaultCompareResult; | ||||
|   }, [basic, compare]); | ||||
|  | ||||
|   return ( | ||||
|     <div> | ||||
|       <h6>Compare in HCT Space</h6> | ||||
|       <div className={styles.elements}> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>H</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.hue.delta.toFixed(2)}</span> | ||||
|             <span> | ||||
|               {isNaN(differ.hue.percent) ? '0.00' : (differ.hue.percent * 100).toFixed(2)}% | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>C</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.chroma.delta.toFixed(2)}</span> | ||||
|             <span> | ||||
|               {isNaN(differ.chroma.percent) ? '0.00' : (differ.chroma.percent * 100).toFixed(2)}% | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>T</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.lightness.delta.toFixed(2)}</span> | ||||
|             <span> | ||||
|               {isNaN(differ.lightness.percent) | ||||
|                 ? '0.00' | ||||
|                 : (differ.lightness.percent * 100).toFixed(2)} | ||||
|               % | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										77
									
								
								src/page-components/color-compare/HSLCompare.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/page-components/color-compare/HSLCompare.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| import { useMemo } from 'react'; | ||||
| import { HSLDifference } from '../../color_functions/color_module'; | ||||
| import { useColorFunction } from '../../ColorFunctionContext'; | ||||
| import styles from './CompareLayout.module.css'; | ||||
| import { CompareMethodProps } from './share-props'; | ||||
|  | ||||
| const defaultCompareResult: HSLDifference = { | ||||
|   hue: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   saturation: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   lightness: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export function HSLCompare({ basic = '000000', compare = '000000' }: CompareMethodProps) { | ||||
|   const { colorFn } = useColorFunction(); | ||||
|   const differ = useMemo(() => { | ||||
|     if (!colorFn) { | ||||
|       return defaultCompareResult; | ||||
|     } | ||||
|     try { | ||||
|       const diff = colorFn.differ_in_hsl(basic, compare); | ||||
|       return diff; | ||||
|     } catch (e) { | ||||
|       console.error('[Compare in HSL]', e); | ||||
|     } | ||||
|     return defaultCompareResult; | ||||
|   }, [basic, compare]); | ||||
|  | ||||
|   return ( | ||||
|     <div> | ||||
|       <h6>Compare in HSL Space</h6> | ||||
|       <div className={styles.elements}> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>H</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.hue.delta.toFixed(2)}</span> | ||||
|             <span> | ||||
|               {isNaN(differ.hue.percent) ? '0.00' : (differ.hue.percent * 100).toFixed(2)}% | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>S</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{(differ.saturation.delta * 100).toFixed(2)}%</span> | ||||
|             <span> | ||||
|               {isNaN(differ.saturation.percent) | ||||
|                 ? '0.00' | ||||
|                 : (differ.saturation.percent * 100).toFixed(2)} | ||||
|               % | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>L</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{(differ.lightness.delta * 100).toFixed(2)}%</span> | ||||
|             <span> | ||||
|               {isNaN(differ.lightness.percent) | ||||
|                 ? '0.00' | ||||
|                 : (differ.lightness.percent * 100).toFixed(2)} | ||||
|               % | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										74
									
								
								src/page-components/color-compare/OKLCHCompare.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/page-components/color-compare/OKLCHCompare.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| import { useMemo } from 'react'; | ||||
| import { OklchDifference } from '../../color_functions/color_module'; | ||||
| import { useColorFunction } from '../../ColorFunctionContext'; | ||||
| import styles from './CompareLayout.module.css'; | ||||
| import { CompareMethodProps } from './share-props'; | ||||
|  | ||||
| const defaultCompareResult: OklchDifference = { | ||||
|   hue: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   chroma: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   lightness: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export function OklchCompare({ basic = '000000', compare = '000000' }: CompareMethodProps) { | ||||
|   const { colorFn } = useColorFunction(); | ||||
|   const differ = useMemo(() => { | ||||
|     if (!colorFn) { | ||||
|       return defaultCompareResult; | ||||
|     } | ||||
|     try { | ||||
|       const diff = colorFn.differ_in_oklch(basic, compare); | ||||
|       return diff; | ||||
|     } catch (e) { | ||||
|       console.error('[Compare in Oklch]', e); | ||||
|     } | ||||
|     return defaultCompareResult; | ||||
|   }, [basic, compare]); | ||||
|  | ||||
|   return ( | ||||
|     <div> | ||||
|       <h6>Compare in Oklch Space</h6> | ||||
|       <div className={styles.elements}> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>L</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{(differ.lightness.delta * 100).toFixed(2)}%</span> | ||||
|             <span> | ||||
|               {isNaN(differ.lightness.percent) | ||||
|                 ? '0.0000' | ||||
|                 : (differ.lightness.percent * 100).toFixed(2)} | ||||
|               % | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>C</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.chroma.delta.toFixed(4)}</span> | ||||
|             <span> | ||||
|               {isNaN(differ.chroma.percent) ? '0.0000' : (differ.chroma.percent * 100).toFixed(2)}% | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>H</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.hue.delta.toFixed(2)}</span> | ||||
|             <span> | ||||
|               {isNaN(differ.hue.percent) ? '0.00' : (differ.hue.percent * 100).toFixed(2)}% | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										78
									
								
								src/page-components/color-compare/RGBCompare.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/page-components/color-compare/RGBCompare.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| import { useMemo } from 'react'; | ||||
| import { RGBDifference } from '../../color_functions/color_module'; | ||||
| import { useColorFunction } from '../../ColorFunctionContext'; | ||||
| import styles from './CompareLayout.module.css'; | ||||
| import { CompareMethodProps } from './share-props'; | ||||
|  | ||||
| const defaultCompareResult: RGBDifference = { | ||||
|   r: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   g: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
|   b: { | ||||
|     delta: 0, | ||||
|     percent: 0, | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export function RGBCompare({ basic = '000000', compare = '000000' }: CompareMethodProps) { | ||||
|   const { colorFn } = useColorFunction(); | ||||
|   const differ = useMemo(() => { | ||||
|     if (!colorFn) { | ||||
|       return defaultCompareResult; | ||||
|     } | ||||
|     try { | ||||
|       const diff = colorFn?.differ_in_rgb(basic, compare); | ||||
|       return { | ||||
|         r: { | ||||
|           delta: Math.round(diff.r.delta * 255), | ||||
|           percent: diff.r.percent, | ||||
|         }, | ||||
|         g: { | ||||
|           delta: Math.round(diff.g.delta * 255), | ||||
|           percent: diff.g.percent, | ||||
|         }, | ||||
|         b: { | ||||
|           delta: Math.round(diff.b.delta * 255), | ||||
|           percent: diff.b.percent, | ||||
|         }, | ||||
|       } as RGBDifference; | ||||
|     } catch (e) { | ||||
|       console.error('[Compare in RGB]', e); | ||||
|     } | ||||
|     return defaultCompareResult; | ||||
|   }, [basic, compare]); | ||||
|  | ||||
|   return ( | ||||
|     <div> | ||||
|       <h6>Compare in RGB Space</h6> | ||||
|       <div className={styles.elements}> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>R</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.r.delta}</span> | ||||
|             <span>{isNaN(differ.r.percent) ? '0.00' : (differ.r.percent * 100).toFixed(2)}%</span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>G</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.g.delta}</span> | ||||
|             <span>{isNaN(differ.g.percent) ? '0.00' : (differ.g.percent * 100).toFixed(2)}%</span> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className={styles.element}> | ||||
|           <div className={styles.element_name}>B</div> | ||||
|           <div className={styles.element_values}> | ||||
|             <span>{differ.b.delta}</span> | ||||
|             <span>{isNaN(differ.b.percent) ? '0.00' : (differ.b.percent * 100).toFixed(2)}%</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										4
									
								
								src/page-components/color-compare/share-props.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/page-components/color-compare/share-props.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| export type CompareMethodProps = { | ||||
|   basic?: string; | ||||
|   compare?: string; | ||||
| }; | ||||
							
								
								
									
										18
									
								
								src/pages/Compare.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/pages/Compare.module.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| @layer pages { | ||||
|   .compare_workspace { | ||||
|     flex-direction: column; | ||||
|   } | ||||
|   .compare_content { | ||||
|     width: 100%; | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|     align-items: flex-start; | ||||
|     gap: var(--spacing-l); | ||||
|     .compare_column { | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       gap: var(--spacing-s); | ||||
|       font-size: var(--font-size-s); | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										44
									
								
								src/pages/Compare.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/pages/Compare.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| import cx from 'clsx'; | ||||
| import { useState } from 'react'; | ||||
| import { ColorPicker } from '../components/ColorPicker'; | ||||
| import { ScrollArea } from '../components/ScrollArea'; | ||||
| import { HCTCompare } from '../page-components/color-compare/HCTCompare'; | ||||
| import { HSLCompare } from '../page-components/color-compare/HSLCompare'; | ||||
| import { OklchCompare } from '../page-components/color-compare/OKLCHCompare'; | ||||
| import { RGBCompare } from '../page-components/color-compare/RGBCompare'; | ||||
| import styles from './Compare.module.css'; | ||||
|  | ||||
| export function ColorCompare() { | ||||
|   const [basicColor, setBasicColor] = useState('000000'); | ||||
|   const [compareColor, setCompareColor] = useState('000000'); | ||||
|  | ||||
|   return ( | ||||
|     <div className={cx('workspace', styles.compare_workspace)}> | ||||
|       <header> | ||||
|         <h3>Color Compare</h3> | ||||
|         <p> | ||||
|           Compare the properties of two colors and find the associated patterns of color change. | ||||
|         </p> | ||||
|       </header> | ||||
|       <ScrollArea enableY> | ||||
|         <div className={styles.compare_content}> | ||||
|           <div className={styles.compare_column}> | ||||
|             <h5>Basic Color</h5> | ||||
|             <ColorPicker color={basicColor} onSelect={setBasicColor} /> | ||||
|           </div> | ||||
|           <div className={styles.compare_column}> | ||||
|             <h5>Compare Color</h5> | ||||
|             <ColorPicker color={compareColor} onSelect={setCompareColor} /> | ||||
|           </div> | ||||
|           <div className={styles.compare_column}> | ||||
|             <h5>Compare Result</h5> | ||||
|             <RGBCompare basic={basicColor} compare={compareColor} /> | ||||
|             <HSLCompare basic={basicColor} compare={compareColor} /> | ||||
|             <HCTCompare basic={basicColor} compare={compareColor} /> | ||||
|             <OklchCompare basic={basicColor} compare={compareColor} /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </ScrollArea> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user