@opensite/ui 2.8.5 → 2.8.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.
Files changed (141) hide show
  1. package/dist/about-developer-profile.cjs +17 -10
  2. package/dist/about-developer-profile.js +17 -10
  3. package/dist/article-chapters-author.cjs +17 -10
  4. package/dist/article-chapters-author.js +17 -10
  5. package/dist/carousel-animated-sections.cjs +79 -25
  6. package/dist/carousel-animated-sections.d.cts +7 -2
  7. package/dist/carousel-animated-sections.d.ts +7 -2
  8. package/dist/carousel-animated-sections.js +79 -25
  9. package/dist/carousel-gallery-thumbnails.cjs +79 -25
  10. package/dist/carousel-gallery-thumbnails.d.cts +7 -2
  11. package/dist/carousel-gallery-thumbnails.d.ts +7 -2
  12. package/dist/carousel-gallery-thumbnails.js +79 -25
  13. package/dist/carousel-portfolio-hero.cjs +79 -25
  14. package/dist/carousel-portfolio-hero.d.cts +7 -2
  15. package/dist/carousel-portfolio-hero.d.ts +7 -2
  16. package/dist/carousel-portfolio-hero.js +79 -25
  17. package/dist/components.cjs +35 -10
  18. package/dist/components.d.cts +29 -2
  19. package/dist/components.d.ts +29 -2
  20. package/dist/components.js +35 -11
  21. package/dist/footer-accordion-social.cjs +17 -10
  22. package/dist/footer-accordion-social.js +17 -10
  23. package/dist/footer-animated-social.cjs +17 -10
  24. package/dist/footer-animated-social.js +17 -10
  25. package/dist/footer-brand-description.cjs +17 -10
  26. package/dist/footer-brand-description.js +17 -10
  27. package/dist/footer-brand-links-contact.cjs +17 -10
  28. package/dist/footer-brand-links-contact.js +17 -10
  29. package/dist/footer-comprehensive-links.cjs +17 -10
  30. package/dist/footer-comprehensive-links.js +17 -10
  31. package/dist/footer-contact-card.cjs +17 -10
  32. package/dist/footer-contact-card.js +17 -10
  33. package/dist/footer-cta-banner.cjs +17 -10
  34. package/dist/footer-cta-banner.js +17 -10
  35. package/dist/footer-cta-social.cjs +17 -10
  36. package/dist/footer-cta-social.js +17 -10
  37. package/dist/footer-info-cards-accordion.cjs +17 -10
  38. package/dist/footer-info-cards-accordion.js +17 -10
  39. package/dist/footer-nav-social.cjs +17 -10
  40. package/dist/footer-nav-social.js +17 -10
  41. package/dist/footer-newsletter-contact.cjs +17 -10
  42. package/dist/footer-newsletter-contact.js +17 -10
  43. package/dist/footer-newsletter-grid.cjs +17 -10
  44. package/dist/footer-newsletter-grid.js +17 -10
  45. package/dist/footer-newsletter-minimal.cjs +17 -10
  46. package/dist/footer-newsletter-minimal.js +17 -10
  47. package/dist/footer-social-apps.cjs +17 -10
  48. package/dist/footer-social-apps.js +17 -10
  49. package/dist/footer-social-newsletter.cjs +17 -10
  50. package/dist/footer-social-newsletter.js +17 -10
  51. package/dist/footer-split-image-accordion.cjs +17 -10
  52. package/dist/footer-split-image-accordion.js +17 -10
  53. package/dist/hero-badge-shadow-overlay.cjs +1 -1
  54. package/dist/hero-badge-shadow-overlay.js +1 -1
  55. package/dist/hero-coming-soon-countdown.cjs +17 -10
  56. package/dist/hero-coming-soon-countdown.js +17 -10
  57. package/dist/hero-video-background-dark.cjs +78 -16
  58. package/dist/hero-video-background-dark.d.cts +7 -2
  59. package/dist/hero-video-background-dark.d.ts +7 -2
  60. package/dist/hero-video-background-dark.js +78 -16
  61. package/dist/index.cjs +35 -10
  62. package/dist/index.d.cts +1 -0
  63. package/dist/index.d.ts +1 -0
  64. package/dist/index.js +35 -11
  65. package/dist/link-page-bento-layout.cjs +17 -10
  66. package/dist/link-page-bento-layout.js +17 -10
  67. package/dist/link-page-grid-cards.cjs +17 -10
  68. package/dist/link-page-grid-cards.js +17 -10
  69. package/dist/link-page-minimal-profile.cjs +17 -10
  70. package/dist/link-page-minimal-profile.js +17 -10
  71. package/dist/link-page-newsletter-social.cjs +17 -10
  72. package/dist/link-page-newsletter-social.js +17 -10
  73. package/dist/link-tree-block.cjs +17 -10
  74. package/dist/link-tree-block.js +17 -10
  75. package/dist/navbar-fullscreen-menu.cjs +17 -10
  76. package/dist/navbar-fullscreen-menu.js +17 -10
  77. package/dist/navbar-transparent-overlay.cjs +17 -10
  78. package/dist/navbar-transparent-overlay.js +17 -10
  79. package/dist/registry.cjs +1398 -851
  80. package/dist/registry.js +1398 -851
  81. package/dist/social-link-icon.cjs +17 -10
  82. package/dist/social-link-icon.d.cts +5 -0
  83. package/dist/social-link-icon.d.ts +5 -0
  84. package/dist/social-link-icon.js +17 -10
  85. package/dist/testimonials-animated-split.cjs +5 -5
  86. package/dist/testimonials-animated-split.js +5 -5
  87. package/dist/testimonials-bento-grid.cjs +48 -56
  88. package/dist/testimonials-bento-grid.js +48 -56
  89. package/dist/testimonials-carousel-image.cjs +608 -96
  90. package/dist/testimonials-carousel-image.d.cts +26 -2
  91. package/dist/testimonials-carousel-image.d.ts +26 -2
  92. package/dist/testimonials-carousel-image.js +609 -97
  93. package/dist/testimonials-centered-avatars.cjs +89 -62
  94. package/dist/testimonials-centered-avatars.d.cts +5 -1
  95. package/dist/testimonials-centered-avatars.d.ts +5 -1
  96. package/dist/testimonials-centered-avatars.js +89 -62
  97. package/dist/testimonials-company-logo.cjs +6 -6
  98. package/dist/testimonials-company-logo.js +6 -6
  99. package/dist/testimonials-grid-add-review.cjs +51 -29
  100. package/dist/testimonials-grid-add-review.js +51 -29
  101. package/dist/testimonials-images-helpful.cjs +181 -160
  102. package/dist/testimonials-images-helpful.d.cts +9 -1
  103. package/dist/testimonials-images-helpful.d.ts +9 -1
  104. package/dist/testimonials-images-helpful.js +181 -159
  105. package/dist/testimonials-list-verified.cjs +63 -44
  106. package/dist/testimonials-list-verified.d.cts +5 -1
  107. package/dist/testimonials-list-verified.d.ts +5 -1
  108. package/dist/testimonials-list-verified.js +64 -45
  109. package/dist/testimonials-logo-cards.cjs +53 -29
  110. package/dist/testimonials-logo-cards.d.cts +5 -1
  111. package/dist/testimonials-logo-cards.d.ts +5 -1
  112. package/dist/testimonials-logo-cards.js +53 -29
  113. package/dist/testimonials-marquee.cjs +524 -102
  114. package/dist/testimonials-marquee.d.cts +5 -1
  115. package/dist/testimonials-marquee.d.ts +5 -1
  116. package/dist/testimonials-marquee.js +525 -100
  117. package/dist/testimonials-mini-dividers.cjs +120 -83
  118. package/dist/testimonials-mini-dividers.d.cts +10 -6
  119. package/dist/testimonials-mini-dividers.d.ts +10 -6
  120. package/dist/testimonials-mini-dividers.js +120 -83
  121. package/dist/testimonials-minimal-numbered.cjs +7 -6
  122. package/dist/testimonials-minimal-numbered.d.cts +5 -1
  123. package/dist/testimonials-minimal-numbered.d.ts +5 -1
  124. package/dist/testimonials-minimal-numbered.js +7 -6
  125. package/dist/testimonials-parallax-number.cjs +14 -8
  126. package/dist/testimonials-parallax-number.js +14 -8
  127. package/dist/testimonials-scrolling-columns.cjs +97 -13
  128. package/dist/testimonials-scrolling-columns.js +97 -13
  129. package/dist/testimonials-simple-grid.cjs +513 -68
  130. package/dist/testimonials-simple-grid.d.cts +9 -5
  131. package/dist/testimonials-simple-grid.d.ts +9 -5
  132. package/dist/testimonials-simple-grid.js +510 -62
  133. package/dist/testimonials-slider-minimal.cjs +604 -90
  134. package/dist/testimonials-slider-minimal.d.cts +17 -1
  135. package/dist/testimonials-slider-minimal.d.ts +17 -1
  136. package/dist/testimonials-slider-minimal.js +598 -81
  137. package/dist/testimonials-split-image.cjs +452 -17
  138. package/dist/testimonials-split-image.js +448 -13
  139. package/dist/testimonials-twitter-cards.cjs +26 -14
  140. package/dist/testimonials-twitter-cards.js +26 -14
  141. package/package.json +11 -1
