Icon.vue
57 lines
| 1 | <script lang="ts" setup> |
| 2 | import { computed, defineAsyncComponent } from "vue"; |
| 3 | |
| 4 | import type { Color } from "@/types"; |
| 5 | import type { IconUnion } from "@/types/enums/iconModels"; |
| 6 | import { toTitleCase, wrapInCssVar } from "@/utils/helpers"; |
| 7 | import { kebabToCamel } from "@/utils/services/snakeCamelService"; |
| 8 | |
| 9 | interface Props { |
| 10 | dimensions?: number; |
| 11 | color?: Color; |
| 12 | name: IconUnion; |
| 13 | } |
| 14 | |
| 15 | const props = withDefaults(defineProps<Props>(), { |
| 16 | dimensions: 24, |
| 17 | color: "white" |
| 18 | }); |
| 19 | |
| 20 | const iconColor = computed(() => { |
| 21 | if (!props.color) return ""; |
| 22 | |
| 23 | return wrapInCssVar(props.color); |
| 24 | }); |
| 25 | |
| 26 | const selectedIcon = computed(() => |
| 27 | defineAsyncComponent( |
| 28 | () => |
| 29 | import( |
| 30 | `@/components/Icon/Icons/${kebabToCamel(toTitleCase(props.name))}.vue` |
| 31 | ) |
| 32 | ) |
| 33 | ); |
| 34 | </script> |
| 35 | |
| 36 | <template> |
| 37 | <svg |
| 38 | class="icon" |
| 39 | aria-hidden="true" |
| 40 | > |
| 41 | <g> |
| 42 | <Component :is="selectedIcon" /> |
| 43 | </g> |
| 44 | </svg> |
| 45 | </template> |
| 46 | |
| 47 | <style lang="scss" scoped> |
| 48 | .icon { |
| 49 | transition: 0.3s ease transform; |
| 50 | fill: currentColor; |
| 51 | color: v-bind(iconColor); |
| 52 | width: v-bind("dimensions + 'px'"); |
| 53 | height: v-bind("dimensions + 'px'"); |
| 54 | min-width: v-bind("dimensions + 'px'"); |
| 55 | } |
| 56 | </style> |
| 57 |