better_ui 0.3.0 → 0.7.0

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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +257 -212
  3. data/Rakefile +11 -2
  4. data/app/components/better_ui/action_messages_component/action_messages_component.html.erb +48 -0
  5. data/app/components/better_ui/action_messages_component.rb +544 -0
  6. data/app/components/better_ui/application_component.rb +66 -0
  7. data/app/components/better_ui/button_component/button_component.html.erb +31 -0
  8. data/app/components/better_ui/button_component.rb +307 -0
  9. data/app/components/better_ui/card_component/card_component.html.erb +17 -0
  10. data/app/components/better_ui/card_component.rb +460 -0
  11. data/app/components/better_ui/drawer/header_component/header_component.html.erb +24 -0
  12. data/app/components/better_ui/drawer/header_component.rb +238 -0
  13. data/app/components/better_ui/drawer/layout_component/layout_component.html.erb +44 -0
  14. data/app/components/better_ui/drawer/layout_component.rb +270 -0
  15. data/app/components/better_ui/drawer/nav_group_component/nav_group_component.html.erb +10 -0
  16. data/app/components/better_ui/drawer/nav_group_component.rb +155 -0
  17. data/app/components/better_ui/drawer/nav_item_component/nav_item_component.html.erb +13 -0
  18. data/app/components/better_ui/drawer/nav_item_component.rb +225 -0
  19. data/app/components/better_ui/drawer/sidebar_component/sidebar_component.html.erb +17 -0
  20. data/app/components/better_ui/drawer/sidebar_component.rb +263 -0
  21. data/app/components/better_ui/forms/base_component.rb +450 -0
  22. data/app/components/better_ui/forms/checkbox_component/checkbox_component.html.erb +28 -0
  23. data/app/components/better_ui/forms/checkbox_component.rb +419 -0
  24. data/app/components/better_ui/forms/checkbox_group_component/checkbox_group_component.html.erb +40 -0
  25. data/app/components/better_ui/forms/checkbox_group_component.rb +363 -0
  26. data/app/components/better_ui/forms/number_input_component/number_input_component.html.erb +40 -0
  27. data/app/components/better_ui/forms/number_input_component.rb +320 -0
  28. data/app/components/better_ui/forms/password_input_component/password_input_component.html.erb +71 -0
  29. data/app/components/better_ui/forms/password_input_component.rb +206 -0
  30. data/app/components/better_ui/forms/text_input_component/text_input_component.html.erb +40 -0
  31. data/app/components/better_ui/forms/text_input_component.rb +258 -0
  32. data/app/components/better_ui/forms/textarea_component/textarea_component.html.erb +40 -0
  33. data/app/components/better_ui/forms/textarea_component.rb +329 -0
  34. data/app/form_builders/better_ui/ui_form_builder.rb +467 -0
  35. data/app/helpers/better_ui/application_helper.rb +325 -51
  36. data/app/views/layouts/better_ui/application.html.erb +1 -1
  37. data/config/routes.rb +1 -0
  38. data/lib/better_ui/engine.rb +34 -5
  39. data/lib/better_ui/version.rb +1 -1
  40. data/lib/better_ui.rb +32 -4
  41. data/lib/generators/better_ui/install/USAGE +44 -0
  42. data/lib/generators/better_ui/install/install_generator.rb +87 -0
  43. data/lib/generators/better_ui/install/templates/better_ui_theme.css.tt +280 -0
  44. data/lib/tasks/better_ui_tasks.rake +39 -4
  45. metadata +52 -185
  46. data/app/components/better_ui/application/card/component.html.erb +0 -20
  47. data/app/components/better_ui/application/card/component.rb +0 -214
  48. data/app/components/better_ui/application/main/component.html.erb +0 -9
  49. data/app/components/better_ui/application/main/component.rb +0 -123
  50. data/app/components/better_ui/application/navbar/component.html.erb +0 -92
  51. data/app/components/better_ui/application/navbar/component.rb +0 -136
  52. data/app/components/better_ui/application/sidebar/component.html.erb +0 -227
  53. data/app/components/better_ui/application/sidebar/component.rb +0 -130
  54. data/app/components/better_ui/general/accordion/component.html.erb +0 -5
  55. data/app/components/better_ui/general/accordion/component.rb +0 -92
  56. data/app/components/better_ui/general/accordion/item_component.html.erb +0 -12
  57. data/app/components/better_ui/general/accordion/item_component.rb +0 -176
  58. data/app/components/better_ui/general/alert/component.html.erb +0 -32
  59. data/app/components/better_ui/general/alert/component.rb +0 -242
  60. data/app/components/better_ui/general/avatar/component.html.erb +0 -20
  61. data/app/components/better_ui/general/avatar/component.rb +0 -301
  62. data/app/components/better_ui/general/badge/component.html.erb +0 -23
  63. data/app/components/better_ui/general/badge/component.rb +0 -248
  64. data/app/components/better_ui/general/breadcrumb/component.html.erb +0 -15
  65. data/app/components/better_ui/general/breadcrumb/component.rb +0 -187
  66. data/app/components/better_ui/general/button/component.html.erb +0 -34
  67. data/app/components/better_ui/general/button/component.rb +0 -214
  68. data/app/components/better_ui/general/divider/component.html.erb +0 -10
  69. data/app/components/better_ui/general/divider/component.rb +0 -226
  70. data/app/components/better_ui/general/dropdown/component.html.erb +0 -25
  71. data/app/components/better_ui/general/dropdown/component.rb +0 -170
  72. data/app/components/better_ui/general/dropdown/divider_component.html.erb +0 -1
  73. data/app/components/better_ui/general/dropdown/divider_component.rb +0 -41
  74. data/app/components/better_ui/general/dropdown/item_component.html.erb +0 -6
  75. data/app/components/better_ui/general/dropdown/item_component.rb +0 -119
  76. data/app/components/better_ui/general/field/component.html.erb +0 -27
  77. data/app/components/better_ui/general/field/component.rb +0 -37
  78. data/app/components/better_ui/general/heading/component.html.erb +0 -22
  79. data/app/components/better_ui/general/heading/component.rb +0 -257
  80. data/app/components/better_ui/general/icon/component.html.erb +0 -7
  81. data/app/components/better_ui/general/icon/component.rb +0 -239
  82. data/app/components/better_ui/general/input/checkbox/component.html.erb +0 -5
  83. data/app/components/better_ui/general/input/checkbox/component.rb +0 -238
  84. data/app/components/better_ui/general/input/datetime/component.html.erb +0 -5
  85. data/app/components/better_ui/general/input/datetime/component.rb +0 -223
  86. data/app/components/better_ui/general/input/radio/component.html.erb +0 -5
  87. data/app/components/better_ui/general/input/radio/component.rb +0 -230
  88. data/app/components/better_ui/general/input/select/component.html.erb +0 -16
  89. data/app/components/better_ui/general/input/select/component.rb +0 -184
  90. data/app/components/better_ui/general/input/select/select_component.html.erb +0 -5
  91. data/app/components/better_ui/general/input/select/select_component.rb +0 -37
  92. data/app/components/better_ui/general/input/text/component.html.erb +0 -5
  93. data/app/components/better_ui/general/input/text/component.rb +0 -171
  94. data/app/components/better_ui/general/input/textarea/component.html.erb +0 -5
  95. data/app/components/better_ui/general/input/textarea/component.rb +0 -166
  96. data/app/components/better_ui/general/link/component.html.erb +0 -18
  97. data/app/components/better_ui/general/link/component.rb +0 -258
  98. data/app/components/better_ui/general/modal/component.html.erb +0 -5
  99. data/app/components/better_ui/general/modal/component.rb +0 -47
  100. data/app/components/better_ui/general/modal/modal_component.html.erb +0 -52
  101. data/app/components/better_ui/general/modal/modal_component.rb +0 -160
  102. data/app/components/better_ui/general/pagination/component.html.erb +0 -85
  103. data/app/components/better_ui/general/pagination/component.rb +0 -216
  104. data/app/components/better_ui/general/panel/component.html.erb +0 -28
  105. data/app/components/better_ui/general/panel/component.rb +0 -249
  106. data/app/components/better_ui/general/progress/component.html.erb +0 -11
  107. data/app/components/better_ui/general/progress/component.rb +0 -160
  108. data/app/components/better_ui/general/spinner/component.html.erb +0 -35
  109. data/app/components/better_ui/general/spinner/component.rb +0 -93
  110. data/app/components/better_ui/general/table/component.html.erb +0 -5
  111. data/app/components/better_ui/general/table/component.rb +0 -217
  112. data/app/components/better_ui/general/table/tbody_component.html.erb +0 -3
  113. data/app/components/better_ui/general/table/tbody_component.rb +0 -30
  114. data/app/components/better_ui/general/table/td_component.html.erb +0 -3
  115. data/app/components/better_ui/general/table/td_component.rb +0 -44
  116. data/app/components/better_ui/general/table/tfoot_component.html.erb +0 -3
  117. data/app/components/better_ui/general/table/tfoot_component.rb +0 -28
  118. data/app/components/better_ui/general/table/th_component.html.erb +0 -6
  119. data/app/components/better_ui/general/table/th_component.rb +0 -51
  120. data/app/components/better_ui/general/table/thead_component.html.erb +0 -3
  121. data/app/components/better_ui/general/table/thead_component.rb +0 -28
  122. data/app/components/better_ui/general/table/tr_component.html.erb +0 -3
  123. data/app/components/better_ui/general/table/tr_component.rb +0 -30
  124. data/app/components/better_ui/general/tabs/component.html.erb +0 -11
  125. data/app/components/better_ui/general/tabs/component.rb +0 -120
  126. data/app/components/better_ui/general/tabs/panel_component.html.erb +0 -3
  127. data/app/components/better_ui/general/tabs/panel_component.rb +0 -37
  128. data/app/components/better_ui/general/tabs/tab_component.html.erb +0 -13
  129. data/app/components/better_ui/general/tabs/tab_component.rb +0 -111
  130. data/app/components/better_ui/general/tag/component.html.erb +0 -3
  131. data/app/components/better_ui/general/tag/component.rb +0 -104
  132. data/app/components/better_ui/general/tooltip/component.html.erb +0 -7
  133. data/app/components/better_ui/general/tooltip/component.rb +0 -239
  134. data/app/helpers/better_ui/application/components/card/card_helper.rb +0 -96
  135. data/app/helpers/better_ui/application/components/card.rb +0 -11
  136. data/app/helpers/better_ui/application/components/main/main_helper.rb +0 -64
  137. data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +0 -77
  138. data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +0 -51
  139. data/app/helpers/better_ui/general/components/accordion/accordion_helper.rb +0 -73
  140. data/app/helpers/better_ui/general/components/accordion.rb +0 -11
  141. data/app/helpers/better_ui/general/components/alert/alert_helper.rb +0 -57
  142. data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +0 -29
  143. data/app/helpers/better_ui/general/components/badge/badge_helper.rb +0 -53
  144. data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +0 -37
  145. data/app/helpers/better_ui/general/components/button/button_helper.rb +0 -65
  146. data/app/helpers/better_ui/general/components/container/container_helper.rb +0 -60
  147. data/app/helpers/better_ui/general/components/divider/divider_helper.rb +0 -63
  148. data/app/helpers/better_ui/general/components/dropdown/divider_helper.rb +0 -32
  149. data/app/helpers/better_ui/general/components/dropdown/dropdown_helper.rb +0 -79
  150. data/app/helpers/better_ui/general/components/dropdown/item_helper.rb +0 -62
  151. data/app/helpers/better_ui/general/components/field/field_helper.rb +0 -26
  152. data/app/helpers/better_ui/general/components/heading/heading_helper.rb +0 -72
  153. data/app/helpers/better_ui/general/components/icon/icon_helper.rb +0 -16
  154. data/app/helpers/better_ui/general/components/input/checkbox/checkbox_helper.rb +0 -81
  155. data/app/helpers/better_ui/general/components/input/datetime/datetime_helper.rb +0 -91
  156. data/app/helpers/better_ui/general/components/input/radio/radio_helper.rb +0 -79
  157. data/app/helpers/better_ui/general/components/input/radio_group/radio_group_helper.rb +0 -124
  158. data/app/helpers/better_ui/general/components/input/select/select_helper.rb +0 -70
  159. data/app/helpers/better_ui/general/components/input/text/text_helper.rb +0 -138
  160. data/app/helpers/better_ui/general/components/input/textarea/textarea_helper.rb +0 -73
  161. data/app/helpers/better_ui/general/components/link/link_helper.rb +0 -89
  162. data/app/helpers/better_ui/general/components/modal/modal_helper.rb +0 -85
  163. data/app/helpers/better_ui/general/components/modal.rb +0 -11
  164. data/app/helpers/better_ui/general/components/pagination/pagination_helper.rb +0 -82
  165. data/app/helpers/better_ui/general/components/panel/panel_helper.rb +0 -83
  166. data/app/helpers/better_ui/general/components/progress/progress_helper.rb +0 -53
  167. data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +0 -19
  168. data/app/helpers/better_ui/general/components/table/table_helper.rb +0 -53
  169. data/app/helpers/better_ui/general/components/table/tbody_helper.rb +0 -13
  170. data/app/helpers/better_ui/general/components/table/td_helper.rb +0 -19
  171. data/app/helpers/better_ui/general/components/table/tfoot_helper.rb +0 -13
  172. data/app/helpers/better_ui/general/components/table/th_helper.rb +0 -19
  173. data/app/helpers/better_ui/general/components/table/thead_helper.rb +0 -13
  174. data/app/helpers/better_ui/general/components/table/tr_helper.rb +0 -13
  175. data/app/helpers/better_ui/general/components/tabs/panel_helper.rb +0 -62
  176. data/app/helpers/better_ui/general/components/tabs/tab_helper.rb +0 -55
  177. data/app/helpers/better_ui/general/components/tabs/tabs_helper.rb +0 -95
  178. data/app/helpers/better_ui/general/components/tag/tag_helper.rb +0 -26
  179. data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +0 -60
  180. data/app/jobs/better_ui/application_job.rb +0 -4
  181. data/app/mailers/better_ui/application_mailer.rb +0 -6
  182. data/config/initializers/lookbook.rb +0 -23
  183. data/lib/better_ui/railtie.rb +0 -20
