From e3b3151bba507c9c17faf18bb1f19461d06a38a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Mon, 6 Jan 2025 15:30:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=89=B2=E8=B0=83=E8=B0=83?= =?UTF-8?q?=E8=89=B2=E5=8A=9F=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 + src/page-components/tones/ToneSeries.tsx | 62 +++++++++++++++ src/pages/Tones.module.css | 55 +++++++++++++ src/pages/Tones.tsx | 98 ++++++++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 src/page-components/tones/ToneSeries.tsx create mode 100644 src/pages/Tones.module.css create mode 100644 src/pages/Tones.tsx diff --git a/src/App.tsx b/src/App.tsx index 2d6d8bf..2eb9908 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import { NewScheme } from './pages/NewScheme'; import { SchemeDetail } from './pages/SchemeDetail'; import { SchemeNotFound } from './pages/SchemeNotFound'; import { Schemes } from './pages/Schemes'; +import { Tones } from './pages/Tones'; import { Wheels } from './pages/Wheels'; const routes = createBrowserRouter([ @@ -27,6 +28,7 @@ const routes = createBrowserRouter([ }, { path: 'harmonies', element: }, { path: 'wheels', element: }, + { path: 'tones', element: }, ], }, ]); diff --git a/src/page-components/tones/ToneSeries.tsx b/src/page-components/tones/ToneSeries.tsx new file mode 100644 index 0000000..8d6624d --- /dev/null +++ b/src/page-components/tones/ToneSeries.tsx @@ -0,0 +1,62 @@ +import { useMemo } from 'react'; +import { useColorFunction } from '../../ColorFunctionContext'; +import { FlexColorStand } from '../../components/FlexColorStand'; + +type ToneSeresProps = { + color?: string; + expand?: number; + step?: number; + valueMode?: 'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'; +}; + +export function LightenSeries({ + color = '000000', + expand = 3, + step = 10, + valueMode = 'hex', +}: ToneSeresProps) { + const { colorFn } = useColorFunction(); + const colors = useMemo(() => { + try { + const lightenColors = colorFn!.tonal_lighten_series(color, expand, step / 100); + return lightenColors; + } catch (e) { + console.error('[Expand lighten colors]', e); + } + return Array.from({ length: expand }, () => color); + }, [color, expand, step]); + + return ( + <> + {colors.map((c, index) => ( + + ))} + + ); +} + +export function DarkenSeries({ + color = '000000', + expand = 3, + step = 10, + valueMode = 'hex', +}: ToneSeresProps) { + const { colorFn } = useColorFunction(); + const colors = useMemo(() => { + try { + const darkenColors = colorFn!.tonal_darken_series(color, expand, step / 100); + return darkenColors; + } catch (e) { + console.error('[Expand darken colors]', e); + } + return Array.from({ length: expand }, () => color); + }, [color, expand, step]); + + return ( + <> + {colors.map((c, index) => ( + + ))} + + ); +} diff --git a/src/pages/Tones.module.css b/src/pages/Tones.module.css new file mode 100644 index 0000000..510fb1a --- /dev/null +++ b/src/pages/Tones.module.css @@ -0,0 +1,55 @@ +@layer pages { + .tone_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); + } + } + .tones_content { + flex: 1; + padding: 0 var(--spacing-m); + display: flex; + flex-direction: column; + gap: var(--spacing-xs); + 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: 15em; + } + } +} diff --git a/src/pages/Tones.tsx b/src/pages/Tones.tsx new file mode 100644 index 0000000..1b28dd8 --- /dev/null +++ b/src/pages/Tones.tsx @@ -0,0 +1,98 @@ +import cx from 'clsx'; +import { useAtom } from 'jotai'; +import { toInteger } from 'lodash-es'; +import { useState } from 'react'; +import { ColorPicker } from '../components/ColorPicker'; +import { FlexColorStand } from '../components/FlexColorStand'; +import { HSegmentedControl } from '../components/HSegmentedControl'; +import { LabeledPicker } from '../components/LabeledPicker'; +import { DarkenSeries, LightenSeries } from '../page-components/tones/ToneSeries'; +import { currentPickedColor } from '../stores/colors'; +import styles from './Tones.module.css'; + +export function Tones() { + const [selectedColor, setSelectedColor] = useAtom(currentPickedColor); + const [steps, setSteps] = useState(10); + const [tones, setTones] = useState(3); + const [seedBias, setSeedBias] = useState(0); + const [mode, setMode] = useState<'hex' | 'rgb' | 'hsl' | 'lab' | 'oklch'>('hex'); + + return ( +
+
+

Color Tones

+

By regularly changing the color hue to generate a series of light and dark colors.

+
+
+ +
+
Color Tones
+
+ + +
+
+ + + +
+
+
+
+ ); +}