mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-18 14:13:37 +08:00
Merge branch "master" into "feature"
This commit is contained in:
commit
879784c665
@ -219,6 +219,8 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
|
||||
// Wait for parent component ref has its value
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setTargetEventListeners(target);
|
||||
// Mock Event object.
|
||||
this.updatePosition({} as Event);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ export default class Button extends React.Component<ButtonProps, any> {
|
||||
[`${prefixCls}-${type}`]: type,
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
||||
[`${prefixCls}-icon-only`]: !children && icon,
|
||||
[`${prefixCls}-icon-only`]: !children && children !== 0 && icon,
|
||||
[`${prefixCls}-loading`]: loading,
|
||||
[`${prefixCls}-background-ghost`]: ghost,
|
||||
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar,
|
||||
|
@ -234,6 +234,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-loading {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: @card-padding-base;
|
||||
background: @component-background;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
&-loading &-body {
|
||||
user-select: none;
|
||||
}
|
||||
|
@ -262,11 +262,11 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
|
||||
handlePopupVisibleChange = (popupVisible: boolean) => {
|
||||
if (!('popupVisible' in this.props)) {
|
||||
this.setState({
|
||||
this.setState(state => ({
|
||||
popupVisible,
|
||||
inputFocused: popupVisible,
|
||||
inputValue: popupVisible ? this.state.inputValue : '',
|
||||
});
|
||||
inputValue: popupVisible ? state.inputValue : '',
|
||||
}));
|
||||
}
|
||||
|
||||
const onPopupVisibleChange = this.props.onPopupVisibleChange;
|
||||
|
@ -69,7 +69,7 @@
|
||||
|
||||
&-actions {
|
||||
margin-top: 12px;
|
||||
|
||||
padding-left: 0;
|
||||
> li {
|
||||
display: inline-block;
|
||||
color: @comment-action-color;
|
||||
|
@ -143,17 +143,14 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
|
||||
};
|
||||
|
||||
getRcDrawerStyle = () => {
|
||||
const { zIndex, placement, maskStyle } = this.props;
|
||||
return this.state.push
|
||||
? {
|
||||
...maskStyle,
|
||||
zIndex,
|
||||
transform: this.getPushTransform(placement),
|
||||
}
|
||||
: {
|
||||
...maskStyle,
|
||||
zIndex,
|
||||
};
|
||||
const { zIndex, placement, maskStyle, style } = this.props;
|
||||
const { push } = this.state;
|
||||
return {
|
||||
...maskStyle,
|
||||
zIndex,
|
||||
transform: push ? this.getPushTransform(placement) : undefined,
|
||||
style,
|
||||
};
|
||||
};
|
||||
|
||||
// render drawer body dom
|
||||
@ -210,14 +207,12 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
|
||||
>
|
||||
{header}
|
||||
{closer}
|
||||
<div className={`${prefixCls}-body`} style={this.props.style}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
<div className={`${prefixCls}-body`}>{this.props.children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// render Provider for Multi-level drawer
|
||||
// render Provider for Multi-level drawe
|
||||
renderProvider = (value: Drawer) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
|
@ -15,7 +15,7 @@
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
left: -7px;
|
||||
right: -7px;
|
||||
right: 0;
|
||||
bottom: -7px;
|
||||
content: ' ';
|
||||
opacity: 0.0001;
|
||||
@ -55,6 +55,7 @@
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
background-clip: padding-box;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
|
||||
&-item-group-title {
|
||||
color: @text-color-secondary;
|
||||
|
@ -104,7 +104,7 @@ export default class Row extends React.Component<RowProps, RowState> {
|
||||
getGutter(): number | undefined {
|
||||
const { gutter } = this.props;
|
||||
if (typeof gutter === 'object') {
|
||||
for (let i = 0; i <= responsiveArray.length; i++) {
|
||||
for (let i = 0; i < responsiveArray.length; i++) {
|
||||
const breakpoint: Breakpoint = responsiveArray[i];
|
||||
if (this.state.screens[breakpoint] && gutter[breakpoint] !== undefined) {
|
||||
return gutter[breakpoint];
|
||||
|
@ -138,7 +138,7 @@ const Icon: IconComponent<IconProps> = props => {
|
||||
);
|
||||
}
|
||||
computedType = withThemeSuffix(
|
||||
removeTypeTheme(alias(type)),
|
||||
removeTypeTheme(alias(computedType)),
|
||||
dangerousTheme || theme || defaultTheme,
|
||||
);
|
||||
innerNode = (
|
||||
|
@ -46,7 +46,11 @@ class Basic extends React.Component<BasicProps, any> {
|
||||
}
|
||||
}
|
||||
|
||||
class BasicLayout extends React.Component<BasicProps, any> {
|
||||
interface BasicLayoutState {
|
||||
siders: string[];
|
||||
}
|
||||
|
||||
class BasicLayout extends React.Component<BasicProps, BasicLayoutState> {
|
||||
static childContextTypes = {
|
||||
siderHook: PropTypes.object,
|
||||
};
|
||||
@ -56,14 +60,14 @@ class BasicLayout extends React.Component<BasicProps, any> {
|
||||
return {
|
||||
siderHook: {
|
||||
addSider: (id: string) => {
|
||||
this.setState({
|
||||
siders: [...this.state.siders, id],
|
||||
});
|
||||
this.setState(state => ({
|
||||
siders: [...state.siders, id],
|
||||
}));
|
||||
},
|
||||
removeSider: (id: string) => {
|
||||
this.setState({
|
||||
siders: this.state.siders.filter(currentId => currentId !== id),
|
||||
});
|
||||
this.setState(state => ({
|
||||
siders: state.siders.filter(currentId => currentId !== id),
|
||||
}));
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -94,6 +94,7 @@ class Mention extends React.Component<MentionProps, MentionState> {
|
||||
this.props.onFocus(ev);
|
||||
}
|
||||
};
|
||||
|
||||
onBlur = (ev: React.FocusEvent<HTMLElement>) => {
|
||||
this.setState({
|
||||
focus: false,
|
||||
@ -102,9 +103,11 @@ class Mention extends React.Component<MentionProps, MentionState> {
|
||||
this.props.onBlur(ev);
|
||||
}
|
||||
};
|
||||
|
||||
focus = () => {
|
||||
this.mentionEle._editor.focusEditor();
|
||||
};
|
||||
|
||||
mentionRef = (ele: any) => {
|
||||
this.mentionEle = ele;
|
||||
};
|
||||
@ -122,7 +125,6 @@ class Mention extends React.Component<MentionProps, MentionState> {
|
||||
[`${prefixCls}-active`]: focus,
|
||||
[`${prefixCls}-placement-top`]: placement === 'top',
|
||||
});
|
||||
|
||||
const notFoundContent = loading ? <Icon type="loading" /> : this.props.notFoundContent;
|
||||
|
||||
return (
|
||||
|
@ -214,26 +214,19 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
|
||||
const { openAnimation, openTransitionName } = this.props;
|
||||
let menuOpenAnimation = openAnimation || openTransitionName;
|
||||
if (openAnimation === undefined && openTransitionName === undefined) {
|
||||
switch (menuMode) {
|
||||
case 'horizontal':
|
||||
menuOpenAnimation = 'slide-up';
|
||||
break;
|
||||
case 'vertical':
|
||||
case 'vertical-left':
|
||||
case 'vertical-right':
|
||||
// When mode switch from inline
|
||||
// submenu should hide without animation
|
||||
if (this.switchingModeFromInline) {
|
||||
menuOpenAnimation = '';
|
||||
this.switchingModeFromInline = false;
|
||||
} else {
|
||||
menuOpenAnimation = 'zoom-big';
|
||||
}
|
||||
break;
|
||||
case 'inline':
|
||||
menuOpenAnimation = animation;
|
||||
break;
|
||||
default:
|
||||
if (menuMode === 'horizontal') {
|
||||
menuOpenAnimation = 'slide-up';
|
||||
} else if (menuMode === 'inline') {
|
||||
menuOpenAnimation = animation;
|
||||
} else {
|
||||
// When mode switch from inline
|
||||
// submenu should hide without animation
|
||||
if (this.switchingModeFromInline) {
|
||||
menuOpenAnimation = '';
|
||||
this.switchingModeFromInline = false;
|
||||
} else {
|
||||
menuOpenAnimation = 'zoom-big';
|
||||
}
|
||||
}
|
||||
}
|
||||
return menuOpenAnimation;
|
||||
|
@ -136,7 +136,7 @@ export default function confirm(config: ModalFuncProps) {
|
||||
if (unmountResult && div.parentNode) {
|
||||
div.parentNode.removeChild(div);
|
||||
}
|
||||
const triggerCancel = args && args.length && args.some(param => param && param.triggerCancel);
|
||||
const triggerCancel = args.some(param => param && param.triggerCancel);
|
||||
if (config.onCancel && triggerCancel) {
|
||||
config.onCancel(...args);
|
||||
}
|
||||
|
@ -101,6 +101,7 @@
|
||||
|
||||
&-arrow {
|
||||
background: @popover-bg;
|
||||
background-color: inherit;
|
||||
width: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
height: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
|
||||
transform: rotate(45deg);
|
||||
|
@ -89,6 +89,33 @@ exports[`Progress render negetive successPercent 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Progress render normal progress 1`] = `
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="ant-progress-outer"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-inner"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-bg"
|
||||
style="width: 0%; height: 8px; border-radius: 100px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-progress-text"
|
||||
title="0%"
|
||||
>
|
||||
0%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Progress render out-of-range progress 1`] = `
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-success ant-progress-show-info ant-progress-default"
|
||||
|
@ -46,4 +46,9 @@ describe('Progress', () => {
|
||||
const wrapper = mount(<Progress type="circle" percent={50} strokeColor="red" />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('render normal progress', () => {
|
||||
const wrapper = mount(<Progress status="normal" />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -22,7 +22,7 @@ If it will take a long time to complete an operation, you can use `Progress` to
|
||||
| gapPosition `(type=circle)` | the gap position, options: `top` `bottom` `left` `right` | string | `top` |
|
||||
| percent | to set the completion percentage | number | 0 |
|
||||
| showInfo | whether to display the progress value and the status icon | boolean | true |
|
||||
| status | to set the status of the Progress, options: `success` `exception` `active` | string | - |
|
||||
| status | to set the status of the Progress, options: `success` `exception` `active` `normal` | string | - |
|
||||
| strokeWidth `(type=line)` | to set the width of the progress bar, unit: `px` | number | 10 |
|
||||
| strokeWidth `(type=circle)` | to set the width of the circular progress bar, unit: percentage of the canvas width | number | 6 |
|
||||
| strokeLinecap | to set the style of the progress linecap | Enum{ 'round', 'square' } | `round` |
|
||||
|
@ -23,7 +23,7 @@ title: Progress
|
||||
| gapPosition `(type=circle)` | 圆形进度条缺口位置 | Enum{ 'top', 'bottom', 'left', 'right' } | `top` |
|
||||
| percent | 百分比 | number | 0 |
|
||||
| showInfo | 是否显示进度数值或状态图标 | boolean | true |
|
||||
| status | 状态,可选:`success` `exception` `active` | string | - |
|
||||
| status | 状态,可选:`success` `exception` `active` `normal` | string | - |
|
||||
| strokeWidth `(type=line)` | 进度条线的宽度,单位 px | number | 10 |
|
||||
| strokeWidth `(type=circle)` | 圆形进度条线的宽度,单位是进度条画布宽度的百分比 | number | 6 |
|
||||
| strokeLinecap | | Enum{ 'round', 'square' } | `round` |
|
||||
|
@ -21,7 +21,7 @@ export interface ProgressProps {
|
||||
percent?: number;
|
||||
successPercent?: number;
|
||||
format?: (percent?: number, successPercent?: number) => React.ReactNode;
|
||||
status?: 'success' | 'active' | 'exception';
|
||||
status?: 'success' | 'active' | 'exception' | 'normal';
|
||||
showInfo?: boolean;
|
||||
strokeWidth?: number;
|
||||
strokeLinecap?: string;
|
||||
|
@ -37,7 +37,7 @@ export interface AbstractSelectProps {
|
||||
open?: boolean;
|
||||
onDropdownVisibleChange?: (open: boolean) => void;
|
||||
autoClearSearchValue?: boolean;
|
||||
dropdownRender?: (menu: React.ReactNode) => React.ReactNode;
|
||||
dropdownRender?: (menu?: React.ReactNode, props?: SelectProps) => React.ReactNode;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,10 @@ title:
|
||||
When `tooltipVisible` is `true`, ToolTip will show always, or ToolTip will not show anyway, even if dragging or hovering.
|
||||
|
||||
|
||||
````jsx
|
||||
````jsx
|
||||
|
||||
import Slider from '..';
|
||||
import { Slider } from 'antd';
|
||||
|
||||
ReactDOM.render(<Slider defaultValue={30} tooltipVisible />, mountNode);
|
||||
ReactDOM.render(<Slider defaultValue={30} tooltipVisible />, mountNode);
|
||||
|
||||
````
|
||||
````
|
||||
|
@ -85,12 +85,7 @@ export default class Slider extends React.Component<SliderProps, SliderState> {
|
||||
const { tipFormatter, tooltipVisible } = this.props;
|
||||
const { visibles } = this.state;
|
||||
const isTipFormatter = tipFormatter ? visibles[index] || dragging : false;
|
||||
let visible;
|
||||
if (tooltipVisible) {
|
||||
visible = tooltipVisible || isTipFormatter;
|
||||
} else if (tooltipVisible === undefined) {
|
||||
visible = isTipFormatter;
|
||||
}
|
||||
const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
|
||||
return (
|
||||
<Tooltip
|
||||
prefixCls={tooltipPrefixCls}
|
||||
|
@ -432,6 +432,8 @@
|
||||
@tabs-bar-margin: 0 0 16px 0;
|
||||
@tabs-horizontal-margin: 0 32px 0 0;
|
||||
@tabs-horizontal-padding: 12px 16px;
|
||||
@tabs-horizontal-padding-lg: 16px;
|
||||
@tabs-horizontal-padding-sm: 8px 16px;
|
||||
@tabs-vertical-padding: 8px 24px;
|
||||
@tabs-vertical-margin: 0 0 16px 0;
|
||||
@tabs-scrolling-size: 32px;
|
||||
|
@ -494,7 +494,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection);
|
||||
const key = this.getRecordKey(record, rowIndex);
|
||||
const { pivot } = this.state;
|
||||
const rows = this.getFlatCurrentPageData();
|
||||
const rows = this.getFlatCurrentPageData(this.props.childrenColumnName);
|
||||
let realIndex = rowIndex;
|
||||
if (this.props.expandedRowRender) {
|
||||
realIndex = rows.findIndex(row => this.getRecordKey(row, rowIndex) === key);
|
||||
@ -559,10 +559,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
handleRadioSelect = (record: T, rowIndex: number, e: RadioChangeEvent) => {
|
||||
const checked = e.target.checked;
|
||||
const nativeEvent = e.nativeEvent;
|
||||
const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection();
|
||||
let selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection);
|
||||
const key = this.getRecordKey(record, rowIndex);
|
||||
selectedRowKeys = [key];
|
||||
const selectedRowKeys = [key];
|
||||
this.store.setState({
|
||||
selectionDirty: true,
|
||||
});
|
||||
@ -576,7 +574,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
};
|
||||
|
||||
handleSelectRow = (selectionKey: string, index: number, onSelectFunc: SelectionItemSelectFn) => {
|
||||
const data = this.getFlatCurrentPageData();
|
||||
const data = this.getFlatCurrentPageData(this.props.childrenColumnName);
|
||||
const defaultSelection = this.store.getState().selectionDirty ? [] : this.getDefaultSelection();
|
||||
const selectedRowKeys = this.store.getState().selectedRowKeys.concat(defaultSelection);
|
||||
const changeableRowKeys = data
|
||||
@ -728,10 +726,10 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
};
|
||||
|
||||
renderRowSelection(prefixCls: string, locale: TableLocale) {
|
||||
const { rowSelection } = this.props;
|
||||
const { rowSelection, childrenColumnName } = this.props;
|
||||
const columns = this.columns.concat();
|
||||
if (rowSelection) {
|
||||
const data = this.getFlatCurrentPageData().filter((item, index) => {
|
||||
const data = this.getFlatCurrentPageData(childrenColumnName).filter((item, index) => {
|
||||
if (rowSelection.getCheckboxProps) {
|
||||
return !this.getCheckboxPropsByItem(item, index).disabled;
|
||||
}
|
||||
@ -783,7 +781,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
}
|
||||
|
||||
getColumnKey(column: ColumnProps<T>, index?: number) {
|
||||
return column.key || column.dataIndex || index;
|
||||
return column.key || (column.dataIndex as string) || index;
|
||||
}
|
||||
|
||||
getMaxCurrent(total: number) {
|
||||
@ -1034,8 +1032,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
|
||||
return flatArray(this.getLocalData(null, false));
|
||||
}
|
||||
|
||||
getFlatCurrentPageData() {
|
||||
return flatArray(this.getCurrentPageData());
|
||||
getFlatCurrentPageData(childrenColumnName: string | undefined) {
|
||||
return flatArray(this.getCurrentPageData(), childrenColumnName);
|
||||
}
|
||||
|
||||
recursiveSort(data: T[], sorterFn: (a: any, b: any) => number): T[] {
|
||||
|
@ -615,4 +615,40 @@ describe('Table.rowSelection', () => {
|
||||
expect(onChange.mock.calls[1][0].length).toBe(2);
|
||||
expect(onChange.mock.calls[1][1].length).toBe(2);
|
||||
});
|
||||
|
||||
it('render correctly when set childrenColumnName', () => {
|
||||
const newDatas = [
|
||||
{
|
||||
key: 1,
|
||||
name: 'Jack',
|
||||
children: [
|
||||
{
|
||||
key: 11,
|
||||
name: 'John Brown',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
name: 'Lucy',
|
||||
children: [
|
||||
{
|
||||
key: 21,
|
||||
name: 'Lucy Brown',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const wrapper = mount(
|
||||
<Table columns={columns} dataSource={newDatas} childrenColumnName="test" rowSelection={{}} />,
|
||||
);
|
||||
const checkboxes = wrapper.find('input');
|
||||
const checkboxAll = wrapper.find('SelectionCheckboxAll');
|
||||
|
||||
checkboxes.at(1).simulate('change', { target: { checked: true } });
|
||||
expect(checkboxAll.instance().state).toEqual({ indeterminate: true, checked: false });
|
||||
|
||||
checkboxes.at(2).simulate('change', { target: { checked: true } });
|
||||
expect(checkboxAll.instance().state).toEqual({ indeterminate: false, checked: true });
|
||||
});
|
||||
});
|
||||
|
@ -19,7 +19,7 @@ export interface ColumnProps<T> {
|
||||
},
|
||||
) => React.ReactNode);
|
||||
key?: React.Key;
|
||||
dataIndex?: string;
|
||||
dataIndex?: keyof T;
|
||||
render?: (text: any, record: T, index: number) => React.ReactNode;
|
||||
align?: 'left' | 'right' | 'center';
|
||||
filters?: ColumnFilterItem[];
|
||||
|
@ -204,7 +204,7 @@
|
||||
font-size: @tabs-title-font-size-lg;
|
||||
}
|
||||
.@{tab-prefix-cls}-tab {
|
||||
padding: 16px;
|
||||
padding: @tabs-horizontal-padding-lg;
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@
|
||||
font-size: @tabs-title-font-size-sm;
|
||||
}
|
||||
.@{tab-prefix-cls}-tab {
|
||||
padding: 8px 16px;
|
||||
padding: @tabs-horizontal-padding-sm;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ export default class DirectoryTree extends React.Component<DirectoryTreeProps, D
|
||||
|
||||
onSelect = (keys: string[], event: AntTreeNodeSelectedEvent) => {
|
||||
const { onSelect, multiple, children } = this.props;
|
||||
const { expandedKeys = [], selectedKeys = [] } = this.state;
|
||||
const { expandedKeys = [] } = this.state;
|
||||
const { node, nativeEvent } = event;
|
||||
const { eventKey = '' } = node.props;
|
||||
|
||||
@ -143,7 +143,7 @@ export default class DirectoryTree extends React.Component<DirectoryTreeProps, D
|
||||
const shiftPick: boolean = nativeEvent.shiftKey;
|
||||
|
||||
// Generate new selected keys
|
||||
let newSelectedKeys = selectedKeys.slice();
|
||||
let newSelectedKeys: string[];
|
||||
if (multiple && ctrlPick) {
|
||||
// Control click
|
||||
newSelectedKeys = keys;
|
||||
|
@ -21,3 +21,4 @@
|
||||
@import './theme';
|
||||
@import './docsearch';
|
||||
@import './nprogress';
|
||||
@import './santa';
|
||||
|
171
site/theme/static/santa.less
Normal file
171
site/theme/static/santa.less
Normal file
@ -0,0 +1,171 @@
|
||||
.santa {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.santa-body {
|
||||
font-size: 24px;
|
||||
color: #f91047;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
box-shadow: inset 0 -0.25em rgba(0, 0, 0, 0.1);
|
||||
border-radius: 50%;
|
||||
transform-origin: center bottom;
|
||||
animation: balance alternate infinite 2s ease-in-out;
|
||||
}
|
||||
|
||||
.santa-head {
|
||||
font-size: 0.4em;
|
||||
width: 1em;
|
||||
height: 1.9em;
|
||||
background-color: white;
|
||||
border-radius: 0.5em;
|
||||
transform: translateY(-1em);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.santa-head::before {
|
||||
content: '';
|
||||
width: 1em;
|
||||
height: 0.375em;
|
||||
display: block;
|
||||
background-color: #ff9876;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0.65em;
|
||||
}
|
||||
|
||||
.santa-ear {
|
||||
background-color: #fc8363;
|
||||
width: 0.1em;
|
||||
height: 0.3em;
|
||||
position: absolute;
|
||||
top: 0.75em;
|
||||
}
|
||||
|
||||
.santa-ear:nth-of-type(1) {
|
||||
border-radius: 0.05em 0 0 0.05em;
|
||||
left: -0.1em;
|
||||
}
|
||||
|
||||
.santa-ear:nth-of-type(2) {
|
||||
border-radius: 0 0.05em 0.05em 0;
|
||||
right: -0.1em;
|
||||
}
|
||||
|
||||
.santa-hat {
|
||||
content: '';
|
||||
width: 1em;
|
||||
height: 0.15em;
|
||||
position: absolute;
|
||||
transform: scale(1.1);
|
||||
top: 0.5em;
|
||||
left: 0;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.santa-hat::before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 1em;
|
||||
height: 0.5em;
|
||||
background: #f91047;
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
.santa-hat::after {
|
||||
/* pompom */
|
||||
content: '';
|
||||
width: 0.25em;
|
||||
height: 0.25em;
|
||||
display: block;
|
||||
background-color: white;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
top: -0.72em;
|
||||
right: 0;
|
||||
box-shadow: -0.2em 0.2em 0 0.12em rgba(0, 0, 0, 0.2), -0.2em 0.2em 0 0.12em #f91047;
|
||||
}
|
||||
|
||||
.santa-eye {
|
||||
width: 0.12em;
|
||||
height: 0.12em;
|
||||
background-color: black;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 0.76em;
|
||||
left: 0.2em;
|
||||
}
|
||||
|
||||
.santa-eye + .santa-eye {
|
||||
left: auto;
|
||||
right: 0.2em;
|
||||
}
|
||||
|
||||
.santa-nose {
|
||||
width: 0.12em;
|
||||
height: 0.22em;
|
||||
background-color: #f24c4c;
|
||||
border-radius: 0 0 0.12em 0.12em;
|
||||
position: absolute;
|
||||
top: 0.84em;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.santa-mouth {
|
||||
width: 0.18em;
|
||||
height: 0.1em;
|
||||
border-bottom-right-radius: 5vw;
|
||||
border-bottom-left-radius: 5vw;
|
||||
margin-top: 0.3em;
|
||||
background-color: black;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: hohoho 4s linear forwards infinite;
|
||||
}
|
||||
|
||||
@keyframes hohoho {
|
||||
0%,
|
||||
10%,
|
||||
20%,
|
||||
40%,
|
||||
100% {
|
||||
/* smiling */
|
||||
width: 0.18em;
|
||||
height: 0.1em;
|
||||
border-bottom-right-radius: 1vw;
|
||||
border-bottom-left-radius: 1vw;
|
||||
}
|
||||
|
||||
5%,
|
||||
15%,
|
||||
25%,
|
||||
35% {
|
||||
/* hohoho */
|
||||
width: 0.15em;
|
||||
height: 0.2em;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes balance {
|
||||
from {
|
||||
transform: rotate(-4deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(4deg);
|
||||
}
|
||||
}
|
@ -169,12 +169,12 @@ export default class Demo extends React.Component {
|
||||
const dependencies = sourceCode.split('\n').reduce(
|
||||
(acc, line) => {
|
||||
const matches = line.match(/import .+? from '(.+)';$/);
|
||||
if (matches && matches[1]) {
|
||||
if (matches && matches[1] && !line.includes('antd')) {
|
||||
acc[matches[1]] = 'latest';
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ react: 'latest', 'react-dom': 'latest' },
|
||||
{ react: 'latest', 'react-dom': 'latest', antd: 'latest' },
|
||||
);
|
||||
const codesanboxPrefillConfig = {
|
||||
files: {
|
||||
|
@ -4,6 +4,7 @@ import { Link } from 'bisheng/router';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { Select, Menu, Row, Col, Icon, Popover, Input, Badge, Button } from 'antd';
|
||||
import Santa from './Santa';
|
||||
import * as utils from '../utils';
|
||||
import { version as antdVersion } from '../../../../package.json';
|
||||
|
||||
@ -238,6 +239,7 @@ export default class Header extends React.Component {
|
||||
alt="Ant Design"
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/DkKNubTaaVsKURhcVGkh.svg"
|
||||
/>
|
||||
<Santa />
|
||||
</Link>
|
||||
</Col>
|
||||
<Col xxl={20} xl={19} lg={19} md={19} sm={0} xs={0}>
|
||||
|
26
site/theme/template/Layout/Santa.jsx
Normal file
26
site/theme/template/Layout/Santa.jsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { Tooltip } from 'antd';
|
||||
|
||||
export default () => {
|
||||
const now = new Date();
|
||||
const isChristmas = now.getMonth() === 11 && now.getDate() === 25;
|
||||
return (
|
||||
isChristmas && (
|
||||
<Tooltip title="🎅🏻 Merry Chrismas!">
|
||||
<div className="santa">
|
||||
<div className="santa-body">
|
||||
<div className="santa-head">
|
||||
<div className="santa-ear" />
|
||||
<div className="santa-ear" />
|
||||
<div className="santa-hat" />
|
||||
<div className="santa-eye" />
|
||||
<div className="santa-eye" />
|
||||
<div className="santa-nose" />
|
||||
<div className="santa-mouth" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user