@saasmakers/ui 2.0.48 → 2.0.50

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.
@@ -3,22 +3,17 @@ import { NuxtLinkLocale } from '#components'
3
3
  import type { BaseCard } from '../../types/bases'
4
4
 
5
5
  const props = withDefaults(defineProps<BaseCard>(), {
6
- avatar: '',
7
6
  clickable: true,
8
7
  color: 'gray',
9
8
  description: '',
10
9
  disabled: false,
11
10
  emoji: undefined,
12
- hasBackground: true,
13
11
  hasChevron: false,
14
- icon: undefined,
15
12
  id: undefined,
16
13
  image: '',
17
14
  isSelected: false,
18
15
  orientation: 'horizontal',
19
- size: 'base',
20
16
  title: undefined,
21
- titleIcon: undefined,
22
17
  to: undefined,
23
18
  })
24
19
 
@@ -28,44 +23,16 @@ const emit = defineEmits<{
28
23
 
29
24
  defineSlots<{
30
25
  default?: () => VNode[]
31
- innerBoxLeft?: () => VNode[]
32
- innerBoxRight?: () => VNode[]
33
- outerBoxLeft?: () => VNode[]
34
- outerBoxRight?: () => VNode[]
35
- right?: () => VNode[]
36
26
  }>()
37
27
 
38
- const hasAvatarBox = computed<boolean>(() => {
39
- return !!(props.avatar || props.emoji || props.icon || props.image)
40
- })
41
-
42
28
  const hasMediaBox = computed<boolean>(() => {
43
- return !!(props.avatar || props.icon || props.image)
29
+ return !!(props.image || (props.emoji && props.orientation !== 'horizontal'))
44
30
  })
45
31
 
46
- const isHorizontal = computed(() => props.orientation === 'horizontal')
47
-
48
32
  const isClickable = computed(() => {
49
33
  return props.to || props.clickable
50
34
  })
51
35
 
52
- const titleColorClass = computed(() => {
53
- if (!isHorizontal.value || props.color === 'gray') {
54
- return 'text-gray-900 dark:text-gray-100'
55
- }
56
-
57
- const colorClasses: Partial<Record<BaseColor, string>> = {
58
- black: 'text-gray-900 dark:text-gray-100',
59
- green: 'text-green-600 dark:text-green-400',
60
- indigo: 'text-indigo-600 dark:text-indigo-400',
61
- orange: 'text-orange-600 dark:text-orange-400',
62
- red: 'text-red-600 dark:text-red-400',
63
- white: 'text-gray-900 dark:text-gray-100',
64
- }
65
-
66
- return colorClasses[props.color] ?? 'text-gray-900 dark:text-gray-100'
67
- })
68
-
69
36
  function onClick(event: MouseEvent) {
70
37
  emit('click', event, props.id)
71
38
  }
@@ -79,15 +46,12 @@ function onClick(event: MouseEvent) {
79
46
  'cursor-default': !isClickable,
80
47
  'cursor-pointer': isClickable,
81
48
  'opacity-50': disabled,
82
- 'base-surface h-12 overflow-hidden pl-2 pr-2.5': hasBackground && size === 'base' && isHorizontal,
83
- 'base-surface h-14 overflow-hidden pl-3 pr-3': hasBackground && size === 'lg' && isHorizontal,
84
- 'base-surface p-3': hasBackground && size === 'base' && !isHorizontal,
85
- 'base-surface p-4': hasBackground && size === 'lg' && !isHorizontal,
86
- 'w-fit': !hasBackground && isHorizontal,
87
- 'base-border-hover': hasBackground && isClickable,
88
- 'rounded-lg': hasBackground && isHorizontal,
89
- 'rounded-xl': hasBackground && !isHorizontal,
90
- 'relative': !isHorizontal,
49
+ 'base-surface h-12 overflow-hidden pl-2 pr-2.5': orientation === 'horizontal',
50
+ 'base-surface p-3': orientation !== 'horizontal',
51
+ 'base-border-hover': isClickable,
52
+ 'rounded-lg': orientation === 'horizontal',
53
+ 'rounded-xl': orientation !== 'horizontal',
54
+ 'relative': orientation !== 'horizontal',
91
55
  }"
92
56
  :to="disabled ? undefined : to"
93
57
  @click="onClick"
@@ -95,23 +59,19 @@ function onClick(event: MouseEvent) {
95
59
  <div
96
60
  class="flex overflow-hidden"
97
61
  :class="{
98
- 'h-12 w-full flex-row items-center text-left': isHorizontal && size === 'base' && hasBackground,
99
- 'h-14 w-full flex-row items-center text-left': isHorizontal && size === 'lg' && hasBackground,
100
- 'flex-row items-center text-left': isHorizontal && !hasBackground,
101
- 'flex-col items-center text-center': !isHorizontal,
62
+ 'h-12 w-full flex-row items-center text-left': orientation === 'horizontal',
63
+ 'flex-col items-center text-center': orientation !== 'horizontal',
102
64
  }"
103
65
  >
104
66
  <span
105
67
  class="flex items-center"
106
68
  :class="{
107
- 'shrink-0 justify-center': isHorizontal,
108
- 'justify-center': !isHorizontal,
69
+ 'shrink-0 justify-center': orientation === 'horizontal',
70
+ 'justify-center': orientation !== 'horizontal',
109
71
  }"
