159 lines
2.9 KiB
Vue
159 lines
2.9 KiB
Vue
|
<template>
|
||
|
<div :style="cssVars">
|
||
|
<div class="rating" tabindex="0" @keyup="handleKeyUp">
|
||
|
<span v-for="i in index" :key="i" :class="{ checked: isChecked(i) }">
|
||
|
<input
|
||
|
:id="'rating' + componentId + '-' + i"
|
||
|
type="radio" name="rating" :value="i"
|
||
|
@click="setChecked(i)">
|
||
|
<label :for="'rating' + componentId + '-' + i" :aria-label="i"></label>
|
||
|
</span>
|
||
|
</div>
|
||
|
<div class="legend" aria-hidden="true">
|
||
|
<span>pas du tout</span>
|
||
|
<span>en partie</span>
|
||
|
<span>totalement</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script lang="ts">
|
||
|
|
||
|
import {Component, Prop, Vue} from "nuxt-property-decorator";
|
||
|
|
||
|
@Component
|
||
|
export default class Rating extends Vue {
|
||
|
|
||
|
@Prop({
|
||
|
type: String,
|
||
|
default: "#DC6A00"
|
||
|
})
|
||
|
readonly color !: string;
|
||
|
|
||
|
|
||
|
@Prop({
|
||
|
type: Number,
|
||
|
required: false
|
||
|
})
|
||
|
readonly initialValue !: number | undefined;
|
||
|
|
||
|
readonly MAX_VALUE = 10;
|
||
|
|
||
|
created() {
|
||
|
if (this.initialValue) {
|
||
|
this.checkedValue = this.initialValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
readonly index = Array.apply(0, Array(this.MAX_VALUE)).map((_, b) => {
|
||
|
return b + 1;
|
||
|
}).reverse();
|
||
|
|
||
|
public checkedValue = 0;
|
||
|
private _uid: any;
|
||
|
|
||
|
public setChecked(index: number) {
|
||
|
if (index < 1) {
|
||
|
index = 1;
|
||
|
} else if (index > this.MAX_VALUE) {
|
||
|
index = this.MAX_VALUE;
|
||
|
}
|
||
|
this.checkedValue = index;
|
||
|
this.$emit('rate', index);
|
||
|
}
|
||
|
|
||
|
public increment() {
|
||
|
this.setChecked(this.checkedValue + 1);
|
||
|
}
|
||
|
|
||
|
public decrement() {
|
||
|
this.setChecked(this.checkedValue - 1);
|
||
|
}
|
||
|
|
||
|
public isChecked(index: number) {
|
||
|
return this.checkedValue >= index;
|
||
|
}
|
||
|
|
||
|
get componentId() {
|
||
|
return this._uid;
|
||
|
}
|
||
|
|
||
|
handleKeyUp(event: KeyboardEvent) {
|
||
|
switch (event.key) {
|
||
|
case "ArrowLeft":
|
||
|
this.decrement();
|
||
|
break;
|
||
|
case "ArrowRight":
|
||
|
this.increment();
|
||
|
break;
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
get cssVars() {
|
||
|
return {
|
||
|
'--color': this.color
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<style lang="scss" scoped>
|
||
|
|
||
|
@import "assets/css/color";
|
||
|
@import "assets/css/spacing";
|
||
|
@import "assets/css/font";
|
||
|
|
||
|
$width: 401px;
|
||
|
$input_width: 32px;
|
||
|
|
||
|
.rating {
|
||
|
display: flex;
|
||
|
justify-content: space-around;
|
||
|
flex-direction: row-reverse;
|
||
|
max-width: $width;
|
||
|
}
|
||
|
|
||
|
.rating span {
|
||
|
position: relative;
|
||
|
}
|
||
|
|
||
|
.rating span input {
|
||
|
position: absolute;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
opacity: 0;
|
||
|
}
|
||
|
|
||
|
.rating span label {
|
||
|
display: inline-block;
|
||
|
width: $input_width;
|
||
|
height: $input_width;
|
||
|
color: $white;
|
||
|
line-height: $input_width;
|
||
|
border-radius: 50%;
|
||
|
border: 1px solid $black;
|
||
|
}
|
||
|
|
||
|
.rating span:hover ~ span label,
|
||
|
.rating span:hover label,
|
||
|
.rating span.checked label,
|
||
|
.rating span.checked ~ span label {
|
||
|
background-color: var(--color);
|
||
|
color: #FFF;
|
||
|
border: 0;
|
||
|
cursor: pointer;
|
||
|
width: $input_width;
|
||
|
}
|
||
|
|
||
|
.legend {
|
||
|
display: flex;
|
||
|
justify-content: space-between;
|
||
|
max-width: $width;
|
||
|
color: $gray_3;
|
||
|
font-weight: 400;
|
||
|
font-size: $small-font-size;
|
||
|
}
|
||
|
</style>
|