Add rating scale component
This commit is contained in:
parent
1183e0c016
commit
e86c36248c
|
|
@ -1,5 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: {
|
plugins: {
|
||||||
|
"postcss-import": {},
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
type RGB = [number, number, number];
|
||||||
|
const red: RGB = [221, 103, 81]; // red-600
|
||||||
|
const yellow: RGB = [250, 200, 82]; // yellow-500
|
||||||
|
const lightGreen: RGB = [120, 222, 163]; // green-500
|
||||||
|
const darkGreen: RGB = [91, 183, 130]; // green-600
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rating: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const weight = computed(() => {
|
||||||
|
return props.rating % 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
const scale = computed(() => {
|
||||||
|
return Math.floor(props.rating);
|
||||||
|
});
|
||||||
|
|
||||||
|
const colors = computed(() => {
|
||||||
|
switch (scale.value) {
|
||||||
|
case 1:
|
||||||
|
return [red, yellow];
|
||||||
|
case 2:
|
||||||
|
return [yellow, lightGreen];
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
return [lightGreen, darkGreen];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const blendColorValue = (v1: number, v2: number, weight: number) => {
|
||||||
|
return v1 * weight + v2 * (1 - weight);
|
||||||
|
};
|
||||||
|
|
||||||
|
const blendColors = (c1: RGB, c2: RGB, weight: number): RGB => {
|
||||||
|
const [r1, g1, b1] = c1;
|
||||||
|
const [r2, g2, b2] = c2;
|
||||||
|
return [
|
||||||
|
blendColorValue(r1, r2, weight),
|
||||||
|
blendColorValue(g1, g2, weight),
|
||||||
|
blendColorValue(b1, b2, weight),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRGBString = ([r, g, b]: RGB) => {
|
||||||
|
return `rgb(${Math.floor(r)}, ${Math.floor(g)}, ${Math.floor(b)})`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRGBStyle = (c1: RGB, c2: RGB, weight: number) => {
|
||||||
|
return getRGBString(blendColors(c1, c2, weight));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLeftPosition = (rating:number, weight: number) => {
|
||||||
|
const percent = (rating - 1) * 33 + weight * 25;
|
||||||
|
return `${Math.floor(percent)}%`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
backgroundColor: getRGBStyle(colors.value[0], colors.value[1], weight.value),
|
||||||
|
left: getLeftPosition(scale.value, weight.value),
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(props);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h3>{{ props.rating }} - {{ weight }} = {{style}}</h3>
|
||||||
|
<div class="gradient-with-circle pt-3 relative">
|
||||||
|
<!-- <div -->
|
||||||
|
<!-- class="circle" -->
|
||||||
|
<!-- :style="{ -->
|
||||||
|
<!-- backgroundColor: getRGBStyle(yellow, red, 0.5), -->
|
||||||
|
<!-- left: getLeftPosition(0.5), -->
|
||||||
|
<!-- }" -->
|
||||||
|
<!-- ></div> -->
|
||||||
|
<!-- <div -->
|
||||||
|
<!-- class="circle" -->
|
||||||
|
<!-- :style="{ -->
|
||||||
|
<!-- backgroundColor: getRGBStyle(yellow, red, 0.25), -->
|
||||||
|
<!-- left: getLeftPosition(0.25), -->
|
||||||
|
<!-- }" -->
|
||||||
|
<!-- ></div> -->
|
||||||
|
<div class="circle" :style="style"></div>
|
||||||
|
<div class="h-2 gradient"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.circle {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 32px;
|
||||||
|
position: absolute;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
top: 0;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle:before {
|
||||||
|
content: "";
|
||||||
|
background-color: white;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient {
|
||||||
|
background-color: theme(colors.yellow.400);
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
theme(colors.red.600) 0%,
|
||||||
|
theme(colors.yellow.500) 33%,
|
||||||
|
theme(colors.green.500) 66%,
|
||||||
|
theme(colors.green.600) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -7,6 +7,7 @@ import ItDropdown from "@/components/ui/ItDropdown.vue";
|
||||||
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
import ItRadioGroup from "@/components/ui/ItRadioGroup.vue";
|
import ItRadioGroup from "@/components/ui/ItRadioGroup.vue";
|
||||||
import ItTextarea from "@/components/ui/ItTextarea.vue";
|
import ItTextarea from "@/components/ui/ItTextarea.vue";
|
||||||
|
import RatingScale from "@/components/ui/RatingScale.vue";
|
||||||
import logger from "loglevel";
|
import logger from "loglevel";
|
||||||
import { reactive, ref } from "vue";
|
import { reactive, ref } from "vue";
|
||||||
|
|
||||||
|
|
@ -424,6 +425,13 @@ function log(data: any) {
|
||||||
:label="satisfactionText"
|
:label="satisfactionText"
|
||||||
:items="satisfactionValues"
|
:items="satisfactionValues"
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
|
<RatingScale :rating="1" />
|
||||||
|
<RatingScale :rating="1.3" />
|
||||||
|
<RatingScale :rating="2.5" />
|
||||||
|
<RatingScale :rating="3.9" />
|
||||||
|
<RatingScale :rating="4" />
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue