Skip to content

Commit

Permalink
feat: add more attributes to theme set
Browse files Browse the repository at this point in the history
  • Loading branch information
pearmini committed Oct 8, 2023
1 parent c4c275d commit 6610366
Show file tree
Hide file tree
Showing 26 changed files with 463 additions and 77 deletions.
30 changes: 30 additions & 0 deletions site/.dumi/theme/components/ColorPicker.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.color-picker-overlay {
// 重写颜色选择器样式

// 中间颜色滑轨部分
.flexbox-fix:nth-last-child(3) {
& > :last-child {
display: none;
}
}

// 中间 rgb 手动输入部分
.flexbox-fix:nth-last-child(2) {
input {
width: 100% !important;
color: rgba(0, 0, 0, 0.65);
text-align: center;
}
label {
color: rgba(0, 0, 0, 0.45) !important;
}
}

// 底部推荐色部分
.flexbox-fix:last-child {
& > div {
width: 18px !important;
height: 18px !important;
}
}
}
40 changes: 40 additions & 0 deletions site/.dumi/theme/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import { SketchPicker } from 'react-color';
import { Dropdown } from 'antd';
import { BUILT_COLORS } from './builtins';

export function ColorPicker({ value, onChange, style = {}, className = '' }) {
function onColorChange(newColor) {
const {
rgb: { r, g, b, a },
} = newColor;
const alpha =
value === undefined || value.toLowerCase() === 'transparent' ? 1 : a;
onChange(`rgba(${r}, ${g}, ${b}, ${alpha})`);
}

return (
<Dropdown
overlay={
<SketchPicker
color={value}
className="config-color-picker-overlay"
onChangeComplete={onColorChange}
presetColors={BUILT_COLORS}
/>
}
trigger={['click', 'hover']}
>
<span
className={className}
style={{
background: value,
display: 'inline-block',
height: '100%',
cursor: 'pointer',
...style,
}}
></span>
</Dropdown>
);
}
13 changes: 13 additions & 0 deletions site/.dumi/theme/components/ConfigPanel.less
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,16 @@
margin-right: 8px;
}
}

.config-palette {
padding: 0px 0px !important;
width: 100%;
border-radius: 5px !important;
overflow: hidden;

& > span {
display: grid;
grid-template-columns: repeat(10, 10%);
height: 100%;
}
}
171 changes: 142 additions & 29 deletions site/.dumi/theme/components/ConfigPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
import * as React from 'react';
import { Button, Collapse, Radio } from 'antd';
import { Button, Collapse, Radio, Space, Divider, InputNumber } from 'antd';
import { UploadOutlined, CopyOutlined } from '@ant-design/icons';
import { stdlib } from '@antv/g2';
import { copyToClipboard } from '../utils/copyToBoard';
import { exportDataToLocal } from '../utils/exportDataToLocal';
import { ColorPicker } from './ColorPicker';
import {
BUILT_CATEGORIES,
BUILT_THEMES,
BUILT_COLOR_ATTRIBUTES,
BUILT_PADDING_ATTRIBUTES,
} from './builtins';
import './ConfigPanel.less';

const BUILT_THEMES = [
{ label: '默认风格', key: 'light' },
{ label: '暗色风格', key: 'dark' },
{ label: '学术风格', key: 'academy' },
];

function getG2Theme(theme: string | Record<string, any>) {
if (typeof theme === 'object') return theme;

const library = stdlib();
const themeToken = library[`theme.${theme}`]();
return themeToken;
}