@@ -1,55 +1,329 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterUi
4
+ # View helpers for rendering BetterUi components with a concise API.
5
+ #
6
+ # All helpers follow the `bui_<component>` naming convention and delegate
7
+ # to the corresponding ViewComponent class.
8
+ #
9
+ # @example Basic button
10
+ # <%= bui_button(variant: :primary) { "Click me" } %>
11
+ #
12
+ # @example Card with slots
13
+ # <%= bui_card(variant: :success) do |card| %>
14
+ # <% card.with_header { "Title" } %>
15
+ # <% card.with_body { "Content" } %>
16
+ # <% end %>
2
17
  module ApplicationHelper
3
- # Inclusione dei moduli aggregatori per i componenti application
4
- # Questo assicura che tutti gli helper specifici dei componenti siano disponibili.
5
-
6
- # General Components
7
- include General::Components::Accordion::AccordionHelper
8
- include General::Components::Alert::AlertHelper
9
- include General::Components::Avatar::AvatarHelper
10
- include General::Components::Badge::BadgeHelper
11
- include General::Components::Breadcrumb::BreadcrumbHelper
12
- include General::Components::Button::ButtonHelper
13
- include General::Components::Divider::DividerHelper
14
- include General::Components::Dropdown::DropdownHelper
15
- include General::Components::Dropdown::ItemHelper
16
- include General::Components::Dropdown::DividerHelper
17
- include General::Components::Heading::HeadingHelper
18
- include General::Components::Icon::IconHelper
19
- include General::Components::Link::LinkHelper
20
- include General::Components::Modal::ModalHelper
21
- include General::Components::Pagination::PaginationHelper
22
- include General::Components::Panel::PanelHelper
23
- include General::Components::Progress::ProgressHelper
24
- include General::Components::Spinner::SpinnerHelper
25
- include General::Components::Tag::TagHelper
26
- include General::Components::Tooltip::TooltipHelper
27
-
28
- include General::Components::Table::TableHelper
29
- include General::Components::Table::TbodyHelper
30
- include General::Components::Table::TdHelper
31
- include General::Components::Table::TfootHelper
32
- include General::Components::Table::ThHelper
33
- include General::Components::Table::TheadHelper
34
- include General::Components::Table::TrHelper
35
-
36
- include General::Components::Tabs::TabsHelper
37
- include General::Components::Tabs::TabHelper
38
- include General::Components::Tabs::PanelHelper
39
-
40
- # General Form Components
41
- include General::Components::Input::Checkbox::CheckboxHelper
42
- include General::Components::Input::Datetime::DatetimeHelper
43
- include General::Components::Input::Radio::RadioHelper
44
- include General::Components::Input::RadioGroup::RadioGroupHelper
45
- include General::Components::Input::Select::SelectHelper
46
- include General::Components::Input::Text::TextHelper
47
- include General::Components::Input::Textarea::TextareaHelper
48
-
49
- # Application Components
50
- include Application::Components::Main::MainHelper
51
- include Application::Components::Navbar::NavbarHelper
52
- include Application::Components::Sidebar::SidebarHelper
53
- include Application::Components::Card::CardHelper
18
+ # ============================================
19
+ # Core Components
20
+ # ============================================
21
+
22
+ # Renders a button component.
23
+ #
24
+ # @param options [Hash] Options passed to ButtonComponent
25
+ # @option options [Symbol] :variant Color variant (:primary, :secondary, :accent, :success, :danger, :warning, :info, :light, :dark)
26
+ # @option options [Symbol] :style Button style (:solid, :outline, :ghost, :soft)
27
+ # @option options [Symbol] :size Size (:xs, :sm, :md, :lg, :xl)
28
+ # @option options [Boolean] :show_loader Show loading spinner
29
+ # @option options [Boolean] :show_loader_on_click Show loader on click
30
+ # @option options [Boolean] :disabled Disable the button
31
+ # @option options [Symbol] :type Button type (:button, :submit, :reset)
32
+ # @yield Button content
33
+ # @return [String] Rendered HTML
34
+ #
35
+ # @example Simple button
36
+ # <%= bui_button(variant: :primary) { "Click me" } %>
37
+ #
38
+ # @example Submit button with loader
39
+ # <%= bui_button(type: :submit, show_loader_on_click: true) { "Save" } %>
40
+ def bui_button(**options, &block)
41
+ render BetterUi::ButtonComponent.new(**options), &block
42
+ end
43
+
44
+ # Renders a card component.
45
+ #
46
+ # @param options [Hash] Options passed to CardComponent
47
+ # @option options [Symbol] :variant Color variant
48
+ # @option options [Symbol] :style Card style (:solid, :outline, :ghost, :soft, :bordered)
49
+ # @option options [Symbol] :size Size (:xs, :sm, :md, :lg, :xl)
50
+ # @option options [Boolean] :shadow Show shadow
51
+ # @yield [card] Block with card slots
52
+ # @yieldparam card [BetterUi::CardComponent] The card component for slot access
53
+ # @return [String] Rendered HTML
54
+ #
55
+ # @example Card with header and body
56
+ # <%= bui_card(variant: :primary) do |card| %>
57
+ # <% card.with_header { "Title" } %>
58
+ # <% card.with_body { "Content goes here" } %>
59
+ # <% card.with_footer { "Footer" } %>
60
+ # <% end %>
61
+ def bui_card(**options, &block)
62
+ render BetterUi::CardComponent.new(**options), &block
63
+ end
64
+
65
+ # Renders action messages (alerts/flash messages).
66
+ #
67
+ # @param messages [Array<String>] Messages to display
68
+ # @param options [Hash] Options passed to ActionMessagesComponent
69
+ # @option options [Symbol] :variant Color variant
70
+ # @option options [Symbol] :style Alert style (:solid, :soft, :outline, :ghost)
71
+ # @option options [Boolean] :dismissible Allow dismissing
72
+ # @option options [Integer, Float, nil] :auto_dismiss Auto-dismiss after seconds
73
+ # @option options [String, nil] :title Alert title
74
+ # @return [String] Rendered HTML
75
+ #
76
+ # @example Success message
77
+ # <%= bui_action_messages(["Saved successfully!"], variant: :success, dismissible: true) %>
78
+ #
79
+ # @example Error messages
80
+ # <%= bui_action_messages(@errors, variant: :danger, title: "Errors occurred") %>
81
+ def bui_action_messages(messages = [], **options)
82
+ render BetterUi::ActionMessagesComponent.new(messages: messages, **options)
83
+ end
84
+
85
+ # ============================================
86
+ # Form Components
87
+ # ============================================
88
+
89
+ # Renders a text input component.
90
+ #
91
+ # @param name [String] Input name attribute
92
+ # @param options [Hash] Options passed to Forms::TextInputComponent
93
+ # @option options [String, nil] :value Input value
94
+ # @option options [String, nil] :label Label text
95
+ # @option options [String, nil] :hint Hint text
96
+ # @option options [String, nil] :placeholder Placeholder text
97
+ # @option options [Symbol] :size Size (:xs, :sm, :md, :lg, :xl)
98
+ # @option options [Boolean] :disabled Disabled state
99
+ # @option options [Boolean] :readonly Readonly state
100
+ # @option options [Boolean] :required Required field
101
+ # @option options [Array<String>, String, nil] :errors Error messages
102
+ # @yield [input] Block with input slots
103
+ # @return [String] Rendered HTML
104
+ #
105
+ # @example Basic text input
106
+ # <%= bui_text_input("email", label: "Email", placeholder: "you@example.com") %>
107
+ #
108
+ # @example With icon
109
+ # <%= bui_text_input("search") do |input| %>
110
+ # <% input.with_prefix_icon { icon_svg } %>
111
+ # <% end %>
112
+ def bui_text_input(name, **options, &block)
113
+ render BetterUi::Forms::TextInputComponent.new(name: name, **options), &block
114
+ end
115
+
116
+ # Renders a number input component.
117
+ #
118
+ # @param name [String] Input name attribute
119
+ # @param options [Hash] Options passed to Forms::NumberInputComponent
120
+ # @option options [Numeric, nil] :value Input value
121
+ # @option options [String, nil] :label Label text
122
+ # @option options [Numeric, nil] :min Minimum value
123
+ # @option options [Numeric, nil] :max Maximum value
124
+ # @option options [Numeric, nil] :step Step value
125
+ # @option options [Boolean] :show_spinner Show up/down arrows (default: true)
126
+ # @yield [input] Block with input slots
127
+ # @return [String] Rendered HTML
128
+ #
129
+ # @example Number input with range
130
+ # <%= bui_number_input("quantity", min: 1, max: 100, label: "Quantity") %>
131
+ #
132
+ # @example Price input
133
+ # <%= bui_number_input("price", step: 0.01) do |input| %>
134
+ # <% input.with_prefix_icon { "$" } %>
135
+ # <% end %>
136
+ def bui_number_input(name, **options, &block)
137
+ render BetterUi::Forms::NumberInputComponent.new(name: name, **options), &block
138
+ end
139
+
140
+ # Renders a password input component with visibility toggle.
141
+ #
142
+ # @param name [String] Input name attribute
143
+ # @param options [Hash] Options passed to Forms::PasswordInputComponent
144
+ # @option options [String, nil] :label Label text
145
+ # @option options [String, nil] :hint Hint text
146
+ # @option options [Symbol] :size Size (:xs, :sm, :md, :lg, :xl)
147
+ # @yield [input] Block with input slots
148
+ # @return [String] Rendered HTML
149
+ #
150
+ # @example Password input
151
+ # <%= bui_password_input("password", label: "Password", hint: "Min 8 characters") %>
152
+ def bui_password_input(name, **options, &block)
153
+ render BetterUi::Forms::PasswordInputComponent.new(name: name, **options), &block
154
+ end
155
+
156
+ # Renders a textarea component.
157
+ #
158
+ # @param name [String] Input name attribute
159
+ # @param options [Hash] Options passed to Forms::TextareaComponent
160
+ # @option options [String, nil] :value Textarea content
161
+ # @option options [String, nil] :label Label text
162
+ # @option options [Integer] :rows Number of visible rows (default: 4)
163
+ # @option options [Integer, nil] :cols Width in characters
164
+ # @option options [Integer, nil] :maxlength Maximum characters
165
+ # @option options [Symbol] :resize Resize behavior (:none, :vertical, :horizontal, :both)
166
+ # @yield [textarea] Block with textarea slots
167
+ # @return [String] Rendered HTML
168
+ #
169
+ # @example Textarea with maxlength
170
+ # <%= bui_textarea("bio", rows: 6, maxlength: 500, label: "Bio") %>
171
+ def bui_textarea(name, **options, &block)
172
+ render BetterUi::Forms::TextareaComponent.new(name: name, **options), &block
173
+ end
174
+
175
+ # Renders a checkbox component.
176
+ #
177
+ # @param name [String] Input name attribute
178
+ # @param options [Hash] Options passed to Forms::CheckboxComponent
179
+ # @option options [String] :value Value when checked (default: "1")
180
+ # @option options [Boolean] :checked Checked state
181
+ # @option options [String, nil] :label Label text
182
+ # @option options [String, nil] :hint Hint text
183
+ # @option options [Symbol] :variant Color variant (:primary, :secondary, etc.)
184
+ # @option options [Symbol] :size Size (:xs, :sm, :md, :lg, :xl)
185
+ # @option options [Symbol] :label_position Label position (:left, :right)
186
+ # @option options [Boolean] :disabled Disabled state
187
+ # @option options [Boolean] :readonly Readonly state
188
+ # @option options [Boolean] :required Required field
189
+ # @option options [Array<String>, String, nil] :errors Error messages
190
+ # @return [String] Rendered HTML
191
+ #
192
+ # @example Basic checkbox
193
+ # <%= bui_checkbox("newsletter", label: "Subscribe to newsletter") %>
194
+ #
195
+ # @example Checkbox with variant
196
+ # <%= bui_checkbox("active", label: "Active", variant: :success, checked: true) %>
197
+ def bui_checkbox(name, **options)
198
+ render BetterUi::Forms::CheckboxComponent.new(name: name, **options)
199
+ end
200
+
201
+ # Renders a checkbox group component.
202
+ #
203
+ # @param name [String] Input name attribute (will have [] appended for array submission)
204
+ # @param collection [Array] Collection of options (values or [label, value] pairs)
205
+ # @param options [Hash] Options passed to Forms::CheckboxGroupComponent
206
+ # @option options [Array] :selected Currently selected values
207
+ # @option options [String, nil] :legend Legend text for the fieldset
208
+ # @option options [String, nil] :hint Hint text
209
+ # @option options [Symbol] :variant Color variant (:primary, :secondary, etc.)
210
+ # @option options [Symbol] :size Size (:xs, :sm, :md, :lg, :xl)
211
+ # @option options [Symbol] :orientation Layout orientation (:vertical, :horizontal)
212
+ # @option options [Boolean] :disabled Disabled state
213
+ # @option options [Boolean] :required Required field
214
+ # @option options [Array<String>, String, nil] :errors Error messages
215
+ # @return [String] Rendered HTML
216
+ #
217
+ # @example Basic checkbox group
218
+ # <%= bui_checkbox_group("roles", ["Admin", "Editor", "Viewer"], legend: "Roles") %>
219
+ #
220
+ # @example With label/value pairs and selected values
221
+ # <%= bui_checkbox_group("permissions",
222
+ # [["Read", "read"], ["Write", "write"]],
223
+ # selected: ["read"],
224
+ # orientation: :horizontal
225
+ # ) %>
226
+ def bui_checkbox_group(name, collection, **options)
227
+ render BetterUi::Forms::CheckboxGroupComponent.new(name: name, collection: collection, **options)
228
+ end
229
+
230
+ # ============================================
231
+ # Drawer Components
232
+ # ============================================
233
+
234
+ # Renders a drawer layout component with header, sidebar, and main content areas.
235
+ #
236
+ # @param options [Hash] Options passed to Drawer::LayoutComponent
237
+ # @option options [Symbol] :sidebar_position Sidebar position (:left, :right)
238
+ # @option options [Symbol] :sidebar_breakpoint Desktop breakpoint (:md, :lg, :xl)
239
+ # @yield [layout] Block with layout slots
240
+ # @yieldparam layout [BetterUi::Drawer::LayoutComponent] The layout component
241
+ # @return [String] Rendered HTML
242
+ #
243
+ # @example Full layout
244
+ # <%= bui_drawer_layout(sidebar_position: :left) do |layout| %>
245
+ # <% layout.with_header { render_header } %>
246
+ # <% layout.with_sidebar { render_sidebar } %>
247
+ # <% layout.with_main { yield } %>
248
+ # <% end %>
249
+ def bui_drawer_layout(**options, &block)
250
+ render BetterUi::Drawer::LayoutComponent.new(**options), &block
251
+ end
252
+
253
+ # Renders a drawer sidebar component.
254
+ #
255
+ # @param options [Hash] Options passed to Drawer::SidebarComponent
256
+ # @option options [Symbol] :variant Color variant (:light, :dark, :primary)
257
+ # @option options [Symbol] :position Position (:left, :right)
258
+ # @option options [Symbol] :width Width (:sm, :md, :lg)
259
+ # @option options [Boolean] :collapsible Allow collapsing
260
+ # @yield [sidebar] Block with sidebar slots
261
+ # @return [String] Rendered HTML
262
+ #
263
+ # @example Sidebar with navigation
264
+ # <%= bui_drawer_sidebar(variant: :dark) do |sidebar| %>
265
+ # <% sidebar.with_header { "App Name" } %>
266
+ # <% sidebar.with_navigation { render_nav } %>
267
+ # <% sidebar.with_footer { render_footer } %>
268
+ # <% end %>
269
+ def bui_drawer_sidebar(**options, &block)
270
+ render BetterUi::Drawer::SidebarComponent.new(**options), &block
271
+ end
272
+
273
+ # Renders a drawer header component.
274
+ #
275
+ # @param options [Hash] Options passed to Drawer::HeaderComponent
276
+ # @option options [Symbol] :variant Color variant (:light, :dark, :transparent, :primary)
277
+ # @option options [Boolean] :sticky Sticky positioning (default: true)
278
+ # @option options [Symbol] :height Height (:sm, :md, :lg)
279
+ # @yield [header] Block with header slots
280
+ # @return [String] Rendered HTML
281
+ #
282
+ # @example Header with logo and navigation
283
+ # <%= bui_drawer_header(variant: :light) do |header| %>
284
+ # <% header.with_logo { image_tag("logo.svg") } %>
285
+ # <% header.with_navigation { render_nav } %>
286
+ # <% header.with_actions { render_actions } %>
287
+ # <% header.with_mobile_menu_button { hamburger_button } %>
288
+ # <% end %>
289
+ def bui_drawer_header(**options, &block)
290
+ render BetterUi::Drawer::HeaderComponent.new(**options), &block
291
+ end
292
+
293
+ # Renders a drawer navigation item.
294
+ #
295
+ # @param label [String] Item label text
296
+ # @param href [String] Link URL
297
+ # @param options [Hash] Options passed to Drawer::NavItemComponent
298
+ # @option options [Boolean] :active Active state
299
+ # @option options [Symbol, nil] :method HTTP method (:get, :post, :put, :patch, :delete)
300
+ # @option options [Symbol] :variant Color variant (:light, :dark, :primary)
301
+ # @yield [item] Block with item slots
302
+ # @return [String] Rendered HTML
303
+ #
304
+ # @example Navigation item with icon
305
+ # <%= bui_drawer_nav_item("Dashboard", dashboard_path, active: true) do |item| %>
306
+ # <% item.with_icon { dashboard_icon } %>
307
+ # <% end %>
308
+ def bui_drawer_nav_item(label, href, **options, &block)
309
+ render BetterUi::Drawer::NavItemComponent.new(label: label, href: href, **options), &block
310
+ end
311
+
312
+ # Renders a drawer navigation group with title and items.
313
+ #
314
+ # @param options [Hash] Options passed to Drawer::NavGroupComponent
315
+ # @option options [String, nil] :title Group title
316
+ # @option options [Symbol] :variant Color variant (:light, :dark, :primary)
317
+ # @yield [group] Block with group slots
318
+ # @return [String] Rendered HTML
319
+ #
320
+ # @example Navigation group with items
321
+ # <%= bui_drawer_nav_group(title: "Main Menu") do |group| %>
322
+ # <% group.with_item(label: "Home", href: root_path) %>
323
+ # <% group.with_item(label: "Settings", href: settings_path) %>
324
+ # <% end %>
325
+ def bui_drawer_nav_group(**options, &block)
326
+ render BetterUi::Drawer::NavGroupComponent.new(**options), &block
327
+ end
54
328
  end
