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
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterUi
|
|
4
|
+
# A flexible card component for displaying content in a styled container.
|
|
5
|
+
#
|
|
6
|
+
# This component provides a versatile box container with support for multiple color variants,
|
|
7
|
+
# visual styles, sizes, and optional header/footer sections. Perfect for displaying grouped
|
|
8
|
+
# content, information panels, dashboards, and feature highlights.
|
|
9
|
+
#
|
|
10
|
+
# @example Basic card
|
|
11
|
+
# <%= render BetterUi::CardComponent.new do %>
|
|
12
|
+
# Card content here
|
|
13
|
+
# <% end %>
|
|
14
|
+
#
|
|
15
|
+
# @example Card with header and footer
|
|
16
|
+
# <%= render BetterUi::CardComponent.new(variant: :primary, style: :outline) do |card| %>
|
|
17
|
+
# <% card.with_header { "Card Title" } %>
|
|
18
|
+
# <% card.with_body { "Main content goes here" } %>
|
|
19
|
+
# <% card.with_footer { "Footer actions" } %>
|
|
20
|
+
# <% end %>
|
|
21
|
+
#
|
|
22
|
+
# @example Transparent card
|
|
23
|
+
# <%= render BetterUi::CardComponent.new(style: :ghost) do %>
|
|
24
|
+
# Transparent card content
|
|
25
|
+
# <% end %>
|
|
26
|
+
#
|
|
27
|
+
# @example Large success card without shadow
|
|
28
|
+
# <%= render BetterUi::CardComponent.new(variant: :success, size: :lg, shadow: false) do |card| %>
|
|
29
|
+
# <% card.with_header { "Success!" } %>
|
|
30
|
+
# <% card.with_body { "Operation completed successfully" } %>
|
|
31
|
+
# <% end %>
|
|
32
|
+
#
|
|
33
|
+
# @example Different styles
|
|
34
|
+
# # Solid (default): Filled colored background
|
|
35
|
+
# <%= render BetterUi::CardComponent.new(style: :solid) { "Solid card" } %>
|
|
36
|
+
#
|
|
37
|
+
# # Outline: White background with colored border
|
|
38
|
+
# <%= render BetterUi::CardComponent.new(style: :outline) { "Outline card" } %>
|
|
39
|
+
#
|
|
40
|
+
# # Ghost: Transparent background
|
|
41
|
+
# <%= render BetterUi::CardComponent.new(style: :ghost) { "Ghost card" } %>
|
|
42
|
+
#
|
|
43
|
+
# # Soft: Light colored background
|
|
44
|
+
# <%= render BetterUi::CardComponent.new(style: :soft) { "Soft card" } %>
|
|
45
|
+
#
|
|
46
|
+
# # Bordered: Neutral gray border (variant-agnostic)
|
|
47
|
+
# <%= render BetterUi::CardComponent.new(style: :bordered) { "Bordered card" } %>
|
|
48
|
+
class CardComponent < ApplicationComponent
|
|
49
|
+
# Size configurations for padding, text, and border radius
|
|
50
|
+
SIZES = {
|
|
51
|
+
xs: { padding: "p-3", text: "text-xs", radius: "rounded" },
|
|
52
|
+
sm: { padding: "p-4", text: "text-sm", radius: "rounded-md" },
|
|
53
|
+
md: { padding: "p-6", text: "text-base", radius: "rounded-lg" },
|
|
54
|
+
lg: { padding: "p-8", text: "text-lg", radius: "rounded-lg" },
|
|
55
|
+
xl: { padding: "p-10", text: "text-xl", radius: "rounded-xl" }
|
|
56
|
+
}.freeze
|
|
57
|
+
|
|
58
|
+
# Available visual styles
|
|
59
|
+
STYLES = %i[solid outline ghost soft bordered].freeze
|
|
60
|
+
|
|
61
|
+
# @!method with_header
|
|
62
|
+
# Slot for rendering optional header content at the top of the card.
|
|
63
|
+
# The header is separated from the body with a divider.
|
|
64
|
+
# @yieldreturn [String] the HTML content for the header
|
|
65
|
+
renders_one :header
|
|
66
|
+
|
|
67
|
+
# @!method with_body
|
|
68
|
+
# Slot for rendering the main body content of the card.
|
|
69
|
+
# If not provided, the card will render its default content in the body.
|
|
70
|
+
# @yieldreturn [String] the HTML content for the body
|
|
71
|
+
renders_one :body
|
|
72
|
+
|
|
73
|
+
# @!method with_footer
|
|
74
|
+
# Slot for rendering optional footer content at the bottom of the card.
|
|
75
|
+
# The footer is separated from the body with a divider.
|
|
76
|
+
# @yieldreturn [String] the HTML content for the footer
|
|
77
|
+
renders_one :footer
|
|
78
|
+
|
|
79
|
+
# Initializes a new card component.
|
|
80
|
+
#
|
|
81
|
+
# @param variant [Symbol] the color variant (:primary, :secondary, :accent, :success, :danger, :warning, :info, :light, :dark), defaults to :primary
|
|
82
|
+
# @param style [Symbol] the visual style (:solid, :outline, :ghost, :soft, :bordered), defaults to :solid
|
|
83
|
+
# @param size [Symbol] the size variant (:xs, :sm, :md, :lg, :xl), defaults to :md
|
|
84
|
+
# @param shadow [Boolean] whether to apply shadow, defaults to true
|
|
85
|
+
# @param header_padding [Boolean] whether to apply padding to header section, defaults to true
|
|
86
|
+
# @param body_padding [Boolean] whether to apply padding to body section, defaults to true
|
|
87
|
+
# @param footer_padding [Boolean] whether to apply padding to footer section, defaults to true
|
|
88
|
+
# @param container_classes [String, nil] additional CSS classes for the outer wrapper
|
|
89
|
+
# @param header_classes [String, nil] additional CSS classes for the header section
|
|
90
|
+
# @param body_classes [String, nil] additional CSS classes for the body section
|
|
91
|
+
# @param footer_classes [String, nil] additional CSS classes for the footer section
|
|
92
|
+
# @param options [Hash] additional HTML attributes passed to the card element
|
|
93
|
+
#
|
|
94
|
+
# @raise [ArgumentError] if variant is not one of the allowed values
|
|
95
|
+
# @raise [ArgumentError] if style is not one of the allowed values
|
|
96
|
+
# @raise [ArgumentError] if size is not one of the allowed values
|
|
97
|
+
#
|
|
98
|
+
# @example With all options
|
|
99
|
+
# <%= render BetterUi::CardComponent.new(
|
|
100
|
+
# variant: :primary,
|
|
101
|
+
# style: :outline,
|
|
102
|
+
# size: :lg,
|
|
103
|
+
# shadow: true,
|
|
104
|
+
# container_classes: "mb-4",
|
|
105
|
+
# id: "my-card",
|
|
106
|
+
# data: { controller: "custom" }
|
|
107
|
+
# ) do |card| %>
|
|
108
|
+
# <% card.with_header { "Title" } %>
|
|
109
|
+
# <% card.with_body { "Content" } %>
|
|
110
|
+
# <% end %>
|
|
111
|
+
#
|
|
112
|
+
# @example Full-width image with no body padding
|
|
113
|
+
# <%= render BetterUi::CardComponent.new(body_padding: false) do |card| %>
|
|
114
|
+
# <% card.with_header { "Gallery" } %>
|
|
115
|
+
# <% card.with_body do %>
|
|
116
|
+
# <%= image_tag "photo.jpg", class: "w-full" %>
|
|
117
|
+
# <% end %>
|
|
118
|
+
# <% end %>
|
|
119
|
+
#
|
|
120
|
+
# @example Table container with no padding
|
|
121
|
+
# <%= render BetterUi::CardComponent.new(
|
|
122
|
+
# body_padding: false,
|
|
123
|
+
# style: :bordered
|
|
124
|
+
# ) do |card| %>
|
|
125
|
+
# <% card.with_body do %>
|
|
126
|
+
# <table class="w-full">...</table>
|
|
127
|
+
# <% end %>
|
|
128
|
+
# <% end %>
|
|
129
|
+
def initialize(
|
|
130
|
+
variant: :primary,
|
|
131
|
+
style: :solid,
|
|
132
|
+
size: :md,
|
|
133
|
+
shadow: true,
|
|
134
|
+
header_padding: true,
|
|
135
|
+
body_padding: true,
|
|
136
|
+
footer_padding: true,
|
|
137
|
+
container_classes: nil,
|
|
138
|
+
header_classes: nil,
|
|
139
|
+
body_classes: nil,
|
|
140
|
+
footer_classes: nil,
|
|
141
|
+
**options
|
|
142
|
+
)
|
|
143
|
+
@variant = validate_variant(variant)
|
|
144
|
+
@style = validate_style(style)
|
|
145
|
+
@size = validate_size(size)
|
|
146
|
+
@shadow = shadow
|
|
147
|
+
@header_padding = header_padding
|
|
148
|
+
@body_padding = body_padding
|
|
149
|
+
@footer_padding = footer_padding
|
|
150
|
+
@container_classes = container_classes
|
|
151
|
+
@header_classes = header_classes
|
|
152
|
+
@body_classes = body_classes
|
|
153
|
+
@footer_classes = footer_classes
|
|
154
|
+
@options = options
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
|
|
159
|
+
# Returns the complete CSS classes for the card container.
|
|
160
|
+
#
|
|
161
|
+
# @return [String] the merged CSS class string
|
|
162
|
+
# @api private
|
|
163
|
+
def component_classes
|
|
164
|
+
css_classes([
|
|
165
|
+
"flex",
|
|
166
|
+
"flex-col",
|
|
167
|
+
size_config[:radius],
|
|
168
|
+
size_config[:text],
|
|
169
|
+
style_classes,
|
|
170
|
+
shadow_classes,
|
|
171
|
+
@container_classes
|
|
172
|
+
].flatten.compact)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Returns CSS classes specific to the selected style.
|
|
176
|
+
#
|
|
177
|
+
# @return [Array<String>] array of CSS classes for the style
|
|
178
|
+
# @api private
|
|
179
|
+
def style_classes
|
|
180
|
+
case @style
|
|
181
|
+
when :solid then solid_classes
|
|
182
|
+
when :outline then outline_classes
|
|
183
|
+
when :ghost then ghost_classes
|
|
184
|
+
when :soft then soft_classes
|
|
185
|
+
when :bordered then bordered_classes
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Returns CSS classes for solid style.
|
|
190
|
+
# Filled background with subtle border and dark text.
|
|
191
|
+
#
|
|
192
|
+
# @return [Array<String>] array of CSS classes
|
|
193
|
+
# @api private
|
|
194
|
+
def solid_classes
|
|
195
|
+
case @variant
|
|
196
|
+
when :primary
|
|
197
|
+
[ "bg-primary-50", "border", "border-primary-200", "text-primary-900" ]
|
|
198
|
+
when :secondary
|
|
199
|
+
[ "bg-secondary-50", "border", "border-secondary-200", "text-secondary-900" ]
|
|
200
|
+
when :accent
|
|
201
|
+
[ "bg-accent-50", "border", "border-accent-200", "text-accent-900" ]
|
|
202
|
+
when :success
|
|
203
|
+
[ "bg-success-50", "border", "border-success-200", "text-success-900" ]
|
|
204
|
+
when :danger
|
|
205
|
+
[ "bg-danger-50", "border", "border-danger-200", "text-danger-900" ]
|
|
206
|
+
when :warning
|
|
207
|
+
[ "bg-warning-50", "border", "border-warning-200", "text-warning-900" ]
|
|
208
|
+
when :info
|
|
209
|
+
[ "bg-info-50", "border", "border-info-200", "text-info-900" ]
|
|
210
|
+
when :light
|
|
211
|
+
[ "bg-light", "border", "border-grayscale-200", "text-grayscale-900" ]
|
|
212
|
+
when :dark
|
|
213
|
+
[ "bg-dark", "border", "border-grayscale-700", "text-grayscale-50" ]
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Returns CSS classes for outline style.
|
|
218
|
+
# White background with colored border.
|
|
219
|
+
#
|
|
220
|
+
# @return [Array<String>] array of CSS classes
|
|
221
|
+
# @api private
|
|
222
|
+
def outline_classes
|
|
223
|
+
case @variant
|
|
224
|
+
when :primary
|
|
225
|
+
[ "bg-white", "border-2", "border-primary-500", "text-primary-700" ]
|
|
226
|
+
when :secondary
|
|
227
|
+
[ "bg-white", "border-2", "border-secondary-500", "text-secondary-700" ]
|
|
228
|
+
when :accent
|
|
229
|
+
[ "bg-white", "border-2", "border-accent-500", "text-accent-700" ]
|
|
230
|
+
when :success
|
|
231
|
+
[ "bg-white", "border-2", "border-success-500", "text-success-700" ]
|
|
232
|
+
when :danger
|
|
233
|
+
[ "bg-white", "border-2", "border-danger-500", "text-danger-700" ]
|
|
234
|
+
when :warning
|
|
235
|
+
[ "bg-white", "border-2", "border-warning-500", "text-warning-700" ]
|
|
236
|
+
when :info
|
|
237
|
+
[ "bg-white", "border-2", "border-info-500", "text-info-700" ]
|
|
238
|
+
when :light
|
|
239
|
+
[ "bg-white", "border-2", "border-grayscale-300", "text-grayscale-700" ]
|
|
240
|
+
when :dark
|
|
241
|
+
[ "bg-white", "border-2", "border-grayscale-900", "text-grayscale-900" ]
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Returns CSS classes for ghost style.
|
|
246
|
+
# Transparent background with colored text (for transparent cards).
|
|
247
|
+
#
|
|
248
|
+
# @return [Array<String>] array of CSS classes
|
|
249
|
+
# @api private
|
|
250
|
+
def ghost_classes
|
|
251
|
+
case @variant
|
|
252
|
+
when :primary
|
|
253
|
+
[ "bg-transparent", "text-primary-600" ]
|
|
254
|
+
when :secondary
|
|
255
|
+
[ "bg-transparent", "text-secondary-600" ]
|
|
256
|
+
when :accent
|
|
257
|
+
[ "bg-transparent", "text-accent-600" ]
|
|
258
|
+
when :success
|
|
259
|
+
[ "bg-transparent", "text-success-600" ]
|
|
260
|
+
when :danger
|
|
261
|
+
[ "bg-transparent", "text-danger-600" ]
|
|
262
|
+
when :warning
|
|
263
|
+
[ "bg-transparent", "text-warning-600" ]
|
|
264
|
+
when :info
|
|
265
|
+
[ "bg-transparent", "text-info-600" ]
|
|
266
|
+
when :light
|
|
267
|
+
[ "bg-transparent", "text-grayscale-400" ]
|
|
268
|
+
when :dark
|
|
269
|
+
[ "bg-transparent", "text-grayscale-900" ]
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Returns CSS classes for soft style.
|
|
274
|
+
# Light background with subtle border and medium text.
|
|
275
|
+
#
|
|
276
|
+
# @return [Array<String>] array of CSS classes
|
|
277
|
+
# @api private
|
|
278
|
+
def soft_classes
|
|
279
|
+
case @variant
|
|
280
|
+
when :primary
|
|
281
|
+
[ "bg-primary-50", "border", "border-primary-100", "text-primary-800" ]
|
|
282
|
+
when :secondary
|
|
283
|
+
[ "bg-secondary-50", "border", "border-secondary-100", "text-secondary-800" ]
|
|
284
|
+
when :accent
|
|
285
|
+
[ "bg-accent-50", "border", "border-accent-100", "text-accent-800" ]
|
|
286
|
+
when :success
|
|
287
|
+
[ "bg-success-50", "border", "border-success-100", "text-success-800" ]
|
|
288
|
+
when :danger
|
|
289
|
+
[ "bg-danger-50", "border", "border-danger-100", "text-danger-800" ]
|
|
290
|
+
when :warning
|
|
291
|
+
[ "bg-warning-50", "border", "border-warning-100", "text-warning-800" ]
|
|
292
|
+
when :info
|
|
293
|
+
[ "bg-info-50", "border", "border-info-100", "text-info-800" ]
|
|
294
|
+
when :light
|
|
295
|
+
[ "bg-light", "border", "border-grayscale-100", "text-grayscale-800" ]
|
|
296
|
+
when :dark
|
|
297
|
+
[ "bg-grayscale-800", "border", "border-grayscale-700", "text-grayscale-100" ]
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Returns CSS classes for bordered style.
|
|
302
|
+
# Neutral white background with gray border, variant-agnostic.
|
|
303
|
+
# Perfect for visual content separation and isolation.
|
|
304
|
+
#
|
|
305
|
+
# @return [Array<String>] array of CSS classes
|
|
306
|
+
# @api private
|
|
307
|
+
def bordered_classes
|
|
308
|
+
[ "bg-white", "border", "border-gray-300", "text-gray-900" ]
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Returns shadow CSS classes based on the shadow parameter.
|
|
312
|
+
#
|
|
313
|
+
# @return [String, nil] shadow class or nil
|
|
314
|
+
# @api private
|
|
315
|
+
def shadow_classes
|
|
316
|
+
@shadow ? "shadow-md" : nil
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Returns the size configuration hash for the current size.
|
|
320
|
+
#
|
|
321
|
+
# @return [Hash] size configuration with padding, text, radius, and gap
|
|
322
|
+
# @api private
|
|
323
|
+
def size_config
|
|
324
|
+
SIZES[@size]
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Returns CSS classes for the header section.
|
|
328
|
+
#
|
|
329
|
+
# @return [String] CSS classes for header
|
|
330
|
+
# @api private
|
|
331
|
+
def header_wrapper_classes
|
|
332
|
+
css_classes([
|
|
333
|
+
(@header_padding ? size_config[:padding] : nil),
|
|
334
|
+
"border-b",
|
|
335
|
+
border_color_class,
|
|
336
|
+
@header_classes
|
|
337
|
+
].flatten.compact)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Returns CSS classes for the body section.
|
|
341
|
+
#
|
|
342
|
+
# @return [String] CSS classes for body
|
|
343
|
+
# @api private
|
|
344
|
+
def body_wrapper_classes
|
|
345
|
+
css_classes([
|
|
346
|
+
(@body_padding ? size_config[:padding] : nil),
|
|
347
|
+
@body_classes
|
|
348
|
+
].flatten.compact)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Returns CSS classes for the footer section.
|
|
352
|
+
#
|
|
353
|
+
# @return [String] CSS classes for footer
|
|
354
|
+
# @api private
|
|
355
|
+
def footer_wrapper_classes
|
|
356
|
+
css_classes([
|
|
357
|
+
(@footer_padding ? size_config[:padding] : nil),
|
|
358
|
+
"border-t",
|
|
359
|
+
border_color_class,
|
|
360
|
+
@footer_classes
|
|
361
|
+
].flatten.compact)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# Returns the appropriate border color class based on variant and style.
|
|
365
|
+
#
|
|
366
|
+
# @return [String] border color class
|
|
367
|
+
# @api private
|
|
368
|
+
def border_color_class
|
|
369
|
+
case @style
|
|
370
|
+
when :solid
|
|
371
|
+
case @variant
|
|
372
|
+
when :primary then "border-primary-200"
|
|
373
|
+
when :secondary then "border-secondary-200"
|
|
374
|
+
when :accent then "border-accent-200"
|
|
375
|
+
when :success then "border-success-200"
|
|
376
|
+
when :danger then "border-danger-200"
|
|
377
|
+
when :warning then "border-warning-200"
|
|
378
|
+
when :info then "border-info-200"
|
|
379
|
+
when :light then "border-grayscale-200"
|
|
380
|
+
when :dark then "border-grayscale-700"
|
|
381
|
+
end
|
|
382
|
+
when :outline
|
|
383
|
+
case @variant
|
|
384
|
+
when :primary then "border-primary-500"
|
|
385
|
+
when :secondary then "border-secondary-500"
|
|
386
|
+
when :accent then "border-accent-500"
|
|
387
|
+
when :success then "border-success-500"
|
|
388
|
+
when :danger then "border-danger-500"
|
|
389
|
+
when :warning then "border-warning-500"
|
|
390
|
+
when :info then "border-info-500"
|
|
391
|
+
when :light then "border-grayscale-300"
|
|
392
|
+
when :dark then "border-grayscale-900"
|
|
393
|
+
end
|
|
394
|
+
when :soft
|
|
395
|
+
case @variant
|
|
396
|
+
when :primary then "border-primary-100"
|
|
397
|
+
when :secondary then "border-secondary-100"
|
|
398
|
+
when :accent then "border-accent-100"
|
|
399
|
+
when :success then "border-success-100"
|
|
400
|
+
when :danger then "border-danger-100"
|
|
401
|
+
when :warning then "border-warning-100"
|
|
402
|
+
when :info then "border-info-100"
|
|
403
|
+
when :light then "border-grayscale-100"
|
|
404
|
+
when :dark then "border-grayscale-700"
|
|
405
|
+
end
|
|
406
|
+
when :ghost
|
|
407
|
+
"border-transparent"
|
|
408
|
+
when :bordered
|
|
409
|
+
"border-gray-300"
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Returns HTML attributes for the card element.
|
|
414
|
+
#
|
|
415
|
+
# @return [Hash] HTML attributes hash
|
|
416
|
+
# @api private
|
|
417
|
+
def html_attributes
|
|
418
|
+
@options
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Validates the variant parameter.
|
|
422
|
+
#
|
|
423
|
+
# @param variant [Symbol] the variant to validate
|
|
424
|
+
# @return [Symbol] the validated variant
|
|
425
|
+
# @raise [ArgumentError] if variant is invalid
|
|
426
|
+
# @api private
|
|
427
|
+
def validate_variant(variant)
|
|
428
|
+
unless BetterUi::ApplicationComponent::VARIANTS.key?(variant)
|
|
429
|
+
raise ArgumentError, "Invalid variant: #{variant}. Must be one of: #{BetterUi::ApplicationComponent::VARIANTS.keys.join(', ')}"
|
|
430
|
+
end
|
|
431
|
+
variant
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# Validates the style parameter.
|
|
435
|
+
#
|
|
436
|
+
# @param style [Symbol] the style to validate
|
|
437
|
+
# @return [Symbol] the validated style
|
|
438
|
+
# @raise [ArgumentError] if style is invalid
|
|
439
|
+
# @api private
|
|
440
|
+
def validate_style(style)
|
|
441
|
+
unless STYLES.include?(style)
|
|
442
|
+
raise ArgumentError, "Invalid style: #{style}. Must be one of: #{STYLES.join(', ')}"
|
|
443
|
+
end
|
|
444
|
+
style
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
# Validates the size parameter.
|
|
448
|
+
#
|
|
449
|
+
# @param size [Symbol] the size to validate
|
|
450
|
+
# @return [Symbol] the validated size
|
|
451
|
+
# @raise [ArgumentError] if size is invalid
|
|
452
|
+
# @api private
|
|
453
|
+
def validate_size(size)
|
|
454
|
+
unless SIZES.key?(size)
|
|
455
|
+
raise ArgumentError, "Invalid size: #{size}. Must be one of: #{SIZES.keys.join(', ')}"
|
|
456
|
+
end
|
|
457
|
+
size
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<header class="<%= component_classes %>" <%= tag.attributes(html_attributes) %>>
|
|
2
|
+
<div class="<%= logo_classes %>">
|
|
3
|
+
<% if mobile_menu_button? %>
|
|
4
|
+
<div class="<%= mobile_menu_button_classes %> mr-2">
|
|
5
|
+
<%= mobile_menu_button %>
|
|
6
|
+
</div>
|
|
7
|
+
<% end %>
|
|
8
|
+
<% if logo? %>
|
|
9
|
+
<%= logo %>
|
|
10
|
+
<% end %>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<% if navigation? %>
|
|
14
|
+
<div class="<%= navigation_classes %>">
|
|
15
|
+
<%= navigation %>
|
|
16
|
+
</div>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
19
|
+
<% if actions? %>
|
|
20
|
+
<div class="<%= actions_classes %>">
|
|
21
|
+
<%= actions %>
|
|
22
|
+
</div>
|
|
23
|
+
<% end %>
|
|
24
|
+
</header>
|