From f3eceda5609bf34a944806ea0f57d7a01da33a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Tue, 7 Jan 2025 11:15:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90Lighten=20&=20Darken=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 + .../lighten-darken/darkens.tsx | 59 ++++++++ .../lighten-darken/lightens.tsx | 59 ++++++++ src/pages/LightenDarken.module.css | 55 +++++++ src/pages/LightenDarken.tsx | 135 ++++++++++++++++++ 5 files changed, 310 insertions(+) create mode 100644 src/page-components/lighten-darken/darkens.tsx create mode 100644 src/page-components/lighten-darken/lightens.tsx create mode 100644 src/pages/LightenDarken.module.css create mode 100644 src/pages/LightenDarken.tsx diff --git a/src/App.tsx b/src/App.tsx index db7cfe8..83384b1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,6 +3,7 @@ import { ColorFunctionProvider } from './ColorFunctionContext'; import { Notifications } from './components/Notifications'; import { Harmonies } from './pages/Harmonies'; import { Home } from './pages/Home'; +import { LightenDarken } from './pages/LightenDarken'; import { MainLayout } from './pages/MainLayout'; import { NewScheme } from './pages/NewScheme'; import { SchemeDetail } from './pages/SchemeDetail'; @@ -31,6 +32,7 @@ const routes = createBrowserRouter([ { path: 'wheels', element: }, { path: 'tones', element: }, { path: 'tints-shades', element: }, + { path: 'lighten-darken', element: }, ], }, ]); diff --git a/src/page-components/lighten-darken/darkens.tsx b/src/page-components/lighten-darken/darkens.tsx new file mode 100644 index 0000000..025f3c2 --- /dev/null +++ b/src/page-components/lighten-darken/darkens.tsx @@ -0,0 +1,59 @@ +import { last } from 'lodash-es'; +import { useMemo } from 'react'; +import { useColorFunction } from '../../ColorFunctionContext'; +import { FlexColorStand } from '../../components/FlexColorStand'; + +type DarkensProps = { + color: string; + darkens: number; + mix: 'progressive' | 'linear' | 'average'; + step?: number; + maximum?: number; + copyMode: 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'; +}; + +export function Darkens({ color, darkens, mix, step, maximum, copyMode }: DarkensProps) { + const { colorFn } = useColorFunction(); + const colors = useMemo(() => { + try { + if (!colorFn) { + return Array.from({ length: darkens + 1 }, () => color); + } + const darkenColors = [color]; + switch (mix) { + case 'progressive': + for (let i = 1; i <= darkens; i++) { + const darkenColor = colorFn.darken(last(darkenColors), step); + darkenColors.push(darkenColor); + } + break; + case 'linear': + for (let i = 1; i <= darkens; i++) { + const darkenColor = colorFn.darken(color, step * i); + darkenColors.push(darkenColor); + } + break; + case 'average': { + const interval = maximum / darkens / 100; + for (let i = 1; i <= darkens; i++) { + const darkenColor = colorFn.darken(color, interval * i); + darkenColors.push(darkenColor); + } + break; + } + } + return darkenColors.reverse(); + } catch (e) { + console.error('[Generate Lighten]', e); + } + return Array.from({ length: darkens + 1 }, () => color); + }, [color, darkens, mix, step, maximum]); + + return ( + <> + {colors.map((c, index) => ( + + ))} + + ); +} diff --git a/src/page-components/lighten-darken/lightens.tsx b/src/page-components/lighten-darken/lightens.tsx new file mode 100644 index 0000000..5a0806f --- /dev/null +++ b/src/page-components/lighten-darken/lightens.tsx @@ -0,0 +1,59 @@ +import { last } from 'lodash-es'; +import { useMemo } from 'react'; +import { useColorFunction } from '../../ColorFunctionContext'; +import { FlexColorStand } from '../../components/FlexColorStand'; + +type LightensProps = { + color: string; + lightens: number; + mix: 'progressive' | 'linear' | 'average'; + step?: number; + maximum?: number; + copyMode: 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'; +}; + +export function Lightens({ color, lightens, mix, step, maximum, copyMode }: LightensProps) { + const { colorFn } = useColorFunction(); + const colors = useMemo(() => { + try { + if (!colorFn) { + return Array.from({ length: lightens + 1 }, () => color); + } + const lightenColors = [color]; + switch (mix) { + case 'progressive': + for (let i = 1; i <= lightens; i++) { + const lightenColor = colorFn.lighten(last(lightenColors), step); + lightenColors.push(lightenColor); + } + break; + case 'linear': + for (let i = 1; i <= lightens; i++) { + const lightenColor = colorFn.lighten(color, step * i); + lightenColors.push(lightenColor); + } + break; + case 'average': { + const interval = maximum / lightens / 100; + for (let i = 1; i <= lightens; i++) { + const lightenColor = colorFn.lighten(color, interval * i); + lightenColors.push(lightenColor); + } + break; + } + } + return lightenColors; + } catch (e) { + console.error('[Generate Lighten]', e); + } + return Array.from({ length: lightens + 1 }, () => color); + }, [color, lightens, mix, step, maximum]); + + return ( + <> + {colors.map((c, index) => ( + + ))} + + ); +} diff --git a/src/pages/LightenDarken.module.css b/src/pages/LightenDarken.module.css new file mode 100644 index 0000000..cb73db7 --- /dev/null +++ b/src/pages/LightenDarken.module.css @@ -0,0 +1,55 @@ +@layer pages { + .lighten_workspace { + flex-direction: column; + } + .explore_section { + width: 100%; + flex: 1; + display: flex; + flex-direction: row; + align-items: stretch; + gap: var(--spacing-m); + } + .function_side { + display: flex; + flex-direction: column; + gap: var(--spacing-m); + font-size: var(--font-size-s); + .mode_navigation { + display: flex; + flex-direction: column; + align-items: stretch; + gap: var(--spacing-s); + } + h5 { + padding-block: var(--spacing-m); + font-size: var(--font-size-m); + } + } + .lights_content { + flex: 1; + padding: 0 var(--spacing-m); + display: flex; + flex-direction: column; + gap: var(--spacing-s); + h5 { + padding-block: var(--spacing-m); + font-size: var(--font-size-m); + } + .color_value_mode { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--spacing-s); + font-size: var(--font-size-s); + } + .colors_booth { + display: flex; + flex-direction: row; + justify-content: center; + align-items: stretch; + gap: var(--spacing-xs); + min-height: 12em; + } + } +} diff --git a/src/pages/LightenDarken.tsx b/src/pages/LightenDarken.tsx new file mode 100644 index 0000000..93324b5 --- /dev/null +++ b/src/pages/LightenDarken.tsx @@ -0,0 +1,135 @@ +import cx from 'clsx'; +import { useAtom } from 'jotai'; +import { isEqual } from 'lodash-es'; +import { useState } from 'react'; +import { ColorPicker } from '../components/ColorPicker'; +import { HSegmentedControl } from '../components/HSegmentedControl'; +import { Labeled } from '../components/Labeled'; +import { LabeledPicker } from '../components/LabeledPicker'; +import { ScrollArea } from '../components/ScrollArea'; +import { VSegmentedControl } from '../components/VSegmentedControl'; +import { Darkens } from '../page-components/lighten-darken/darkens'; +import { Lightens } from '../page-components/lighten-darken/lightens'; +import { currentPickedColor } from '../stores/colors'; +import styles from './LightenDarken.module.css'; + +export function LightenDarken() { + const [selectedColor, setSelectedColor] = useAtom(currentPickedColor); + const [lighten, setLighten] = useState(3); + const [darken, setDarken] = useState(3); + const [steps, setSteps] = useState(10); + const [maximum, setMaximum] = useState(90); + const [mixMode, setMixMode] = useState<'progressive' | 'average'>('progressive'); + const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); + + return ( +
+ {' '} +
+

Lighten & Darken

+

By varying the brightness of a specified color, produced a series of colors.

+
+ +
+ +
+
Lighten Series
+
+ +
+
Darken Series
+
+ +
+
+ + +
+
+
+
+
+ ); +}