velvetkit 0.1.0.beta

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 (481) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +197 -0
  5. data/lib/generators/velvetkit/add/add_generator.rb +111 -0
  6. data/lib/generators/velvetkit/ai/ai_generator.rb +78 -0
  7. data/lib/generators/velvetkit/helpers.rb +64 -0
  8. data/lib/generators/velvetkit/install/install_generator.rb +108 -0
  9. data/lib/velvetkit/namespace.rb +57 -0
  10. data/lib/velvetkit/reference.rb +108 -0
  11. data/lib/velvetkit/registry.rb +162 -0
  12. data/lib/velvetkit/version.rb +5 -0
  13. data/lib/velvetkit.rb +28 -0
  14. data/registry/app/assets/tailwind/velvetkit.css +342 -0
  15. data/registry/app/components/ui/accordion/content.html.erb +5 -0
  16. data/registry/app/components/ui/accordion/content.rb +34 -0
  17. data/registry/app/components/ui/accordion/item.html.erb +1 -0
  18. data/registry/app/components/ui/accordion/item.rb +40 -0
  19. data/registry/app/components/ui/accordion/trigger.html.erb +1 -0
  20. data/registry/app/components/ui/accordion/trigger.rb +37 -0
  21. data/registry/app/components/ui/accordion.html.erb +7 -0
  22. data/registry/app/components/ui/accordion.rb +34 -0
  23. data/registry/app/components/ui/alert/description.html.erb +1 -0
  24. data/registry/app/components/ui/alert/description.rb +12 -0
  25. data/registry/app/components/ui/alert/title.html.erb +1 -0
  26. data/registry/app/components/ui/alert/title.rb +12 -0
  27. data/registry/app/components/ui/alert.html.erb +16 -0
  28. data/registry/app/components/ui/alert.rb +55 -0
  29. data/registry/app/components/ui/avatar/fallback.html.erb +1 -0
  30. data/registry/app/components/ui/avatar/fallback.rb +12 -0
  31. data/registry/app/components/ui/avatar/image.rb +20 -0
  32. data/registry/app/components/ui/avatar.html.erb +1 -0
  33. data/registry/app/components/ui/avatar.rb +56 -0
  34. data/registry/app/components/ui/avatar_group.html.erb +1 -0
  35. data/registry/app/components/ui/avatar_group.rb +35 -0
  36. data/registry/app/components/ui/badge.html.erb +1 -0
  37. data/registry/app/components/ui/badge.rb +38 -0
  38. data/registry/app/components/ui/banner.html.erb +10 -0
  39. data/registry/app/components/ui/banner.rb +47 -0
  40. data/registry/app/components/ui/base.rb +53 -0
  41. data/registry/app/components/ui/breadcrumb/auto_ellipsis.html.erb +23 -0
  42. data/registry/app/components/ui/breadcrumb/auto_ellipsis.rb +12 -0
  43. data/registry/app/components/ui/breadcrumb/ellipsis.html.erb +18 -0
  44. data/registry/app/components/ui/breadcrumb/ellipsis.rb +8 -0
  45. data/registry/app/components/ui/breadcrumb/item.html.erb +1 -0
  46. data/registry/app/components/ui/breadcrumb/item.rb +12 -0
  47. data/registry/app/components/ui/breadcrumb/item_slot.html.erb +10 -0
  48. data/registry/app/components/ui/breadcrumb/item_slot.rb +47 -0
  49. data/registry/app/components/ui/breadcrumb/list.html.erb +1 -0
  50. data/registry/app/components/ui/breadcrumb/list.rb +12 -0
  51. data/registry/app/components/ui/breadcrumb/separator.html.erb +1 -0
  52. data/registry/app/components/ui/breadcrumb/separator.rb +12 -0
  53. data/registry/app/components/ui/breadcrumb.html.erb +30 -0
  54. data/registry/app/components/ui/breadcrumb.rb +83 -0
  55. data/registry/app/components/ui/button.html.erb +1 -0
  56. data/registry/app/components/ui/button.rb +81 -0
  57. data/registry/app/components/ui/button_to.html.erb +1 -0
  58. data/registry/app/components/ui/button_to.rb +33 -0
  59. data/registry/app/components/ui/card/content.html.erb +1 -0
  60. data/registry/app/components/ui/card/content.rb +12 -0
  61. data/registry/app/components/ui/card/description.html.erb +1 -0
  62. data/registry/app/components/ui/card/description.rb +12 -0
  63. data/registry/app/components/ui/card/footer.html.erb +1 -0
  64. data/registry/app/components/ui/card/footer.rb +12 -0
  65. data/registry/app/components/ui/card/header.html.erb +1 -0
  66. data/registry/app/components/ui/card/header.rb +15 -0
  67. data/registry/app/components/ui/card/title.html.erb +1 -0
  68. data/registry/app/components/ui/card/title.rb +12 -0
  69. data/registry/app/components/ui/card.html.erb +1 -0
  70. data/registry/app/components/ui/card.rb +18 -0
  71. data/registry/app/components/ui/checkbox.html.erb +18 -0
  72. data/registry/app/components/ui/checkbox.rb +133 -0
  73. data/registry/app/components/ui/data_grid.html.erb +2 -0
  74. data/registry/app/components/ui/data_grid.rb +84 -0
  75. data/registry/app/components/ui/date_picker.html.erb +70 -0
  76. data/registry/app/components/ui/date_picker.rb +111 -0
  77. data/registry/app/components/ui/dialog/close.html.erb +7 -0
  78. data/registry/app/components/ui/dialog/close.rb +53 -0
  79. data/registry/app/components/ui/dialog/content.html.erb +26 -0
  80. data/registry/app/components/ui/dialog/content.rb +102 -0
  81. data/registry/app/components/ui/dialog/description.html.erb +1 -0
  82. data/registry/app/components/ui/dialog/description.rb +16 -0
  83. data/registry/app/components/ui/dialog/footer.html.erb +1 -0
  84. data/registry/app/components/ui/dialog/footer.rb +14 -0
  85. data/registry/app/components/ui/dialog/header.html.erb +1 -0
  86. data/registry/app/components/ui/dialog/header.rb +16 -0
  87. data/registry/app/components/ui/dialog/title.html.erb +1 -0
  88. data/registry/app/components/ui/dialog/title.rb +16 -0
  89. data/registry/app/components/ui/dialog/trigger.html.erb +5 -0
  90. data/registry/app/components/ui/dialog/trigger.rb +75 -0
  91. data/registry/app/components/ui/dialog.html.erb +3 -0
  92. data/registry/app/components/ui/dialog.rb +41 -0
  93. data/registry/app/components/ui/divider.html.erb +9 -0
  94. data/registry/app/components/ui/divider.rb +41 -0
  95. data/registry/app/components/ui/icon.html.erb +1 -0
  96. data/registry/app/components/ui/icon.rb +41 -0
  97. data/registry/app/components/ui/image.html.erb +1 -0
  98. data/registry/app/components/ui/image.rb +74 -0
  99. data/registry/app/components/ui/input.html.erb +9 -0
  100. data/registry/app/components/ui/input.rb +127 -0
  101. data/registry/app/components/ui/input_group/addon.html.erb +6 -0
  102. data/registry/app/components/ui/input_group/addon.rb +51 -0
  103. data/registry/app/components/ui/input_group/field.rb +26 -0
  104. data/registry/app/components/ui/input_group.html.erb +5 -0
  105. data/registry/app/components/ui/input_group.rb +55 -0
  106. data/registry/app/components/ui/label.html.erb +2 -0
  107. data/registry/app/components/ui/label.rb +48 -0
  108. data/registry/app/components/ui/link.html.erb +1 -0
  109. data/registry/app/components/ui/link.rb +64 -0
  110. data/registry/app/components/ui/menu/content.html.erb +5 -0
  111. data/registry/app/components/ui/menu/content.rb +106 -0
  112. data/registry/app/components/ui/menu/group.html.erb +1 -0
  113. data/registry/app/components/ui/menu/group.rb +19 -0
  114. data/registry/app/components/ui/menu/item.html.erb +1 -0
  115. data/registry/app/components/ui/menu/item.rb +68 -0
  116. data/registry/app/components/ui/menu/label.html.erb +1 -0
  117. data/registry/app/components/ui/menu/label.rb +33 -0
  118. data/registry/app/components/ui/menu/separator.html.erb +1 -0
  119. data/registry/app/components/ui/menu/separator.rb +20 -0
  120. data/registry/app/components/ui/menu/trigger.html.erb +1 -0
  121. data/registry/app/components/ui/menu/trigger.rb +29 -0
  122. data/registry/app/components/ui/menu.html.erb +3 -0
  123. data/registry/app/components/ui/menu.rb +23 -0
  124. data/registry/app/components/ui/native_select.html.erb +16 -0
  125. data/registry/app/components/ui/native_select.rb +109 -0
  126. data/registry/app/components/ui/pagination.html.erb +34 -0
  127. data/registry/app/components/ui/pagination.rb +62 -0
  128. data/registry/app/components/ui/password_input.html.erb +20 -0
  129. data/registry/app/components/ui/password_input.rb +94 -0
  130. data/registry/app/components/ui/popover/content.html.erb +12 -0
  131. data/registry/app/components/ui/popover/content.rb +83 -0
  132. data/registry/app/components/ui/popover/trigger.html.erb +1 -0
  133. data/registry/app/components/ui/popover/trigger.rb +29 -0
  134. data/registry/app/components/ui/popover.html.erb +3 -0
  135. data/registry/app/components/ui/popover.rb +24 -0
  136. data/registry/app/components/ui/radio_group/item.html.erb +18 -0
  137. data/registry/app/components/ui/radio_group/item.rb +97 -0
  138. data/registry/app/components/ui/radio_group.html.erb +1 -0
  139. data/registry/app/components/ui/radio_group.rb +35 -0
  140. data/registry/app/components/ui/select.html.erb +60 -0
  141. data/registry/app/components/ui/select.rb +181 -0
  142. data/registry/app/components/ui/sheet/close.rb +4 -0
  143. data/registry/app/components/ui/sheet/content.html.erb +24 -0
  144. data/registry/app/components/ui/sheet/content.rb +97 -0
  145. data/registry/app/components/ui/sheet/trigger.rb +4 -0
  146. data/registry/app/components/ui/sheet.html.erb +3 -0
  147. data/registry/app/components/ui/sheet.rb +37 -0
  148. data/registry/app/components/ui/sidebar/content.html.erb +1 -0
  149. data/registry/app/components/ui/sidebar/content.rb +18 -0
  150. data/registry/app/components/ui/sidebar/footer.html.erb +3 -0
  151. data/registry/app/components/ui/sidebar/footer.rb +16 -0
  152. data/registry/app/components/ui/sidebar/group.html.erb +1 -0
  153. data/registry/app/components/ui/sidebar/group.rb +19 -0
  154. data/registry/app/components/ui/sidebar/group_label.html.erb +1 -0
  155. data/registry/app/components/ui/sidebar/group_label.rb +18 -0
  156. data/registry/app/components/ui/sidebar/header.html.erb +1 -0
  157. data/registry/app/components/ui/sidebar/header.rb +16 -0
  158. data/registry/app/components/ui/sidebar/inset.html.erb +1 -0
  159. data/registry/app/components/ui/sidebar/inset.rb +17 -0
  160. data/registry/app/components/ui/sidebar/menu.html.erb +1 -0
  161. data/registry/app/components/ui/sidebar/menu.rb +18 -0
  162. data/registry/app/components/ui/sidebar/menu_button.html.erb +1 -0
  163. data/registry/app/components/ui/sidebar/menu_button.rb +30 -0
  164. data/registry/app/components/ui/sidebar/menu_item.html.erb +1 -0
  165. data/registry/app/components/ui/sidebar/menu_item.rb +23 -0
  166. data/registry/app/components/ui/sidebar/trigger.html.erb +1 -0
  167. data/registry/app/components/ui/sidebar/trigger.rb +24 -0
  168. data/registry/app/components/ui/sidebar/wrapper.html.erb +1 -0
  169. data/registry/app/components/ui/sidebar/wrapper.rb +40 -0
  170. data/registry/app/components/ui/sidebar.html.erb +11 -0
  171. data/registry/app/components/ui/sidebar.rb +29 -0
  172. data/registry/app/components/ui/spinner.html.erb +1 -0
  173. data/registry/app/components/ui/spinner.rb +20 -0
  174. data/registry/app/components/ui/switch.html.erb +12 -0
  175. data/registry/app/components/ui/switch.rb +109 -0
  176. data/registry/app/components/ui/table/cell.html.erb +1 -0
  177. data/registry/app/components/ui/table/cell.rb +16 -0
  178. data/registry/app/components/ui/table/column.html.erb +1 -0
  179. data/registry/app/components/ui/table/column.rb +18 -0
  180. data/registry/app/components/ui/table/head.html.erb +1 -0
  181. data/registry/app/components/ui/table/head.rb +13 -0
  182. data/registry/app/components/ui/table/row.html.erb +1 -0
  183. data/registry/app/components/ui/table/row.rb +26 -0
  184. data/registry/app/components/ui/table.html.erb +4 -0
  185. data/registry/app/components/ui/table.rb +45 -0
  186. data/registry/app/components/ui/tabs/content.html.erb +1 -0
  187. data/registry/app/components/ui/tabs/content.rb +43 -0
  188. data/registry/app/components/ui/tabs/list.html.erb +1 -0
  189. data/registry/app/components/ui/tabs/list.rb +28 -0
  190. data/registry/app/components/ui/tabs/trigger.html.erb +1 -0
  191. data/registry/app/components/ui/tabs/trigger.rb +91 -0
  192. data/registry/app/components/ui/tabs.html.erb +3 -0
  193. data/registry/app/components/ui/tabs.rb +27 -0
  194. data/registry/app/components/ui/text.html.erb +1 -0
  195. data/registry/app/components/ui/text.rb +48 -0
  196. data/registry/app/components/ui/theme_toggle.html.erb +9 -0
  197. data/registry/app/components/ui/theme_toggle.rb +63 -0
  198. data/registry/app/components/ui/tooltip/content.html.erb +1 -0
  199. data/registry/app/components/ui/tooltip/content.rb +65 -0
  200. data/registry/app/components/ui/tooltip/trigger.html.erb +1 -0
  201. data/registry/app/components/ui/tooltip/trigger.rb +33 -0
  202. data/registry/app/components/ui/tooltip.html.erb +3 -0
  203. data/registry/app/components/ui/tooltip.rb +24 -0
  204. data/registry/app/components/ui/typography/blockquote.html.erb +1 -0
  205. data/registry/app/components/ui/typography/blockquote.rb +15 -0
  206. data/registry/app/components/ui/typography/code.html.erb +1 -0
  207. data/registry/app/components/ui/typography/code.rb +25 -0
  208. data/registry/app/components/ui/typography/h1.rb +7 -0
  209. data/registry/app/components/ui/typography/h2.rb +7 -0
  210. data/registry/app/components/ui/typography/h3.rb +7 -0
  211. data/registry/app/components/ui/typography/h4.rb +7 -0
  212. data/registry/app/components/ui/typography/large.rb +7 -0
  213. data/registry/app/components/ui/typography/lead.rb +7 -0
  214. data/registry/app/components/ui/typography/muted.rb +7 -0
  215. data/registry/app/components/ui/typography/small.rb +7 -0
  216. data/registry/app/javascript/ag_grid.ts +26 -0
  217. data/registry/app/javascript/cally.ts +8 -0
  218. data/registry/app/javascript/controllers/ui/_internal/use_dismiss.ts +88 -0
  219. data/registry/app/javascript/controllers/ui/_internal/use_floating.ts +112 -0
  220. data/registry/app/javascript/controllers/ui/accordion_controller.ts +100 -0
  221. data/registry/app/javascript/controllers/ui/alert_controller.ts +7 -0
  222. data/registry/app/javascript/controllers/ui/banner_controller.ts +7 -0
  223. data/registry/app/javascript/controllers/ui/data_grid_controller.ts +198 -0
  224. data/registry/app/javascript/controllers/ui/date_picker_controller.ts +141 -0
  225. data/registry/app/javascript/controllers/ui/dialog_controller.ts +70 -0
  226. data/registry/app/javascript/controllers/ui/menu_controller.ts +201 -0
  227. data/registry/app/javascript/controllers/ui/password_visibility_controller.ts +43 -0
  228. data/registry/app/javascript/controllers/ui/popover_controller.ts +108 -0
  229. data/registry/app/javascript/controllers/ui/select_controller.ts +274 -0
  230. data/registry/app/javascript/controllers/ui/sidebar_controller.ts +64 -0
  231. data/registry/app/javascript/controllers/ui/tabs_controller.ts +74 -0
  232. data/registry/app/javascript/controllers/ui/theme_controller.ts +101 -0
  233. data/registry/app/javascript/controllers/ui/tooltip_controller.ts +102 -0
  234. data/registry/app/javascript/velvetkit_icons.ts +58 -0
  235. data/registry/app/views/layouts/_theme_script.html.erb +19 -0
  236. data/registry/components.yml +102 -0
  237. data/registry/config/locales/velvetkit.en.yml +56 -0
  238. data/registry/docs/agents.md +62 -0
  239. data/registry/test/components/previews/ui/accordion_preview/faq_style.html.erb +20 -0
  240. data/registry/test/components/previews/ui/accordion_preview/multiple.html.erb +27 -0
  241. data/registry/test/components/previews/ui/accordion_preview/single.html.erb +22 -0
  242. data/registry/test/components/previews/ui/accordion_preview.rb +31 -0
  243. data/registry/test/components/previews/ui/alert_preview/title_only.html.erb +12 -0
  244. data/registry/test/components/previews/ui/alert_preview/variants.html.erb +22 -0
  245. data/registry/test/components/previews/ui/alert_preview/with_icon.html.erb +12 -0
  246. data/registry/test/components/previews/ui/alert_preview/with_link.html.erb +18 -0
  247. data/registry/test/components/previews/ui/alert_preview.rb +34 -0
  248. data/registry/test/components/previews/ui/avatar_group_preview/default.html.erb +11 -0
  249. data/registry/test/components/previews/ui/avatar_group_preview/overflow.html.erb +23 -0
  250. data/registry/test/components/previews/ui/avatar_group_preview/small.html.erb +12 -0
  251. data/registry/test/components/previews/ui/avatar_group_preview.rb +23 -0
  252. data/registry/test/components/previews/ui/avatar_preview/colors.html.erb +8 -0
  253. data/registry/test/components/previews/ui/avatar_preview/shapes.html.erb +10 -0
  254. data/registry/test/components/previews/ui/avatar_preview/sizes.html.erb +8 -0
  255. data/registry/test/components/previews/ui/avatar_preview/with_image.html.erb +10 -0
  256. data/registry/test/components/previews/ui/avatar_preview.rb +24 -0
  257. data/registry/test/components/previews/ui/badge_preview/sizes.html.erb +5 -0
  258. data/registry/test/components/previews/ui/badge_preview/variants.html.erb +8 -0
  259. data/registry/test/components/previews/ui/badge_preview/with_icon.html.erb +14 -0
  260. data/registry/test/components/previews/ui/badge_preview.rb +20 -0
  261. data/registry/test/components/previews/ui/banner_preview/introduction.html.erb +9 -0
  262. data/registry/test/components/previews/ui/banner_preview/promotion.html.erb +9 -0
  263. data/registry/test/components/previews/ui/banner_preview/with_illustration.html.erb +12 -0
  264. data/registry/test/components/previews/ui/banner_preview.rb +25 -0
  265. data/registry/test/components/previews/ui/breadcrumb_preview/collapsed.html.erb +50 -0
  266. data/registry/test/components/previews/ui/breadcrumb_preview/default.html.erb +8 -0
  267. data/registry/test/components/previews/ui/breadcrumb_preview/long_path.html.erb +8 -0
  268. data/registry/test/components/previews/ui/breadcrumb_preview/medium.html.erb +7 -0
  269. data/registry/test/components/previews/ui/breadcrumb_preview/with_avatar.html.erb +8 -0
  270. data/registry/test/components/previews/ui/breadcrumb_preview.rb +66 -0
  271. data/registry/test/components/previews/ui/button_preview/disabled.html.erb +39 -0
  272. data/registry/test/components/previews/ui/button_preview/icon_only.html.erb +17 -0
  273. data/registry/test/components/previews/ui/button_preview/loading.html.erb +12 -0
  274. data/registry/test/components/previews/ui/button_preview/sizes.html.erb +6 -0
  275. data/registry/test/components/previews/ui/button_preview/variants.html.erb +8 -0
  276. data/registry/test/components/previews/ui/button_preview/with_both_icons.html.erb +12 -0
  277. data/registry/test/components/previews/ui/button_preview/with_leading_icon.html.erb +22 -0
  278. data/registry/test/components/previews/ui/button_preview/with_trailing_icon.html.erb +14 -0
  279. data/registry/test/components/previews/ui/button_preview.rb +65 -0
  280. data/registry/test/components/previews/ui/button_to_preview/states.html.erb +8 -0
  281. data/registry/test/components/previews/ui/button_to_preview/variants.html.erb +5 -0
  282. data/registry/test/components/previews/ui/button_to_preview/with_icon.html.erb +11 -0
  283. data/registry/test/components/previews/ui/button_to_preview.rb +21 -0
  284. data/registry/test/components/previews/ui/card_preview/complete.html.erb +31 -0
  285. data/registry/test/components/previews/ui/card_preview/default.html.erb +7 -0
  286. data/registry/test/components/previews/ui/card_preview/settings_form.html.erb +25 -0
  287. data/registry/test/components/previews/ui/card_preview/with_footer.html.erb +13 -0
  288. data/registry/test/components/previews/ui/card_preview/with_header.html.erb +11 -0
  289. data/registry/test/components/previews/ui/card_preview.rb +44 -0
  290. data/registry/test/components/previews/ui/checkbox_preview/in_form.html.erb +9 -0
  291. data/registry/test/components/previews/ui/checkbox_preview/states.html.erb +22 -0
  292. data/registry/test/components/previews/ui/checkbox_preview/with_label.html.erb +5 -0
  293. data/registry/test/components/previews/ui/checkbox_preview.rb +27 -0
  294. data/registry/test/components/previews/ui/data_grid_preview.rb +18 -0
  295. data/registry/test/components/previews/ui/date_picker_preview/default.html.erb +3 -0
  296. data/registry/test/components/previews/ui/date_picker_preview/states.html.erb +7 -0
  297. data/registry/test/components/previews/ui/date_picker_preview.rb +13 -0
  298. data/registry/test/components/previews/ui/dialog_preview/confirmation.html.erb +11 -0
  299. data/registry/test/components/previews/ui/dialog_preview/custom_trigger.html.erb +16 -0
  300. data/registry/test/components/previews/ui/dialog_preview/default.html.erb +15 -0
  301. data/registry/test/components/previews/ui/dialog_preview/long_content.html.erb +16 -0
  302. data/registry/test/components/previews/ui/dialog_preview/playground.html.erb +12 -0
  303. data/registry/test/components/previews/ui/dialog_preview/scrollable_body.html.erb +29 -0
  304. data/registry/test/components/previews/ui/dialog_preview/sizes.html.erb +46 -0
  305. data/registry/test/components/previews/ui/dialog_preview/without_close_button.html.erb +11 -0
  306. data/registry/test/components/previews/ui/dialog_preview/without_title.html.erb +13 -0
  307. data/registry/test/components/previews/ui/dialog_preview.rb +38 -0
  308. data/registry/test/components/previews/ui/divider_preview/horizontal.html.erb +5 -0
  309. data/registry/test/components/previews/ui/divider_preview/vertical.html.erb +9 -0
  310. data/registry/test/components/previews/ui/divider_preview/with_label.html.erb +5 -0
  311. data/registry/test/components/previews/ui/divider_preview.rb +19 -0
  312. data/registry/test/components/previews/ui/icon_preview/common.html.erb +8 -0
  313. data/registry/test/components/previews/ui/icon_preview/sizes.html.erb +7 -0
  314. data/registry/test/components/previews/ui/icon_preview.rb +20 -0
  315. data/registry/test/components/previews/ui/image_preview/radii.html.erb +8 -0
  316. data/registry/test/components/previews/ui/image_preview/sizing.html.erb +9 -0
  317. data/registry/test/components/previews/ui/image_preview.rb +16 -0
  318. data/registry/test/components/previews/ui/input_group_preview/addons.html.erb +29 -0
  319. data/registry/test/components/previews/ui/input_group_preview/playground.html.erb +12 -0
  320. data/registry/test/components/previews/ui/input_group_preview.rb +17 -0
  321. data/registry/test/components/previews/ui/input_preview/sizes.html.erb +5 -0
  322. data/registry/test/components/previews/ui/input_preview/states.html.erb +7 -0
  323. data/registry/test/components/previews/ui/input_preview/with_labels.html.erb +10 -0
  324. data/registry/test/components/previews/ui/input_preview.rb +33 -0
  325. data/registry/test/components/previews/ui/label_preview/sizes.html.erb +6 -0
  326. data/registry/test/components/previews/ui/label_preview/states.html.erb +6 -0
  327. data/registry/test/components/previews/ui/label_preview/weights.html.erb +5 -0
  328. data/registry/test/components/previews/ui/label_preview.rb +22 -0
  329. data/registry/test/components/previews/ui/link_preview/sizes.html.erb +5 -0
  330. data/registry/test/components/previews/ui/link_preview/variants.html.erb +8 -0
  331. data/registry/test/components/previews/ui/link_preview/with_icons.html.erb +11 -0
  332. data/registry/test/components/previews/ui/link_preview.rb +20 -0
  333. data/registry/test/components/previews/ui/menu_preview/positions.html.erb +122 -0
  334. data/registry/test/components/previews/ui/menu_preview/variants.html.erb +218 -0
  335. data/registry/test/components/previews/ui/menu_preview.rb +26 -0
  336. data/registry/test/components/previews/ui/native_select_preview/sizes.html.erb +6 -0
  337. data/registry/test/components/previews/ui/native_select_preview/states.html.erb +6 -0
  338. data/registry/test/components/previews/ui/native_select_preview.rb +23 -0
  339. data/registry/test/components/previews/ui/pagination_preview/states.html.erb +15 -0
  340. data/registry/test/components/previews/ui/pagination_preview.rb +15 -0
  341. data/registry/test/components/previews/ui/password_input_preview/states.html.erb +19 -0
  342. data/registry/test/components/previews/ui/password_input_preview.rb +21 -0
  343. data/registry/test/components/previews/ui/popover_preview/default.html.erb +7 -0
  344. data/registry/test/components/previews/ui/popover_preview/positions.html.erb +30 -0
  345. data/registry/test/components/previews/ui/popover_preview/with_close_button.html.erb +8 -0
  346. data/registry/test/components/previews/ui/popover_preview/with_rich_content.html.erb +17 -0
  347. data/registry/test/components/previews/ui/popover_preview/without_title.html.erb +9 -0
  348. data/registry/test/components/previews/ui/popover_preview.rb +32 -0
  349. data/registry/test/components/previews/ui/radio_group_preview/default.html.erb +10 -0
  350. data/registry/test/components/previews/ui/radio_group_preview/disabled.html.erb +17 -0
  351. data/registry/test/components/previews/ui/radio_group_preview/with_required.html.erb +10 -0
  352. data/registry/test/components/previews/ui/radio_group_preview.rb +25 -0
  353. data/registry/test/components/previews/ui/select_preview/default.html.erb +4 -0
  354. data/registry/test/components/previews/ui/select_preview/long_list.html.erb +5 -0
  355. data/registry/test/components/previews/ui/select_preview/multiple.html.erb +6 -0
  356. data/registry/test/components/previews/ui/select_preview/sizes.html.erb +5 -0
  357. data/registry/test/components/previews/ui/select_preview/states.html.erb +6 -0
  358. data/registry/test/components/previews/ui/select_preview.rb +45 -0
  359. data/registry/test/components/previews/ui/sheet_preview/bottom.html.erb +12 -0
  360. data/registry/test/components/previews/ui/sheet_preview/left.html.erb +10 -0
  361. data/registry/test/components/previews/ui/sheet_preview/playground.html.erb +15 -0
  362. data/registry/test/components/previews/ui/sheet_preview/right.html.erb +11 -0
  363. data/registry/test/components/previews/ui/sheet_preview/top.html.erb +8 -0
  364. data/registry/test/components/previews/ui/sheet_preview.rb +22 -0
  365. data/registry/test/components/previews/ui/sidebar_preview/_brand.html.erb +14 -0
  366. data/registry/test/components/previews/ui/sidebar_preview/_shell.html.erb +60 -0
  367. data/registry/test/components/previews/ui/sidebar_preview/collapsible.html.erb +55 -0
  368. data/registry/test/components/previews/ui/sidebar_preview/default.html.erb +17 -0
  369. data/registry/test/components/previews/ui/sidebar_preview/with_dropdown_header.html.erb +33 -0
  370. data/registry/test/components/previews/ui/sidebar_preview/with_groups.html.erb +22 -0
  371. data/registry/test/components/previews/ui/sidebar_preview.rb +15 -0
  372. data/registry/test/components/previews/ui/spinner_preview/in_buttons.html.erb +7 -0
  373. data/registry/test/components/previews/ui/spinner_preview/sizes.html.erb +7 -0
  374. data/registry/test/components/previews/ui/spinner_preview.rb +19 -0
  375. data/registry/test/components/previews/ui/switch_preview/default.html.erb +4 -0
  376. data/registry/test/components/previews/ui/switch_preview/sizes.html.erb +5 -0
  377. data/registry/test/components/previews/ui/switch_preview/states.html.erb +7 -0
  378. data/registry/test/components/previews/ui/switch_preview.rb +26 -0
  379. data/registry/test/components/previews/ui/table_preview/customers.html.erb +15 -0
  380. data/registry/test/components/previews/ui/table_preview/empty.html.erb +8 -0
  381. data/registry/test/components/previews/ui/table_preview/with_caption.html.erb +14 -0
  382. data/registry/test/components/previews/ui/table_preview.rb +12 -0
  383. data/registry/test/components/previews/ui/tabs_preview/default.html.erb +39 -0
  384. data/registry/test/components/previews/ui/tabs_preview/pill_variant.html.erb +18 -0
  385. data/registry/test/components/previews/ui/tabs_preview/settings_form.html.erb +42 -0
  386. data/registry/test/components/previews/ui/tabs_preview/with_icons.html.erb +34 -0
  387. data/registry/test/components/previews/ui/tabs_preview.rb +33 -0
  388. data/registry/test/components/previews/ui/text_preview/sizes.html.erb +10 -0
  389. data/registry/test/components/previews/ui/text_preview/tones.html.erb +5 -0
  390. data/registry/test/components/previews/ui/text_preview/weights.html.erb +6 -0
  391. data/registry/test/components/previews/ui/text_preview.rb +26 -0
  392. data/registry/test/components/previews/ui/theme_toggle_preview/in_a_header.html.erb +14 -0
  393. data/registry/test/components/previews/ui/theme_toggle_preview/palette.html.erb +47 -0
  394. data/registry/test/components/previews/ui/theme_toggle_preview.rb +15 -0
  395. data/registry/test/components/previews/ui/tooltip_preview/default.html.erb +8 -0
  396. data/registry/test/components/previews/ui/tooltip_preview/positions.html.erb +34 -0
  397. data/registry/test/components/previews/ui/tooltip_preview/with_button.html.erb +8 -0
  398. data/registry/test/components/previews/ui/tooltip_preview/with_icon.html.erb +10 -0
  399. data/registry/test/components/previews/ui/tooltip_preview.rb +29 -0
  400. data/registry/test/components/previews/ui/typography_preview/article.html.erb +11 -0
  401. data/registry/test/components/previews/ui/typography_preview/code_and_quotes.html.erb +6 -0
  402. data/registry/test/components/previews/ui/typography_preview/headings.html.erb +6 -0
  403. data/registry/test/components/previews/ui/typography_preview/text_styles.html.erb +7 -0
  404. data/registry/test/components/previews/ui/typography_preview.rb +23 -0
  405. data/registry/test/components/ui/accordion/content_test.rb +64 -0
  406. data/registry/test/components/ui/accordion/item_test.rb +61 -0
  407. data/registry/test/components/ui/accordion/trigger_test.rb +80 -0
  408. data/registry/test/components/ui/accordion_test.rb +96 -0
  409. data/registry/test/components/ui/alert/description_test.rb +37 -0
  410. data/registry/test/components/ui/alert/title_test.rb +38 -0
  411. data/registry/test/components/ui/alert_test.rb +184 -0
  412. data/registry/test/components/ui/avatar_group_test.rb +79 -0
  413. data/registry/test/components/ui/avatar_test.rb +129 -0
  414. data/registry/test/components/ui/badge_test.rb +112 -0
  415. data/registry/test/components/ui/banner_test.rb +116 -0
  416. data/registry/test/components/ui/base_test.rb +98 -0
  417. data/registry/test/components/ui/breadcrumb/ellipsis_test.rb +51 -0
  418. data/registry/test/components/ui/breadcrumb/item_test.rb +39 -0
  419. data/registry/test/components/ui/breadcrumb/list_test.rb +34 -0
  420. data/registry/test/components/ui/breadcrumb/separator_test.rb +36 -0
  421. data/registry/test/components/ui/breadcrumb_test.rb +276 -0
  422. data/registry/test/components/ui/button_test.rb +276 -0
  423. data/registry/test/components/ui/button_to_test.rb +74 -0
  424. data/registry/test/components/ui/card/content_test.rb +41 -0
  425. data/registry/test/components/ui/card/description_test.rb +32 -0
  426. data/registry/test/components/ui/card/footer_test.rb +34 -0
  427. data/registry/test/components/ui/card/header_test.rb +57 -0
  428. data/registry/test/components/ui/card/title_test.rb +34 -0
  429. data/registry/test/components/ui/card_test.rb +67 -0
  430. data/registry/test/components/ui/checkbox_test.rb +236 -0
  431. data/registry/test/components/ui/data_grid_test.rb +88 -0
  432. data/registry/test/components/ui/date_picker_test.rb +168 -0
  433. data/registry/test/components/ui/dialog/content_test.rb +156 -0
  434. data/registry/test/components/ui/dialog/trigger_test.rb +74 -0
  435. data/registry/test/components/ui/dialog_test.rb +54 -0
  436. data/registry/test/components/ui/divider_test.rb +69 -0
  437. data/registry/test/components/ui/icon_test.rb +82 -0
  438. data/registry/test/components/ui/image_test.rb +74 -0
  439. data/registry/test/components/ui/input_group_test.rb +143 -0
  440. data/registry/test/components/ui/input_test.rb +251 -0
  441. data/registry/test/components/ui/label_test.rb +96 -0
  442. data/registry/test/components/ui/link_test.rb +95 -0
  443. data/registry/test/components/ui/menu/content_test.rb +233 -0
  444. data/registry/test/components/ui/menu/group_test.rb +24 -0
  445. data/registry/test/components/ui/menu/item_test.rb +76 -0
  446. data/registry/test/components/ui/menu/label_test.rb +43 -0
  447. data/registry/test/components/ui/menu/separator_test.rb +32 -0
  448. data/registry/test/components/ui/menu/trigger_test.rb +109 -0
  449. data/registry/test/components/ui/menu_test.rb +152 -0
  450. data/registry/test/components/ui/native_select_test.rb +118 -0
  451. data/registry/test/components/ui/pagination_test.rb +92 -0
  452. data/registry/test/components/ui/password_input_test.rb +98 -0
  453. data/registry/test/components/ui/popover/content_test.rb +226 -0
  454. data/registry/test/components/ui/popover/trigger_test.rb +83 -0
  455. data/registry/test/components/ui/popover_test.rb +101 -0
  456. data/registry/test/components/ui/radio_group/item_test.rb +14 -0
  457. data/registry/test/components/ui/radio_group_test.rb +139 -0
  458. data/registry/test/components/ui/select_test.rb +181 -0
  459. data/registry/test/components/ui/sheet/content_test.rb +135 -0
  460. data/registry/test/components/ui/sheet/trigger_test.rb +23 -0
  461. data/registry/test/components/ui/sheet_test.rb +43 -0
  462. data/registry/test/components/ui/sidebar/menu_button_test.rb +43 -0
  463. data/registry/test/components/ui/sidebar/trigger_test.rb +17 -0
  464. data/registry/test/components/ui/sidebar/wrapper_test.rb +15 -0
  465. data/registry/test/components/ui/sidebar_test.rb +43 -0
  466. data/registry/test/components/ui/spinner_test.rb +63 -0
  467. data/registry/test/components/ui/switch_test.rb +206 -0
  468. data/registry/test/components/ui/table_test.rb +106 -0
  469. data/registry/test/components/ui/tabs/content_test.rb +93 -0
  470. data/registry/test/components/ui/tabs/list_test.rb +65 -0
  471. data/registry/test/components/ui/tabs/trigger_test.rb +159 -0
  472. data/registry/test/components/ui/tabs_test.rb +88 -0
  473. data/registry/test/components/ui/text_test.rb +84 -0
  474. data/registry/test/components/ui/theme_toggle_test.rb +88 -0
  475. data/registry/test/components/ui/tooltip/content_test.rb +135 -0
  476. data/registry/test/components/ui/tooltip/trigger_test.rb +52 -0
  477. data/registry/test/components/ui/tooltip_test.rb +97 -0
  478. data/registry/test/components/ui/typography/code_blockquote_test.rb +57 -0
  479. data/registry/test/components/ui/typography/heading_test.rb +71 -0
  480. data/registry/test/components/ui/typography/text_variants_test.rb +71 -0
  481. metadata +540 -0