55
329
  end
@@ -9,7 +9,7 @@
9
9
 
10
10
  <%= stylesheet_link_tag "better_ui/application", media: "all" %>
11
11
  </head>
12
- <body style="padding: 10px;">
12
+ <body>
13
13
 
14
14
  <%= yield %>
15
15
 
data/config/routes.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  BetterUi::Engine.routes.draw do
2
+ mount Lookbook::Engine, at: "/lookbook"
2
3
  end
@@ -1,14 +1,43 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterUi
2
4
  class Engine < ::Rails::Engine
3
5
  isolate_namespace BetterUi
4
6
 
5
- initializer "better_ui.view_helpers" do
6
- ActiveSupport.on_load :action_controller do
7
- helper BetterUi::ApplicationHelper if defined?(BetterUi::ApplicationHelper)
7
+ # Configure Zeitwerk autoloading for the engine
8
+ config.autoload_paths += %W[
9
+ #{root}/lib
10
+ ]
11
+
12
+ # Ignore non-autoloadable directories
13
+ initializer "better_ui.autoload_ignore", before: :set_autoload_paths do
14
+ Rails.autoloaders.main.ignore(
15
+ "#{root}/lib/tasks",
16
+ "#{root}/lib/generators"
17
+ )
18
+ end
19
+
20
+ # Configure ViewComponent preview paths (must run before Lookbook)
21
+ initializer "better_ui.view_component", before: :load_config_initializers do |app|
22
+ # Add engine preview paths to ViewComponent using absolute paths
23
+ if app.config.respond_to?(:view_component)
24
+ # Use the correct configuration: previews.paths (not preview_paths or previews_paths)
25
+ app.config.view_component.previews.paths << root.join("spec/components/previews").to_s
8
26
  end
