@bobbykim/mcl-cards 0.2.0

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,92 @@
1
+ import type { ColorPalette, CrossOrigin, CtaTarget, HeadingSize } from '@bobbykim/manguito-theme';
2
+ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
3
+ title: string;
4
+ titleSize?: HeadingSize | undefined;
5
+ titleColor?: ColorPalette | undefined;
6
+ titleBlockColor?: ColorPalette | undefined;
7
+ borderColor?: ColorPalette | undefined;
8
+ imageSource?: string | undefined;
9
+ imageAlt?: string | undefined;
10
+ imageCors?: CrossOrigin | undefined;
11
+ displayGrayScale?: boolean | undefined;
12
+ ctaAsLink?: boolean | undefined;
13
+ ctaLink?: string | undefined;
14
+ ctaTarget?: CtaTarget | undefined;
15
+ rounded?: boolean | undefined;
16
+ }>, {
17
+ titleSize: string;
18
+ titleColor: string;
19
+ titleBlockColor: string;
20
+ borderColor: string;
21
+ displayGrayScale: boolean;
22
+ imageCors: string;
23
+ ctaAsLink: boolean;
24
+ ctaLink: string;
25
+ ctaTarget: string;
26
+ rounded: boolean;
27
+ }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
28
+ "card-click": (...args: any[]) => void;
29
+ }, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
30
+ title: string;
31
+ titleSize?: HeadingSize | undefined;
32
+ titleColor?: ColorPalette | undefined;
33
+ titleBlockColor?: ColorPalette | undefined;
34
+ borderColor?: ColorPalette | undefined;
35
+ imageSource?: string | undefined;
36
+ imageAlt?: string | undefined;
37
+ imageCors?: CrossOrigin | undefined;
38
+ displayGrayScale?: boolean | undefined;
39
+ ctaAsLink?: boolean | undefined;
40
+ ctaLink?: string | undefined;
41
+ ctaTarget?: CtaTarget | undefined;
42
+ rounded?: boolean | undefined;
43
+ }>, {
44
+ titleSize: string;
45
+ titleColor: string;
46
+ titleBlockColor: string;
47
+ borderColor: string;
48
+ displayGrayScale: boolean;
49
+ imageCors: string;
50
+ ctaAsLink: boolean;
51
+ ctaLink: string;
52
+ ctaTarget: string;
53
+ rounded: boolean;
54
+ }>>> & {
55
+ "onCard-click"?: ((...args: any[]) => any) | undefined;
56
+ }, {
57
+ titleColor: ColorPalette;
58
+ titleSize: HeadingSize;
59
+ borderColor: ColorPalette;
60
+ imageCors: CrossOrigin;
61
+ ctaAsLink: boolean;
62
+ ctaLink: string;
63
+ ctaTarget: CtaTarget;
64
+ rounded: boolean;
65
+ titleBlockColor: ColorPalette;
66
+ displayGrayScale: boolean;
67
+ }, {}>, {
68
+ default?(_: {}): any;
69
+ }>;
70
+ export default _default;
71
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
72
+ type __VLS_TypePropsToRuntimeProps<T> = {
73
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
74
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
75
+ } : {
76
+ type: import('vue').PropType<T[K]>;
77
+ required: true;
78
+ };
79
+ };
80
+ type __VLS_WithDefaults<P, D> = {
81
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
82
+ default: D[K];
83
+ }> : P[K];
84
+ };
85
+ type __VLS_Prettify<T> = {
86
+ [K in keyof T]: T[K];
87
+ } & {};
88
+ type __VLS_WithTemplateSlots<T, S> = T & {
89
+ new (): {
90
+ $slots: S;
91
+ };
92
+ };
@@ -0,0 +1,142 @@
1
+ <script setup lang="ts">
2
+ import { ref, computed } from 'vue'
3
+ import generateClass from '@bobbykim/manguito-theme'
4
+ import type {
5
+ ColorPalette,
6
+ CrossOrigin,
7
+ HeadingSize,
8
+ OpacityRange,
9
+ } from '@bobbykim/manguito-theme'
10
+
11
+ const props = withDefaults(
12
+ defineProps<{
13
+ imageSource: string
14
+ imageAlt?: string
15
+ title?: string
16
+ titleSize?: HeadingSize
17
+ titleColor?: ColorPalette
18
+ displayHighlight?: boolean
19
+ highlightColor?: ColorPalette
20
+ highlightOpacity?: OpacityRange
21
+ displayTitle?: boolean
22
+ cardColor?: ColorPalette
23
+ imageCors?: CrossOrigin
24
+ }>(),
25
+ {
26
+ titleSize: 'md',
27
+ titleColor: 'dark-3',
28
+ displayHighlight: false,
29
+ highlightColor: 'light-3',
30
+ highlightOpacity: 80,
31
+ displayTitle: false,
32
+ cardColor: 'primary',
33
+ imageCors: 'anonymous',
34
+ }
35
+ )
36
+
37
+ const cardFlipped = ref<boolean>(false)
38
+ const emit = defineEmits(['card-click'])
39
+
40
+ const cardClass = computed(() => {
41
+ const classArray: string[] = [generateClass('BGCOLOR', props.cardColor)]
42
+ if (cardFlipped.value) {
43
+ classArray.push('flip-card')
44
+ }
45
+
46
+ return classArray.join(' ')
47
+ })
48
+ const titleClass = (
49
+ tSize: HeadingSize,
50
+ tColor: ColorPalette,
51
+ dHl: boolean,
52
+ hlColor: ColorPalette,
53
+ hlOpacity: OpacityRange
54
+ ): string => {
55
+ /**
56
+ * @tSize - titleSize
57
+ * @tColor - titleColor
58
+ * @dHl - displayHighlight
59
+ * @hlColor - highlightColor
60
+ * @hlOpacity - highlightOpacity
61
+ */
62
+ const classArray: string[] = [
63
+ generateClass('H3', tSize),
64
+ generateClass('TEXTCOLOR', tColor),
65
+ ]
66
+ if (dHl) {
67
+ classArray.push('px-xs py-2xs mb-2xs rounded')
68
+ classArray.push(generateClass('BGCOLOR', hlColor))
69
+ classArray.push(generateClass('BGOPACITY', hlOpacity))
70
+ }
71
+ return classArray.join(' ')
72
+ }
73
+ const handleCardClick = (e: Event) => {
74
+ e.preventDefault()
75
+ if (cardFlipped.value) {
76
+ emit('card-click', e)
77
+ }
78
+ cardFlipped.value = true
79
+ }
80
+ </script>
81
+
82
+ <template>
83
+ <div
84
+ class="relative aspect-square card transition duration-[1600ms] max-h-[400px] overflow-hidden"
85
+ :class="cardClass"
86
+ @click="handleCardClick"
87
+ >
88
+ <img
89
+ :src="imageSource"
90
+ :alt="imageAlt"
91
+ :class="[
92
+ cardFlipped ? 'opacity-100' : 'opacity-0',
93
+ 'absolute inset-0 object-cover object-center transition-opacity delay-500 duration-[800ms] grayscale-0 hover:grayscale',
94
+ ]"
95
+ :crossorigin="imageCors"
96
+ />
97
+ <div
98
+ :class="[
99
+ cardFlipped ? 'cursor-pointer opacity-100' : 'opacity-0',
100
+ 'relative flex flex-col justify-end p-sm h-full transition delay-500 duration-[800ms]',
101
+ ]"
102
+ >
103
+ <h3
104
+ v-if="displayTitle"
105
+ class="relative self-start"
106
+ :class="
107
+ titleClass(
108
+ titleSize,
109
+ titleColor,
110
+ displayHighlight,
111
+ highlightColor,
112
+ highlightOpacity
113
+ )
114
+ "
115
+ >
116
+ <span>
117
+ {{ title }}
118
+ </span>
119
+ </h3>
120
+ <slot name="card-body" />
121
+ </div>
122
+ </div>
123
+ </template>
124
+
125
+ <style lang="scss" scoped>
126
+ .perspective {
127
+ -webkit-perspective: 1800px;
128
+ perspective: 1800px;
129
+ }
130
+ .card {
131
+ -webkit-transform-style: preserve-3d;
132
+ transform-style: preserve-3d;
133
+ -webkit-transform: rotateY(0deg);
134
+ transform: rotateY(0deg);
135
+ -webkit-backface-visibility: hidden;
136
+ backface-visibility: hidden;
137
+ }
138
+ .flip-card {
139
+ -webkit-transform: rotateY(360deg);
140
+ transform: rotateY(360deg);
141
+ }
142
+ </style>
@@ -0,0 +1,82 @@
1
+ import type { ColorPalette, CrossOrigin, HeadingSize, OpacityRange } from '@bobbykim/manguito-theme';
2
+ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
3
+ imageSource: string;
4
+ imageAlt?: string | undefined;
5
+ title?: string | undefined;
6
+ titleSize?: HeadingSize | undefined;
7
+ titleColor?: ColorPalette | undefined;
8
+ displayHighlight?: boolean | undefined;
9
+ highlightColor?: ColorPalette | undefined;
10
+ highlightOpacity?: OpacityRange | undefined;
11
+ displayTitle?: boolean | undefined;
12
+ cardColor?: ColorPalette | undefined;
13
+ imageCors?: CrossOrigin | undefined;
14
+ }>, {
15
+ titleSize: string;
16
+ titleColor: string;
17
+ displayHighlight: boolean;
18
+ highlightColor: string;
19
+ highlightOpacity: number;
20
+ displayTitle: boolean;
21
+ cardColor: string;
22
+ imageCors: string;
23
+ }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
24
+ "card-click": (...args: any[]) => void;
25
+ }, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
26
+ imageSource: string;
27
+ imageAlt?: string | undefined;
28
+ title?: string | undefined;
29
+ titleSize?: HeadingSize | undefined;
30
+ titleColor?: ColorPalette | undefined;
31
+ displayHighlight?: boolean | undefined;
32
+ highlightColor?: ColorPalette | undefined;
33
+ highlightOpacity?: OpacityRange | undefined;
34
+ displayTitle?: boolean | undefined;
35
+ cardColor?: ColorPalette | undefined;
36
+ imageCors?: CrossOrigin | undefined;
37
+ }>, {
38
+ titleSize: string;
39
+ titleColor: string;
40
+ displayHighlight: boolean;
41
+ highlightColor: string;
42
+ highlightOpacity: number;
43
+ displayTitle: boolean;
44
+ cardColor: string;
45
+ imageCors: string;
46
+ }>>> & {
47
+ "onCard-click"?: ((...args: any[]) => any) | undefined;
48
+ }, {
49
+ titleColor: ColorPalette;
50
+ titleSize: HeadingSize;
51
+ imageCors: CrossOrigin;
52
+ displayHighlight: boolean;
53
+ highlightColor: ColorPalette;
54
+ highlightOpacity: OpacityRange;
55
+ displayTitle: boolean;
56
+ cardColor: ColorPalette;
57
+ }, {}>, {
58
+ "card-body"?(_: {}): any;
59
+ }>;
60
+ export default _default;
61
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
62
+ type __VLS_TypePropsToRuntimeProps<T> = {
63
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
64
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
65
+ } : {
66
+ type: import('vue').PropType<T[K]>;
67
+ required: true;
68
+ };
69
+ };
70
+ type __VLS_WithDefaults<P, D> = {
71
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
72
+ default: D[K];
73
+ }> : P[K];
74
+ };
75
+ type __VLS_Prettify<T> = {
76
+ [K in keyof T]: T[K];
77
+ } & {};
78
+ type __VLS_WithTemplateSlots<T, S> = T & {
79
+ new (): {
80
+ $slots: S;
81
+ };
82
+ };
@@ -0,0 +1,264 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ ColorPalette,
4
+ CrossOrigin,
5
+ CtaTarget,
6
+ HeadingSize,
7
+ Range,
8
+ } from '@bobbykim/manguito-theme'
9
+ import generateClass from '@bobbykim/manguito-theme'
10
+ import { computed } from 'vue'
11
+ import type { CardClickEvent } from '../common/index.types'
12
+ import type { ColorMap } from './index.types'
13
+
14
+ // gradient color options objects
15
+ const fromColorClasses: ColorMap = {
16
+ primary: 'from-primary',
17
+ secondary: 'from-secondary',
18
+ success: 'from-success',
19
+ info: 'from-info',
20
+ warning: 'from-warning',
21
+ danger: 'from-danger',
22
+ 'light-1': 'from-light-1',
23
+ 'light-2': 'from-light-2',
24
+ 'light-3': 'from-light-3',
25
+ 'light-4': 'from-light-4',
26
+ 'dark-1': 'from-dark-1',
27
+ 'dark-2': 'from-dark-2',
28
+ 'dark-3': 'from-dark-3',
29
+ 'dark-4': 'from-dark-4',
30
+ black: 'from-black',
31
+ white: 'from-white',
32
+ transparent: 'from-transparent',
33
+ }
34
+ const viaColorClasses: ColorMap = {
35
+ primary: 'via-primary',
36
+ secondary: 'via-secondary',
37
+ success: 'via-success',
38
+ info: 'via-info',
39
+ warning: 'via-warning',
40
+ danger: 'via-danger',
41
+ 'light-1': 'via-light-1',
42
+ 'light-2': 'via-light-2',
43
+ 'light-3': 'via-light-3',
44
+ 'light-4': 'via-light-4',
45
+ 'dark-1': 'via-dark-1',
46
+ 'dark-2': 'via-dark-2',
47
+ 'dark-3': 'via-dark-3',
48
+ 'dark-4': 'via-dark-4',
49
+ black: 'via-black',
50
+ white: 'via-white',
51
+ transparent: 'via-transparent',
52
+ }
53
+ const toColorClasses: ColorMap = {
54
+ primary: 'to-primary',
55
+ secondary: 'to-secondary',
56
+ success: 'to-success',
57
+ info: 'to-info',
58
+ warning: 'to-warning',
59
+ danger: 'to-danger',
60
+ 'light-1': 'to-light-1',
61
+ 'light-2': 'to-light-2',
62
+ 'light-3': 'to-light-3',
63
+ 'light-4': 'to-light-4',
64
+ 'dark-1': 'to-dark-1',
65
+ 'dark-2': 'to-dark-2',
66
+ 'dark-3': 'to-dark-3',
67
+ 'dark-4': 'to-dark-4',
68
+ black: 'to-black',
69
+ white: 'to-white',
70
+ transparent: 'to-transparent',
71
+ }
72
+
73
+ const props = withDefaults(
74
+ defineProps<{
75
+ displayImage?: boolean
76
+ imageSource?: string
77
+ imageAlt?: string
78
+ imageCors?: CrossOrigin
79
+ title: string
80
+ titleSize?: HeadingSize
81
+ titleColor?: ColorPalette
82
+ bgColor?: ColorPalette
83
+ displayHighlight?: boolean
84
+ highlightColor?: ColorPalette
85
+ ctaText?: string
86
+ ctaLink: string
87
+ ctaLinkTarget?: CtaTarget
88
+ ctaAsLink?: boolean
89
+ ctaButton?: boolean
90
+ ctaButtonColor?: ColorPalette
91
+ ctaButtonBlock?: boolean
92
+ borderWidth?: Range<1, 10>
93
+ borderColor?: ColorPalette
94
+ gradient1?: ColorPalette
95
+ gradient2?: ColorPalette
96
+ customColor?: ColorMap
97
+ }>(),
98
+ {
99
+ displayImage: true,
100
+ imageAlt: '',
101
+ imageCors: 'anonymous',
102
+ titleSize: 'md',
103
+ titleColor: 'dark-4',
104
+ bgColor: 'light-1',
105
+ displayHighlight: true,
106
+ highlightColor: 'primary',
107
+ ctaText: 'Read more',
108
+ ctaLinkTarget: '_self',
109
+ ctaAsLink: true,
110
+ ctaButton: false,
111
+ ctaButtonColor: 'warning',
112
+ ctaButtonBlock: false,
113
+ borderWidth: 3,
114
+ borderColor: 'light-3',
115
+ gradient1: 'primary',
116
+ gradient2: 'secondary',
117
+ }
118
+ )
119
+
120
+ const emit = defineEmits(['card-click'])
121
+
122
+ const titleClass = (size: HeadingSize, color: ColorPalette): string => {
123
+ /**
124
+ * @param {HeadingSize} size - titleSize
125
+ * @param {ColorPalette} color - titleColor
126
+ */
127
+
128
+ const classArray: string[] = [
129
+ generateClass('H2', size),
130
+ generateClass('TEXTCOLOR', color),
131
+ ]
132
+ return classArray.join(' ')
133
+ }
134
+ const buttonClass = (
135
+ dBtn: boolean,
136
+ color: ColorPalette,
137
+ block: boolean
138
+ ): string => {
139
+ /**
140
+ * @param {boolean} - dBtn = ctaButton
141
+ * @param {ColorPalette} - color = ctaButtonColor
142
+ * @param {boolean} - block = ctaButtonBlock
143
+ */
144
+ const classArray: string[] = []
145
+ const lightColor: string[] = ['light-1', 'light-2', 'light-3', 'light-4']
146
+ if (!dBtn) {
147
+ classArray.push('mcl-link')
148
+ }
149
+ if (dBtn) {
150
+ classArray.push('btn')
151
+ classArray.push(generateClass('BTNCOLOR', color))
152
+ }
153
+ if (dBtn && block) {
154
+ classArray.push('btn-full')
155
+ }
156
+ if (dBtn && !lightColor.includes(color)) {
157
+ classArray.push('text-white')
158
+ }
159
+ return classArray.join(' ')
160
+ }
161
+
162
+ const borderVariable = computed(() => {
163
+ return {
164
+ '--border-width': `${props.borderWidth}px`,
165
+ }
166
+ })
167
+
168
+ const gradientClass = computed<string>(() => {
169
+ const gradientBorerColor: string = fromColorClasses[props.borderColor]
170
+ const gradient1Color: string = viaColorClasses[props.gradient1]
171
+ const gradient2Color: string = toColorClasses[props.gradient2]
172
+ let classArray: string[] = [
173
+ generateClass('BORDER', props.borderColor),
174
+ gradientBorerColor,
175
+ gradient1Color,
176
+ gradient2Color,
177
+ ]
178
+
179
+ return classArray.join(' ')
180
+ })
181
+
182
+ const handleCardClick = (e: Event) => {
183
+ /**
184
+ * @param {Event} e - click event
185
+ * @param {Boolean} link - ctaAsLink
186
+ */
187
+
188
+ const { title, ctaLink, ctaLinkTarget, ctaAsLink } = props
189
+ const cardEvent: CardClickEvent = {
190
+ event: e,
191
+ title,
192
+ url: ctaLink,
193
+ target: ctaLinkTarget ? ctaLinkTarget : '_self',
194
+ }
195
+ !ctaAsLink && e.preventDefault()
196
+ emit('card-click', cardEvent)
197
+ }
198
+ </script>
199
+
200
+ <template>
201
+ <div
202
+ class="card [--border-angle:0deg] bg-[conic-gradient(from_var(--border-angle),var(--tw-gradient-stops))] from-20% overflow-hidden rounded-md max-w-[450px] sm:max-w-[350px] w-full xs:w-auto flex-grow flex-shrink-0 border"
203
+ :class="gradientClass"
204
+ :style="borderVariable"
205
+ >
206
+ <div class="flex flex-col rounded-md overflow-hidden">
207
+ <img
208
+ v-if="displayImage"
209
+ :src="imageSource"
210
+ :crossorigin="imageCors"
211
+ class="object-cover object-top max-h-[200px]"
212
+ :alt="imageAlt"
213
+ />
214
+ <div class="p-xs" :class="generateClass('BGCOLOR', bgColor)">
215
+ <h3 class="mb-xs" :class="titleClass(titleSize, titleColor)">
216
+ {{ title }}
217
+ </h3>
218
+ <div
219
+ v-if="displayHighlight"
220
+ class="mb-xs h-3xs w-md"
221
+ :class="generateClass('BGCOLOR', highlightColor)"
222
+ ></div>
223
+ <div>
224
+ <slot></slot>
225
+ </div>
226
+ <div class="mt-xs" :class="{ 'mb-2xs': !ctaButton }">
227
+ <a
228
+ :href="ctaLink"
229
+ :target="ctaLinkTarget"
230
+ :class="buttonClass(ctaButton, ctaButtonColor, ctaButtonBlock)"
231
+ @click="handleCardClick"
232
+ >{{ ctaText }}</a
233
+ >
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ </template>
239
+
240
+ <style lang="scss" scoped>
241
+ .card {
242
+ background-size: cover;
243
+ background-position: center center;
244
+ background-repeat: no-repeat;
245
+ padding: var(--border-width);
246
+
247
+ animation: bg-spin 4s linear infinite;
248
+ @keyframes bg-spin {
249
+ to {
250
+ --border-angle: 360deg;
251
+ }
252
+ }
253
+
254
+ &:hover {
255
+ animation-play-state: paused;
256
+ }
257
+ }
258
+
259
+ @property --border-angle {
260
+ syntax: '<angle>';
261
+ inherits: true;
262
+ initial-value: 0deg;
263
+ }
264
+ </style>