maquina-components 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +410 -13
- data/app/assets/images/maquina.svg +1 -0
- data/app/assets/stylesheets/alert.css +143 -0
- data/app/assets/stylesheets/badge.css +145 -0
- data/app/assets/stylesheets/breadcrumbs.css +163 -0
- data/app/assets/stylesheets/card.css +128 -0
- data/app/assets/stylesheets/dropdown_menu.css +248 -0
- data/app/assets/stylesheets/empty.css +133 -0
- data/app/assets/stylesheets/form.css +617 -0
- data/app/assets/stylesheets/header.css +61 -0
- data/app/assets/stylesheets/maquina_components.css +178 -0
- data/app/assets/stylesheets/pagination.css +154 -0
- data/app/assets/stylesheets/sidebar.css +477 -0
- data/app/assets/stylesheets/table.css +205 -0
- data/app/assets/stylesheets/toggle_group.css +151 -0
- data/app/assets/tailwind/maquina_components_engine/engine.css +16 -0
- data/app/helpers/maquina_components/breadcrumbs_helper.rb +118 -0
- data/app/helpers/maquina_components/dropdown_menu_helper.rb +249 -0
- data/app/helpers/maquina_components/empty_helper.rb +102 -0
- data/app/helpers/maquina_components/icons_helper.rb +161 -0
- data/app/helpers/maquina_components/pagination_helper.rb +153 -0
- data/app/helpers/maquina_components/sidebar_helper.rb +63 -0
- data/app/helpers/maquina_components/table_helper.rb +144 -0
- data/app/helpers/maquina_components/toggle_group_helper.rb +172 -0
- data/app/javascript/controllers/breadcrumb_controller.js +71 -0
- data/app/javascript/controllers/dropdown_menu_controller.js +203 -0
- data/app/javascript/controllers/menu_button_controller.js +59 -0
- data/app/javascript/controllers/sidebar_controller.js +316 -0
- data/app/javascript/controllers/sidebar_trigger_controller.js +32 -0
- data/app/javascript/controllers/toggle_group_controller.js +178 -0
- data/app/views/components/_alert.html.erb +12 -0
- data/app/views/components/_badge.html.erb +10 -0
- data/app/views/components/_breadcrumbs.html.erb +16 -0
- data/app/views/components/_card.html.erb +6 -0
- data/app/views/components/_dropdown.html.erb +25 -0
- data/app/views/components/_dropdown_menu.html.erb +9 -0
- data/app/views/components/_empty.html.erb +10 -0
- data/app/views/components/_header.html.erb +8 -0
- data/app/views/components/_menu_button.html.erb +44 -0
- data/app/views/components/_pagination.html.erb +13 -0
- data/app/views/components/_separator.html.erb +11 -0
- data/app/views/components/_sidebar.html.erb +40 -0
- data/app/views/components/_simple_table.html.erb +49 -0
- data/app/views/components/_table.html.erb +21 -0
- data/app/views/components/_toggle_group.html.erb +24 -0
- data/app/views/components/alert/_description.html.erb +6 -0
- data/app/views/components/alert/_title.html.erb +6 -0
- data/app/views/components/breadcrumbs/_ellipsis.html.erb +9 -0
- data/app/views/components/breadcrumbs/_item.html.erb +8 -0
- data/app/views/components/breadcrumbs/_link.html.erb +8 -0
- data/app/views/components/breadcrumbs/_list.html.erb +8 -0
- data/app/views/components/breadcrumbs/_page.html.erb +8 -0
- data/app/views/components/breadcrumbs/_separator.html.erb +17 -0
- data/app/views/components/card/_action.html.erb +6 -0
- data/app/views/components/card/_content.html.erb +9 -0
- data/app/views/components/card/_description.html.erb +6 -0
- data/app/views/components/card/_footer.html.erb +17 -0
- data/app/views/components/card/_header.html.erb +9 -0
- data/app/views/components/card/_title.html.erb +9 -0
- data/app/views/components/dropdown_menu/_content.html.erb +20 -0
- data/app/views/components/dropdown_menu/_group.html.erb +12 -0
- data/app/views/components/dropdown_menu/_item.html.erb +29 -0
- data/app/views/components/dropdown_menu/_label.html.erb +13 -0
- data/app/views/components/dropdown_menu/_separator.html.erb +11 -0
- data/app/views/components/dropdown_menu/_shortcut.html.erb +12 -0
- data/app/views/components/dropdown_menu/_trigger.html.erb +24 -0
- data/app/views/components/empty/_content.html.erb +8 -0
- data/app/views/components/empty/_description.html.erb +12 -0
- data/app/views/components/empty/_header.html.erb +8 -0
- data/app/views/components/empty/_media.html.erb +13 -0
- data/app/views/components/empty/_title.html.erb +12 -0
- data/app/views/components/pagination/_content.html.erb +8 -0
- data/app/views/components/pagination/_ellipsis.html.erb +28 -0
- data/app/views/components/pagination/_item.html.erb +8 -0
- data/app/views/components/pagination/_link.html.erb +23 -0
- data/app/views/components/pagination/_next.html.erb +57 -0
- data/app/views/components/pagination/_previous.html.erb +57 -0
- data/app/views/components/sidebar/_content.html.erb +8 -0
- data/app/views/components/sidebar/_footer.html.erb +8 -0
- data/app/views/components/sidebar/_group.html.erb +12 -0
- data/app/views/components/sidebar/_header.html.erb +8 -0
- data/app/views/components/sidebar/_inset.html.erb +8 -0
- data/app/views/components/sidebar/_menu.html.erb +8 -0
- data/app/views/components/sidebar/_menu_button.html.erb +14 -0
- data/app/views/components/sidebar/_menu_item.html.erb +7 -0
- data/app/views/components/sidebar/_menu_link.html.erb +32 -0
- data/app/views/components/sidebar/_provider.html.erb +16 -0
- data/app/views/components/sidebar/_trigger.html.erb +12 -0
- data/app/views/components/stats/_stats_card.html.erb +100 -0
- data/app/views/components/stats/_stats_grid.html.erb +38 -0
- data/app/views/components/table/_body.html.erb +5 -0
- data/app/views/components/table/_caption.html.erb +5 -0
- data/app/views/components/table/_cell.html.erb +5 -0
- data/app/views/components/table/_footer.html.erb +5 -0
- data/app/views/components/table/_head.html.erb +8 -0
- data/app/views/components/table/_header.html.erb +8 -0
- data/app/views/components/table/_row.html.erb +8 -0
- data/app/views/components/toggle_group/_item.html.erb +19 -0
- data/config/importmap.rb +1 -0
- data/lib/generators/maquina_components/install/USAGE +39 -0
- data/lib/generators/maquina_components/install/install_generator.rb +123 -0
- data/lib/generators/maquina_components/install/templates/maquina_components_helper.rb.tt +68 -0
- data/lib/generators/maquina_components/install/templates/theme.css.tt +179 -0
- data/lib/maquina_components/engine.rb +10 -0
- data/lib/maquina_components/version.rb +1 -1
- metadata +121 -5
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
module MaquinaComponents
|
|
2
|
+
module IconsHelper
|
|
3
|
+
def icon_for(name, options = {})
|
|
4
|
+
return nil unless name
|
|
5
|
+
|
|
6
|
+
svg = icon_svg_for(name.to_sym) || main_icon_svg_for(name.to_sym)
|
|
7
|
+
return nil unless svg
|
|
8
|
+
|
|
9
|
+
css_classes = options[:class]
|
|
10
|
+
svg = svg.gsub('class="', "class=\"#{css_classes} ")
|
|
11
|
+
|
|
12
|
+
if options[:stroke_width]
|
|
13
|
+
svg = svg.gsub('stroke-width="2"', "stroke-width=\"#{options[:stroke_width]}\"")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
svg.html_safe
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def main_icon_svg_for(name)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def icon_svg_for(name)
|
|
23
|
+
case name
|
|
24
|
+
when :dollar
|
|
25
|
+
<<~SVG.freeze
|
|
26
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
27
|
+
<line x1="12" y1="2" x2="12" y2="22"></line>
|
|
28
|
+
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>
|
|
29
|
+
</svg>
|
|
30
|
+
SVG
|
|
31
|
+
when :users
|
|
32
|
+
<<~SVG.freeze
|
|
33
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
34
|
+
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path>
|
|
35
|
+
<circle cx="9" cy="7" r="4"></circle>
|
|
36
|
+
<path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"></path>
|
|
37
|
+
</svg>
|
|
38
|
+
SVG
|
|
39
|
+
when :credit_card
|
|
40
|
+
<<~SVG.freeze
|
|
41
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
42
|
+
<rect width="20" height="14" x="2" y="5" rx="2"></rect>
|
|
43
|
+
<line x1="2" y1="10" x2="22" y2="10"></line>
|
|
44
|
+
</svg>
|
|
45
|
+
SVG
|
|
46
|
+
when :activity
|
|
47
|
+
<<~SVG.freeze
|
|
48
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
49
|
+
<path d="M22 12h-4l-3 9L9 3l-3 9H2"></path>
|
|
50
|
+
</svg>
|
|
51
|
+
SVG
|
|
52
|
+
when :trend_up
|
|
53
|
+
<<~SVG.freeze
|
|
54
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
55
|
+
<polyline points="22 7 13.5 15.5 8.5 10.5 2 17"></polyline>
|
|
56
|
+
<polyline points="16 7 22 7 22 13"></polyline>
|
|
57
|
+
</svg>
|
|
58
|
+
SVG
|
|
59
|
+
when :trend_down
|
|
60
|
+
<<~SVG.freeze
|
|
61
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
62
|
+
<polyline points="22 17 13.5 8.5 8.5 13.5 2 7"></polyline>
|
|
63
|
+
<polyline points="16 17 22 17 22 11"></polyline>
|
|
64
|
+
</svg>
|
|
65
|
+
SVG
|
|
66
|
+
when :clock
|
|
67
|
+
<<~SVG.freeze
|
|
68
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
69
|
+
<circle cx="12" cy="12" r="10"></circle>
|
|
70
|
+
<polyline points="12 6 12 12 16 14"></polyline>
|
|
71
|
+
</svg>
|
|
72
|
+
SVG
|
|
73
|
+
when :money
|
|
74
|
+
<<~SVG.freeze
|
|
75
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
76
|
+
<rect width="20" height="12" x="2" y="6" rx="2"></rect>
|
|
77
|
+
<circle cx="12" cy="12" r="2"></circle>
|
|
78
|
+
<path d="M6 12h.01M18 12h.01"></path>
|
|
79
|
+
</svg>
|
|
80
|
+
SVG
|
|
81
|
+
when :line_chart
|
|
82
|
+
<<~SVG.freeze
|
|
83
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
84
|
+
<path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/>
|
|
85
|
+
</svg>
|
|
86
|
+
SVG
|
|
87
|
+
when :piggy_bank
|
|
88
|
+
<<~SVG.freeze
|
|
89
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
90
|
+
<path d="M19 5c-1.5 0-2.8 1.4-3 2-3.5-1.5-11-.3-11 5 0 1.8 0 3 2 4.5V20h4v-2h3v2h4v-4c1-.5 1.7-1 2-2h2v-4h-2c0-1-.5-1.5-1-2h0V5z"/>
|
|
91
|
+
<path d="M2 9v1c0 1.1.9 2 2 2h1"/>
|
|
92
|
+
<path d="M16 11h0"/>
|
|
93
|
+
</svg>
|
|
94
|
+
SVG
|
|
95
|
+
when :arrow_left
|
|
96
|
+
<<~SVG.freeze
|
|
97
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
98
|
+
<line x1="19" y1="12" x2="5" y2="12"></line>
|
|
99
|
+
<polyline points="12 19 5 12 12 5"></polyline>
|
|
100
|
+
</svg>
|
|
101
|
+
SVG
|
|
102
|
+
when :select_chevron
|
|
103
|
+
<<~SVG.freeze
|
|
104
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="" aria-hidden="true">
|
|
105
|
+
<path d="m6 9 6 6 6-6"></path>
|
|
106
|
+
</svg>
|
|
107
|
+
SVG
|
|
108
|
+
when :check
|
|
109
|
+
<<~SVG.freeze
|
|
110
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
111
|
+
<path d="M20 6 9 17l-5-5"/>
|
|
112
|
+
</svg>
|
|
113
|
+
SVG
|
|
114
|
+
when :circle_alert
|
|
115
|
+
<<~SVG.freeze
|
|
116
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
117
|
+
<circle cx="12" cy="12" r="10"/>
|
|
118
|
+
<line x1="12" x2="12" y1="8" y2="12"/>
|
|
119
|
+
<line x1="12" x2="12.01" y1="16" y2="16"/>
|
|
120
|
+
</svg>
|
|
121
|
+
SVG
|
|
122
|
+
when :logout
|
|
123
|
+
<<~SVG.freeze
|
|
124
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
125
|
+
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
|
126
|
+
<polyline points="16 17 21 12 16 7"></polyline>
|
|
127
|
+
<line x1="21" x2="9" y1="12" y2="12"></line>
|
|
128
|
+
</svg>
|
|
129
|
+
SVG
|
|
130
|
+
when :chevron_up_down
|
|
131
|
+
<<~SVG.freeze
|
|
132
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
133
|
+
<path d="m7 15 5 5 5-5"></path>
|
|
134
|
+
<path d="m7 9 5-5 5 5"></path>
|
|
135
|
+
</svg>
|
|
136
|
+
SVG
|
|
137
|
+
when :chevron_right
|
|
138
|
+
<<~SVG
|
|
139
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
140
|
+
<path d="m9 18 6-6-6-6"/>
|
|
141
|
+
</svg>
|
|
142
|
+
SVG
|
|
143
|
+
when :left_panel
|
|
144
|
+
<<~SVG.freeze
|
|
145
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="">
|
|
146
|
+
<rect width="18" height="18" x="3" y="3" rx="2"></rect>
|
|
147
|
+
<path d="M9 3v18"></path>
|
|
148
|
+
</svg>
|
|
149
|
+
SVG
|
|
150
|
+
when :ellipsis
|
|
151
|
+
<<~SVG.freeze
|
|
152
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
153
|
+
<circle cx="12" cy="12" r="1"/>
|
|
154
|
+
<circle cx="19" cy="12" r="1"/>
|
|
155
|
+
<circle cx="5" cy="12" r="1"/>
|
|
156
|
+
</svg>
|
|
157
|
+
SVG
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MaquinaComponents
|
|
4
|
+
# Pagination Helper
|
|
5
|
+
#
|
|
6
|
+
# Provides convenient methods for creating pagination components with Pagy integration.
|
|
7
|
+
#
|
|
8
|
+
# @example Using the helper with Pagy
|
|
9
|
+
# <%%= pagination_nav(@pagy, :users_path) %>
|
|
10
|
+
#
|
|
11
|
+
# @example With additional params
|
|
12
|
+
# <%%= pagination_nav(@pagy, :search_users_path, params: { q: params[:q] }) %>
|
|
13
|
+
#
|
|
14
|
+
# @example With Turbo options
|
|
15
|
+
# <%%= pagination_nav(@pagy, :users_path, turbo: { action: :replace, frame: "users" }) %>
|
|
16
|
+
#
|
|
17
|
+
# @example Using partials directly
|
|
18
|
+
# <%%= render "components/pagination" do %>
|
|
19
|
+
# <%%= render "components/pagination/content" do %>
|
|
20
|
+
# <%%= render "components/pagination/item" do %>
|
|
21
|
+
# <%%= render "components/pagination/previous", href: prev_path %>
|
|
22
|
+
# <%% end %>
|
|
23
|
+
# ...
|
|
24
|
+
# <%% end %>
|
|
25
|
+
# <%% end %>
|
|
26
|
+
#
|
|
27
|
+
module PaginationHelper
|
|
28
|
+
# Renders a complete pagination navigation from a Pagy object
|
|
29
|
+
#
|
|
30
|
+
# @param pagy [Pagy] The Pagy pagination object
|
|
31
|
+
# @param route_helper [Symbol] Route helper method name (e.g., :users_path)
|
|
32
|
+
# @param params [Hash] Additional params to pass to route helper
|
|
33
|
+
# @param turbo [Hash] Turbo-specific data attributes
|
|
34
|
+
# @param show_labels [Boolean] Whether to show Previous/Next text labels
|
|
35
|
+
# @param css_classes [String] Additional CSS classes for the nav
|
|
36
|
+
# @return [String] Rendered HTML
|
|
37
|
+
def pagination_nav(pagy, route_helper, params: {}, turbo: {action: :replace}, show_labels: true, css_classes: "", **html_options)
|
|
38
|
+
return if pagy.pages <= 1
|
|
39
|
+
|
|
40
|
+
render "components/pagination", css_classes: css_classes, **html_options do
|
|
41
|
+
render "components/pagination/content" do
|
|
42
|
+
safe_join([
|
|
43
|
+
pagination_previous_item(pagy, route_helper, params, turbo, show_labels),
|
|
44
|
+
pagination_page_items(pagy, route_helper, params, turbo),
|
|
45
|
+
pagination_next_item(pagy, route_helper, params, turbo, show_labels)
|
|
46
|
+
])
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Simpler pagination with just Previous/Next (no page numbers)
|
|
52
|
+
#
|
|
53
|
+
# @param pagy [Pagy] The Pagy pagination object
|
|
54
|
+
# @param route_helper [Symbol] Route helper method name
|
|
55
|
+
# @param params [Hash] Additional params to pass to route helper
|
|
56
|
+
# @param turbo [Hash] Turbo-specific data attributes
|
|
57
|
+
# @return [String] Rendered HTML
|
|
58
|
+
def pagination_simple(pagy, route_helper, params: {}, turbo: {action: :replace}, css_classes: "", **html_options)
|
|
59
|
+
return if pagy.pages <= 1
|
|
60
|
+
|
|
61
|
+
render "components/pagination", css_classes: css_classes, **html_options do
|
|
62
|
+
render "components/pagination/content" do
|
|
63
|
+
safe_join([
|
|
64
|
+
pagination_previous_item(pagy, route_helper, params, turbo, true),
|
|
65
|
+
pagination_next_item(pagy, route_helper, params, turbo, true)
|
|
66
|
+
])
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Build paginated path with page param
|
|
72
|
+
#
|
|
73
|
+
# @param route_helper [Symbol] Route helper method name
|
|
74
|
+
# @param pagy [Pagy] The Pagy pagination object
|
|
75
|
+
# @param page [Integer] Page number
|
|
76
|
+
# @param extra_params [Hash] Additional params
|
|
77
|
+
# @return [String] URL path
|
|
78
|
+
def paginated_path(route_helper, pagy, page, extra_params = {})
|
|
79
|
+
page_param = pagy.vars[:page_param] || Pagy::DEFAULT[:page_param]
|
|
80
|
+
query_params = request.query_parameters.except(page_param.to_s).merge(extra_params)
|
|
81
|
+
query_params[page_param] = page
|
|
82
|
+
|
|
83
|
+
send(route_helper, query_params)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def pagination_previous_item(pagy, route_helper, params, turbo, show_label)
|
|
89
|
+
render "components/pagination/item" do
|
|
90
|
+
if pagy.prev
|
|
91
|
+
render "components/pagination/previous",
|
|
92
|
+
href: paginated_path(route_helper, pagy, pagy.prev, params),
|
|
93
|
+
show_label: show_label,
|
|
94
|
+
data: turbo_data(turbo)
|
|
95
|
+
else
|
|
96
|
+
render "components/pagination/previous",
|
|
97
|
+
disabled: true,
|
|
98
|
+
show_label: show_label
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def pagination_next_item(pagy, route_helper, params, turbo, show_label)
|
|
104
|
+
render "components/pagination/item" do
|
|
105
|
+
if pagy.next
|
|
106
|
+
render "components/pagination/next",
|
|
107
|
+
href: paginated_path(route_helper, pagy, pagy.next, params),
|
|
108
|
+
show_label: show_label,
|
|
109
|
+
data: turbo_data(turbo)
|
|
110
|
+
else
|
|
111
|
+
render "components/pagination/next",
|
|
112
|
+
disabled: true,
|
|
113
|
+
show_label: show_label
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def pagination_page_items(pagy, route_helper, params, turbo)
|
|
119
|
+
pagy.series.map do |item|
|
|
120
|
+
render "components/pagination/item" do
|
|
121
|
+
case item
|
|
122
|
+
when Integer
|
|
123
|
+
render "components/pagination/link",
|
|
124
|
+
href: paginated_path(route_helper, pagy, item, params),
|
|
125
|
+
active: item == pagy.page,
|
|
126
|
+
data: turbo_data(turbo) do
|
|
127
|
+
item.to_s
|
|
128
|
+
end
|
|
129
|
+
when String
|
|
130
|
+
# Current page (string representation)
|
|
131
|
+
render "components/pagination/link",
|
|
132
|
+
href: paginated_path(route_helper, pagy, item.to_i, params),
|
|
133
|
+
active: true,
|
|
134
|
+
data: turbo_data(turbo) do
|
|
135
|
+
item
|
|
136
|
+
end
|
|
137
|
+
when :gap
|
|
138
|
+
render "components/pagination/ellipsis"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def turbo_data(turbo)
|
|
145
|
+
return {} if turbo.blank?
|
|
146
|
+
|
|
147
|
+
data = {}
|
|
148
|
+
data[:turbo_action] = turbo[:action] if turbo[:action]
|
|
149
|
+
data[:turbo_frame] = turbo[:frame] if turbo[:frame]
|
|
150
|
+
data
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module MaquinaComponents
|
|
2
|
+
module SidebarHelper
|
|
3
|
+
# Get sidebar state from cookie
|
|
4
|
+
#
|
|
5
|
+
# Reads the sidebar state cookie and returns a String.
|
|
6
|
+
# Use this to set the state value in the sidebar
|
|
7
|
+
# to ensure server-rendered state matches client state.
|
|
8
|
+
#
|
|
9
|
+
# @param cookie_name [String] The cookie name (default: "sidebar_state")
|
|
10
|
+
# @return [String] expanded if sidebar should be open, collapsed otherwise
|
|
11
|
+
#
|
|
12
|
+
# @example In layout
|
|
13
|
+
# <%= render "components/sidebar",
|
|
14
|
+
# state: sidebar_state do %>
|
|
15
|
+
# <!-- content -->
|
|
16
|
+
# <% end %>
|
|
17
|
+
#
|
|
18
|
+
# @example With custom cookie name
|
|
19
|
+
# <%= render "components/sidebar",
|
|
20
|
+
# state: sidebar_state("custom_sidebar_cookie") do %>
|
|
21
|
+
# <!-- content -->
|
|
22
|
+
# <% end %>
|
|
23
|
+
#
|
|
24
|
+
def sidebar_state(cookie_name = "sidebar_state")
|
|
25
|
+
# Read cookie value
|
|
26
|
+
cookie_value = cookies[cookie_name]
|
|
27
|
+
|
|
28
|
+
# Default to expanded when no cookie exists
|
|
29
|
+
return :expanded if cookie_value.nil?
|
|
30
|
+
|
|
31
|
+
# Return expanded if cookie says "true", otherwise collapsed
|
|
32
|
+
(cookie_value == "true") ? :expanded : :collapsed
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Check if sidebar is currently open
|
|
36
|
+
#
|
|
37
|
+
# @param cookie_name [String] The cookie name (default: "sidebar_state")
|
|
38
|
+
# @return [Boolean] true if sidebar is open
|
|
39
|
+
#
|
|
40
|
+
# @example
|
|
41
|
+
# <% if sidebar_open? %>
|
|
42
|
+
# <!-- Show sidebar-specific content -->
|
|
43
|
+
# <% end %>
|
|
44
|
+
#
|
|
45
|
+
def sidebar_open?(cookie_name = "sidebar_state")
|
|
46
|
+
sidebar_state(cookie_name) == :expanded
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Check if sidebar is currently closed
|
|
50
|
+
#
|
|
51
|
+
# @param cookie_name [String] The cookie name (default: "sidebar_state")
|
|
52
|
+
# @return [Boolean] true if sidebar is closed
|
|
53
|
+
#
|
|
54
|
+
# @example
|
|
55
|
+
# <% if sidebar_closed? %>
|
|
56
|
+
# <!-- Show expanded content when sidebar is closed -->
|
|
57
|
+
# <% end %>
|
|
58
|
+
#
|
|
59
|
+
def sidebar_closed?(cookie_name = "sidebar_state")
|
|
60
|
+
sidebar_state(cookie_name) == :collapsed
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MaquinaComponents
|
|
4
|
+
# Table Component Helper
|
|
5
|
+
#
|
|
6
|
+
# Provides a simple helper for rendering basic tables from collections.
|
|
7
|
+
# For complex tables, use the partials directly for full control.
|
|
8
|
+
#
|
|
9
|
+
# @example Basic usage with collection
|
|
10
|
+
# <%= simple_table @invoices,
|
|
11
|
+
# columns: [
|
|
12
|
+
# { key: :number, label: "Invoice" },
|
|
13
|
+
# { key: :status, label: "Status" },
|
|
14
|
+
# { key: :amount, label: "Amount", align: :right }
|
|
15
|
+
# ] %>
|
|
16
|
+
#
|
|
17
|
+
# @example With caption and bordered variant
|
|
18
|
+
# <%= simple_table @users,
|
|
19
|
+
# columns: [
|
|
20
|
+
# { key: :name, label: "Name" },
|
|
21
|
+
# { key: :email, label: "Email" },
|
|
22
|
+
# { key: :role, label: "Role" }
|
|
23
|
+
# ],
|
|
24
|
+
# caption: "Active users",
|
|
25
|
+
# variant: :bordered %>
|
|
26
|
+
#
|
|
27
|
+
module TableHelper
|
|
28
|
+
# Render a simple table from a collection
|
|
29
|
+
#
|
|
30
|
+
# @param collection [Array, ActiveRecord::Relation] The collection to render
|
|
31
|
+
# @param columns [Array<Hash>] Column definitions with :key, :label, and optional :align
|
|
32
|
+
# @param caption [String, nil] Optional table caption
|
|
33
|
+
# @param variant [Symbol, nil] Container variant (:bordered)
|
|
34
|
+
# @param table_variant [Symbol, nil] Table variant (:striped)
|
|
35
|
+
# @param empty_message [String] Message to show when collection is empty
|
|
36
|
+
# @param row_id [Symbol, nil] Method to call for row ID (e.g., :id)
|
|
37
|
+
# @param html_options [Hash] Additional HTML options for the table
|
|
38
|
+
# @return [String] Rendered HTML
|
|
39
|
+
def simple_table(collection, columns:, caption: nil, variant: nil, table_variant: nil, empty_message: "No data available", row_id: nil, **html_options)
|
|
40
|
+
render partial: "components/simple_table", locals: {
|
|
41
|
+
collection: collection,
|
|
42
|
+
columns: columns,
|
|
43
|
+
caption: caption,
|
|
44
|
+
variant: variant,
|
|
45
|
+
table_variant: table_variant,
|
|
46
|
+
empty_message: empty_message,
|
|
47
|
+
row_id: row_id,
|
|
48
|
+
html_options: html_options
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Generate data attributes for table elements
|
|
53
|
+
# Useful when composing tables with other Rails helpers
|
|
54
|
+
#
|
|
55
|
+
# @example Using with content_tag
|
|
56
|
+
# <%= content_tag :table, **table_data_attrs do %>
|
|
57
|
+
# ...
|
|
58
|
+
# <% end %>
|
|
59
|
+
#
|
|
60
|
+
# @param variant [Symbol, nil] Table variant (:striped)
|
|
61
|
+
# @return [Hash] Data attributes hash
|
|
62
|
+
def table_data_attrs(variant: nil)
|
|
63
|
+
attrs = { data: { component: "table" } }
|
|
64
|
+
attrs[:data][:variant] = variant.to_s if variant
|
|
65
|
+
attrs
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Generate data attributes for table container
|
|
69
|
+
#
|
|
70
|
+
# @param variant [Symbol, nil] Container variant (:bordered)
|
|
71
|
+
# @return [Hash] Data attributes hash
|
|
72
|
+
def table_container_data_attrs(variant: nil)
|
|
73
|
+
attrs = { data: { table_part: "container" } }
|
|
74
|
+
attrs[:data][:variant] = variant.to_s if variant
|
|
75
|
+
attrs
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Generate data attributes for table row
|
|
79
|
+
#
|
|
80
|
+
# @param selected [Boolean] Whether the row is selected
|
|
81
|
+
# @return [Hash] Data attributes hash
|
|
82
|
+
def table_row_data_attrs(selected: false)
|
|
83
|
+
attrs = { data: { table_part: "row" } }
|
|
84
|
+
attrs[:data][:state] = "selected" if selected
|
|
85
|
+
attrs
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Generate data attributes for table header
|
|
89
|
+
#
|
|
90
|
+
# @param sticky [Boolean] Whether the header is sticky
|
|
91
|
+
# @return [Hash] Data attributes hash
|
|
92
|
+
def table_header_data_attrs(sticky: false)
|
|
93
|
+
attrs = { data: { table_part: "header" } }
|
|
94
|
+
attrs[:data][:sticky] = "true" if sticky
|
|
95
|
+
attrs
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Generate data attributes for table head cell
|
|
99
|
+
# @return [Hash] Data attributes hash
|
|
100
|
+
def table_head_data_attrs
|
|
101
|
+
{ data: { table_part: "head" } }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Generate data attributes for table cell
|
|
105
|
+
#
|
|
106
|
+
# @param empty [Boolean] Whether this is an empty state cell
|
|
107
|
+
# @return [Hash] Data attributes hash
|
|
108
|
+
def table_cell_data_attrs(empty: false)
|
|
109
|
+
attrs = { data: { table_part: "cell" } }
|
|
110
|
+
attrs[:data][:empty] = "true" if empty
|
|
111
|
+
attrs
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Generate data attributes for table body
|
|
115
|
+
# @return [Hash] Data attributes hash
|
|
116
|
+
def table_body_data_attrs
|
|
117
|
+
{ data: { table_part: "body" } }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Generate data attributes for table footer
|
|
121
|
+
# @return [Hash] Data attributes hash
|
|
122
|
+
def table_footer_data_attrs
|
|
123
|
+
{ data: { table_part: "footer" } }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Generate data attributes for table caption
|
|
127
|
+
# @return [Hash] Data attributes hash
|
|
128
|
+
def table_caption_data_attrs
|
|
129
|
+
{ data: { table_part: "caption" } }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Convert alignment symbol to CSS class
|
|
133
|
+
#
|
|
134
|
+
# @param align [Symbol, nil] Alignment (:left, :center, :right)
|
|
135
|
+
# @return [String, nil] CSS class name
|
|
136
|
+
def table_alignment_class(align)
|
|
137
|
+
case align&.to_sym
|
|
138
|
+
when :right then "text-right"
|
|
139
|
+
when :center then "text-center"
|
|
140
|
+
else nil
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|