uikit_rails 0.1.1

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 (378) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +301 -0
  3. data/Rakefile +12 -0
  4. data/app/controllers/uikit_rails/styleguide_controller.rb +72 -0
  5. data/app/views/layouts/uikit_rails/application.html.erb +412 -0
  6. data/app/views/uikit_rails/styleguide/index.html.erb +27 -0
  7. data/app/views/uikit_rails/styleguide/show.html.erb +56 -0
  8. data/config/routes.rb +6 -0
  9. data/lib/uikit_rails/engine.rb +13 -0
  10. data/lib/uikit_rails/generators/add_generator.rb +110 -0
  11. data/lib/uikit_rails/generators/install_generator.rb +62 -0
  12. data/lib/uikit_rails/generators/templates/base_component.rb.tt +32 -0
  13. data/lib/uikit_rails/generators/templates/uikit_rails.css.tt +69 -0
  14. data/lib/uikit_rails/templates/components/accordion/USAGE +30 -0
  15. data/lib/uikit_rails/templates/components/accordion/accordion.css +74 -0
  16. data/lib/uikit_rails/templates/components/accordion/component.html.erb +13 -0
  17. data/lib/uikit_rails/templates/components/accordion/component.rb +35 -0
  18. data/lib/uikit_rails/templates/components/accordion/preview.yml +81 -0
  19. data/lib/uikit_rails/templates/components/alert/USAGE +25 -0
  20. data/lib/uikit_rails/templates/components/alert/alert.css +60 -0
  21. data/lib/uikit_rails/templates/components/alert/component.html.erb +9 -0
  22. data/lib/uikit_rails/templates/components/alert/component.rb +27 -0
  23. data/lib/uikit_rails/templates/components/alert/preview.yml +53 -0
  24. data/lib/uikit_rails/templates/components/alert_dialog/USAGE +38 -0
  25. data/lib/uikit_rails/templates/components/alert_dialog/alert_dialog.css +108 -0
  26. data/lib/uikit_rails/templates/components/alert_dialog/component.html.erb +27 -0
  27. data/lib/uikit_rails/templates/components/alert_dialog/component.rb +23 -0
  28. data/lib/uikit_rails/templates/components/alert_dialog/preview.yml +94 -0
  29. data/lib/uikit_rails/templates/components/avatar/USAGE +20 -0
  30. data/lib/uikit_rails/templates/components/avatar/avatar.css +53 -0
  31. data/lib/uikit_rails/templates/components/avatar/component.html.erb +7 -0
  32. data/lib/uikit_rails/templates/components/avatar/component.rb +31 -0
  33. data/lib/uikit_rails/templates/components/avatar/preview.yml +42 -0
  34. data/lib/uikit_rails/templates/components/badge/USAGE +13 -0
  35. data/lib/uikit_rails/templates/components/badge/badge.css +61 -0
  36. data/lib/uikit_rails/templates/components/badge/component.rb +28 -0
  37. data/lib/uikit_rails/templates/components/badge/preview.yml +38 -0
  38. data/lib/uikit_rails/templates/components/breadcrumb/USAGE +23 -0
  39. data/lib/uikit_rails/templates/components/breadcrumb/breadcrumb.css +55 -0
  40. data/lib/uikit_rails/templates/components/breadcrumb/component.html.erb +14 -0
  41. data/lib/uikit_rails/templates/components/breadcrumb/component.rb +40 -0
  42. data/lib/uikit_rails/templates/components/breadcrumb/preview.yml +42 -0
  43. data/lib/uikit_rails/templates/components/button/USAGE +21 -0
  44. data/lib/uikit_rails/templates/components/button/button.css +125 -0
  45. data/lib/uikit_rails/templates/components/button/component.rb +44 -0
  46. data/lib/uikit_rails/templates/components/button/preview.yml +106 -0
  47. data/lib/uikit_rails/templates/components/card/USAGE +33 -0
  48. data/lib/uikit_rails/templates/components/card/card.css +63 -0
  49. data/lib/uikit_rails/templates/components/card/component.html.erb +16 -0
  50. data/lib/uikit_rails/templates/components/card/component.rb +26 -0
  51. data/lib/uikit_rails/templates/components/card/preview.yml +57 -0
  52. data/lib/uikit_rails/templates/components/checkbox/USAGE +19 -0
  53. data/lib/uikit_rails/templates/components/checkbox/checkbox.css +67 -0
  54. data/lib/uikit_rails/templates/components/checkbox/component.html.erb +6 -0
  55. data/lib/uikit_rails/templates/components/checkbox/component.rb +26 -0
  56. data/lib/uikit_rails/templates/components/checkbox/preview.yml +43 -0
  57. data/lib/uikit_rails/templates/components/collapsible/USAGE +31 -0
  58. data/lib/uikit_rails/templates/components/collapsible/collapsible.css +55 -0
  59. data/lib/uikit_rails/templates/components/collapsible/component.html.erb +8 -0
  60. data/lib/uikit_rails/templates/components/collapsible/component.rb +18 -0
  61. data/lib/uikit_rails/templates/components/collapsible/preview.yml +65 -0
  62. data/lib/uikit_rails/templates/components/dialog/USAGE +41 -0
  63. data/lib/uikit_rails/templates/components/dialog/component.html.erb +23 -0
  64. data/lib/uikit_rails/templates/components/dialog/component.rb +20 -0
  65. data/lib/uikit_rails/templates/components/dialog/dialog.css +133 -0
  66. data/lib/uikit_rails/templates/components/dialog/preview.yml +77 -0
  67. data/lib/uikit_rails/templates/components/dropdown/USAGE +40 -0
  68. data/lib/uikit_rails/templates/components/dropdown/component.html.erb +14 -0
  69. data/lib/uikit_rails/templates/components/dropdown/component.rb +62 -0
  70. data/lib/uikit_rails/templates/components/dropdown/dropdown.css +104 -0
  71. data/lib/uikit_rails/templates/components/dropdown/preview.yml +75 -0
  72. data/lib/uikit_rails/templates/components/form/USAGE +51 -0
  73. data/lib/uikit_rails/templates/components/form/builder.rb +233 -0
  74. data/lib/uikit_rails/templates/components/form/form.css +48 -0
  75. data/lib/uikit_rails/templates/components/form/preview.yml +95 -0
  76. data/lib/uikit_rails/templates/components/input/USAGE +21 -0
  77. data/lib/uikit_rails/templates/components/input/component.rb +25 -0
  78. data/lib/uikit_rails/templates/components/input/input.css +43 -0
  79. data/lib/uikit_rails/templates/components/input/preview.yml +58 -0
  80. data/lib/uikit_rails/templates/components/label/USAGE +16 -0
  81. data/lib/uikit_rails/templates/components/label/component.rb +25 -0
  82. data/lib/uikit_rails/templates/components/label/label.css +25 -0
  83. data/lib/uikit_rails/templates/components/label/preview.yml +34 -0
  84. data/lib/uikit_rails/templates/components/pagination/USAGE +45 -0
  85. data/lib/uikit_rails/templates/components/pagination/component.html.erb +7 -0
  86. data/lib/uikit_rails/templates/components/pagination/component.rb +90 -0
  87. data/lib/uikit_rails/templates/components/pagination/pagination.css +89 -0
  88. data/lib/uikit_rails/templates/components/pagination/preview.yml +61 -0
  89. data/lib/uikit_rails/templates/components/popover/USAGE +44 -0
  90. data/lib/uikit_rails/templates/components/popover/component.html.erb +8 -0
  91. data/lib/uikit_rails/templates/components/popover/component.rb +19 -0
  92. data/lib/uikit_rails/templates/components/popover/popover.css +94 -0
  93. data/lib/uikit_rails/templates/components/popover/preview.yml +102 -0
  94. data/lib/uikit_rails/templates/components/progress/USAGE +15 -0
  95. data/lib/uikit_rails/templates/components/progress/component.html.erb +3 -0
  96. data/lib/uikit_rails/templates/components/progress/component.rb +38 -0
  97. data/lib/uikit_rails/templates/components/progress/preview.yml +44 -0
  98. data/lib/uikit_rails/templates/components/progress/progress.css +20 -0
  99. data/lib/uikit_rails/templates/components/select/USAGE +19 -0
  100. data/lib/uikit_rails/templates/components/select/component.rb +38 -0
  101. data/lib/uikit_rails/templates/components/select/preview.yml +61 -0
  102. data/lib/uikit_rails/templates/components/select/select.css +46 -0
  103. data/lib/uikit_rails/templates/components/separator/USAGE +15 -0
  104. data/lib/uikit_rails/templates/components/separator/component.rb +34 -0
  105. data/lib/uikit_rails/templates/components/separator/preview.yml +32 -0
  106. data/lib/uikit_rails/templates/components/separator/separator.css +21 -0
  107. data/lib/uikit_rails/templates/components/sheet/USAGE +44 -0
  108. data/lib/uikit_rails/templates/components/sheet/component.html.erb +23 -0
  109. data/lib/uikit_rails/templates/components/sheet/component.rb +23 -0
  110. data/lib/uikit_rails/templates/components/sheet/preview.yml +105 -0
  111. data/lib/uikit_rails/templates/components/sheet/sheet.css +193 -0
  112. data/lib/uikit_rails/templates/components/skeleton/USAGE +19 -0
  113. data/lib/uikit_rails/templates/components/skeleton/component.rb +38 -0
  114. data/lib/uikit_rails/templates/components/skeleton/preview.yml +44 -0
  115. data/lib/uikit_rails/templates/components/skeleton/skeleton.css +25 -0
  116. data/lib/uikit_rails/templates/components/switch/USAGE +19 -0
  117. data/lib/uikit_rails/templates/components/switch/component.html.erb +19 -0
  118. data/lib/uikit_rails/templates/components/switch/component.rb +23 -0
  119. data/lib/uikit_rails/templates/components/switch/preview.yml +43 -0
  120. data/lib/uikit_rails/templates/components/switch/switch.css +81 -0
  121. data/lib/uikit_rails/templates/components/table/USAGE +40 -0
  122. data/lib/uikit_rails/templates/components/table/component.html.erb +14 -0
  123. data/lib/uikit_rails/templates/components/table/component.rb +25 -0
  124. data/lib/uikit_rails/templates/components/table/preview.yml +109 -0
  125. data/lib/uikit_rails/templates/components/table/table.css +86 -0
  126. data/lib/uikit_rails/templates/components/tabs/USAGE +24 -0
  127. data/lib/uikit_rails/templates/components/tabs/component.html.erb +10 -0
  128. data/lib/uikit_rails/templates/components/tabs/component.rb +35 -0
  129. data/lib/uikit_rails/templates/components/tabs/preview.yml +60 -0
  130. data/lib/uikit_rails/templates/components/tabs/tabs.css +72 -0
  131. data/lib/uikit_rails/templates/components/textarea/USAGE +19 -0
  132. data/lib/uikit_rails/templates/components/textarea/component.rb +25 -0
  133. data/lib/uikit_rails/templates/components/textarea/preview.yml +47 -0
  134. data/lib/uikit_rails/templates/components/textarea/textarea.css +39 -0
  135. data/lib/uikit_rails/templates/components/toggle/USAGE +25 -0
  136. data/lib/uikit_rails/templates/components/toggle/component.rb +39 -0
  137. data/lib/uikit_rails/templates/components/toggle/preview.yml +81 -0
  138. data/lib/uikit_rails/templates/components/toggle/toggle.css +89 -0
  139. data/lib/uikit_rails/templates/components/tooltip/USAGE +23 -0
  140. data/lib/uikit_rails/templates/components/tooltip/component.html.erb +8 -0
  141. data/lib/uikit_rails/templates/components/tooltip/component.rb +19 -0
  142. data/lib/uikit_rails/templates/components/tooltip/preview.yml +52 -0
  143. data/lib/uikit_rails/templates/components/tooltip/tooltip.css +78 -0
  144. data/lib/uikit_rails/templates/stimulus/accordion_controller.js +19 -0
  145. data/lib/uikit_rails/templates/stimulus/alert_dialog_controller.js +25 -0
  146. data/lib/uikit_rails/templates/stimulus/collapsible_controller.js +9 -0
  147. data/lib/uikit_rails/templates/stimulus/dialog_controller.js +19 -0
  148. data/lib/uikit_rails/templates/stimulus/dropdown_controller.js +47 -0
  149. data/lib/uikit_rails/templates/stimulus/popover_controller.js +47 -0
  150. data/lib/uikit_rails/templates/stimulus/sheet_controller.js +19 -0
  151. data/lib/uikit_rails/templates/stimulus/tabs_controller.js +24 -0
  152. data/lib/uikit_rails/templates/stimulus/tooltip_controller.js +13 -0
  153. data/lib/uikit_rails/version.rb +5 -0
  154. data/lib/uikit_rails.rb +59 -0
  155. data/sig/uikit_rails.rbs +4 -0
  156. data/test_app/.dockerignore +51 -0
  157. data/test_app/.gitattributes +9 -0
  158. data/test_app/.github/dependabot.yml +12 -0
  159. data/test_app/.github/workflows/ci.yml +124 -0
  160. data/test_app/.gitignore +35 -0
  161. data/test_app/.kamal/hooks/docker-setup.sample +3 -0
  162. data/test_app/.kamal/hooks/post-app-boot.sample +3 -0
  163. data/test_app/.kamal/hooks/post-deploy.sample +14 -0
  164. data/test_app/.kamal/hooks/post-proxy-reboot.sample +3 -0
  165. data/test_app/.kamal/hooks/pre-app-boot.sample +3 -0
  166. data/test_app/.kamal/hooks/pre-build.sample +51 -0
  167. data/test_app/.kamal/hooks/pre-connect.sample +47 -0
  168. data/test_app/.kamal/hooks/pre-deploy.sample +122 -0
  169. data/test_app/.kamal/hooks/pre-proxy-reboot.sample +3 -0
  170. data/test_app/.kamal/secrets +20 -0
  171. data/test_app/.rubocop.yml +8 -0
  172. data/test_app/.ruby-version +1 -0
  173. data/test_app/Dockerfile +77 -0
  174. data/test_app/Gemfile +68 -0
  175. data/test_app/Gemfile.lock +587 -0
  176. data/test_app/README.md +24 -0
  177. data/test_app/Rakefile +6 -0
  178. data/test_app/app/assets/images/.keep +0 -0
  179. data/test_app/app/assets/stylesheets/application.css +10 -0
  180. data/test_app/app/assets/stylesheets/ui/accordion.css +74 -0
  181. data/test_app/app/assets/stylesheets/ui/alert.css +60 -0
  182. data/test_app/app/assets/stylesheets/ui/alert_dialog.css +108 -0
  183. data/test_app/app/assets/stylesheets/ui/avatar.css +53 -0
  184. data/test_app/app/assets/stylesheets/ui/badge.css +61 -0
  185. data/test_app/app/assets/stylesheets/ui/breadcrumb.css +55 -0
  186. data/test_app/app/assets/stylesheets/ui/button.css +125 -0
  187. data/test_app/app/assets/stylesheets/ui/card.css +63 -0
  188. data/test_app/app/assets/stylesheets/ui/checkbox.css +67 -0
  189. data/test_app/app/assets/stylesheets/ui/collapsible.css +55 -0
  190. data/test_app/app/assets/stylesheets/ui/dialog.css +133 -0
  191. data/test_app/app/assets/stylesheets/ui/dropdown.css +104 -0
  192. data/test_app/app/assets/stylesheets/ui/form.css +48 -0
  193. data/test_app/app/assets/stylesheets/ui/input.css +43 -0
  194. data/test_app/app/assets/stylesheets/ui/label.css +25 -0
  195. data/test_app/app/assets/stylesheets/ui/pagination.css +89 -0
  196. data/test_app/app/assets/stylesheets/ui/popover.css +94 -0
  197. data/test_app/app/assets/stylesheets/ui/progress.css +20 -0
  198. data/test_app/app/assets/stylesheets/ui/select.css +46 -0
  199. data/test_app/app/assets/stylesheets/ui/separator.css +21 -0
  200. data/test_app/app/assets/stylesheets/ui/sheet.css +193 -0
  201. data/test_app/app/assets/stylesheets/ui/skeleton.css +25 -0
  202. data/test_app/app/assets/stylesheets/ui/switch.css +81 -0
  203. data/test_app/app/assets/stylesheets/ui/table.css +86 -0
  204. data/test_app/app/assets/stylesheets/ui/tabs.css +72 -0
  205. data/test_app/app/assets/stylesheets/ui/textarea.css +39 -0
  206. data/test_app/app/assets/stylesheets/ui/toggle.css +89 -0
  207. data/test_app/app/assets/stylesheets/ui/tooltip.css +78 -0
  208. data/test_app/app/assets/stylesheets/uikit_rails.css +69 -0
  209. data/test_app/app/components/ui/accordion/component.html.erb +13 -0
  210. data/test_app/app/components/ui/accordion/component.rb +35 -0
  211. data/test_app/app/components/ui/accordion/preview.yml +81 -0
  212. data/test_app/app/components/ui/alert/component.html.erb +9 -0
  213. data/test_app/app/components/ui/alert/component.rb +27 -0
  214. data/test_app/app/components/ui/alert/preview.yml +53 -0
  215. data/test_app/app/components/ui/alert_dialog/component.html.erb +27 -0
  216. data/test_app/app/components/ui/alert_dialog/component.rb +23 -0
  217. data/test_app/app/components/ui/alert_dialog/preview.yml +94 -0
  218. data/test_app/app/components/ui/avatar/component.html.erb +7 -0
  219. data/test_app/app/components/ui/avatar/component.rb +31 -0
  220. data/test_app/app/components/ui/avatar/preview.yml +42 -0
  221. data/test_app/app/components/ui/badge/component.rb +28 -0
  222. data/test_app/app/components/ui/badge/preview.yml +38 -0
  223. data/test_app/app/components/ui/base_component.rb +32 -0
  224. data/test_app/app/components/ui/breadcrumb/component.html.erb +14 -0
  225. data/test_app/app/components/ui/breadcrumb/component.rb +40 -0
  226. data/test_app/app/components/ui/breadcrumb/preview.yml +42 -0
  227. data/test_app/app/components/ui/button/component.rb +44 -0
  228. data/test_app/app/components/ui/button/preview.yml +106 -0
  229. data/test_app/app/components/ui/card/component.html.erb +16 -0
  230. data/test_app/app/components/ui/card/component.rb +26 -0
  231. data/test_app/app/components/ui/card/preview.yml +57 -0
  232. data/test_app/app/components/ui/checkbox/component.html.erb +6 -0
  233. data/test_app/app/components/ui/checkbox/component.rb +26 -0
  234. data/test_app/app/components/ui/checkbox/preview.yml +43 -0
  235. data/test_app/app/components/ui/collapsible/component.html.erb +8 -0
  236. data/test_app/app/components/ui/collapsible/component.rb +18 -0
  237. data/test_app/app/components/ui/collapsible/preview.yml +65 -0
  238. data/test_app/app/components/ui/dialog/component.html.erb +23 -0
  239. data/test_app/app/components/ui/dialog/component.rb +20 -0
  240. data/test_app/app/components/ui/dialog/preview.yml +77 -0
  241. data/test_app/app/components/ui/dropdown/component.html.erb +14 -0
  242. data/test_app/app/components/ui/dropdown/component.rb +62 -0
  243. data/test_app/app/components/ui/dropdown/preview.yml +75 -0
  244. data/test_app/app/components/ui/form/USAGE +51 -0
  245. data/test_app/app/components/ui/form/builder.rb +233 -0
  246. data/test_app/app/components/ui/form/component.rb +258 -0
  247. data/test_app/app/components/ui/form/form.css +48 -0
  248. data/test_app/app/components/ui/form/preview.yml +95 -0
  249. data/test_app/app/components/ui/input/component.rb +25 -0
  250. data/test_app/app/components/ui/input/preview.yml +58 -0
  251. data/test_app/app/components/ui/label/component.rb +25 -0
  252. data/test_app/app/components/ui/label/preview.yml +34 -0
  253. data/test_app/app/components/ui/pagination/component.html.erb +7 -0
  254. data/test_app/app/components/ui/pagination/component.rb +90 -0
  255. data/test_app/app/components/ui/pagination/preview.yml +61 -0
  256. data/test_app/app/components/ui/popover/component.html.erb +8 -0
  257. data/test_app/app/components/ui/popover/component.rb +19 -0
  258. data/test_app/app/components/ui/popover/preview.yml +102 -0
  259. data/test_app/app/components/ui/progress/component.html.erb +3 -0
  260. data/test_app/app/components/ui/progress/component.rb +38 -0
  261. data/test_app/app/components/ui/progress/preview.yml +44 -0
  262. data/test_app/app/components/ui/select/component.rb +38 -0
  263. data/test_app/app/components/ui/select/preview.yml +61 -0
  264. data/test_app/app/components/ui/separator/component.rb +34 -0
  265. data/test_app/app/components/ui/separator/preview.yml +32 -0
  266. data/test_app/app/components/ui/sheet/component.html.erb +23 -0
  267. data/test_app/app/components/ui/sheet/component.rb +23 -0
  268. data/test_app/app/components/ui/sheet/preview.yml +105 -0
  269. data/test_app/app/components/ui/skeleton/component.rb +38 -0
  270. data/test_app/app/components/ui/skeleton/preview.yml +44 -0
  271. data/test_app/app/components/ui/switch/component.html.erb +19 -0
  272. data/test_app/app/components/ui/switch/component.rb +23 -0
  273. data/test_app/app/components/ui/switch/preview.yml +43 -0
  274. data/test_app/app/components/ui/table/component.html.erb +14 -0
  275. data/test_app/app/components/ui/table/component.rb +25 -0
  276. data/test_app/app/components/ui/table/preview.yml +109 -0
  277. data/test_app/app/components/ui/tabs/component.html.erb +10 -0
  278. data/test_app/app/components/ui/tabs/component.rb +35 -0
  279. data/test_app/app/components/ui/tabs/preview.yml +60 -0
  280. data/test_app/app/components/ui/textarea/component.rb +25 -0
  281. data/test_app/app/components/ui/textarea/preview.yml +47 -0
  282. data/test_app/app/components/ui/toggle/component.rb +39 -0
  283. data/test_app/app/components/ui/toggle/preview.yml +81 -0
  284. data/test_app/app/components/ui/tooltip/component.html.erb +8 -0
  285. data/test_app/app/components/ui/tooltip/component.rb +19 -0
  286. data/test_app/app/components/ui/tooltip/preview.yml +52 -0
  287. data/test_app/app/controllers/application_controller.rb +7 -0
  288. data/test_app/app/controllers/concerns/.keep +0 -0
  289. data/test_app/app/helpers/application_helper.rb +2 -0
  290. data/test_app/app/javascript/application.js +3 -0
  291. data/test_app/app/javascript/controllers/application.js +9 -0
  292. data/test_app/app/javascript/controllers/hello_controller.js +7 -0
  293. data/test_app/app/javascript/controllers/index.js +4 -0
  294. data/test_app/app/javascript/controllers/ui/accordion_controller.js +19 -0
  295. data/test_app/app/javascript/controllers/ui/alert_dialog_controller.js +25 -0
  296. data/test_app/app/javascript/controllers/ui/collapsible_controller.js +9 -0
  297. data/test_app/app/javascript/controllers/ui/dialog_controller.js +19 -0
  298. data/test_app/app/javascript/controllers/ui/dropdown_controller.js +47 -0
  299. data/test_app/app/javascript/controllers/ui/popover_controller.js +47 -0
  300. data/test_app/app/javascript/controllers/ui/sheet_controller.js +19 -0
  301. data/test_app/app/javascript/controllers/ui/tabs_controller.js +24 -0
  302. data/test_app/app/javascript/controllers/ui/tooltip_controller.js +13 -0
  303. data/test_app/app/jobs/application_job.rb +7 -0
  304. data/test_app/app/mailers/application_mailer.rb +4 -0
  305. data/test_app/app/models/application_record.rb +3 -0
  306. data/test_app/app/models/concerns/.keep +0 -0
  307. data/test_app/app/views/layouts/application.html.erb +29 -0
  308. data/test_app/app/views/layouts/mailer.html.erb +13 -0
  309. data/test_app/app/views/layouts/mailer.text.erb +1 -0
  310. data/test_app/app/views/pwa/manifest.json.erb +22 -0
  311. data/test_app/app/views/pwa/service-worker.js +26 -0
  312. data/test_app/bin/brakeman +7 -0
  313. data/test_app/bin/bundler-audit +6 -0
  314. data/test_app/bin/ci +6 -0
  315. data/test_app/bin/dev +2 -0
  316. data/test_app/bin/docker-entrypoint +8 -0
  317. data/test_app/bin/importmap +4 -0
  318. data/test_app/bin/jobs +6 -0
  319. data/test_app/bin/kamal +16 -0
  320. data/test_app/bin/rails +4 -0
  321. data/test_app/bin/rake +4 -0
  322. data/test_app/bin/rubocop +8 -0
  323. data/test_app/bin/setup +35 -0
  324. data/test_app/bin/thrust +5 -0
  325. data/test_app/config/application.rb +27 -0
  326. data/test_app/config/boot.rb +4 -0
  327. data/test_app/config/bundler-audit.yml +5 -0
  328. data/test_app/config/cable.yml +17 -0
  329. data/test_app/config/cache.yml +16 -0
  330. data/test_app/config/ci.rb +24 -0
  331. data/test_app/config/credentials.yml.enc +1 -0
  332. data/test_app/config/database.yml +40 -0
  333. data/test_app/config/deploy.yml +119 -0
  334. data/test_app/config/environment.rb +5 -0
  335. data/test_app/config/environments/development.rb +78 -0
  336. data/test_app/config/environments/production.rb +90 -0
  337. data/test_app/config/environments/test.rb +53 -0
  338. data/test_app/config/importmap.rb +7 -0
  339. data/test_app/config/initializers/assets.rb +7 -0
  340. data/test_app/config/initializers/content_security_policy.rb +29 -0
  341. data/test_app/config/initializers/filter_parameter_logging.rb +8 -0
  342. data/test_app/config/initializers/inflections.rb +16 -0
  343. data/test_app/config/locales/en.yml +31 -0
  344. data/test_app/config/puma.rb +42 -0
  345. data/test_app/config/queue.yml +18 -0
  346. data/test_app/config/recurring.yml +15 -0
  347. data/test_app/config/routes.rb +13 -0
  348. data/test_app/config/storage.yml +27 -0
  349. data/test_app/config.ru +6 -0
  350. data/test_app/db/cable_schema.rb +11 -0
  351. data/test_app/db/cache_schema.rb +12 -0
  352. data/test_app/db/queue_schema.rb +129 -0
  353. data/test_app/db/seeds.rb +9 -0
  354. data/test_app/lib/tasks/.keep +0 -0
  355. data/test_app/log/.keep +0 -0
  356. data/test_app/public/400.html +135 -0
  357. data/test_app/public/404.html +135 -0
  358. data/test_app/public/406-unsupported-browser.html +135 -0
  359. data/test_app/public/422.html +135 -0
  360. data/test_app/public/500.html +135 -0
  361. data/test_app/public/icon.png +0 -0
  362. data/test_app/public/icon.svg +3 -0
  363. data/test_app/public/robots.txt +1 -0
  364. data/test_app/script/.keep +0 -0
  365. data/test_app/storage/.keep +0 -0
  366. data/test_app/test/controllers/.keep +0 -0
  367. data/test_app/test/fixtures/files/.keep +0 -0
  368. data/test_app/test/helpers/.keep +0 -0
  369. data/test_app/test/integration/.keep +0 -0
  370. data/test_app/test/mailers/.keep +0 -0
  371. data/test_app/test/models/.keep +0 -0
  372. data/test_app/test/test_helper.rb +15 -0
  373. data/test_app/tmp/.keep +0 -0
  374. data/test_app/tmp/pids/.keep +0 -0
  375. data/test_app/tmp/storage/.keep +0 -0
  376. data/test_app/vendor/.keep +0 -0
  377. data/test_app/vendor/javascript/.keep +0 -0
  378. metadata +448 -0
