@saasmakers/ui 0.1.107 → 0.1.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/bases/BaseAlert.vue +13 -10
- package/app/components/bases/BaseAvatar.vue +27 -2
- package/app/components/bases/BaseCharacter.vue +8 -7
- package/app/components/bases/BaseChart.vue +21 -19
- package/app/components/bases/BaseEmoji.vue +11 -2
- package/app/components/bases/BaseHeading.stories.ts +1 -1
- package/app/components/bases/BaseHeading.vue +7 -1
- package/app/components/bases/BaseIcon.vue +41 -25
- package/app/components/bases/BaseMessage.vue +4 -6
- package/app/components/bases/BaseMetric.vue +9 -8
- package/app/components/bases/BaseOverlay.vue +17 -3
- package/app/components/bases/BaseParagraph.stories.ts +1 -1
- package/app/components/bases/BaseParagraph.vue +7 -1
- package/app/components/bases/BaseQuote.stories.ts +1 -1
- package/app/components/bases/BaseQuote.vue +19 -17
- package/app/components/bases/BaseSpinner.vue +10 -1
- package/app/components/bases/BaseTag.vue +21 -1
- package/app/components/bases/BaseTags.vue +3 -4
- package/app/components/bases/BaseToast.vue +10 -1
- package/app/components/fields/FieldDays.vue +2 -1
- package/app/components/fields/FieldEmojis.vue +3 -3
- package/app/components/fields/FieldLabel.vue +24 -8
- package/app/components/fields/FieldMessage.vue +60 -92
- package/app/components/fields/FieldSelect.vue +33 -8
- package/app/components/fields/FieldTime.vue +12 -1
- package/app/composables/useChartist.ts +1 -1
- package/app/composables/useDevice.ts +1 -0
- package/app/composables/useLayerUtils.ts +16 -16
- package/app/composables/useToasts.ts +1 -1
- package/app/composables/useTranslation.ts +1 -1
- package/app/types/bases.d.ts +2 -0
- package/nuxt.config.ts +6 -6
- package/package.json +17 -13
|
@@ -40,10 +40,9 @@ const { getIcon } = useLayerIcons()
|
|
|
40
40
|
|
|
41
41
|
const sortedTags = computed({
|
|
42
42
|
get() {
|
|
43
|
-
return props.tags
|
|
44
|
-
.slice()
|
|
43
|
+
return [...props.tags]
|
|
45
44
|
.filter((_tag, tagIndex) => tagIndex < props.maxTags || showingAllTags.value)
|
|
46
|
-
.
|
|
45
|
+
.toSorted((tagA, tagB) => {
|
|
47
46
|
return (tagA.order ?? 0) < (tagB.order ?? 0) ? -1 : 0
|
|
48
47
|
})
|
|
49
48
|
},
|
|
@@ -54,7 +53,7 @@ const sortedTags = computed({
|
|
|
54
53
|
id: tag.id,
|
|
55
54
|
order,
|
|
56
55
|
}))
|
|
57
|
-
.map(tag => ({
|
|
56
|
+
.map((tag) => ({
|
|
58
57
|
id: tag.id,
|
|
59
58
|
order: tag.order,
|
|
60
59
|
}))
|
|
@@ -19,16 +19,25 @@ function onClose(event: MouseEvent) {
|
|
|
19
19
|
emit('close', event, props)
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
function onKeydown(event: KeyboardEvent) {
|
|
24
|
+
if ((event.key === 'Enter' || event.key === ' ') && props.hasClose) {
|
|
25
|
+
onClose(event as unknown as MouseEvent)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
22
28
|
</script>
|
|
23
29
|
|
|
24
30
|
<template>
|
|
25
31
|
<div
|
|
26
32
|
class="group flex select-none items-center rounded-full bg-gray-900 px-3 py-2 text-base text-white font-normal dark:bg-gray-100 dark:text-black"
|
|
27
33
|
:class="{ 'cursor-pointer': hasClose }"
|
|
34
|
+
role="button"
|
|
35
|
+
tabindex="0"
|
|
28
36
|
@click="onClose"
|
|
37
|
+
@keydown.prevent="onKeydown"
|
|
29
38
|
>
|
|
30
39
|
<BaseIcon
|
|
31
|
-
class="flex-initial"
|
|
40
|
+
class="pointer-events-none flex-initial"
|
|
32
41
|
:status="status"
|
|
33
42
|
:text="text"
|
|
34
43
|
/>
|
|
@@ -31,7 +31,7 @@ const emojisFiltered = computed(() => {
|
|
|
31
31
|
const englishKeywords = (emoji.keywords.en ?? [])
|
|
32
32
|
const allKeywords = [...localizedKeywords, ...englishKeywords]
|
|
33
33
|
|
|
34
|
-
return allKeywords.some(keyword => normalizeText(keyword).includes(searchQueryCleaned))
|
|
34
|
+
return allKeywords.some((keyword) => normalizeText(keyword).includes(searchQueryCleaned))
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
return {
|
|
@@ -39,7 +39,7 @@ const emojisFiltered = computed(() => {
|
|
|
39
39
|
emojis: filtered,
|
|
40
40
|
}
|
|
41
41
|
})
|
|
42
|
-
.filter(category => category.emojis.length > 0)
|
|
42
|
+
.filter((category) => category.emojis.length > 0)
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
function onEmojiClick(event: MouseEvent, emoji?: string) {
|
|
@@ -69,7 +69,7 @@ function onEmojiClick(event: MouseEvent, emoji?: string) {
|
|
|
69
69
|
:key="category.category"
|
|
70
70
|
>
|
|
71
71
|
<div
|
|
72
|
-
v-if="category.emojis.length"
|
|
72
|
+
v-if="category.emojis.length > 0"
|
|
73
73
|
class="mt-4"
|
|
74
74
|
>
|
|
75
75
|
<div class="mb-4">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { FieldLabel } from '../../types/fields'
|
|
3
3
|
|
|
4
|
-
withDefaults(defineProps<FieldLabel>(), {
|
|
4
|
+
const props = withDefaults(defineProps<FieldLabel>(), {
|
|
5
5
|
disabled: false,
|
|
6
6
|
forField: '',
|
|
7
7
|
hasMarginBottom: false,
|
|
@@ -19,21 +19,34 @@ const emit = defineEmits<{
|
|
|
19
19
|
click: [event: MouseEvent]
|
|
20
20
|
}>()
|
|
21
21
|
|
|
22
|
+
const isClickable = computed(() => {
|
|
23
|
+
return !props.loading && !props.disabled
|
|
24
|
+
})
|
|
25
|
+
|
|
22
26
|
function onClick(event: MouseEvent) {
|
|
23
|
-
|
|
27
|
+
if (isClickable.value) {
|
|
28
|
+
emit('click', event)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function onKeydown(event: KeyboardEvent) {
|
|
33
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
34
|
+
onClick(event as unknown as MouseEvent)
|
|
35
|
+
}
|
|
24
36
|
}
|
|
25
37
|
</script>
|
|
26
38
|
|
|
27
39
|
<template>
|
|
28
|
-
<
|
|
40
|
+
<component
|
|
41
|
+
:is="forField ? 'label' : (isClickable ? 'button' : 'span')"
|
|
29
42
|
class="flex select-none items-center font-semibold tracking-tight"
|
|
30
43
|
:class="{
|
|
31
44
|
'field-disabled': disabled,
|
|
32
|
-
'cursor-pointer':
|
|
45
|
+
'cursor-pointer': isClickable,
|
|
33
46
|
'cursor-wait': loading,
|
|
34
47
|
'text-gray-900 dark:text-gray-100': !lineThrough,
|
|
35
48
|
'text-gray-500 dark:text-gray-500 line-through': lineThrough,
|
|
36
|
-
'hover:text-black dark:hover:text-white':
|
|
49
|
+
'hover:text-black dark:hover:text-white': isClickable && !lineThrough,
|
|
37
50
|
'w-0 truncate': truncate,
|
|
38
51
|
'mb-1.5': size === 'xs' && hasMarginBottom,
|
|
39
52
|
'mb-2': size === 'sm' && hasMarginBottom,
|
|
@@ -44,8 +57,11 @@ function onClick(event: MouseEvent) {
|
|
|
44
57
|
'ml-2': size === 'base' && hasMarginLeft,
|
|
45
58
|
'ml-2.5': size === 'lg' && hasMarginLeft,
|
|
46
59
|
}"
|
|
47
|
-
:for="forField"
|
|
48
|
-
|
|
60
|
+
:for="forField || undefined"
|
|
61
|
+
:tabindex="isClickable && !forField ? 0 : undefined"
|
|
62
|
+
:type="isClickable && !forField ? 'button' : undefined"
|
|
63
|
+
@click="isClickable ? onClick : undefined"
|
|
64
|
+
@keydown.prevent="isClickable ? onKeydown : undefined"
|
|
49
65
|
>
|
|
50
66
|
<BaseIcon
|
|
51
67
|
:icon="icon"
|
|
@@ -59,5 +75,5 @@ function onClick(event: MouseEvent) {
|
|
|
59
75
|
:size="size"
|
|
60
76
|
text="*"
|
|
61
77
|
/>
|
|
62
|
-
</
|
|
78
|
+
</component>
|
|
63
79
|
</template>
|
|
@@ -15,105 +15,73 @@ const { t } = useI18n()
|
|
|
15
15
|
const validationMessage = computed(() => {
|
|
16
16
|
// Available rules
|
|
17
17
|
// https://vuelidate.js.org/#sub-builtin-validators
|
|
18
|
-
let message = ''
|
|
19
|
-
|
|
20
18
|
if (props.validation && props.validation.$dirty) {
|
|
21
19
|
// Required, Required If, Required Unless
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
message = t('email')
|
|
82
|
-
}
|
|
83
|
-
// IP Address
|
|
84
|
-
else if (props.validation.ipAddress === false) {
|
|
85
|
-
message = t('ipAddress')
|
|
86
|
-
}
|
|
87
|
-
// Mac Address
|
|
88
|
-
else if (props.validation.macAddress === false) {
|
|
89
|
-
message = t('maxAddress')
|
|
90
|
-
}
|
|
91
|
-
// Same As
|
|
92
|
-
else if (props.validation.sameAs === false) {
|
|
93
|
-
const field = props.validation.$params.sameAs.eq
|
|
94
|
-
|
|
95
|
-
message = t('sameAs', { field })
|
|
96
|
-
}
|
|
97
|
-
// Url
|
|
98
|
-
else if (props.validation.url === false) {
|
|
99
|
-
message = t('url')
|
|
100
|
-
}
|
|
101
|
-
// Other rules
|
|
102
|
-
else if (props.validation.$invalid === true) {
|
|
103
|
-
message = t('invalid')
|
|
20
|
+
switch (false) {
|
|
21
|
+
case props.validation.alpha: {
|
|
22
|
+
return t('alpha')
|
|
23
|
+
}
|
|
24
|
+
case props.validation.alphaNum: {
|
|
25
|
+
return t('alphaNum')
|
|
26
|
+
}
|
|
27
|
+
case props.validation.between: {
|
|
28
|
+
return t('between', {
|
|
29
|
+
max: props.validation.$params.between.max,
|
|
30
|
+
min: props.validation.$params.between.min,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
case props.validation.decimal: {
|
|
34
|
+
return t('decimal')
|
|
35
|
+
}
|
|
36
|
+
case props.validation.email: {
|
|
37
|
+
return t('email')
|
|
38
|
+
}
|
|
39
|
+
case props.validation.integer: {
|
|
40
|
+
return t('integer')
|
|
41
|
+
}
|
|
42
|
+
case props.validation.ipAddress: {
|
|
43
|
+
return t('ipAddress')
|
|
44
|
+
}
|
|
45
|
+
case props.validation.macAddress: {
|
|
46
|
+
return t('maxAddress')
|
|
47
|
+
}
|
|
48
|
+
case props.validation.maxLength: {
|
|
49
|
+
return t('maxLength', { max: props.validation.$params.maxLength.max })
|
|
50
|
+
}
|
|
51
|
+
case props.validation.maxValue: {
|
|
52
|
+
return t('maxValue', { max: props.validation.$params.maxValue.max })
|
|
53
|
+
}
|
|
54
|
+
case props.validation.minLength: {
|
|
55
|
+
return t('minLength', { min: props.validation.$params.minLength.min })
|
|
56
|
+
}
|
|
57
|
+
case props.validation.minValue: {
|
|
58
|
+
return t('minValue', { min: props.validation.$params.minValue.min })
|
|
59
|
+
}
|
|
60
|
+
case props.validation.numeric: {
|
|
61
|
+
return t('numeric')
|
|
62
|
+
}
|
|
63
|
+
case props.validation.required:
|
|
64
|
+
case props.validation.requiredIf:
|
|
65
|
+
case props.validation.requiredUnless: {
|
|
66
|
+
return t('required')
|
|
67
|
+
}
|
|
68
|
+
case props.validation.sameAs: {
|
|
69
|
+
return t('sameAs', { field: props.validation.$params.sameAs.eq })
|
|
70
|
+
}
|
|
71
|
+
case props.validation.url: {
|
|
72
|
+
return t('url')
|
|
73
|
+
}
|
|
74
|
+
default: {
|
|
75
|
+
if (props.validation.$invalid === true) {
|
|
76
|
+
return t('invalid')
|
|
77
|
+
}
|
|
78
|
+
}
|
|
104
79
|
}
|
|
105
80
|
}
|
|
106
|
-
|
|
107
|
-
return message
|
|
108
81
|
})
|
|
109
82
|
|
|
110
83
|
const status = computed(() => {
|
|
111
|
-
|
|
112
|
-
return 'error'
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
return 'default'
|
|
116
|
-
}
|
|
84
|
+
return validationMessage.value && !props.hideError ? 'error' : 'default'
|
|
117
85
|
})
|
|
118
86
|
|
|
119
87
|
const text = computed<BaseTextText>(() => {
|
|
@@ -37,7 +37,7 @@ const modelValue = defineModel<FieldSelect['modelValue']>({ default: '' })
|
|
|
37
37
|
const opened = ref(false)
|
|
38
38
|
|
|
39
39
|
const computedColumns = computed(() => {
|
|
40
|
-
if (props.columns.length) {
|
|
40
|
+
if (props.columns.length > 0) {
|
|
41
41
|
return props.columns
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -48,7 +48,7 @@ const computedOptions = computed(() => {
|
|
|
48
48
|
const options: FieldSelectOption[] = []
|
|
49
49
|
|
|
50
50
|
// Add index to each option
|
|
51
|
-
if (props.columns.length) {
|
|
51
|
+
if (props.columns.length > 0) {
|
|
52
52
|
for (const column of props.columns) {
|
|
53
53
|
for (const columnOption of column.options) {
|
|
54
54
|
options.push(columnOption)
|
|
@@ -70,6 +70,12 @@ const selectedOption = computed(() => {
|
|
|
70
70
|
})
|
|
71
71
|
})
|
|
72
72
|
|
|
73
|
+
function onBlur() {
|
|
74
|
+
if (props.openOnHover && !props.disabled) {
|
|
75
|
+
opened.value = false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
function onClose() {
|
|
74
80
|
reset()
|
|
75
81
|
}
|
|
@@ -90,6 +96,12 @@ function onContainerKeypress(event: KeyboardEvent) {
|
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
|
|
99
|
+
function onFocus() {
|
|
100
|
+
if (props.openOnHover && !props.disabled) {
|
|
101
|
+
opened.value = true
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
function onLabelClick() {
|
|
94
106
|
if (!props.disabled) {
|
|
95
107
|
opened.value = !opened.value
|
|
@@ -111,17 +123,23 @@ function onMouseLeave() {
|
|
|
111
123
|
function onOptionClick(event: MouseEvent, option: FieldSelectOption) {
|
|
112
124
|
if (!props.disabled) {
|
|
113
125
|
// Check that the option is not currently selected
|
|
114
|
-
if ((selectedOption.value || {}).value
|
|
115
|
-
|
|
126
|
+
if ((selectedOption.value || {}).value === option.value) {
|
|
127
|
+
reset()
|
|
116
128
|
}
|
|
117
129
|
else {
|
|
118
|
-
|
|
130
|
+
selectOption(event, option.value)
|
|
119
131
|
}
|
|
120
132
|
|
|
121
133
|
emit('optionClick', event, option.value)
|
|
122
134
|
}
|
|
123
135
|
}
|
|
124
136
|
|
|
137
|
+
function onOptionKeydown(event: KeyboardEvent, option: FieldSelectOption) {
|
|
138
|
+
if ((event.key === 'Enter' || event.key === ' ') && !props.disabled) {
|
|
139
|
+
onOptionClick(event as unknown as MouseEvent, option)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
125
143
|
function reset() {
|
|
126
144
|
opened.value = false
|
|
127
145
|
}
|
|
@@ -155,8 +173,6 @@ function selectOption(event: MouseEvent, value: string) {
|
|
|
155
173
|
'field-disabled': disabled,
|
|
156
174
|
'cursor-pointer': !disabled,
|
|
157
175
|
}"
|
|
158
|
-
@mouseenter="onMouseEnter"
|
|
159
|
-
@mouseleave="onMouseLeave"
|
|
160
176
|
>
|
|
161
177
|
<div
|
|
162
178
|
class="relative"
|
|
@@ -177,9 +193,15 @@ function selectOption(event: MouseEvent, value: string) {
|
|
|
177
193
|
'text-sm h-12': size === 'base',
|
|
178
194
|
'text-base h-14': size === 'lg',
|
|
179
195
|
}"
|
|
180
|
-
|
|
196
|
+
role="button"
|
|
197
|
+
:aria-disabled="disabled"
|
|
198
|
+
tabindex="0"
|
|
181
199
|
@click="onContainerClick"
|
|
182
200
|
@keypress.prevent="onContainerKeypress"
|
|
201
|
+
@mouseenter="onMouseEnter"
|
|
202
|
+
@mouseleave="onMouseLeave"
|
|
203
|
+
@focusin="onFocus"
|
|
204
|
+
@focusout="onBlur"
|
|
183
205
|
>
|
|
184
206
|
<template v-if="selectedOption">
|
|
185
207
|
<BaseIcon
|
|
@@ -258,7 +280,10 @@ function selectOption(event: MouseEvent, value: string) {
|
|
|
258
280
|
'text-gray-900 dark:text-gray-100': selectedOption && option.value === selectedOption.value,
|
|
259
281
|
'bg-white dark:bg-gray-900': selectedOption && option.value !== selectedOption.value,
|
|
260
282
|
}"
|
|
283
|
+
role="button"
|
|
284
|
+
tabindex="0"
|
|
261
285
|
@click="onOptionClick($event, option)"
|
|
286
|
+
@keydown.prevent="onOptionKeydown($event, option)"
|
|
262
287
|
>
|
|
263
288
|
<BaseIcon
|
|
264
289
|
v-if="option.text"
|
|
@@ -29,7 +29,14 @@ const inputRef = ref<HTMLInputElement>()
|
|
|
29
29
|
function onContainerClick() {
|
|
30
30
|
if (!props.disabled && inputRef.value) {
|
|
31
31
|
inputRef.value.focus()
|
|
32
|
-
inputRef.value.showPicker
|
|
32
|
+
inputRef.value.showPicker()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function onContainerKeydown(event: KeyboardEvent) {
|
|
37
|
+
if ((event.key === 'Enter' || event.key === ' ') && !props.disabled && inputRef.value) {
|
|
38
|
+
inputRef.value.focus()
|
|
39
|
+
inputRef.value.showPicker()
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
42
|
|
|
@@ -63,7 +70,11 @@ function onFieldBlur(event: FocusEvent) {
|
|
|
63
70
|
'text-sm h-12': size === 'base',
|
|
64
71
|
'text-base h-14': size === 'lg',
|
|
65
72
|
}"
|
|
73
|
+
role="button"
|
|
74
|
+
:aria-disabled="disabled"
|
|
75
|
+
tabindex="0"
|
|
66
76
|
@click="onContainerClick"
|
|
77
|
+
@keydown.prevent="onContainerKeydown"
|
|
67
78
|
>
|
|
68
79
|
<BaseIcon
|
|
69
80
|
:icon="getIcon('clock')"
|
|
@@ -50,7 +50,7 @@ export default function useChartist() {
|
|
|
50
50
|
// Clean up the dash attributes after it finishes
|
|
51
51
|
const total = delay + duration + (stagger ? stagger * (lineCtx.seriesIndex ?? 0) : 0)
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
globalThis.setTimeout(() => {
|
|
54
54
|
lineCtx.element.attr({
|
|
55
55
|
'stroke-dasharray': undefined,
|
|
56
56
|
'stroke-dashoffset': undefined,
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import numbroLib from 'numbro'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const numbro = (number: '∞' | number | undefined, format?: string) => {
|
|
12
|
-
if (!number && number !== 0) {
|
|
13
|
-
return ''
|
|
14
|
-
}
|
|
15
|
-
else if (number === '∞' || number % 1 !== 0) {
|
|
16
|
-
return `${number}`
|
|
17
|
-
}
|
|
3
|
+
const normalizeText = (text: string) => {
|
|
4
|
+
return text
|
|
5
|
+
.toLowerCase()
|
|
6
|
+
.normalize('NFD')
|
|
7
|
+
.replaceAll(/[\u0300-\u036F]/g, '')
|
|
8
|
+
}
|
|
18
9
|
|
|
19
|
-
|
|
10
|
+
const numbro = (number: '∞' | number | undefined, format?: string) => {
|
|
11
|
+
if (!number && number !== 0) {
|
|
12
|
+
return ''
|
|
20
13
|
}
|
|
14
|
+
else if (number === '∞' || number % 1 !== 0) {
|
|
15
|
+
return `${number}`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return numbroLib(number).format(format || '0,0')
|
|
19
|
+
}
|
|
21
20
|
|
|
21
|
+
export default function useLayerUtils() {
|
|
22
22
|
return {
|
|
23
23
|
normalizeText,
|
|
24
24
|
numbro,
|
|
@@ -20,7 +20,7 @@ export default function useToast() {
|
|
|
20
20
|
const createToast = (message: string, status: BaseStatus = 'success', i18nParams?: Record<string, number | string>) => {
|
|
21
21
|
if (import.meta.client) {
|
|
22
22
|
const toast: BaseToast = {
|
|
23
|
-
id: Math.floor((1 + Math.random()) *
|
|
23
|
+
id: Math.floor((1 + Math.random()) * 0x1_00_00).toString(16),
|
|
24
24
|
status: status || 'success',
|
|
25
25
|
text: message.includes(' ') ? message : nuxtApp.$i18n.t(`toasts.${message}`, i18nParams || {}),
|
|
26
26
|
}
|
|
@@ -35,7 +35,7 @@ export default function useTranslation(slots: SetupContext['slots'], locale: Ref
|
|
|
35
35
|
const endPosition = content.indexOf(separator, startPosition)
|
|
36
36
|
|
|
37
37
|
content = content
|
|
38
|
-
.
|
|
38
|
+
.slice(startPosition, endPosition > 0 ? endPosition : content.length)
|
|
39
39
|
.trim()
|
|
40
40
|
|
|
41
41
|
// Markdown parser
|
package/app/types/bases.d.ts
CHANGED
|
@@ -141,6 +141,7 @@ export interface BaseHeading {
|
|
|
141
141
|
alignment?: BaseAlignment
|
|
142
142
|
size?: BaseHeadingSize
|
|
143
143
|
tag?: BaseHeadingTag
|
|
144
|
+
text?: BaseTextText
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
export type BaseHeadingSize
|
|
@@ -217,6 +218,7 @@ export type BaseOverlayPosition = 'absolute' | 'fixed'
|
|
|
217
218
|
export interface BaseParagraph {
|
|
218
219
|
alignment?: BaseAlignment
|
|
219
220
|
size?: BaseParagraphSize
|
|
221
|
+
text?: BaseTextText
|
|
220
222
|
}
|
|
221
223
|
|
|
222
224
|
export type BaseParagraphSize = 'base' | 'lg' | 'sm'
|
package/nuxt.config.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from 'node:path'
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { defineNuxtConfig } from 'nuxt/config'
|
|
4
|
-
import uno from './uno.config'
|
|
4
|
+
import uno from './uno.config.js'
|
|
5
5
|
|
|
6
|
-
const currentDir = dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
|
7
7
|
|
|
8
8
|
export default defineNuxtConfig({
|
|
9
9
|
// --> BUILD <--
|
|
@@ -44,9 +44,9 @@ export default defineNuxtConfig({
|
|
|
44
44
|
|
|
45
45
|
css: [
|
|
46
46
|
'@unocss/reset/tailwind.css',
|
|
47
|
-
join(currentDir, './app/assets/styles/chartist.css'),
|
|
48
|
-
join(currentDir, './app/assets/styles/colors.css'),
|
|
49
|
-
join(currentDir, './app/assets/styles/v-popper.css'),
|
|
47
|
+
path.join(currentDir, './app/assets/styles/chartist.css'),
|
|
48
|
+
path.join(currentDir, './app/assets/styles/colors.css'),
|
|
49
|
+
path.join(currentDir, './app/assets/styles/v-popper.css'),
|
|
50
50
|
],
|
|
51
51
|
|
|
52
52
|
modules: [
|
package/package.json
CHANGED
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saasmakers/ui",
|
|
3
|
-
"
|
|
4
|
-
"version": "0.1.107",
|
|
3
|
+
"version": "0.1.108",
|
|
5
4
|
"private": false,
|
|
6
5
|
"description": "Reusable Nuxt UI components for SaaS Makers projects",
|
|
7
|
-
"license": "MIT",
|
|
8
6
|
"repository": {
|
|
9
7
|
"type": "git",
|
|
10
8
|
"url": "git+https://github.com/saasmakers/saasmakers-turborepo.git",
|
|
11
9
|
"directory": "packages/ui"
|
|
12
10
|
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": "SaaS Makers",
|
|
13
|
+
"sideEffects": false,
|
|
14
|
+
"type": "module",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./nuxt.config.ts"
|
|
17
|
+
},
|
|
13
18
|
"main": "nuxt.config.ts",
|
|
14
19
|
"types": "app/types/global.d.ts",
|
|
15
|
-
"publishConfig": {
|
|
16
|
-
"access": "public"
|
|
17
|
-
},
|
|
18
20
|
"files": [
|
|
19
21
|
"app",
|
|
20
|
-
"nuxt.config.ts",
|
|
21
22
|
"public",
|
|
22
23
|
"uno.config.ts"
|
|
23
24
|
],
|
|
24
|
-
"peerDependencies": {
|
|
25
|
-
"@saasmakers/shared": "^0.1.13",
|
|
26
|
-
"nuxt": "4.2.2"
|
|
27
|
-
},
|
|
28
25
|
"dependencies": {
|
|
29
26
|
"@capacitor/preferences": "8.0.0",
|
|
30
27
|
"@nuxt/icon": "2.1.1",
|
|
@@ -58,10 +55,17 @@
|
|
|
58
55
|
"devDependencies": {
|
|
59
56
|
"nuxt": "4.2.2",
|
|
60
57
|
"typescript": "5.9.3",
|
|
61
|
-
"@saasmakers/shared": "0.1.
|
|
58
|
+
"@saasmakers/shared": "0.1.15"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@saasmakers/shared": "^0.1.15",
|
|
62
|
+
"nuxt": "4.2.2"
|
|
63
|
+
},
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
62
66
|
},
|
|
63
67
|
"scripts": {
|
|
64
|
-
"dev": "storybook dev -p 3103",
|
|
68
|
+
"dev": "storybook dev -p 3103 --no-open",
|
|
65
69
|
"lint": "eslint .",
|
|
66
70
|
"typecheck": "nuxi typecheck"
|
|
67
71
|
}
|