81 lines
1.6 KiB
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>
|