110
72
  >
111
- <slot name="outerBoxLeft" />
112
-
113
73
  <BaseEmoji
114
- v-if="emoji && isHorizontal"
74
+ v-if="emoji && orientation === 'horizontal'"
115
75
  class="mr-2 shrink-0 bg-gray-100 flex-initial dark:bg-gray-900"
116
76
  :clickable="false"
117
77
  :emoji="emoji"
@@ -119,115 +79,79 @@ function onClick(event: MouseEvent) {
119
79
  />
120
80
 
121
81
  <span
122
- v-if="hasMediaBox || (emoji && !isHorizontal)"
82
+ v-if="hasMediaBox"
123
83
  class="relative z-10 flex items-center justify-center flex-initial"
124
84
  :class="{
125
- 'border shadow-inner': !avatar && !image && (!emoji || !isHorizontal),
126
- 'rounded-lg': !avatar && !image && (!emoji || !isHorizontal),
127
- 'base-border bg-gray-100 dark:bg-gray-900': !avatar && !image && (!emoji || !isHorizontal),
128
- 'mr-2': isHorizontal && size === 'base',
129
- 'mr-3': isHorizontal && size === 'lg',
130
- 'mb-2': !isHorizontal && size === 'base',
131
- 'mb-3': !isHorizontal && size === 'lg',
132
- 'h-9 w-9': size === 'base' && isHorizontal,
133
- 'h-11 w-11': size === 'lg' && isHorizontal,
134
- 'h-20 w-20': size === 'base' && !isHorizontal,
135
- 'h-24 w-24': size === 'lg' && !isHorizontal,
85
+ 'border shadow-inner rounded-lg base-border bg-gray-100 dark:bg-gray-900': !image && (!emoji || orientation !== 'horizontal'),
86
+ 'mr-2': orientation === 'horizontal',
87
+ 'mb-2': orientation !== 'horizontal',
88
+ 'h-9 w-9': orientation === 'horizontal',
89
+ 'h-20 w-20': orientation !== 'horizontal',
136
90
  }"
137
91
  >
138
- <slot name="innerBoxLeft" />
139
-
140
- <BaseAvatar
141
- v-if="avatar"
142
- class="rounded-lg flex-initial"
143
- :class="{
144
- 'h-10 w-10': size === 'base' && isHorizontal,
145
- 'h-12 w-12': size === 'lg' && isHorizontal,
146
- 'h-20 w-20': size === 'base' && !isHorizontal,
147
- 'h-24 w-24': size === 'lg' && !isHorizontal,
148
- }"
149
- :src="avatar"
150
- />
151
-
152
92
  <BaseEmoji
153
- v-else-if="emoji"
93
+ v-if="emoji && orientation !== 'horizontal'"
154
94
  class="m-0.5"
155
95
  :emoji="emoji"
156
96
  :has-box="false"
157
- :size="size === 'lg' ? 'lg' : 'base'"
158
- />
159
-
160
- <BaseIcon
161
- v-else-if="icon"
162
- :color="color"
163
- :icon="icon"
164
- :size="size === 'lg' ? '2xl' : 'lg'"
165
97
  />
166
98
 
167
99
  <img
168
100
  v-else-if="image"
169
101
  class="select-none rounded-lg object-cover shadow-sm transition-[filter] duration-300 drag-none flex-initial"
170
102
  :class="{
171
- 'h-9 w-9': size === 'base' && isHorizontal,
172
- 'h-11 w-11': size === 'lg' && isHorizontal,
173
- 'h-20 w-20': size === 'base' && !isHorizontal,
174
- 'h-24 w-24': size === 'lg' && !isHorizontal,
103
+ 'h-9 w-9': orientation === 'horizontal',
104
+ 'h-20 w-20': orientation !== 'horizontal',
175
105
  'grayscale': disabled,
176
106
  }"
177
107
  :alt="title"