27
+ end
28
+
29
+ # Configure Lookbook for component previews (must run before Lookbook scans for previews)
30
+ initializer "better_ui.lookbook", before: "lookbook.set_autoload_paths" do |app|
31
+ # Only configure Lookbook if it's available
32
+ if defined?(Lookbook)
33
+ # Add engine preview paths to Lookbook with absolute path
34
+ Lookbook.config.preview_paths << root.join("spec/components/previews").to_s
35
+
36
+ # Configure Lookbook to work with the engine namespace
37
+ Lookbook.config.project_name = "BetterUi Components"
9
38
 
10
- ActiveSupport.on_load :action_view do
11
- include BetterUi::ApplicationHelper if defined?(BetterUi::ApplicationHelper)
39
+ # Enable syntax highlighting for code examples
40
+ Lookbook.config.preview_srcdoc = true
12
41
  end
13
42
  end
14
43
  end
@@ -1,3 +1,3 @@
1
1
  module BetterUi
2
- VERSION = "0.3.0"
2
+ VERSION = "0.7.0"
3
3
  end
data/lib/better_ui.rb CHANGED
@@ -1,9 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "view_component"
4
+ require "tailwind_merge"
5
+ require "lookbook"
1
6
  require "better_ui/version"
2
7
  require "better_ui/engine"
