funkwhale/front/src/components/ui/Button.vue

81 lines
1.6 KiB
Vue

<script setup lang="ts">
import { useColor } from '~/composables/colors'
import { FwLoader } from '~/components'
import { ref, computed, useSlots } from 'vue'
import type { ColorProps } from '~/types/common-props'
interface Props {
variant?: 'solid' | 'outline' | 'ghost'
width?: 'standard' | 'auto' | 'full'
alignText?: 'left' | 'center' | 'right'
isActive?: boolean
isLoading?: boolean
shadow?: boolean
round?: boolean
icon?: string
onClick?: (...args: any[]) => void | Promise<void>
}
const props = defineProps<Props & ColorProps>()
const color = useColor(() => props.color)
const slots = useSlots()
const iconOnly = computed(() => !!props.icon && !slots.default)
const internalLoader = ref(false)
const isLoading = computed(() => props.isLoading || internalLoader.value)
const click = async (...args: any[]) => {
internalLoader.value = true
try {
await props.onClick?.(...args)
} finally {
internalLoader.value = false
}
}
</script>
<template>
<button
class="funkwhale is-colored button"
:class="[
color,
'is-' + (variant ?? 'solid'),
'is-' + (width ?? 'standard'),
'is-aligned-' + (alignText ?? 'center'),
{
'is-active': isActive,
'is-loading': isLoading,
'icon-only': iconOnly,
'has-icon': !!icon,
'is-round': round,
'is-shadow': shadow
}
]"
@click="click"
>
<i
v-if="icon"
:class="['bi', icon]"
/>
<span>
<slot />
</span>
<fw-loader
v-if="isLoading"
:container="false"
/>
</button>
</template>
<style lang="scss">
@import './style.scss'
</style>