Add rating scale component

This commit is contained in:
Ramon Wenger 2023-01-17 16:34:57 +01:00 committed by Christian Cueni
parent 1183e0c016
commit e86c36248c
3 changed files with 130 additions and 0 deletions

View File

@ -1,5 +1,6 @@
module.exports = {
plugins: {
"postcss-import": {},
tailwindcss: {},
autoprefixer: {},
},

View File

@ -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>

View File

@ -7,6 +7,7 @@ import ItDropdown from "@/components/ui/ItDropdown.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import ItRadioGroup from "@/components/ui/ItRadioGroup.vue";
import ItTextarea from "@/components/ui/ItTextarea.vue";
import RatingScale from "@/components/ui/RatingScale.vue";
import logger from "loglevel";
import { reactive, ref } from "vue";
@ -424,6 +425,13 @@ function log(data: any) {
:label="satisfactionText"
:items="satisfactionValues"
/>
<div>
<RatingScale :rating="1" />
<RatingScale :rating="1.3" />
<RatingScale :rating="2.5" />
<RatingScale :rating="3.9" />
<RatingScale :rating="4" />
</div>
</main>
</template>