mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-15 01:04:03 +00:00
Add missing base components and global alias registrations
Create BaseCustomTag (dynamic tag render), BaseFormatMoney, BaseHeading, BaseScrollPane, BaseDescriptionList/Item, BaseLabel, BaseCustomerSelectInput, BaseSpinner, BaseRating, and status label components. Register all renamed v2 components under their old Base* names (BaseInputGroup->FormGroup, BasePage->Page, BaseTable->DataTable, etc.) so templates resolve correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
16
resources/scripts-v2/components/base/BaseCustomTag.vue
Normal file
16
resources/scripts-v2/components/base/BaseCustomTag.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { h, defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BaseCustomTag',
|
||||
props: {
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'button',
|
||||
},
|
||||
},
|
||||
setup(props, { slots, attrs }) {
|
||||
return () => h(props.tag, attrs, slots)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
104
resources/scripts-v2/components/base/BaseCustomerSelectInput.vue
Normal file
104
resources/scripts-v2/components/base/BaseCustomerSelectInput.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useCustomerStore } from '../../features/company/customers/store'
|
||||
import { useModalStore } from '../../stores/modal.store'
|
||||
import { useUserStore } from '../../stores/user.store'
|
||||
import { ABILITIES } from '../../config/abilities'
|
||||
import CustomerModal from '../../features/company/customers/components/CustomerModal.vue'
|
||||
|
||||
interface Props {
|
||||
modelValue?: string | number | Record<string, unknown> | null
|
||||
fetchAll?: boolean
|
||||
showAction?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: '',
|
||||
fetchAll: false,
|
||||
showAction: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string | number | Record<string, unknown> | null): void
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const modalStore = useModalStore()
|
||||
const customerStore = useCustomerStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const selectedCustomer = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emit('update:modelValue', value as string | number | Record<string, unknown> | null)
|
||||
},
|
||||
})
|
||||
|
||||
async function searchCustomers(search: string) {
|
||||
const data: Record<string, unknown> = { search }
|
||||
|
||||
if (props.fetchAll) {
|
||||
data.limit = 'all'
|
||||
}
|
||||
|
||||
const response = await customerStore.fetchCustomers(data)
|
||||
const results = response.data ?? []
|
||||
|
||||
if (results.length > 0 && customerStore.editCustomer) {
|
||||
const customerFound = results.find(
|
||||
(c: Record<string, unknown>) => c.id === customerStore.editCustomer?.id
|
||||
)
|
||||
if (!customerFound) {
|
||||
const editCopy = { ...customerStore.editCustomer }
|
||||
results.unshift(editCopy as typeof results[0])
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
function addCustomer(): void {
|
||||
customerStore.resetCurrentCustomer()
|
||||
|
||||
modalStore.openModal({
|
||||
title: t('customers.add_new_customer'),
|
||||
componentName: 'CustomerModal',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseMultiselect
|
||||
v-model="selectedCustomer"
|
||||
v-bind="$attrs"
|
||||
track-by="name"
|
||||
value-prop="id"
|
||||
label="name"
|
||||
:filter-results="false"
|
||||
resolve-on-load
|
||||
:delay="500"
|
||||
:searchable="true"
|
||||
:options="searchCustomers"
|
||||
label-value="name"
|
||||
:placeholder="$t('customers.type_or_click')"
|
||||
:can-deselect="false"
|
||||
class="w-full"
|
||||
>
|
||||
<template v-if="showAction" #action>
|
||||
<BaseSelectAction
|
||||
v-if="userStore.hasAbilities(ABILITIES.CREATE_CUSTOMER)"
|
||||
@click="addCustomer"
|
||||
>
|
||||
<BaseIcon
|
||||
name="UserPlusIcon"
|
||||
class="h-4 mr-2 -ml-2 text-center text-primary-400"
|
||||
/>
|
||||
|
||||
{{ $t('customers.add_new_customer') }}
|
||||
</BaseSelectAction>
|
||||
</template>
|
||||
</BaseMultiselect>
|
||||
|
||||
<CustomerModal />
|
||||
</template>
|
||||
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div class="grid gap-4 mt-5 md:grid-cols-2 lg:grid-cols-3">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
label: string
|
||||
value?: string | number
|
||||
contentLoading?: boolean
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
value: '',
|
||||
contentLoading: false,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<BaseContentPlaceholders v-if="contentLoading">
|
||||
<BaseContentPlaceholdersBox class="w-20 h-5 mb-1" />
|
||||
<BaseContentPlaceholdersBox class="w-40 h-5" />
|
||||
</BaseContentPlaceholders>
|
||||
|
||||
<div v-else>
|
||||
<BaseLabel class="font-normal mb-1">
|
||||
{{ label }}
|
||||
</BaseLabel>
|
||||
|
||||
<p class="text-sm font-bold leading-5 text-heading non-italic">
|
||||
{{ value }}
|
||||
|
||||
<slot />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { EstimateStatus } from '@v2/types/domain'
|
||||
|
||||
interface Props {
|
||||
status?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
status: '',
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const labelStatus = computed<string>(() => {
|
||||
switch (props.status) {
|
||||
case EstimateStatus.DRAFT:
|
||||
case 'DRAFT':
|
||||
return t('estimates.draft')
|
||||
case EstimateStatus.SENT:
|
||||
case 'SENT':
|
||||
return t('estimates.sent')
|
||||
case EstimateStatus.VIEWED:
|
||||
case 'VIEWED':
|
||||
return t('estimates.viewed')
|
||||
case EstimateStatus.EXPIRED:
|
||||
case 'EXPIRED':
|
||||
return t('estimates.expired')
|
||||
case EstimateStatus.ACCEPTED:
|
||||
case 'ACCEPTED':
|
||||
return t('estimates.accepted')
|
||||
case EstimateStatus.REJECTED:
|
||||
case 'REJECTED':
|
||||
return t('estimates.rejected')
|
||||
default:
|
||||
return props.status
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ labelStatus }}
|
||||
</template>
|
||||
27
resources/scripts-v2/components/base/BaseFormatMoney.vue
Normal file
27
resources/scripts-v2/components/base/BaseFormatMoney.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useCompanyStore } from '@v2/stores/company.store'
|
||||
import { formatMoney } from '../../utils/format-money'
|
||||
import type { CurrencyConfig } from '../../utils/format-money'
|
||||
|
||||
interface Props {
|
||||
amount: number | string
|
||||
currency?: CurrencyConfig | null
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
currency: null,
|
||||
})
|
||||
|
||||
const companyStore = useCompanyStore()
|
||||
|
||||
const formattedAmount = computed<string>(() => {
|
||||
const amountNum = typeof props.amount === 'string' ? Number(props.amount) : props.amount
|
||||
const currencyConfig = props.currency ?? companyStore.selectedCompanyCurrency
|
||||
return formatMoney(amountNum, currencyConfig ?? undefined)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span style="font-family: sans-serif">{{ formattedAmount }}</span>
|
||||
</template>
|
||||
22
resources/scripts-v2/components/base/BaseHeading.vue
Normal file
22
resources/scripts-v2/components/base/BaseHeading.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Props {
|
||||
type?: 'section-title' | 'heading-title'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'section-title',
|
||||
})
|
||||
|
||||
const typeClass = computed<Record<string, boolean>>(() => ({
|
||||
'text-heading text-lg font-medium': props.type === 'heading-title',
|
||||
'text-muted uppercase text-base': props.type === 'section-title',
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h6 :class="typeClass">
|
||||
<slot />
|
||||
</h6>
|
||||
</template>
|
||||
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { InvoiceStatus, InvoicePaidStatus } from '@v2/types/domain'
|
||||
|
||||
interface Props {
|
||||
status?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
status: '',
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const labelStatus = computed<string>(() => {
|
||||
switch (props.status) {
|
||||
case InvoiceStatus.DRAFT:
|
||||
case 'DRAFT':
|
||||
return t('general.draft')
|
||||
case InvoiceStatus.SENT:
|
||||
case 'SENT':
|
||||
return t('general.sent')
|
||||
case InvoiceStatus.VIEWED:
|
||||
case 'VIEWED':
|
||||
return t('invoices.viewed')
|
||||
case InvoiceStatus.COMPLETED:
|
||||
case 'COMPLETED':
|
||||
return t('invoices.completed')
|
||||
case 'DUE':
|
||||
return t('general.due')
|
||||
case 'OVERDUE':
|
||||
return t('invoices.overdue')
|
||||
case InvoicePaidStatus.UNPAID:
|
||||
case 'UNPAID':
|
||||
return t('invoices.unpaid')
|
||||
case InvoicePaidStatus.PARTIALLY_PAID:
|
||||
case 'PARTIALLY_PAID':
|
||||
return t('invoices.partially_paid')
|
||||
case InvoicePaidStatus.PAID:
|
||||
case 'PAID':
|
||||
return t('invoices.paid')
|
||||
default:
|
||||
return props.status
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ labelStatus }}
|
||||
</template>
|
||||
5
resources/scripts-v2/components/base/BaseLabel.vue
Normal file
5
resources/scripts-v2/components/base/BaseLabel.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<label class="text-sm not-italic font-medium leading-5 text-primary-800">
|
||||
<slot />
|
||||
</label>
|
||||
</template>
|
||||
204
resources/scripts-v2/components/base/BaseRating.vue
Normal file
204
resources/scripts-v2/components/base/BaseRating.vue
Normal file
@@ -0,0 +1,204 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onBeforeMount } from 'vue'
|
||||
|
||||
interface RatingConfig {
|
||||
style?: Partial<RatingStyle>
|
||||
isIndicatorActive?: boolean
|
||||
}
|
||||
|
||||
interface RatingStyle {
|
||||
fullStarColor: string
|
||||
emptyStarColor: string
|
||||
starWidth: number
|
||||
starHeight: number
|
||||
}
|
||||
|
||||
interface StarData {
|
||||
raw: number
|
||||
percent: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
config?: RatingConfig | null
|
||||
rating?: number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
config: null,
|
||||
rating: 0,
|
||||
})
|
||||
|
||||
const EMPTY_STAR = 0
|
||||
const FULL_STAR = 1
|
||||
const TOTAL_STARS = 5
|
||||
|
||||
const stars = ref<StarData[]>([])
|
||||
const isIndicatorActive = ref<boolean>(false)
|
||||
const style = ref<RatingStyle>({
|
||||
fullStarColor: '#F1C644',
|
||||
emptyStarColor: '#D4D4D4',
|
||||
starWidth: 20,
|
||||
starHeight: 20,
|
||||
})
|
||||
|
||||
const getStarPoints = computed<string>(() => {
|
||||
const centerX = style.value.starWidth / 2
|
||||
const centerY = style.value.starHeight / 2
|
||||
const innerCircleArms = 5
|
||||
const innerRadius = style.value.starWidth / innerCircleArms
|
||||
const innerOuterRadiusRatio = 2.5
|
||||
const outerRadius = innerRadius * innerOuterRadiusRatio
|
||||
|
||||
return calcStarPoints(centerX, centerY, innerCircleArms, innerRadius, outerRadius)
|
||||
})
|
||||
|
||||
function calcStarPoints(
|
||||
centerX: number,
|
||||
centerY: number,
|
||||
innerCircleArms: number,
|
||||
innerRadius: number,
|
||||
outerRadius: number
|
||||
): string {
|
||||
const angle = Math.PI / innerCircleArms
|
||||
const angleOffsetToCenterStar = 60
|
||||
const totalArms = innerCircleArms * 2
|
||||
let points = ''
|
||||
|
||||
for (let i = 0; i < totalArms; i++) {
|
||||
const isEvenIndex = i % 2 === 0
|
||||
const r = isEvenIndex ? outerRadius : innerRadius
|
||||
const currX = centerX + Math.cos(i * angle + angleOffsetToCenterStar) * r
|
||||
const currY = centerY + Math.sin(i * angle + angleOffsetToCenterStar) * r
|
||||
points += currX + ',' + currY + ' '
|
||||
}
|
||||
|
||||
return points
|
||||
}
|
||||
|
||||
function calcStarFullness(starData: StarData): string {
|
||||
return starData.raw * 100 + '%'
|
||||
}
|
||||
|
||||
function getFullFillColor(starData: StarData): string {
|
||||
return starData.raw !== EMPTY_STAR
|
||||
? style.value.fullStarColor
|
||||
: style.value.emptyStarColor
|
||||
}
|
||||
|
||||
function initStars(): void {
|
||||
for (let i = 0; i < TOTAL_STARS; i++) {
|
||||
stars.value.push({
|
||||
raw: EMPTY_STAR,
|
||||
percent: EMPTY_STAR + '%',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function setStars(): void {
|
||||
let fullStarsCounter = Math.floor(props.rating)
|
||||
|
||||
for (let i = 0; i < stars.value.length; i++) {
|
||||
if (fullStarsCounter !== 0) {
|
||||
stars.value[i].raw = FULL_STAR
|
||||
stars.value[i].percent = calcStarFullness(stars.value[i])
|
||||
fullStarsCounter--
|
||||
} else {
|
||||
const surplus = Math.round((props.rating % 1) * 10) / 10
|
||||
const roundedOneDecimalPoint = Math.round(surplus * 10) / 10
|
||||
stars.value[i].raw = roundedOneDecimalPoint
|
||||
stars.value[i].percent = calcStarFullness(stars.value[i])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setConfigData(): void {
|
||||
if (props.config) {
|
||||
if (props.config.style?.fullStarColor) {
|
||||
style.value.fullStarColor = props.config.style.fullStarColor
|
||||
}
|
||||
if (props.config.style?.emptyStarColor) {
|
||||
style.value.emptyStarColor = props.config.style.emptyStarColor
|
||||
}
|
||||
if (props.config.style?.starWidth) {
|
||||
style.value.starWidth = props.config.style.starWidth
|
||||
}
|
||||
if (props.config.style?.starHeight) {
|
||||
style.value.starHeight = props.config.style.starHeight
|
||||
}
|
||||
if (props.config.isIndicatorActive) {
|
||||
isIndicatorActive.value = props.config.isIndicatorActive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
initStars()
|
||||
setStars()
|
||||
setConfigData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="star-rating">
|
||||
<div
|
||||
v-for="(star, index) in stars"
|
||||
:key="index"
|
||||
:title="String(rating)"
|
||||
class="star-container"
|
||||
>
|
||||
<svg
|
||||
:style="[
|
||||
{ fill: `url(#gradient${star.raw})` },
|
||||
{ width: style.starWidth },
|
||||
{ height: style.starHeight },
|
||||
]"
|
||||
class="star-svg"
|
||||
>
|
||||
<polygon :points="getStarPoints" style="fill-rule: nonzero" />
|
||||
<defs>
|
||||
<linearGradient :id="`gradient${star.raw}`">
|
||||
<stop
|
||||
id="stop1"
|
||||
:offset="star.percent"
|
||||
:stop-color="getFullFillColor(star)"
|
||||
stop-opacity="1"
|
||||
/>
|
||||
<stop
|
||||
id="stop2"
|
||||
:offset="star.percent"
|
||||
:stop-color="getFullFillColor(star)"
|
||||
stop-opacity="0"
|
||||
/>
|
||||
<stop
|
||||
id="stop3"
|
||||
:offset="star.percent"
|
||||
:stop-color="style.emptyStarColor"
|
||||
stop-opacity="1"
|
||||
/>
|
||||
<stop
|
||||
id="stop4"
|
||||
:stop-color="style.emptyStarColor"
|
||||
offset="100%"
|
||||
stop-opacity="1"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div v-if="isIndicatorActive" class="indicator">{{ rating }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.star-rating {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.star-container {
|
||||
display: flex;
|
||||
}
|
||||
.star-container:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RecurringInvoiceStatus } from '@v2/types/domain'
|
||||
|
||||
interface Props {
|
||||
status?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
status: '',
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const labelStatus = computed<string>(() => {
|
||||
switch (props.status) {
|
||||
case RecurringInvoiceStatus.COMPLETED:
|
||||
case 'COMPLETED':
|
||||
return t('recurring_invoices.complete')
|
||||
case RecurringInvoiceStatus.ON_HOLD:
|
||||
case 'ON_HOLD':
|
||||
return t('recurring_invoices.on_hold')
|
||||
case RecurringInvoiceStatus.ACTIVE:
|
||||
case 'ACTIVE':
|
||||
return t('recurring_invoices.active')
|
||||
default:
|
||||
return props.status
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ labelStatus }}
|
||||
</template>
|
||||
11
resources/scripts-v2/components/base/BaseScrollPane.vue
Normal file
11
resources/scripts-v2/components/base/BaseScrollPane.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<div class="-my-2 overflow-x-auto lg:overflow-visible sm:-mx-6 lg:-mx-8">
|
||||
<div class="py-2 align-middle inline-block min-w-full sm:px-4 lg:px-6">
|
||||
<div class="overflow-hidden lg:overflow-visible sm:px-2 lg:p-2">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
22
resources/scripts-v2/components/base/BaseSpinner.vue
Normal file
22
resources/scripts-v2/components/base/BaseSpinner.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<svg
|
||||
class="animate-spin"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
class="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
stroke-width="4"
|
||||
/>
|
||||
<path
|
||||
class="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -3,29 +3,41 @@ export { default as BaseButton } from './BaseButton.vue'
|
||||
export { default as BaseCard } from './BaseCard.vue'
|
||||
export { default as BaseCheckbox } from './BaseCheckbox.vue'
|
||||
export { default as BaseCustomerAddressDisplay } from './BaseCustomerAddressDisplay.vue'
|
||||
export { default as BaseCustomerSelectInput } from './BaseCustomerSelectInput.vue'
|
||||
export { default as BaseCustomerSelectPopup } from './BaseCustomerSelectPopup.vue'
|
||||
export { default as BaseCustomInput } from './BaseCustomInput.vue'
|
||||
export { default as BaseDatePicker } from './BaseDatePicker.vue'
|
||||
export { default as BaseDescriptionList } from './BaseDescriptionList.vue'
|
||||
export { default as BaseDescriptionListItem } from './BaseDescriptionListItem.vue'
|
||||
export { default as BaseDialog } from './BaseDialog.vue'
|
||||
export { default as BaseDivider } from './BaseDivider.vue'
|
||||
export { default as BaseDropdown } from './BaseDropdown.vue'
|
||||
export { default as BaseDropdownItem } from './BaseDropdownItem.vue'
|
||||
export { default as BaseErrorAlert } from './BaseErrorAlert.vue'
|
||||
export { default as BaseEstimateStatusLabel } from './BaseEstimateStatusLabel.vue'
|
||||
export { default as BaseFileUploader } from './BaseFileUploader.vue'
|
||||
export { default as BaseFormatMoney } from './BaseFormatMoney.vue'
|
||||
export { default as BaseGlobalLoader } from './BaseGlobalLoader.vue'
|
||||
export { default as BaseHeading } from './BaseHeading.vue'
|
||||
export { default as BaseIcon } from './BaseIcon.vue'
|
||||
export { default as BaseInfoAlert } from './BaseInfoAlert.vue'
|
||||
export { default as BaseInput } from './BaseInput.vue'
|
||||
export { default as BaseInvoiceStatusLabel } from './BaseInvoiceStatusLabel.vue'
|
||||
export { default as BaseItemSelect } from './BaseItemSelect.vue'
|
||||
export { default as BaseLabel } from './BaseLabel.vue'
|
||||
export { default as BaseList } from './BaseList.vue'
|
||||
export { default as BaseListItem } from './BaseListItem.vue'
|
||||
export { default as BaseMoney } from './BaseMoney.vue'
|
||||
export { default as BaseModal } from './BaseModal.vue'
|
||||
export { default as BaseMultiselect } from './BaseMultiselect.vue'
|
||||
export { default as BaseRadio } from './BaseRadio.vue'
|
||||
export { default as BaseRating } from './BaseRating.vue'
|
||||
export { default as BaseRecurringInvoiceStatusLabel } from './BaseRecurringInvoiceStatusLabel.vue'
|
||||
export { default as BaseScrollPane } from './BaseScrollPane.vue'
|
||||
export { default as BaseSelectAction } from './BaseSelectAction.vue'
|
||||
export { default as BaseSelectInput } from './BaseSelectInput.vue'
|
||||
export { default as BaseSettingCard } from './BaseSettingCard.vue'
|
||||
export { default as BaseSpinner } from './BaseSpinner.vue'
|
||||
export { default as BaseSwitch } from './BaseSwitch.vue'
|
||||
export { default as BaseTabGroup } from './BaseTabGroup.vue'
|
||||
export { default as BaseText } from './BaseText.vue'
|
||||
|
||||
Reference in New Issue
Block a user