From 0288c1f533857a6766febe8fc77608c4ed37fae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Mon, 30 Dec 2024 13:09:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90=E9=A2=9C?= =?UTF-8?q?=E8=89=B2=E5=B1=95=E7=A4=BA=E7=BB=84=E4=BB=B6=E7=9A=84=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ColorStand.module.css | 60 +++++++++++++ src/components/ColorStand.tsx | 123 +++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/components/ColorStand.module.css create mode 100644 src/components/ColorStand.tsx diff --git a/src/components/ColorStand.module.css b/src/components/ColorStand.module.css new file mode 100644 index 0000000..2294075 --- /dev/null +++ b/src/components/ColorStand.module.css @@ -0,0 +1,60 @@ +@layer components { + .color_stand { + display: flex; + flex-direction: column; + font-size: var(--font-size-xs); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-xxs); + min-width: 200px; + .preview_box { + position: relative; + .head_line { + position: absolute; + width: 100%; + display: flex; + flex-direction: row; + justify-content: flex-start; + gap: var(--spacing-xxs); + padding: var(--spacing-xxs) var(--spacing-xs); + h5 { + display: inline-block; + flex: 1; + font-size: var(--font-size-xs); + line-height: calc(var(--font-size-xs) * 1.2); + filter: drop-shadow(0 0 2px oklch(from var(--color-black) l c h / 30%)); + } + } + .color_box { + aspect-ratio: 3 / 2; + } + } + .color_describe { + display: flex; + flex-direction: column; + gap: var(--spacing-xs); + padding: var(--spacing-xs); + } + } + .color_value { + display: flex; + flex-direction: row; + justify-content: space-between; + gap: var(--spacing-xxs); + font-size: var(--font-size-xs); + line-height: var(--font-size-xs); + padding-inline: var(--spacing-xxs); + h6 { + font-size: var(--font-size-xs); + } + .na_value { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--spacing-xs); + color: var(--color-warn); + } + .value { + font-size: var(--font-size-xs); + } + } +} diff --git a/src/components/ColorStand.tsx b/src/components/ColorStand.tsx new file mode 100644 index 0000000..56c84b2 --- /dev/null +++ b/src/components/ColorStand.tsx @@ -0,0 +1,123 @@ +import { Icon } from '@iconify/react/dist/iconify.js'; +import { isNil } from 'lodash-es'; +import { useCallback, useEffect, useMemo } from 'react'; +import { useCopyToClipboard } from 'react-use'; +import NoColor from '../assets/NoColor.svg'; +import { useColorFunction } from '../ColorFunctionContext'; +import styles from './ColorStand.module.css'; +import { NotificationType, useNotification } from './Notifications'; + +type ColorValueProps = { + title: string; + value: string | null; +}; + +function ColorValue({ title, value }: ColorValueProps) { + const [cpState, copyToClipboard] = useCopyToClipboard(); + const { showToast } = useNotification(); + const handleCopy = useCallback(() => { + if (!isNil(value)) { + copyToClipboard(value); + } + }, [value]); + + useEffect(() => { + if (!isNil(cpState.error)) { + showToast(NotificationType.ERROR, 'Failed to copy to clipboard', 'tabler:alert-circle', 3000); + } else if (!isNil(cpState.value)) { + showToast( + NotificationType.SUCCESS, + `${cpState.value} has been copied to clipboard.`, + 'tabler:circle-check', + 3000, + ); + } + }, [cpState]); + + return ( +
+
{title}
+ {isNil(value) ? ( +
+ + Not Available +
+ ) : ( +
+ {value} +
+ )} +
+ ); +} + +type ColorStandProps = { + title?: string; + color?: string; +}; + +export function ColorStand({ title, color }: ColorStandProps) { + const { colorFn } = useColorFunction(); + const rgb = useMemo(() => { + try { + const rgbValues = colorFn?.represent_rgb(color); + return `rgb(${rgbValues[0]}, ${rgbValues[1]}, ${rgbValues[2]})`; + } catch (e) { + console.error('[Convert RGB]', e); + } + return null; + }, [color]); + const hsl = useMemo(() => { + try { + const hslValues = colorFn?.represent_hsl(color); + return `hsl(${hslValues[0].toFixed(2)}, ${(hslValues[1] * 100).toFixed(2)}%, ${( + hslValues[2] * 100 + ).toFixed(2)}%)`; + } catch (e) { + console.error('[Convert HSL]', e); + } + return null; + }, [color]); + const lab = useMemo(() => { + try { + const labValues = colorFn?.represent_lab(color); + return `lab(${labValues[0].toFixed(2)}, ${labValues[1].toFixed(2)}, ${labValues[2].toFixed( + 2, + )})`; + } catch (e) { + console.error('[Convert LAB]', e); + } + return null; + }, [color]); + const oklch = useMemo(() => { + try { + const oklchValues = colorFn?.represent_oklch(color); + return `oklch(${oklchValues[0].toFixed(2)}, ${oklchValues[1].toFixed( + 2, + )}, ${oklchValues[2].toFixed(2)})`; + } catch (e) { + console.error('[Convert OKLCH]', e); + } + return null; + }, [color]); + + return ( +
+
+
+
{title}
+
+
+ No Color +
+
+
+ + + + + +
+
+ ); +}