Skip to content
Snippets Groups Projects
Commit c0411348 authored by Konrad Mohrfeldt's avatar Konrad Mohrfeldt :koala:
Browse files

feat: add ACircularProgress component

parent 9fac4906
No related branches found
No related tags found
No related merge requests found
<template>
<div
:aria-valuemax="max"
:aria-valuemin="min"
:aria-valuenow="progress !== 'indeterminate' ? progress : undefined"
:aria-valuetext="
percentage ? `${percentage.toLocaleString(locale, { maximumFractionDigits: 2 })}%` : undefined
"
role="progressbar"
>
<svg
class="tw-aspect-square tw-max-w-full tw-max-h-full"
height="120"
viewBox="0 0 120 120"
width="120"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<g class="circle" :class="{ indeterminate: progress === 'indeterminate' }">
<circle class="track" cx="60" cy="60" fill="none" r="54" stroke-width="12" />
<circle
class="value"
:stroke-dashoffset="dashOffset"
cx="60"
cy="60"
fill="none"
pathLength="100"
r="54"
stroke="currentColor"
stroke-dasharray="100"
stroke-width="12"
/>
</g>
<text
v-if="percentage"
x="50%"
y="52.5%"
dominant-baseline="middle"
text-anchor="middle"
font-size="200%"
>
{{ `${Math.round(percentage)}%` }}
</text>
</g>
</svg>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useI18n } from '@/i18n'
const progress = defineModel<number | 'indeterminate'>('progress', { required: true })
const props = withDefaults(
defineProps<{
min?: number
max?: number
}>(),
{
min: 0,
max: 100,
},
)
const { locale } = useI18n()
const percentage = computed(() => {
if (progress.value === 'indeterminate') return null
if (progress.value < props.min) {
return 0
} else if (progress.value > props.max) {
return 100
}
return ((progress.value - props.min) / (props.max - props.min)) * 100
})
const dashOffset = computed(() => 100 - (percentage.value ?? 0))
</script>
<style lang="postcss" scoped>
.track {
stroke: theme('colors.gray.100');
stroke: color-mix(in oklab, currentColor 15%, transparent 10%);
}
.value {
transition: stroke-dashoffset 0.2s;
}
.circle {
@apply tw-origin-center;
&:not(.indeterminate) {
@apply tw-translate-x-0 tw-translate-y-0 tw-skew-x-0 tw-skew-y-0 tw-scale-100 -tw-rotate-90;
}
&.indeterminate {
animation: tw-spin 1s linear infinite;
& > .value {
animation: stretch 3s linear infinite;
}
}
}
@keyframes stretch {
0%,
50%,
100% {
stroke-dashoffset: 90;
}
25%,
75% {
stroke-dashoffset: 65;
}
}
</style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment