完成WACG对比度检测功能。
This commit is contained in:
parent
6bc0779f26
commit
f775c3b78f
@ -12,6 +12,7 @@ import { SchemeNotFound } from './pages/SchemeNotFound';
|
|||||||
import { Schemes } from './pages/Schemes';
|
import { Schemes } from './pages/Schemes';
|
||||||
import { TintsShades } from './pages/TintsShades';
|
import { TintsShades } from './pages/TintsShades';
|
||||||
import { Tones } from './pages/Tones';
|
import { Tones } from './pages/Tones';
|
||||||
|
import { WACGCheck } from './pages/WACG';
|
||||||
import { Wheels } from './pages/Wheels';
|
import { Wheels } from './pages/Wheels';
|
||||||
|
|
||||||
const routes = createBrowserRouter([
|
const routes = createBrowserRouter([
|
||||||
@ -35,6 +36,7 @@ const routes = createBrowserRouter([
|
|||||||
{ path: 'tints-shades', element: <TintsShades /> },
|
{ path: 'tints-shades', element: <TintsShades /> },
|
||||||
{ path: 'lighten-darken', element: <LightenDarken /> },
|
{ path: 'lighten-darken', element: <LightenDarken /> },
|
||||||
{ path: 'mixer', element: <Mixer /> },
|
{ path: 'mixer', element: <Mixer /> },
|
||||||
|
{ path: 'wacg', element: <WACGCheck /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
13
src/page-components/wacg/Ratio.module.css
Normal file
13
src/page-components/wacg/Ratio.module.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
@layer pages {
|
||||||
|
.ratio_layout {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
padding: var(--spacing-s) var(--spacing-m);
|
||||||
|
.ratio {
|
||||||
|
font-size: calc(var(--font-size) * 5);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
src/page-components/wacg/Ratio.tsx
Normal file
13
src/page-components/wacg/Ratio.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import styles from './Ratio.module.css';
|
||||||
|
|
||||||
|
type ContrastRatioProps = {
|
||||||
|
ratio: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ContrastRatio({ ratio }: ContrastRatioProps) {
|
||||||
|
return (
|
||||||
|
<div className={styles.ratio_layout}>
|
||||||
|
<div className={styles.ratio}>{ratio.toFixed(2)} : 1</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
46
src/page-components/wacg/TextDemo.module.css
Normal file
46
src/page-components/wacg/TextDemo.module.css
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
@layer pages {
|
||||||
|
.demo_block {
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius-xxs);
|
||||||
|
padding: var(--spacing-m) var(--spacing-s);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
gap: var(--spacing-s);
|
||||||
|
.normal_text {
|
||||||
|
font-size: 14pt;
|
||||||
|
}
|
||||||
|
.large_text {
|
||||||
|
font-size: 18pt;
|
||||||
|
}
|
||||||
|
.bold_text {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.wacg_rating {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-s);
|
||||||
|
.rating_unit {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sub_header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
color: var(--color-neutral-focus);
|
||||||
|
}
|
||||||
|
}
|
61
src/page-components/wacg/TextDemo.tsx
Normal file
61
src/page-components/wacg/TextDemo.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import cx from 'clsx';
|
||||||
|
import styles from './TextDemo.module.css';
|
||||||
|
|
||||||
|
type TextDemoProps = {
|
||||||
|
fg: string;
|
||||||
|
bg: string;
|
||||||
|
ratio: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function TextDemo({ fg, bg, ratio }: TextDemoProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<header className={styles.sub_header}>
|
||||||
|
<h5>Normal Text</h5>
|
||||||
|
<p className={styles.description}>14pt normal weight text.</p>
|
||||||
|
</header>
|
||||||
|
<div className={styles.demo_block} style={{ backgroundColor: `#${bg}`, color: `#${fg}` }}>
|
||||||
|
<div className={styles.normal_text}>The quick brown fox jumps over the lazy dog.</div>
|
||||||
|
<div className={styles.normal_text}>白日依山尽,黄河入海流。欲穷千里目,更上一层楼。</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.wacg_rating}>
|
||||||
|
<div className={styles.rating_unit}>
|
||||||
|
<span>WACG AA:</span>
|
||||||
|
<span className={cx('badge', 'uppercase', ratio > 4.5 ? 'success' : 'danger')}>
|
||||||
|
{ratio > 4.5 ? 'pass' : 'failed'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.rating_unit}>
|
||||||
|
<span>WACG AAA:</span>
|
||||||
|
<span className={cx('badge', 'uppercase', ratio > 7 ? 'success' : 'danger')}>
|
||||||
|
{ratio > 7 ? 'pass' : 'failed'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<header className={styles.sub_header}>
|
||||||
|
<h5>Large/Bold Text</h5>
|
||||||
|
<p className={styles.description}>18pt normal weight text and 14pt bold text.</p>
|
||||||
|
</header>
|
||||||
|
<div className={styles.demo_block} style={{ backgroundColor: `#${bg}`, color: `#${fg}` }}>
|
||||||
|
<div className={styles.large_text}>The quick brown fox jumps over the lazy dog.</div>
|
||||||
|
<div className={styles.large_text}>白日依山尽,黄河入海流。欲穷千里目,更上一层楼。</div>
|
||||||
|
<div className={styles.bold_text}>The quick brown fox jumps over the lazy dog.</div>
|
||||||
|
<div className={styles.bold_text}>白日依山尽,黄河入海流。欲穷千里目,更上一层楼。</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.wacg_rating}>
|
||||||
|
<div className={styles.rating_unit}>
|
||||||
|
<span>WACG AA:</span>
|
||||||
|
<span className={cx('badge', 'uppercase', ratio > 3 ? 'success' : 'danger')}>
|
||||||
|
{ratio > 3 ? 'pass' : 'failed'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.rating_unit}>
|
||||||
|
<span>WACG AAA:</span>
|
||||||
|
<span className={cx('badge', 'uppercase', ratio > 4.5 ? 'success' : 'danger')}>
|
||||||
|
{ratio > 4.5 ? 'pass' : 'failed'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
40
src/pages/WACG.module.css
Normal file
40
src/pages/WACG.module.css
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
@layer pages {
|
||||||
|
.wacg_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.wacg_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/pages/WACG.tsx
Normal file
47
src/pages/WACG.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import cx from 'clsx';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { useColorFunction } from '../ColorFunctionContext';
|
||||||
|
import { ColorPicker } from '../components/ColorPicker';
|
||||||
|
import { ScrollArea } from '../components/ScrollArea';
|
||||||
|
import { ContrastRatio } from '../page-components/wacg/Ratio';
|
||||||
|
import { TextDemo } from '../page-components/wacg/TextDemo';
|
||||||
|
import styles from './WACG.module.css';
|
||||||
|
|
||||||
|
export function WACGCheck() {
|
||||||
|
const { colorFn } = useColorFunction();
|
||||||
|
const [fgColor, setFgColor] = useState('ffffff');
|
||||||
|
const [bgColor, setBgColor] = useState('000000');
|
||||||
|
const contrastRatio = useMemo(() => {
|
||||||
|
try {
|
||||||
|
if (!colorFn) return 1;
|
||||||
|
const ratio = colorFn.wacg_relative_contrast(fgColor, bgColor);
|
||||||
|
return ratio;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[WACG Check]', e);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}, [fgColor, bgColor]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cx('workspace', styles.wacg_workspace)}>
|
||||||
|
<header>
|
||||||
|
<h3>WACG Check</h3>
|
||||||
|
</header>
|
||||||
|
<ScrollArea enableY>
|
||||||
|
<section className={styles.explore_section}>
|
||||||
|
<aside className={styles.function_side}>
|
||||||
|
<h5>Foreground Color</h5>
|
||||||
|
<ColorPicker color={fgColor} onSelect={setFgColor} />
|
||||||
|
<h5>Background Color</h5>
|
||||||
|
<ColorPicker color={bgColor} onSelect={setBgColor} />
|
||||||
|
</aside>
|
||||||
|
<div className={styles.wacg_content}>
|
||||||
|
<h5>WACG Contrast Ratio</h5>
|
||||||
|
<ContrastRatio ratio={contrastRatio} />
|
||||||
|
<TextDemo fg={fgColor} bg={bgColor} ratio={contrastRatio} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user