xertica-ui 2.8.0 → 2.9.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 (286) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/README.md +1 -1
  3. package/bin/cli.ts +327 -87
  4. package/bin/language-config.ts +58 -18
  5. package/components/blocks/auth/AuthPageShell.tsx +63 -18
  6. package/components/blocks/auth/SocialLoginButtons.tsx +3 -3
  7. package/components/blocks/index.ts +1 -0
  8. package/components/blocks/marketing/CTASection.tsx +73 -0
  9. package/components/blocks/marketing/ComplianceBadgeRow.tsx +49 -0
  10. package/components/blocks/marketing/EvidenceTimeline.tsx +91 -0
  11. package/components/blocks/marketing/FeatureRow.tsx +78 -0
  12. package/components/blocks/marketing/Hero.tsx +125 -0
  13. package/components/blocks/marketing/HowItWorksSteps.tsx +90 -0
  14. package/components/blocks/marketing/LogoCloud.tsx +47 -0
  15. package/components/blocks/marketing/MarketingFooter.tsx +109 -0
  16. package/components/blocks/marketing/MarketingNavbar.tsx +192 -0
  17. package/components/blocks/marketing/PillBadge.tsx +96 -0
  18. package/components/blocks/marketing/SectionHeading.tsx +82 -0
  19. package/components/blocks/marketing/ServiceCardGrid.tsx +238 -0
  20. package/components/blocks/marketing/StatBand.tsx +99 -0
  21. package/components/blocks/marketing/TopAccentCards.tsx +91 -0
  22. package/components/blocks/marketing/index.ts +41 -0
  23. package/components/brand/index.ts +1 -0
  24. package/components/brand/isotype/Isotype.tsx +64 -0
  25. package/components/brand/isotype/IsotypeDiagonal.tsx +51 -0
  26. package/components/brand/isotype/IsotypeFrames.tsx +82 -0
  27. package/components/brand/isotype/IsotypeMini.tsx +65 -0
  28. package/components/brand/isotype/IsotypeTwist.tsx +68 -0
  29. package/components/brand/isotype/frame-variants.ts +20 -0
  30. package/components/brand/isotype/index.ts +9 -0
  31. package/components/brand/isotype/isotype-diagonal.mdx +52 -0
  32. package/components/brand/isotype/isotype-diagonal.stories.tsx +44 -0
  33. package/components/brand/isotype/isotype-diagonal.test.tsx +180 -0
  34. package/components/brand/isotype/isotype-frames.mdx +50 -0
  35. package/components/brand/isotype/isotype-frames.stories.tsx +63 -0
  36. package/components/brand/isotype/isotype-frames.test.tsx +92 -0
  37. package/components/brand/isotype/isotype-mini.mdx +61 -0
  38. package/components/brand/isotype/isotype-mini.stories.tsx +75 -0
  39. package/components/brand/isotype/isotype-mini.test.tsx +45 -0
  40. package/components/brand/isotype/isotype-twist.test.tsx +71 -0
  41. package/components/brand/isotype/isotype.mdx +61 -0
  42. package/components/brand/isotype/isotype.stories.tsx +74 -0
  43. package/components/brand/isotype/isotype.test.tsx +41 -0
  44. package/components/brand/isotype/mini-patterns.ts +50 -0
  45. package/components/brand/isotype/patterns.ts +83 -0
  46. package/components/brand/isotype/twist-variants.ts +20 -0
  47. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +3 -6
  48. package/components/pages/index.ts +1 -0
  49. package/components/pages/landing-page/LandingPage.tsx +360 -0
  50. package/components/pages/landing-page/index.ts +1 -0
  51. package/components/pages/login-page/LoginPage.tsx +3 -6
  52. package/components/pages/reset-password-page/ResetPasswordPage.tsx +1 -4
  53. package/components/pages/verify-email-page/VerifyEmailPage.tsx +2 -5
  54. package/components/ui/button/button.test.tsx +1 -1
  55. package/components/ui/button/button.tsx +7 -6
  56. package/components/ui/card/card.test.tsx +12 -0
  57. package/components/ui/card/card.tsx +5 -3
  58. package/components/ui/input-otp/input-otp.test.tsx +14 -1
  59. package/contexts/BrandColorsContext.tsx +9 -5
  60. package/contexts/theme-data.ts +32 -5
  61. package/dist/AssistantChart-BU48lxL2.js +3383 -0
  62. package/dist/AssistantChart-CoN6ga6Z.js +3383 -0
  63. package/dist/AssistantChart-DIRYJ7WY.js +3383 -0
  64. package/dist/AssistantChart-DOnY1ZlD.cjs +3551 -0
  65. package/dist/AssistantChart-DjM3qnp5.cjs +3551 -0
  66. package/dist/AssistantChart-hxPyE1S9.cjs +3551 -0
  67. package/dist/AudioPlayer-CpihsbaD.js +1278 -0
  68. package/dist/AudioPlayer-CvGajzMC.cjs +1282 -0
  69. package/dist/AudioPlayer-CvHpFqDG.cjs +1282 -0
  70. package/dist/AudioPlayer-D4S7GQou.js +1278 -0
  71. package/dist/BrandColorsContext-BNKLUVcU.js +829 -0
  72. package/dist/BrandColorsContext-DNZGHItQ.cjs +836 -0
  73. package/dist/BrandColorsContext-Ug_TZ8yn.cjs +846 -0
  74. package/dist/BrandColorsContext-z0O2LlZz.js +839 -0
  75. package/dist/CodeBlock-BkaZf-R8.cjs +223 -0
  76. package/dist/CodeBlock-CKu8LgbP.cjs +223 -0
  77. package/dist/CodeBlock-DiLS5LLI.js +221 -0
  78. package/dist/CodeBlock-zdylBGdZ.js +221 -0
  79. package/dist/CustomTooltipContent-BAR5qCQg.js +33 -0
  80. package/dist/CustomTooltipContent-CBLHBxX8.cjs +54 -0
  81. package/dist/CustomTooltipContent-CjWm3jjV.js +33 -0
  82. package/dist/CustomTooltipContent-DTV9MN9E.cjs +54 -0
  83. package/dist/EvidenceTimeline-DrRk4yqb.cjs +560 -0
  84. package/dist/EvidenceTimeline-l4MaV4C7.js +546 -0
  85. package/dist/FeatureCard-CIbBHqeY.cjs +497 -0
  86. package/dist/FeatureCard-DtoKPSfW.cjs +497 -0
  87. package/dist/FeatureCard-P4iEpBmB.js +485 -0
  88. package/dist/FeatureCard-e3f8bnF0.js +485 -0
  89. package/dist/ImageWithFallback-C1ww9Hg3.cjs +122 -0
  90. package/dist/ImageWithFallback-CBrkAEo3.cjs +122 -0
  91. package/dist/ImageWithFallback-CGk5zPH-.js +98 -0
  92. package/dist/ImageWithFallback-CfnoFFSP.js +98 -0
  93. package/dist/Isotype--fRZWwS6.js +85 -0
  94. package/dist/Isotype-0dpLqetB.js +85 -0
  95. package/dist/Isotype-B8XLEXSB.cjs +92 -0
  96. package/dist/Isotype-ChKwN7e-.cjs +91 -0
  97. package/dist/IsotypeDiagonal-CuPYPP4f.js +84 -0
  98. package/dist/IsotypeDiagonal-eNcOXRAc.cjs +91 -0
  99. package/dist/IsotypeDiagonal-oiwpXZhE.js +104 -0
  100. package/dist/IsotypeDiagonal-xMFoFXkb.cjs +109 -0
  101. package/dist/IsotypeFrames-BcWtyAWp.cjs +83 -0
  102. package/dist/IsotypeFrames-BnvSJKiH.cjs +73 -0
  103. package/dist/IsotypeFrames-iDRTRuIu.js +79 -0
  104. package/dist/IsotypeFrames-qoXOvOJt.js +69 -0
  105. package/dist/IsotypeMini-CQtWVo3h.js +126 -0
  106. package/dist/IsotypeMini-Cu_sW5yN.cjs +134 -0
  107. package/dist/IsotypeTwist-BTdNL4iV.js +106 -0
  108. package/dist/IsotypeTwist-DvsUgZs_.cjs +115 -0
  109. package/dist/LanguageContext-B1aOXO-K.js +1987 -0
  110. package/dist/LanguageContext-BP0k7AzI.js +1993 -0
  111. package/dist/LanguageContext-CChcIHIG.cjs +1998 -0
  112. package/dist/LanguageContext-ubC7TSs_.cjs +1992 -0
  113. package/dist/LanguageSelector-BLFPXGo8.cjs +48 -0
  114. package/dist/LanguageSelector-CYRzWkRZ.cjs +48 -0
  115. package/dist/LanguageSelector-CyHjZgC4.cjs +48 -0
  116. package/dist/LanguageSelector-DE8lIySO.js +46 -0
  117. package/dist/LanguageSelector-DUr1hjBW.js +46 -0
  118. package/dist/LanguageSelector-DjbWIKWC.js +46 -0
  119. package/dist/LogoCloud-C_uMKVNg.cjs +513 -0
  120. package/dist/LogoCloud-DJsMPNPh.js +500 -0
  121. package/dist/MarketingFooter-B_ycEdTJ.cjs +727 -0
  122. package/dist/MarketingFooter-Bhx-2Vlr.cjs +727 -0
  123. package/dist/MarketingFooter-Br1MGK9e.js +699 -0
  124. package/dist/MarketingFooter-BwE1vmeX.cjs +700 -0
  125. package/dist/MarketingFooter-CsZ1_xL9.js +709 -0
  126. package/dist/MarketingFooter-DCwf78Q4.cjs +716 -0
  127. package/dist/MarketingFooter-KH2r-OOL.js +709 -0
  128. package/dist/MarketingFooter-nB7G7gQ5.js +682 -0
  129. package/dist/SectionHeading-DEeOKcAd.cjs +857 -0
  130. package/dist/SectionHeading-DMNObcwm.js +838 -0
  131. package/dist/ThemeToggle--CGJjQJv.cjs +219 -0
  132. package/dist/ThemeToggle-Bn_7Pmfe.js +215 -0
  133. package/dist/ThemeToggle-CoL8Ady7.js +215 -0
  134. package/dist/ThemeToggle-D2Wzm5bn.cjs +219 -0
  135. package/dist/VerifyEmailPage-90lK6pP4.js +3258 -0
  136. package/dist/VerifyEmailPage-BJX1Rter.cjs +3320 -0
  137. package/dist/VerifyEmailPage-BSWvOgry.js +3310 -0
  138. package/dist/VerifyEmailPage-CDqIkhx-.js +3224 -0
  139. package/dist/VerifyEmailPage-Crxje3ZB.js +3323 -0
  140. package/dist/VerifyEmailPage-D2ShbuEN.cjs +3333 -0
  141. package/dist/VerifyEmailPage-DEBZXQ7c.cjs +3310 -0
  142. package/dist/VerifyEmailPage-DGaX-jZv.cjs +3268 -0
  143. package/dist/VerifyEmailPage-ZtOPkgOA.cjs +3234 -0
  144. package/dist/VerifyEmailPage-s927GSiR.js +3300 -0
  145. package/dist/XerticaOrbe-BHex09xs.js +1925 -0
  146. package/dist/XerticaOrbe-BKW3LJEz.js +1925 -0
  147. package/dist/XerticaOrbe-Br2i99U_.cjs +1927 -0
  148. package/dist/XerticaOrbe-kjFmuyx-.cjs +1927 -0
  149. package/dist/XerticaProvider-Bi5lKC9N.js +44 -0
  150. package/dist/XerticaProvider-BrPMVhiv.js +44 -0
  151. package/dist/XerticaProvider-CnX5kt5W.cjs +46 -0
  152. package/dist/XerticaProvider-DEKNJTlN.js +44 -0
  153. package/dist/XerticaProvider-X_wavDYA.cjs +46 -0
  154. package/dist/XerticaProvider-b3n_oL8w.cjs +46 -0
  155. package/dist/alert-dialog--qdlmB5i.cjs +872 -0
  156. package/dist/alert-dialog-C48TOdYU.cjs +872 -0
  157. package/dist/alert-dialog-CEPpnpXt.js +819 -0
  158. package/dist/alert-dialog-NjflitDa.js +819 -0
  159. package/dist/assistant.cjs.js +2 -2
  160. package/dist/assistant.es.js +2 -2
  161. package/dist/avatar-CtEKgg7s.cjs +77 -0
  162. package/dist/avatar-D03MNQxs.js +54 -0
  163. package/dist/avatar-Df7KgSvs.js +54 -0
  164. package/dist/avatar-Gy0_Xu9i.cjs +77 -0
  165. package/dist/blocks.cjs.js +33 -18
  166. package/dist/blocks.es.js +2 -2
  167. package/dist/brand.cjs.js +110 -4
  168. package/dist/brand.es.js +98 -4
  169. package/dist/breadcrumb-BGO5PZPG.js +90 -0
  170. package/dist/breadcrumb-BvGAY4ne.cjs +98 -0
  171. package/dist/breadcrumb-CU-punra.js +90 -0
  172. package/dist/breadcrumb-DjV9wfX1.cjs +98 -0
  173. package/dist/button-B05czY_8.js +62 -0
  174. package/dist/button-B3SE1liJ.js +62 -0
  175. package/dist/button-BMDlWZR8.cjs +85 -0
  176. package/dist/button-DVhloDtr.cjs +85 -0
  177. package/dist/cli.js +280 -62
  178. package/dist/components/blocks/auth/AuthPageShell.d.ts +21 -5
  179. package/dist/components/blocks/index.d.ts +1 -0
  180. package/dist/components/blocks/marketing/CTASection.d.ts +28 -0
  181. package/dist/components/blocks/marketing/ComplianceBadgeRow.d.ts +23 -0
  182. package/dist/components/blocks/marketing/EvidenceTimeline.d.ts +26 -0
  183. package/dist/components/blocks/marketing/FeatureRow.d.ts +25 -0
  184. package/dist/components/blocks/marketing/Hero.d.ts +35 -0
  185. package/dist/components/blocks/marketing/HowItWorksSteps.d.ts +29 -0
  186. package/dist/components/blocks/marketing/LogoCloud.d.ts +22 -0
  187. package/dist/components/blocks/marketing/MarketingFooter.d.ts +42 -0
  188. package/dist/components/blocks/marketing/MarketingNavbar.d.ts +47 -0
  189. package/dist/components/blocks/marketing/PillBadge.d.ts +21 -0
  190. package/dist/components/blocks/marketing/SectionHeading.d.ts +23 -0
  191. package/dist/components/blocks/marketing/ServiceCardGrid.d.ts +65 -0
  192. package/dist/components/blocks/marketing/StatBand.d.ts +25 -0
  193. package/dist/components/blocks/marketing/TopAccentCards.d.ts +29 -0
  194. package/dist/components/blocks/marketing/index.d.ts +28 -0
  195. package/dist/components/brand/index.d.ts +1 -0
  196. package/dist/components/brand/isotype/Isotype.d.ts +27 -0
  197. package/dist/components/brand/isotype/IsotypeDiagonal.d.ts +19 -0
  198. package/dist/components/brand/isotype/IsotypeFrames.d.ts +21 -0
  199. package/dist/components/brand/isotype/IsotypeMini.d.ts +26 -0
  200. package/dist/components/brand/isotype/IsotypeTwist.d.ts +22 -0
  201. package/dist/components/brand/isotype/frame-variants.d.ts +11 -0
  202. package/dist/components/brand/isotype/index.d.ts +9 -0
  203. package/dist/components/brand/isotype/mini-patterns.d.ts +25 -0
  204. package/dist/components/brand/isotype/patterns.d.ts +42 -0
  205. package/dist/components/brand/isotype/twist-variants.d.ts +11 -0
  206. package/dist/components/pages/forgot-password-page/ForgotPasswordPage.d.ts +2 -2
  207. package/dist/components/pages/index.d.ts +1 -0
  208. package/dist/components/pages/landing-page/LandingPage.d.ts +18 -0
  209. package/dist/components/pages/landing-page/index.d.ts +1 -0
  210. package/dist/components/pages/login-page/LoginPage.d.ts +2 -2
  211. package/dist/components/pages/verify-email-page/VerifyEmailPage.d.ts +1 -1
  212. package/dist/components/ui/card/card.d.ts +3 -1
  213. package/dist/contexts/theme-data.d.ts +6 -0
  214. package/dist/dropdown-menu-ChQa9zW3.cjs +225 -0
  215. package/dist/dropdown-menu-DRvnsQAt.cjs +225 -0
  216. package/dist/dropdown-menu-DUk81i5Y.js +190 -0
  217. package/dist/dropdown-menu-NlUHhVmK.js +190 -0
  218. package/dist/hooks.cjs.js +2 -2
  219. package/dist/hooks.es.js +2 -2
  220. package/dist/index.cjs.js +57 -41
  221. package/dist/index.es.js +25 -25
  222. package/dist/input-Csp_Metb.cjs +91 -0
  223. package/dist/input-DVRwGVLx.js +65 -0
  224. package/dist/input-Dqyj7Hdw.cjs +91 -0
  225. package/dist/input-dOgrFQ-3.js +65 -0
  226. package/dist/layout.cjs.js +1 -1
  227. package/dist/layout.es.js +1 -1
  228. package/dist/media.cjs.js +1 -1
  229. package/dist/media.es.js +1 -1
  230. package/dist/pages.cjs.js +2 -1
  231. package/dist/pages.es.js +1 -1
  232. package/dist/rich-text-editor-7K7UjLJN.cjs +2968 -0
  233. package/dist/rich-text-editor-B3jLP2bm.cjs +2968 -0
  234. package/dist/rich-text-editor-BntMVQsB.js +2894 -0
  235. package/dist/rich-text-editor-Diz_onyB.js +2894 -0
  236. package/dist/rich-text-editor-RWvK4hd3.cjs +2968 -0
  237. package/dist/rich-text-editor-gauEkzPM.js +2894 -0
  238. package/dist/select-B6PygS38.cjs +161 -0
  239. package/dist/select-BD763J5Y.cjs +161 -0
  240. package/dist/select-QJDKZITN.js +130 -0
  241. package/dist/select-q7aDfuPn.js +130 -0
  242. package/dist/sidebar-Bkk1YAsD.cjs +1154 -0
  243. package/dist/sidebar-CuzYeOSz.cjs +1154 -0
  244. package/dist/sidebar-CwlW3LXE.js +1151 -0
  245. package/dist/sidebar-DNkf-Ug6.js +1151 -0
  246. package/dist/sidebar-DaS3fplw.cjs +1154 -0
  247. package/dist/sidebar-FDCY42oP.js +1151 -0
  248. package/dist/skeleton-BtBwJ39W.js +79 -0
  249. package/dist/skeleton-CJyg0eJ1.cjs +88 -0
  250. package/dist/skeleton-D8WaauK0.cjs +88 -0
  251. package/dist/skeleton-DBYtjaZW.cjs +88 -0
  252. package/dist/skeleton-DY_lSFWf.js +79 -0
  253. package/dist/skeleton-Df65Ox10.js +79 -0
  254. package/dist/slider-BKV_vvsh.cjs +78 -0
  255. package/dist/slider-B_lUjFNa.cjs +78 -0
  256. package/dist/slider-CtBpIaU4.js +56 -0
  257. package/dist/slider-KgWmSJbx.js +56 -0
  258. package/dist/tooltip-BPttuPxU.js +48 -0
  259. package/dist/tooltip-CIKRzQqE.cjs +72 -0
  260. package/dist/tooltip-CoDByjE_.cjs +72 -0
  261. package/dist/tooltip-_MAwsiOL.js +48 -0
  262. package/dist/ui.cjs.js +13 -13
  263. package/dist/ui.es.js +13 -13
  264. package/dist/xertica-assistant-B1xAl2Vn.js +2173 -0
  265. package/dist/xertica-assistant-BBUMaUXw.js +2173 -0
  266. package/dist/xertica-assistant-CWuBwfzt.cjs +2180 -0
  267. package/dist/xertica-assistant-D2hlwiEP.js +2173 -0
  268. package/dist/xertica-assistant-DN2J_sQQ.cjs +2180 -0
  269. package/dist/xertica-assistant-DdYS6WXT.cjs +2180 -0
  270. package/dist/xertica-ui.css +1 -1
  271. package/llms-compact.txt +1 -1
  272. package/llms.txt +1 -1
  273. package/package.json +4 -2
  274. package/styles/xertica/base.css +8 -0
  275. package/styles/xertica/tokens.css +1 -0
  276. package/templates/package.json +1 -1
  277. package/templates/src/app/components/AuthGuard.tsx +6 -0
  278. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +1 -4
  279. package/templates/src/features/auth/ui/LoginContent.tsx +1 -4
  280. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +1 -4
  281. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +1 -4
  282. package/templates/src/locales/en/pages/landing.json +175 -0
  283. package/templates/src/locales/es/pages/landing.json +175 -0
  284. package/templates/src/locales/pt-BR/pages/landing.json +175 -0
  285. package/templates/src/pages/LandingPage.tsx +349 -0
  286. package/templates/src/styles/xertica/tokens.css +1 -0
