From a77fb3f18b454822222070b01e7aff92752f6667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Fri, 18 Jul 2025 15:45:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(q-2-scheme):=20=E6=B7=BB=E5=8A=A0=E9=A2=9C?= =?UTF-8?q?=E8=89=B2=E6=96=B9=E6=A1=88=E9=A2=84=E8=A7=88=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 Q2SchemePreview 组件用于展示颜色方案的预览效果 将 Map 类型改为 Record 以简化数据结构 --- src/page-components/scheme/Q2Scheme.tsx | 2 + .../scheme/q-2-scheme/Preview.module.css | 58 ++++++ .../scheme/q-2-scheme/Preview.tsx | 169 ++++++++++++++++++ src/q-2-scheme.ts | 4 +- 4 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 src/page-components/scheme/q-2-scheme/Preview.module.css create mode 100644 src/page-components/scheme/q-2-scheme/Preview.tsx diff --git a/src/page-components/scheme/Q2Scheme.tsx b/src/page-components/scheme/Q2Scheme.tsx index f15ac69..fb027d7 100644 --- a/src/page-components/scheme/Q2Scheme.tsx +++ b/src/page-components/scheme/Q2Scheme.tsx @@ -6,6 +6,7 @@ import { Q2SchemeStorage } from '../../q-2-scheme'; import { isNilOrEmpty } from '../../utls'; import { SchemeExport } from './Export'; import { Q2SchemeBuilder } from './q-2-scheme/Builder'; +import Q2SchemePreview from './q-2-scheme/Preview'; const tabOptions = [ { title: 'Overview', id: 'overview' }, @@ -33,6 +34,7 @@ export function Q2Scheme({ scheme }: Q2SchemeProps) { export: isNilOrEmpty(scheme.schemeStorage?.cssVariables), }} /> + {isEqual(activeTab, 'overview') && } {isEqual(activeTab, 'builder') && ( setActiveTab('overview')} /> )} diff --git a/src/page-components/scheme/q-2-scheme/Preview.module.css b/src/page-components/scheme/q-2-scheme/Preview.module.css new file mode 100644 index 0000000..81f9785 --- /dev/null +++ b/src/page-components/scheme/q-2-scheme/Preview.module.css @@ -0,0 +1,58 @@ +@layer pages { + .preview_layout { + padding: var(--spacing-s) var(--spacing-m); + width: 100%; + display: flex; + flex-direction: column; + align-items: stretch; + gap: var(--spacing-m); + } + .preview_block { + width: inherit; + padding: var(--spacing-xl) var(--spacing-m); + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: stretch; + gap: var(--spacing-xs); + h2 { + font-size: var(--font-size-xl); + font-weight: bold; + line-height: 1.7em; + } + } + .preview_unit { + width: inherit; + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: var(--spacing-xs); + } + .preview_indi_block { + width: inherit; + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--spacing-xs); + } + .preview_swatch { + width: inherit; + display: grid; + grid-template-columns: repeat(16, 1fr); + gap: var(--spacing-xs); + .preview_swatch_cell { + height: 1em; + } + } + .preview_cell { + padding: var(--spacing-xs) var(--spacing-s); + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-xxs); + font-size: var(--font-size-s); + line-height: 1.5em; + .wacg { + font-size: var(--font-size-xxs); + line-height: 1em; + } + } +} diff --git a/src/page-components/scheme/q-2-scheme/Preview.tsx b/src/page-components/scheme/q-2-scheme/Preview.tsx new file mode 100644 index 0000000..c9141a8 --- /dev/null +++ b/src/page-components/scheme/q-2-scheme/Preview.tsx @@ -0,0 +1,169 @@ +import { capitalize, keys } from 'lodash-es'; +import { FC, ReactNode, useMemo } from 'react'; +import { useColorFunction } from '../../../ColorFunctionContext'; +import { ScrollArea } from '../../../components/ScrollArea'; +import { SchemeContent } from '../../../models'; +import { Q2Baseline, Q2ColorSet, Q2ColorUnit, Q2SchemeStorage } from '../../../q-2-scheme'; +import styles from './Preview.module.css'; + +interface PreviewCellProps { + bg: string; + fg: string; + children: ReactNode; +} + +const PreviewCell: FC = ({ bg, fg, children }) => { + const { colorFn } = useColorFunction(); + const wacgRatio = useMemo(() => { + try { + if (!colorFn) return null; + return colorFn.wacg_relative_contrast(fg, bg); + } catch (e) { + console.error('[Error on calc WACG Ratio]', e); + } + return null; + }, [bg, fg]); + + return ( +
+ {children} + {wacgRatio && WACG {wacgRatio?.toFixed(2)}} +
+ ); +}; + +interface PreviewLineProps { + name: string; + unit: Q2ColorSet; +} + +const PreviewLine: FC = ({ name, unit }) => { + return ( +
+ + {name} + + + {name} Hover + + + {name} Active + + + {name} Focus + + + {name} Disabled + +
+ ); +}; + +interface PreviewSwatchLineProps { + swatch: Record; +} + +const PreviewSwatchLine: FC = ({ swatch }) => { + const cells = useMemo(() => { + const collection: ReactNode[] = []; + for (const key of keys(swatch)) { + const color = swatch[key]; + collection.push( +
, + ); + } + return collection; + }, [swatch]); + + return
{cells}
; +}; + +interface PreviewSetProps { + name: string; + colorUnit: Q2ColorUnit; +} + +const PreviewSet: FC = ({ name, colorUnit }) => { + return ( + <> + + + + + ); +}; + +interface PreviewBlockProps { + baseline: Q2Baseline; + title: string; +} + +const PreviewBlock: FC = ({ baseline, title }) => { + const customSets = useMemo(() => { + const colors = keys(baseline.custom); + const elements: ReactNode[] = []; + + for (const key of colors) { + const color = baseline.custom[key]; + elements.push(); + } + + return elements; + }, [baseline.custom]); + + return ( +
+

{title}

+ + + + + + + + + + + + +
+ + Shadow + + + Overlay + + + Outline + + + Outline Variant + +
+ {customSets} +
+ ); +}; + +interface PreviewProps { + scheme: SchemeContent; +} + +const Q2SchemePreview: FC = ({ scheme }) => { + return ( + +
+
+ {scheme.schemeStorage.scheme?.light && ( + + )} + {scheme.schemeStorage.scheme?.dark && ( + + )} +
+
+
+ ); +}; + +export default Q2SchemePreview; diff --git a/src/q-2-scheme.ts b/src/q-2-scheme.ts index 98f2379..b204d4f 100644 --- a/src/q-2-scheme.ts +++ b/src/q-2-scheme.ts @@ -13,7 +13,7 @@ export type Q2ColorSet = { export type Q2ColorUnit = { root: Q2ColorSet; surface: Q2ColorSet; - swatch: Map; + swatch: Record; }; export type Q2Baseline = { @@ -33,7 +33,7 @@ export type Q2Baseline = { overlay: string; outline: string; outlineVariant: string; - custom: Map; + custom: Record; }; export type Q2Scheme = {