@@ -0,0 +1,12 @@
1
+ <div class="flex flex-col gap-4 max-w-lg">
2
+ <%= render(UI::Alert.new) do |alert| %>
3
+ <% alert.with_title { "Title only, no description" } %>
4
+ <% end %>
5
+ <%= render(UI::Alert.new(variant: :info)) do |alert| %>
6
+ <% alert.with_title { "Info with custom icon" } %>
7
+ <% end %>
8
+ <%= render(UI::Alert.new(variant: :warning)) do |alert| %>
9
+ <% alert.with_icon(name: "circle-alert") %>
10
+ <% alert.with_title { "Warning with custom icon, title only" } %>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,22 @@
1
+ <div class="flex flex-col gap-4 max-w-lg">
2
+ <%= render(UI::Alert.new) do |alert| %>
3
+ <% alert.with_title { "Default" } %>
4
+ <% alert.with_description { "This is a default alert with important information." } %>
5
+ <% end %>
6
+ <%= render(UI::Alert.new(variant: :success)) do |alert| %>
7
+ <% alert.with_title { "Success" } %>
8
+ <% alert.with_description { "Your changes have been saved successfully." } %>
9
+ <% end %>
10
+ <%= render(UI::Alert.new(variant: :destructive)) do |alert| %>
11
+ <% alert.with_title { "Destructive" } %>
12
+ <% alert.with_description { "There was a problem with your request." } %>
13
+ <% end %>
14
+ <%= render(UI::Alert.new(variant: :warning)) do |alert| %>
15
+ <% alert.with_title { "Warning" } %>
16
+ <% alert.with_description { "This action cannot be undone." } %>
17
+ <% end %>
18
+ <%= render(UI::Alert.new(variant: :info)) do |alert| %>
19
+ <% alert.with_title { "Info" } %>
20
+ <% alert.with_description { "Here's some helpful information." } %>
21
+ <% end %>
22
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="flex flex-col gap-4 max-w-lg">
2
+ <%= render(UI::Alert.new) do |alert| %>
3
+ <% alert.with_icon(name: "badge-check") %>
4
+ <% alert.with_title { "Custom icon" } %>
5
+ <% alert.with_description { "Uses a custom badge-check icon instead of default." } %>
6
+ <% end %>
7
+ <%= render(UI::Alert.new(variant: :success)) do |alert| %>
8
+ <% alert.with_icon(name: "circle-check", class: "text-emerald-600") %>
9
+ <% alert.with_title { "Custom colored icon" } %>
10
+ <% alert.with_description { "Icon color overridden via class prop." } %>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,18 @@
1
+ <div class="flex flex-col gap-4 max-w-lg">
2
+ <%= render(UI::Alert.new(variant: :info)) do |alert| %>
3
+ <% alert.with_title { "Did you know?" } %>
4
+ <% alert.with_description { "Check out the <a class='underline font-medium' href='/docs'>documentation</a> for more details.".html_safe } %>
5
+ <% end %>
6
+ <%= render(UI::Alert.new(variant: :success)) do |alert| %>
7
+ <% alert.with_title { "Profile updated" } %>
8
+ <% alert.with_description { "Your changes were saved. <a class='underline font-medium' href='/settings'>View your profile</a> to confirm.".html_safe } %>
9
+ <% end %>
10
+ <%= render(UI::Alert.new(variant: :warning)) do |alert| %>
11
+ <% alert.with_title { "Action required" } %>
12
+ <% alert.with_description { "Please <a class='underline font-medium' href='/verify'>verify your email</a> before continuing.".html_safe } %>
13
+ <% end %>
14
+ <%= render(UI::Alert.new(variant: :destructive)) do |alert| %>
15
+ <% alert.with_title { "Payment failed" } %>
16
+ <% alert.with_description { "Your card was declined. <a class='underline font-medium' href='/billing'>Update payment method</a> to retry.".html_safe } %>
17
+ <% end %>
18
+ </div>
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UI::AlertPreview < ViewComponent::Preview
4
+ # @label Playground
5
+ # @param variant select { choices: [default, destructive, warning, success, info] }
6
+ # @param title text
7
+ # @param description text
8
+ def playground(variant: :default, title: "Heads up!", description: "This is a sample alert message.")
9
+ render(UI::Alert.new(variant: variant.to_sym)) do |alert|
10
+ alert.with_title { title }
11
+ alert.with_description { description }
12
+ end
13
+ end
14
+
15
+ # @label All Variants
16
+ def variants; render_with_template; end
17
+
18
+ # @label With Icon
19
+ def with_icon; render_with_template; end
20
+
21
+ # @label Title Only
22
+ def title_only; render_with_template; end
23
+
24
+ # @label With Link
25
+ def with_link; render_with_template; end
26
+
27
+ # @label Dismissible
28
+ def dismissible
29
+ render(UI::Alert.new(variant: :info, dismissible: true)) do |alert|
30
+ alert.with_title { "Update available" }
31
+ alert.with_description { "A new version of the application is ready to install." }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ <div class="space-y-8">
2
+ <div>
3
+ <p class="text-sm text-muted-foreground mb-3">4 avatars, overlapping with ring separation</p>
4
+ <%= render(UI::AvatarGroup.new) do |group| %>
5
+ <% group.with_avatar { "JD" } %>
6
+ <% group.with_avatar { "AS" } %>
7
+ <% group.with_avatar { "RM" } %>
8
+ <% group.with_avatar { "BK" } %>
9
+ <% end %>
10
+ </div>
11
+ </div>
@@ -0,0 +1,23 @@
1
+ <div class="space-y-8">
2
+ <div>
3
+ <p class="text-sm text-muted-foreground mb-3">max=3 with 6 total → shows 3 + "+3"</p>
4
+ <%= render(UI::AvatarGroup.new(max: 3)) do |group| %>
5
+ <% group.with_avatar { "JD" } %>
6
+ <% group.with_avatar { "AS" } %>
7
+ <% group.with_avatar { "RM" } %>
8
+ <% group.with_avatar { "BK" } %>
9
+ <% group.with_avatar { "CD" } %>
10
+ <% group.with_avatar { "PK" } %>
11
+ <% end %>
12
+ </div>
13
+ <div>
14
+ <p class="text-sm text-muted-foreground mb-3">max=2 with 5 total → shows 2 + "+3"</p>
15
+ <%= render(UI::AvatarGroup.new(max: 2, size: :sm)) do |group| %>
16
+ <% group.with_avatar { "JD" } %>
17
+ <% group.with_avatar { "AS" } %>
18
+ <% group.with_avatar { "RM" } %>
19
+ <% group.with_avatar { "BK" } %>
20
+ <% group.with_avatar { "CD" } %>
21
+ <% end %>
22
+ </div>
23
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="space-y-8">
2
+ <div>
3
+ <p class="text-sm text-muted-foreground mb-3">Small avatars stacked (size: :sm)</p>
4
+ <%= render(UI::AvatarGroup.new(size: :sm)) do |group| %>
5
+ <% group.with_avatar { "JD" } %>
6
+ <% group.with_avatar { "AS" } %>
7
+ <% group.with_avatar { "RM" } %>
8
+ <% group.with_avatar { "BK" } %>
9
+ <% group.with_avatar { "CD" } %>
10
+ <% end %>
11
+ </div>
12
+ </div>
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UI::AvatarGroupPreview < ViewComponent::Preview
4
+ # @label Playground
5
+ # @param count number { min: 1, max: 8 }
6
+ # @param size select { choices: [sm, default, lg, xl] }
7
+ def playground(count: 4, size: :default)
8
+ render(UI::AvatarGroup.new(size: size.to_sym)) do |group|
9
+ INITIALS[0...count.to_i.clamp(1, 8)].each { |init| group.with_avatar { init } }
10
+ end
11
+ end
12
+
13
+ INITIALS = %w[JD AS RM BK CD PK NP TW].freeze
14
+
15
+ # @label Default Stack
16
+ def default; render_with_template; end
17
+
18
+ # @label With Overflow
19
+ def overflow; render_with_template; end
20
+
21
+ # @label Small Stack
22
+ def small; render_with_template; end
23
+ end
@@ -0,0 +1,8 @@
1
+ <div class="flex flex-wrap items-center gap-6">
2
+ <% { default: "bg-muted", primary: "bg-primary", destructive: "bg-destructive", amber: "bg-amber-500", emerald: "bg-emerald-500", purple: "bg-purple-500", sky: "bg-sky-500" }.each do |color, label| %>
3
+ <div class="flex flex-col items-center gap-2">
4
+ <%= render(UI::Avatar.new(color: color)) { "JD" } %>
5
+ <span class="text-xs text-muted-foreground"><%= color %></span>
6
+ </div>
7
+ <% end %>
8
+ </div>
@@ -0,0 +1,10 @@
1
+ <div class="flex flex-wrap items-center gap-6">
2
+ <div class="flex flex-col items-center gap-2">
3
+ <%= render(UI::Avatar.new(shape: :circle)) { "JD" } %>
4
+ <span class="text-xs text-muted-foreground">Circle (People)</span>
5
+ </div>
6
+ <div class="flex flex-col items-center gap-2">
7
+ <%= render(UI::Avatar.new(shape: :rounded)) { "NS" } %>
8
+ <span class="text-xs text-muted-foreground">Rounded (Groups/Projects)</span>
9
+ </div>
10
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="flex flex-wrap items-center gap-6">
2
+ <% { sm: 24, default: 40, lg: 48, xl: 64 }.each do |size, px| %>
3
+ <div class="flex flex-col items-center gap-2">
4
+ <%= render(UI::Avatar.new(size: size)) { "JD" } %>
5
+ <span class="text-xs text-muted-foreground"><%= size %> (<%= px %>px)</span>
6
+ </div>
7
+ <% end %>
8
+ </div>
@@ -0,0 +1,10 @@
1
+ <div class="flex flex-wrap items-end gap-6">
2
+ <% { sm: 24, default: 40, lg: 48 }.each do |size, px| %>
3
+ <div class="flex flex-col items-center gap-2">
4
+ <%= render(UI::Avatar.new(size: size)) do |avatar| %>
5
+ <% avatar.with_image(src: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=96&h=96&fit=crop&crop=face", alt: "User") %>
6
+ <% end %>
7
+ <span class="text-xs text-muted-foreground"><%= size %> (<%= px %>px)</span>
8
+ </div>
9
+ <% end %>
10
+ </div>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UI::AvatarPreview < ViewComponent::Preview
4
+ # @label Playground
5
+ # @param size select { choices: [sm, default, lg, xl] }
6
+ # @param shape select { choices: [circle, rounded] }
7
+ # @param color select { choices: [default, primary, destructive, amber, emerald, purple, sky] }
8
+ # @param initials text
9
+ def playground(size: :default, shape: :circle, color: :default, initials: "JD")
10
+ render(UI::Avatar.new(size: size.to_sym, shape: shape.to_sym, color: color.to_sym)) { initials }
11
+ end
12
+
13
+ # @label Sizes
14
+ def sizes; render_with_template; end
15
+
16
+ # @label Shapes
17
+ def shapes; render_with_template; end
18
+
19
+ # @label Colors
20
+ def colors; render_with_template; end
21
+
22
+ # @label With Image
23
+ def with_image; render_with_template; end
24
+ end
@@ -0,0 +1,5 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Badge.new(size: :sm)) { "Small" } %>
3
+ <%= render(UI::Badge.new(size: :default)) { "Default" } %>
4
+ <%= render(UI::Badge.new(size: :lg)) { "Large" } %>
5
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Badge.new(variant: :default)) { "Default" } %>
3
+ <%= render(UI::Badge.new(variant: :secondary)) { "Secondary" } %>
4
+ <%= render(UI::Badge.new(variant: :destructive)) { "Destructive" } %>
5
+ <%= render(UI::Badge.new(variant: :outline)) { "Outline" } %>
6
+ <%= render(UI::Badge.new(variant: :success)) { "Success" } %>
7
+ <%= render(UI::Badge.new(variant: :warning)) { "Warning" } %>
8
+ </div>
@@ -0,0 +1,14 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Badge.new) do |badge| %>
3
+ <% badge.with_leading_icon(name: "badge-check") %>
4
+ Verified
5
+ <% end %>
6
+ <%= render(UI::Badge.new(variant: :success)) do |badge| %>
7
+ <% badge.with_leading_icon(name: "circle-check") %>
8
+ 42
9
+ <% end %>
10
+ <%= render(UI::Badge.new(variant: :warning)) do |badge| %>
11
+ <% badge.with_leading_icon(name: "circle-alert") %>
12
+ Pending
13
+ <% end %>
14
+ </div>
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UI::BadgePreview < ViewComponent::Preview
4
+ # @label Playground
5
+ # @param variant select { choices: [default, secondary, destructive, outline, success, warning] }
6
+ # @param size select { choices: [sm, default, lg] }
7
+ # @param text text
8
+ def playground(variant: :default, size: :default, text: "Badge")
9
+ render(UI::Badge.new(variant: variant.to_sym, size: size.to_sym)) { text }
10
+ end
11
+
12
+ # @label All Variants
13
+ def variants; render_with_template; end
14
+
15
+ # @label Sizes
16
+ def sizes; render_with_template; end
17
+
18
+ # @label With Icon
19
+ def with_icon; render_with_template; end
20
+ end
@@ -0,0 +1,9 @@
1
+ <div class="space-y-4 max-w-2xl">
2
+ <%= render(UI::Banner.new(variant: :introduction)) do |banner| %>
3
+ <% banner.with_title { "Welcome to your workspace" } %>
4
+ Invite your team, connect your data and publish your first report.
5
+ <% banner.with_action do %>
6
+ <a href="#" class="inline-flex items-center text-sm font-medium text-primary hover:underline">Get started →</a>
7
+ <% end %>
8
+ <% end %>
9
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="space-y-4 max-w-2xl">
2
+ <%= render(UI::Banner.new(variant: :promotion)) do |banner| %>
3
+ <% banner.with_title { "Now available: Advanced Analytics" } %>
4
+ Unlock powerful insights with our new analytics dashboard. Free for Pro plan users until June 30.
5
+ <% banner.with_action do %>
6
+ <a href="#" class="inline-flex items-center text-sm font-medium text-primary hover:underline">Upgrade now →</a>
7
+ <% end %>
8
+ <% end %>
9
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="space-y-4 max-w-2xl">
2
+ <%= render(UI::Banner.new(variant: :introduction)) do |banner| %>
3
+ <% banner.with_illustration do %>
4
+ <img src="https://placehold.co/64x64/7c3aed/white?text=VK" alt="" class="h-16 w-16 rounded-lg" />
5
+ <% end %>
6
+ <% banner.with_title { "Introducing Velvet Kit" } %>
7
+ A modern component library for Rails. Build beautiful interfaces faster with pre-built, accessible components.
8
+ <% banner.with_action do %>
9
+ <a href="#" class="inline-flex items-center text-sm font-medium text-primary hover:underline">View docs →</a>
10
+ <% end %>
11
+ <% end %>
12
+ </div>
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UI::BannerPreview < ViewComponent::Preview
4
+ # @label Playground
5
+ # @param variant select { choices: [introduction, promotion] }
6
+ # @param dismissible toggle
7
+ def playground(variant: :introduction, dismissible: true)
8
+ render(UI::Banner.new(variant: variant.to_sym, dismissible: dismissible)) do |banner|
9
+ banner.with_title { "Try our new pipeline editor" }
10
+ "Visualize and edit your CI/CD pipelines with an interactive drag-and-drop editor. No YAML required."
11
+ banner.with_action do
12
+ "<a href='#' class='inline-flex items-center text-sm font-medium text-primary hover:underline'>Learn more</a>".html_safe
13
+ end
14
+ end
15
+ end
16
+
17
+ # @label Introduction
18
+ def introduction; render_with_template; end
19
+
20
+ # @label Promotion
21
+ def promotion; render_with_template; end
22
+
23
+ # @label With Illustration
24
+ def with_illustration; render_with_template; end
25
+ end
@@ -0,0 +1,50 @@
1
+ <div class="flex flex-col gap-8 max-w-xl">
2
+ <div>
3
+ <h3 class="text-sm font-medium mb-2">Slot API — ellipsis at end</h3>
4
+ <%= render(UI::Breadcrumb.new(size: :sm)) do |bc| %>
5
+ <% bc.with_item(href: "#", text: "Projects") %>
6
+ <% bc.with_item(href: "#", text: "Website", avatar_src: "/icon.png") %>
7
+ <% bc.with_ellipsis do %>
8
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "Settings" } %>
9
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "Members" } %>
10
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "Billing" } %>
11
+ <% end %>
12
+ <% bc.with_item(href: "#", text: "Dashboard") %>
13
+ <% end %>
14
+ </div>
15
+ <div>
16
+ <h3 class="text-sm font-medium mb-2">Compound API — ellipsis in middle</h3>
17
+ <%= render(UI::Breadcrumb.new(size: :sm)) do %>
18
+ <%= render(UI::Breadcrumb::List.new) do %>
19
+ <%= render(UI::Breadcrumb::Item.new) do %>
20
+ <%= render(UI::Link.new(href: "#", class: "text-xs text-muted-foreground max-w-32 truncate font-normal justify-start rounded-sm")) { "Handbook" } %>
21
+ <% end %>
22
+ <%= render(UI::Breadcrumb::Separator.new) %>
23
+ <%= render(UI::Breadcrumb::Ellipsis.new) do %>
24
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "Docs" } %>
25
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "API" } %>
26
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "Platform" } %>
27
+ <% end %>
28
+ <%= render(UI::Breadcrumb::Separator.new) %>
29
+ <%= render(UI::Breadcrumb::Item.new) do %>
30
+ <%= render(UI::Link.new(href: "#", class: "text-xs text-foreground font-normal justify-start rounded-sm", aria: { current: "page" })) { "Cloud providers" } %>
31
+ <% end %>
32
+ <% end %>
33
+ <% end %>
34
+ </div>
35
+ <div>
36
+ <h3 class="text-sm font-medium mb-2">Compound API — ellipsis at start</h3>
37
+ <%= render(UI::Breadcrumb.new(size: :sm)) do %>
38
+ <%= render(UI::Breadcrumb::List.new) do %>
39
+ <%= render(UI::Breadcrumb::Ellipsis.new) do %>
40
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "Learn" } %>
41
+ <%= render(UI::Link.new(href: "#", class: "justify-start rounded-sm px-3 py-1.5 text-sm font-normal text-popover-foreground hover:bg-accent hover:text-accent-foreground hover:no-underline w-full")) { "Tutorials" } %>
42
+ <% end %>
43
+ <%= render(UI::Breadcrumb::Separator.new) %>
44
+ <%= render(UI::Breadcrumb::Item.new) do %>
45
+ <%= render(UI::Link.new(href: "#", class: "text-xs text-foreground font-normal justify-start rounded-sm", aria: { current: "page" })) { "Getting Started" } %>
46
+ <% end %>
47
+ <% end %>
48
+ <% end %>
49
+ </div>
50
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="max-w-2xl">
2
+ <%= render(UI::Breadcrumb.new(size: :sm)) do |bc| %>
3
+ <% bc.with_item(href: "#", text: "Workspace") %>
4
+ <% bc.with_item(href: "#", text: "Website") %>
5
+ <% bc.with_item(href: "#", text: "Issues") %>
6
+ <% bc.with_item(href: "#", text: "#1234") %>
7
+ <% end %>
8
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="max-w-80">
2
+ <%= render(UI::Breadcrumb.new(size: :sm)) do |bc| %>
3
+ <% bc.with_item(href: "#", text: "Workspace") %>
4
+ <% bc.with_item(href: "#", text: "Very Long Project Name That Should Truncate") %>
5
+ <% bc.with_item(href: "#", text: "Settings") %>
6
+ <% bc.with_item(href: "#", text: "General") %>
7
+ <% end %>
8
+ </div>
@@ -0,0 +1,7 @@
1
+ <div class="max-w-2xl">
2
+ <%= render(UI::Breadcrumb.new(size: :md)) do |bc| %>
3
+ <% bc.with_item(href: "#", text: "Workspace") %>
4
+ <% bc.with_item(href: "#", text: "Website") %>
5
+ <% bc.with_item(href: "#", text: "Issues") %>
6
+ <% end %>
7
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="max-w-2xl">
2
+ <%= render(UI::Breadcrumb.new(size: :sm)) do |bc| %>
3
+ <% bc.with_item(href: "#", text: "Website", avatar_src: "/icon.png") %>
4
+ <% bc.with_item(href: "#", text: "Projects", avatar_src: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT9Y9w-vhwNHxfSOZWSDFJ-9iPU8EPY0GR47A&s") %>
5
+ <% bc.with_item(href: "#", text: "Dashboard") %>
6
+ <% bc.with_item(href: "#", text: "Settings") %>
7
+ <% end %>
8
+ </div>
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UI::BreadcrumbPreview < ViewComponent::Preview
4
+ # @label Playground
5
+ # @param size select { choices: [sm, md] }
6
+ def playground(size: :sm)
7
+ render(UI::Breadcrumb.new(size: size.to_sym)) do |bc|
8
+ bc.with_item(href: "#", text: "Workspace")
9
+ bc.with_item(href: "#", text: "Website")
10
+ bc.with_item(href: "#", text: "Issues")
11
+ bc.with_item(href: "#", text: "#1234")
12
+ end
13
+ end
14
+
15
+ # @label Default (sm)
16
+ def default; render_with_template; end
17
+
18
+ # @label Medium (md)
19
+ def medium; render_with_template; end
20
+
21
+ # @label With Avatar
22
+ def with_avatar; render_with_template; end
23
+
24
+ # @label Long Path
25
+ def long_path; render_with_template; end
26
+
27
+ # @label Collapsed — middle (default)
28
+ # Auto-ellipsis with collapse_at: :middle. Keeps first and last segments.
29
+ def collapsed_middle
30
+ render(UI::Breadcrumb.new(max_items: 3, collapse_at: :middle)) do |bc|
31
+ bc.with_item(href: "#", text: "Handbook")
32
+ bc.with_item(href: "#", text: "Docs")
33
+ bc.with_item(href: "#", text: "API")
34
+ bc.with_item(href: "#", text: "Platform")
35
+ bc.with_item(href: "#", text: "Cloud providers")
36
+ end
37
+ end
38
+
39
+ # @label Collapsed — start
40
+ # Auto-ellipsis with collapse_at: :start. Keeps the last segments.
41
+ def collapsed_start
42
+ render(UI::Breadcrumb.new(max_items: 3, collapse_at: :start)) do |bc|
43
+ bc.with_item(href: "#", text: "Learn")
44
+ bc.with_item(href: "#", text: "Tutorials")
45
+ bc.with_item(href: "#", text: "Get Started")
46
+ bc.with_item(href: "#", text: "Components")
47
+ bc.with_item(href: "#", text: "Breadcrumb")
48
+ end
49
+ end
50
+
51
+ # @label Collapsed — end
52
+ # Auto-ellipsis with collapse_at: :end. Keeps the first segments.
53
+ def collapsed_end
54
+ render(UI::Breadcrumb.new(max_items: 3, collapse_at: :end)) do |bc|
55
+ bc.with_item(href: "#", text: "Home")
56
+ bc.with_item(href: "#", text: "Settings")
57
+ bc.with_item(href: "#", text: "Account")
58
+ bc.with_item(href: "#", text: "Billing")
59
+ bc.with_item(href: "#", text: "Invoices")
60
+ end
61
+ end
62
+
63
+ # @label Collapsed (legacy explicit ellipsis)
64
+ # Manual ellipsis slot (deprecated — use max_items + collapse_at instead)
65
+ def collapsed; render_with_template; end
66
+ end
@@ -0,0 +1,39 @@
1
+ <div class="flex flex-col gap-6">
2
+ <div>
3
+ <p class="text-xs text-muted-foreground mb-2">All variants — disabled</p>
4
+ <div class="flex flex-wrap items-center gap-3">
5
+ <%= render(UI::Button.new(variant: :default, disabled: true)) { "Default" } %>
6
+ <%= render(UI::Button.new(variant: :destructive, disabled: true)) { "Destructive" } %>
7
+ <%= render(UI::Button.new(variant: :outline, disabled: true)) { "Outline" } %>
8
+ <%= render(UI::Button.new(variant: :secondary, disabled: true)) { "Secondary" } %>
9
+ <%= render(UI::Button.new(variant: :ghost, disabled: true)) { "Ghost" } %>
10
+ <%= render(UI::Button.new(variant: :link, disabled: true)) { "Link" } %>
11
+ </div>
12
+ </div>
13
+
14
+ <div>
15
+ <p class="text-xs text-muted-foreground mb-2">Disabled with icons</p>
16
+ <div class="flex flex-wrap items-center gap-3">
17
+ <%= render(UI::Button.new(disabled: true)) do |btn|
18
+ btn.with_leading_icon(name: "lock")
19
+ "Locked"
20
+ end %>
21
+ <%= render(UI::Button.new(variant: :outline, disabled: true)) do |btn|
22
+ btn.with_trailing_icon(name: "arrow-right")
23
+ "Continue"
24
+ end %>
25
+ <%= render(UI::Button.new(variant: :destructive, size: :icon, disabled: true)) do |btn|
26
+ btn.with_leading_icon(name: "x")
27
+ end %>
28
+ </div>
29
+ </div>
30
+
31
+ <div>
32
+ <p class="text-xs text-muted-foreground mb-2">Loading auto-disables (cursor-not-allowed shows on hover)</p>
33
+ <div class="flex flex-wrap items-center gap-3">
34
+ <%= render(UI::Button.new(loading: true)) { "Saving" } %>
35
+ <%= render(UI::Button.new(variant: :destructive, loading: true)) { "Deleting" } %>
36
+ <%= render(UI::Button.new(variant: :outline, loading: true)) { "Loading" } %>
37
+ </div>
38
+ </div>
39
+ </div>
@@ -0,0 +1,17 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Button.new(variant: :default, size: :icon)) do |btn|
3
+ btn.with_leading_icon(name: "menu")
4
+ end %>
5
+ <%= render(UI::Button.new(variant: :outline, size: :icon)) do |btn|
6
+ btn.with_leading_icon(name: "user")
7
+ end %>
8
+ <%= render(UI::Button.new(variant: :secondary, size: :icon)) do |btn|
9
+ btn.with_leading_icon(name: "panel-left")
10
+ end %>
11
+ <%= render(UI::Button.new(variant: :ghost, size: :icon)) do |btn|
12
+ btn.with_leading_icon(name: "x")
13
+ end %>
14
+ <%= render(UI::Button.new(variant: :destructive, size: :icon)) do |btn|
15
+ btn.with_leading_icon(name: "x")
16
+ end %>
17
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Button.new(loading: true)) { "Saving" } %>
3
+ <%= render(UI::Button.new(variant: :outline, loading: true)) do |btn|
4
+ btn.with_leading_icon(name: "lock")
5
+ "Authenticating"
6
+ end %>
7
+ <%= render(UI::Button.new(variant: :destructive, loading: true)) do |btn|
8
+ btn.with_trailing_icon(name: "arrow-right")
9
+ "Deleting"
10
+ end %>
11
+ <%= render(UI::Button.new(variant: :default, size: :icon, loading: true)) %>
12
+ </div>
@@ -0,0 +1,6 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Button.new(size: :sm)) { "Small" } %>
3
+ <%= render(UI::Button.new(size: :default)) { "Default" } %>
4
+ <%= render(UI::Button.new(size: :lg)) { "Large" } %>
5
+ <%= render(UI::Button.new(size: :icon)) { "I" } %>
6
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Button.new(variant: :default)) { "Default" } %>
3
+ <%= render(UI::Button.new(variant: :destructive)) { "Destructive" } %>
4
+ <%= render(UI::Button.new(variant: :outline)) { "Outline" } %>
5
+ <%= render(UI::Button.new(variant: :secondary)) { "Secondary" } %>
6
+ <%= render(UI::Button.new(variant: :ghost)) { "Ghost" } %>
7
+ <%= render(UI::Button.new(variant: :link)) { "Link" } %>
8
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="flex flex-wrap items-center gap-3">
2
+ <%= render(UI::Button.new(variant: :default)) do |btn|
3
+ btn.with_leading_icon(name: "lock")
4
+ btn.with_trailing_icon(name: "arrow-right")
5
+ "Sign in"
6
+ end %>
7
+ <%= render(UI::Button.new(variant: :outline, size: :lg)) do |btn|
8
+ btn.with_leading_icon(name: "eye")
9
+ btn.with_trailing_icon(name: "chevrons-up-down")
10
+ "Preview options"
11
+ end %>
12
+ </div>