@saasmakers/ui 0.1.38 → 0.1.40

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,46 @@
1
+ <script lang="ts" setup>
2
+ import type { BaseBordered } from '../../types/bases'
3
+
4
+ withDefaults(defineProps<BaseBordered>(), {
5
+ background: 'white',
6
+ borderColor: 'gray',
7
+ hasBorder: true,
8
+ shadow: false,
9
+ title: '',
10
+ })
11
+ </script>
12
+
13
+ <template>
14
+ <div
15
+ class="flex flex-col items-center p-4 sm:p-6"
16
+ :class="{
17
+ 'rounded-xl border pt-0 sm:pt-0': hasBorder,
18
+ 'shadow-sm': shadow,
19
+
20
+ 'bg-gray-100 dark:bg-gray-900': background === 'gray',
21
+ 'bg-white dark:bg-gray-900': background === 'white',
22
+
23
+ 'border-black dark:border-white': borderColor === 'black',
24
+ 'border-gray-200 dark:border-gray-800': borderColor === 'gray',
25
+ }"
26
+ >
27
+ <BaseText
28
+ v-if="title"
29
+ class="mb-4 inline-block px-3 text-center text-gray-900 -mt-2 sm:px-4 dark:text-gray-100"
30
+ :class="{
31
+ 'bg-gray-100 dark:bg-gray-900': background === 'gray',
32
+ 'bg-white dark:bg-gray-900': background === 'white',
33
+ }"
34
+ size="xs"
35
+ :text="title"
36
+ uppercase
37
+ />
38
+
39
+ <div
40
+ v-if="$slots.default"
41
+ class="w-full"
42
+ >
43
+ <slot />
44
+ </div>
45
+ </div>
46
+ </template>
@@ -0,0 +1,132 @@
1
+ <script lang="ts" setup>
2
+ import type { BaseButton } from '../../types/bases'
3
+ import { NuxtLinkLocale } from '#components'
4
+
5
+ const props = withDefaults(defineProps<BaseButton>(), {
6
+ background: true,
7
+ circular: false,
8
+ color: 'black',
9
+ confirmation: false,
10
+ disabled: false,
11
+ fullWidth: false,
12
+ icon: undefined,
13
+ iconColor: undefined,
14
+ id: undefined,
15
+ light: false,
16
+ loading: false,
17
+ reverse: false,
18
+ size: 'base',
19
+ text: '',
20
+ to: undefined,
21
+ type: 'button',
22
+ })
23
+
24
+ const emit = defineEmits<{
25
+ click: [event: MouseEvent, id: number | string | undefined]
26
+ confirm: [event: MouseEvent, id: number | string | undefined]
27
+ }>()
28
+
29
+ const confirming = ref(false)
30
+
31
+ const { t } = useI18n()
32
+
33
+ function onClick(event: MouseEvent) {
34
+ if (!props.loading) {
35
+ if (props.confirmation) {
36
+ if (confirming.value) {
37
+ emit('confirm', event, props.id)
38
+ }
39
+ else {
40
+ setTimeout(() => (confirming.value = false), 3 * 1000)
41
+ }
42
+
43
+ confirming.value = !confirming.value
44
+ }
45
+
46
+ emit('click', event, props.id)
47
+ }
48
+ }
49
+ </script>
50
+
51
+ <template>
52
+ <component
53
+ :is="to ? NuxtLinkLocale : 'button'"
54
+ class="relative inline-block select-none appearance-none border rounded-md focus:outline-none"
55
+ :class="{
56
+ 'inline-block': !circular,
57
+ 'flex items-center justify-center': circular,
58
+ 'cursor-not-allowed opacity-50': disabled,
59
+ 'cursor-wait': loading,
60
+ 'cursor-pointer': !loading,
61
+ 'w-full': fullWidth,
62
+ 'bg-transparent shadow-none': light,
63
+ 'shadow-sm': !light,
64
+
65
+ 'h-6 w-6': size === '2xs' && circular,
66
+ 'h-8 w-8': size === 'xs' && circular && !confirming,
67
+ 'h-10 w-10': size === 'sm' && circular && !confirming,
68
+ 'h-12 w-12': size === 'base' && circular && !confirming,
69
+ 'h-14 w-14': size === 'lg' && circular && !confirming,
70
+ 'h-16 w-16': size === 'xl' && circular && !confirming,
71
+
72
+ 'border-gray-900 dark:border-gray-100 bg-gray-900 dark:bg-gray-100 text-white dark:text-black': color === 'black' && !light,
73
+ 'hover:bg-black dark:hover:bg-white hover:text-white dark:hover:text-black': color === 'black' && !light && !disabled && !loading,
74
+ 'border-gray-900 dark:border-gray-100 text-gray-900 dark:text-gray-100': color === 'black' && light,
75
+ 'border-gray-700 dark:border-gray-300 bg-gray-700 dark:bg-gray-300 text-white dark:text-black': color === 'gray' && !light,
76
+ 'hover:bg-gray-800 dark:hover:bg-gray-200': color === 'gray' && !light && !disabled && !loading,
77
+ 'border-gray-700 dark:border-gray-300 text-gray-700 dark:text-gray-300': color === 'gray' && light,
78
+ 'border-green-700 dark:border-green-300 bg-green-700 dark:bg-green-300 text-white dark:text-black': color === 'green' && !light,
79
+ 'hover:bg-green-800 dark:hover:bg-green-200': color === 'green' && !light && !disabled && !loading,
80
+ 'border-green-700 dark:border-green-300 text-green-700 dark:text-green-300': color === 'green' && light,
81
+ 'border-indigo-700 dark:border-indigo-300 bg-indigo-700 dark:bg-indigo-300 text-white dark:text-black': color === 'indigo' && !light,
82
+ 'hover:bg-indigo-800 dark:hover:bg-indigo-200': color === 'indigo' && !light && !disabled && !loading,
83
+ 'border-indigo-700 dark:border-indigo-300 text-indigo-700 dark:text-indigo-300': color === 'indigo' && light,
84
+ 'border-orange-700 dark:border-orange-300 bg-orange-700 dark:bg-orange-300 text-white dark:text-black': color === 'orange' && !light,
85
+ 'hover:bg-orange-800 dark:hover:bg-orange-200': color === 'orange' && !light && !disabled && !loading,
86
+ 'border-orange-700 dark:border-orange-300 text-orange-700 dark:text-orange-300': color === 'orange' && light,
87
+ 'border-red-700 dark:border-red-300 bg-red-700 dark:bg-red-300 text-white dark:text-black': color === 'red' && !light,
88
+ 'hover:bg-red-800 dark:hover:bg-red-200': color === 'red' && !light && !disabled && !loading,
89
+ 'border-red-700 dark:border-red-300 text-red-700 dark:text-red-300': color === 'red' && light,
90
+ 'border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100': color === 'white' && !light,
91
+ 'hover:bg-white dark:hover:bg-gray-900': color === 'white' && !light && !disabled && !loading,
92
+ 'border-white dark:border-gray-900 text-white dark:text-black': color === 'white' && light,
93
+ 'hover:border-black dark:hover:border-white hover:text-black dark:hover:text-white': color !== 'white' && light && !disabled && !loading,
94
+ 'hover:bg-white dark:hover:bg-gray-900 hover:text-gray-800 dark:hover:text-gray-200': color === 'white' && light && !disabled && !loading,
95
+
96
+ 'h-6 px-3': size === '2xs' && (!circular || confirming),
97
+ 'h-8 px-4': size === 'xs' && (!circular || confirming),
98
+ 'h-10 px-5': size === 'sm' && (!circular || confirming),
99
+ 'h-12 px-6': size === 'base' && (!circular || confirming),
100
+ 'h-13 px-6.5': size === 'lg' && (!circular || confirming),
101
+ 'h-14 px-7': size === 'xl' && (!circular || confirming),
102
+ }"
103
+ :disabled="disabled"
104
+ :to="to"
105
+ :type="typeof to === 'object' && to ? null : type"
106
+ @click="onClick"
107
+ >
108
+ <span
109
+ class="h-full flex items-center justify-center"
110
+ :class="{ 'opacity-0': loading }"
111
+ >
112
+ <slot />
113
+
114
+ <BaseIcon
115
+ class="flex-initial"
116
+ :color="iconColor"
117
+ :icon="confirming ? undefined : icon"
118
+ :light="light"
119
+ :reverse="reverse"
120
+ :size="size"
121
+ :text="confirming ? t('globals.confirm') : text"
122
+ />
123
+ </span>
124
+
125
+ <BaseSpinner
126
+ v-if="loading"
127
+ class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2"
128
+ :color="!background ? 'black' : light ? color : color === 'white' ? 'indigo' : 'white'"
129
+ :size="size"
130
+ />
131
+ </component>
132
+ </template>
@@ -0,0 +1,79 @@
1
+ <script lang="ts" setup>
2
+ import type { BaseOverlay } from '../../types/bases'
3
+ import { Motion } from 'motion-v'
4
+ import { getIcon } from '../../composables/useIcons'
5
+ import useMotion from '../../composables/useMotion'
6
+
7
+ withDefaults(defineProps<BaseOverlay>(), {
8
+ active: true,
9
+ clickable: true,
10
+ fixed: true,
11
+ hasClose: true,
12
+ opacity: 75,
13
+ position: 'absolute',
14
+ })
15
+
16
+ const emit = defineEmits<{
17
+ click: [event: MouseEvent]
18
+ close: [event: MouseEvent]
19
+ }>()
20
+
21
+ const { fadeIn } = useMotion()
22
+
23
+ function onClick(event: MouseEvent) {
24
+ emit('click', event)
25
+ }
26
+
27
+ function onClose(event: MouseEvent) {
28
+ emit('close', event)
29
+ }
30
+ </script>
31
+
32
+ <template>
33
+ <div
34
+ v-hotkey="{ esc: onClose }"
35
+ :class="{
36
+ 'fixed inset-0': fixed,
37
+ 'cursor-pointer': clickable || hasClose,
38
+ }"
39
+ @click="onClick"
40
+ >
41
+ <BaseIcon
42
+ v-if="hasClose"
43
+ class="absolute right-4 top-4 z-50 text-gray-200 dark:text-gray-800"
44
+ :icon="getIcon('close')"
45
+ @click="onClose"
46
+ />
47
+
48
+ <div
49
+ v-if="$slots.default"
50
+ class="relative z-50 h-full w-full"
51
+ >
52
+ <slot />
53
+ </div>
54
+
55
+ <Motion
56
+ :animate="fadeIn.animate"
57
+ as="span"
58
+ class="absolute inset-0 z-40"
59
+ :initial="fadeIn.initial"
60
+ >
61
+ <div
62
+ class="inset-0 bg-gray-900 dark:bg-gray-100"
63
+ :class="{
64
+ 'h-0 w-0': !active,
65
+
66
+ 'opacity-0': opacity === 0,
67
+ 'opacity-25': opacity === 25,
68
+ 'opacity-50': opacity === 50,
69
+ 'opacity-75': opacity === 75,
70
+ 'opacity-95': opacity === 95,
71
+ 'opacity-100': opacity === 100,
72
+
73
+ 'absolute': position === 'absolute',
74
+ 'fixed': position === 'fixed',
75
+ }"
76
+ />
77
+ </Motion>
78
+ </div>
79
+ </template>
@@ -3,7 +3,7 @@ import type { BaseText } from '../../types/bases'
3
3
  import { NuxtLinkLocale } from '#components'
