@saasmakers/ui 0.1.17 → 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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
3
  "type": "module",
4
- "version": "0.1.17",
4
+ "version": "0.1.19",
5
5
  "private": false,
6
6
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
7
7
  "license": "MIT",
package/types/bases.d.ts CHANGED
@@ -36,7 +36,7 @@ declare global {
36
36
  size?: BaseSize
37
37
  skeleton?: boolean
38
38
  text?: BaseTextText
39
- to?: RawLocation
39
+ to?: RouteLocationRaw
40
40
  truncate?: boolean
41
41
  underline?: boolean
42
42
  uppercase?: boolean
package/types/index.d.ts CHANGED
@@ -2,7 +2,9 @@ import './bases'
2
2
 
3
3
  declare global {
4
4
  // Packages
5
- type RawLocation = import('@intlify/vue-router-bridge').RawLocation
5
+ type LocationQuery = import('vue-router').LocationQuery
6
+ type RouteLocation = import('vue-router').RouteLocation
7
+ type RouteLocationRaw = import('vue-router').RouteLocationRaw
6
8
  }
7
9
 
8
10
  export {}
@@ -1,5 +0,0 @@
1
- <template>
2
- <div>
3
- <h1>Hello World!</h1>
4
- </div>
5
- </template>