完成色轮选色的基础功能。
This commit is contained in:
		
							
								
								
									
										46
									
								
								src/page-components/wheels/ColorColumn.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/page-components/wheels/ColorColumn.module.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
@layer pages {
 | 
			
		||||
  @keyframes current_blink {
 | 
			
		||||
    0% {
 | 
			
		||||
      opacity: 0.2;
 | 
			
		||||
    }
 | 
			
		||||
    50% {
 | 
			
		||||
      opacity: 0.5;
 | 
			
		||||
    }
 | 
			
		||||
    100% {
 | 
			
		||||
      opacity: 0.2;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .color_column {
 | 
			
		||||
    clip-path: polygon(38.5% 0px, 50% 100%, 61.25% 0px);
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    transform-origin: center bottom;
 | 
			
		||||
  }
 | 
			
		||||
  .color_block {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    height: 1.5em;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    .bg {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      inset: 0;
 | 
			
		||||
    }
 | 
			
		||||
    .dim_overlay {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      inset: 0;
 | 
			
		||||
      background: rgba(0, 0, 0, 70%);
 | 
			
		||||
      opacity: 0;
 | 
			
		||||
    }
 | 
			
		||||
    .show_overlay {
 | 
			
		||||
      opacity: 0.8;
 | 
			
		||||
      transition: opacity 500ms ease-in-out;
 | 
			
		||||
    }
 | 
			
		||||
    .active {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      inset: 0;
 | 
			
		||||
      background-color: var(--color-white);
 | 
			
		||||
      animation: current_blink 2s linear infinite;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								src/page-components/wheels/ColorColumn.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/page-components/wheels/ColorColumn.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
import cx from 'clsx';
 | 
			
		||||
import { isEqual } from 'lodash-es';
 | 
			
		||||
import { useMemo } from 'react';
 | 
			
		||||
import { useColorFunction } from '../../ColorFunctionContext';
 | 
			
		||||
import { useCopyColor } from '../../hooks/useCopyColor';
 | 
			
		||||
import styles from './ColorColumn.module.css';
 | 
			
		||||
 | 
			
		||||
type ColorBlockProps = {
 | 
			
		||||
  dimmed: boolean;
 | 
			
		||||
  color: string;
 | 
			
		||||
  isRoot?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function ColorBlock({ dimmed, color, isRoot = false }: ColorBlockProps) {
 | 
			
		||||
  const copyColor = useCopyColor();
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={styles.color_block} onClick={() => copyColor(color)}>
 | 
			
		||||
      <div className={styles.bg} style={{ backgroundColor: `#${color}` }} />
 | 
			
		||||
      <div className={cx(styles.dim_overlay, dimmed && styles.show_overlay)} />
 | 
			
		||||
      <div className={cx(isRoot && styles.active)} />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ColorWheelProps = {
 | 
			
		||||
  actived: boolean;
 | 
			
		||||
  rotate: number;
 | 
			
		||||
  rootColor: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function ColorColumn({ actived, rotate, rootColor }: ColorWheelProps) {
 | 
			
		||||
  const { colorFn } = useColorFunction();
 | 
			
		||||
  const colorSeries = useMemo(() => {
 | 
			
		||||
    try {
 | 
			
		||||
      const colors = colorFn?.series(rootColor, 4, 0.16);
 | 
			
		||||
      return (colors ?? Array.from({ length: 9 }, () => rootColor)).reverse();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.error('[Generate Color Series]', e);
 | 
			
		||||
    }
 | 
			
		||||
    return Array.from({ length: 9 }, () => rootColor);
 | 
			
		||||
  }, [rootColor]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={styles.color_column} style={{ transform: `rotate(${rotate}deg)` }}>
 | 
			
		||||
      {colorSeries.map((c, index) => (
 | 
			
		||||
        <ColorBlock
 | 
			
		||||
          key={`${c}-${index}`}
 | 
			
		||||
          dimmed={!actived}
 | 
			
		||||
          color={c}
 | 
			
		||||
          isRoot={isEqual(c, rootColor) && isEqual(rotate, 0)}
 | 
			
		||||
        />
 | 
			
		||||
      ))}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								src/page-components/wheels/ColorWheel.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/page-components/wheels/ColorWheel.module.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
@layer pages {
 | 
			
		||||
  .wheel_view {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    padding: 0 var(--spacing-m);
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    h5 {
 | 
			
		||||
      padding-block: var(--spacing-m);
 | 
			
		||||
      font-size: var(--font-size-m);
 | 
			
		||||
    }
 | 
			
		||||
    .wheel_place {
 | 
			
		||||
      flex: 1;
 | 
			
		||||
      padding: var(--spacing-m) 0;
 | 
			
		||||
    }
 | 
			
		||||
    .wheel_container {
 | 
			
		||||
      position: relative;
 | 
			
		||||
      aspect-ratio: 1 / 1;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								src/page-components/wheels/ColorWheel.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/page-components/wheels/ColorWheel.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
import cx from 'clsx';
 | 
			
		||||
import { includes } from 'lodash-es';
 | 
			
		||||
import { useMemo } from 'react';
 | 
			
		||||
import { useColorFunction } from '../../ColorFunctionContext';
 | 
			
		||||
import { ColorColumn } from './ColorColumn';
 | 
			
		||||
import styles from './ColorWheel.module.css';
 | 
			
		||||
 | 
			
		||||
type ColorWheelProps = {
 | 
			
		||||
  originColor?: string;
 | 
			
		||||
  highlightMode?:
 | 
			
		||||
    | 'complementary'
 | 
			
		||||
    | 'analogous'
 | 
			
		||||
    | 'analogous_with_complementary'
 | 
			
		||||
    | 'triadic'
 | 
			
		||||
    | 'split_complementary'
 | 
			
		||||
    | 'tetradic'
 | 
			
		||||
    | 'flip_tetradic'
 | 
			
		||||
    | 'square';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const wheelRotates = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330];
 | 
			
		||||
const highlightSeries = {
 | 
			
		||||
  complementary: [0, 180],
 | 
			
		||||
  analogous: [0, 30, 330],
 | 
			
		||||
  analogous_with_complementary: [0, 30, 180, 330],
 | 
			
		||||
  triadic: [0, 120, 240],
 | 
			
		||||
  split_complementary: [0, 150, 210],
 | 
			
		||||
  tetradic: [0, 60, 180, 240],
 | 
			
		||||
  flip_tetradic: [0, 120, 180, 300],
 | 
			
		||||
  square: [0, 90, 180, 270],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function ColorWheel({
 | 
			
		||||
  originColor = '000000',
 | 
			
		||||
  highlightMode = 'complementary',
 | 
			
		||||
}: ColorWheelProps) {
 | 
			
		||||
  const { colorFn } = useColorFunction();
 | 
			
		||||
  const wheelColors = useMemo(() => {
 | 
			
		||||
    return wheelRotates.map((rotate) => {
 | 
			
		||||
      try {
 | 
			
		||||
        const color = colorFn?.shift_hue(originColor, rotate);
 | 
			
		||||
        return { color: color ?? '000000', rotate };
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        console.error('[Generate color wheel]', e);
 | 
			
		||||
      }
 | 
			
		||||
      return { color: '000000', rotate };
 | 
			
		||||
    });
 | 
			
		||||
  }, [originColor]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={styles.wheel_view}>
 | 
			
		||||
      <h5>Color Wheel</h5>
 | 
			
		||||
      <div className={cx('center', styles.wheel_place)}>
 | 
			
		||||
        <div className={styles.wheel_container}>
 | 
			
		||||
          {wheelColors.map(({ color, rotate }) => (
 | 
			
		||||
            <ColorColumn
 | 
			
		||||
              key={`${color}-${rotate}`}
 | 
			
		||||
              rootColor={color}
 | 
			
		||||
              rotate={rotate}
 | 
			
		||||
              actived={includes(highlightSeries[highlightMode], rotate)}
 | 
			
		||||
            />
 | 
			
		||||
          ))}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user