127 lines
2.8 KiB
Vue
127 lines
2.8 KiB
Vue
<template>
|
|
<RouterLink v-if="to" :to="to" :class="rootClass">
|
|
<slot name="prependIcon" />
|
|
<span :class="['base-button__text', textClass]">{{ text }}</span>
|
|
<slot name="appendIcon" />
|
|
</RouterLink>
|
|
<button
|
|
v-else
|
|
:class="rootClass"
|
|
:type="type"
|
|
:disabled="disabled || loading"
|
|
@click="handleClick"
|
|
>
|
|
<template v-if="loading">
|
|
<SvgIcon
|
|
name="spinner"
|
|
:size="24"
|
|
:color="spinnerFill"
|
|
class="base-button__spinner animate-spin"
|
|
/>
|
|
</template>
|
|
<template v-else>
|
|
<slot name="prependIcon" />
|
|
<span :class="['base-button__text', textClass]">{{ text }}</span>
|
|
<slot name="appendIcon" />
|
|
</template>
|
|
</button>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue'
|
|
import { RouterLink } from 'vue-router'
|
|
|
|
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
|
|
|
const props = defineProps({
|
|
to: { type: [String, Object], default: null },
|
|
type: { type: String, default: 'button' },
|
|
variant: { type: String, default: 'primary' },
|
|
text: { type: String, default: 'تایید' },
|
|
textClass: { type: String, default: '' },
|
|
customClass: { type: String, default: 'base-button--full' },
|
|
disabled: { type: Boolean, default: false },
|
|
loading: { type: Boolean, default: false },
|
|
})
|
|
|
|
const emit = defineEmits(['click'])
|
|
|
|
const rootClass = computed(() => [
|
|
'base-button',
|
|
`base-button--${props.variant}`,
|
|
props.customClass,
|
|
{ 'base-button--disabled': props.disabled, 'base-button--loading': props.loading },
|
|
])
|
|
|
|
const spinnerFill = computed(() => (props.variant === 'primary' ? '#fff' : '#2B2B2B'))
|
|
|
|
const handleClick = (event) => {
|
|
if (props.type !== 'submit' && (props.disabled || props.loading)) {
|
|
event.preventDefault()
|
|
event.stopPropagation()
|
|
return
|
|
}
|
|
if (props.type === 'submit') return
|
|
emit('click', event)
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.base-button {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 2.35rem;
|
|
border: none;
|
|
border-radius: 9999px;
|
|
cursor: pointer;
|
|
transition: opacity 0.2s ease, background-color 0.2s ease;
|
|
font-family: var(--font-family-fa);
|
|
text-decoration: none;
|
|
padding: 0 1rem;
|
|
white-space: nowrap;
|
|
|
|
&__text {
|
|
line-height: 1.25rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
&__spinner {
|
|
margin: 0 auto;
|
|
}
|
|
|
|
&--full {
|
|
width: 100%;
|
|
}
|
|
|
|
&--primary {
|
|
background-color: var(--color-primary);
|
|
color: #fff;
|
|
|
|
&:hover:not(.base-button--disabled, .base-button--loading) {
|
|
opacity: 0.9;
|
|
}
|
|
}
|
|
|
|
&--secondary {
|
|
background-color: var(--color-thd-gray);
|
|
color: var(--color-sec-gray);
|
|
|
|
&:hover:not(.base-button--disabled, .base-button--loading) {
|
|
opacity: 0.9;
|
|
}
|
|
}
|
|
|
|
&--transparent {
|
|
background-color: transparent;
|
|
color: var(--color-sec-gray);
|
|
}
|
|
|
|
&--disabled,
|
|
&:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
</style>
|