better_ui 0.6.0 → 0.7.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.
- checksums.yaml +4 -4
- data/README.md +257 -212
- data/Rakefile +11 -2
- data/app/components/better_ui/action_messages_component/action_messages_component.html.erb +48 -0
- data/app/components/better_ui/action_messages_component.rb +544 -0
- data/app/components/better_ui/application_component.rb +66 -0
- data/app/components/better_ui/button_component/button_component.html.erb +31 -0
- data/app/components/better_ui/button_component.rb +307 -0
- data/app/components/better_ui/card_component/card_component.html.erb +17 -0
- data/app/components/better_ui/card_component.rb +460 -0
- data/app/components/better_ui/drawer/header_component/header_component.html.erb +24 -0
- data/app/components/better_ui/drawer/header_component.rb +238 -0
- data/app/components/better_ui/drawer/layout_component/layout_component.html.erb +44 -0
- data/app/components/better_ui/drawer/layout_component.rb +270 -0
- data/app/components/better_ui/drawer/nav_group_component/nav_group_component.html.erb +10 -0
- data/app/components/better_ui/drawer/nav_group_component.rb +155 -0
- data/app/components/better_ui/drawer/nav_item_component/nav_item_component.html.erb +13 -0
- data/app/components/better_ui/drawer/nav_item_component.rb +225 -0
- data/app/components/better_ui/drawer/sidebar_component/sidebar_component.html.erb +17 -0
- data/app/components/better_ui/drawer/sidebar_component.rb +263 -0
- data/app/components/better_ui/forms/base_component.rb +450 -0
- data/app/components/better_ui/forms/checkbox_component/checkbox_component.html.erb +28 -0
- data/app/components/better_ui/forms/checkbox_component.rb +419 -0
- data/app/components/better_ui/forms/checkbox_group_component/checkbox_group_component.html.erb +40 -0
- data/app/components/better_ui/forms/checkbox_group_component.rb +363 -0
- data/app/components/better_ui/forms/number_input_component/number_input_component.html.erb +40 -0
- data/app/components/better_ui/forms/number_input_component.rb +320 -0
- data/app/components/better_ui/forms/password_input_component/password_input_component.html.erb +71 -0
- data/app/components/better_ui/forms/password_input_component.rb +206 -0
- data/app/components/better_ui/forms/text_input_component/text_input_component.html.erb +40 -0
- data/app/components/better_ui/forms/text_input_component.rb +258 -0
- data/app/components/better_ui/forms/textarea_component/textarea_component.html.erb +40 -0
- data/app/components/better_ui/forms/textarea_component.rb +329 -0
- data/app/form_builders/better_ui/ui_form_builder.rb +467 -0
- data/app/helpers/better_ui/application_helper.rb +325 -58
- data/app/views/layouts/better_ui/application.html.erb +1 -1
- data/config/routes.rb +1 -0
- data/lib/better_ui/engine.rb +34 -5
- data/lib/better_ui/version.rb +1 -1
- data/lib/better_ui.rb +32 -5
- data/lib/generators/better_ui/install/USAGE +44 -0
- data/lib/generators/better_ui/install/install_generator.rb +87 -0
- data/lib/generators/better_ui/install/templates/better_ui_theme.css.tt +280 -0
- data/lib/tasks/better_ui_tasks.rake +39 -4
- metadata +55 -203
- data/app/components/better_ui/application/card/component.html.erb +0 -20
- data/app/components/better_ui/application/card/component.rb +0 -214
- data/app/components/better_ui/application/main/component.html.erb +0 -9
- data/app/components/better_ui/application/main/component.rb +0 -123
- data/app/components/better_ui/application/navbar/component.html.erb +0 -92
- data/app/components/better_ui/application/navbar/component.rb +0 -136
- data/app/components/better_ui/application/sidebar/component.html.erb +0 -249
- data/app/components/better_ui/application/sidebar/component.rb +0 -187
- data/app/components/better_ui/general/accordion/component.html.erb +0 -5
- data/app/components/better_ui/general/accordion/component.rb +0 -92
- data/app/components/better_ui/general/accordion/item_component.html.erb +0 -12
- data/app/components/better_ui/general/accordion/item_component.rb +0 -176
- data/app/components/better_ui/general/alert/component.html.erb +0 -32
- data/app/components/better_ui/general/alert/component.rb +0 -242
- data/app/components/better_ui/general/avatar/component.html.erb +0 -20
- data/app/components/better_ui/general/avatar/component.rb +0 -301
- data/app/components/better_ui/general/badge/component.html.erb +0 -23
- data/app/components/better_ui/general/badge/component.rb +0 -248
- data/app/components/better_ui/general/breadcrumb/component.html.erb +0 -15
- data/app/components/better_ui/general/breadcrumb/component.rb +0 -187
- data/app/components/better_ui/general/button/component.html.erb +0 -34
- data/app/components/better_ui/general/button/component.rb +0 -214
- data/app/components/better_ui/general/divider/component.html.erb +0 -10
- data/app/components/better_ui/general/divider/component.rb +0 -226
- data/app/components/better_ui/general/dropdown/component.html.erb +0 -28
- data/app/components/better_ui/general/dropdown/component.rb +0 -192
- data/app/components/better_ui/general/dropdown/divider_component.html.erb +0 -1
- data/app/components/better_ui/general/dropdown/divider_component.rb +0 -41
- data/app/components/better_ui/general/dropdown/item_component.html.erb +0 -6
- data/app/components/better_ui/general/dropdown/item_component.rb +0 -119
- data/app/components/better_ui/general/field/component.html.erb +0 -27
- data/app/components/better_ui/general/field/component.rb +0 -37
- data/app/components/better_ui/general/grid/cell_component.html.erb +0 -3
- data/app/components/better_ui/general/grid/cell_component.rb +0 -390
- data/app/components/better_ui/general/grid/component.html.erb +0 -3
- data/app/components/better_ui/general/grid/component.rb +0 -301
- data/app/components/better_ui/general/heading/component.html.erb +0 -22
- data/app/components/better_ui/general/heading/component.rb +0 -257
- data/app/components/better_ui/general/icon/component.html.erb +0 -7
- data/app/components/better_ui/general/icon/component.rb +0 -240
- data/app/components/better_ui/general/input/checkbox/component.html.erb +0 -5
- data/app/components/better_ui/general/input/checkbox/component.rb +0 -238
- data/app/components/better_ui/general/input/datetime/component.html.erb +0 -5
- data/app/components/better_ui/general/input/datetime/component.rb +0 -223
- data/app/components/better_ui/general/input/pin/component.html.erb +0 -1
- data/app/components/better_ui/general/input/pin/component.rb +0 -201
- data/app/components/better_ui/general/input/radio/component.html.erb +0 -5
- data/app/components/better_ui/general/input/radio/component.rb +0 -230
- data/app/components/better_ui/general/input/rating/component.html.erb +0 -4
- data/app/components/better_ui/general/input/rating/component.rb +0 -272
- data/app/components/better_ui/general/input/select/component.html.erb +0 -78
- data/app/components/better_ui/general/input/select/component.rb +0 -249
- data/app/components/better_ui/general/input/select/select_component.html.erb +0 -5
- data/app/components/better_ui/general/input/select/select_component.rb +0 -37
- data/app/components/better_ui/general/input/text/component.html.erb +0 -5
- data/app/components/better_ui/general/input/text/component.rb +0 -171
- data/app/components/better_ui/general/input/textarea/component.html.erb +0 -5
- data/app/components/better_ui/general/input/textarea/component.rb +0 -166
- data/app/components/better_ui/general/input/toggle/component.html.erb +0 -5
- data/app/components/better_ui/general/input/toggle/component.rb +0 -242
- data/app/components/better_ui/general/link/component.html.erb +0 -18
- data/app/components/better_ui/general/link/component.rb +0 -258
- data/app/components/better_ui/general/modal/component.html.erb +0 -5
- data/app/components/better_ui/general/modal/component.rb +0 -47
- data/app/components/better_ui/general/modal/modal_component.html.erb +0 -52
- data/app/components/better_ui/general/modal/modal_component.rb +0 -160
- data/app/components/better_ui/general/pagination/component.html.erb +0 -85
- data/app/components/better_ui/general/pagination/component.rb +0 -216
- data/app/components/better_ui/general/panel/component.html.erb +0 -28
- data/app/components/better_ui/general/panel/component.rb +0 -249
- data/app/components/better_ui/general/progress/component.html.erb +0 -11
- data/app/components/better_ui/general/progress/component.rb +0 -160
- data/app/components/better_ui/general/spinner/component.html.erb +0 -35
- data/app/components/better_ui/general/spinner/component.rb +0 -93
- data/app/components/better_ui/general/table/component.html.erb +0 -5
- data/app/components/better_ui/general/table/component.rb +0 -217
- data/app/components/better_ui/general/table/tbody_component.html.erb +0 -3
- data/app/components/better_ui/general/table/tbody_component.rb +0 -30
- data/app/components/better_ui/general/table/td_component.html.erb +0 -3
- data/app/components/better_ui/general/table/td_component.rb +0 -44
- data/app/components/better_ui/general/table/tfoot_component.html.erb +0 -3
- data/app/components/better_ui/general/table/tfoot_component.rb +0 -28
- data/app/components/better_ui/general/table/th_component.html.erb +0 -6
- data/app/components/better_ui/general/table/th_component.rb +0 -51
- data/app/components/better_ui/general/table/thead_component.html.erb +0 -3
- data/app/components/better_ui/general/table/thead_component.rb +0 -28
- data/app/components/better_ui/general/table/tr_component.html.erb +0 -3
- data/app/components/better_ui/general/table/tr_component.rb +0 -30
- data/app/components/better_ui/general/tabs/component.html.erb +0 -11
- data/app/components/better_ui/general/tabs/component.rb +0 -120
- data/app/components/better_ui/general/tabs/panel_component.html.erb +0 -3
- data/app/components/better_ui/general/tabs/panel_component.rb +0 -37
- data/app/components/better_ui/general/tabs/tab_component.html.erb +0 -13
- data/app/components/better_ui/general/tabs/tab_component.rb +0 -111
- data/app/components/better_ui/general/tag/component.html.erb +0 -3
- data/app/components/better_ui/general/tag/component.rb +0 -104
- data/app/components/better_ui/general/text/component.html.erb +0 -1
- data/app/components/better_ui/general/text/component.rb +0 -194
- data/app/components/better_ui/general/tooltip/component.html.erb +0 -7
- data/app/components/better_ui/general/tooltip/component.rb +0 -239
- data/app/helpers/better_ui/application/components/card/card_helper.rb +0 -96
- data/app/helpers/better_ui/application/components/card.rb +0 -11
- data/app/helpers/better_ui/application/components/main/main_helper.rb +0 -64
- data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +0 -77
- data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +0 -51
- data/app/helpers/better_ui/general/components/accordion/accordion_helper.rb +0 -73
- data/app/helpers/better_ui/general/components/alert/alert_helper.rb +0 -57
- data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +0 -29
- data/app/helpers/better_ui/general/components/badge/badge_helper.rb +0 -53
- data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +0 -37
- data/app/helpers/better_ui/general/components/button/button_helper.rb +0 -65
- data/app/helpers/better_ui/general/components/container/container_helper.rb +0 -60
- data/app/helpers/better_ui/general/components/divider/divider_helper.rb +0 -63
- data/app/helpers/better_ui/general/components/dropdown/divider_helper.rb +0 -32
- data/app/helpers/better_ui/general/components/dropdown/dropdown_helper.rb +0 -88
- data/app/helpers/better_ui/general/components/dropdown/item_helper.rb +0 -68
- data/app/helpers/better_ui/general/components/field/field_helper.rb +0 -26
- data/app/helpers/better_ui/general/components/grid/grid_helper.rb +0 -145
- data/app/helpers/better_ui/general/components/heading/heading_helper.rb +0 -72
- data/app/helpers/better_ui/general/components/icon/icon_helper.rb +0 -16
- data/app/helpers/better_ui/general/components/input/checkbox/checkbox_helper.rb +0 -81
- data/app/helpers/better_ui/general/components/input/datetime/datetime_helper.rb +0 -91
- data/app/helpers/better_ui/general/components/input/pin/pin_helper.rb +0 -76
- data/app/helpers/better_ui/general/components/input/radio/radio_helper.rb +0 -79
- data/app/helpers/better_ui/general/components/input/radio_group/radio_group_helper.rb +0 -124
- data/app/helpers/better_ui/general/components/input/rating/rating_helper.rb +0 -70
- data/app/helpers/better_ui/general/components/input/select/select_helper.rb +0 -86
- data/app/helpers/better_ui/general/components/input/text/text_helper.rb +0 -138
- data/app/helpers/better_ui/general/components/input/textarea/textarea_helper.rb +0 -73
- data/app/helpers/better_ui/general/components/input/toggle/toggle_helper.rb +0 -77
- data/app/helpers/better_ui/general/components/link/link_helper.rb +0 -89
- data/app/helpers/better_ui/general/components/modal/modal_helper.rb +0 -85
- data/app/helpers/better_ui/general/components/pagination/pagination_helper.rb +0 -82
- data/app/helpers/better_ui/general/components/panel/panel_helper.rb +0 -83
- data/app/helpers/better_ui/general/components/progress/progress_helper.rb +0 -53
- data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +0 -19
- data/app/helpers/better_ui/general/components/table/table_helper.rb +0 -53
- data/app/helpers/better_ui/general/components/table/tbody_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/table/td_helper.rb +0 -19
- data/app/helpers/better_ui/general/components/table/tfoot_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/table/th_helper.rb +0 -19
- data/app/helpers/better_ui/general/components/table/thead_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/table/tr_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/tabs/panel_helper.rb +0 -62
- data/app/helpers/better_ui/general/components/tabs/tab_helper.rb +0 -55
- data/app/helpers/better_ui/general/components/tabs/tabs_helper.rb +0 -95
- data/app/helpers/better_ui/general/components/tag/tag_helper.rb +0 -26
- data/app/helpers/better_ui/general/components/text/text_helper.rb +0 -83
- data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +0 -60
- data/app/jobs/better_ui/application_job.rb +0 -4
- data/app/mailers/better_ui/application_mailer.rb +0 -6
- data/config/initializers/lookbook.rb +0 -23
- data/lib/better_ui/railtie.rb +0 -20
|
@@ -1,62 +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
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
#
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
61
328
|
end
|
|
62
329
|
end
|
data/config/routes.rb
CHANGED
data/lib/better_ui/engine.rb
CHANGED
|
@@ -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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
11
|
-
|
|
39
|
+
# Enable syntax highlighting for code examples
|
|
40
|
+
Lookbook.config.preview_srcdoc = true
|
|
12
41
|
end
|
|
13
42
|
end
|
|
14
43
|
end
|
data/lib/better_ui/version.rb
CHANGED
data/lib/better_ui.rb
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
require "better_ui/engine"
|
|
3
|
-
require "better_ui/railtie"
|
|
1
|
+
# frozen_string_literal: true
|
|
4
2
|
|
|
5
|
-
require "font-awesome-sass"
|
|
6
3
|
require "view_component"
|
|
4
|
+
require "tailwind_merge"
|
|
5
|
+
require "lookbook"
|
|
6
|
+
require "better_ui/version"
|
|
7
|
+
require "better_ui/engine"
|
|
7
8
|
|
|
8
9
|
module BetterUi
|
|
9
|
-
#
|
|
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
|
|
10
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
|