@yatoday/astro-ui 0.10.2 → 0.10.7

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,7 +3,7 @@ import type { BreadcrumbsProps as Props } from './types';
3
3
 
4
4
  import { Icon } from 'astro-icon/components';
5
5
 
6
- const { class: classNames = 'text-gray-600 dark:text-gray-400', ariaLabel = 'Breadcrumbs', items = [] } = Astro.props;
6
+ const { class: classNames = '', ariaLabel = 'Breadcrumbs', items = [] } = Astro.props;
7
7
  ---
8
8
 
9
9
  <nav class:list={['breadcrumbs', classNames]} aria-label={ariaLabel}>
@@ -1,12 +1,23 @@
1
1
  ---
2
- import type { Card0Props as Props } from './types';
3
- import { twMerge } from 'tailwind-merge';
2
+ import type {Card0Props as Props} from './types';
3
+ import {twMerge} from 'tailwind-merge';
4
4
 
5
- const { badge, as = 'article', classes = {} } = Astro.props;
5
+ const {
6
+ badge,
7
+ badgeTopRight,
8
+ badgeBottomRight,
9
+ badgeBottomLeft,
10
+ as = 'article',
11
+ classes = {}
12
+ } = Astro.props;
6
13
 
7
14
  const WrapperTag = as;
8
15
 
9
- const { container: containerClass = '', badge: badgeClass = 'top-2 left-2' } = classes;
16
+ const {
17
+ container: containerClass = '',
18
+ badge: badgeClass = '',
19
+ badgeTopRight: badgeTopRightClass = '',
20
+ } = classes;
10
21
  ---
11
22
 
12
23
  <WrapperTag
@@ -15,13 +26,25 @@ const { container: containerClass = '', badge: badgeClass = 'top-2 left-2' } = c
15
26
  containerClass
16
27
  )}
17
28
  >
18
- <div class={twMerge('absolute z-10', badgeClass)}>
19
- <slot name="badge">
20
- {badge && <span set:html={badge} />}
21
- </slot>
22
- </div>
29
+ <!-- Default badge -->
30
+ {(Astro.slots.has('badge') || badge) && (
31
+ <div class={twMerge('absolute z-10 top-2 left-2', badgeClass)}>
32
+ <slot name="badge">
33
+ {badge && <span set:html={badge}/>}
34
+ </slot>
35
+ </div>
36
+ )}
37
+
38
+ {(Astro.slots.has('badgeTopRight') || badgeTopRight) && (
39
+ <div class={twMerge('absolute z-10 top-2 right-2', badgeTopRightClass)}>
40
+ <slot name="badgeTopRight">
41
+ {badgeTopRight && <span set:html={badgeTopRight}/>}
42
+ </slot>
43
+ </div>
44
+ )}
45
+
23
46
 
24
- <slot name="image" />
47
+ <slot name="image"/>
25
48
 
26
- <slot />
49
+ <slot/>
27
50
  </WrapperTag>
@@ -9,5 +9,8 @@ export type Card0Props = {
9
9
  content?: string;
10
10
  ['as']?: HTMLTag;
11
11
  badge?: string;
12
+ badgeTopRight?: string;
13
+ badgeBottomRight?: string;
14
+ badgeBottomLeft?: string;
12
15
  classes?: Record<string, string>;
13
16
  };
@@ -19,6 +19,9 @@ const {
19
19
  as = 'article',
20
20
  asHeader = 'h3',
21
21
  badge = await Astro.slots.render('badge'),
22
+ badgeTopRight = await Astro.slots.render('badgeTopRight'),
23
+ badgeBottomRight = await Astro.slots.render('badgeBottomRight'),
24
+ badgeBottomLeft = await Astro.slots.render('badgeBottomLeft'),
22
25
  } = Astro.props;
23
26
 
24
27
  const WrapperHeaderTag = asHeader;
