All files / components/base BaseSpinner.vue

100% Statements 43/43
100% Branches 0/0
100% Functions 0/0
100% Lines 43/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71  1x 1x 1x 1x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                     1x         1x 1x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x    
<template>
  <div :class="spinnerClasses">
    <svg
      :class="[sizeClasses, 'text-primary-600']"
      class="animate-spin"
      fill="none"
      viewBox="0 0 24 24"
    >
      <circle
        class="opacity-25"
        cx="12"
        cy="12"
        r="10"
        stroke="currentColor"
        stroke-width="4"
      />
      <path
        class="opacity-75"
        fill="currentColor"
        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
      />
    </svg>
    <span v-if="text" :class="textClasses">{{ text }}</span>
  </div>
</template>
 
<script setup lang="ts">
/**
 * BaseSpinner
 * @description Loading spinner component with optional text
 * Can be used inline or centered
 */
 
interface Props {
  /** Size of the spinner */
  size?: 'sm' | 'md' | 'lg'
  /** Optional loading text */
  text?: string
  /** Center the spinner */
  center?: boolean
}
 
const props = withDefaults(defineProps<Props>(), {
  size: 'md',
  center: false
})
 
const spinnerClasses = computed(() => [
  'flex items-center gap-2',
  props.center ? 'justify-center' : ''
])
 
const sizeClasses = computed(() => {
  const sizes = {
    sm: 'h-4 w-4',
    md: 'h-8 w-8',
    lg: 'h-12 w-12'
  }
  return sizes[props.size]
})
 
const textClasses = computed(() => {
  const textSizes = {
    sm: 'text-sm',
    md: 'text-base',
    lg: 'text-lg'
  }
  return [textSizes[props.size], 'text-secondary-600']
})
</script>