mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-28 05:05:48 +08:00
Merge branch 'master' into antd-3.0
This commit is contained in:
commit
714b4ae06a
@ -17,6 +17,16 @@ If you want to read change logs before `2.0.0`, please visit [GitHub](https://gi
|
||||
|
||||
---
|
||||
|
||||
## 2.13.9
|
||||
|
||||
`2017-11-06`
|
||||
|
||||
- Published [Ant Design Pro](https://pro.ant.design/).
|
||||
- Fix that `Cascader[popupVisible]` doesn't work. [#8088](https://github.com/ant-design/ant-design/issues/8088)
|
||||
- Fix that native `input[type=checkbox|radio]` invisible issue. [7c3a483](https://github.com/ant-design/ant-design/commit/7c3a48319074a800c89935e728904933d503ee86)
|
||||
- Fix that `Input.Search[suffix]` doesn't work. [#7970](https://github.com/ant-design/ant-design/issues/7970)
|
||||
- Fix TypeScript definitions of Slider. [#8102](https://github.com/ant-design/ant-design/pull/8102) [@davschne](https://github.com/davschne)
|
||||
|
||||
## 2.13.8
|
||||
|
||||
`2017-10-27`
|
||||
|
@ -17,6 +17,16 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 2.13.9
|
||||
|
||||
`2017-11-06`
|
||||
|
||||
- 发布 [Ant Design Pro](https://pro.ant.design/)。
|
||||
- 修复 `Cascader[popupVisible]` 失效问题。[#8088](https://github.com/ant-design/ant-design/issues/8088)
|
||||
- 修复原生 `input[type=checkbox|radio]` 看不到的问题。[7c3a483](https://github.com/ant-design/ant-design/commit/7c3a48319074a800c89935e728904933d503ee86)
|
||||
- 修复 `Input.Search[suffix]` 失效的问题。[#7970](https://github.com/ant-design/ant-design/issues/7970)
|
||||
- 修复 Slider TypeScript 定义问题。[#8102](https://github.com/ant-design/ant-design/pull/8102) [@davschne](https://github.com/davschne)
|
||||
|
||||
## 2.13.8
|
||||
|
||||
`2017-10-27`
|
||||
|
@ -81,11 +81,10 @@ import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
|
||||
|
||||
## 链接
|
||||
|
||||
- [首页](http://ant.design/index-cn)
|
||||
- [UI 组件库](http://ant.design/docs/react/introduce-cn)
|
||||
- [首页](http://ant.design/)
|
||||
- [组件库](http://ant.design/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [更新日志](CHANGELOG.en-US.md)
|
||||
- [官方脚手架](https://github.com/dvajs/dva-cli)
|
||||
- [开发工具文档](http://ant-tool.github.io/)
|
||||
- [脚手架市场](http://scaffold.ant.design)
|
||||
- [React 底层基础组件](http://react-component.github.io/)
|
||||
- [移动端组件](http://mobile.ant.design)
|
||||
|
@ -121,10 +121,9 @@ See [i18n](http://ant.design/docs/react/i18n).
|
||||
## Links
|
||||
|
||||
- [Home page](http://ant.design/)
|
||||
- [UI library](http://ant.design/docs/react/introduce)
|
||||
- [Components](http://ant.design/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [Change Log](CHANGELOG.en-US.md)
|
||||
- [Official Scaffold Tool](https://github.com/dvajs/dva-cli/)
|
||||
- [Development Tool](http://ant-tool.github.io/)
|
||||
- [Scaffold Market](http://scaffold.ant.design)
|
||||
- [rc-components](http://react-component.github.io/)
|
||||
- [Mobile UI](http://mobile.ant.design)
|
||||
|
@ -40,6 +40,7 @@ Cascade selection box.
|
||||
| value | selected value | [CascaderOptionType](https://git.io/vMMoK)\[] | - |
|
||||
| onChange | callback when finishing cascader select | `(value, selectedOptions) => void` | - |
|
||||
| onPopupVisibleChange | callback when popup shown or hidden | `(value) => void` | - |
|
||||
| popupVisible | set visible of cascader popup | boolean | - |
|
||||
|
||||
Fields in `showSearch`:
|
||||
|
||||
|
@ -116,7 +116,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
value: props.value || props.defaultValue || [],
|
||||
inputValue: '',
|
||||
inputFocused: false,
|
||||
popupVisible: false,
|
||||
popupVisible: props.popupVisible,
|
||||
flattenOptions: props.showSearch && this.flattenTree(props.options, props.changeOnSelect),
|
||||
};
|
||||
}
|
||||
@ -125,6 +125,9 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
if ('value' in nextProps) {
|
||||
this.setState({ value: nextProps.value || [] });
|
||||
}
|
||||
if ('popupVisible' in nextProps) {
|
||||
this.setState({ popupVisible: nextProps.popupVisible });
|
||||
}
|
||||
if (nextProps.showSearch && this.props.options !== nextProps.options) {
|
||||
this.setState({ flattenOptions: this.flattenTree(nextProps.options, nextProps.changeOnSelect) });
|
||||
}
|
||||
@ -142,11 +145,13 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
}
|
||||
|
||||
handlePopupVisibleChange = (popupVisible) => {
|
||||
this.setState({
|
||||
popupVisible,
|
||||
inputFocused: popupVisible,
|
||||
inputValue: popupVisible ? this.state.inputValue : '',
|
||||
});
|
||||
if (!('popupVisible' in this.props)) {
|
||||
this.setState({
|
||||
popupVisible,
|
||||
inputFocused: popupVisible,
|
||||
inputValue: popupVisible ? this.state.inputValue : '',
|
||||
});
|
||||
}
|
||||
|
||||
const onPopupVisibleChange = this.props.onPopupVisibleChange;
|
||||
if (onPopupVisibleChange) {
|
||||
@ -204,7 +209,7 @@ export default class Cascader extends React.Component<CascaderProps, any> {
|
||||
e.stopPropagation();
|
||||
if (!this.state.inputValue) {
|
||||
this.setValue([]);
|
||||
this.setState({ popupVisible: false });
|
||||
this.handlePopupVisibleChange(false);
|
||||
} else {
|
||||
this.setState({ inputValue: '' });
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ subtitle: 级联选择
|
||||
| value | 指定选中项 | [CascaderOptionType](https://git.io/vMMoK)\[] | - |
|
||||
| onChange | 选择完成后的回调 | `(value, selectedOptions) => void` | - |
|
||||
| onPopupVisibleChange | 显示/隐藏浮层的回调 | `(value) => void` | - |
|
||||
| popupVisible | 控制浮层显隐 | boolean | - |
|
||||
|
||||
`showSearch` 为对象时,其中的字段:
|
||||
|
||||
|
@ -32,9 +32,9 @@ export default class Search extends React.Component<SearchProps, any> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, prefixCls, inputPrefixCls, size, enterButton, ...others } = this.props;
|
||||
const { className, prefixCls, inputPrefixCls, size, enterButton, suffix, ...others } = this.props;
|
||||
delete (others as any).onSearch;
|
||||
const searchSuffix = enterButton
|
||||
const buttonOrIcon = enterButton
|
||||
? (
|
||||
<Button
|
||||
className={`${prefixCls}-button`}
|
||||
@ -45,6 +45,7 @@ export default class Search extends React.Component<SearchProps, any> {
|
||||
{enterButton === true ? <Icon type="search" /> : enterButton}
|
||||
</Button>
|
||||
) : <Icon className={`${prefixCls}-icon`} type="search" />;
|
||||
const searchSuffix = suffix ? [suffix, buttonOrIcon] : buttonOrIcon;
|
||||
const inputClassName = classNames(prefixCls, className, {
|
||||
[`${prefixCls}-enter-button`]: !!enterButton,
|
||||
[`${prefixCls}-${size}`]: !!size,
|
||||
|
@ -17,6 +17,59 @@ exports[`Input should support maxLength 1`] = `
|
||||
</Input>
|
||||
`;
|
||||
|
||||
exports[`Input.Search should support suffix 1`] = `
|
||||
<Search
|
||||
inputPrefixCls="ant-input"
|
||||
prefixCls="ant-input-search"
|
||||
suffix="suffix"
|
||||
>
|
||||
<Input
|
||||
className="ant-input-search"
|
||||
disabled={false}
|
||||
onPressEnter={[Function]}
|
||||
prefixCls="ant-input"
|
||||
suffix={
|
||||
Array [
|
||||
"suffix",
|
||||
<Icon
|
||||
className="ant-input-search-icon"
|
||||
onClick={[Function]}
|
||||
type="search"
|
||||
/>,
|
||||
]
|
||||
}
|
||||
type="text"
|
||||
>
|
||||
<span
|
||||
className="ant-input-search ant-input-affix-wrapper"
|
||||
>
|
||||
<input
|
||||
className="ant-input"
|
||||
disabled={false}
|
||||
onKeyDown={[Function]}
|
||||
style={null}
|
||||
type="text"
|
||||
/>
|
||||
<span
|
||||
className="ant-input-suffix"
|
||||
>
|
||||
suffix
|
||||
<Icon
|
||||
className="ant-input-search-icon"
|
||||
onClick={[Function]}
|
||||
type="search"
|
||||
>
|
||||
<i
|
||||
className="anticon anticon-search ant-input-search-icon"
|
||||
onClick={[Function]}
|
||||
/>
|
||||
</Icon>
|
||||
</span>
|
||||
</span>
|
||||
</Input>
|
||||
</Search>
|
||||
`;
|
||||
|
||||
exports[`TextArea should support disabled 1`] = `
|
||||
<TextArea
|
||||
disabled={true}
|
||||
|
@ -7,7 +7,6 @@ const { TextArea } = Input;
|
||||
|
||||
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
|
||||
|
||||
|
||||
describe('Input', () => {
|
||||
it('should support maxLength', async () => {
|
||||
const wrapper = mount(
|
||||
@ -16,6 +15,7 @@ describe('Input', () => {
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('TextArea', () => {
|
||||
it('should auto calculate height according to content length', async () => {
|
||||
const wrapper = mount(
|
||||
@ -77,3 +77,12 @@ describe('As Form Control', () => {
|
||||
expect(wrapper.find('textarea').prop('value')).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Input.Search', () => {
|
||||
it('should support suffix', async () => {
|
||||
const wrapper = mount(
|
||||
<Input.Search suffix="suffix" />
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -42,13 +42,13 @@
|
||||
}
|
||||
|
||||
&-circle-path {
|
||||
stroke: @process-default-color;
|
||||
stroke: @progress-default-color;
|
||||
animation: ~"@{ant-prefix}-progress-appear" .3s;
|
||||
}
|
||||
|
||||
&-bg {
|
||||
border-radius: 100px;
|
||||
background-color: @process-default-color;
|
||||
background-color: @progress-default-color;
|
||||
transition: all .4s @ease-out-circ 0s;
|
||||
position: relative;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export interface SliderProps {
|
||||
range?: boolean;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number | void;
|
||||
step?: number | null;
|
||||
marks?: SliderMarks;
|
||||
dots?: boolean;
|
||||
value?: SliderValue;
|
||||
@ -29,7 +29,7 @@ export interface SliderProps {
|
||||
vertical?: boolean;
|
||||
onChange?: (value: SliderValue) => void;
|
||||
onAfterChange?: (value: SliderValue) => void;
|
||||
tipFormatter?: void | ((value: number) => React.ReactNode);
|
||||
tipFormatter?: null | ((value: number) => React.ReactNode);
|
||||
className?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
@ -298,7 +298,7 @@
|
||||
|
||||
// Progress
|
||||
// --
|
||||
@process-default-color: @primary-color;
|
||||
@progress-default-color: @primary-color;
|
||||
@progress-remaining-color: @background-color-base;
|
||||
|
||||
// Menu
|
||||
|
@ -24,8 +24,10 @@ import moment from 'moment';
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| addon | called from timepicker panel to render some addon to its bottom | function | - |
|
||||
| allowEmpty | allow clearing text | boolean | true |
|
||||
| className | className of picker | string | '' |
|
||||
| defaultOpenValue | to highlight values in panel when there is no selected value | [moment](http://momentjs.com/) | moment() |
|
||||
| clearText | clear tooltip of icon | string | clear |
|
||||
| defaultOpenValue | default open panel value, used to set utcOffset,locale if value/defaultValue absent | [moment](http://momentjs.com/) | moment() |
|
||||
| defaultValue | to set default time | [moment](http://momentjs.com/) | - |
|
||||
| disabled | determine whether the TimePicker is disabled | boolean | false |
|
||||
| disabledHours | to specify the hours that cannot be selected | function() | - |
|
||||
|
@ -42,6 +42,10 @@ export interface TimePickerProps {
|
||||
hourStep?: number;
|
||||
minuteStep?: number;
|
||||
secondStep?: number;
|
||||
allowEmpty?: boolean;
|
||||
clearText?: string;
|
||||
defaultOpenValue?: moment.Moment;
|
||||
popupClassName?: string;
|
||||
}
|
||||
|
||||
export default class TimePicker extends React.Component<TimePickerProps, any> {
|
||||
|
@ -25,8 +25,10 @@ import moment from 'moment';
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| addon | 选择框底部显示自定义的内容 | function | 无 |
|
||||
| allowEmpty | 是否展示清除按钮 | boolean | true |
|
||||
| className | 选择器类名 | string | '' |
|
||||
| defaultOpenValue | 无选中值时,面板打开时高亮的值 | [moment](http://momentjs.com/) | moment() |
|
||||
| clearText | 清除按钮的提示文案 | string | clear |
|
||||
| defaultOpenValue | 当 defaultValue/value 不存在时,可以设置面板打开时默认选中的值 | [moment](http://momentjs.com/) | moment() |
|
||||
| defaultValue | 默认时间 | [moment](http://momentjs.com/) | 无 |
|
||||
| disabled | 禁用全部操作 | boolean | false |
|
||||
| disabledHours | 禁止选择部分小时选项 | function() | 无 |
|
||||
|
@ -130,10 +130,9 @@ import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
|
||||
## Links
|
||||
|
||||
- [Home Page](http://ant.design/)
|
||||
- [UI library](/docs/react/introduce)
|
||||
- [Components](/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [Change Log](/changelog)
|
||||
- [Official Scaffold Tool](https://github.com/dvajs/dva-cli/)
|
||||
- [Development Tool](http://ant-tool.github.io/)
|
||||
- [Scaffold Market](http://scaffold.ant.design)
|
||||
- [rc-components](http://react-component.github.io/)
|
||||
- [Mobile UI](http://mobile.ant.design)
|
||||
|
@ -133,10 +133,9 @@ import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
|
||||
## 链接
|
||||
|
||||
- [首页](http://ant.design/)
|
||||
- [UI 组件库](/docs/react/introduce)
|
||||
- [组件库](/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [更新日志](/changelog)
|
||||
- [官方脚手架](https://github.com/dvajs/dva-cli/)
|
||||
- [开发工具文档](http://ant-tool.github.io/)
|
||||
- [脚手架市场](http://scaffold.ant.design)
|
||||
- [React 底层基础组件](http://react-component.github.io/)
|
||||
- [移动端组件](http://mobile.ant.design)
|
||||
|
@ -25,6 +25,7 @@ Code highlight | [react-syntax-highlighter](https://github.com/conorhastings/rea
|
||||
Markdown renderer | [react-markdown](http://rexxars.github.io/react-markdown/)
|
||||
Infinite Scroll | [react-virtualized](https://github.com/bvaughn/react-virtualized)
|
||||
Map | [react-google-maps](https://github.com/tomchentw/react-google-maps) [google-map-react](https://github.com/istarkov/google-map-react) [react-amap](https://github.com/ElemeFE/react-amap)
|
||||
Emoji | [emoji-mart)](https://github.com/missive/emoji-mart)
|
||||
|
||||
<style>
|
||||
.markdown table td:first-child {
|
||||
|
@ -25,6 +25,7 @@ title: 社区精选组件
|
||||
Markdown 渲染 | [react-markdown](http://rexxars.github.io/react-markdown/)
|
||||
无限滚动 | [react-virtualized](https://github.com/bvaughn/react-virtualized)
|
||||
地图 | [react-google-maps](https://github.com/tomchentw/react-google-maps) [google-map-react](https://github.com/istarkov/google-map-react) [react-amap 高德](https://github.com/ElemeFE/react-amap)
|
||||
Emoji | [emoji-mart)](https://github.com/missive/emoji-mart)
|
||||
|
||||
<style>
|
||||
.markdown table td:first-child {
|
||||
|
@ -184,9 +184,9 @@ $ yarn add react-app-rewire-less --dev
|
||||
module.exports = function override(config, env) {
|
||||
- config = injectBabelPlugin(['import', { libraryName: 'antd', style: 'css' }], config);
|
||||
+ config = injectBabelPlugin(['import', { libraryName: 'antd', style: true }], config); // change importing css to less
|
||||
+ config = rewireLess(config, env, {
|
||||
+ config = rewireLess.withLoaderOptions({
|
||||
+ modifyVars: { "@primary-color": "#1DA57A" },
|
||||
+ });
|
||||
+ })(config, env);
|
||||
return config;
|
||||
};
|
||||
```
|
||||
|
@ -181,9 +181,9 @@ $ yarn add react-app-rewire-less --dev
|
||||
module.exports = function override(config, env) {
|
||||
- config = injectBabelPlugin(['import', { libraryName: 'antd', style: 'css' }], config);
|
||||
+ config = injectBabelPlugin(['import', { libraryName: 'antd', style: true }], config);
|
||||
+ config = rewireLess(config, env, {
|
||||
+ config = rewireLess.withLoaderOptions({
|
||||
+ modifyVars: { "@primary-color": "#1DA57A" },
|
||||
+ });
|
||||
+ })(config, env);
|
||||
return config;
|
||||
};
|
||||
```
|
||||
|
@ -170,6 +170,7 @@
|
||||
"lint-fix": "npm run lint-fix:code && npm run lint-fix:demo",
|
||||
"lint-fix:code": "eslint --fix tests site scripts components ./.eslintrc.js ./webpack.config.js --ext '.js,.jsx'",
|
||||
"lint-fix:demo": "eslint-tinker ./components/*/demo/*.md",
|
||||
"sort-api": "node ./scripts/sort-api-table.js",
|
||||
"dist": "antd-tools run dist",
|
||||
"compile": "antd-tools run compile",
|
||||
"tsc": "tsc",
|
||||
|
@ -75,13 +75,18 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.lang,
|
||||
.header-lang-button,
|
||||
.version {
|
||||
float: right;
|
||||
margin-top: 29px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.header-lang-button {
|
||||
color: @text-color;
|
||||
border-color: @border-color-base;
|
||||
}
|
||||
|
||||
.version {
|
||||
width: 66px;
|
||||
margin-left: 16px;
|
||||
|
@ -6,7 +6,7 @@ const branchUrl = 'https://github.com/ant-design/ant-design/edit/master/';
|
||||
export default function EditButton({ title, filename }) {
|
||||
return (
|
||||
<Tooltip title={title}>
|
||||
<a className="edit-button" href={`${branchUrl}${filename}`}>
|
||||
<a className="edit-button" href={`${branchUrl}${filename}`} target="_blank">
|
||||
<Icon type="edit" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
|
@ -30,6 +30,10 @@ function getStyle() {
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: border .5s cubic-bezier(0.455, 0.03, 0.515, 0.955), background .5s cubic-bezier(0.455, 0.03, 0.515, 0.955);
|
||||
}
|
||||
#header .header-lang-button {
|
||||
color: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
#header .ant-select-selection,
|
||||
#header .ant-menu {
|
||||
background: transparent;
|
||||
@ -37,6 +41,9 @@ function getStyle() {
|
||||
#header .ant-select-search__field {
|
||||
color: #eee;
|
||||
}
|
||||
#header .ant-select-arrow {
|
||||
color: #fff;
|
||||
}
|
||||
#header .ant-select-selection__placeholder {
|
||||
color: rgba(255,255,255,0.57);
|
||||
}
|
||||
@ -56,15 +63,18 @@ function getStyle() {
|
||||
.home-nav-white #nav a {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
.home-nav-white .lang:not(:hover) {
|
||||
#header.home-nav-white .header-lang-button:not(:hover) {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
border-color: rgba(0, 0, 0, 0.65);
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
.home-nav-white .version > .ant-select-selection {
|
||||
#header.home-nav-white .version > .ant-select-selection {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
.home-nav-white .version > .ant-select-selection:not(:hover) {
|
||||
border-color: rgba(0, 0, 0, 0.65);
|
||||
#header.home-nav-white .version > .ant-select-selection:not(:hover) {
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
#header.home-nav-white .version .ant-select-arrow {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
.nav-phone-icon:before {
|
||||
background: #eee;
|
||||
|
@ -93,6 +93,9 @@ class Footer extends React.Component {
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="http://pro.ant.design">Ant Design Pro</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="http://mobile.ant.design">Ant Design Mobile</a>
|
||||
</div>
|
||||
|
@ -155,7 +155,7 @@ export default class Header extends React.Component {
|
||||
});
|
||||
|
||||
const menu = [
|
||||
<Button className="lang" type="ghost" size="small" onClick={this.handleLangChange} key="lang">
|
||||
<Button className="header-lang-button" ghost size="small" onClick={this.handleLangChange} key="lang">
|
||||
<FormattedMessage id="app.header.lang" />
|
||||
</Button>,
|
||||
<Select
|
||||
@ -196,7 +196,12 @@ export default class Header extends React.Component {
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="pro">
|
||||
<a href="http://pro.ant.design" className="header-link">
|
||||
<a
|
||||
href="http://pro.ant.design"
|
||||
className="header-link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<FormattedMessage id="app.header.menu.pro" />
|
||||
<span style={{ display: 'inline-block', position: 'relative', top: -2, width: 18 }}>
|
||||
<Badge dot />
|
||||
|
Loading…
Reference in New Issue
Block a user