@@ -27,10 +30,14 @@ const {
27
30
  title: titleClass = '',
28
31
  description: descriptionClass = 'text-muted-foreground',
29
32
  image: imageClass = '',
33
+ imageLayout: imageLayout = 'cover',
30
34
  icon: iconClass = '',
31
35
  quickLink: quickLinkClass = 'font-semibold underline text-primary hover:text-primary/80',
32
36
  action: actionClass = '',
33
- } = classes;
37
+ } = classes as {
38
+ // Ensure imageLayout is typed as the Layout union, not just string
39
+ imageLayout?: 'fixed' | 'constrained' | 'fullWidth' | 'cover' | 'responsive' | 'contained';
40
+ } & Record<string, string>;
34
41
 
35
42
  const urlForImage = Array.isArray(callToAction)
36
43
  ? typeof callToAction[0] === 'string'
@@ -44,14 +51,36 @@ const urlForImage = Array.isArray(callToAction)
44
51
  <Card0
45
52
  as={as}
46
53
  badge={badge}
54
+ badgeTopRight={badgeTopRight}
55
+ badgeBottomRight={badgeBottomRight}
56
+ badgeBottomLeft={badgeBottomLeft}
47
57
  classes={{
48
58
  content: 'space-y-6',
59
+ badge: classes?.badge,
60
+ badgeTopRight: classes?.badgeTopRight,
49
61
  }}
50
62
  >
51
63
  <Fragment slot="image">
