Merge branch 'master' of github.com:ant-design/ant-design

This commit is contained in:
afc163 2016-10-18 18:20:11 +08:00
commit a223c7bdba
29 changed files with 182 additions and 71 deletions

2
components/alert/index.tsx Normal file → Executable file
View File

@ -18,7 +18,7 @@ export interface AlertProps {
/** Additional content of Alert */ /** Additional content of Alert */
description?: React.ReactNode; description?: React.ReactNode;
/** Callback when close Alert */ /** Callback when close Alert */
onClose?: (event) => void; onClose?: React.MouseEventHandler;
/** Whether to show icon */ /** Whether to show icon */
showIcon?: boolean; showIcon?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;

9
components/auto-complete/index.tsx Normal file → Executable file
View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import Select, { Option, OptGroup } from '../select'; import Select, { OptionProps, OptGroupProps } from '../select';
import { Option, OptGroup } from 'rc-select';
import classNames from 'classnames'; import classNames from 'classnames';
export interface SelectedValue { export interface SelectedValue {
@ -23,13 +24,13 @@ export interface AutoCompleteProps {
defaultValue?: string | Array<any> | SelectedValue | Array<SelectedValue>; defaultValue?: string | Array<any> | SelectedValue | Array<SelectedValue>;
value?: string | Array<any> | SelectedValue | Array<SelectedValue>; value?: string | Array<any> | SelectedValue | Array<SelectedValue>;
allowClear?: boolean; allowClear?: boolean;
onChange?: (value) => void; onChange?: (value: string | Array<any> | SelectedValue | Array<SelectedValue>) => void;
disabled?: boolean; disabled?: boolean;
} }
export default class AutoComplete extends React.Component<AutoCompleteProps, any> { export default class AutoComplete extends React.Component<AutoCompleteProps, any> {
static Option = Option; static Option = Option as React.ClassicComponentClass<OptionProps>;
static OptGroup = OptGroup; static OptGroup = OptGroup as React.ClassicComponentClass<OptGroupProps>;
static defaultProps = { static defaultProps = {
prefixCls: 'ant-select', prefixCls: 'ant-select',

2
components/back-top/index.tsx Normal file → Executable file
View File

@ -25,7 +25,7 @@ const easeInOutCubic = (t, b, c, d) => {
export interface BackTopProps { export interface BackTopProps {
visibilityHeight?: number; visibilityHeight?: number;
onClick?: (event) => void; onClick?: React.MouseEventHandler;
target?: () => HTMLElement | Window; target?: () => HTMLElement | Window;
prefixCls?: string; prefixCls?: string;
className?: string; className?: string;

2
components/breadcrumb/Breadcrumb.tsx Normal file → Executable file
View File

@ -8,7 +8,7 @@ export interface BreadcrumbProps {
routes?: Array<any>; routes?: Array<any>;
params?: Object; params?: Object;
separator?: string | React.ReactNode; separator?: string | React.ReactNode;
itemRender?: (route, params, routes, paths) => React.ReactNode; itemRender?: (route: any, params: any, routes: Array<any>, paths: Array<string>) => React.ReactNode;
style?: React.CSSProperties; style?: React.CSSProperties;
}; };

13
components/date-picker/index.tsx Normal file → Executable file
View File

@ -16,7 +16,7 @@ export interface PickerProps {
popupStyle?: React.CSSProperties; popupStyle?: React.CSSProperties;
locale?: any; locale?: any;
size?: 'large' | 'small' | 'default'; size?: 'large' | 'small' | 'default';
getCalendarContainer?: (trigger) => React.ReactNode; getCalendarContainer?: (trigger: any) => React.ReactNode;
prefixCls?: string; prefixCls?: string;
inputPrefixCls?: string; inputPrefixCls?: string;
} }
@ -37,7 +37,7 @@ const DatePicker = wrapPicker(createPicker(RcCalendar)) as React.ClassicComponen
export interface MonthPickerProps extends PickerProps, SinglePickerProps { export interface MonthPickerProps extends PickerProps, SinglePickerProps {
} }
const MonthPicker = wrapPicker(createPicker(MonthCalendar), 'YYYY-MM') as React.ClassicComponentClass<MonthPickerProps>; const MonthPicker = wrapPicker(createPicker(MonthCalendar), 'YYYY-MM');
export interface RangePickerProps extends PickerProps { export interface RangePickerProps extends PickerProps {
value?: [moment.Moment, moment.Moment]; value?: [moment.Moment, moment.Moment];
@ -48,9 +48,14 @@ export interface RangePickerProps extends PickerProps {
} }
assign(DatePicker, { assign(DatePicker, {
RangePicker: wrapPicker(RangePicker) as React.ClassicComponentClass<RangePickerProps>, RangePicker: wrapPicker(RangePicker),
Calendar, Calendar,
MonthPicker, MonthPicker,
}); });
export default DatePicker; export interface DatePickerDecorator extends React.ClassicComponentClass<DatePickerProps> {
RangePicker: React.ClassicComponentClass<RangePickerProps>;
MonthPicker: React.ClassicComponentClass<MonthPickerProps>;
}
export default DatePicker as DatePickerDecorator;

31
components/form/Form.tsx Normal file → Executable file
View File

@ -42,11 +42,9 @@ export type WrappedFormUtils = {
validateFields(options: Object, callback: (erros: any, values: any) => void): any; validateFields(options: Object, callback: (erros: any, values: any) => void): any;
validateFields(callback: (erros: any, values: any) => void): any; validateFields(callback: (erros: any, values: any) => void): any;
/** 与 `validateFields` 相似,但校验完后,如果校验不通过的菜单域不在可见范围内,则自动滚动进可见范围 */ /** 与 `validateFields` 相似,但校验完后,如果校验不通过的菜单域不在可见范围内,则自动滚动进可见范围 */
validateFieldsAndScroll( validateFieldsAndScroll(fieldNames?: Array<string>,
fieldNames?: Array<string>,
options?: Object, options?: Object,
callback?: (erros: any, values: any) => void callback?: (erros: any, values: any) => void): void;
): void;
/** 获取某个输入控件的 Error */ /** 获取某个输入控件的 Error */
getFieldError(name: string): Object[]; getFieldError(name: string): Object[];
/** 判断一个输入控件是否在校验状态*/ /** 判断一个输入控件是否在校验状态*/
@ -62,7 +60,7 @@ export type WrappedFormUtils = {
/** 收集子节点的值的时机 */ /** 收集子节点的值的时机 */
trigger?: string; trigger?: string;
/** 可以把 onChange 的参数转化为控件的值,例如 DatePicker 可设为:(date, dateString) => dateString */ /** 可以把 onChange 的参数转化为控件的值,例如 DatePicker 可设为:(date, dateString) => dateString */
getValueFromEvent?: (...args) => any; getValueFromEvent?: (...args: any[]) => any;
/** 校验子节点值的时机 */ /** 校验子节点值的时机 */
validateTrigger?: string; validateTrigger?: string;
/** 校验规则,参见 [async-validator](https://github.com/yiminghe/async-validator) */ /** 校验规则,参见 [async-validator](https://github.com/yiminghe/async-validator) */
@ -83,6 +81,8 @@ export interface ComponentDecorator {
<T extends (typeof FormComponent)>(component: T): T; <T extends (typeof FormComponent)>(component: T): T;
} }
let warnedGetFieldProps = false;
export default class Form extends React.Component<FormProps, any> { export default class Form extends React.Component<FormProps, any> {
static defaultProps = { static defaultProps = {
prefixCls: 'ant-form', prefixCls: 'ant-form',
@ -121,16 +121,25 @@ export default class Form extends React.Component<FormProps, any> {
form: this.props.form, form: this.props.form,
}; };
}, },
render() { componentWillMount() {
const getFieldProps = this.props.form.getFieldProps; if (!warnedGetFieldProps) {
function deprecatedGetFieldProps(name, option) { this.getFieldProps = this.props.form.getFieldProps;
}
},
deprecatedGetFieldProps(name, option) {
if (!warnedGetFieldProps) {
warnedGetFieldProps = true;
warning( warning(
false, false,
'`getFieldProps` is deprecated and will be removed in future, please use `getFieldDecorator` instead' '`getFieldProps` is not recommended, please use `getFieldDecorator` instead'
); );
return getFieldProps(name, option);
} }
this.props.form.getFieldProps = deprecatedGetFieldProps; return this.getFieldProps(name, option);
},
render() {
if (!warnedGetFieldProps) {
this.props.form.getFieldProps = this.deprecatedGetFieldProps;
}
const withRef: any = {}; const withRef: any = {};
if (options && options.withRef) { if (options && options.withRef) {

2
components/icon/index.tsx Normal file → Executable file
View File

@ -6,7 +6,7 @@ export interface IconProps {
type: string; type: string;
className?: string; className?: string;
title?: string; title?: string;
onClick?: (e) => void; onClick?: React.MouseEventHandler;
spin?: boolean; spin?: boolean;
} }

4
components/message/index.tsx Normal file → Executable file
View File

@ -55,7 +55,7 @@ function notice(
type ConfigContent = React.ReactNode | string; type ConfigContent = React.ReactNode | string;
type ConfigDuration = number; type ConfigDuration = number;
type ConfigOnClose = () => void; export type ConfigOnClose = () => void;
export interface ConfigOptions { export interface ConfigOptions {
top?: number; top?: number;
@ -64,7 +64,7 @@ export interface ConfigOptions {
} }
export default { export default {
info(content: ConfigContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { info(content: ConfigContent, duration?: ConfigDuration, onClose?: () => ConfigOnClose) {
return notice(content, duration, 'info', onClose); return notice(content, duration, 'info', onClose);
}, },
success(content: ConfigContent, duration?: ConfigDuration, onClose?: ConfigOnClose) { success(content: ConfigContent, duration?: ConfigDuration, onClose?: ConfigOnClose) {

15
components/notification/index.tsx Normal file → Executable file
View File

@ -92,8 +92,19 @@ function notice(args) {
}); });
} }
const api = { const api: {
open(args) { success?(args: ArgsProps): void;
error?(args: ArgsProps): void;
info?(args: ArgsProps): void;
warn?(args: ArgsProps): void;
warning?(args: ArgsProps): void;
open(args: ArgsProps): void;
close(key: string): void;
config(options: ConfigProps): void;
destroy(): void;
} = {
open(args: ArgsProps) {
notice(args); notice(args);
}, },
close(key) { close(key) {

5
components/select/index.tsx Normal file → Executable file
View File

@ -35,7 +35,7 @@ export interface SelectProps {
style?: React.CSSProperties; style?: React.CSSProperties;
dropdownStyle?: React.CSSProperties; dropdownStyle?: React.CSSProperties;
dropdownMenuStyle?: React.CSSProperties; dropdownMenuStyle?: React.CSSProperties;
onChange?: (value) => void; onChange?: (value: SelectValue) => void;
} }
export interface OptionProps { export interface OptionProps {
@ -53,7 +53,8 @@ export interface SelectContext {
}; };
} }
export { Option, OptGroup }; // => It is needless to export the declaration of below two inner components.
// export { Option, OptGroup };
export default class Select extends React.Component<SelectProps, any> { export default class Select extends React.Component<SelectProps, any> {
static Option = Option as React.ClassicComponentClass<OptionProps>; static Option = Option as React.ClassicComponentClass<OptionProps>;

1
components/switch/index.tsx Normal file → Executable file
View File

@ -12,6 +12,7 @@ export interface SwitchProps {
onChange?: (checked: boolean) => any; onChange?: (checked: boolean) => any;
checkedChildren?: React.ReactNode; checkedChildren?: React.ReactNode;
unCheckedChildren?: React.ReactNode; unCheckedChildren?: React.ReactNode;
disabled?: boolean;
} }
export default class Switch extends React.Component<SwitchProps, any> { export default class Switch extends React.Component<SwitchProps, any> {

2
components/table/Table.tsx Normal file → Executable file
View File

@ -750,7 +750,7 @@ export default class Table extends React.Component<TableProps, any> {
const { pagination } = this.state; const { pagination } = this.state;
if (pagination.size) { if (pagination.size) {
size = pagination.size; size = pagination.size;
} else if (this.props.size === 'middle' || this.props.size === 'small') { } else if (this.props.size as string === 'middle' || this.props.size === 'small') {
size = 'small'; size = 'small';
} }
let total = pagination.total || this.getLocalData().length; let total = pagination.total || this.getLocalData().length;

2
components/table/filterDropdown.tsx Normal file → Executable file
View File

@ -6,7 +6,7 @@ import Checkbox from '../checkbox';
import Radio from '../radio'; import Radio from '../radio';
export interface FilterDropdownMenuWrapperProps { export interface FilterDropdownMenuWrapperProps {
onClick?: Function; onClick?: React.MouseEventHandler;
children?: any; children?: any;
className?: string; className?: string;
} }

2
components/tabs/index.tsx Normal file → Executable file
View File

@ -75,7 +75,7 @@ export default class Tabs extends React.Component<TabsProps, any> {
} = this.props; } = this.props;
let className = classNames({ let className = classNames({
[this.props.className]: !!this.props.className, [this.props.className]: !!this.props.className,
[`${prefixCls}-mini`]: size === 'small' || size === 'mini', [`${prefixCls}-mini`]: size === 'small' || size as string === 'mini',
[`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right', [`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right',
[`${prefixCls}-card`]: type.indexOf('card') >= 0, [`${prefixCls}-card`]: type.indexOf('card') >= 0,
[`${prefixCls}-${type}`]: true, [`${prefixCls}-${type}`]: true,

View File

@ -16,7 +16,7 @@
border-radius: @border-radius-base; border-radius: @border-radius-base;
vertical-align: middle; vertical-align: middle;
position: relative; position: relative;
width: 160px; width: 180px;
height: 200px; height: 200px;
padding-top: 33px; padding-top: 33px;

View File

@ -0,0 +1,72 @@
---
order: 9
title:
zh-CN: 上传图片原位显示
en-US: Show uploaded image in-place
---
## zh-CN
上传图片原位显示。
## en-US
Show uploaded image in-place.
```jsx
import { Upload, Icon } from 'antd';
const Demo = React.createClass({
getInitialState() {
return {};
},
handleChange(info) {
if (info.file.status === 'done') {
this.setState({
// Get this url from response in real world.
imageUrl: 'https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg',
});
}
},
render() {
const imageUrl = this.state.imageUrl;
return (
<Upload
className="avatar-uploader"
name="avatar"
showUploadList={false}
action="/upload.do"
onChange={this.handleChange}
>
{
imageUrl ?
<img src={imageUrl} role="presentation" className="avatar" /> :
<Icon type="plus" className="avatar-uploader-trigger" />
}
</Upload>
);
},
});
ReactDOM.render(<Demo />, mountNode);
```
```css
#components-upload-demo-inplace .avatar-uploader,
#components-upload-demo-inplace .avatar-uploader-trigger,
#components-upload-demo-inplace .avatar {
width: 150px;
height: 150px;
}
#components-upload-demo-inplace .avatar-uploader {
display: block;
border: 1px solid #d9d9d9;
border-radius: 6px;
cursor: pointer;
}
#components-upload-demo-inplace .avatar-uploader-trigger {
display: table-cell;
vertical-align: middle;
font-size: 28px;
}
```

View File

@ -247,6 +247,7 @@ export default class Upload extends React.Component<UploadProps, any> {
onProgress: this.onProgress, onProgress: this.onProgress,
onSuccess: this.onSuccess, onSuccess: this.onSuccess,
}); });
delete rcUploadProps.className;
const uploadList = showUploadList ? ( const uploadList = showUploadList ? (
<UploadList <UploadList

2
components/upload/interface.tsx Normal file → Executable file
View File

@ -30,7 +30,7 @@ export interface UploadProps {
defaultFileList?: Array<File>; defaultFileList?: Array<File>;
fileList?: Array<File>; fileList?: Array<File>;
action: string; action: string;
data?: Object | ((File) => any); data?: Object | ((file: File) => any);
headers?: HttpRequestHeader; headers?: HttpRequestHeader;
showUploadList?: boolean; showUploadList?: boolean;
multiple?: boolean; multiple?: boolean;

View File

@ -84,7 +84,7 @@ export default class MainContent extends React.Component {
const disabled = item.disabled; const disabled = item.disabled;
const url = item.filename.replace(/(\/index)?((\.zh-CN)|(\.en-US))?\.md$/i, '').toLowerCase(); const url = item.filename.replace(/(\/index)?((\.zh-CN)|(\.en-US))?\.md$/i, '').toLowerCase();
const child = !item.link ? const child = !item.link ?
<Link to={/^components/.test(url) ? `${url}/` : url} disabled={disabled}> <Link to={{ query: this.props.location.query, pathname: /^components/.test(url) ? `${url}/` : url }} disabled={disabled}>
{text} {text}
</Link> : </Link> :
<a href={item.link} target="_blank" rel="noopener noreferrer" disabled={disabled}> <a href={item.link} target="_blank" rel="noopener noreferrer" disabled={disabled}>

View File

@ -1,13 +1,9 @@
import React from 'react'; import React from 'react';
import Promise from 'bluebird'; import Promise from 'bluebird';
import MainContent from './MainContent'; import MainContent from './MainContent';
import * as utils from '../utils';
// locale copy from layout const locale = utils.isZhCN() ? 'zh-CN' : 'en-US';
const language = (typeof localStorage === 'undefined' || !localStorage.getItem('locale')) ?
navigator.language : localStorage.getItem('locale');
const isZhCN = language === 'zh-CN';
const locale = isZhCN ? 'zh-CN' : 'en-US';
export function collect(nextProps, callback) { export function collect(nextProps, callback) {
const pageData = nextProps.location.pathname === 'changelog' ? const pageData = nextProps.location.pathname === 'changelog' ?
nextProps.data.CHANGELOG : nextProps.pageData; nextProps.data.CHANGELOG : nextProps.pageData;

View File

@ -16,7 +16,8 @@ function typeFunc(a) {
return 'left'; return 'left';
} }
export default function Banner() { export default function Banner({ location }) {
const query = location.query;
return ( return (
<section id="banner"> <section id="banner">
<ScrollElement scrollName="banner" className="page"> <ScrollElement scrollName="banner" className="page">
@ -25,10 +26,10 @@ export default function Banner() {
<p key="content"><FormattedMessage id="app.home.slogan" /></p> <p key="content"><FormattedMessage id="app.home.slogan" /></p>
<span className="line" key="line" /> <span className="line" key="line" />
<div key="button1" className="start-button clearfix"> <div key="button1" className="start-button clearfix">
<Link to="/docs/spec/introduce"> <Link to={{ query, pathname: '/docs/spec/introduce' }}>
<FormattedMessage id="app.home.introduce" /> <FormattedMessage id="app.home.introduce" />
</Link> </Link>
<Link to="/docs/react/introduce"> <Link to={{ query, pathname: '/docs/react/introduce' }}>
<FormattedMessage id="app.home.start" /> <FormattedMessage id="app.home.start" />
</Link> </Link>
</div> </div>

View File

@ -18,7 +18,7 @@ function onScrollEvent(e) {
} }
} }
export default function Page1() { export default function Page1({ location }) {
return ( return (
<ScrollOverPack scrollName="page1" className="content-wrapper page" <ScrollOverPack scrollName="page1" className="content-wrapper page"
playScale={1} replay scrollEvent={onScrollEvent} playScale={1} replay scrollEvent={onScrollEvent}
@ -32,7 +32,7 @@ export default function Page1() {
<h2 key="h2"><FormattedMessage id="app.home.best-practice" /></h2> <h2 key="h2"><FormattedMessage id="app.home.best-practice" /></h2>
<p key="p" style={{ maxWidth: 310 }}><FormattedMessage id="app.home.experience" /></p> <p key="p" style={{ maxWidth: 310 }}><FormattedMessage id="app.home.experience" /></p>
<div key="button"> <div key="button">
<Link to="/docs/practice/cases"> <Link to={{ query: location.query, pathname: '/docs/practice/cases' }}>
<Button type="primary" size="large"> <Button type="primary" size="large">
<FormattedMessage id="app.home.learn-more" /> <FormattedMessage id="app.home.learn-more" />
<Icon type="right" /> <Icon type="right" />

View File

@ -6,7 +6,7 @@ import ScrollOverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import { Icon, Button } from 'antd'; import { Icon, Button } from 'antd';
import QueueAnim from 'rc-queue-anim'; import QueueAnim from 'rc-queue-anim';
export default function Page2() { export default function Page2({ location }) {
return ( return (
<ScrollOverPack scrollName="page2" <ScrollOverPack scrollName="page2"
className="content-wrapper page" playScale={1} replay className="content-wrapper page" playScale={1} replay
@ -18,7 +18,7 @@ export default function Page2() {
<h2 key="h2"><FormattedMessage id="app.home.design-pattern" /></h2> <h2 key="h2"><FormattedMessage id="app.home.design-pattern" /></h2>
<p key="p" style={{ maxWidth: 260 }}><FormattedMessage id="app.home.pattern" /></p> <p key="p" style={{ maxWidth: 260 }}><FormattedMessage id="app.home.pattern" /></p>
<div key="button"> <div key="button">
<Link to="/docs/pattern/navigation"> <Link to={{ query: location.query, pathname: '/docs/pattern/navigation' }}>
<Button type="primary" size="large"> <Button type="primary" size="large">
<FormattedMessage id="app.home.learn-more" /> <FormattedMessage id="app.home.learn-more" />
<Icon type="right" /> <Icon type="right" />

View File

@ -6,7 +6,7 @@ import ScrollOverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import { Icon, Button } from 'antd'; import { Icon, Button } from 'antd';
import QueueAnim from 'rc-queue-anim'; import QueueAnim from 'rc-queue-anim';
export default function Page3() { export default function Page3({ location }) {
return ( return (
<ScrollOverPack scrollName="page3" className="content-wrapper page" playScale={1} replay <ScrollOverPack scrollName="page3" className="content-wrapper page" playScale={1} replay
hideProps={{ image: { reverse: true } }} hideProps={{ image: { reverse: true } }}
@ -21,7 +21,7 @@ export default function Page3() {
<h2 key="h2"><FormattedMessage id="app.home.reusable-components" /></h2> <h2 key="h2"><FormattedMessage id="app.home.reusable-components" /></h2>
<p key="p" style={{ maxWidth: 280 }}><FormattedMessage id="app.home.components-intro" /></p> <p key="p" style={{ maxWidth: 280 }}><FormattedMessage id="app.home.components-intro" /></p>
<div key="button"> <div key="button">
<Link to="/docs/react/introduce"> <Link to={{ query: location.query, pathname: '/docs/react/introduce' }}>
<Button type="primary" size="large"> <Button type="primary" size="large">
<FormattedMessage id="app.home.learn-more" /> <FormattedMessage id="app.home.learn-more" />
<Icon type="right" /> <Icon type="right" />

View File

@ -92,11 +92,11 @@ function Home(props) {
<DocumentTitle title={`Ant Design - ${props.intl.formatMessage({ id: 'app.home.slogan' })}`}> <DocumentTitle title={`Ant Design - ${props.intl.formatMessage({ id: 'app.home.slogan' })}`}>
<div className="main-wrapper"> <div className="main-wrapper">
<Link /> <Link />
<Banner /> <Banner {...props} />
<Page1 /> <Page1 {...props} />
<Page2 /> <Page2 {...props} />
<Page3 /> <Page3 {...props} />
<Page4 /> <Page4 {...props} />
<style dangerouslySetInnerHTML={{ __html: getStyle() }} /> <style dangerouslySetInnerHTML={{ __html: getStyle() }} />
</div> </div>
</DocumentTitle> </DocumentTitle>

View File

@ -62,7 +62,7 @@ export default class Header extends React.Component {
if (typeof localStorage !== 'undefined') { if (typeof localStorage !== 'undefined') {
const locale = this.context.intl.locale === 'zh-CN' ? 'en-US' : 'zh-CN'; const locale = this.context.intl.locale === 'zh-CN' ? 'en-US' : 'zh-CN';
localStorage.setItem('locale', locale); localStorage.setItem('locale', locale);
location.reload(); location.search = `?locale=${locale}`;
} }
} }
@ -99,38 +99,39 @@ export default class Header extends React.Component {
}); });
const menuMode = this.state.menuMode; const menuMode = this.state.menuMode;
const query = location.query;
const menu = [ const menu = [
<Button className="lang" type="ghost" size="small" onClick={this.handleLangChange} key="lang"> <Button className="lang" type="ghost" size="small" onClick={this.handleLangChange} key="lang">
<FormattedMessage id="app.header.lang" /> <FormattedMessage id="app.header.lang" />
</Button>, </Button>,
<Menu mode={menuMode} selectedKeys={[activeMenuItem]} id="nav" key="nav"> <Menu mode={menuMode} selectedKeys={[activeMenuItem]} id="nav" key="nav">
<Menu.Item key="home"> <Menu.Item key="home">
<Link to="/"> <Link to={{ query, pathname: '/' }}>
<FormattedMessage id="app.header.menu.home" /> <FormattedMessage id="app.header.menu.home" />
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="docs/spec"> <Menu.Item key="docs/spec">
<Link to="/docs/spec/introduce"> <Link to={{ query, pathname: '/docs/spec/introduce' }}>
<FormattedMessage id="app.header.menu.spec" /> <FormattedMessage id="app.header.menu.spec" />
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="docs/react"> <Menu.Item key="docs/react">
<Link to="/docs/react/introduce"> <Link to={{ query, pathname: '/docs/react/introduce' }}>
<FormattedMessage id="app.header.menu.components" /> <FormattedMessage id="app.header.menu.components" />
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="docs/pattern"> <Menu.Item key="docs/pattern">
<Link to="/docs/pattern/navigation"> <Link to={{ query, pathname: '/docs/pattern/navigation' }}>
<FormattedMessage id="app.header.menu.pattern" /> <FormattedMessage id="app.header.menu.pattern" />
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="docs/practice"> <Menu.Item key="docs/practice">
<Link to="/docs/practice/cases"> <Link to={{ query, pathname: '/docs/practice/cases' }}>
<FormattedMessage id="app.header.menu.practice" /> <FormattedMessage id="app.header.menu.practice" />
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="docs/resource"> <Menu.Item key="docs/resource">
<Link to="/docs/resource/download"> <Link to={{ query, pathname: '/docs/resource/download' }}>
<FormattedMessage id="app.header.menu.resource" /> <FormattedMessage id="app.header.menu.resource" />
</Link> </Link>
</Menu.Item> </Menu.Item>
@ -153,7 +154,7 @@ export default class Header extends React.Component {
</Popover> </Popover>
<Row> <Row>
<Col lg={4} md={6} sm={7} xs={24}> <Col lg={4} md={6} sm={7} xs={24}>
<Link to="/" id="logo"> <Link to={{ query, pathname: '/' }} id="logo">
<img alt="logo" src="https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg" /> <img alt="logo" src="https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg" />
<span>Ant Design</span> <span>Ant Design</span>
</Link> </Link>

View File

@ -7,6 +7,7 @@ import Header from './Header';
import Footer from './Footer'; import Footer from './Footer';
import enLocale from '../../en-US'; import enLocale from '../../en-US';
import cnLocale from '../../zh-CN'; import cnLocale from '../../zh-CN';
import * as utils from '../utils';
import '../../static/style'; import '../../static/style';
// Expose to iframe // Expose to iframe
@ -14,11 +15,7 @@ window.react = React;
window['react-dom'] = ReactDOM; window['react-dom'] = ReactDOM;
window.antd = require('antd'); window.antd = require('antd');
const language = (typeof localStorage === 'undefined' || !localStorage.getItem('locale')) ? const appLocale = utils.isZhCN() ? cnLocale : enLocale;
navigator.language : localStorage.getItem('locale');
const isZhCN = language === 'zh-CN';
const appLocale = isZhCN ? cnLocale : enLocale;
addLocaleData(appLocale.data); addLocaleData(appLocale.data);
export default class Layout extends React.Component { export default class Layout extends React.Component {

View File

@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import { Link } from 'react-router'; import { Link } from 'react-router';
export default function NotFound() { export default function NotFound({ location }) {
return ( return (
<div id="page-404"> <div id="page-404">
<section> <section>
<h1>404</h1> <h1>404</h1>
<p>你要找的页面不存在 <Link to="/">返回首页</Link></p> <p>你要找的页面不存在 <Link to={{ query: location.query, pathname: '/' }}>返回首页</Link></p>
</section> </section>
<style <style
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{

View File

@ -19,6 +19,21 @@ export function getMenuItems(moduleData, locale) {
return menuItems; return menuItems;
} }
export function isZhCN() {
if (location.search.indexOf('locale=zh-CN') > -1) {
return true;
}
if (location.search.indexOf('locale=en-US') > -1) {
return false;
}
const language = (
typeof localStorage === 'undefined' ||
!localStorage.getItem('locale')
) ? navigator.language : localStorage.getItem('locale');
return language === 'zh-CN';
}
export function ping(url, callback) { export function ping(url, callback) {
const img = new Image(); const img = new Image();
let done; let done;