mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[new feature] Circle: support gradient color (#4157)
This commit is contained in:
parent
a3712f7c5b
commit
b7244f8fa9
@ -37,20 +37,72 @@ export default {
|
||||
};
|
||||
```
|
||||
|
||||
### Custom style
|
||||
### Custom Width
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
color="#07c160"
|
||||
fill="#fff"
|
||||
size="120px"
|
||||
layer-color="#ebedf0"
|
||||
:text="text"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
:clockwise="false"
|
||||
:stroke-width="60"
|
||||
text="Custom Width"
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom Color
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
layer-color="#ebedf0"
|
||||
text="Custom Color"
|
||||
/>
|
||||
```
|
||||
|
||||
### Gradient
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
:color="gradientColor"
|
||||
text="Gradient"
|
||||
/>
|
||||
```
|
||||
|
||||
``` javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentRate: 0,
|
||||
gradientColor: {
|
||||
'0%': '#ffd01e',
|
||||
'100%': '#ee0a24'
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Counter Clockwise
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
:clockwise="false"
|
||||
text="Counter Clockwise"
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom Size
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
size="120px"
|
||||
text="Custom Size"
|
||||
/>
|
||||
```
|
||||
|
||||
@ -63,7 +115,7 @@ export default {
|
||||
| v-model | Current rate | `number` | - |
|
||||
| rate | Target rate | `number` | `100` |
|
||||
| size | Circle size | `string` | `100px` |
|
||||
| color | Progress bar color | `string` | `#1989fa` |
|
||||
| color | Progress color, passing object to render gradient | `string | object` | `#1989fa` |
|
||||
| layer-color | Layer color | `string` | `#fff` |
|
||||
| fill | Fill color | `string` | `none` |
|
||||
| speed | Animate speed(rate/s)| `number` | `0` |
|
||||
|
@ -39,20 +39,82 @@ export default {
|
||||
};
|
||||
```
|
||||
|
||||
### 样式定制
|
||||
### 宽度定制
|
||||
|
||||
通过`stroke-width`属性来控制进度条宽度
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
color="#07c160"
|
||||
fill="#fff"
|
||||
size="120px"
|
||||
layer-color="#ebedf0"
|
||||
:text="text"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
:clockwise="false"
|
||||
:stroke-width="60"
|
||||
text="宽度定制"
|
||||
/>
|
||||
```
|
||||
|
||||
### 颜色定制
|
||||
|
||||
通过`color`属性来控制进度条颜色,`layer-color`属性来控制轨道颜色
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
layer-color="#ebedf0"
|
||||
text="颜色定制"
|
||||
/>
|
||||
```
|
||||
|
||||
### 渐变色
|
||||
|
||||
`color`属性支持传入对象格式来定义渐变色
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
:color="gradientColor"
|
||||
text="渐变色"
|
||||
/>
|
||||
```
|
||||
|
||||
``` javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentRate: 0,
|
||||
gradientColor: {
|
||||
'0%': '#ffd01e',
|
||||
'100%': '#ee0a24'
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 逆时针方向
|
||||
|
||||
将`clockwise`设置为`false`,进度会从逆时针方向开始
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
:clockwise="false"
|
||||
text="逆时针方向"
|
||||
/>
|
||||
```
|
||||
|
||||
### 大小定制
|
||||
|
||||
通过`size`属性设置圆环直径
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="rate"
|
||||
size="120px"
|
||||
text="大小定制"
|
||||
/>
|
||||
```
|
||||
|
||||
@ -65,7 +127,7 @@ export default {
|
||||
| v-model | 当前进度 | `number` | - | - |
|
||||
| rate | 目标进度 | `number` | `100` | - |
|
||||
| size | 圆环直径 | `string` | `100px` | - |
|
||||
| color | 进度条颜色 | `string` | `#1989fa` | - |
|
||||
| color | 进度条颜色,传入对象格式可以定义渐变色 | `string | object` | `#1989fa` | 2.1.4 |
|
||||
| layer-color | 轨道颜色 | `string` | `#fff` | - |
|
||||
| fill | 填充颜色 | `string` | `none` | - |
|
||||
| speed | 动画速度(单位为 rate/s)| `number` | `0` | - |
|
||||
|
@ -5,39 +5,73 @@
|
||||
v-model="currentRate1"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
size="120px"
|
||||
:text="currentRate1.toFixed(0) + '%'"
|
||||
/>
|
||||
<div>
|
||||
<van-button
|
||||
:text="$t('add')"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="add"
|
||||
/>
|
||||
<van-button
|
||||
:text="$t('decrease')"
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="reduce"
|
||||
/>
|
||||
</div>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('customStyle')">
|
||||
<van-circle
|
||||
v-model="currentRate2"
|
||||
color="#07c160"
|
||||
fill="#fff"
|
||||
v-model="currentRate3"
|
||||
:rate="rate"
|
||||
size="120px"
|
||||
layer-color="#ebedf0"
|
||||
:speed="100"
|
||||
:stroke-width="60"
|
||||
:text="$t('customWidth')"
|
||||
/>
|
||||
|
||||
<van-circle
|
||||
v-model="currentRate3"
|
||||
color="#f44"
|
||||
:rate="rate"
|
||||
layer-color="#ebedf0"
|
||||
:speed="100"
|
||||
:text="$t('customColor')"
|
||||
/>
|
||||
|
||||
<van-circle
|
||||
v-model="currentRate2"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
:color="gradientColor"
|
||||
:text="$t('gradient')"
|
||||
/>
|
||||
|
||||
<van-circle
|
||||
v-model="currentRate4"
|
||||
color="#07c160"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
:clockwise="false"
|
||||
:text="currentRate2.toFixed(0) + '%'"
|
||||
:text="$t('counterClockwise')"
|
||||
style="margin-top: 15px;"
|
||||
/>
|
||||
|
||||
<van-circle
|
||||
v-model="currentRate4"
|
||||
color="#7232dd"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
size="120px"
|
||||
:clockwise="false"
|
||||
:text="$t('customSize')"
|
||||
style="margin-top: 15px;"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<div style="margin-top: 15px;">
|
||||
<van-button
|
||||
:text="$t('add')"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="add"
|
||||
/>
|
||||
<van-button
|
||||
:text="$t('decrease')"
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="reduce"
|
||||
/>
|
||||
</div>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
@ -47,18 +81,34 @@ const format = rate => Math.min(Math.max(rate, 0), 100);
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
customStyle: '样式定制'
|
||||
gradient: '渐变色',
|
||||
customSize: '大小定制',
|
||||
customStyle: '样式定制',
|
||||
customColor: '颜色定制',
|
||||
customWidth: '宽度定制',
|
||||
counterClockwise: '逆时针'
|
||||
},
|
||||
'en-US': {
|
||||
customStyle: 'Custom Style'
|
||||
gradient: 'Gradient',
|
||||
customSize: 'Custom Size',
|
||||
customStyle: 'Custom Style',
|
||||
customColor: 'Custom Color',
|
||||
customWidth: 'Custom Width',
|
||||
counterClockwise: 'Counter Clockwise'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
rate: 30,
|
||||
currentRate1: 30,
|
||||
currentRate2: 30
|
||||
rate: 70,
|
||||
currentRate1: 70,
|
||||
currentRate2: 70,
|
||||
currentRate3: 70,
|
||||
currentRate4: 70,
|
||||
gradientColor: {
|
||||
'0%': '#ffd01e',
|
||||
'100%': '#ee0a24'
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -1,15 +1,22 @@
|
||||
import { createNamespace } from '../utils';
|
||||
import { createNamespace, isObj } from '../utils';
|
||||
import { raf, cancelRaf } from '../utils/dom/raf';
|
||||
import { BLUE, WHITE } from '../utils/constant';
|
||||
|
||||
const [createComponent, bem] = createNamespace('circle');
|
||||
|
||||
const PERIMETER = 3140;
|
||||
const PATH = 'M 530 530 m -500, 0 a 500, 500 0 1, 1 1000, 0 a 500, 500 0 1, 1 -1000, 0';
|
||||
|
||||
let uid = 0;
|
||||
|
||||
function format(rate) {
|
||||
return Math.min(Math.max(rate, 0), 100);
|
||||
}
|
||||
|
||||
function getPath(clockwise) {
|
||||
const sweepFlag = clockwise ? 1 : 0;
|
||||
return `M 530 530 m 0, -500 a 500, 500 0 1, ${sweepFlag} 0, 1000 a 500, 500 0 1, ${sweepFlag} 0, -1000`;
|
||||
}
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
text: String,
|
||||
@ -38,7 +45,7 @@ export default createComponent({
|
||||
default: WHITE
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
type: [String, Object],
|
||||
default: BLUE
|
||||
},
|
||||
strokeWidth: {
|
||||
@ -51,6 +58,10 @@ export default createComponent({
|
||||
}
|
||||
},
|
||||
|
||||
beforeCreate() {
|
||||
this.uid = `van-circle-gradient-${uid++}`;
|
||||
},
|
||||
|
||||
computed: {
|
||||
style() {
|
||||
return {
|
||||
@ -59,14 +70,17 @@ export default createComponent({
|
||||
};
|
||||
},
|
||||
|
||||
path() {
|
||||
return getPath(this.clockwise);
|
||||
},
|
||||
|
||||
layerStyle() {
|
||||
let offset = (PERIMETER * (100 - this.value)) / 100;
|
||||
offset = this.clockwise ? offset : PERIMETER * 2 - offset;
|
||||
const offset = (PERIMETER * this.value) / 100;
|
||||
|
||||
return {
|
||||
stroke: `${this.color}`,
|
||||
strokeDashoffset: `${offset}px`,
|
||||
strokeWidth: `${this.strokeWidth + 1}px`
|
||||
strokeWidth: `${this.strokeWidth + 1}px`,
|
||||
strokeDasharray: `${offset}px ${PERIMETER}px`
|
||||
};
|
||||
},
|
||||
|
||||
@ -76,6 +90,30 @@ export default createComponent({
|
||||
stroke: `${this.layerColor}`,
|
||||
strokeWidth: `${this.strokeWidth}px`
|
||||
};
|
||||
},
|
||||
|
||||
gradient() {
|
||||
return isObj(this.color);
|
||||
},
|
||||
|
||||
LinearGradient() {
|
||||
if (!this.gradient) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Stops = Object.keys(this.color)
|
||||
.sort((a, b) => parseFloat(a) - parseFloat(b))
|
||||
.map((key, index) => (
|
||||
<stop key={index} offset={key} stop-color={this.color[key]} />
|
||||
));
|
||||
|
||||
return (
|
||||
<defs>
|
||||
<linearGradient id={this.uid} x1="100%" y1="0%" x2="0%" y2="0%">
|
||||
{Stops}
|
||||
</linearGradient>
|
||||
</defs>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@ -116,8 +154,14 @@ export default createComponent({
|
||||
return (
|
||||
<div class={bem()} style={this.style}>
|
||||
<svg viewBox="0 0 1060 1060">
|
||||
<path class={bem('hover')} style={this.hoverStyle} d={PATH} />
|
||||
<path class={bem('layer')} style={this.layerStyle} d={PATH} />
|
||||
{this.LinearGradient}
|
||||
<path class={bem('hover')} style={this.hoverStyle} d={this.path} />
|
||||
<path
|
||||
d={this.path}
|
||||
class={bem('layer')}
|
||||
style={this.layerStyle}
|
||||
stroke={this.gradient ? `url(#${this.uid})` : this.color}
|
||||
/>
|
||||
</svg>
|
||||
{this.slots() || (this.text && <div class={bem('text')}>{this.text}</div>)}
|
||||
</div>
|
||||
|
@ -14,14 +14,11 @@
|
||||
}
|
||||
|
||||
&__layer {
|
||||
transform: rotate(90deg);
|
||||
// should not use transform-origin: center
|
||||
// that will cause incorrect style in android devices
|
||||
transform-origin: 530px 530px;
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 3140;
|
||||
stroke-dashoffset: 3140;
|
||||
}
|
||||
|
||||
&__text {
|
||||
|
@ -3,21 +3,51 @@
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div class="van-circle" style="width: 120px; height: 120px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m -500, 0 a 500, 500 0 1, 1 1000, 0 a 500, 500 0 1, 1 -1000, 0" class="van-circle__hover" style="fill: none; stroke: #fff; stroke-width: 40px;"></path>
|
||||
<path d="M 530 530 m -500, 0 a 500, 500 0 1, 1 1000, 0 a 500, 500 0 1, 1 -1000, 0" class="van-circle__layer" style="stroke: #1989fa; stroke-dashoffset: 2198px; stroke-width: 41px;"></path>
|
||||
<div class="van-circle" style="width: 100px; height: 100px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" class="van-circle__hover" style="fill: none; stroke: #fff; stroke-width: 40px;"></path>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" stroke="#1989fa" class="van-circle__layer" style="stroke: #1989fa; stroke-width: 41px; stroke-dasharray: 2198px 3140px;"></path>
|
||||
</svg>
|
||||
<div class="van-circle__text">30%</div>
|
||||
<div class="van-circle__text">70%</div>
|
||||
</div>
|
||||
<div><button class="van-button van-button--primary van-button--small"><span class="van-button__text">增加</span></button> <button class="van-button van-button--danger van-button--small"><span class="van-button__text">减少</span></button></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-circle" style="width: 120px; height: 120px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m -500, 0 a 500, 500 0 1, 1 1000, 0 a 500, 500 0 1, 1 -1000, 0" class="van-circle__hover" style="fill: #fff; stroke: #ebedf0; stroke-width: 60px;"></path>
|
||||
<path d="M 530 530 m -500, 0 a 500, 500 0 1, 1 1000, 0 a 500, 500 0 1, 1 -1000, 0" class="van-circle__layer" style="stroke: #07c160; stroke-dashoffset: 4082px; stroke-width: 61px;"></path>
|
||||
<div class="van-circle" style="width: 100px; height: 100px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" class="van-circle__hover" style="fill: none; stroke: #ebedf0; stroke-width: 60px;"></path>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" stroke="#1989fa" class="van-circle__layer" style="stroke: #1989fa; stroke-width: 61px; stroke-dasharray: 2198px 3140px;"></path>
|
||||
</svg>
|
||||
<div class="van-circle__text">30%</div>
|
||||
<div class="van-circle__text">宽度定制</div>
|
||||
</div>
|
||||
<div class="van-circle" style="width: 100px; height: 100px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" class="van-circle__hover" style="fill: none; stroke: #ebedf0; stroke-width: 40px;"></path>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" stroke="#f44" class="van-circle__layer" style="stroke: #f44; stroke-width: 41px; stroke-dasharray: 2198px 3140px;"></path>
|
||||
</svg>
|
||||
<div class="van-circle__text">颜色定制</div>
|
||||
</div>
|
||||
<div class="van-circle" style="width: 100px; height: 100px;"><svg viewBox="0 0 1060 1060">
|
||||
<defs>
|
||||
<linearGradient id="van-circle-gradient-3" x1="100%" y1="0%" x2="0%" y2="0%">
|
||||
<stop offset="0%" stop-color="#ffd01e"></stop>
|
||||
<stop offset="100%" stop-color="#ee0a24"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" class="van-circle__hover" style="fill: none; stroke: #fff; stroke-width: 40px;"></path>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" stroke="url(#van-circle-gradient-3)" class="van-circle__layer" style="stroke: [object Object]; stroke-width: 41px; stroke-dasharray: 2198px 3140px;"></path>
|
||||
</svg>
|
||||
<div class="van-circle__text">渐变色</div>
|
||||
</div>
|
||||
<div class="van-circle" style="width: 100px; height: 100px; margin-top: 15px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 0 0, 1000 a 500, 500 0 1, 0 0, -1000" class="van-circle__hover" style="fill: none; stroke: #fff; stroke-width: 40px;"></path>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 0 0, 1000 a 500, 500 0 1, 0 0, -1000" stroke="#07c160" class="van-circle__layer" style="stroke: #07c160; stroke-width: 41px; stroke-dasharray: 2198px 3140px;"></path>
|
||||
</svg>
|
||||
<div class="van-circle__text">逆时针</div>
|
||||
</div>
|
||||
<div class="van-circle" style="width: 120px; height: 120px; margin-top: 15px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 0 0, 1000 a 500, 500 0 1, 0 0, -1000" class="van-circle__hover" style="fill: none; stroke: #fff; stroke-width: 40px;"></path>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 0 0, 1000 a 500, 500 0 1, 0 0, -1000" stroke="#7232dd" class="van-circle__layer" style="stroke: #7232dd; stroke-width: 41px; stroke-dasharray: 2198px 3140px;"></path>
|
||||
</svg>
|
||||
<div class="van-circle__text">大小定制</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 15px;"><button class="van-button van-button--primary van-button--small"><span class="van-button__text">增加</span></button> <button class="van-button van-button--danger van-button--small"><span class="van-button__text">减少</span></button></div>
|
||||
</div>
|
||||
`;
|
||||
|
8
src/circle/test/__snapshots__/index.spec.js.snap
Normal file
8
src/circle/test/__snapshots__/index.spec.js.snap
Normal file
@ -0,0 +1,8 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`speed is 0 1`] = `
|
||||
<div class="van-circle" style="width: 100px; height: 100px;"><svg viewBox="0 0 1060 1060">
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" class="van-circle__hover" style="fill: none; stroke: #fff; stroke-width: 40px;"></path>
|
||||
<path d="M 530 530 m 0, -500 a 500, 500 0 1, 1 0, 1000 a 500, 500 0 1, 1 0, -1000" stroke="#1989fa" class="van-circle__layer" style="stroke: #1989fa; stroke-width: 41px; stroke-dasharray: 1570px 3140px;"></path>
|
||||
</svg></div>
|
||||
`;
|
39
src/circle/test/index.spec.js
Normal file
39
src/circle/test/index.spec.js
Normal file
@ -0,0 +1,39 @@
|
||||
import Vue from 'vue';
|
||||
import Circle from '..';
|
||||
import { mount, later } from '../../../test/utils';
|
||||
|
||||
test('speed is 0', async () => {
|
||||
const wrapper = mount(Circle, {
|
||||
propsData: {
|
||||
rate: 50,
|
||||
value: 0
|
||||
},
|
||||
listeners: {
|
||||
input(value) {
|
||||
Vue.nextTick(() => {
|
||||
wrapper.setProps({ value });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await later();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('animate', async () => {
|
||||
const onInput = jest.fn();
|
||||
mount(Circle, {
|
||||
propsData: {
|
||||
rate: 50,
|
||||
speed: 100
|
||||
},
|
||||
listeners: {
|
||||
input: onInput
|
||||
}
|
||||
});
|
||||
|
||||
await later(50);
|
||||
expect(onInput).toHaveBeenCalled();
|
||||
expect(onInput.mock.calls[0][0]).not.toEqual(0);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user