From ebeda75c36724c186b8205ae5e00b180a8a44f7b Mon Sep 17 00:00:00 2001 From: afc163 Date: Fri, 17 Mar 2017 20:14:11 +0800 Subject: [PATCH] Add color palette generator tool --- docs/spec/colors.md | 10 ++ package.json | 3 + site/theme/static/colors.less | 12 ++ site/theme/template/ColorPaletteTool.jsx | 193 +++++++++++++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 site/theme/template/ColorPaletteTool.jsx diff --git a/docs/spec/colors.md b/docs/spec/colors.md index 4d083420a7..80c990ba7e 100644 --- a/docs/spec/colors.md +++ b/docs/spec/colors.md @@ -144,6 +144,16 @@ ReactDOM.render(, mountNode); 为了考虑文本在不同颜色背景下的呈现,我们选择了『White #FFFFFF』和『Black #000000』并配以透明度来区分文本的等级层次。详情请查看 [字体颜色]()。 +### 色板生成工具 + +如果上面的色板不能满足你的需求,你可以选择一个主色,Ant Design 的色彩生成算法会为你生成完整的色板。 + +`````__react +import ColorPaletteTool from '../../site/theme/template/ColorPaletteTool'; + +ReactDOM.render(, mountNode); +````` + --- ## 色彩应用 diff --git a/package.json b/package.json index b0269cadf7..233277fbfc 100644 --- a/package.json +++ b/package.json @@ -88,11 +88,13 @@ "babel-preset-es2015": "^6.18.0", "babel-preset-react": "^6.16.0", "babel-preset-stage-0": "^6.16.0", + "bezier-easing": "^2.0.3", "bisheng": "^0.22.0", "bisheng-plugin-antd": "^0.13.0", "bisheng-plugin-description": "^0.1.1", "bisheng-plugin-react": "^0.5.0", "bisheng-plugin-toc": "^0.4.0", + "color-standalone": "^0.11.6", "cross-env": "^3.1.4", "dekko": "^0.2.0", "dora-plugin-upload": "^0.3.1", @@ -121,6 +123,7 @@ "rc-tween-one": "~0.11.0", "react": "^15.0.0", "react-addons-test-utils": "^15.0.0", + "react-color-standalone": "^2.4.2-1", "react-copy-to-clipboard": "^4.0.1", "react-document-title": "^2.0.1", "react-dom": "^15.0.0", diff --git a/site/theme/static/colors.less b/site/theme/static/colors.less index 6975c68e72..f8cc6788ab 100644 --- a/site/theme/static/colors.less +++ b/site/theme/static/colors.less @@ -1,5 +1,17 @@ .color-palette { margin: 45px 0; + &-pick { + text-align: center; + font-size: 20px; + margin-bottom: 8px; + } + &-picker { + margin: 12px 0 24px; + &-value { + font-size: 13px; + font-family: Consolas; + } + } } .main-color { diff --git a/site/theme/template/ColorPaletteTool.jsx b/site/theme/template/ColorPaletteTool.jsx new file mode 100644 index 0000000000..17ee2015eb --- /dev/null +++ b/site/theme/template/ColorPaletteTool.jsx @@ -0,0 +1,193 @@ +import React, { Component } from 'react'; +import Color from 'color-standalone'; +import { ChromePicker } from 'react-color-standalone'; +import BezierEasing from 'bezier-easing/dist/bezier-easing'; +import { message } from 'antd'; +import CopyToClipboard from 'react-copy-to-clipboard'; + +const easing = BezierEasing.apply(null, [0.26, 0.09, 0.37, 0.18]); // 色彩分布曲线 +const warmDark = 0.5; // 暖色深度 +const warmRotate = -26; // 暖色角度 +const coldDark = 0.55; // 冷色深度 +const coldRotate = 10; // 冷色角度 + +class Picker extends React.Component { + constructor(props) { + super(); + this.state = { + displayColorPicker: false, + color: props.color, + }; + } + componentWillReceiveProps(nextProps) { + this.setState({ color: nextProps.color }); + } + handleClick = () => { + this.setState({ displayColorPicker: !this.state.displayColorPicker }); + }; + handleClose = () => { + this.setState({ displayColorPicker: false }); + }; + handleChange = (color) => { + this.setState({ color: color.hex }); + this.props.onChange(color.hex); + }; + render() { + const styles = { + color: { + width: '120px', + height: '24px', + borderRadius: '2px', + background: this.state.color, + }, + swatch: { + padding: '5px', + background: '#fff', + borderRadius: '1px', + boxShadow: '0 0 0 1px rgba(0,0,0,.1)', + display: 'inline-block', + cursor: 'pointer', + }, + popover: { + position: 'absolute', + zIndex: '2', + }, + cover: { + position: 'fixed', + top: '0px', + right: '0px', + bottom: '0px', + left: '0px', + }, + wrapper: { + position: 'inherit', + zIndex: '100', + }, + }; + return ( +
+
+
+
+ {this.state.displayColorPicker ?
+
+
+ +
+
: null} +
+ ); + } +} + +// eslint-disable-next-line +class ColorBlock extends Component { + getTextStyle() { + const { color, dark } = this.props; + return { + background: color, + color: dark ? '#fff' : '', + }; + } + onCopied = () => { + const { color } = this.props; + message.success(`Copied: ${color}`); + } + render() { + const { color, index } = this.props; + return ( + +
+ color-{index} + + {color} + +
+
+ ); + } +} + +// eslint-disable-next-line +export default class ColorPaletteTool extends Component { + state = { + primaryColor: '#1088e9', + }; + handleChangeColor = (e) => { + const value = e.target ? e.target.value : e; + this.setState({ + primaryColor: value, + }); + } + getShadeColor() { + const color = Color(this.state.primaryColor); + let rotate; + let dark; + if (color.red() > color.blue()) { + rotate = warmRotate; + dark = warmDark; + } else { + rotate = coldRotate; + dark = coldDark; + } + return color.darken(dark).rotate(rotate).hexString(); + } + renderColorPatterns() { + const patterns = []; + const [count1, count2] = [4, 5]; + const tColor = Color('#fff'); + const pColor = Color(this.state.primaryColor); + const sColor = Color(this.getShadeColor()); + let index = 1; + const primaryEasing = easing(0.1 * (count1 + 1)); + for (let i = 1; i <= count1; i += 1) { + const colorString = + pColor + .clone() + .mix(tColor, easing(0.1 * i) / primaryEasing) + .hexString(); + patterns.push( + + ); + index += 1; + } + for (let i = count1 + 1; i <= count1 + count2 + 1; i += 1) { + const colorString = + pColor + .clone() + .mix(sColor, 1 - ((easing(i * 0.1) - primaryEasing) / (1 - primaryEasing))) + .hexString(); + patterns.push( + + ); + index += 1; + } + return patterns; + } + render() { + return ( +
+
+ 选择自定义主色 +
+ + + +
+ {this.state.primaryColor} +
+
+
+
+ {this.renderColorPatterns()} +
+
+ ); + } +}