@saasmakers/ui 0.1.18 → 0.1.19
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.
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { NuxtLinkLocale } from '#components'
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
background: {
|
|
6
|
+
default: '',
|
|
7
|
+
type: String as PropType<BaseTextBackground>,
|
|
8
|
+
},
|
|
9
|
+
bold: {
|
|
10
|
+
default: false,
|
|
11
|
+
type: Boolean,
|
|
12
|
+
},
|
|
13
|
+
hasMargin: {
|
|
14
|
+
default: false,
|
|
15
|
+
type: Boolean,
|
|
16
|
+
},
|
|
17
|
+
maxCharacters: {
|
|
18
|
+
default: 0,
|
|
19
|
+
type: Number,
|
|
20
|
+
},
|
|
21
|
+
noWrap: {
|
|
22
|
+
default: false,
|
|
23
|
+
type: Boolean,
|
|
24
|
+
},
|
|
25
|
+
reverse: {
|
|
26
|
+
default: false,
|
|
27
|
+
type: Boolean,
|
|
28
|
+
},
|
|
29
|
+
size: {
|
|
30
|
+
default: 'base',
|
|
31
|
+
type: String as PropType<BaseSize>,
|
|
32
|
+
},
|
|
33
|
+
skeleton: {
|
|
34
|
+
default: false,
|
|
35
|
+
type: Boolean,
|
|
36
|
+
},
|
|
37
|
+
text: {
|
|
38
|
+
default: '',
|
|
39
|
+
type: [String, Object] as PropType<BaseTextText>,
|
|
40
|
+
},
|
|
41
|
+
to: {
|
|
42
|
+
default: undefined,
|
|
43
|
+
type: [Object, String] as PropType<RouteLocationRaw | string>,
|
|
44
|
+
},
|
|
45
|
+
truncate: {
|
|
46
|
+
default: false,
|
|
47
|
+
type: Boolean,
|
|
48
|
+
},
|
|
49
|
+
underline: {
|
|
50
|
+
default: false,
|
|
51
|
+
type: Boolean,
|
|
52
|
+
},
|
|
53
|
+
uppercase: {
|
|
54
|
+
default: false,
|
|
55
|
+
type: Boolean,
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const emit = defineEmits<{
|
|
60
|
+
click: [event: MouseEvent]
|
|
61
|
+
}>()
|
|
62
|
+
|
|
63
|
+
const showAll = ref(false)
|
|
64
|
+
|
|
65
|
+
const { t } = useI18n()
|
|
66
|
+
|
|
67
|
+
const finalText = computed(() => {
|
|
68
|
+
if (props.maxCharacters && typeof props.text === 'string') {
|
|
69
|
+
return ellipsize(
|
|
70
|
+
props.text,
|
|
71
|
+
showAll.value ? Number.POSITIVE_INFINITY : props.maxCharacters,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return props.text as string
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
function ellipsize(inputString: string, maxLength: number) {
|
|
79
|
+
if (inputString.length <= maxLength) {
|
|
80
|
+
return inputString
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// If the input string is longer than the maximum length, find the last full word that fits
|
|
84
|
+
const truncatedString = inputString.slice(0, maxLength)
|
|
85
|
+
const lastSpaceIndex = truncatedString.lastIndexOf(' ')
|
|
86
|
+
|
|
87
|
+
// If there's no space in the truncated string, we can't avoid cutting a word
|
|
88
|
+
if (lastSpaceIndex === -1) {
|
|
89
|
+
return `${truncatedString.slice(0, maxLength - 3)}...`
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Return the string truncated at the last full word, with an ellipsis appended
|
|
93
|
+
return `${truncatedString.slice(0, lastSpaceIndex)}...`
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function onClick(event: MouseEvent) {
|
|
98
|
+
if (props.to) {
|
|
99
|
+
event.stopPropagation()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
emit('click', event)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function onShowMore() {
|
|
106
|
+
showAll.value = true
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<template>
|
|
111
|
+
<Component
|
|
112
|
+
:is="to ? NuxtLinkLocale : 'div'"
|
|
113
|
+
:class="{
|
|
114
|
+
'font-bold': bold,
|
|
115
|
+
'font-medium': uppercase || !bold,
|
|
116
|
+
'truncate': truncate,
|
|
117
|
+
'underline text-indigo-700 dark:text-indigo-300': !!to,
|
|
118
|
+
'uppercase': uppercase,
|
|
119
|
+
'whitespace-nowrap': noWrap,
|
|
120
|
+
underline,
|
|
121
|
+
|
|
122
|
+
'bg-gray-100 dark:bg-gray-900': background === 'gray',
|
|
123
|
+
'bg-white dark:bg-gray-900': background === 'white',
|
|
124
|
+
|
|
125
|
+
'ml-0.5': ['3xs'].includes(size) && !reverse && hasMargin,
|
|
126
|
+
'ml-1.5': ['2xs', 'xs', 'sm'].includes(size) && !reverse && hasMargin,
|
|
127
|
+
'ml-2': ['base', 'lg'].includes(size) && !reverse && hasMargin,
|
|
128
|
+
'ml-2.5': ['xl', '2xl'].includes(size) && !reverse && hasMargin,
|
|
129
|
+
'ml-3': ['3xl', '4xl'].includes(size) && !reverse && hasMargin,
|
|
130
|
+
'mr-0.5': ['3xs'].includes(size) && reverse && hasMargin,
|
|
131
|
+
'mr-1.5': ['2xs', 'xs', 'sm'].includes(size) && reverse && hasMargin,
|
|
132
|
+
'mr-2': ['base', 'lg'].includes(size) && reverse && hasMargin,
|
|
133
|
+
'mr-2.5': ['xl', '2xl'].includes(size) && reverse && hasMargin,
|
|
134
|
+
'mr-3': ['3xl', '4xl'].includes(size) && reverse && hasMargin,
|
|
135
|
+
|
|
136
|
+
'text-3xs': (size === '3xs') && !uppercase,
|
|
137
|
+
'text-2xs': (size === '2xs') || (size === 'xs' && uppercase),
|
|
138
|
+
'text-xs': (size === 'xs' && !uppercase) || (size === 'sm' && uppercase),
|
|
139
|
+
'text-sm': (size === 'sm' && !uppercase) || (size === 'base' && uppercase),
|
|
140
|
+
'text-base': (size === 'base' && !uppercase) || (size === 'lg' && uppercase),
|
|
141
|
+
'text-lg': (size === 'lg' && !uppercase) || (size === 'xl' && uppercase),
|
|
142
|
+
'text-xl': (size === 'xl' && !uppercase) || (size === '2xl' && uppercase),
|
|
143
|
+
'text-2xl': (size === '2xl' && !uppercase) || (size === '3xl' && uppercase),
|
|
144
|
+
'text-3xl': (size === '3xl' && !uppercase) || (size === '4xl' && uppercase),
|
|
145
|
+
'text-4xl': size === '4xl' && !uppercase,
|
|
146
|
+
}"
|
|
147
|
+
:to="to"
|
|
148
|
+
@click="onClick"
|
|
149
|
+
>
|
|
150
|
+
<template v-if="!skeleton">
|
|
151
|
+
<span v-if="maxCharacters || typeof text === 'string'">
|
|
152
|
+
{{ finalText }}
|
|
153
|
+
</span>
|
|
154
|
+
|
|
155
|
+
<template v-else-if="typeof text === 'object'">
|
|
156
|
+
<span class="sm:hidden">
|
|
157
|
+
{{ text.sm }}
|
|
158
|
+
</span>
|
|
159
|
+
|
|
160
|
+
<span class="hidden sm:inline">
|
|
161
|
+
{{ text.base }}
|
|
162
|
+
</span>
|
|
163
|
+
</template>
|
|
164
|
+
|
|
165
|
+
<BaseText
|
|
166
|
+
v-if="maxCharacters && typeof text === 'string' && finalText?.length !== text.length"
|
|
167
|
+
class="inline cursor-pointer text-indigo-700 dark:text-indigo-300"
|
|
168
|
+
has-margin
|
|
169
|
+
:size="size"
|
|
170
|
+
:text="t('showMore')"
|
|
171
|
+
@click="onShowMore"
|
|
172
|
+
/>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<div
|
|
176
|
+
v-else
|
|
177
|
+
class="w-full rounded bg-gray-300 dark:bg-gray-700"
|
|
178
|
+
:class="{
|
|
179
|
+
'h-2': size === '3xs',
|
|
180
|
+
'h-2.5': size === '2xs',
|
|
181
|
+
'h-3': size === 'xs',
|
|
182
|
+
'h-3.5': size === 'sm',
|
|
183
|
+
'h-4': size === 'base',
|
|
184
|
+
'h-4.5': size === 'lg',
|
|
185
|
+
'h-5': size === 'xl',
|
|
186
|
+
'h-6': size === '2xl',
|
|
187
|
+
'h-7': size === '3xl',
|
|
188
|
+
'h-8': size === '4xl',
|
|
189
|
+
}"
|
|
190
|
+
/>
|
|
191
|
+
|
|
192
|
+
<slot />
|
|
193
|
+
</Component>
|
|
194
|
+
</template>
|
|
195
|
+
|
|
196
|
+
<i18n lang="json">
|
|
197
|
+
{
|
|
198
|
+
"en": {
|
|
199
|
+
"showMore": "(show more)"
|
|
200
|
+
},
|
|
201
|
+
"fr": {
|
|
202
|
+
"showMore": "(afficher)"
|
|
203
|
+
},
|
|
204
|
+
"ja": {
|
|
205
|
+
"showMore": "(もっと見る)"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
</i18n>
|
package/package.json
CHANGED