178
108
  loading="lazy"
179
109
  :src="image"
180
110
  >
181
-
182
- <slot name="innerBoxRight" />
183
111
  </span>
184
-
185
- <slot name="outerBoxRight" />
186
112
  </span>
187
113
 
188
114
  <div
189
115
  class="min-w-0 flex flex-col justify-center leading-snug"
190
116
  :class="{
191
- 'flex-1': isHorizontal && hasBackground,
192
- 'w-full': !isHorizontal,
193
- 'mr-4': isHorizontal && size === 'base' && (to || hasChevron),
194
- 'mr-5': isHorizontal && size === 'lg' && (to || hasChevron),
195
- 'items-center': !isHorizontal,
117
+ 'flex-1': orientation === 'horizontal',
118
+ 'w-full': orientation !== 'horizontal',
119
+ 'items-center': orientation !== 'horizontal',
196
120
  }"
197
121
  >
198
122
  <div
199
123
  class="w-full flex flex-col"
200
124
  :class="{
201
- 'gap-0': size === 'base',
202
- 'gap-0.5': size === 'lg',
203
- 'gap-1': !isHorizontal && size === 'base',
204
- 'gap-1.5': !isHorizontal && size === 'lg',
125
+ 'gap-0': orientation === 'horizontal',
126
+ 'gap-1': orientation !== 'horizontal',
205
127
  }"
206
128
  >
207
129
  <p
208
- v-if="title && isHorizontal && !titleIcon && hasBackground"
130
+ v-if="title && orientation === 'horizontal'"
209
131
  class="line-clamp-1 min-w-0 break-words text-xs font-medium tracking-tight uppercase"
210
- :class="titleColorClass"
132
+ :class="{
133
+ 'text-gray-900 dark:text-gray-100': color === 'gray' || color === 'black' || color === 'white',
134
+ 'text-green-600 dark:text-green-400': color === 'green',
135
+ 'text-indigo-600 dark:text-indigo-400': color === 'indigo',
136
+ 'text-orange-600 dark:text-orange-400': color === 'orange',
137
+ 'text-red-600 dark:text-red-400': color === 'red',
138
+ }"
211
139
  >
212
140
  {{ title }}
213
141
  </p>
214
142
 
215
143
  <BaseIcon
216
144
  v-else-if="title"
217
- class="w-full"
218
- :class="{ 'self-center': !hasAvatarBox }"
219
- :color="isHorizontal ? color : undefined"
220
- :icon="titleIcon"
221
- :size="size === 'lg' ? 'base' : 'sm'"
145
+ class="w-full self-center"
146
+ size="sm"
222
147
  :text="title"
223
- :truncate="isHorizontal"
224
148
  />
225
149
 
226
150
  <BaseText
227
- v-if="description && !isHorizontal"
151
+ v-if="description && orientation !== 'horizontal'"
228
152
  block
229
153
  class="text-gray-600 dark:text-gray-400"
230
- :size="size === 'lg' ? 'xs' : '2xs'"
154
+ size="2xs"
231
155
  :text="description"
232
156
  />
233
157
  </div>
@@ -237,23 +161,20 @@ function onClick(event: MouseEvent) {
237
161
  v-if="isSelected"
238
162
  class="flex-initial"
239
163
  :class="{
240
- 'mr-1.5 self-center': isHorizontal,
241
- 'absolute right-2 top-2': !isHorizontal && size === 'base',
242
- 'absolute right-2.5 top-2.5': !isHorizontal && size === 'lg',
164
+ 'mr-1.5 self-center': orientation === 'horizontal',
165
+ 'absolute right-2 top-2': orientation !== 'horizontal',
243
166
  }"
244
167
  color="green"
245
168
  :icon="getLayerIcon('checkCircle')"
246
- :size="size === 'lg' ? '2xl' : 'xl'"
169
+ size="xl"
247
170
  />
248
171
 
249
172
  <BaseIcon
250
- v-else-if="isHorizontal && (to || hasChevron)"
173
+ v-else-if="orientation === 'horizontal' && (to || hasChevron)"
251
174
  class="self-center text-gray-500 flex-initial dark:text-gray-500 group-hover:text-gray-900 dark:group-hover:text-gray-100"
252
175
  :icon="getLayerIcon('chevronRight')"
253
- :size="size === 'lg' ? '2xl' : 'xl'"
176
+ size="xl"
254
177
  />
255
-
256
- <slot name="right" />
257
178
  </div>
258
179
 
259
180
  <slot />
@@ -100,15 +100,29 @@ function onClick(event: MouseEvent) {
100
100
  emit('click', event)
101
101
  }
