122 lines
2.8 KiB
Vue
122 lines
2.8 KiB
Vue
<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>
|