52
64
  {
53
65
  image && (
54
- <div class={twMerge('w-full overflow-hidden -mt-6 h-60 bg-gray-400 dark:bg-zinc-700', imageClass)}>
66
+ <div class={twMerge('relative w-full overflow-hidden -mt-6 h-60 bg-gray-400 dark:bg-zinc-700', imageClass)}>
67
+
68
+ {(Astro.slots.has('badgeBottomRight') || badgeBottomRight) && (
69
+ <div class={twMerge('absolute z-10 bottom-2 right-2', classes?.badgeBottomRight)}>
70
+ <slot name="badgeBottomRight">
71
+ {badgeBottomRight && <span set:html={badgeBottomRight}/>}
72
+ </slot>
73
+ </div>
74
+ )}
75
+
76
+ {(Astro.slots.has('badgeBottomLeft') || badgeBottomLeft) && (
77
+ <div class={twMerge('absolute z-10 bottom-2 left-2', classes?.badgeBottomLeft)}>
78
+ <slot name="badgeBottomLeft">
79
+ {badgeBottomLeft && <span set:html={badgeBottomLeft}/>}
80
+ </slot>
81
+ </div>
82
+ )}
83
+
55
84
  {urlForImage ? (
56
85
  <a href={urlForImage} class="group">
57
86
  {typeof image === 'string' ? (
@@ -63,7 +92,7 @@ const urlForImage = Array.isArray(callToAction)
63
92
  width={400}
64
93
  height={400}
65
94
  sizes="(max-width: 900px) 400px, 900px"
66
- layout="cover"
95
+ layout={imageLayout}
67
96
  loading="lazy"
68
97
  decoding="async"
69
98
  {...image}
@@ -81,7 +110,7 @@ const urlForImage = Array.isArray(callToAction)
81
110
  width={400}
82
111
  height={400}
83
112
  sizes="(max-width: 900px) 400px, 900px"
84
- layout="cover"
113
+ layout={imageLayout}
85
114
  loading="lazy"
86
115
  decoding="async"
87
116
  {...image}
@@ -17,6 +17,9 @@ const {
17
17
  as = 'article',
18
18
  asHeader = 'h3',
19
19
  badge = await Astro.slots.render('badge'),
20
+ badgeTopRight = await Astro.slots.render('badgeTopRight'),
21
+ badgeBottomRight = await Astro.slots.render('badgeBottomRight'),
22
+ badgeBottomLeft = await Astro.slots.render('badgeBottomLeft'),
20
23
  } = Astro.props;
21
24
 
22
25
  const WrapperHeaderTag = asHeader;
@@ -27,23 +30,48 @@ const {
27
30
  content: contentClass = 'text-muted-foreground',
28
31
  icon: iconClass = '',
29
32
  image: imageClass = '',
33
+ imageLayout: imageLayout = 'cover',
30
34
  badge: badgeClass = 'top-2 left-2',
31
- } = classes;
35
+ } = classes as {
36
+ // Ensure imageLayout is typed as the Layout union, not just string
37
+ imageLayout?: 'fixed' | 'constrained' | 'fullWidth' | 'cover' | 'responsive' | 'contained';
38
+ } & Record<string, string>;
32
39
  ---
33
40
 
34
41
  <Card0
35
42
  as={as}
36
43
  badge={badge}
44
+ badgeTopRight={badgeTopRight}
45
+ badgeBottomRight={badgeBottomRight}
46
+ badgeBottomLeft={badgeBottomLeft}
37
47
  classes={{
38
48
  container: cn('group', containerClass),
39
49
  badge: badgeClass,
50
+ badgeTopRight: classes?.badgeTopRight,
40
51
  }}
41
52
  >
42
53
  <!-- Image -->
43
54
  <Fragment slot="image">
44
55
  {
45
56
  image && (
46
- <div class={twMerge('w-full overflow-hidden -mt-6 h-40 bg-gray-400 dark:bg-zinc-700', imageClass)}>
57
+ <div class={twMerge('relative w-full overflow-hidden -mt-6 h-40 bg-gray-400 dark:bg-zinc-700', imageClass)}>
58
+
59
+ {(Astro.slots.has('badgeBottomRight') || badgeBottomRight) && (
60
+ <div class={twMerge('absolute z-10 bottom-2 right-2', classes?.badgeBottomRight)}>
61
+ <slot name="badgeBottomRight">
62
+ {badgeBottomRight && <span set:html={badgeBottomRight}/>}
63
+ </slot>
64
+ </div>
65
+ )}
66
+
67
+ {(Astro.slots.has('badgeBottomLeft') || badgeBottomLeft) && (
68
+ <div class={twMerge('absolute z-10 bottom-2 left-2', classes?.badgeBottomLeft)}>
69
+ <slot name="badgeBottomLeft">
70
+ {badgeBottomLeft && <span set:html={badgeBottomLeft}/>}
71
+ </slot>
72
+ </div>
73
+ )}
74
+
47
75
  {typeof image === 'string' ? (
48
76
  <Fragment set:html={image} />
49
77
  ) : (
@@ -57,7 +85,7 @@ const {
57
85
  width={400}
58
86
  height={400}
59
87
  sizes="(max-width: 900px) 400px, 900px"
60
- layout="cover"
88
+ layout={imageLayout}
61
89
  loading="lazy"
62
90
  decoding="async"
63
91
  {...image}
@@ -15,6 +15,9 @@ const {
15
15
  as = 'article',
16
16
  asHeader = 'h3',
17
17
  badge = await Astro.slots.render('badge'),
18
+ badgeTopRight = await Astro.slots.render('badgeTopRight'),
19
+ badgeBottomRight = await Astro.slots.render('badgeBottomRight'),
20
+ badgeBottomLeft = await Astro.slots.render('badgeBottomLeft'),
18
21
  } = Astro.props;
19
22
 
20
23
  const WrapperHeaderTag = asHeader;
@@ -24,9 +27,13 @@ const {
24
27
  title: titleClass = '',
25
28
  description: descriptionClass = 'text-muted-foreground',
26
29
  image: imageClass = '',
30
+ imageLayout: imageLayout = 'cover',
27
31
  action: actionClass = '',
28
32
  badge: badgeClass = 'top-2 left-2',
29
- } = classes;
33
+ } = classes as {
34
+ // Ensure imageLayout is typed as the Layout union, not just string
35
+ imageLayout?: 'fixed' | 'constrained' | 'fullWidth' | 'cover' | 'responsive' | 'contained';
36
+ } & Record<string, string>;
30
37
 
31
38
  const urlForImage = Array.isArray(callToAction)
32
39
  ? typeof callToAction[0] === 'string'
@@ -40,17 +47,39 @@ const urlForImage = Array.isArray(callToAction)
40
47
  <Card0
41
48
  as={as}
42
49
  badge={badge}
50
+ badgeTopRight={badgeTopRight}
51
+ badgeBottomRight={badgeBottomRight}
52
+ badgeBottomLeft={badgeBottomLeft}
43
53
  classes={{
44
54
  container: twMerge(containerClass, 'justify-start py-0'),
45
55
  badge: badgeClass,
56
+ badgeTopRight: classes?.badgeTopRight,
46
57
  }}
47
58
  >
48
59
  <Fragment slot="image">
49
60
  {
50
61
  image && (
51
62
  <div
52
- class={twMerge('w-full aspect-square overflow-hidden rounded-lg bg-gray-400 dark:bg-zinc-700', imageClass)}
63
+ class={twMerge('relative w-full aspect-square overflow-hidden rounded-lg bg-gray-400 dark:bg-zinc-700', imageClass)}
53
64
  >
65
+
66
+ {(Astro.slots.has('badgeBottomRight') || badgeBottomRight) && (
67
+ <div class={twMerge('absolute z-10 bottom-2 right-2', classes?.badgeBottomRight)}>
68
+ <slot name="badgeBottomRight">
69
+ {badgeBottomRight && <span set:html={badgeBottomRight}/>}
70
+ </slot>
71
+ </div>
72
+ )}
73
+
74
+ {(Astro.slots.has('badgeBottomLeft') || badgeBottomLeft) && (
75
+ <div class={twMerge('absolute z-10 bottom-2 left-2', classes?.badgeBottomLeft)}>
76
+ <slot name="badgeBottomLeft">
77
+ {badgeBottomLeft && <span set:html={badgeBottomLeft}/>}
78
+ </slot>
79
+ </div>
80
+ )}
81
+
82
+
54
83
  {urlForImage ? (
55
84
  <a href={urlForImage} class="group">
56
85
  {typeof image === 'string' ? (
@@ -62,7 +91,7 @@ const urlForImage = Array.isArray(callToAction)
62
91
  width={400}
63
92
  height={400}
64
93
  sizes="(max-width: 900px) 400px, 900px"
65
- layout="cover"
94
+ layout={imageLayout}
66
95
  loading="lazy"
67
96
  decoding="async"
68
97
  {...image}
@@ -80,7 +109,7 @@ const urlForImage = Array.isArray(callToAction)
80
109
  width={400}
81
110
  height={400}
82
111
  sizes="(max-width: 900px) 400px, 900px"
83
- layout="cover"
112
+ layout={imageLayout}
84
113
  loading="lazy"
85
114
  decoding="async"
86
115
  {...image}
@@ -15,6 +15,9 @@ const {
15
15
  as = 'article',
16
16
  asHeader = 'h3',
17
17
  badge = await Astro.slots.render('badge'),
18
+ badgeTopRight = await Astro.slots.render('badgeTopRight'),
19
+ badgeBottomRight = await Astro.slots.render('badgeBottomRight'),
20
+ badgeBottomLeft = await Astro.slots.render('badgeBottomLeft'),
18
21
  widths = [800, 1600],
19
22
  size = 800,
20
23
  sizes = '(max-width: 1600px) 800px, 1600px'
@@ -28,9 +31,13 @@ const {
28
31
  title: titleClass = '',
29
32
  description: descriptionClass = '',
30
33
  image: imageClass = '',
34
+ imageLayout: imageLayout = 'cover',
31
35
  badge: badgeClass = 'top-2 left-2',
32
36
  aspect: aspectClass = 'pb-[100%]',
33
- } = classes;
37
+ } = classes as {
38
+ // Ensure imageLayout is typed as the Layout union, not just string
39
+ imageLayout?: 'fixed' | 'constrained' | 'fullWidth' | 'cover' | 'responsive' | 'contained';
40
+ } & Record<string, string>;
34
41
 
35
42
  const urlForImage = Array.isArray(callToAction)
36
43
  ? typeof callToAction[0] === 'string'
@@ -45,9 +52,13 @@ const LinkWrapperTag = urlForImage ? 'a' : 'div';
45
52
 
46
53
  <Card0
47
54
  as={as}
55
+ badgeTopRight={badgeTopRight}
56
+ badgeBottomRight={badgeBottomRight}
57
+ badgeBottomLeft={badgeBottomLeft}
48
58
  classes={{
49
59
  container: cn('relative h-full bg-gray-200 dark:bg-zinc-700 border-transparent text-inherit justify-start py-0 @container', containerClass),
50
60
  badge: badgeClass,
61
+ badgeTopRight: classes?.badgeTopRight,
51
62
  }}
52
63
  >
53
64
  <!-- Content & link -->
@@ -55,6 +66,22 @@ const LinkWrapperTag = urlForImage ? 'a' : 'div';
55
66
  <div class={cn("p-6 @2xl:p-10 pt-8 @2xl:pt-12", contentClass, !image && 'bg-transparent')}>
56
67
  {badge && (
57
68
  <div class="" set:html={badge}></div>)}
69
+
70
+ {(Astro.slots.has('badgeBottomRight') || badgeBottomRight) && (
71
+ <div class={twMerge('absolute z-10 bottom-2 right-2', classes?.badgeBottomRight)}>
72
+ <slot name="badgeBottomRight">
73
+ {badgeBottomRight && <span set:html={badgeBottomRight}/>}
74
+ </slot>
75
+ </div>
76
+ )}
77
+
78
+ {(Astro.slots.has('badgeBottomLeft') || badgeBottomLeft) && (
79
+ <div class={twMerge('absolute z-10 bottom-2 left-2', classes?.badgeBottomLeft)}>
80
+ <slot name="badgeBottomLeft">
81
+ {badgeBottomLeft && <span set:html={badgeBottomLeft}/>}
82
+ </slot>
83
+ </div>
84
+ )}
58
85
 
59
86
  <WrapperHeaderTag
60
87
  class={cn('font-bold text-lg @lg:text-xl @2xl:text-2xl ', urlForImage && 'group-hover:underline', titleClass)}>
@@ -102,7 +129,7 @@ const LinkWrapperTag = urlForImage ? 'a' : 'div';
102
129
  width={size}
103
130
  height={size}
104
131
  sizes={sizes}
105
- layout="cover"
132
+ layout={imageLayout}
106
133
  loading="lazy"
107
134
  decoding="async"
108
135
  {...image}
@@ -33,14 +33,16 @@ const {
33
33
  >
34
34
  <div class="flex items-center relative">
35
35
  <div class={cn("flex flex-col gap-3 justify-between h-full p-4 ", callToAction && 'border-r dark:border-white/10 border-black/10')}>
36
- {callToAction ? (
36
+
37
+ {title && (callToAction ? (
37
38
  <a href={callToAction.href} class="flex items-center">
38
39
  <WrapperHeaderTag class={cn('text-lg md:text-xl font-bold', titleClass)}>{title}</WrapperHeaderTag>
39
40
  <span class="absolute inset-0" aria-hidden="true"></span>
40
41
  </a>
41
42
  ) : (
42
43
  <WrapperHeaderTag class={cn('text-lg md:text-xl font-bold', titleClass)}>{title}</WrapperHeaderTag>
43
- )}
44
+ ))}
45
+
44
46
  {description && (
45
47
  <p class={cn('text-muted-foreground text-sm/5 md:text-base', descriptionClass)} set:html={description}/>
46
48
  )}
@@ -91,7 +91,6 @@ const {
91
91
  height={500}
92
92
  widths={[400, 768]}
93
93
  sizes="(max-width: 768px) 100vw, 432px"
94
- layout="responsive"
95
94
  {...image}
96
95
  />
97
96
  )}
package/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  // Utility Types
2
+ import type {HTMLAttributes} from "astro/types";
3
+ import type {ImageMetadata} from "astro";
4
+
2
5
  export type ClassValue = ClassArray | ClassDictionary | string | number | bigint | null | boolean | undefined;
3
6
  export type ClassDictionary = Record<string, any>;
4
7
  export type ClassArray = ClassValue[];
@@ -47,6 +50,23 @@ export type Image = {
47
50
  alt?: string;
48
51
  aspectRatio?: string;
49
52
  class?: string;
53
+ } & Omit<HTMLAttributes<'img'>, 'src'> & {
54
+ src?: string | ImageMetadata | null;
55
+ width?: string | number | null;
56
+ height?: string | number | null;
57
+ alt?: string | null;
58
+ loading?: 'eager' | 'lazy' | null;
59
+ decoding?: 'sync' | 'async' | 'auto' | null;
60
+ class?: string;
61
+ style?: string;
62
+ srcset?: string | null;
63
+ sizes?: string | null;
64
+ fetchpriority?: 'high' | 'low' | 'auto' | null;
65
+ layout?: Layout;
66
+ widths?: number[] | null;
67
+ aspectRatio?: string | number | null;
68
+ objectPosition?: string;
69
+ format?: string;
50
70
  };
51
71
 
52
72
  export type Testimonial = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yatoday/astro-ui",
3
3
  "type": "module",
4
- "version": "0.10.2",
4
+ "version": "0.10.7",
5
5
  "scripts": {
6
6
  "prepare": "husky",
7
7
  "pre-commit": "lint-staged",
package/styles/styles.css CHANGED
@@ -7,10 +7,13 @@
7
7
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
8
8
  "Courier New", monospace;
9
9
  --color-red-500: oklch(0.637 0.237 25.331);
10
+ --color-red-700: oklch(0.505 0.213 27.518);
10
11
  --color-orange-300: oklch(0.837 0.128 66.29);
12
+ --color-amber-500: oklch(0.769 0.188 70.08);
11
13
  --color-green-600: oklch(0.627 0.194 149.214);
12
14
  --color-green-700: oklch(0.527 0.154 150.069);
13
15
  --color-emerald-200: oklch(0.905 0.093 164.15);
16
+ --color-blue-700: oklch(0.488 0.243 264.376);
14
17
  --color-violet-500: oklch(0.606 0.25 292.717);
15
18
  --color-purple-500: oklch(0.627 0.265 303.9);
16
19
  --color-purple-800: oklch(0.438 0.218 303.724);
@@ -312,12 +315,18 @@
312
315
  .right-0 {
313
316
  right: calc(var(--spacing) * 0);
314
317
  }
318
+ .right-2 {
319
+ right: calc(var(--spacing) * 2);
320
+ }
315
321
  .right-5 {
316
322
  right: calc(var(--spacing) * 5);
317
323
  }
318
324
  .bottom-0 {
319
325
  bottom: calc(var(--spacing) * 0);
320
326
  }
327
+ .bottom-2 {
328
+ bottom: calc(var(--spacing) * 2);
329
+ }
321
330
  .-left-5 {
322
331
  left: calc(var(--spacing) * -5);
323
332
  }
@@ -1386,6 +1395,9 @@
1386
1395
  .whitespace-nowrap {
1387
1396
  white-space: nowrap;
1388
1397
  }
1398
+ .text-amber-500 {
1399
+ color: var(--color-amber-500);
1400
+ }
1389
1401
  .text-black {
1390
1402
  color: var(--color-black);
1391
1403
  }
@@ -1395,6 +1407,9 @@
1395
1407
  .text-black\/70 {
1396
1408
  color: color-mix(in oklab, var(--color-black) 70%, transparent);
1397
1409
  }
1410
+ .text-blue-700 {
1411
+ color: var(--color-blue-700);
1412
+ }
1398
1413
  .text-gray-50 {
1399
1414
  color: var(--color-gray-50);
1400
1415
  }
@@ -1404,9 +1419,6 @@
1404
1419
  .text-gray-500 {
1405
1420
  color: var(--color-gray-500);
1406
1421
  }
1407
- .text-gray-600 {
1408
- color: var(--color-gray-600);
1409
- }
1410
1422
  .text-gray-700 {
1411
1423
  color: var(--color-gray-700);
1412
1424
  }
@@ -1419,6 +1431,9 @@
1419
1431
  .text-red-500 {
1420
1432
  color: var(--color-red-500);
1421
1433
  }
1434
+ .text-red-700 {
1435
+ color: var(--color-red-700);
1436
+ }
1422
1437
  .text-slate-800 {
1423
1438
  color: var(--color-slate-800);
1424
1439
  }