3
- require "better_ui/railtie"
4
-
5
- require "font-awesome-sass"
6
8
 
7
9
  module BetterUi
8
- # Your code goes here...
10
+ # Returns an array of paths where BetterUi templates are located.
11
+ # This is useful for debugging and documentation purposes.
12
+ #
13
+ # @return [Array<String>] Array of absolute paths to template directories
14
+ #
15
+ # @example
16
+ # BetterUi.template_paths
17
+ # # => ["/path/to/gem/app/views", "/path/to/gem/app/components"]
18
+ def self.template_paths
19
+ root = Engine.root
20
+ [
21
+ root.join("app", "views").to_s,
22
+ root.join("app", "components").to_s
23
+ ].select { |path| Dir.exist?(path) }
24
+ end
25
+
26
+ # Returns the root path of the BetterUi gem.
27
+ # This is useful when you need to reference gem assets or files.
28
+ #
29
+ # @return [Pathname] The root path of the gem
30
+ #
31
+ # @example
32
+ # BetterUi.root
33
+ # # => #<Pathname:/path/to/better_ui>
34
+ def self.root
35
+ Engine.root
36
+ end
9
37
  end
@@ -0,0 +1,44 @@
1
+ Description:
2
+ The install generator sets up BetterUi in your Rails application by creating
3
+ the necessary theme file and configuring Tailwind CSS v4 to work with the gem.
4
+
5
+ Example:
6
+ bin/rails generate better_ui:install
7
+
8
+ This will create:
9
+ app/assets/stylesheets/better_ui_theme.css
10
+ app/assets/stylesheets/application.postcss.css (or update existing)
11
+
12
+ What it does:
13
+ 1. Creates a theme file (better_ui_theme.css) with:
14
+ - 9 color variants (primary, secondary, accent, success, danger, warning, info, light, dark)
15
+ - Full OKLCH color scales (50-950) for each variant
16
+ - Typography tokens (font families)
17
+ - Spacing and sizing tokens
18
+ - Border radius tokens
19
+ - Shadow tokens
20
+ - Utility classes for common patterns
21
+
22
+ 2. Creates or updates application.postcss.css to:
23
+ - Import Tailwind CSS v4
24
+ - Import the BetterUi theme
25
+ - Configure @source directives to scan:
26
+ * Gem templates in vendor/bundle
27
+ * Application views and templates
28
+ * JavaScript files
29
+
30
+ Post-installation:
31
+ 1. Install Tailwind CSS v4:
32
+ npm install tailwindcss@next @tailwindcss/postcss@next
33
+
34
+ 2. Configure PostCSS (postcss.config.js):
35
+ module.exports = {
36
+ plugins: [
37
+ require('@tailwindcss/postcss')
38
+ ]
39
+ }
40
+
41
+ 3. Customize your theme in app/assets/stylesheets/better_ui_theme.css
42
+
43
+ 4. Use BetterUi components in your views:
44
+ <%= render BetterUi::ButtonComponent.new(label: "Click me") %>
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+
5
+ module BetterUi
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ class_option :copy_theme, type: :boolean, default: false,
11
+ desc: "Copy theme CSS file for customization instead of using npm package default"
12
+
13
+ desc "Installs BetterUi npm package and configures your Rails application"
14
+
15
+ def install_npm_package
16
+ say "Installing @pandev-srl/better-ui npm package...", :green
17
+
18
+ if File.exist?(File.join(destination_root, "yarn.lock"))
19
+ run "yarn add @pandev-srl/better-ui"
20
+ elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
21
+ run "pnpm add @pandev-srl/better-ui"
22
+ else
23
+ run "npm install @pandev-srl/better-ui"
24
+ end
25
+ end
26
+
27
+ def copy_theme_file
28
+ return unless options[:copy_theme]
29
+
30
+ say "Copying BetterUi theme file for customization...", :green
31
+ template "better_ui_theme.css.tt", "app/assets/stylesheets/better_ui_theme.css"
32
+ end
33
+
34
+ def show_post_install_message
35
+ say "\n"
36
+ say "=" * 80, :green
37
+ say "BetterUi installation complete!", :green
38
+ say "=" * 80, :green
39
+ say "\n"
40
+
41
+ say "JavaScript Setup:", :cyan
42
+ say " Add to your JavaScript entry point (e.g., app/javascript/application.js):"
43
+ say ""
44
+ say " import { Application } from \"@hotwired/stimulus\""
45
+ say " import { registerControllers } from \"@pandev-srl/better-ui\""
46
+ say ""
47
+ say " const application = Application.start()"
48
+ say " registerControllers(application)"
49
+ say "\n"
50
+
51
+ say "CSS Setup:", :cyan
52
+
53
+ if options[:copy_theme]
54
+ say " Theme file copied to: app/assets/stylesheets/better_ui_theme.css"
55
+ say " Import in your main CSS file:"
56
+ say ""
57
+ say " @import \"tailwindcss\";"
58
+ say " @import \"./better_ui_theme.css\";"
59
+ else
60
+ say " Add to your main CSS file (e.g., app/assets/stylesheets/application.css):"
61
+ say ""
62
+ say " /* Option 1: Import pre-built CSS */"
63
+ say " @import \"@pandev-srl/better-ui/css\";"
64
+ say ""
65
+ say " /* Option 2: Import individual modules for customization */"
66
+ say " @import \"tailwindcss\";"
67
+ say " @import \"@pandev-srl/better-ui/theme\"; /* Design tokens */"
68
+ say " @import \"@pandev-srl/better-ui/typography\"; /* Typography utilities */"
69
+ say " @import \"@pandev-srl/better-ui/utilities\"; /* General utilities */"
70
+ end
71
+
72
+ say "\n"
73
+ say "Tailwind Configuration:", :cyan
74
+ say " Ensure Tailwind scans BetterUi components for classes:"
75
+ say " Add to your CSS file:"
76
+ say ""
77
+ say " @source \"../../../vendor/bundle/**/*.{rb,erb}\";"
78
+ say "\n"
79
+
80
+ say "Usage:", :cyan
81
+ say " <%= render BetterUi::ButtonComponent.new(label: \"Click me\") %>"
82
+ say "\n"
83
+ say "=" * 80, :green
84
+ end
85
+ end
86
+ end
87
+ end