const Operations = ({ theme }) => {
const Operations = ({ tokens }) => {
return (
<div className="config-panel-operations">
<div className="config-panel-title">Theme</div>
Expand All @@ -30,18 +22,15 @@ const Operations = ({ theme }) => {
type="primary"
className="config-panel-button"
onClick={() =>
exportDataToLocal(
JSON.stringify(getG2Theme(theme)),
'g2-theme.json',
)
exportDataToLocal(JSON.stringify(tokens), 'g2-theme.json')
}
>
导出
</Button>
<Button
icon={<CopyOutlined />}
className="config-panel-button"
onClick={() => copyToClipboard(JSON.stringify(getG2Theme(theme)))}
onClick={() => copyToClipboard(JSON.stringify(tokens))}
>
复制
</Button>
Expand All @@ -51,24 +40,148 @@ const Operations = ({ theme }) => {
};

export const ConfigPanel = (props) => {
const { theme, changeTheme, className = '' } = props;
const {
theme,
changeTheme,
tokens,
changeTokens,
changeSeed,
seed,
className = '',
} = props;
const { category10 } = tokens;
const encodePalette = (d) => d.join('-');
const decodePalette = (d) => d.split('-');

function onThemeChange(e) {
changeTheme(e.target.value);
}

function onPaletteChange(e) {
const { value } = e.target;
const palette = decodePalette(value);
const [defaultColor] = palette;
const { category20 } = tokens;
changeTokens({
category10: palette,
category20: [...palette, ...category20.slice(10)],
color: defaultColor,
});
}

function onColorChange(d, i) {
const { category10 } = tokens;
const newCategory10 = [...category10];
newCategory10.splice(i, 1, d);
onPaletteChange({ target: { value: newCategory10.join('-') } });
}

return (
<div className={`config-panel ${className}`}>
<Operations theme={theme} />
<Operations tokens={tokens} />
<Collapse collapsible="header" defaultActiveKey={['1']}>
<Collapse.Panel header="内置风格" key="1">
<Radio.Group
onChange={(e) => changeTheme(e.target.value)}
value={theme}
>
<Collapse.Panel header="风格" key="1">
<Radio.Group onChange={onThemeChange} value={theme}>
{BUILT_THEMES.map((d) => (
<Radio.Button value={d.key} key={d.key}>
{d.label}
</Radio.Button>
))}
</Radio.Group>
</Collapse.Panel>
<Collapse.Panel header="色板" key="2">
<Radio.Group
onChange={onPaletteChange}
value={encodePalette(category10)}
style={{ width: '100%' }}
>
<Space direction="vertical" style={{ width: '100%' }}>
{BUILT_CATEGORIES.map((category10) => (
<Radio.Button
value={encodePalette(category10)}
key={encodePalette(category10)}
className="config-palette"
>
{category10.map((d) => (
<span
style={{
background: d,
display: 'inline-block',
height: '100%',
}}
></span>
))}
</Radio.Button>
))}
</Space>
<Divider style={{ fontSize: 14, fontWeight: 'normal' }}>
自定义
</Divider>
<div
className="config-palette"
style={{
height: 32,
display: 'grid',
gridTemplateColumns: 'repeat(10, 10%)',
border: '1px solid #d9d9d9',
borderColor: BUILT_CATEGORIES.find(
(d) => encodePalette(d) === encodePalette(category10),
)
? '#d9d9d9'
: '#873bf4',
}}
>
{category10.map((d, i) => (
<ColorPicker value={d} onChange={(d) => onColorChange(d, i)} />
))}
</div>
</Radio.Group>
</Collapse.Panel>
<Collapse.Panel header="颜色" key="3">
<Space direction="vertical" style={{ width: '100%' }}>
{BUILT_COLOR_ATTRIBUTES.map((d) => (
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<span>{d.name}</span>
<ColorPicker
value={seed[d.value]}
onChange={(color) => changeSeed(d.value, color)}
style={{
display: 'block',
height: 32,
width: 32,
borderRadius: 5,
border: '1px solid #d9d9d9',
}}
/>
</div>
))}
</Space>
</Collapse.Panel>
<Collapse.Panel header="间距" key="4">
<Space direction="vertical" style={{ width: '100%' }}>
{BUILT_PADDING_ATTRIBUTES.map((d) => (
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<span>{d.name}</span>
<InputNumber
onChange={(value) => changeSeed(d.value, value)}
value={seed[d.value]}
/>
</div>
))}
</Space>
</Collapse.Panel>
</Collapse>
</div>
);
Expand Down
8 changes: 5 additions & 3 deletions site/.dumi/theme/components/DemosView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Chart } from '@antv/g2';
import { examples } from '../examples';
import './DemosView.less';

const DemoContainer = ({ theme, className = '', render }) => {
const DemoContainer = ({ theme, className = '', render, tokens = {} }) => {
const domRef = React.useRef<HTMLDivElement | null>(null);
const chartRef = React.useRef<Chart | null>(null);

Expand All @@ -15,6 +15,7 @@ const DemoContainer = ({ theme, className = '', render }) => {
theme,
width: container.clientWidth,
height: container.clientHeight,
tokens,
});
}

Expand All @@ -26,7 +27,7 @@ const DemoContainer = ({ theme, className = '', render }) => {
chart.destroy();
init(theme);
}
}, [theme]);
}, [theme, tokens]);

React.useLayoutEffect(() => {
const el = domRef.current;
Expand All @@ -47,7 +48,7 @@ const DemoContainer = ({ theme, className = '', render }) => {
return <div ref={domRef} className={className} />;
};

export const DemosView = ({ theme, className = '' }) => {
export const DemosView = ({ theme, tokens, className = '' }) => {
function openExample(example) {
// @ts-ignore
window.open(`/examples/${example.link}`);
Expand All @@ -66,6 +67,7 @@ export const DemosView = ({ theme, className = '' }) => {
className="demo-container"
theme={theme}
render={example.render}
tokens={tokens}
/>
</div>
</Badge.Ribbon>
Expand Down
Loading

0 comments on commit 6610366

Please sign in to comment.