|
| 1 | +<script setup lang="ts"> |
| 2 | +type Theme = 'blue' | 'default' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow' |
| 3 | +
|
| 4 | +const props = withDefaults(defineProps<{ |
| 5 | + activeFramework?: string |
| 6 | + frameworks?: string |
| 7 | + icon?: string |
| 8 | + image?: string |
| 9 | + logo?: string |
| 10 | + logoImage?: string |
| 11 | + name: string |
| 12 | + theme?: Theme |
| 13 | +}>(), { |
| 14 | + activeFramework: undefined, |
| 15 | + frameworks: undefined, |
| 16 | + icon: undefined, |
| 17 | + image: undefined, |
| 18 | + logo: undefined, |
| 19 | + logoImage: undefined, |
| 20 | + theme: 'default', |
| 21 | +}) |
| 22 | +
|
| 23 | +const themes: Record<Theme, string> = { |
| 24 | + default: 'border-gray-500/25 bg-gray-500/10 text-gray-600 shadow-gray-500/20 dark:text-gray-300', |
| 25 | + green: 'border-green-500/25 bg-green-500/10 text-green-700 shadow-green-500/20 dark:text-green-300', |
| 26 | + teal: 'border-teal-500/25 bg-teal-500/10 text-teal-700 shadow-teal-500/20 dark:text-teal-300', |
| 27 | + blue: 'border-blue-500/25 bg-blue-500/10 text-blue-700 shadow-blue-500/20 dark:text-blue-300', |
| 28 | + red: 'border-red-500/25 bg-red-500/10 text-red-700 shadow-red-500/20 dark:text-red-300', |
| 29 | + pink: 'border-pink-500/25 bg-pink-500/10 text-pink-700 shadow-pink-500/20 dark:text-pink-300', |
| 30 | + yellow: 'border-yellow-500/25 bg-yellow-500/10 text-yellow-700 shadow-yellow-500/20 dark:text-yellow-300', |
| 31 | + purple: 'border-purple-500/25 bg-purple-500/10 text-purple-700 shadow-purple-500/20 dark:text-purple-300', |
| 32 | + orange: 'border-orange-500/25 bg-orange-500/10 text-orange-700 shadow-orange-500/20 dark:text-orange-300', |
| 33 | +} |
| 34 | +
|
| 35 | +const supportedFrameworks = computed(() => props.frameworks?.split(' ') ?? []) |
| 36 | +const highlighted = computed(() => !!props.activeFramework |
| 37 | + && (props.activeFramework === 'your' |
| 38 | + || !props.frameworks |
| 39 | + || supportedFrameworks.value.includes(props.activeFramework))) |
| 40 | +const dimmed = computed(() => !!props.activeFramework && !highlighted.value) |
| 41 | +</script> |
| 42 | + |
| 43 | +<template> |
| 44 | + <div |
| 45 | + :title="name" |
| 46 | + tabindex="0" |
| 47 | + class="relative box-border flex h-20 w-20 min-w-0 flex-col items-center justify-center gap-2 rounded-xl border p-2 outline-none transition-all duration-300 ease-out hover:z-10 hover:-translate-y-0.5 hover:shadow-lg focus-visible:z-10 focus-visible:-translate-y-0.5 focus-visible:ring-2 focus-visible:ring-current/40 focus-visible:shadow-lg max-md:h-10 max-md:w-28 max-md:flex-row" |
| 48 | + :class="[ |
| 49 | + themes[theme], |
| 50 | + dimmed && 'opacity-20', |
| 51 | + highlighted && '-translate-y-0.5 shadow-lg', |
| 52 | + ]" |
| 53 | + > |
| 54 | + <img |
| 55 | + v-if="image" |
| 56 | + :src="image" |
| 57 | + alt="" |
| 58 | + class="size-7 flex-none object-contain" |
| 59 | + > |
| 60 | + <UIcon |
| 61 | + v-else |
| 62 | + :name="icon!" |
| 63 | + class="size-7 flex-none" |
| 64 | + /> |
| 65 | + |
| 66 | + <span class="w-full overflow-hidden text-center text-[0.65rem] leading-tight font-medium text-ellipsis max-md:flex-1"> |
| 67 | + {{ name }} |
| 68 | + </span> |
| 69 | + |
| 70 | + <img |
| 71 | + v-if="logoImage" |
| 72 | + :src="logoImage" |
| 73 | + alt="" |
| 74 | + class="pointer-events-none absolute top-1.5 right-1.5 size-3.5 object-contain max-md:hidden" |
| 75 | + > |
| 76 | + <UIcon |
| 77 | + v-else-if="logo" |
| 78 | + :name="logo" |
| 79 | + class="pointer-events-none absolute top-1.5 right-1.5 size-3.5 max-md:hidden" |
| 80 | + /> |
| 81 | + </div> |
| 82 | +</template> |
0 commit comments