@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.
- package/app/components/bases/BaseBordered.vue +46 -0
- package/app/components/bases/BaseButton.vue +132 -0
- package/app/components/bases/BaseOverlay.vue +79 -0
- package/app/components/bases/BaseText.vue +1 -1
- package/app/composables/useIcons.ts +1 -0
- package/app/composables/useMotion.ts +39 -0
- package/app/types/bases.d.ts +48 -2
- package/app/types/global.d.ts +12 -4
- package/package.json +1 -1
|
@@ -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>
|
|
@@ -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
|
+
}
|
package/app/types/bases.d.ts
CHANGED
|
@@ -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 }
|
package/app/types/global.d.ts
CHANGED
|
@@ -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
|
|