102
102
 
103
+ function onEnterKeyDown(event: KeyboardEvent) {
104
+ if (!props.to) {
105
+ onKeyDown(event)
106
+ }
107
+ }
108
+
103
109
  function onKeyDown(event: KeyboardEvent) {
104
110
  if (isClickable.value) {
105
111
  (event.currentTarget as HTMLElement).click()
106
112
  }
107
113
  }
114
+
115
+ function onSpaceKeyDown(event: KeyboardEvent) {
116
+ if (!props.to) {
117
+ event.preventDefault()
118
+ onKeyDown(event)
119
+ }
120
+ }
108
121
  </script>
109
122
 
110
123
  <template>
111
- <div
124
+ <component
125
+ :is="to ? NuxtLinkLocale : 'div'"
112
126
  class="flex items-center"
113
127
  :class="{
114
128
  'group cursor-pointer hover:underline hover:text-black dark:hover:text-white': isClickable && text,
@@ -116,14 +130,14 @@ function onKeyDown(event: KeyboardEvent) {
116
130
  'flex-row': !reverse,
117
131
  'flex-row-reverse': reverse,
118
132
  }"
119
- :role="isClickable ? 'button' : undefined"
120
- :tabindex="isClickable ? 0 : undefined"
133
+ :role="isClickable && !to ? 'button' : undefined"
134
+ :tabindex="isClickable && !to ? 0 : undefined"
135
+ :to="to"
121
136
  @click="onClick"
122
- @keydown.enter="onKeyDown"
123
- @keydown.space.prevent="onKeyDown"
137
+ @keydown.enter="onEnterKeyDown"
138
+ @keydown.space="onSpaceKeyDown"
124
139
  >
125
- <component
126
- :is="to ? NuxtLinkLocale : 'span'"
140
+ <span
127
141
  v-if="finalIcon && !loading"
128
142
  class="flex items-center justify-center"
129
143
  :class="{
@@ -153,10 +167,9 @@ function onKeyDown(event: KeyboardEvent) {
153
167
  'group-hover:text-orange-700 dark:group-hover:text-orange-300': isClickable && finalColor === 'orange',
154
168
  'group-hover:text-red-700 dark:group-hover:text-red-300': isClickable && finalColor === 'red',
155
169
  }"
156
- :to="to"
157
170
  >
158
171
  <Icon :name="finalIcon" />
159
- </component>
172
+ </span>
160
173
 
161
174
  <BaseSpinner
162
175
  v-else-if="loading"
@@ -176,7 +189,7 @@ function onKeyDown(event: KeyboardEvent) {
176
189
  :truncate="truncate"
177
190
  :underline="underline"
178
191
  />
179
- </div>
192
+ </component>
180
193
  </template>
181
194
 
182
195
  <i18n lang="json">
@@ -81,29 +81,22 @@ export type BaseButtonSize
81
81
  export type BaseButtonType = 'button' | 'reset' | 'submit'
82
82
 
83
83
  export interface BaseCard {
84
- avatar?: string
85
84
  clickable?: boolean
86
85
  color?: BaseColor
87
86
  description?: string
88
87
  disabled?: boolean
89
88
  emoji?: string
90
- hasBackground?: boolean
91
89
  hasChevron?: boolean
92
- icon?: string
93
90
  id?: number | string
94
91
  image?: string
95
92
  isSelected?: boolean
96
93
  orientation?: BaseCardOrientation
97
- size?: BaseCardSize
98
94
  title?: string
99
- titleIcon?: string
100
95
  to?: RouteLocationNamedI18n
101
96
  }
102
97
 
103
98
  export type BaseCardOrientation = 'horizontal' | 'vertical'
104
99
 
105
- export type BaseCardSize = 'base' | 'lg'
106
-
107
100
  export interface BaseCharacter {
108
101
  character?: BaseCharacterCharacter
109
102
  size?: BaseCharacterSize
@@ -30,7 +30,6 @@ declare global {
30
30
  type BaseButtonType = import('./bases').BaseButtonType
31
31
  type BaseCard = import('./bases').BaseCard
32
32
  type BaseCardOrientation = import('./bases').BaseCardOrientation
33
- type BaseCardSize = import('./bases').BaseCardSize
34
33
  type BaseCharacter = import('./bases').BaseCharacter
35
34
  type BaseCharacterCharacter = import('./bases').BaseCharacterCharacter
36
35
  type BaseCharacterSize = import('./bases').BaseCharacterSize
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
- "version": "2.0.48",
3
+ "version": "2.0.50",
4
4
  "private": false,
5
5
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
6
6
  "license": "MIT",