@@ -1,9 +1,11 @@
1
1
  "use client";
2
- import React, { useCallback, useMemo } from 'react';
2
+ import * as React3 from 'react';
3
+ import React3__default, { useCallback, useMemo } from 'react';
3
4
  import { clsx } from 'clsx';
4
5
  import { twMerge } from 'tailwind-merge';
5
6
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
6
7
  import { jsx, jsxs } from 'react/jsx-runtime';
8
+ import { cva } from 'class-variance-authority';
7
9
 
8
10
  // components/blocks/testimonials/testimonials-simple-grid.tsx
9
11
  function cn(...inputs) {
@@ -54,19 +56,6 @@ function AvatarFallback({
54
56
  }
55
57
  );
56
58
  }
57
- function Card({ className, ...props }) {
58
- return /* @__PURE__ */ jsx(
59
- "div",
60
- {
61
- "data-slot": "card",
62
- className: cn(
63
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
64
- className
65
- ),
66
- ...props
67
- }
68
- );
69
- }
70
59
  function CardContent({ className, ...props }) {
71
60
  return /* @__PURE__ */ jsx(
72
61
  "div",
@@ -86,7 +75,7 @@ var maxWidthStyles = {
86
75
  "4xl": "max-w-[1536px]",
87
76
  full: "max-w-full"
88
77
  };
89
- var Container = React.forwardRef(
78
+ var Container = React3__default.forwardRef(
90
79
  ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
91
80
  const Component = as;
92
81
  return /* @__PURE__ */ jsx(
@@ -392,7 +381,7 @@ var spacingStyles = {
392
381
  };
393
382
  var predefinedSpacings = ["none", "sm", "md", "lg", "xl", "hero"];
394
383
  var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
395
- var Section = React.forwardRef(
384
+ var Section = React3__default.forwardRef(
396
385
  ({
397
386
  id,
398
387
  title,
@@ -453,6 +442,424 @@ var Section = React.forwardRef(
453
442
  }
454
443
  );
455
444
  Section.displayName = "Section";
445
+ function normalizePhoneNumber(input) {
446
+ const trimmed = input.trim();
447
+ if (trimmed.toLowerCase().startsWith("tel:")) {
448
+ return trimmed;
449
+ }
450
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
451
+ if (match) {
452
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
453
+ const extension = match[3];
454
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
455
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
456
+ return `tel:${withExtension}`;
457
+ }
458
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
459
+ return `tel:${cleaned}`;
460
+ }
461
+ function normalizeEmail(input) {
462
+ const trimmed = input.trim();
463
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
464
+ return trimmed;
465
+ }
466
+ return `mailto:${trimmed}`;
467
+ }
468
+ function isEmail(input) {
469
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
470
+ return emailRegex.test(input.trim());
471
+ }
472
+ function isPhoneNumber(input) {
473
+ const trimmed = input.trim();
474
+ if (trimmed.toLowerCase().startsWith("tel:")) {
475
+ return true;
476
+ }
477
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
478
+ return phoneRegex.test(trimmed);
479
+ }
480
+ function isInternalUrl(href) {
481
+ if (typeof window === "undefined") {
482
+ return href.startsWith("/") && !href.startsWith("//");
483
+ }
484
+ const trimmed = href.trim();
485
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
486
+ return true;
487
+ }
488
+ try {
489
+ const url = new URL(trimmed, window.location.href);
490
+ const currentOrigin = window.location.origin;
491
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
492
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
493
+ } catch {
494
+ return false;
495
+ }
496
+ }
497
+ function toRelativePath(href) {
498
+ if (typeof window === "undefined") {
499
+ return href;
500
+ }
501
+ const trimmed = href.trim();
502
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
503
+ return trimmed;
504
+ }
505
+ try {
506
+ const url = new URL(trimmed, window.location.href);
507
+ const currentOrigin = window.location.origin;
508
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
509
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
510
+ return url.pathname + url.search + url.hash;
511
+ }
512
+ } catch {
513
+ }
514
+ return trimmed;
515
+ }
516
+ function useNavigation({
517
+ href,
518
+ onClick
519
+ } = {}) {
520
+ const linkType = React3.useMemo(() => {
521
+ if (!href || href.trim() === "") {
522
+ return onClick ? "none" : "none";
523
+ }
524
+ const trimmed = href.trim();
525
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
526
+ return "mailto";
527
+ }
528
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
529
+ return "tel";
530
+ }
531
+ if (isInternalUrl(trimmed)) {
532
+ return "internal";
533
+ }
534
+ try {
535
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
536
+ return "external";
537
+ } catch {
538
+ return "internal";
539
+ }
540
+ }, [href, onClick]);
541
+ const normalizedHref = React3.useMemo(() => {
542
+ if (!href || href.trim() === "") {
543
+ return void 0;
544
+ }
545
+ const trimmed = href.trim();
546
+ switch (linkType) {
547
+ case "tel":
548
+ return normalizePhoneNumber(trimmed);
549
+ case "mailto":
550
+ return normalizeEmail(trimmed);
551
+ case "internal":
552
+ return toRelativePath(trimmed);
553
+ case "external":
554
+ return trimmed;
555
+ default:
556
+ return trimmed;
557
+ }
558
+ }, [href, linkType]);
559
+ const target = React3.useMemo(() => {
560
+ switch (linkType) {
561
+ case "external":
562
+ return "_blank";
563
+ case "internal":
564
+ return "_self";
565
+ case "mailto":
566
+ case "tel":
567
+ return void 0;
568
+ default:
569
+ return void 0;
570
+ }
571
+ }, [linkType]);
572
+ const rel = React3.useMemo(() => {
573
+ if (linkType === "external") {
574
+ return "noopener noreferrer";
575
+ }
576
+ return void 0;
577
+ }, [linkType]);
578
+ const isExternal = linkType === "external";
579
+ const isInternal = linkType === "internal";
580
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
581
+ const handleClick = React3.useCallback(
582
+ (event) => {
583
+ if (onClick) {
584
+ try {
585
+ onClick(event);
586
+ } catch (error) {
587
+ console.error("Error in user onClick handler:", error);
588
+ }
589
+ }
590
+ if (event.defaultPrevented) {
591
+ return;
592
+ }
593
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
594
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
595
+ if (typeof window !== "undefined") {
596
+ const handler = window.__opensiteNavigationHandler;
597
+ if (typeof handler === "function") {
598
+ try {
599
+ const handled = handler(normalizedHref, event.nativeEvent || event);
600
+ if (handled !== false) {
601
+ event.preventDefault();
602
+ }
603
+ } catch (error) {
604
+ console.error("Error in navigation handler:", error);
605
+ }
606
+ }
607
+ }
608
+ }
609
+ },
610
+ [onClick, shouldUseRouter, normalizedHref]
611
+ );
612
+ return {
613
+ linkType,
614
+ normalizedHref,
615
+ target,
616
+ rel,
617
+ isExternal,
618
+ isInternal,
619
+ shouldUseRouter,
620
+ handleClick
621
+ };
622
+ }
623
+ var baseStyles = [
624
+ // Layout
625
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
626
+ // Typography - using CSS variables with sensible defaults
627
+ "font-[var(--button-font-family,inherit)]",
628
+ "font-[var(--button-font-weight,500)]",
629
+ "tracking-[var(--button-letter-spacing,0)]",
630
+ "leading-[var(--button-line-height,1.25)]",
631
+ "[text-transform:var(--button-text-transform,none)]",
632
+ "text-sm",
633
+ // Border radius
634
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
635
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
636
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
637
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
638
+ "[box-shadow:var(--button-shadow,none)]",
639
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
640
+ // Disabled state
641
+ "disabled:pointer-events-none disabled:opacity-50",
642
+ // SVG handling
643
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
644
+ // Focus styles
645
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
646
+ // Invalid state
647
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
648
+ ].join(" ");
649
+ var buttonVariants = cva(baseStyles, {
650
+ variants: {
651
+ variant: {
652
+ // Default (Primary) variant - full customization
653
+ default: [
654
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
655
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
656
+ "border-[length:var(--button-default-border-width,0px)]",
657
+ "border-[color:var(--button-default-border,transparent)]",
658
+ "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
659
+ "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
660
+ "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
661
+ "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
662
+ "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
663
+ ].join(" "),
664
+ // Destructive variant - full customization
665
+ destructive: [
666
+ "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
667
+ "text-[var(--button-destructive-fg,white)]",
668
+ "border-[length:var(--button-destructive-border-width,0px)]",
669
+ "border-[color:var(--button-destructive-border,transparent)]",
670
+ "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
671
+ "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
672
+ "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
673
+ "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
674
+ "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
675
+ "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
676
+ "dark:bg-destructive/60"
677
+ ].join(" "),
678
+ // Outline variant - full customization with proper border handling
679
+ outline: [
680
+ "bg-[var(--button-outline-bg,hsl(var(--background)))]",
681
+ "text-[var(--button-outline-fg,inherit)]",
682
+ "border-[length:var(--button-outline-border-width,1px)]",
683
+ "border-[color:var(--button-outline-border,hsl(var(--border)))]",
684
+ "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
685
+ "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
686
+ "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
687
+ "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
688
+ "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
689
+ "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
690
+ ].join(" "),
691
+ // Secondary variant - full customization
692
+ secondary: [
693
+ "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
694
+ "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
695
+ "border-[length:var(--button-secondary-border-width,0px)]",
696
+ "border-[color:var(--button-secondary-border,transparent)]",
697
+ "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
698
+ "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
699
+ "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
700
+ "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
701
+ "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
702
+ ].join(" "),
703
+ // Ghost variant - full customization
704
+ ghost: [
705
+ "bg-[var(--button-ghost-bg,transparent)]",
706
+ "text-[var(--button-ghost-fg,inherit)]",
707
+ "border-[length:var(--button-ghost-border-width,0px)]",
708
+ "border-[color:var(--button-ghost-border,transparent)]",
709
+ "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
710
+ "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
711
+ "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
712
+ "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
713
+ "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
714
+ "dark:hover:bg-accent/50"
715
+ ].join(" "),
716
+ // Link variant - full customization
717
+ link: [
718
+ "bg-[var(--button-link-bg,transparent)]",
719
+ "text-[var(--button-link-fg,hsl(var(--primary)))]",
720
+ "border-[length:var(--button-link-border-width,0px)]",
721
+ "border-[color:var(--button-link-border,transparent)]",
722
+ "[box-shadow:var(--button-link-shadow,none)]",
723
+ "hover:bg-[var(--button-link-hover-bg,transparent)]",
724
+ "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
725
+ "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
726
+ "underline-offset-4 hover:underline"
727
+ ].join(" ")
728
+ },
729
+ size: {
730
+ default: [
731
+ "h-[var(--button-height-md,2.25rem)]",
732
+ "px-[var(--button-padding-x-md,1rem)]",
733
+ "py-[var(--button-padding-y-md,0.5rem)]",
734
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
735
+ ].join(" "),
736
+ sm: [
737
+ "h-[var(--button-height-sm,2rem)]",
738
+ "px-[var(--button-padding-x-sm,0.75rem)]",
739
+ "py-[var(--button-padding-y-sm,0.25rem)]",
740
+ "gap-1.5",
741
+ "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
742
+ ].join(" "),
743
+ md: [
744
+ "h-[var(--button-height-md,2.25rem)]",
745
+ "px-[var(--button-padding-x-md,1rem)]",
746
+ "py-[var(--button-padding-y-md,0.5rem)]",
747
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
748
+ ].join(" "),
749
+ lg: [
750
+ "h-[var(--button-height-lg,2.5rem)]",
751
+ "px-[var(--button-padding-x-lg,1.5rem)]",
752
+ "py-[var(--button-padding-y-lg,0.5rem)]",
753
+ "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
754
+ ].join(" "),
755
+ icon: "size-[var(--button-height-md,2.25rem)]",
756
+ "icon-sm": "size-[var(--button-height-sm,2rem)]",
757
+ "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
758
+ }
759
+ },
760
+ defaultVariants: {
761
+ variant: "default",
762
+ size: "default"
763
+ }
764
+ });
765
+ var Pressable = React3.forwardRef(
766
+ ({
767
+ children,
768
+ className,
769
+ href,
770
+ onClick,
771
+ variant,
772
+ size,
773
+ asButton = false,
774
+ fallbackComponentType = "span",
775
+ componentType,
776
+ "aria-label": ariaLabel,
777
+ "aria-describedby": ariaDescribedby,
778
+ id,
779
+ ...props
780
+ }, ref) => {
781
+ const navigation = useNavigation({ href, onClick });
782
+ const {
783
+ normalizedHref,
784
+ target,
785
+ rel,
786
+ linkType,
787
+ isInternal,
788
+ handleClick
789
+ } = navigation;
790
+ const shouldRenderLink = normalizedHref && linkType !== "none";
791
+ const shouldRenderButton = !shouldRenderLink && onClick;
792
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
793
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
794
+ const shouldApplyButtonStyles = asButton || variant || size;
795
+ const combinedClassName = cn(
796
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
797
+ className
798
+ );
799
+ const dataProps = Object.fromEntries(
800
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
801
+ );
802
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
803
+ "data-slot": "button",
804
+ "data-variant": variant ?? "default",
805
+ "data-size": size ?? "default"
806
+ } : {};
807
+ const commonProps = {
808
+ className: combinedClassName,
809
+ onClick: handleClick,
810
+ "aria-label": ariaLabel,
811
+ "aria-describedby": ariaDescribedby,
812
+ id,
813
+ ...dataProps,
814
+ ...buttonDataAttributes
815
+ };
816
+ if (finalComponentType === "a" && shouldRenderLink) {
817
+ return /* @__PURE__ */ jsx(
818
+ "a",
819
+ {
820
+ ref,
821
+ href: normalizedHref,
822
+ target,
823
+ rel,
824
+ ...commonProps,
825
+ ...props,
826
+ children
827
+ }
828
+ );
829
+ }
830
+ if (finalComponentType === "button") {
831
+ return /* @__PURE__ */ jsx(
832
+ "button",
833
+ {
834
+ ref,
835
+ type: props.type || "button",
836
+ ...commonProps,
837
+ ...props,
838
+ children
839
+ }
840
+ );
841
+ }
842
+ if (finalComponentType === "div") {
843
+ return /* @__PURE__ */ jsx(
844
+ "div",
845
+ {
846
+ ref,
847
+ ...commonProps,
848
+ children
849
+ }
850
+ );
851
+ }
852
+ return /* @__PURE__ */ jsx(
853
+ "span",
854
+ {
855
+ ref,
856
+ ...commonProps,
857
+ children
858
+ }
859
+ );
860
+ }
861
+ );
862
+ Pressable.displayName = "Pressable";
456
863
  function TestimonialsSimpleGrid({
457
864
  testimonials,
458
865
  testimonialsSlot,
@@ -463,6 +870,7 @@ function TestimonialsSimpleGrid({
463
870
  headerClassName,
464
871
  headingClassName,
465
872
  descriptionClassName,
873
+ cardContentClassName,
466
874
  gridClassName,
467
875
  cardClassName,
468
876
  quoteClassName,
@@ -473,17 +881,11 @@ function TestimonialsSimpleGrid({
473
881
  pattern,
474
882
  patternOpacity
475
883
  }) {
476
- const gridCols = {
477
- 2: "sm:grid-cols-2",
478
- 3: "sm:grid-cols-2 lg:grid-cols-3",
479
- 4: "sm:grid-cols-2 lg:grid-cols-4"
480
- };
481
- const effectiveColumns = columns || 3;
482
884
  const getAuthorName = useCallback((testimonial) => {
483
885
  if (typeof testimonial.author === "string") return testimonial.author;
484
886
  return "";
485
887
  }, []);
486
- const getAvatarSrc = useCallback(
888
+ useCallback(
487
889
  (testimonial) => {
488
890
  return testimonial.avatarSrc || testimonial.avatar?.src;
489
891
  },
@@ -498,53 +900,89 @@ function TestimonialsSimpleGrid({
498
900
  return /* @__PURE__ */ jsx(
499
901
  "div",
500
902
  {
501
- className: cn("grid gap-6", gridCols[effectiveColumns], gridClassName),
903
+ className: cn(
904
+ "grid gap-4 md:gap-6 lg:gap-8 md:grid-cols-2 lg:grid-cols-3",
905
+ gridClassName
906
+ ),
502
907
  children: testimonials.map((testimonial, index) => {
503
908
  const authorName = getAuthorName(testimonial);
504
- const avatarSrc = getAvatarSrc(testimonial);
505
- return /* @__PURE__ */ jsx(Card, { className: cardClassName, children: /* @__PURE__ */ jsxs(CardContent, { className: "p-6", children: [
506
- testimonial.quote && (typeof testimonial.quote === "string" ? /* @__PURE__ */ jsxs(
507
- "p",
508
- {
509
- className: cn(
510
- "mb-6 text-sm leading-relaxed ",
511
- quoteClassName
512
- ),
513
- children: [
514
- "\u201C",
515
- testimonial.quote,
516
- "\u201D"
517
- ]
518
- }
519
- ) : /* @__PURE__ */ jsx("div", { className: cn("mb-6", quoteClassName), children: testimonial.quote })),
520
- /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3", authorClassName), children: [
521
- /* @__PURE__ */ jsxs(Avatar, { className: "size-10", children: [
522
- /* @__PURE__ */ jsx(AvatarImage, { src: avatarSrc, alt: authorName }),
523
- /* @__PURE__ */ jsx(AvatarFallback, { children: getInitials(authorName) })
524
- ] }),
525
- /* @__PURE__ */ jsxs("div", { children: [
526
- testimonial.author && (typeof testimonial.author === "string" ? /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: testimonial.author }) : testimonial.author),
527
- /* @__PURE__ */ jsxs("p", { className: "text-xs ", children: [
528
- testimonial.role && (typeof testimonial.role === "string" ? testimonial.role : null),
529
- testimonial.company && (typeof testimonial.company === "string" ? `, ${testimonial.company}` : null)
530
- ] })
531
- ] })
532
- ] })
533
- ] }) }, index);
909
+ return /* @__PURE__ */ jsx(
910
+ Pressable,
911
+ {
912
+ href: testimonial.linkConfig?.href,
913
+ className: cn(
914
+ "bg-card text-card-foreground",
915
+ "flex flex-col gap-6",
916
+ testimonial.linkConfig?.href ? "cursor-pointer hover:bg-black hover:text-white transition-all duration-500" : "",
917
+ "rounded-2xl py-0 shadow-xl group",
918
+ "ring-4 ring-ring",
919
+ cardClassName
920
+ ),
921
+ children: /* @__PURE__ */ jsxs(
922
+ CardContent,
923
+ {
924
+ className: cn(
925
+ "px-0 h-full flex flex-col-reverse items-stretch justify-between gap-12",
926
+ cardContentClassName
927
+ ),
928
+ children: [
929
+ /* @__PURE__ */ jsx(
930
+ "div",
931
+ {
932
+ className: cn(
933
+ "flex items-center justify-between",
934
+ authorClassName
935
+ ),
936
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
937
+ /* @__PURE__ */ jsxs(Avatar, { className: "relative flex shrink-0 size-24 border-t-4 border-r-4 border-primary rounded-tr-xl rounded-tl-none rounded-br-none rounded-bl-none shadow-xl", children: [
938
+ /* @__PURE__ */ jsx(
939
+ AvatarImage,
940
+ {
941
+ src: testimonial.avatarSrc,
942
+ alt: authorName
943
+ }
944
+ ),
945
+ /* @__PURE__ */ jsx(AvatarFallback, { children: getInitials(authorName) })
946
+ ] }),
947
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1 pt-2 pr-6 pb-2", children: [
948
+ /* @__PURE__ */ jsxs("div", { className: "space-y-0", children: [
949
+ testimonial.author && (typeof testimonial.author === "string" ? /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold leading-relaxed", children: testimonial.author }) : testimonial.author),
950
+ testimonial.role && (typeof testimonial.role === "string" ? /* @__PURE__ */ jsx("p", { className: "text-base", children: testimonial.role }) : testimonial.role)
951
+ ] }),
952
+ testimonial.linkConfig?.href && /* @__PURE__ */ jsx(
953
+ Pressable,
954
+ {
955
+ href: testimonial.linkConfig.href,
956
+ className: cn(
957
+ "text-base transition-all duration-300",
958
+ "underline underline-offset-4",
959
+ testimonial.linkConfig.className
960
+ ),
961
+ children: testimonial.linkConfig.label
962
+ }
963
+ )
964
+ ] })
965
+ ] })
966
+ }
967
+ ),
968
+ /* @__PURE__ */ jsx("div", { className: "pt-6 md: pt-8 px-6 md:px-8", children: testimonial.quote && (typeof testimonial.quote === "string" ? /* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed", children: testimonial.quote }) : testimonial.quote) })
969
+ ]
970
+ }
971
+ )
972
+ },
973
+ index
974
+ );
534
975
  })
535
976
  }
536
977
  );
537
978
  }, [
538
979
  testimonialsSlot,
539
- gridCols,
540
- effectiveColumns,
541
980
  gridClassName,
542
981
  testimonials,
543
982
  cardClassName,
544
- quoteClassName,
983
+ cardContentClassName,
545
984
  authorClassName,
546
985
  getAuthorName,
547
- getAvatarSrc,
548
986
  getInitials
549
987
  ]);
550
988
  return /* @__PURE__ */ jsxs(
@@ -560,19 +998,29 @@ function TestimonialsSimpleGrid({
560
998
  /* @__PURE__ */ jsxs(
561
999
  "div",
562
1000
  {
563
- className: cn("mx-auto mb-12 max-w-2xl text-center", headerClassName),
1001
+ className: cn(
1002
+ "mx-auto mb-12 max-w-full md:max-w-2xl text-center",
1003
+ headerClassName
1004
+ ),
564
1005
  children: [
565
1006
  heading && (typeof heading === "string" ? /* @__PURE__ */ jsx(
566
1007
  "h2",
567
1008
  {
568
1009
  className: cn(
569
- "text-3xl font-semibold tracking-tight md:text-4xl",
1010
+ "text-pretty text-3xl md:text-4xl lg:text-6xl",
1011
+ "font-semibold tracking-tight",
570
1012
  headingClassName
571
1013
  ),
572
1014
  children: heading
573
1015
  }
574
- ) : /* @__PURE__ */ jsx("div", { className: headingClassName, children: heading })),
575
- description && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: cn("mt-4 text-lg ", descriptionClassName), children: description }) : /* @__PURE__ */ jsx("div", { className: cn("mt-4", descriptionClassName), children: description }))
1016
+ ) : heading),
1017
+ description && (typeof description === "string" ? /* @__PURE__ */ jsx(
1018
+ "p",
1019
+ {
1020
+ className: cn("mt-4 text-lg text-balance", descriptionClassName),
1021
+ children: description
1022
+ }
1023
+ ) : description)
576
1024
  ]
577
1025
  }
578
1026
  ),