4
4
 
5
5
  const props = withDefaults(defineProps<BaseText>(), {
6
- background: '',
6
+ background: undefined,
7
7
  bold: false,
8
8
  hasMargin: false,
9
9
  maxCharacters: 0,
@@ -10,6 +10,7 @@
10
10
 
11
11
  const icons = {
12
12
  checkCircle: 'hugeicons:checkmark-circle-02',
13
+ close: 'hugeicons:cancel-01',
13
14
  closeCircle: 'hugeicons:cancel-circle',
14
15
  default: 'hugeicons:help-circle',
15
16
  exclamationCircle: 'hugeicons:alert-circle',
@@ -0,0 +1,39 @@
1
+ export default function useMotion() {
2
+ const fadeIn = {
3
+ animate: {
4
+ opacity: 1,
5
+ transition: { duration: 0.25 },
6
+ },
7
+ initial: { opacity: 0 },
8
+ }
9
+
10
+ const fadeInLeft = {
11
+ animate: {
12
+ opacity: 1,
13
+ transition: { duration: 0.25 },
14
+ x: 0,
15
+ },
16
+ initial: {
17
+ opacity: 0,
18
+ x: -25,
19
+ },
20
+ }
21
+
22
+ const fadeInUp = {
23
+ animate: {
24
+ opacity: 1,
25
+ transition: { duration: 0.25 },
26
+ y: 0,
27
+ },
28
+ initial: {
29
+ opacity: 0,
30
+ y: 25,
31
+ },
32
+ }
33
+
34
+ return {
35
+ fadeIn,
36
+ fadeInLeft,
37
+ fadeInUp,
38
+ }
39
+ }
@@ -1,3 +1,5 @@
1
+ export type BaseBackground = 'gray' | 'white'
2
+
1
3
  export type BaseColor
2
4
  = | 'black'
3
5
  | 'gray'
@@ -25,6 +27,39 @@ export type BaseStatus
25
27
  | 'success'
26
28
  | 'warning'
27
29
 
30
+ export interface BaseBordered {
31
+ background?: BaseBackground
32
+ borderColor?: BaseBorderedColor
33
+ hasBorder?: boolean
34
+ shadow?: boolean
35
+ title: string
36
+ }
37
+
38
+ export type BaseBorderedColor = 'black' | 'gray'
39
+
40
+ export interface BaseButton {
41
+ background?: boolean
42
+ circular?: boolean
43
+ color?: BaseColor
44
+ confirmation?: boolean
45
+ disabled?: boolean
46
+ fullWidth?: boolean
47
+ icon?: string
48
+ iconColor?: BaseColor
49
+ id?: number | string
50
+ light?: boolean
51
+ loading?: boolean
52
+ reverse?: boolean
53
+ size?: BaseButtonSize
54
+ text?: BaseTextText
55
+ to?: RouteLocationNamedI18n
56
+ type?: BaseButtonType
57
+ }
58
+
59
+ export type BaseButtonSize = '2xs' | 'base' | 'lg' | 'sm' | 'xl' | 'xs'
60
+
61
+ export type BaseButtonType = 'button' | 'reset' | 'submit'
62
+
28
63
  export interface BaseDivider {
29
64
  borderStyle?: BaseDividerBorderStyle
30
65
  margin?: number
@@ -53,6 +88,19 @@ export interface BaseIcon {
53
88
  uppercase?: boolean
54
89
  }
55
90
 
91
+ export interface BaseOverlay {
92
+ active?: boolean
93
+ clickable?: boolean
94
+ fixed?: boolean
95
+ hasClose?: boolean
96
+ opacity?: BaseOverlayOpacity
97
+ position?: BaseOverlayPosition
98
+ }
99
+
100
+ export type BaseOverlayOpacity = 0 | 25 | 50 | 75 | 95 | 100
101
+
102
+ export type BaseOverlayPosition = 'absolute' | 'fixed'
103
+
56
104
  export interface BaseSpinner {
57
105
  clickable?: boolean
58
106
  color?: BaseColor
@@ -79,6 +127,4 @@ export interface BaseText {
79
127
  uppercase?: boolean
80
128
  }
81
129
 
82
- export type BaseTextBackground = '' | 'gray' | 'white'
83
-
84
130
  export type BaseTextText = string | { base: string, sm: string }
@@ -5,16 +5,24 @@ declare global {
5
5
  type RouteLocationNamedI18n = import('vue-router').RouteLocationNamedI18n
6
6
 
7
7
  // Bases
8
+ type BaseBackground = Bases.BaseBackground
9
+ type BaseBordered = Bases.BaseBordered
10
+ type BaseBorderedColor = Bases.BaseBorderedColor
11
+ type BaseButton = Bases.BaseButton
12
+ type BaseButtonSize = Bases.BaseButtonSize
13
+ type BaseButtonType = Bases.BaseButtonType
8
14
  type BaseColor = Bases.BaseColor
9
- type BaseSize = Bases.BaseSize
10
- type BaseStatus = Bases.BaseStatus
11
15
  type BaseDivider = Bases.BaseDivider
12
16
  type BaseDividerBorderStyle = Bases.BaseDividerBorderStyle
13
17
  type BaseDividerSize = Bases.BaseDividerSize
14
- type BaseSpinner = Bases.BaseSpinner
15
18
  type BaseIcon = Bases.BaseIcon
19
+ type BaseOverlay = Bases.BaseOverlay
20
+ type BaseOverlayOpacity = Bases.BaseOverlayOpacity
21
+ type BaseOverlayPosition = Bases.BaseOverlayPosition
22
+ type BaseSize = Bases.BaseSize
23
+ type BaseSpinner = Bases.BaseSpinner
24
+ type BaseStatus = Bases.BaseStatus
16
25
  type BaseText = Bases.BaseText
17
- type BaseTextBackground = Bases.BaseTextBackground
18
26
  type BaseTextText = Bases.BaseTextText
19
27
  }
20
28
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@saasmakers/ui",
3
3
  "type": "module",
4
- "version": "0.1.38",
4
+ "version": "0.1.40",
5
5
  "private": false,
6
6
  "description": "Reusable Nuxt UI components for SaaS Makers projects",
7
7
  "license": "MIT",