package/dist/cli.js CHANGED
@@ -69,12 +69,12 @@ var colorThemes = [
69
69
  darkCard: "#1E1E1E",
70
70
  darkMuted: "#26241f",
71
71
  darkBorder: "#38352c",
72
- gradientStart: "#1899AF",
73
- // Celeste
74
- gradientEnd: "#C45BAA",
75
- // Magenta
76
- gradientStartDark: "#126578",
77
- gradientEndDark: "#8F3F7D",
72
+ // Flat fill, same value on every stop — this theme uses solid ink
73
+ // colors, never gradients (Negro Xertica, matching sidebar/secondary-button).
74
+ gradientStart: "#1E1E1E",
75
+ gradientEnd: "#1E1E1E",
76
+ gradientStartDark: "#1E1E1E",
77
+ gradientEndDark: "#1E1E1E",
78
78
  chart1: "#3D63AC",
79
79
  // Azul
80
80
  chart2: "#1899AF",
@@ -91,11 +91,22 @@ var colorThemes = [
91
91
  // Marfim — cards, header, assistant panel
92
92
  inputBorderColor: "rgba(30, 30, 30, 0.4)",
93
93
  // Negro Xertica stroke — form fields only
94
+ outlineBorderColor: "rgba(30, 30, 30, 0.4)",
95
+ // Negro Xertica stroke — Button `outline` variant only
96
+ successColor: "#2E8B5A",
97
+ // Verde
98
+ warningColor: "#E37744",
99
+ // Naranja
100
+ infoColor: "#3D63AC",
101
+ // Azul
102
+ destructiveColor: "#DE5B48",
103
+ // Rojo Coral
94
104
  buttonRadius: "9999px",
95
- buttonStrokeWidth: "2px",
105
+ buttonStrokeWidth: "1px",
96
106
  buttonStrokeColor: "#1E1E1E",
97
107
  buttonStrokeColorDark: "#F2EDD8",
98
108
  // Crema
109
+ buttonFontWeight: "400",
99
110
  buttonSecondaryBg: "#1E1E1E",
100
111
  buttonSecondaryBgDark: "#1E1E1E",
101
112
  buttonSecondaryForeground: "#FFFEF8",
@@ -832,14 +843,7 @@ function generateAppTsx(selectedCodes, disableDarkMode = false) {
832
843
  const isMonolingual = selectedLangs.length === 1;
833
844
  const disableDarkModeProp = disableDarkMode ? `
834
845
  disableDarkMode={true}` : "";
835
- const isAllDefaults = selectedLangs.length === SUPPORTED_LANGUAGES.length && selectedLangs.every((l) => DEFAULT_SELECTION.includes(l.code));
836
- const languagesArrayLiteral = selectedLangs.map(
837
- (l) => ` { code: '${l.code}', label: '${l.label}', shortLabel: '${l.shortLabel}' },`
838
- ).join("\n");
839
- const availableLanguagesProp = isAllDefaults ? "" : `
840
- availableLanguages={[
841
- ${languagesArrayLiteral}
842
- ]}`;
846
+ const availableLanguagesProp = buildAvailableLanguagesProp(selectedCodes, " ");
843
847
  const monolingualBanner = isMonolingual ? `
844
848
  // This project is configured for a single language \u2014 the LanguageSelector
845
849
  // auto-hides because there is nothing to switch to.` : "";
@@ -895,6 +899,38 @@ export default function App() {
895
899
  }
896
900
  `;
897
901
  }
902
+ function generateLandingAppTsx(selectedCodes, disableDarkMode = false) {
903
+ const disableDarkModeProp = disableDarkMode ? `
904
+ disableDarkMode={true}` : "";
905
+ const availableLanguagesProp = buildAvailableLanguagesProp(selectedCodes, " ");
906
+ return `import React from 'react';
907
+ import { XerticaProvider } from 'xertica-ui/brand';
908
+ import { LandingPage } from '../pages/LandingPage';
909
+
910
+ export default function App() {
911
+ return (
912
+ <XerticaProvider
913
+ useCustomTokens={true}${availableLanguagesProp}${disableDarkModeProp}
914
+ >
915
+ <LandingPage />
916
+ </XerticaProvider>
917
+ );
918
+ }
919
+ `;
920
+ }
921
+ function buildAvailableLanguagesProp(selectedCodes, indent) {
922
+ const selectedLangs = SUPPORTED_LANGUAGES.filter((l) => selectedCodes.includes(l.code));
923
+ const isAllDefaults = selectedLangs.length === SUPPORTED_LANGUAGES.length && selectedLangs.every((l) => DEFAULT_SELECTION.includes(l.code));
924
+ if (isAllDefaults) return "";
925
+ const itemIndent = `${indent} `;
926
+ const languagesArrayLiteral = selectedLangs.map(
927
+ (l) => `${itemIndent}{ code: '${l.code}', label: '${l.label}', shortLabel: '${l.shortLabel}' },`
928
+ ).join("\n");
929
+ return `
930
+ ${indent}availableLanguages={[
931
+ ${languagesArrayLiteral}
932
+ ${indent}]}`;
933
+ }
898
934
  function toJsIdent(code) {
899
935
  return code.replace(/[^a-zA-Z0-9]/g, "");
900
936
  }
@@ -1112,12 +1148,156 @@ export function TemplatePage() {
1112
1148
  }
1113
1149
  `;
1114
1150
  }
1151
+ async function copyPackageJson(templatesDir, targetDir) {
1152
+ const pkgTemplatePath = path2.join(templatesDir, "package.json");
1153
+ if (await fs2.pathExists(pkgTemplatePath)) {
1154
+ const pkgContent = await fs2.readJson(pkgTemplatePath);
1155
+ const projectName = path2.basename(targetDir) || "my-xertica-app";
1156
+ pkgContent.name = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
1157
+ await fs2.writeJson(path2.join(targetDir, "package.json"), pkgContent, { spaces: 2 });
1158
+ }
1159
+ }
1160
+ async function initPageProject(targetDir, templatesDir) {
1161
+ const response = await prompts([
1162
+ {
1163
+ type: "multiselect",
1164
+ name: "languages",
1165
+ message: "Which languages should the page support?",
1166
+ instructions: false,
1167
+ hint: "Select at least 1. Single-language apps auto-hide the LanguageSelector.",
1168
+ min: 1,
1169
+ choices: SUPPORTED_LANGUAGES.map((l) => ({
1170
+ title: l.label,
1171
+ value: l.code,
1172
+ selected: true
1173
+ }))
1174
+ },
1175
+ {
1176
+ type: "select",
1177
+ name: "theme",
1178
+ message: "Select the default color theme for your project:",
1179
+ choices: colorThemes.map((t) => ({
1180
+ title: t.name,
1181
+ description: t.description,
1182
+ value: t.id
1183
+ })),
1184
+ initial: 0
1185
+ },
1186
+ {
1187
+ type: "confirm",
1188
+ name: "install",
1189
+ message: "Install dependencies automatically?",
1190
+ initial: true
1191
+ }
1192
+ ]);
1193
+ if (!response.languages || !response.theme) return;
1194
+ const spinner = ora("Initializing project...").start();
1195
+ try {
1196
+ await fs2.ensureDir(targetDir);
1197
+ const selectedLanguages = Array.isArray(response.languages) && response.languages.length > 0 ? response.languages : DEFAULT_SELECTION;
1198
+ const rootFilesToCopy = [
1199
+ "index.html",
1200
+ "vite.config.ts",
1201
+ "tsconfig.json",
1202
+ "tsconfig.node.json",
1203
+ "postcss.config.js",
1204
+ "vite-env.d.ts",
1205
+ "eslint.config.js",
1206
+ ".gitignore",
1207
+ ".prettierrc"
1208
+ ];
1209
+ for (const file of rootFilesToCopy) {
1210
+ const srcPath = path2.join(templatesDir, file);
1211
+ if (await fs2.pathExists(srcPath)) {
1212
+ await fs2.copy(srcPath, path2.join(targetDir, file));
1213
+ }
1214
+ }
1215
+ await copyPackageJson(templatesDir, targetDir);
1216
+ await fs2.copy(
1217
+ path2.join(templatesDir, "src", "main.tsx"),
1218
+ path2.join(targetDir, "src", "main.tsx")
1219
+ );
1220
+ await fs2.ensureDir(path2.join(targetDir, "src", "app"));
1221
+ await fs2.writeFile(
1222
+ path2.join(targetDir, "src", "app", "App.tsx"),
1223
+ generateLandingAppTsx(selectedLanguages)
1224
+ );
1225
+ await fs2.writeFile(
1226
+ path2.join(targetDir, "src", "i18n.ts"),
1227
+ generateI18nFile(selectedLanguages)
1228
+ );
1229
+ await syncLocaleFiles(templatesDir, targetDir, selectedLanguages, { pruneOthers: true });
1230
+ await writeLanguagesConfig(targetDir, selectedLanguages);
1231
+ await writeXerticaConfig(targetDir, {
1232
+ hasAssistant: false,
1233
+ disableDarkMode: false,
1234
+ themeId: response.theme,
1235
+ projectType: "page"
1236
+ });
1237
+ await fs2.ensureDir(path2.join(targetDir, "src", "pages"));
1238
+ await fs2.copy(
1239
+ path2.join(templatesDir, "src", "pages", "LandingPage.tsx"),
1240
+ path2.join(targetDir, "src", "pages", "LandingPage.tsx")
1241
+ );
1242
+ const selectedTheme = colorThemes.find((t) => t.id === response.theme) || colorThemes[0];
1243
+ const tokensDir = path2.join(targetDir, "src", "styles", "xertica");
1244
+ await fs2.ensureDir(tokensDir);
1245
+ await fs2.copy(
1246
+ path2.join(templatesDir, "src", "styles", "index.css"),
1247
+ path2.join(targetDir, "src", "styles", "index.css")
1248
+ );
1249
+ await fs2.writeFile(path2.join(tokensDir, "tokens.css"), generateTokensCss(selectedTheme));
1250
+ spinner.succeed("Project initialized successfully!");
1251
+ if (response.install) {
1252
+ const installSpinner = ora("Installing dependencies...").start();
1253
+ await execa("npm", ["install"], { cwd: targetDir });
1254
+ installSpinner.succeed("Dependencies installed!");
1255
+ }
1256
+ console.log(chalk.green("\n\u2705 Done! Your Xertica UI landing page is ready."));
1257
+ console.log(chalk.cyan(`
1258
+ cd ${path2.relative(process.cwd(), targetDir) || "."}`));
1259
+ if (!response.install) {
1260
+ console.log(chalk.cyan(" npm install"));
1261
+ }
1262
+ console.log(chalk.cyan(" npm run dev"));
1263
+ console.log();
1264
+ console.log(chalk.gray(" Edit the demo content in src/pages/LandingPage.tsx"));
1265
+ console.log(chalk.gray(" Customize the theme in src/styles/xertica/tokens.css"));
1266
+ console.log(chalk.gray(" To change the theme or languages later: npx xertica-ui update"));
1267
+ } catch (error) {
1268
+ spinner.fail("Failed to initialize project");
1269
+ console.error(error);
1270
+ }
1271
+ }
1115
1272
  var program = new Command();
1116
1273
  program.name("xertica-ui").description("CLI to initialize Xertica UI projects").version(pkgJson.version);
1117
1274
  program.command("init").description("Initialize a new Xertica UI project").argument("[directory]", "Directory to initialize in", ".").action(async (directory) => {
1118
1275
  const targetDir = path2.resolve(process.cwd(), directory);
1119
1276
  const templatesDir = path2.resolve(__dirname, "../templates");
1120
1277
  console.log(chalk.blue(`\u{1F680} Welcome to Xertica UI CLI! ${chalk.dim(`v${pkgJson.version}`)}`));
1278
+ const { projectType } = await prompts({
1279
+ type: "select",
1280
+ name: "projectType",
1281
+ message: "What do you want to create?",
1282
+ choices: [
1283
+ {
1284
+ title: "Full system",
1285
+ description: "Auth, sidebar, pages, i18n \u2014 the current full scaffold",
1286
+ value: "system"
1287
+ },
1288
+ {
1289
+ title: "Web page",
1290
+ description: "Just the marketing landing page \u2014 pick a theme and languages, done",
1291
+ value: "page"
1292
+ }
1293
+ ],
1294
+ initial: 0
1295
+ });
1296
+ if (!projectType) return;
1297
+ if (projectType === "page") {
1298
+ await initPageProject(targetDir, templatesDir);
1299
+ return;
1300
+ }
1121
1301
  const response = await prompts([
1122
1302
  {
1123
1303
  type: "multiselect",
@@ -1206,13 +1386,7 @@ program.command("init").description("Initialize a new Xertica UI project").argum
1206
1386
  await fs2.copy(srcPath, path2.join(targetDir, file));
1207
1387
  }
1208
1388
  }
1209
- const pkgTemplatePath = path2.join(templatesDir, "package.json");
1210
- if (await fs2.pathExists(pkgTemplatePath)) {
1211
- const pkgContent = await fs2.readJson(pkgTemplatePath);
1212
- const projectName = path2.basename(targetDir) || "my-xertica-app";
1213
- pkgContent.name = projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
1214
- await fs2.writeJson(path2.join(targetDir, "package.json"), pkgContent, { spaces: 2 });
1215
- }
1389
+ await copyPackageJson(templatesDir, targetDir);
1216
1390
  await fs2.copy(
1217
1391
  path2.join(templatesDir, "src", "main.tsx"),
1218
1392
  path2.join(targetDir, "src", "main.tsx")
@@ -1238,7 +1412,12 @@ program.command("init").description("Initialize a new Xertica UI project").argum
1238
1412
  );
1239
1413
  await syncLocaleFiles(templatesDir, targetDir, selectedLanguages, { pruneOthers: true });
1240
1414
  await writeLanguagesConfig(targetDir, selectedLanguages);
1241
- await writeXerticaConfig(targetDir, { hasAssistant, disableDarkMode, themeId: response.theme });
1415
+ await writeXerticaConfig(targetDir, {
1416
+ hasAssistant,
1417
+ disableDarkMode,
1418
+ themeId: response.theme,
1419
+ projectType: "system"
1420
+ });
1242
1421
  await fs2.ensureDir(path2.join(targetDir, "src", "app", "context"));
1243
1422
  await fs2.copy(
1244
1423
  path2.join(templatesDir, "src", "app", "context", "AuthContext.tsx"),
@@ -1362,6 +1541,8 @@ program.command("update").alias("update-theme").description("Update theme or pro
1362
1541
  const targetDir = process.cwd();
1363
1542
  console.log(chalk.blue(`\u{1F527} Xertica UI CLI ${chalk.dim(`v${pkgJson.version}`)}`));
1364
1543
  const currentConfig = await readXerticaConfig(targetDir);
1544
+ const projectType = currentConfig?.projectType ?? "system";
1545
+ const isPageProject = projectType === "page";
1365
1546
  const { updateType } = await prompts({
1366
1547
  type: "select",
1367
1548
  name: "updateType",
@@ -1377,11 +1558,13 @@ program.command("update").alias("update-theme").description("Update theme or pro
1377
1558
  description: "Add or remove supported languages (pt-BR, en, es, \u2026)",
1378
1559
  value: "languages"
1379
1560
  },
1380
- {
1381
- title: "Assistant",
1382
- description: currentConfig?.hasAssistant ? "Remove the AI Assistant from your project" : "Add the AI Assistant to your project",
1383
- value: "assistant"
1384
- },
1561
+ ...isPageProject ? [] : [
1562
+ {
1563
+ title: "Assistant",
1564
+ description: currentConfig?.hasAssistant ? "Remove the AI Assistant from your project" : "Add the AI Assistant to your project",
1565
+ value: "assistant"
1566
+ }
1567
+ ],
1385
1568
  {
1386
1569
  title: "Dark Mode",
1387
1570
  description: currentConfig?.disableDarkMode ? "Enable dark mode support in your project" : "Disable dark mode support in your project",
@@ -1389,7 +1572,7 @@ program.command("update").alias("update-theme").description("Update theme or pro
1389
1572
  },
1390
1573
  {
1391
1574
  title: "Project files",
1392
- description: "Update app shell, shared, features and pages to a specific version",
1575
+ description: isPageProject ? "Update the app shell and landing page to a specific version" : "Update app shell, shared, features and pages to a specific version",
1393
1576
  value: "project"
1394
1577
  }
1395
1578
  ]
@@ -1510,7 +1693,7 @@ ${summary.join("\n")}
1510
1693
  await fs2.writeFile(path2.join(targetDir, "src", "i18n.ts"), generateI18nFile(newCodes));
1511
1694
  await fs2.writeFile(
1512
1695
  path2.join(targetDir, "src", "app", "App.tsx"),
1513
- generateAppTsx(newCodes, currentConfig?.disableDarkMode ?? false)
1696
+ isPageProject ? generateLandingAppTsx(newCodes, currentConfig?.disableDarkMode ?? false) : generateAppTsx(newCodes, currentConfig?.disableDarkMode ?? false)
1514
1697
  );
1515
1698
  await writeLanguagesConfig(targetDir, newCodes);
1516
1699
  spinner2.succeed("Languages updated successfully!");
@@ -1672,7 +1855,7 @@ AI Assistant is currently: ${currentlyHas ? chalk.green("enabled") : chalk.red("
1672
1855
  const selectedCodes = persistedCodes && persistedCodes.length > 0 ? persistedCodes : DEFAULT_SELECTION;
1673
1856
  await fs2.writeFile(
1674
1857
  path2.join(targetDir, "src", "app", "App.tsx"),
1675
- generateAppTsx(selectedCodes, newDisableDarkMode)
1858
+ isPageProject ? generateLandingAppTsx(selectedCodes, newDisableDarkMode) : generateAppTsx(selectedCodes, newDisableDarkMode)
1676
1859
  );
1677
1860
  spinner2.succeed(
1678
1861
  newDisableDarkMode ? "Dark mode disabled successfully! (Locked to Light Mode)" : "Dark mode enabled successfully!"
@@ -1712,7 +1895,20 @@ AI Assistant is currently: ${currentlyHas ? chalk.green("enabled") : chalk.red("
1712
1895
  type: "multiselect",
1713
1896
  name: "filesToUpdate",
1714
1897
  message: "Select which parts of the project to update:",
1715
- choices: [
1898
+ choices: isPageProject ? [
1899
+ {
1900
+ title: "App shell + landing page",
1901
+ description: "App.tsx and the LandingPage re-export",
1902
+ value: "app",
1903
+ selected: true
1904
+ },
1905
+ {
1906
+ title: "Root config files",
1907
+ description: "vite.config.ts, tsconfig.json, etc.",
1908
+ value: "config",
1909
+ selected: false
1910
+ }
1911
+ ] : [
1716
1912
  {
1717
1913
  title: "App shell (src/app/)",
1718
1914
  description: "App.tsx, AppLayout.tsx",
@@ -1764,11 +1960,6 @@ AI Assistant is currently: ${currentlyHas ? chalk.green("enabled") : chalk.red("
1764
1960
  spinner.text = "Copying updated files...";
1765
1961
  const updatedTemplatesDir = path2.join(targetDir, "node_modules", "xertica-ui", "templates");
1766
1962
  if (filesToUpdate.includes("app")) {
1767
- await fs2.copy(
1768
- path2.join(updatedTemplatesDir, "src", "app", "components", "AppLayout.tsx"),
1769
- path2.join(targetDir, "src", "app", "components", "AppLayout.tsx"),
1770
- { overwrite: true }
1771
- );
1772
1963
  const persistedCodes = await readLanguagesConfig(targetDir);
1773
1964
  let selectedCodes = persistedCodes ?? [];
1774
1965
  if (selectedCodes.length === 0) {
@@ -1783,31 +1974,58 @@ AI Assistant is currently: ${currentlyHas ? chalk.green("enabled") : chalk.red("
1783
1974
  await writeLanguagesConfig(targetDir, selectedCodes);
1784
1975
  }
1785
1976
  const projectConfig = await readXerticaConfig(targetDir);
1786
- await fs2.writeFile(
1787
- path2.join(targetDir, "src", "app", "App.tsx"),
1788
- generateAppTsx(selectedCodes, projectConfig?.disableDarkMode ?? false)
1789
- );
1790
- await fs2.writeFile(path2.join(targetDir, "src", "i18n.ts"), generateI18nFile(selectedCodes));
1791
- await syncLocaleFiles(updatedTemplatesDir, targetDir, selectedCodes, {
1792
- pruneOthers: true
1793
- });
1794
- const pagesDir = path2.join(targetDir, "src", "pages");
1795
- const existingPages = await fs2.pathExists(pagesDir) ? await fs2.readdir(pagesDir) : [];
1796
- const hasLoginP = existingPages.includes("LoginPage.tsx");
1797
- const hasHomeP = existingPages.includes("HomePage.tsx");
1798
- const hasTemplateP = existingPages.includes("TemplatePage.tsx");
1799
- const hasAssistantP = projectConfig?.hasAssistant ?? existingPages.includes("AssistantPage.tsx");
1800
- const firstProtectedP = hasHomeP ? "/home" : hasTemplateP ? "/template" : "/login";
1801
- await fs2.writeFile(
1802
- path2.join(targetDir, "src", "app", "components", "AuthGuard.tsx"),
1803
- generateAuthGuard({
1804
- hasLogin: hasLoginP,
1805
- hasHome: hasHomeP,
1806
- hasTemplate: hasTemplateP,
1807
- hasAssistant: hasAssistantP,
1808
- firstProtectedPath: firstProtectedP
1809
- })
1810
- );
1977
+ if (isPageProject) {
1978
+ await fs2.writeFile(
1979
+ path2.join(targetDir, "src", "app", "App.tsx"),
1980
+ generateLandingAppTsx(selectedCodes, projectConfig?.disableDarkMode ?? false)
1981
+ );
1982
+ await fs2.writeFile(
1983
+ path2.join(targetDir, "src", "i18n.ts"),
1984
+ generateI18nFile(selectedCodes)
1985
+ );
1986
+ await syncLocaleFiles(updatedTemplatesDir, targetDir, selectedCodes, {
1987
+ pruneOthers: true
1988
+ });
1989
+ await fs2.copy(
1990
+ path2.join(updatedTemplatesDir, "src", "pages", "LandingPage.tsx"),
1991
+ path2.join(targetDir, "src", "pages", "LandingPage.tsx"),
1992
+ { overwrite: true }
1993
+ );
1994
+ } else {
1995
+ await fs2.copy(
1996
+ path2.join(updatedTemplatesDir, "src", "app", "components", "AppLayout.tsx"),
1997
+ path2.join(targetDir, "src", "app", "components", "AppLayout.tsx"),
1998
+ { overwrite: true }
1999
+ );
2000
+ await fs2.writeFile(
2001
+ path2.join(targetDir, "src", "app", "App.tsx"),
2002
+ generateAppTsx(selectedCodes, projectConfig?.disableDarkMode ?? false)
2003
+ );
2004
+ await fs2.writeFile(
2005
+ path2.join(targetDir, "src", "i18n.ts"),
2006
+ generateI18nFile(selectedCodes)
2007
+ );
2008
+ await syncLocaleFiles(updatedTemplatesDir, targetDir, selectedCodes, {
2009
+ pruneOthers: true
2010
+ });
2011
+ const pagesDir = path2.join(targetDir, "src", "pages");
2012
+ const existingPages = await fs2.pathExists(pagesDir) ? await fs2.readdir(pagesDir) : [];
2013
+ const hasLoginP = existingPages.includes("LoginPage.tsx");
2014
+ const hasHomeP = existingPages.includes("HomePage.tsx");
2015
+ const hasTemplateP = existingPages.includes("TemplatePage.tsx");
2016
+ const hasAssistantP = projectConfig?.hasAssistant ?? existingPages.includes("AssistantPage.tsx");
2017
+ const firstProtectedP = hasHomeP ? "/home" : hasTemplateP ? "/template" : "/login";
2018
+ await fs2.writeFile(
2019
+ path2.join(targetDir, "src", "app", "components", "AuthGuard.tsx"),
2020
+ generateAuthGuard({
2021
+ hasLogin: hasLoginP,
2022
+ hasHome: hasHomeP,
2023
+ hasTemplate: hasTemplateP,
2024
+ hasAssistant: hasAssistantP,
2025
+ firstProtectedPath: firstProtectedP
2026
+ })
2027
+ );
2028
+ }
1811
2029
  }
1812
2030
  if (filesToUpdate.includes("shared")) {
1813
2031
  await fs2.copy(
@@ -1,12 +1,28 @@
1
1
  import React from 'react';
2
- export interface AuthPageShellProps {
2
+ export type AuthPageShellProps = {
3
+ /** Hero photo on the left (default). Requires `imageSrc`/`imageAlt`. */
4
+ leftPanel?: 'image';
3
5
  imageSrc: string;
4
6
  imageAlt: string;
7
+ /**
8
+ * Background classes for the hero image overlay gradient. Defaults to the
9
+ * shared `--gradient-diagonal` theme token; pass a Tailwind gradient to
10
+ * override it for a specific auth page without affecting the others.
11
+ */
12
+ gradientClassName?: string;
5
13
  children: React.ReactNode;
6
- }
14
+ } | {
15
+ /**
16
+ * Brand isotype mark on a solid `bg-muted` panel — no photo, no
17
+ * gradient. Pairs with a lighter `bg-card` form panel on the right,
18
+ * the inverse of the `image` variant's `bg-muted` form panel.
19
+ */
20
+ leftPanel: 'isotype';
21
+ children: React.ReactNode;
22
+ };
7
23
  /**
8
24
  * Shared two-column shell used by every auth page (Login, ForgotPassword,
9
- * ResetPassword, VerifyEmail): hero image on the left, centered form panel
10
- * with a language selector on the right.
25
+ * ResetPassword, VerifyEmail): a left panel (hero image or brand isotype) and
26
+ * a centered form panel with a language selector on the right.
11
27
  */
12
- export declare function AuthPageShell({ imageSrc, imageAlt, children }: AuthPageShellProps): React.JSX.Element;
28
+ export declare function AuthPageShell(props: AuthPageShellProps): React.JSX.Element;
@@ -1,2 +1,3 @@
1
1
  export * from './card-patterns';
2
2
  export * from './auth';
3
+ export * from './marketing';
@@ -0,0 +1,28 @@
1
+ import * as React from 'react';
2
+ export interface CTASectionAction {
3
+ label: string;
4
+ href?: string;
5
+ onClick?: () => void;
6
+ }
7
+ export interface CTASectionProps extends React.HTMLAttributes<HTMLElement> {
8
+ title: string;
9
+ description?: string;
10
+ cta: CTASectionAction;
11
+ secondaryCta?: CTASectionAction;
12
+ }
13
+ /**
14
+ * Full-width dark band prompting a primary conversion action.
15
+ *
16
+ * @description
17
+ * A high-impact closing section for marketing pages: a bold left-aligned
18
+ * headline, optional supporting copy, and up to two CTA buttons on a flat
19
+ * `bg-sidebar` surface — the same token-driven dark surface used elsewhere
20
+ * on this page (e.g. the methodology section) — so it stays legible across
21
+ * all Xertica-ui themes without per-theme contrast tuning or a gradient.
22
+ *
23
+ * @ai-rules
24
+ * 1. The background is a flat `bg-sidebar` surface with a `border-sidebar-border` hairline — never reintroduce a gradient or hardcode colors here.
25
+ * 2. Both buttons use their natural variants (`default` for `cta`, `outline` for `secondaryCta`) with no color overrides — they already contrast correctly against `bg-sidebar`; do not force-style them with one-off colors.
26
+ * 3. Each `cta`/`secondaryCta` needs either `href` (renders an `<a>`) or `onClick`.
27
+ */
28
+ export declare function CTASection({ title, description, cta, secondaryCta, className, ...props }: CTASectionProps): React.JSX.Element;
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+ export interface ComplianceBadge {
3
+ icon: React.ReactNode;
4
+ label: string;
5
+ description?: string;
6
+ }
7
+ export interface ComplianceBadgeRowProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ badges: ComplianceBadge[];
9
+ }
10
+ /**
11
+ * A row of certification/compliance badges (e.g. SOC 2, GDPR, WCAG 2.1 AA).
12
+ *
13
+ * @description
14
+ * Renders a left-aligned grid where each badge pairs a token-radius outlined
15
+ * icon chip with a label and an optional short description, built entirely
16
+ * from theme tokens so it reskins across all Xertica-ui themes and dark mode.
17
+ *
18
+ * @ai-rules
19
+ * 1. Provide `badges` as `{ icon, label, description? }` — `icon` should be a small lucide-react element.
20
+ * 2. Keep `label` and `description` short — badges sit in a `grid-cols-2 sm:grid-cols-4` layout, so each column has limited width.
21
+ * 3. Do not hand-roll badge styling elsewhere — this component owns the icon-chip/label/description layout.
22
+ */
23
+ export declare function ComplianceBadgeRow({ badges, className, ...props }: ComplianceBadgeRowProps): React.JSX.Element;
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+ export type BlockColor = 'primary' | 'chart-1' | 'chart-2' | 'chart-3' | 'chart-4' | 'chart-5' | 'success' | 'info' | 'warning' | 'destructive';
3
+ export interface EvidenceTimelineItem {
4
+ number?: string | number;
5
+ icon?: React.ReactNode;
6
+ title: string;
7
+ description: string;
8
+ color?: BlockColor;
9
+ }
10
+ export interface EvidenceTimelineProps extends React.HTMLAttributes<HTMLDivElement> {
11
+ items: EvidenceTimelineItem[];
12
+ }
13
+ /**
14
+ * Vertical numbered timeline with a connecting line and colored step dots.
15
+ *
16
+ * @description
17
+ * Renders a "how our methodology works" style list: each item gets a
18
+ * colored dot (icon or step number) on a shared vertical line, with a
19
+ * title and description to its right.
20
+ *
21
+ * @ai-rules
22
+ * 1. Provide `icon` for a lucide-react icon in the dot, or `number` for a step label; if neither is set the 1-based index is used.
23
+ * 2. Each item's `color` maps to `colorTokens` — never hardcode colors.
24
+ * 3. This block has no outer card chrome; wrap it in a `<Card>` or section if chrome is needed.
25
+ */
26
+ export declare function EvidenceTimeline({ items, className, ...props }: EvidenceTimelineProps): React.JSX.Element;
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ export interface FeatureRowProps extends React.HTMLAttributes<HTMLElement> {
3
+ eyebrow?: string;
4
+ title: string;
5
+ description?: string;
6
+ bullets?: string[];
7
+ visual: React.ReactNode;
8
+ reverse?: boolean;
9
+ tone?: 'default' | 'muted' | 'card';
10
+ }
11
+ /**
12
+ * Alternating text + visual marketing section.
13
+ *
14
+ * @description
15
+ * A two-column "how it works" / definition row: a text block (eyebrow,
16
+ * title, description, optional checklist) paired with a consumer-supplied
17
+ * visual (image, illustration, or custom node). Stacks on mobile and
18
+ * alternates sides on desktop via `reverse`.
19
+ *
20
+ * @ai-rules
21
+ * 1. Chain multiple `FeatureRow`s and alternate `reverse` to build a "how it works" narrative.
22
+ * 2. Pass the visual as `<ImageWithFallback />` or any custom `ReactNode`; this component never renders an image itself.
23
+ * 3. Use `tone="muted"` on every other row to create a subtle section break instead of adding manual dividers; use `tone="card"` when a theme needs a stronger, genuinely lighter break (some themes set `--muted` equal to `--background`).
24
+ */
25
+ export declare function FeatureRow({ eyebrow, title, description, bullets, visual, reverse, tone, className, ...props }: FeatureRowProps): React.JSX.Element;
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+ export interface HeroCta {
3
+ label: string;
4
+ href?: string;
5
+ onClick?: () => void;
6
+ }
7
+ export interface HeroProps extends Omit<React.HTMLAttributes<HTMLElement>, 'title'> {
8
+ eyebrow?: {
9
+ label: string;
10
+ icon?: React.ReactNode;
11
+ };
12
+ title: React.ReactNode;
13
+ description?: React.ReactNode;
14
+ primaryCta?: HeroCta;
15
+ secondaryCta?: HeroCta;
16
+ visual?: React.ReactNode;
17
+ align?: 'left' | 'center';
18
+ decorative?: boolean;
19
+ }
20
+ /**
21
+ * Full-width, above-the-fold marketing hero section.
22
+ *
23
+ * @description
24
+ * The lead block for landing and marketing pages: an optional `PillBadge`
25
+ * eyebrow, a very large headline, supporting copy, and up to two `<Button>`
26
+ * CTAs. Automatically switches from a single column to a two-column layout
27
+ * once a `visual` (screenshot, illustration, collage) is supplied.
28
+ *
29
+ * @ai-rules
30
+ * 1. Pass `visual` for the two-column desktop layout; omit it for a single-column hero.
31
+ * 2. `primaryCta` renders as `default` (primary/brand) and `secondaryCta` as `secondary`, both via `<Button>` (`size="lg"`) — never hand-roll buttons.
32
+ * 3. Set `decorative` to add a token-based gradient blob backdrop; it is purely visual and never shifts layout.
33
+ * 4. `align="center"` centers the eyebrow/heading/copy/CTAs — pair it with omitting `visual` for a classic centered hero.
34
+ */
35
+ export declare function Hero({ eyebrow, title, description, primaryCta, secondaryCta, visual, align, decorative, className, ...props }: HeroProps): React.JSX.Element;
@@ -0,0 +1,29 @@
1
+ import * as React from 'react';
2
+ export type BlockColor = 'primary' | 'chart-1' | 'chart-2' | 'chart-3' | 'chart-4' | 'chart-5' | 'success' | 'info' | 'warning' | 'destructive';
3
+ export interface HowItWorksStepItem {
4
+ number?: string | number;
5
+ icon?: React.ReactNode;
6
+ title: string;
7
+ description: string;
8
+ color?: BlockColor;
9
+ }
10
+ export interface HowItWorksStepsProps {
11
+ items: HowItWorksStepItem[];
12
+ className?: string;
13
+ }
14
+ /**
15
+ * Horizontal numbered process row — the horizontal counterpart to `EvidenceTimeline`.
16
+ *
17
+ * @description
18
+ * Renders a "how it works" style row of steps: each item gets a colored
19
+ * badge (icon or step number) above a title and description, laid out
20
+ * side by side in a responsive grid instead of `EvidenceTimeline`'s
21
+ * vertical connecting line.
22
+ *
23
+ * @ai-rules
24
+ * 1. Provide `icon` for a lucide-react icon in the badge, or `number` for a step label; if neither is set the 1-based index is used.
25
+ * 2. Each item's `color` maps to `colorTokens` — never hardcode colors.
26
+ * 3. There is no connecting line between steps (unlike `EvidenceTimeline`) — this avoids awkward line fragments when steps wrap to a new row on narrow screens.
27
+ * 4. This block has no outer card chrome; wrap it in a `<Card>` or section if chrome is needed.
28
+ */
29
+ export declare function HowItWorksSteps({ items, className }: HowItWorksStepsProps): React.JSX.Element;