@@ -0,0 +1,69 @@
1
+ /*
2
+ * UikitRails — Design Tokens
3
+ *
4
+ * Customize these CSS custom properties to match your brand.
5
+ * All UikitRails components reference these tokens so changing them
6
+ * here will update every component at once.
7
+ */
8
+
9
+ :root {
10
+ /* Colors */
11
+ --ui-background: #ffffff;
12
+ --ui-foreground: #0f172a;
13
+
14
+ --ui-primary: #0f172a;
15
+ --ui-primary-foreground: #ffffff;
16
+
17
+ --ui-secondary: #f1f5f9;
18
+ --ui-secondary-foreground: #0f172a;
19
+
20
+ --ui-destructive: #ef4444;
21
+ --ui-destructive-foreground: #ffffff;
22
+
23
+ --ui-muted: #f1f5f9;
24
+ --ui-muted-foreground: #64748b;
25
+
26
+ --ui-accent: #f1f5f9;
27
+ --ui-accent-foreground: #0f172a;
28
+
29
+ --ui-border: #e2e8f0;
30
+ --ui-input: #e2e8f0;
31
+ --ui-ring: #0f172a;
32
+
33
+ /* Spacing & Radii */
34
+ --ui-radius: 0.375rem;
35
+
36
+ /* Typography */
37
+ --ui-font-family: inherit;
38
+ --ui-font-size-xs: 0.75rem;
39
+ --ui-font-size-sm: 0.875rem;
40
+ --ui-font-size-base: 1rem;
41
+
42
+ /* Transitions */
43
+ --ui-transition-speed: 150ms;
44
+ }
45
+
46
+ /* Dark mode — add class="dark" to <html> or <body> */
47
+ .dark {
48
+ --ui-background: #0f172a;
49
+ --ui-foreground: #f8fafc;
50
+
51
+ --ui-primary: #f8fafc;
52
+ --ui-primary-foreground: #0f172a;
53
+
54
+ --ui-secondary: #1e293b;
55
+ --ui-secondary-foreground: #f8fafc;
56
+
57
+ --ui-destructive: #dc2626;
58
+ --ui-destructive-foreground: #f8fafc;
59
+
60
+ --ui-muted: #1e293b;
61
+ --ui-muted-foreground: #94a3b8;
62
+
63
+ --ui-accent: #1e293b;
64
+ --ui-accent-foreground: #f8fafc;
65
+
66
+ --ui-border: #1e293b;
67
+ --ui-input: #1e293b;
68
+ --ui-ring: #cbd5e1;
69
+ }
@@ -0,0 +1,13 @@
1
+ <div class="ui-accordion" data-controller="ui--accordion" data-ui--accordion-multiple-value="<%= multiple %>" <%= tag.attributes(html_attrs) %>>
2
+ <% items.each do |item| %>
3
+ <details class="ui-accordion__item" data-ui--accordion-target="item" data-action="toggle->ui--accordion#toggle" <%= "open" if item.open %> <%= tag.attributes(item.html_attrs) %>>
4
+ <summary class="ui-accordion__trigger">
5
+ <span><%= item.title %></span>
6
+ <svg class="ui-accordion__chevron" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
7
+ </summary>
8
+ <div class="ui-accordion__content">
9
+ <%= item.to_s %>
10
+ </div>
11
+ </details>
12
+ <% end %>
13
+ </div>
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ui
4
+ module Accordion
5
+ # Collapsible accordion with multiple items.
6
+ class Component < Ui::BaseComponent
7
+ renders_many :items, lambda { |title:, open: false, **html_attrs|
8
+ Item.new(title: title, open: open, **html_attrs)
9
+ }
10
+
11
+ attr_reader :multiple, :html_attrs
12
+
13
+ def initialize(multiple: false, **html_attrs)
14
+ @multiple = multiple
15
+ @html_attrs = html_attrs
16
+ super()
17
+ end
18
+
19
+ class Item < Ui::BaseComponent
20
+ attr_reader :title, :open, :html_attrs
21
+
22
+ def initialize(title:, open: false, **html_attrs)
23
+ @title = title
24
+ @open = open
25
+ @html_attrs = html_attrs
26
+ super()
27
+ end
28
+
29
+ def call
30
+ content
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,81 @@
1
+ description: Collapsible accordion for organizing content into expandable sections. Built on native details/summary for progressive enhancement. Supports single or multiple open items.
2
+
3
+ sections:
4
+ - title: Basic Accordion
5
+ examples:
6
+ - title: Single open (default)
7
+ code: |
8
+ <%= render Ui::Accordion::Component.new do |accordion| %>
9
+ <% accordion.with_item(title: "Is it accessible?") do %>
10
+ Yes. The accordion uses native HTML details/summary elements and follows WAI-ARIA patterns for keyboard navigation.
11
+ <% end %>
12
+ <% accordion.with_item(title: "Is it styled?") do %>
13
+ Yes. It ships with default styles using CSS custom properties that match your design system tokens.
14
+ <% end %>
15
+ <% accordion.with_item(title: "Is it animated?") do %>
16
+ The chevron icon rotates on open/close. Additional transitions can be added via CSS.
17
+ <% end %>
18
+ <% end %>
19
+
20
+ - title: Multiple Open
21
+ examples:
22
+ - title: Allow multiple sections open
23
+ code: |
24
+ <%= render Ui::Accordion::Component.new(multiple: true) do |accordion| %>
25
+ <% accordion.with_item(title: "Section One") do %>
26
+ <p>This section can stay open while others are opened too.</p>
27
+ <% end %>
28
+ <% accordion.with_item(title: "Section Two") do %>
29
+ <p>Multiple sections can be expanded simultaneously.</p>
30
+ <% end %>
31
+ <% accordion.with_item(title: "Section Three") do %>
32
+ <p>Each section operates independently.</p>
33
+ <% end %>
34
+ <% end %>
35
+
36
+ - title: Default Open
37
+ examples:
38
+ - title: Item open by default
39
+ code: |
40
+ <%= render Ui::Accordion::Component.new do |accordion| %>
41
+ <% accordion.with_item(title: "Closed by default") do %>
42
+ This item starts closed.
43
+ <% end %>
44
+ <% accordion.with_item(title: "Open by default", open: true) do %>
45
+ This item starts open and visible.
46
+ <% end %>
47
+ <% accordion.with_item(title: "Also closed") do %>
48
+ This item also starts closed.
49
+ <% end %>
50
+ <% end %>
51
+
52
+ - title: Rich Content
53
+ examples:
54
+ - title: With nested elements
55
+ code: |
56
+ <%= render Ui::Accordion::Component.new do |accordion| %>
57
+ <% accordion.with_item(title: "Getting Started") do %>
58
+ <p>Follow these steps to get started:</p>
59
+ <ol style="padding-left: 1.25rem; margin-top: 0.5rem;">
60
+ <li>Install the gem</li>
61
+ <li>Run the generator</li>
62
+ <li>Add components to your views</li>
63
+ </ol>
64
+ <% end %>
65
+ <% accordion.with_item(title: "Configuration") do %>
66
+ <p>Configure your components using the initializer file at <code>config/initializers/uikit_rails.rb</code>.</p>
67
+ <% end %>
68
+ <% end %>
69
+
70
+ - title: Custom Attributes
71
+ examples:
72
+ - title: With custom class
73
+ code: |
74
+ <%= render Ui::Accordion::Component.new(class: "my-faq", data: { turbo: false }) do |accordion| %>
75
+ <% accordion.with_item(title: "Question one?") do %>
76
+ Answer one.
77
+ <% end %>
78
+ <% accordion.with_item(title: "Question two?") do %>
79
+ Answer two.
80
+ <% end %>
81
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <%= content_tag :div, **computed_attrs do %>
2
+ <% if title? %>
3
+ <h5 class="ui-alert__title"><%= title %></h5>
4
+ <% end %>
5
+ <% if description? %>
6
+ <div class="ui-alert__description"><%= description %></div>
7
+ <% end %>
8
+ <%= content %>
9
+ <% end %>
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ui
4
+ module Alert
5
+ # Informational message with optional title and description.
6
+ class Component < Ui::BaseComponent
7
+ VARIANTS = %i[default destructive].freeze
8
+
9
+ renders_one :title
10
+ renders_one :description
11
+
12
+ attr_reader :variant, :html_attrs
13
+
14
+ def initialize(variant: :default, **html_attrs)
15
+ @variant = variant.to_sym
16
+ @html_attrs = html_attrs
17
+ super()
18
+ end
19
+
20
+ private
21
+
22
+ def computed_attrs
23
+ merge_attrs({ class: class_names("ui-alert", "ui-alert--#{variant}"), role: "alert" }, html_attrs)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ description: An informational message box with optional title and description. Supports default and destructive variants.
2
+
3
+ sections:
4
+ - title: Variants
5
+ examples:
6
+ - title: Default
7
+ code: |
8
+ <%= render Ui::Alert::Component.new do |alert| %>
9
+ <% alert.with_title do %>Heads up!<% end %>
10
+ <% alert.with_description do %>You can add components to your app using the CLI.<% end %>
11
+ <% end %>
12
+
13
+ - title: Destructive
14
+ code: |
15
+ <%= render Ui::Alert::Component.new(variant: :destructive) do |alert| %>
16
+ <% alert.with_title do %>Error<% end %>
17
+ <% alert.with_description do %>Your session has expired. Please log in again.<% end %>
18
+ <% end %>
19
+
20
+ - title: Content Variations
21
+ examples:
22
+ - title: Title only
23
+ code: |
24
+ <%= render Ui::Alert::Component.new do |alert| %>
25
+ <% alert.with_title do %>Everything is up to date.<% end %>
26
+ <% end %>
27
+
28
+ - title: Description only
29
+ code: |
30
+ <%= render Ui::Alert::Component.new do |alert| %>
31
+ <% alert.with_description do %>This action cannot be undone.<% end %>
32
+ <% end %>
33
+
34
+ - title: With body content
35
+ code: |
36
+ <%= render Ui::Alert::Component.new do |alert| %>
37
+ <% alert.with_title do %>Notice<% end %>
38
+ <% alert.with_description do %>Please review the following items.<% end %>
39
+ <ul><li>Item one</li><li>Item two</li></ul>
40
+ <% end %>
41
+
42
+ - title: With Custom Attributes
43
+ examples:
44
+ - title: Custom class and data attributes
45
+ code: |
46
+ <%= render Ui::Alert::Component.new(
47
+ variant: :destructive,
48
+ class: "my-custom-alert",
49
+ data: { controller: "dismissable" }
50
+ ) do |alert| %>
51
+ <% alert.with_title do %>Warning<% end %>
52
+ <% alert.with_description do %>Something went wrong.<% end %>
53
+ <% end %>
@@ -0,0 +1,27 @@
1
+ <div data-controller="ui--alert-dialog" <%= tag.attributes(html_attrs) %>>
2
+ <% if trigger? %>
3
+ <div data-action="click->ui--alert-dialog#open"><%= trigger %></div>
4
+ <% end %>
5
+ <dialog class="ui-alert-dialog" data-ui--alert-dialog-target="dialog">
6
+ <div class="ui-alert-dialog__overlay"></div>
7
+ <div class="ui-alert-dialog__content" role="alertdialog" aria-modal="true">
8
+ <% if title? || description? %>
9
+ <div class="ui-alert-dialog__header">
10
+ <% if title? %><h2 class="ui-alert-dialog__title"><%= title %></h2><% end %>
11
+ <% if description? %><p class="ui-alert-dialog__description"><%= description %></p><% end %>
12
+ </div>
13
+ <% end %>
14
+ <% if content? %>
15
+ <div class="ui-alert-dialog__body"><%= content %></div>
16
+ <% end %>
17
+ <div class="ui-alert-dialog__footer">
18
+ <% if cancel? %>
19
+ <div data-action="click->ui--alert-dialog#close"><%= cancel %></div>
20
+ <% end %>
21
+ <% if action? %>
22
+ <div data-action="click->ui--alert-dialog#close"><%= action %></div>
23
+ <% end %>
24
+ </div>
25
+ </div>
26
+ </dialog>
27
+ </div>
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ui
4
+ module AlertDialog
5
+ # Confirmation dialog that requires an explicit action to dismiss.
6
+ # Unlike Dialog, there is no close button — the user must choose
7
+ # cancel or confirm.
8
+ class Component < Ui::BaseComponent
9
+ renders_one :trigger
10
+ renders_one :title
11
+ renders_one :description
12
+ renders_one :cancel
13
+ renders_one :action
14
+
15
+ attr_reader :html_attrs
16
+
17
+ def initialize(**html_attrs)
18
+ @html_attrs = html_attrs
19
+ super()
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,94 @@
1
+ description: A confirmation dialog that interrupts the user and requires an explicit response. Unlike Dialog, there is no close button or backdrop dismiss — the user must choose cancel or confirm.
2
+
3
+ sections:
4
+ - title: Basic Alert Dialog
5
+ examples:
6
+ - title: Delete confirmation
7
+ code: |
8
+ <%= render Ui::AlertDialog::Component.new do |alert| %>
9
+ <% alert.with_trigger do %>
10
+ <%= render Ui::Button::Component.new(variant: :destructive) do %>Delete Account<% end %>
11
+ <% end %>
12
+ <% alert.with_title do %>Are you absolutely sure?<% end %>
13
+ <% alert.with_description do %>This action cannot be undone. This will permanently delete your account and remove your data from our servers.<% end %>
14
+ <% alert.with_cancel do %>
15
+ <%= render Ui::Button::Component.new(variant: :outline) do %>Cancel<% end %>
16
+ <% end %>
17
+ <% alert.with_action do %>
18
+ <%= render Ui::Button::Component.new(variant: :destructive) do %>Yes, delete account<% end %>
19
+ <% end %>
20
+ <% end %>
21
+
22
+ - title: Various Confirmations
23
+ examples:
24
+ - title: Discard changes
25
+ code: |
26
+ <%= render Ui::AlertDialog::Component.new do |alert| %>
27
+ <% alert.with_trigger do %>
28
+ <%= render Ui::Button::Component.new(variant: :outline) do %>Discard<% end %>
29
+ <% end %>
30
+ <% alert.with_title do %>Discard changes?<% end %>
31
+ <% alert.with_description do %>You have unsaved changes. Are you sure you want to discard them? This cannot be undone.<% end %>
32
+ <% alert.with_cancel do %>
33
+ <%= render Ui::Button::Component.new(variant: :outline) do %>Keep editing<% end %>
34
+ <% end %>
35
+ <% alert.with_action do %>
36
+ <%= render Ui::Button::Component.new(variant: :destructive) do %>Discard<% end %>
37
+ <% end %>
38
+ <% end %>
39
+
40
+ - title: Publish confirmation
41
+ code: |
42
+ <%= render Ui::AlertDialog::Component.new do |alert| %>
43
+ <% alert.with_trigger do %>
44
+ <%= render Ui::Button::Component.new do %>Publish<% end %>
45
+ <% end %>
46
+ <% alert.with_title do %>Publish this article?<% end %>
47
+ <% alert.with_description do %>Once published, this article will be visible to all users. You can unpublish it later from the dashboard.<% end %>
48
+ <% alert.with_cancel do %>
49
+ <%= render Ui::Button::Component.new(variant: :outline) do %>Not yet<% end %>
50
+ <% end %>
51
+ <% alert.with_action do %>
52
+ <%= render Ui::Button::Component.new do %>Yes, publish<% end %>
53
+ <% end %>
54
+ <% end %>
55
+
56
+ - title: With Body Content
57
+ examples:
58
+ - title: Alert with additional details
59
+ code: |
60
+ <%= render Ui::AlertDialog::Component.new do |alert| %>
61
+ <% alert.with_trigger do %>
62
+ <%= render Ui::Button::Component.new(variant: :outline) do %>Remove Members<% end %>
63
+ <% end %>
64
+ <% alert.with_title do %>Remove team members?<% end %>
65
+ <% alert.with_description do %>The following members will lose access immediately:<% end %>
66
+ <ul style="list-style:disc;padding-left:1.25rem;font-size:var(--ui-font-size-sm);line-height:1.75;">
67
+ <li>alice@example.com</li>
68
+ <li>bob@example.com</li>
69
+ </ul>
70
+ <% alert.with_cancel do %>
71
+ <%= render Ui::Button::Component.new(variant: :outline) do %>Cancel<% end %>
72
+ <% end %>
73
+ <% alert.with_action do %>
74
+ <%= render Ui::Button::Component.new(variant: :destructive) do %>Remove<% end %>
75
+ <% end %>
76
+ <% end %>
77
+
78
+ - title: Custom Attributes
79
+ examples:
80
+ - title: Alert dialog with custom data attributes
81
+ code: |
82
+ <%= render Ui::AlertDialog::Component.new(data: { turbo_frame: "modal" }) do |alert| %>
83
+ <% alert.with_trigger do %>
84
+ <%= render Ui::Button::Component.new(variant: :secondary) do %>Reset<% end %>
85
+ <% end %>
86
+ <% alert.with_title do %>Reset all settings?<% end %>
87
+ <% alert.with_description do %>This will restore all settings to their default values.<% end %>
88
+ <% alert.with_cancel do %>
89
+ <%= render Ui::Button::Component.new(variant: :outline) do %>Cancel<% end %>
90
+ <% end %>
91
+ <% alert.with_action do %>
92
+ <%= render Ui::Button::Component.new do %>Reset<% end %>
93
+ <% end %>
94
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <span <%= tag.attributes(computed_attrs) %>>
2
+ <% if src.present? %>
3
+ <img class="ui-avatar__image" src="<%= src %>" alt="<%= alt %>" />
4
+ <% else %>
5
+ <span class="ui-avatar__fallback"><%= fallback %></span>
6
+ <% end %>
7
+ </span>
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ui
4
+ module Avatar
5
+ # Circular avatar with image or fallback initials.
6
+ class Component < Ui::BaseComponent
7
+ SIZES = %i[sm md lg].freeze
8
+
9
+ attr_reader :src, :alt, :fallback, :size, :html_attrs
10
+
11
+ def initialize(src: nil, alt: "", fallback: nil, size: :md, **html_attrs)
12
+ @src = src
13
+ @alt = alt
14
+ @fallback = fallback || initials_from(alt)
15
+ @size = size.to_sym
16
+ @html_attrs = html_attrs
17
+ super()
18
+ end
19
+
20
+ private
21
+
22
+ def computed_attrs
23
+ merge_attrs({ class: class_names("ui-avatar", "ui-avatar--#{size}") }, html_attrs)
24
+ end
25
+
26
+ def initials_from(name)
27
+ name.to_s.split(/\s+/).map { |w| w[0] }.first(2).join.upcase
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,42 @@
1
+ description: A circular avatar that displays a user image or falls back to initials derived from the alt text.
2
+
3
+ sections:
4
+ - title: With Image
5
+ examples:
6
+ - title: Default (medium)
7
+ code: |
8
+ <%= render Ui::Avatar::Component.new(src: "https://i.pravatar.cc/80?u=jane", alt: "Jane Doe") %>
9
+
10
+ - title: Large with image
11
+ code: |
12
+ <%= render Ui::Avatar::Component.new(src: "https://i.pravatar.cc/80?u=john", alt: "John Smith", size: :lg) %>
13
+
14
+ - title: Fallback Initials
15
+ examples:
16
+ - title: Auto-generated initials from alt
17
+ code: |
18
+ <%= render Ui::Avatar::Component.new(alt: "Jane Doe") %>
19
+
20
+ - title: Custom fallback text
21
+ code: |
22
+ <%= render Ui::Avatar::Component.new(fallback: "?") %>
23
+
24
+ - title: Sizes
25
+ examples:
26
+ - title: Small
27
+ code: |
28
+ <%= render Ui::Avatar::Component.new(alt: "Alice Brown", size: :sm) %>
29
+
30
+ - title: Medium (default)
31
+ code: |
32
+ <%= render Ui::Avatar::Component.new(alt: "Alice Brown", size: :md) %>
33
+
34
+ - title: Large
35
+ code: |
36
+ <%= render Ui::Avatar::Component.new(alt: "Alice Brown", size: :lg) %>
37
+
38
+ - title: With Custom Attributes
39
+ examples:
40
+ - title: Custom class and data attributes
41
+ code: |
42
+ <%= render Ui::Avatar::Component.new(alt: "Jane Doe", class: "my-avatar", data: { controller: "tooltip" }) %>
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ui
4
+ module Badge
5
+ # Small status indicator with variant styles.
6
+ class Component < Ui::BaseComponent
7
+ VARIANTS = %i[default secondary destructive outline].freeze
8
+
9
+ attr_reader :variant, :html_attrs
10
+
11
+ def initialize(variant: :default, **html_attrs)
12
+ @variant = variant.to_sym
13
+ @html_attrs = html_attrs
14
+ super()
15
+ end
16
+
17
+ def call
18
+ content_tag(:span, content, **computed_attrs)
19
+ end
20
+
21
+ private
22
+
23
+ def computed_attrs
24
+ merge_attrs({ class: class_names("ui-badge", "ui-badge--#{variant}") }, html_attrs)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ description: A small status indicator rendered as a pill-shaped span with multiple variant styles.
2
+
3
+ sections:
4
+ - title: Variants
5
+ examples:
6
+ - title: Default
7
+ code: |
8
+ <%= render Ui::Badge::Component.new do %>Badge<% end %>
9
+
10
+ - title: Secondary
11
+ code: |
12
+ <%= render Ui::Badge::Component.new(variant: :secondary) do %>Secondary<% end %>
13
+
14
+ - title: Destructive
15
+ code: |
16
+ <%= render Ui::Badge::Component.new(variant: :destructive) do %>Destructive<% end %>
17
+
18
+ - title: Outline
19
+ code: |
20
+ <%= render Ui::Badge::Component.new(variant: :outline) do %>Outline<% end %>
21
+
22
+ - title: Usage Examples
23
+ examples:
24
+ - title: Status indicator
25
+ code: |
26
+ <%= render Ui::Badge::Component.new(variant: :secondary) do %>In Progress<% end %>
27
+
28
+ - title: Count badge
29
+ code: |
30
+ <%= render Ui::Badge::Component.new do %>3<% end %>
31
+
32
+ - title: With custom attributes
33
+ code: |
34
+ <%= render Ui::Badge::Component.new(
35
+ variant: :outline,
36
+ class: "my-custom-badge",
37
+ data: { role: "status" }
38
+ ) do %>Custom<% end %>
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ui
4
+ class BaseComponent < ViewComponent::Base
5
+ private
6
+
7
+ def class_names(*args)
8
+ args.flat_map { |arg|
9
+ case arg
10
+ when String
11
+ arg.split(/\s+/)
12
+ when Hash
13
+ arg.select { |_, v| v }.keys.map(&:to_s)
14
+ when nil
15
+ []
16
+ else
17
+ [arg.to_s]
18
+ end
19
+ }.reject(&:empty?).join(" ")
20
+ end
21
+
22
+ def merge_attrs(defaults, overrides)
23
+ defaults.merge(overrides) do |key, old_val, new_val|
24
+ case key
25
+ when :class then class_names(old_val, new_val)
26
+ when :style then [old_val, new_val].compact.join("; ")
27
+ else new_val
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,14 @@
1
+ <nav class="ui-breadcrumb" aria-label="Breadcrumb" <%= tag.attributes(html_attrs) %>>
2
+ <ol class="ui-breadcrumb__list">
3
+ <% items.each_with_index do |item, index| %>
4
+ <li class="ui-breadcrumb__item">
5
+ <%= item %>
6
+ </li>
7
+ <% unless index == items.size - 1 %>
8
+ <li class="ui-breadcrumb__separator" aria-hidden="true">
9
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
10
+ </li>
11
+ <% end %>
12
+ <% end %>
13
+ </ol>
14
+ </nav>