shadcn_view_component 0.3.3

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 (507) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +255 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +604 -0
  5. data/app/assets/stylesheets/shadcn-themes.css +1075 -0
  6. data/app/assets/stylesheets/shadcn.css +853 -0
  7. data/app/components/shadcn/accordion/component.rb +44 -0
  8. data/app/components/shadcn/accordion/content/component.rb +44 -0
  9. data/app/components/shadcn/accordion/item/component.rb +41 -0
  10. data/app/components/shadcn/accordion/preview.rb +16 -0
  11. data/app/components/shadcn/accordion/previews/default.html.erb +10 -0
  12. data/app/components/shadcn/accordion/previews/multiple.html.erb +13 -0
  13. data/app/components/shadcn/accordion/trigger/component.rb +52 -0
  14. data/app/components/shadcn/alert/component.rb +52 -0
  15. data/app/components/shadcn/alert/preview.rb +11 -0
  16. data/app/components/shadcn/alert/previews/default.html.erb +8 -0
  17. data/app/components/shadcn/alert.rb +17 -0
  18. data/app/components/shadcn/alert_dialog/action/component.rb +35 -0
  19. data/app/components/shadcn/alert_dialog/cancel/component.rb +16 -0
  20. data/app/components/shadcn/alert_dialog/component.rb +20 -0
  21. data/app/components/shadcn/alert_dialog/content/component.rb +55 -0
  22. data/app/components/shadcn/alert_dialog/header/component.rb +33 -0
  23. data/app/components/shadcn/alert_dialog/preview.rb +16 -0
  24. data/app/components/shadcn/alert_dialog/previews/default.html.erb +13 -0
  25. data/app/components/shadcn/alert_dialog/previews/small_with_media.html.erb +38 -0
  26. data/app/components/shadcn/alert_dialog.rb +32 -0
  27. data/app/components/shadcn/application_view_component.rb +225 -0
  28. data/app/components/shadcn/application_view_component_preview.rb +8 -0
  29. data/app/components/shadcn/aspect_ratio/component.rb +34 -0
  30. data/app/components/shadcn/aspect_ratio/preview.rb +16 -0
  31. data/app/components/shadcn/aspect_ratio/previews/default.html.erb +5 -0
  32. data/app/components/shadcn/aspect_ratio/previews/ratios.html.erb +12 -0
  33. data/app/components/shadcn/attachment/action/component.rb +19 -0
  34. data/app/components/shadcn/attachment/component.rb +76 -0
  35. data/app/components/shadcn/attachment/media/component.rb +56 -0
  36. data/app/components/shadcn/attachment/preview.rb +11 -0
  37. data/app/components/shadcn/attachment/previews/default.html.erb +80 -0
  38. data/app/components/shadcn/attachment/trigger/component.rb +31 -0
  39. data/app/components/shadcn/attachment.rb +42 -0
  40. data/app/components/shadcn/avatar/component.rb +43 -0
  41. data/app/components/shadcn/avatar/fallback/component.rb +23 -0
  42. data/app/components/shadcn/avatar/image/component.rb +20 -0
  43. data/app/components/shadcn/avatar/preview.rb +11 -0
  44. data/app/components/shadcn/avatar/previews/default.html.erb +13 -0
  45. data/app/components/shadcn/avatar.rb +32 -0
  46. data/app/components/shadcn/badge/component.rb +57 -0
  47. data/app/components/shadcn/badge/preview.rb +11 -0
  48. data/app/components/shadcn/badge/previews/default.html.erb +5 -0
  49. data/app/components/shadcn/breadcrumb/component.rb +15 -0
  50. data/app/components/shadcn/breadcrumb/ellipsis/component.rb +28 -0
  51. data/app/components/shadcn/breadcrumb/page/component.rb +25 -0
  52. data/app/components/shadcn/breadcrumb/preview.rb +16 -0
  53. data/app/components/shadcn/breadcrumb/previews/custom_separator.html.erb +17 -0
  54. data/app/components/shadcn/breadcrumb/previews/default.html.erb +15 -0
  55. data/app/components/shadcn/breadcrumb/separator/component.rb +31 -0
  56. data/app/components/shadcn/breadcrumb.rb +18 -0
  57. data/app/components/shadcn/bubble/component.rb +90 -0
  58. data/app/components/shadcn/bubble/preview.rb +16 -0
  59. data/app/components/shadcn/bubble/previews/alignment.html.erb +33 -0
  60. data/app/components/shadcn/bubble/previews/default.html.erb +22 -0
  61. data/app/components/shadcn/bubble/reactions/component.rb +54 -0
  62. data/app/components/shadcn/bubble.rb +24 -0
  63. data/app/components/shadcn/button/component.rb +85 -0
  64. data/app/components/shadcn/button/preview.rb +31 -0
  65. data/app/components/shadcn/button/previews/default.html.erb +8 -0
  66. data/app/components/shadcn/button/previews/sizes.html.erb +5 -0
  67. data/app/components/shadcn/button/previews/variants.html.erb +5 -0
  68. data/app/components/shadcn/button_group/component.rb +53 -0
  69. data/app/components/shadcn/button_group/preview.rb +15 -0
  70. data/app/components/shadcn/button_group/previews/default.html.erb +18 -0
  71. data/app/components/shadcn/button_group/previews/vertical.html.erb +5 -0
  72. data/app/components/shadcn/button_group/separator/component.rb +30 -0
  73. data/app/components/shadcn/button_group/text/component.rb +20 -0
  74. data/app/components/shadcn/calendar/component.rb +558 -0
  75. data/app/components/shadcn/calendar/month.rb +74 -0
  76. data/app/components/shadcn/calendar/preview.rb +64 -0
  77. data/app/components/shadcn/calendar/previews/booked.html.erb +18 -0
  78. data/app/components/shadcn/calendar/previews/custom_cell_size.html.erb +11 -0
  79. data/app/components/shadcn/calendar/previews/date_and_time.html.erb +31 -0
  80. data/app/components/shadcn/calendar/previews/default.html.erb +8 -0
  81. data/app/components/shadcn/calendar/previews/dropdown_caption.html.erb +11 -0
  82. data/app/components/shadcn/calendar/previews/in_a_form.html.erb +8 -0
  83. data/app/components/shadcn/calendar/previews/presets.html.erb +20 -0
  84. data/app/components/shadcn/calendar/previews/range.html.erb +10 -0
  85. data/app/components/shadcn/calendar/previews/week_numbers.html.erb +8 -0
  86. data/app/components/shadcn/card/component.rb +24 -0
  87. data/app/components/shadcn/card/header/component.rb +26 -0
  88. data/app/components/shadcn/card/preview.rb +16 -0
  89. data/app/components/shadcn/card/previews/default.html.erb +18 -0
  90. data/app/components/shadcn/card/previews/image.html.erb +37 -0
  91. data/app/components/shadcn/card.rb +21 -0
  92. data/app/components/shadcn/carousel/component.rb +61 -0
  93. data/app/components/shadcn/carousel/content/component.rb +86 -0
  94. data/app/components/shadcn/carousel/item/component.rb +42 -0
  95. data/app/components/shadcn/carousel/next/component.rb +59 -0
  96. data/app/components/shadcn/carousel/preview.rb +22 -0
  97. data/app/components/shadcn/carousel/previews/default.html.erb +22 -0
  98. data/app/components/shadcn/carousel/previews/sizes.html.erb +42 -0
  99. data/app/components/shadcn/carousel/previews/vertical.html.erb +27 -0
  100. data/app/components/shadcn/carousel/previous/component.rb +59 -0
  101. data/app/components/shadcn/chart/area/component.rb +43 -0
  102. data/app/components/shadcn/chart/bar/component.rb +75 -0
  103. data/app/components/shadcn/chart/cartesian/component.rb +152 -0
  104. data/app/components/shadcn/chart/component.rb +124 -0
  105. data/app/components/shadcn/chart/focusable.rb +38 -0
  106. data/app/components/shadcn/chart/legend/component.rb +55 -0
  107. data/app/components/shadcn/chart/line/component.rb +50 -0
  108. data/app/components/shadcn/chart/pie/component.rb +169 -0
  109. data/app/components/shadcn/chart/plot.rb +147 -0
  110. data/app/components/shadcn/chart/preview.rb +45 -0
  111. data/app/components/shadcn/chart/previews/area.html.erb +31 -0
  112. data/app/components/shadcn/chart/previews/bar.html.erb +32 -0
  113. data/app/components/shadcn/chart/previews/bar_stacked.html.erb +30 -0
  114. data/app/components/shadcn/chart/previews/default.html.erb +30 -0
  115. data/app/components/shadcn/chart/previews/donut.html.erb +16 -0
  116. data/app/components/shadcn/chart/previews/line.html.erb +30 -0
  117. data/app/components/shadcn/chart/previews/percentages.html.erb +17 -0
  118. data/app/components/shadcn/chart/table/component.rb +75 -0
  119. data/app/components/shadcn/chart/tooltip/component.rb +111 -0
  120. data/app/components/shadcn/checkbox/component.rb +109 -0
  121. data/app/components/shadcn/checkbox/preview.rb +16 -0
  122. data/app/components/shadcn/checkbox/previews/default.html.erb +14 -0
  123. data/app/components/shadcn/checkbox/previews/states.html.erb +23 -0
  124. data/app/components/shadcn/collapsible/component.rb +35 -0
  125. data/app/components/shadcn/collapsible/content/component.rb +20 -0
  126. data/app/components/shadcn/collapsible/preview.rb +11 -0
  127. data/app/components/shadcn/collapsible/previews/default.html.erb +9 -0
  128. data/app/components/shadcn/collapsible/trigger/component.rb +23 -0
  129. data/app/components/shadcn/combobox/chip/component.rb +60 -0
  130. data/app/components/shadcn/combobox/chip_input/component.rb +43 -0
  131. data/app/components/shadcn/combobox/chips/component.rb +54 -0
  132. data/app/components/shadcn/combobox/clear/component.rb +32 -0
  133. data/app/components/shadcn/combobox/component.rb +113 -0
  134. data/app/components/shadcn/combobox/content/component.rb +59 -0
  135. data/app/components/shadcn/combobox/empty/component.rb +23 -0
  136. data/app/components/shadcn/combobox/input/component.rb +85 -0
  137. data/app/components/shadcn/combobox/item/component.rb +69 -0
  138. data/app/components/shadcn/combobox/list/component.rb +27 -0
  139. data/app/components/shadcn/combobox/preview.rb +31 -0
  140. data/app/components/shadcn/combobox/previews/default.html.erb +20 -0
  141. data/app/components/shadcn/combobox/previews/grouped.html.erb +25 -0
  142. data/app/components/shadcn/combobox/previews/multiple.html.erb +28 -0
  143. data/app/components/shadcn/combobox/previews/with_clear.html.erb +16 -0
  144. data/app/components/shadcn/combobox/trigger/component.rb +54 -0
  145. data/app/components/shadcn/combobox.rb +16 -0
  146. data/app/components/shadcn/command/component.rb +67 -0
  147. data/app/components/shadcn/command/dialog/component.rb +72 -0
  148. data/app/components/shadcn/command/empty/component.rb +29 -0
  149. data/app/components/shadcn/command/group/component.rb +63 -0
  150. data/app/components/shadcn/command/input/component.rb +66 -0
  151. data/app/components/shadcn/command/item/component.rb +62 -0
  152. data/app/components/shadcn/command/list/component.rb +36 -0
  153. data/app/components/shadcn/command/preview.rb +26 -0
  154. data/app/components/shadcn/command/previews/default.html.erb +41 -0
  155. data/app/components/shadcn/command/previews/dialog.html.erb +33 -0
  156. data/app/components/shadcn/command/previews/ranking.html.erb +16 -0
  157. data/app/components/shadcn/command/separator/component.rb +33 -0
  158. data/app/components/shadcn/command.rb +14 -0
  159. data/app/components/shadcn/concerns/modal_root.rb +43 -0
  160. data/app/components/shadcn/concerns/submits_value.rb +81 -0
  161. data/app/components/shadcn/context_menu/component.rb +45 -0
  162. data/app/components/shadcn/context_menu/content/component.rb +40 -0
  163. data/app/components/shadcn/context_menu/preview.rb +16 -0
  164. data/app/components/shadcn/context_menu/previews/default.html.erb +34 -0
  165. data/app/components/shadcn/context_menu/previews/items.html.erb +35 -0
  166. data/app/components/shadcn/context_menu/sub/component.rb +47 -0
  167. data/app/components/shadcn/context_menu/sub_content/component.rb +31 -0
  168. data/app/components/shadcn/context_menu/trigger/component.rb +50 -0
  169. data/app/components/shadcn/context_menu.rb +43 -0
  170. data/app/components/shadcn/dialog/close/component.rb +20 -0
  171. data/app/components/shadcn/dialog/component.rb +20 -0
  172. data/app/components/shadcn/dialog/content/component.rb +78 -0
  173. data/app/components/shadcn/dialog/header/component.rb +23 -0
  174. data/app/components/shadcn/dialog/overlay/component.rb +28 -0
  175. data/app/components/shadcn/dialog/preview.rb +28 -0
  176. data/app/components/shadcn/dialog/previews/default.html.erb +17 -0
  177. data/app/components/shadcn/dialog/previews/inside_stacking_context.html.erb +25 -0
  178. data/app/components/shadcn/dialog/previews/no_close_button.html.erb +15 -0
  179. data/app/components/shadcn/dialog/previews/scrollable_content.html.erb +29 -0
  180. data/app/components/shadcn/dialog/trigger/component.rb +24 -0
  181. data/app/components/shadcn/dialog.rb +17 -0
  182. data/app/components/shadcn/drawer/component.rb +33 -0
  183. data/app/components/shadcn/drawer/content/component.rb +95 -0
  184. data/app/components/shadcn/drawer/header/component.rb +34 -0
  185. data/app/components/shadcn/drawer/preview.rb +29 -0
  186. data/app/components/shadcn/drawer/previews/default.html.erb +21 -0
  187. data/app/components/shadcn/drawer/previews/scrollable.html.erb +20 -0
  188. data/app/components/shadcn/drawer/previews/scrollable_side.html.erb +21 -0
  189. data/app/components/shadcn/drawer/previews/sides.html.erb +17 -0
  190. data/app/components/shadcn/drawer.rb +27 -0
  191. data/app/components/shadcn/dropdown_menu/checkbox_item/component.rb +61 -0
  192. data/app/components/shadcn/dropdown_menu/component.rb +48 -0
  193. data/app/components/shadcn/dropdown_menu/content/component.rb +49 -0
  194. data/app/components/shadcn/dropdown_menu/group/component.rb +16 -0
  195. data/app/components/shadcn/dropdown_menu/item/component.rb +50 -0
  196. data/app/components/shadcn/dropdown_menu/preview.rb +16 -0
  197. data/app/components/shadcn/dropdown_menu/previews/checkboxes_and_radio.html.erb +34 -0
  198. data/app/components/shadcn/dropdown_menu/previews/default.html.erb +23 -0
  199. data/app/components/shadcn/dropdown_menu/radio_group/component.rb +16 -0
  200. data/app/components/shadcn/dropdown_menu/radio_item/component.rb +63 -0
  201. data/app/components/shadcn/dropdown_menu/sub/component.rb +44 -0
  202. data/app/components/shadcn/dropdown_menu/sub_content/component.rb +45 -0
  203. data/app/components/shadcn/dropdown_menu/sub_trigger/component.rb +58 -0
  204. data/app/components/shadcn/dropdown_menu/trigger/component.rb +25 -0
  205. data/app/components/shadcn/dropdown_menu.rb +18 -0
  206. data/app/components/shadcn/empty/component.rb +17 -0
  207. data/app/components/shadcn/empty/media/component.rb +48 -0
  208. data/app/components/shadcn/empty/preview.rb +16 -0
  209. data/app/components/shadcn/empty/previews/default.html.erb +15 -0
  210. data/app/components/shadcn/empty/previews/media.html.erb +32 -0
  211. data/app/components/shadcn/empty.rb +26 -0
  212. data/app/components/shadcn/field/component.rb +61 -0
  213. data/app/components/shadcn/field/error/component.rb +49 -0
  214. data/app/components/shadcn/field/legend/component.rb +30 -0
  215. data/app/components/shadcn/field/preview.rb +17 -0
  216. data/app/components/shadcn/field/previews/default.html.erb +29 -0
  217. data/app/components/shadcn/field/previews/form_builder.html.erb +38 -0
  218. data/app/components/shadcn/field/separator/component.rb +35 -0
  219. data/app/components/shadcn/field.rb +44 -0
  220. data/app/components/shadcn/hover_card/component.rb +51 -0
  221. data/app/components/shadcn/hover_card/content/component.rb +45 -0
  222. data/app/components/shadcn/hover_card/preview.rb +16 -0
  223. data/app/components/shadcn/hover_card/previews/default.html.erb +36 -0
  224. data/app/components/shadcn/hover_card/previews/sides.html.erb +15 -0
  225. data/app/components/shadcn/hover_card/trigger/component.rb +33 -0
  226. data/app/components/shadcn/icon/component.rb +76 -0
  227. data/app/components/shadcn/icon.rb +43 -0
  228. data/app/components/shadcn/input/component.rb +26 -0
  229. data/app/components/shadcn/input/preview.rb +16 -0
  230. data/app/components/shadcn/input/previews/default.html.erb +5 -0
  231. data/app/components/shadcn/input/previews/states.html.erb +20 -0
  232. data/app/components/shadcn/input_group/addon/component.rb +65 -0
  233. data/app/components/shadcn/input_group/button/component.rb +40 -0
  234. data/app/components/shadcn/input_group/component.rb +43 -0
  235. data/app/components/shadcn/input_group/input/component.rb +25 -0
  236. data/app/components/shadcn/input_group/preview.rb +17 -0
  237. data/app/components/shadcn/input_group/previews/addons.html.erb +53 -0
  238. data/app/components/shadcn/input_group/previews/default.html.erb +25 -0
  239. data/app/components/shadcn/input_group/text/component.rb +20 -0
  240. data/app/components/shadcn/input_group/textarea/component.rb +21 -0
  241. data/app/components/shadcn/input_otp/component.rb +95 -0
  242. data/app/components/shadcn/input_otp/preview.rb +17 -0
  243. data/app/components/shadcn/input_otp/previews/default.html.erb +19 -0
  244. data/app/components/shadcn/input_otp/previews/variations.html.erb +33 -0
  245. data/app/components/shadcn/input_otp/separator/component.rb +21 -0
  246. data/app/components/shadcn/input_otp/slot/component.rb +60 -0
  247. data/app/components/shadcn/input_otp.rb +11 -0
  248. data/app/components/shadcn/item/component.rb +56 -0
  249. data/app/components/shadcn/item/group/component.rb +53 -0
  250. data/app/components/shadcn/item/media/component.rb +53 -0
  251. data/app/components/shadcn/item/preview.rb +20 -0
  252. data/app/components/shadcn/item/previews/default.html.erb +32 -0
  253. data/app/components/shadcn/item/previews/link.html.erb +39 -0
  254. data/app/components/shadcn/item/previews/outline.html.erb +8 -0
  255. data/app/components/shadcn/item/separator/component.rb +24 -0
  256. data/app/components/shadcn/item.rb +34 -0
  257. data/app/components/shadcn/kbd/component.rb +23 -0
  258. data/app/components/shadcn/kbd/group/component.rb +17 -0
  259. data/app/components/shadcn/kbd/preview.rb +11 -0
  260. data/app/components/shadcn/kbd/previews/default.html.erb +4 -0
  261. data/app/components/shadcn/label/component.rb +20 -0
  262. data/app/components/shadcn/label/preview.rb +11 -0
  263. data/app/components/shadcn/label/previews/default.html.erb +4 -0
  264. data/app/components/shadcn/marker/component.rb +46 -0
  265. data/app/components/shadcn/marker/icon/component.rb +23 -0
  266. data/app/components/shadcn/marker/preview.rb +17 -0
  267. data/app/components/shadcn/marker/previews/default.html.erb +18 -0
  268. data/app/components/shadcn/marker/previews/status.html.erb +32 -0
  269. data/app/components/shadcn/marker.rb +17 -0
  270. data/app/components/shadcn/menubar/component.rb +36 -0
  271. data/app/components/shadcn/menubar/content/component.rb +49 -0
  272. data/app/components/shadcn/menubar/menu/component.rb +39 -0
  273. data/app/components/shadcn/menubar/preview.rb +16 -0
  274. data/app/components/shadcn/menubar/previews/default.html.erb +52 -0
  275. data/app/components/shadcn/menubar/previews/items.html.erb +38 -0
  276. data/app/components/shadcn/menubar/sub/component.rb +43 -0
  277. data/app/components/shadcn/menubar/sub_content/component.rb +31 -0
  278. data/app/components/shadcn/menubar/sub_trigger/component.rb +31 -0
  279. data/app/components/shadcn/menubar/trigger/component.rb +41 -0
  280. data/app/components/shadcn/menubar.rb +47 -0
  281. data/app/components/shadcn/message/component.rb +33 -0
  282. data/app/components/shadcn/message/preview.rb +16 -0
  283. data/app/components/shadcn/message/previews/actions.html.erb +51 -0
  284. data/app/components/shadcn/message/previews/default.html.erb +35 -0
  285. data/app/components/shadcn/message.rb +35 -0
  286. data/app/components/shadcn/message_scroller/button/component.rb +78 -0
  287. data/app/components/shadcn/message_scroller/component.rb +59 -0
  288. data/app/components/shadcn/message_scroller/content/component.rb +50 -0
  289. data/app/components/shadcn/message_scroller/item/component.rb +45 -0
  290. data/app/components/shadcn/message_scroller/preview.rb +11 -0
  291. data/app/components/shadcn/message_scroller/previews/default.html.erb +72 -0
  292. data/app/components/shadcn/message_scroller/viewport/component.rb +41 -0
  293. data/app/components/shadcn/mode_switcher/component.rb +67 -0
  294. data/app/components/shadcn/mode_switcher/preview.rb +11 -0
  295. data/app/components/shadcn/mode_switcher/previews/default.html.erb +5 -0
  296. data/app/components/shadcn/mode_toggle/component.rb +75 -0
  297. data/app/components/shadcn/mode_toggle/preview.rb +11 -0
  298. data/app/components/shadcn/mode_toggle/previews/default.html.erb +20 -0
  299. data/app/components/shadcn/native_select/component.rb +59 -0
  300. data/app/components/shadcn/native_select/preview.rb +16 -0
  301. data/app/components/shadcn/native_select/previews/default.html.erb +9 -0
  302. data/app/components/shadcn/native_select/previews/groups.html.erb +26 -0
  303. data/app/components/shadcn/native_select.rb +16 -0
  304. data/app/components/shadcn/navigation_menu/component.rb +51 -0
  305. data/app/components/shadcn/navigation_menu/content/component.rb +58 -0
  306. data/app/components/shadcn/navigation_menu/preview.rb +11 -0
  307. data/app/components/shadcn/navigation_menu/previews/default.html.erb +49 -0
  308. data/app/components/shadcn/navigation_menu/trigger/component.rb +59 -0
  309. data/app/components/shadcn/navigation_menu.rb +28 -0
  310. data/app/components/shadcn/pagination/component.rb +19 -0
  311. data/app/components/shadcn/pagination/ellipsis/component.rb +28 -0
  312. data/app/components/shadcn/pagination/link/component.rb +37 -0
  313. data/app/components/shadcn/pagination/next/component.rb +31 -0
  314. data/app/components/shadcn/pagination/preview.rb +16 -0
  315. data/app/components/shadcn/pagination/previews/default.html.erb +18 -0
  316. data/app/components/shadcn/pagination/previews/simple.html.erb +39 -0
  317. data/app/components/shadcn/pagination/previous/component.rb +31 -0
  318. data/app/components/shadcn/pagination.rb +14 -0
  319. data/app/components/shadcn/parts.rb +38 -0
  320. data/app/components/shadcn/popover/anchor/component.rb +17 -0
  321. data/app/components/shadcn/popover/component.rb +42 -0
  322. data/app/components/shadcn/popover/content/component.rb +40 -0
  323. data/app/components/shadcn/popover/preview.rb +28 -0
  324. data/app/components/shadcn/popover/previews/align.html.erb +13 -0
  325. data/app/components/shadcn/popover/previews/default.html.erb +9 -0
  326. data/app/components/shadcn/popover/previews/inside_containing_block.html.erb +41 -0
  327. data/app/components/shadcn/popover/previews/inside_stacking_context.html.erb +30 -0
  328. data/app/components/shadcn/popover/trigger/component.rb +24 -0
  329. data/app/components/shadcn/popover.rb +16 -0
  330. data/app/components/shadcn/progress/component.rb +62 -0
  331. data/app/components/shadcn/progress/preview.rb +11 -0
  332. data/app/components/shadcn/progress/previews/default.html.erb +5 -0
  333. data/app/components/shadcn/radio_group/component.rb +51 -0
  334. data/app/components/shadcn/radio_group/item/component.rb +74 -0
  335. data/app/components/shadcn/radio_group/preview.rb +16 -0
  336. data/app/components/shadcn/radio_group/previews/default.html.erb +15 -0
  337. data/app/components/shadcn/radio_group/previews/states.html.erb +41 -0
  338. data/app/components/shadcn/resizable/component.rb +59 -0
  339. data/app/components/shadcn/resizable/handle/component.rb +70 -0
  340. data/app/components/shadcn/resizable/panel/component.rb +53 -0
  341. data/app/components/shadcn/resizable/preview.rb +23 -0
  342. data/app/components/shadcn/resizable/previews/default.html.erb +25 -0
  343. data/app/components/shadcn/resizable/previews/vertical.html.erb +19 -0
  344. data/app/components/shadcn/resizable/previews/with_handle.html.erb +17 -0
  345. data/app/components/shadcn/scroll_area/component.rb +84 -0
  346. data/app/components/shadcn/scroll_area/preview.rb +11 -0
  347. data/app/components/shadcn/scroll_area/previews/default.html.erb +36 -0
  348. data/app/components/shadcn/scroll_area/scrollbar/component.rb +72 -0
  349. data/app/components/shadcn/scroll_area/viewport/component.rb +70 -0
  350. data/app/components/shadcn/scroll_area.rb +14 -0
  351. data/app/components/shadcn/select/component.rb +67 -0
  352. data/app/components/shadcn/select/content/component.rb +157 -0
  353. data/app/components/shadcn/select/empty/component.rb +38 -0
  354. data/app/components/shadcn/select/group/component.rb +16 -0
  355. data/app/components/shadcn/select/item/component.rb +71 -0
  356. data/app/components/shadcn/select/list/component.rb +41 -0
  357. data/app/components/shadcn/select/preview.rb +24 -0
  358. data/app/components/shadcn/select/previews/default.html.erb +17 -0
  359. data/app/components/shadcn/select/previews/scrollable.html.erb +19 -0
  360. data/app/components/shadcn/select/previews/searchable.html.erb +18 -0
  361. data/app/components/shadcn/select/previews/states.html.erb +25 -0
  362. data/app/components/shadcn/select/search/component.rb +54 -0
  363. data/app/components/shadcn/select/trigger/component.rb +78 -0
  364. data/app/components/shadcn/select/value/component.rb +28 -0
  365. data/app/components/shadcn/select.rb +15 -0
  366. data/app/components/shadcn/separator/component.rb +41 -0
  367. data/app/components/shadcn/separator/preview.rb +11 -0
  368. data/app/components/shadcn/separator/previews/default.html.erb +9 -0
  369. data/app/components/shadcn/sheet/component.rb +16 -0
  370. data/app/components/shadcn/sheet/content/component.rb +98 -0
  371. data/app/components/shadcn/sheet/header/component.rb +23 -0
  372. data/app/components/shadcn/sheet/preview.rb +16 -0
  373. data/app/components/shadcn/sheet/previews/default.html.erb +16 -0
  374. data/app/components/shadcn/sheet/previews/no_close_button.html.erb +14 -0
  375. data/app/components/shadcn/sheet.rb +22 -0
  376. data/app/components/shadcn/sidebar/component.rb +232 -0
  377. data/app/components/shadcn/sidebar/input/component.rb +25 -0
  378. data/app/components/shadcn/sidebar/menu_action/component.rb +58 -0
  379. data/app/components/shadcn/sidebar/menu_button/component.rb +100 -0
  380. data/app/components/shadcn/sidebar/menu_skeleton/component.rb +51 -0
  381. data/app/components/shadcn/sidebar/menu_sub_button/component.rb +60 -0
  382. data/app/components/shadcn/sidebar/preview.rb +22 -0
  383. data/app/components/shadcn/sidebar/previews/default.html.erb +189 -0
  384. data/app/components/shadcn/sidebar/previews/floating.html.erb +39 -0
  385. data/app/components/shadcn/sidebar/previews/inset.html.erb +48 -0
  386. data/app/components/shadcn/sidebar/provider/component.rb +53 -0
  387. data/app/components/shadcn/sidebar/rail/component.rb +43 -0
  388. data/app/components/shadcn/sidebar/separator/component.rb +23 -0
  389. data/app/components/shadcn/sidebar/trigger/component.rb +39 -0
  390. data/app/components/shadcn/sidebar.rb +98 -0
  391. data/app/components/shadcn/skeleton/component.rb +14 -0
  392. data/app/components/shadcn/skeleton/preview.rb +11 -0
  393. data/app/components/shadcn/skeleton/previews/default.html.erb +7 -0
  394. data/app/components/shadcn/slider/component.rb +145 -0
  395. data/app/components/shadcn/slider/preview.rb +16 -0
  396. data/app/components/shadcn/slider/previews/default.html.erb +17 -0
  397. data/app/components/shadcn/slider/previews/vertical.html.erb +7 -0
  398. data/app/components/shadcn/slider/range/component.rb +51 -0
  399. data/app/components/shadcn/slider/thumb/component.rb +58 -0
  400. data/app/components/shadcn/slider/track/component.rb +32 -0
  401. data/app/components/shadcn/spinner/component.rb +21 -0
  402. data/app/components/shadcn/spinner/preview.rb +11 -0
  403. data/app/components/shadcn/spinner/previews/default.html.erb +7 -0
  404. data/app/components/shadcn/switch/component.rb +104 -0
  405. data/app/components/shadcn/switch/preview.rb +11 -0
  406. data/app/components/shadcn/switch/previews/default.html.erb +24 -0
  407. data/app/components/shadcn/table/component.rb +26 -0
  408. data/app/components/shadcn/table/preview.rb +16 -0
  409. data/app/components/shadcn/table/previews/default.html.erb +19 -0
  410. data/app/components/shadcn/table/previews/footer.html.erb +25 -0
  411. data/app/components/shadcn/table.rb +33 -0
  412. data/app/components/shadcn/tabs/component.rb +40 -0
  413. data/app/components/shadcn/tabs/content/component.rb +34 -0
  414. data/app/components/shadcn/tabs/list/component.rb +51 -0
  415. data/app/components/shadcn/tabs/preview.rb +16 -0
  416. data/app/components/shadcn/tabs/previews/default.html.erb +21 -0
  417. data/app/components/shadcn/tabs/previews/line.html.erb +23 -0
  418. data/app/components/shadcn/tabs/trigger/component.rb +66 -0
  419. data/app/components/shadcn/textarea/component.rb +24 -0
  420. data/app/components/shadcn/textarea/preview.rb +16 -0
  421. data/app/components/shadcn/textarea/previews/default.html.erb +3 -0
  422. data/app/components/shadcn/textarea/previews/states.html.erb +18 -0
  423. data/app/components/shadcn/theme_selector/component.rb +88 -0
  424. data/app/components/shadcn/theme_selector/preview.rb +17 -0
  425. data/app/components/shadcn/theme_selector/previews/all_themes.html.erb +20 -0
  426. data/app/components/shadcn/theme_selector/previews/default.html.erb +18 -0
  427. data/app/components/shadcn/toaster/component.rb +139 -0
  428. data/app/components/shadcn/toaster/preview.rb +16 -0
  429. data/app/components/shadcn/toaster/previews/default.html.erb +19 -0
  430. data/app/components/shadcn/toaster/previews/from_the_server.html.erb +15 -0
  431. data/app/components/shadcn/toaster/toast/component.rb +134 -0
  432. data/app/components/shadcn/toggle/component.rb +81 -0
  433. data/app/components/shadcn/toggle/preview.rb +11 -0
  434. data/app/components/shadcn/toggle/previews/default.html.erb +6 -0
  435. data/app/components/shadcn/toggle_group/component.rb +62 -0
  436. data/app/components/shadcn/toggle_group/item/component.rb +59 -0
  437. data/app/components/shadcn/toggle_group/preview.rb +16 -0
  438. data/app/components/shadcn/toggle_group/previews/default.html.erb +12 -0
  439. data/app/components/shadcn/toggle_group/previews/sizes.html.erb +37 -0
  440. data/app/components/shadcn/tooltip/component.rb +38 -0
  441. data/app/components/shadcn/tooltip/content/component.rb +62 -0
  442. data/app/components/shadcn/tooltip/preview.rb +21 -0
  443. data/app/components/shadcn/tooltip/previews/default.html.erb +4 -0
  444. data/app/components/shadcn/tooltip/previews/sides.html.erb +19 -0
  445. data/app/components/shadcn/tooltip/previews/with_keyboard_shortcut.html.erb +11 -0
  446. data/app/components/shadcn/tooltip/provider/component.rb +28 -0
  447. data/app/components/shadcn/tooltip/trigger/component.rb +25 -0
  448. data/app/helpers/shadcn_view_component/form_helper.rb +25 -0
  449. data/app/helpers/shadcn_view_component/theme_helper.rb +61 -0
  450. data/app/javascript/shadcn/animation.js +180 -0
  451. data/app/javascript/shadcn/command_score.js +110 -0
  452. data/app/javascript/shadcn/controllers/accordion_controller.js +127 -0
  453. data/app/javascript/shadcn/controllers/avatar_controller.js +32 -0
  454. data/app/javascript/shadcn/controllers/calendar_controller.js +633 -0
  455. data/app/javascript/shadcn/controllers/carousel_controller.js +139 -0
  456. data/app/javascript/shadcn/controllers/chart_controller.js +110 -0
  457. data/app/javascript/shadcn/controllers/checkbox_controller.js +61 -0
  458. data/app/javascript/shadcn/controllers/collapsible_controller.js +55 -0
  459. data/app/javascript/shadcn/controllers/combobox_controller.js +360 -0
  460. data/app/javascript/shadcn/controllers/command_controller.js +199 -0
  461. data/app/javascript/shadcn/controllers/dialog_controller.js +154 -0
  462. data/app/javascript/shadcn/controllers/drawer_controller.js +265 -0
  463. data/app/javascript/shadcn/controllers/dropdown_menu_controller.js +259 -0
  464. data/app/javascript/shadcn/controllers/hover_card_controller.js +85 -0
  465. data/app/javascript/shadcn/controllers/input_group_controller.js +17 -0
  466. data/app/javascript/shadcn/controllers/input_otp_controller.js +80 -0
  467. data/app/javascript/shadcn/controllers/menubar_controller.js +151 -0
  468. data/app/javascript/shadcn/controllers/message_scroller_controller.js +456 -0
  469. data/app/javascript/shadcn/controllers/navigation_menu_controller.js +211 -0
  470. data/app/javascript/shadcn/controllers/popover_controller.js +66 -0
  471. data/app/javascript/shadcn/controllers/radio_group_controller.js +69 -0
  472. data/app/javascript/shadcn/controllers/resizable_controller.js +167 -0
  473. data/app/javascript/shadcn/controllers/scroll_area_controller.js +253 -0
  474. data/app/javascript/shadcn/controllers/select_controller.js +320 -0
  475. data/app/javascript/shadcn/controllers/sidebar_controller.js +273 -0
  476. data/app/javascript/shadcn/controllers/slider_controller.js +230 -0
  477. data/app/javascript/shadcn/controllers/switch_controller.js +39 -0
  478. data/app/javascript/shadcn/controllers/tabs_controller.js +81 -0
  479. data/app/javascript/shadcn/controllers/theme_controller.js +67 -0
  480. data/app/javascript/shadcn/controllers/toaster_controller.js +281 -0
  481. data/app/javascript/shadcn/controllers/toggle_controller.js +24 -0
  482. data/app/javascript/shadcn/controllers/toggle_group_controller.js +73 -0
  483. data/app/javascript/shadcn/controllers/tooltip_controller.js +58 -0
  484. data/app/javascript/shadcn/direction.js +41 -0
  485. data/app/javascript/shadcn/dismiss.js +73 -0
  486. data/app/javascript/shadcn/floating.js +207 -0
  487. data/app/javascript/shadcn/focus.js +86 -0
  488. data/app/javascript/shadcn/id.js +14 -0
  489. data/app/javascript/shadcn/index.js +110 -0
  490. data/app/javascript/shadcn/popper.js +262 -0
  491. data/app/javascript/shadcn/scroll_geometry.js +267 -0
  492. data/app/javascript/shadcn/theme.js +161 -0
  493. data/app/javascript/shadcn/top_layer.js +59 -0
  494. data/app/javascript/shadcn/typeahead.js +99 -0
  495. data/config/importmap.rb +6 -0
  496. data/config/locales/en.yml +62 -0
  497. data/lib/generators/shadcn_view_component/install/install_generator.rb +149 -0
  498. data/lib/shadcn_view_component/engine.rb +73 -0
  499. data/lib/shadcn_view_component/form_builder.rb +264 -0
  500. data/lib/shadcn_view_component/icon_registry.rb +66 -0
  501. data/lib/shadcn_view_component/icons.rb +32 -0
  502. data/lib/shadcn_view_component/themes.rb +1065 -0
  503. data/lib/shadcn_view_component/version.rb +3 -0
  504. data/lib/shadcn_view_component.rb +82 -0
  505. data/lib/tasks/icons.rake +53 -0
  506. data/lib/tasks/themes.rake +171 -0
  507. metadata +608 -0
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Sidebar
5
+ module MenuAction
6
+ # SidebarMenuAction — the small button that sits on a menu item. It has a
7
+ # variant, which is why it is a component rather than a `sidebar_part`.
8
+ class Component < ApplicationViewComponent
9
+ default_tag :button
10
+ slot_name :"sidebar-menu-action"
11
+
12
+ style do
13
+ base {
14
+ "absolute top-1.5 right-1 flex aspect-square w-5 items-center " \
15
+ "justify-center rounded-md p-0 text-sidebar-foreground " \
16
+ "ring-sidebar-ring outline-hidden transition-transform " \
17
+ "peer-hover/menu-button:text-sidebar-accent-foreground " \
18
+ "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground " \
19
+ "focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0 after:absolute " \
20
+ "after:-inset-2 md:after:hidden peer-data-[size=sm]/menu-button:top-1 " \
21
+ "peer-data-[size=default]/menu-button:top-1.5 " \
22
+ "peer-data-[size=lg]/menu-button:top-2.5 " \
23
+ "group-data-[collapsible=icon]:hidden"
24
+ }
25
+
26
+ variants {
27
+ show_on_hover {
28
+ yes {
29
+ "group-focus-within/menu-item:opacity-100 " \
30
+ "group-hover/menu-item:opacity-100 " \
31
+ "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground " \
32
+ "data-[state=open]:opacity-100 md:opacity-0"
33
+ }
34
+ no { "" }
35
+ }
36
+ }
37
+
38
+ defaults { { show_on_hover: :no } }
39
+ end
40
+
41
+ attr_reader :show_on_hover
42
+
43
+ def initialize(show_on_hover: false, **attributes)
44
+ @show_on_hover = show_on_hover
45
+ super(**attributes)
46
+ end
47
+
48
+ def style_variants
49
+ { show_on_hover: show_on_hover ? :yes : :no }
50
+ end
51
+
52
+ def element_attributes(**defaults)
53
+ super(**{ type: "button", "data-sidebar" => "menu-action" }.merge(defaults))
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Sidebar
5
+ module MenuButton
6
+ # SidebarMenuButton — the row a sidebar is mostly made of.
7
+ #
8
+ # `tooltip:` wraps the button in a Tooltip, as upstream does
9
+ # (vendor/shadcn/ui/sidebar.tsx:534-542). Upstream decides whether to show
10
+ # it with a runtime prop — `hidden={state !== "collapsed" || isMobile}` —
11
+ # which a server cannot evaluate. Here the same two conditions are CSS,
12
+ # read off the panel's own `group`: `data-state` is what the controller
13
+ # already writes, and `data-mobile` is what it sets while the mobile sheet
14
+ # is open. Same result, decided by the browser rather than by the render.
15
+ class Component < ApplicationViewComponent
16
+ default_tag :button
17
+ slot_name :"sidebar-menu-button"
18
+
19
+ style do
20
+ base {
21
+ "peer/menu-button flex w-full items-center gap-2 overflow-hidden " \
22
+ "rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden " \
23
+ "transition-[width,height,padding] " \
24
+ "group-has-data-[sidebar=menu-action]/menu-item:pr-8 " \
25
+ "group-data-[collapsible=icon]:size-8! " \
26
+ "group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent " \
27
+ "hover:text-sidebar-accent-foreground focus-visible:ring-2 " \
28
+ "active:bg-sidebar-accent active:text-sidebar-accent-foreground " \
29
+ "disabled:pointer-events-none disabled:opacity-50 " \
30
+ "aria-disabled:pointer-events-none aria-disabled:opacity-50 " \
31
+ "data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium " \
32
+ "data-[active=true]:text-sidebar-accent-foreground " \
33
+ "data-[state=open]:hover:bg-sidebar-accent " \
34
+ "data-[state=open]:hover:text-sidebar-accent-foreground " \
35
+ "[&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0"
36
+ }
37
+
38
+ variants {
39
+ variant {
40
+ default { "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground" }
41
+ outline {
42
+ "bg-background shadow-[0_0_0_1px_var(--sidebar-border)] " \
43
+ "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground " \
44
+ "hover:shadow-[0_0_0_1px_var(--sidebar-accent)]"
45
+ }
46
+ }
47
+
48
+ size {
49
+ default { "h-8 text-sm" }
50
+ sm { "h-7 text-xs" }
51
+ lg { "h-12 text-sm group-data-[collapsible=icon]:p-0!" }
52
+ }
53
+ }
54
+
55
+ defaults { { variant: :default, size: :default } }
56
+ end
57
+
58
+ # A tooltip is only of use when the label beside the icon is gone, so it
59
+ # is hidden while the sidebar is expanded, and while the mobile sheet is
60
+ # showing the full labels anyway.
61
+ TOOLTIP_CLASSES = "group-data-[state=expanded]:hidden group-data-[mobile=true]:hidden"
62
+
63
+ attr_reader :variant, :size, :active, :tooltip
64
+
65
+ def initialize(variant: :default, size: :default, active: false, tooltip: nil, **attributes)
66
+ @variant = variant&.to_sym || :default
67
+ @size = size&.to_sym || :default
68
+ @active = active
69
+ @tooltip = tooltip
70
+ super(**attributes)
71
+ end
72
+
73
+ def call
74
+ return render_element(body: content) if tooltip.blank?
75
+
76
+ render(Shadcn::Tooltip::Component.new(side: :right, align: :center)) do |wrapper|
77
+ # The trigger takes this button's own attributes, `data-slot`
78
+ # included, so the element in the document is still a
79
+ # `sidebar-menu-button` — which is what upstream's `asChild` does.
80
+ wrapper.with_trigger(as: tag_name, **element_attributes.transform_keys(&:to_sym)) { content }
81
+ wrapper.with_tooltip_content(class: TOOLTIP_CLASSES) { tooltip }
82
+ end
83
+ end
84
+
85
+ def style_variants
86
+ { variant:, size: }
87
+ end
88
+
89
+ def element_attributes(**defaults)
90
+ super(**{
91
+ type: "button",
92
+ "data-sidebar" => "menu-button",
93
+ "data-size" => size,
94
+ "data-active" => active.to_s
95
+ }.merge(defaults))
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Sidebar
5
+ module MenuSkeleton
6
+ # SidebarMenuSkeleton — a placeholder row. Upstream randomises the text
7
+ # width between 50% and 90% so a column of them does not look like a
8
+ # barcode (vendor/shadcn/ui/sidebar.tsx:611-613); the same range is used
9
+ # here, drawn once per instance.
10
+ class Component < ApplicationViewComponent
11
+ slot_name :"sidebar-menu-skeleton"
12
+
13
+ style do
14
+ base { "flex h-8 items-center gap-2 rounded-md px-2" }
15
+ end
16
+
17
+ attr_reader :show_icon
18
+
19
+ def initialize(show_icon: false, **attributes)
20
+ @show_icon = show_icon
21
+ @width = "#{rand(50..89)}%"
22
+ super(**attributes)
23
+ end
24
+
25
+ def element_attributes(**defaults)
26
+ super(**{ "data-sidebar" => "menu-skeleton" }.merge(defaults))
27
+ end
28
+
29
+ def call
30
+ render_element(body: safe_join([ icon, text ].compact))
31
+ end
32
+
33
+ private
34
+
35
+ def icon
36
+ return unless show_icon
37
+
38
+ render(Skeleton::Component.new(class: "size-4 rounded-md", "data-sidebar": "menu-skeleton-icon"))
39
+ end
40
+
41
+ def text
42
+ render(Skeleton::Component.new(
43
+ class: "h-4 max-w-(--skeleton-width) flex-1",
44
+ "data-sidebar": "menu-skeleton-text",
45
+ style: "--skeleton-width: #{@width};"
46
+ ))
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Sidebar
5
+ module MenuSubButton
6
+ # SidebarMenuSubButton — an `<a>` rather than a button, because a submenu
7
+ # row is a link upstream (vendor/shadcn/ui/sidebar.tsx:680).
8
+ class Component < ApplicationViewComponent
9
+ default_tag :a
10
+ slot_name :"sidebar-menu-sub-button"
11
+
12
+ style do
13
+ base {
14
+ "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden " \
15
+ "rounded-md px-2 text-sidebar-foreground ring-sidebar-ring " \
16
+ "outline-hidden hover:bg-sidebar-accent " \
17
+ "hover:text-sidebar-accent-foreground focus-visible:ring-2 " \
18
+ "active:bg-sidebar-accent active:text-sidebar-accent-foreground " \
19
+ "disabled:pointer-events-none disabled:opacity-50 " \
20
+ "aria-disabled:pointer-events-none aria-disabled:opacity-50 " \
21
+ "[&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 " \
22
+ "[&>svg]:text-sidebar-accent-foreground " \
23
+ "data-[active=true]:bg-sidebar-accent " \
24
+ "data-[active=true]:text-sidebar-accent-foreground sm md " \
25
+ "group-data-[collapsible=icon]:hidden"
26
+ }
27
+
28
+ variants {
29
+ size {
30
+ sm { "text-xs" }
31
+ md { "text-sm" }
32
+ }
33
+ }
34
+
35
+ defaults { { size: :md } }
36
+ end
37
+
38
+ attr_reader :size, :active
39
+
40
+ def initialize(size: :md, active: false, **attributes)
41
+ @size = size&.to_sym || :md
42
+ @active = active
43
+ super(**attributes)
44
+ end
45
+
46
+ def style_variants
47
+ { size: }
48
+ end
49
+
50
+ def element_attributes(**defaults)
51
+ super(**{
52
+ "data-sidebar" => "menu-sub-button",
53
+ "data-size" => size,
54
+ "data-active" => active.to_s
55
+ }.merge(defaults))
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Sidebar
5
+ class Preview < ApplicationViewComponentPreview
6
+ def default
7
+ render_with_template
8
+ end
9
+
10
+ # Upstream's `floating` variant. Its own page: the panel is `fixed`, so
11
+ # two of them cannot share one.
12
+ def floating
13
+ render_with_template
14
+ end
15
+
16
+ # Upstream's `inset` variant, for the same reason.
17
+ def inset
18
+ render_with_template
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,189 @@
1
+ <%# shadcn's own `sidebar-demo`, read from the iframe it renders in —
2
+ ui.shadcn.com/view/radix-nova/sidebar-demo — with `collapsible: :icon`,
3
+ which is what that demo uses: collapsing leaves a rail of icons rather than
4
+ sliding the whole panel away.
5
+
6
+ The icons are inlined rather than bundled. `Icon::Component`'s PATHS holds
7
+ the icons the *components* need; these are a demo's decoration, and putting
8
+ eight of them into a library's payload for one preview is the wrong trade.
9
+ Their paths were read from upstream's rendered demo rather than recalled.
10
+
11
+ The Projects rows carry `tooltip:`, which is what labels their icons once
12
+ the sidebar collapses. The Platform rows cannot: each is a Collapsible
13
+ trigger wearing the menu button's classes rather than a MenuButton, so it
14
+ takes a plain `title:` — the browser's own tooltip — instead. That
15
+ difference is upstream's too, and the reason is the same on both sides. %>
16
+ <%
17
+ icons = {
18
+ "gallery-vertical-end" => %(<path d="M7 2h10"/><path d="M5 6h14"/><rect width="18" height="12" x="3" y="10" rx="2"/>),
19
+ "square-terminal" => %(<path d="m7 11 2-2-2-2"/><path d="M11 13h4"/><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/>),
20
+ "bot" => %(<path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/>),
21
+ "book-open" => %(<path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/>),
22
+ "settings-2" => %(<path d="M20 7h-9"/><path d="M14 17H5"/><circle cx="17" cy="17" r="3"/><circle cx="7" cy="7" r="3"/>),
23
+ "frame" => %(<line x1="22" x2="2" y1="6" y2="6"/><line x1="22" x2="2" y1="18" y2="18"/><line x1="6" x2="6" y1="2" y2="22"/><line x1="18" x2="18" y1="2" y2="22"/>),
24
+ "chart-pie" => %(<path d="M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z"/><path d="M21.21 15.89A10 10 0 1 1 8 2.83"/>),
25
+ "map" => %(<path d="M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z"/><path d="M15 5.764v15"/><path d="M9 3.236v15"/>),
26
+ }
27
+
28
+ glyph = ->(name, extra = nil) do
29
+ tag.svg(
30
+ icons.fetch(name).html_safe,
31
+ xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24,
32
+ viewBox: "0 0 24 24", fill: "none", stroke: "currentColor",
33
+ "stroke-width": 2, "stroke-linecap": "round", "stroke-linejoin": "round",
34
+ class: [ "size-4 shrink-0", extra ].compact.join(" "), "aria-hidden": true
35
+ )
36
+ end
37
+
38
+ platform = {
39
+ "Playground" => [ "square-terminal", %w[History Starred Settings] ],
40
+ "Models" => [ "bot", %w[Genesis Explorer Quantum] ],
41
+ "Documentation" => [ "book-open", [ "Introduction", "Get Started", "Tutorials" ] ],
42
+ "Settings" => [ "settings-2", %w[General Team Billing] ]
43
+ }
44
+ projects = [ [ "Design Engineering", "frame" ], [ "Sales & Marketing", "chart-pie" ], [ "Travel", "map" ] ]
45
+ %>
46
+ <%= render(Shadcn::Sidebar::Provider::Component.new) do %>
47
+ <%= render(Shadcn::Sidebar::Component.new(collapsible: :icon)) do %>
48
+ <%= render(Shadcn::Sidebar::Header::Component.new) do %>
49
+ <%= render(Shadcn::Sidebar::Menu::Component.new) do %>
50
+ <%= render(Shadcn::Sidebar::MenuItem::Component.new) do %>
51
+ <%= render(Shadcn::DropdownMenu::Component.new) do |menu| %>
52
+ <% menu.with_trigger(
53
+ class: Shadcn::Sidebar::MenuButton::Component.new(size: :lg).css_classes,
54
+ "data-size": "lg"
55
+ ) do %>
56
+ <div class="flex aspect-square size-8 shrink-0 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
57
+ <%= glyph.call("gallery-vertical-end") %>
58
+ </div>
59
+ <div class="grid flex-1 text-left text-sm leading-tight">
60
+ <span class="truncate font-medium">Acme Inc</span>
61
+ <span class="truncate text-xs">Enterprise</span>
62
+ </div>
63
+ <%= render(Shadcn::Icon::Component.new("chevrons-up-down", class: "ml-auto")) %>
64
+ <% end %>
65
+ <% menu.with_menu_content(class: "w-56") do %>
66
+ <%= render(Shadcn::DropdownMenu::Label::Component.new) { "Teams" } %>
67
+ <% [ "Acme Inc", "Acme Corp.", "Evil Corp." ].each do |team| %>
68
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) { team } %>
69
+ <% end %>
70
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
71
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) { "Add team" } %>
72
+ <% end %>
73
+ <% end %>
74
+ <% end %>
75
+ <% end %>
76
+ <% end %>
77
+
78
+ <%= render(Shadcn::Sidebar::Content::Component.new) do %>
79
+ <%= render(Shadcn::Sidebar::Group::Component.new) do %>
80
+ <%= render(Shadcn::Sidebar::GroupLabel::Component.new) { "Platform" } %>
81
+ <%= render(Shadcn::Sidebar::Menu::Component.new) do %>
82
+ <% platform.each_with_index do |(section, (name, pages)), index| %>
83
+ <%= render(Shadcn::Sidebar::MenuItem::Component.new) do %>
84
+ <%= render(Shadcn::Collapsible::Component.new(open: index.zero?, class: "group/collapsible")) do %>
85
+ <%# Neither slot is used, and that is deliberate. Slot content
86
+ renders before block content, so `with_panel` would put the
87
+ submenu above its own trigger; and the trigger has to *be*
88
+ the MenuButton, not a plain trigger wearing its classes,
89
+ because that is where `tooltip:` lives and a collapsed rail
90
+ of icons has nothing else to label it. Upstream composes it
91
+ the same way: `<CollapsibleTrigger asChild>
92
+ <SidebarMenuButton tooltip={…}>`. %>
93
+ <%= render(Shadcn::Sidebar::MenuButton::Component.new(
94
+ tooltip: section,
95
+ "data-shadcn--collapsible-target": "trigger",
96
+ "data-action": "shadcn--collapsible#toggle",
97
+ "aria-expanded": index.zero?.to_s
98
+ )) do %>
99
+ <%= glyph.call(name) %>
100
+ <span><%= section %></span>
101
+ <%= render(Shadcn::Icon::Component.new(
102
+ "chevron-right",
103
+ class: "ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90"
104
+ )) %>
105
+ <% end %>
106
+
107
+ <%= render(Shadcn::Collapsible::Content::Component.new) do %>
108
+ <%= render(Shadcn::Sidebar::MenuSub::Component.new) do %>
109
+ <% pages.each do |page| %>
110
+ <%= render(Shadcn::Sidebar::MenuSubItem::Component.new) do %>
111
+ <%= render(Shadcn::Sidebar::MenuSubButton::Component.new(href: "#")) do %>
112
+ <span><%= page %></span>
113
+ <% end %>
114
+ <% end %>
115
+ <% end %>
116
+ <% end %>
117
+ <% end %>
118
+ <% end %>
119
+ <% end %>
120
+ <% end %>
121
+ <% end %>
122
+ <% end %>
123
+
124
+ <%= render(Shadcn::Sidebar::Group::Component.new(class: "group-data-[collapsible=icon]:hidden")) do %>
125
+ <%= render(Shadcn::Sidebar::GroupLabel::Component.new) { "Projects" } %>
126
+ <%= render(Shadcn::Sidebar::Menu::Component.new) do %>
127
+ <% projects.each do |(project, name)| %>
128
+ <%= render(Shadcn::Sidebar::MenuItem::Component.new) do %>
129
+ <%= render(Shadcn::Sidebar::MenuButton::Component.new(as: :a, href: "#", tooltip: project)) do %>
130
+ <%= glyph.call(name) %>
131
+ <span><%= project %></span>
132
+ <% end %>
133
+ <%= render(Shadcn::Sidebar::MenuAction::Component.new(show_on_hover: true, "aria-label": "More")) do %>
134
+ <%= render(Shadcn::Icon::Component.new("more-horizontal")) %>
135
+ <% end %>
136
+ <% end %>
137
+ <% end %>
138
+ <% end %>
139
+ <% end %>
140
+ <% end %>
141
+
142
+ <%= render(Shadcn::Sidebar::Footer::Component.new) do %>
143
+ <%= render(Shadcn::Sidebar::Menu::Component.new) do %>
144
+ <%= render(Shadcn::Sidebar::MenuItem::Component.new) do %>
145
+ <%= render(Shadcn::DropdownMenu::Component.new(side: :top)) do |menu| %>
146
+ <% menu.with_trigger(
147
+ class: Shadcn::Sidebar::MenuButton::Component.new(size: :lg).css_classes,
148
+ "data-size": "lg"
149
+ ) do %>
150
+ <%= render(Shadcn::Avatar::Component.new(class: "size-8 shrink-0 rounded-lg")) do |avatar| %>
151
+ <% avatar.with_fallback { "SC" } %>
152
+ <% end %>
153
+ <div class="grid flex-1 text-left text-sm leading-tight">
154
+ <span class="truncate font-medium">shadcn</span>
155
+ <span class="truncate text-xs">m@example.com</span>
156
+ </div>
157
+ <%= render(Shadcn::Icon::Component.new("chevrons-up-down", class: "ml-auto")) %>
158
+ <% end %>
159
+ <% menu.with_menu_content(class: "w-56") do %>
160
+ <%= render(Shadcn::DropdownMenu::Label::Component.new) { "m@example.com" } %>
161
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
162
+ <% [ "Account", "Billing", "Notifications" ].each do |entry| %>
163
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) { entry } %>
164
+ <% end %>
165
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
166
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) { "Log out" } %>
167
+ <% end %>
168
+ <% end %>
169
+ <% end %>
170
+ <% end %>
171
+ <% end %>
172
+
173
+ <%# Inside the panel, last, exactly where upstream puts it: its `absolute`
174
+ is meant to resolve against `sidebar-container`, and its
175
+ `group-data-[side=left]:-right-4` against the panel's own `group`.
176
+ Rendered as a sibling instead it positions against the page and draws a
177
+ line straight through the icons. %>
178
+ <%= render(Shadcn::Sidebar::Rail::Component.new) %>
179
+ <% end %>
180
+
181
+ <%= render(Shadcn::Sidebar::Inset::Component.new) do %>
182
+ <div class="flex items-center gap-2 border-b p-2">
183
+ <%= render(Shadcn::Sidebar::Trigger::Component.new) %>
184
+ <%= render(Shadcn::Sidebar::Separator::Component.new(orientation: :vertical, class: "h-4")) %>
185
+ <span class="text-sm font-medium">Dashboard</span>
186
+ </div>
187
+ <p class="p-4 text-sm text-muted-foreground">Page content.</p>
188
+ <% end %>
189
+ <% end %>
@@ -0,0 +1,39 @@
1
+ <%# Upstream's `floating` variant, which the default preview does not show.
2
+
3
+ A page of its own, and that is forced rather than chosen: the desktop panel
4
+ is `fixed inset-y-0 … h-svh` (sidebar.tsx), so it is measured against the
5
+ viewport and cannot be put in a box. The first version of this preview put
6
+ two providers in two bordered `h-64` divs to compare the variants side by
7
+ side; both panels escaped their boxes, one covered the other, and the label
8
+ beside each said the wrong thing. Lookbook gives every preview its own
9
+ iframe, which is the only frame a sidebar can be shown in.
10
+
11
+ `floating` gives the panel its own rounded border and shadow and stands it
12
+ off the edge; `inset` leaves the panel flush and pulls the page's container
13
+ in beside it. Both read `group-data-[variant=…]` off the provider, so the
14
+ difference is on `SidebarInset` as much as on the panel. %>
15
+ <%= render(Shadcn::Sidebar::Provider::Component.new) do %>
16
+ <%= render(Shadcn::Sidebar::Component.new(variant: :floating, collapsible: :icon)) do %>
17
+ <%= render(Shadcn::Sidebar::Content::Component.new) do %>
18
+ <%= render(Shadcn::Sidebar::Group::Component.new) do %>
19
+ <%= render(Shadcn::Sidebar::GroupLabel::Component.new) { "Workspace" } %>
20
+ <%= render(Shadcn::Sidebar::Menu::Component.new) do %>
21
+ <% [["search", "Search"], ["circle", "Projects"], ["check", "Done"]].each do |icon, label| %>
22
+ <%= render(Shadcn::Sidebar::MenuItem::Component.new) do %>
23
+ <%= render(Shadcn::Sidebar::MenuButton::Component.new(tooltip: label)) do %>
24
+ <%= render(Shadcn::Icon::Component.new(icon)) %>
25
+ <span><%= label %></span>
26
+ <% end %>
27
+ <% end %>
28
+ <% end %>
29
+ <% end %>
30
+ <% end %>
31
+ <% end %>
32
+ <% end %>
33
+ <%= render(Shadcn::Sidebar::Inset::Component.new) do %>
34
+ <div class="flex items-center gap-2 border-b p-4">
35
+ <%= render(Shadcn::Sidebar::Trigger::Component.new) %>
36
+ <span class="text-sm text-muted-foreground">The page beside a floating panel — the trigger collapses it to a rail.</span>
37
+ </div>
38
+ <% end %>
39
+ <% end %>
@@ -0,0 +1,48 @@
1
+ <%# Upstream's `inset` variant, which the default preview does not show.
2
+
3
+ A page of its own, and that is forced rather than chosen: the desktop panel
4
+ is `fixed inset-y-0 … h-svh` (sidebar.tsx), so it is measured against the
5
+ viewport and cannot be put in a box. The first version of this preview put
6
+ two providers in two bordered `h-64` divs to compare the variants side by
7
+ side; both panels escaped their boxes, one covered the other, and the label
8
+ beside each said the wrong thing. Lookbook gives every preview its own
9
+ iframe, which is the only frame a sidebar can be shown in.
10
+
11
+ `inset` leaves the panel flush and pulls the page's container in beside it,
12
+ which reads `group-data-[variant=inset]` off the provider — so the variant
13
+ shows on `SidebarInset` as much as on the panel.
14
+
15
+ **The wrapper's background is overridden here, and that is a divergence.**
16
+ Upstream puts `has-data-[variant=inset]:bg-sidebar` on it (sidebar.tsx:142),
17
+ which is what makes the panel and the page look like two cards floating on
18
+ the sidebar's own colour — the whole idea of the variant. This preview asks
19
+ for `bg-background` instead. It is the caller's class, not the component's:
20
+ `cn` replaces the conflicting one, `parity_spec` still sees upstream's
21
+ string in the component source, and a host that says nothing still gets
22
+ upstream's look. `bg-background` rather than a literal white, so it follows
23
+ the theme instead of turning into a white slab in the dark one. %>
24
+ <%= render(Shadcn::Sidebar::Provider::Component.new(class: "has-data-[variant=inset]:bg-background")) do %>
25
+ <%= render(Shadcn::Sidebar::Component.new(variant: :inset, collapsible: :icon)) do %>
26
+ <%= render(Shadcn::Sidebar::Content::Component.new) do %>
27
+ <%= render(Shadcn::Sidebar::Group::Component.new) do %>
28
+ <%= render(Shadcn::Sidebar::GroupLabel::Component.new) { "Workspace" } %>
29
+ <%= render(Shadcn::Sidebar::Menu::Component.new) do %>
30
+ <% [["search", "Search"], ["circle", "Projects"], ["check", "Done"]].each do |icon, label| %>
31
+ <%= render(Shadcn::Sidebar::MenuItem::Component.new) do %>
32
+ <%= render(Shadcn::Sidebar::MenuButton::Component.new(tooltip: label)) do %>
33
+ <%= render(Shadcn::Icon::Component.new(icon)) %>
34
+ <span><%= label %></span>
35
+ <% end %>
36
+ <% end %>
37
+ <% end %>
38
+ <% end %>
39
+ <% end %>
40
+ <% end %>
41
+ <% end %>
42
+ <%= render(Shadcn::Sidebar::Inset::Component.new) do %>
43
+ <div class="flex items-center gap-2 border-b p-4">
44
+ <%= render(Shadcn::Sidebar::Trigger::Component.new) %>
45
+ <span class="text-sm text-muted-foreground">The page beside a inset panel — the trigger collapses it to a rail.</span>
46
+ </div>
47
+ <% end %>
48
+ <% end %>
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Sidebar
5
+ module Provider
6
+ # SidebarProvider — the wrapper that holds the state for everything below
7
+ # it. In React that state is a context (vendor/shadcn/ui/sidebar.tsx:56);
8
+ # here it is the Stimulus controller, which is why this element and not
9
+ # the panel carries `data-controller`.
10
+ #
11
+ # Upstream also wraps its children in a `TooltipProvider` with
12
+ # `delayDuration={0}`, so a collapsed sidebar's icons can explain
13
+ # themselves. This port has no provider component — each Tooltip carries
14
+ # its own delay — so there is nothing to reproduce here.
15
+ class Component < ApplicationViewComponent
16
+ WIDTH = "16rem"
17
+ WIDTH_ICON = "3rem"
18
+ # Upstream's `SIDEBAR_WIDTH_MOBILE` (sidebar.tsx:31), which it applies by
19
+ # overriding `--sidebar-width` on the Sheet it renders instead of the
20
+ # panel. There is no second element here to override it on, so it is
21
+ # published as its own variable and the panel reaches for it directly.
22
+ WIDTH_MOBILE = "18rem"
23
+
24
+ slot_name :"sidebar-wrapper"
25
+
26
+ style do
27
+ base { "group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar" }
28
+ end
29
+
30
+ attr_reader :open
31
+
32
+ # `open:` is what a Rails layout passes after reading the
33
+ # `sidebar_state` cookie, the way a Next.js layout passes `defaultOpen`.
34
+ # It defaults to open, as upstream's does.
35
+ def initialize(open: true, **attributes)
36
+ @open = open
37
+ super(**attributes)
38
+ end
39
+
40
+ def element_attributes(**defaults)
41
+ super(**{
42
+ style: merged_style(
43
+ "--sidebar-width: #{WIDTH}; --sidebar-width-icon: #{WIDTH_ICON}; " \
44
+ "--sidebar-width-mobile: #{WIDTH_MOBILE};"
45
+ ),
46
+ "data-controller" => "shadcn--sidebar",
47
+ "data-shadcn--sidebar-open-value" => open
48
+ }.merge(defaults))
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end