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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +410 -13
  3. data/app/assets/images/maquina.svg +1 -0
  4. data/app/assets/stylesheets/alert.css +143 -0
  5. data/app/assets/stylesheets/badge.css +145 -0
  6. data/app/assets/stylesheets/breadcrumbs.css +163 -0
  7. data/app/assets/stylesheets/card.css +128 -0
  8. data/app/assets/stylesheets/dropdown_menu.css +248 -0
  9. data/app/assets/stylesheets/empty.css +133 -0
  10. data/app/assets/stylesheets/form.css +617 -0
  11. data/app/assets/stylesheets/header.css +61 -0
  12. data/app/assets/stylesheets/maquina_components.css +178 -0
  13. data/app/assets/stylesheets/pagination.css +154 -0
  14. data/app/assets/stylesheets/sidebar.css +477 -0
  15. data/app/assets/stylesheets/table.css +205 -0
  16. data/app/assets/stylesheets/toggle_group.css +151 -0
  17. data/app/assets/tailwind/maquina_components_engine/engine.css +16 -0
  18. data/app/helpers/maquina_components/breadcrumbs_helper.rb +118 -0
  19. data/app/helpers/maquina_components/dropdown_menu_helper.rb +249 -0
  20. data/app/helpers/maquina_components/empty_helper.rb +102 -0
  21. data/app/helpers/maquina_components/icons_helper.rb +161 -0
  22. data/app/helpers/maquina_components/pagination_helper.rb +153 -0
  23. data/app/helpers/maquina_components/sidebar_helper.rb +63 -0
  24. data/app/helpers/maquina_components/table_helper.rb +144 -0
  25. data/app/helpers/maquina_components/toggle_group_helper.rb +172 -0
  26. data/app/javascript/controllers/breadcrumb_controller.js +71 -0
  27. data/app/javascript/controllers/dropdown_menu_controller.js +203 -0
  28. data/app/javascript/controllers/menu_button_controller.js +59 -0
  29. data/app/javascript/controllers/sidebar_controller.js +316 -0
  30. data/app/javascript/controllers/sidebar_trigger_controller.js +32 -0
  31. data/app/javascript/controllers/toggle_group_controller.js +178 -0
  32. data/app/views/components/_alert.html.erb +12 -0
  33. data/app/views/components/_badge.html.erb +10 -0
  34. data/app/views/components/_breadcrumbs.html.erb +16 -0
  35. data/app/views/components/_card.html.erb +6 -0
  36. data/app/views/components/_dropdown.html.erb +25 -0
  37. data/app/views/components/_dropdown_menu.html.erb +9 -0
  38. data/app/views/components/_empty.html.erb +10 -0
  39. data/app/views/components/_header.html.erb +8 -0
  40. data/app/views/components/_menu_button.html.erb +44 -0
  41. data/app/views/components/_pagination.html.erb +13 -0
  42. data/app/views/components/_separator.html.erb +11 -0
  43. data/app/views/components/_sidebar.html.erb +40 -0
  44. data/app/views/components/_simple_table.html.erb +49 -0
  45. data/app/views/components/_table.html.erb +21 -0
  46. data/app/views/components/_toggle_group.html.erb +24 -0
  47. data/app/views/components/alert/_description.html.erb +6 -0
  48. data/app/views/components/alert/_title.html.erb +6 -0
  49. data/app/views/components/breadcrumbs/_ellipsis.html.erb +9 -0
  50. data/app/views/components/breadcrumbs/_item.html.erb +8 -0
  51. data/app/views/components/breadcrumbs/_link.html.erb +8 -0
  52. data/app/views/components/breadcrumbs/_list.html.erb +8 -0
  53. data/app/views/components/breadcrumbs/_page.html.erb +8 -0
  54. data/app/views/components/breadcrumbs/_separator.html.erb +17 -0
  55. data/app/views/components/card/_action.html.erb +6 -0
  56. data/app/views/components/card/_content.html.erb +9 -0
  57. data/app/views/components/card/_description.html.erb +6 -0
  58. data/app/views/components/card/_footer.html.erb +17 -0
  59. data/app/views/components/card/_header.html.erb +9 -0
  60. data/app/views/components/card/_title.html.erb +9 -0
  61. data/app/views/components/dropdown_menu/_content.html.erb +20 -0
  62. data/app/views/components/dropdown_menu/_group.html.erb +12 -0
  63. data/app/views/components/dropdown_menu/_item.html.erb +29 -0
  64. data/app/views/components/dropdown_menu/_label.html.erb +13 -0
  65. data/app/views/components/dropdown_menu/_separator.html.erb +11 -0
  66. data/app/views/components/dropdown_menu/_shortcut.html.erb +12 -0
  67. data/app/views/components/dropdown_menu/_trigger.html.erb +24 -0
  68. data/app/views/components/empty/_content.html.erb +8 -0
  69. data/app/views/components/empty/_description.html.erb +12 -0
  70. data/app/views/components/empty/_header.html.erb +8 -0
  71. data/app/views/components/empty/_media.html.erb +13 -0
  72. data/app/views/components/empty/_title.html.erb +12 -0
  73. data/app/views/components/pagination/_content.html.erb +8 -0
  74. data/app/views/components/pagination/_ellipsis.html.erb +28 -0
  75. data/app/views/components/pagination/_item.html.erb +8 -0
  76. data/app/views/components/pagination/_link.html.erb +23 -0
  77. data/app/views/components/pagination/_next.html.erb +57 -0
  78. data/app/views/components/pagination/_previous.html.erb +57 -0
  79. data/app/views/components/sidebar/_content.html.erb +8 -0
  80. data/app/views/components/sidebar/_footer.html.erb +8 -0
  81. data/app/views/components/sidebar/_group.html.erb +12 -0
  82. data/app/views/components/sidebar/_header.html.erb +8 -0
  83. data/app/views/components/sidebar/_inset.html.erb +8 -0
  84. data/app/views/components/sidebar/_menu.html.erb +8 -0
  85. data/app/views/components/sidebar/_menu_button.html.erb +14 -0
  86. data/app/views/components/sidebar/_menu_item.html.erb +7 -0
  87. data/app/views/components/sidebar/_menu_link.html.erb +32 -0
  88. data/app/views/components/sidebar/_provider.html.erb +16 -0
  89. data/app/views/components/sidebar/_trigger.html.erb +12 -0
  90. data/app/views/components/stats/_stats_card.html.erb +100 -0
  91. data/app/views/components/stats/_stats_grid.html.erb +38 -0
  92. data/app/views/components/table/_body.html.erb +5 -0
  93. data/app/views/components/table/_caption.html.erb +5 -0
  94. data/app/views/components/table/_cell.html.erb +5 -0
  95. data/app/views/components/table/_footer.html.erb +5 -0
  96. data/app/views/components/table/_head.html.erb +8 -0
  97. data/app/views/components/table/_header.html.erb +8 -0
  98. data/app/views/components/table/_row.html.erb +8 -0
  99. data/app/views/components/toggle_group/_item.html.erb +19 -0
  100. data/config/importmap.rb +1 -0
  101. data/lib/generators/maquina_components/install/USAGE +39 -0
  102. data/lib/generators/maquina_components/install/install_generator.rb +123 -0
  103. data/lib/generators/maquina_components/install/templates/maquina_components_helper.rb.tt +68 -0
  104. data/lib/generators/maquina_components/install/templates/theme.css.tt +179 -0
  105. data/lib/maquina_components/engine.rb +10 -0
  106. data/lib/maquina_components/version.rb +1 -1
  107. metadata +121 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0f4bc77b94379658acd2eb8a4861dd9e93c70ae5030553892eae3e8ec8ce660
4
- data.tar.gz: 84502d8a40444a30ec4d3d113c53cb495dbed92e683c62b855877b73097f6fbf
3
+ metadata.gz: cdbbf854a700d7b0fa55c3b91f1975d7fd53282ddeb0a14db55011d055db96a3
4
+ data.tar.gz: 1b69e2f23f390efa573e3192410125e8945ec182001ca8f2db431fee72523efc
5
5
  SHA512:
6
- metadata.gz: 54af9ab2d08c6f8e74a0722377573aaa8434f28d8c592daff680ad660d14f666b78fc8c16aebfcaac13b1a715e7e1c7f3376368802cc956aba533b1b5915d0f2
7
- data.tar.gz: a4044c1f428042c543f940bc601ccb02eb9f88250fd84226cdb6f9b73a04817ecadc23bf93c8ee7951a9ab54afdb6c728490b3a85ddb1190dc35eea74008fc50
6
+ metadata.gz: 07a7b92b85cdaf2987c2a816133bd174e1d838ff9af4ce16166ea218729c0896f7f4bbe71c7c8caaa3f175196dbe097d6f426c28db96e0cdd703054a788ba4f9
7
+ data.tar.gz: 53c9a63b128ed2cef878c3935185ed559d3e01274f1354ab34f438926a8e06cdac3980eabdd4c962e9a02765f7102c1694a106c9775cc05ce7f7358ed89add10
data/README.md CHANGED
@@ -1,28 +1,425 @@
1
- # MaquinaComponents
2
- Short description and motivation.
1
+ # Maquina Components
3
2
 
4
- ## Usage
5
- How to use my plugin.
3
+ UI components for Ruby on Rails, built with ERB, TailwindCSS 4.0, and Stimulus.
6
4
 
7
- ## Installation
8
- Add this line to your application's Gemfile:
5
+ ---
6
+
7
+ ## Why This Exists
8
+
9
+ I started building components inspired by [shadcn/ui](https://ui.shadcn.com/) for production Rails applications—mainly dashboards and admin interfaces. Over time, I iterated on these components across multiple projects, and they became inconsistent: different APIs, different styling approaches, different levels of completeness.
10
+
11
+ It was time to extract the elements I use most and give them a **cohesive API and consistent styling**.
12
+
13
+ ### The Technical Choices
14
+
15
+ I chose **ERB partials** with **TailwindCSS** and **Stimulus controllers** for interactive elements. For static components like form inputs, pure CSS with data attributes is enough.
16
+
17
+ I'm aware of alternatives like [ViewComponent](https://viewcomponent.org/) and [Phlex](https://www.phlex.fun/). The projects I extracted these components from didn't use them. I see the benefits of using a Ruby class to render the UI, but bringing in any of these libraries into a project is a big commitment, and not all projects and teams are open to doing it. The reason is not technical; it is the feeling of moving away from "the Rails way." So I kept it simple: ERB partials that any Rails developer can understand immediately.
18
+
19
+ ### Composability Over Convenience
20
+
21
+ These components are built to be **composable**. They are built of many small ERB partials to render. But that's intentional—you can take these partials and compose them into larger, application-specific components. There are no limits, and you have a standard API to guide you.
22
+
23
+ I didn't copy shadcn/ui one-to-one. I extracted only the components I actually use in my applications. This is a practical toolkit, not a complete port.
24
+
25
+ ### One Approach Among Many
26
+
27
+ There's no single UI kit that rules Rails development. If this approach doesn't resonate with you, here are excellent alternatives:
28
+
29
+ - [RailsUI](https://railsui.com) — Premium UI templates and components
30
+ - [RailsBlocks](https://railsblocks.com) — Copy-paste components for Rails
31
+ - [shadcn-rails](https://shadcn.rails-components.com) — Another shadcn/ui port for Rails
32
+ - [Inertia Rails + shadcn Starter](https://evilmartians.com/opensource/inertia-rails-shadcn-starter) — React/Vue components with Inertia
33
+
34
+ If you're open to trying maquina_components and providing feedback, you're welcome to do so. If this isn't for you, that's okay too.
35
+
36
+ ---
37
+
38
+ ## Features
39
+
40
+ - **ERB partials** with strict locals (`locals:` magic comments)
41
+ - **TailwindCSS 4.0** with CSS custom properties for theming
42
+ - **Data attributes** (`data-component`, `data-*-part`) for CSS styling
43
+ - **Stimulus controllers** only used where interactivity is needed
44
+ - **Dark mode** support via CSS variables
45
+ - **shadcn/ui theming** convention (works with their color system)
46
+ - **Composable** — small partials you can combine freely
47
+
48
+ ![Test dummy app with light mode](/imgs/light.png)
49
+
50
+ ![Test dummy app with dark mode](/imgs/dark.png)
51
+
52
+ ---
53
+
54
+ ## Quick Start
55
+
56
+ ### 1. Add the Gem
9
57
 
10
58
  ```ruby
11
- gem "maquina_components"
59
+ # Gemfile
60
+ gem "maquina-components"
12
61
  ```
13
62
 
14
- And then execute:
15
63
  ```bash
16
- $ bundle
64
+ bundle install
17
65
  ```
18
66
 
19
- Or install it yourself as:
67
+ ### 2. Run the Install Generator
68
+
20
69
  ```bash
21
- $ gem install maquina_components
70
+ bin/rails generate maquina_components:install
22
71
  ```
23
72
 
73
+ This will:
74
+
75
+ - Add the engine CSS import to your Tailwind file
76
+ - Add theme variables (light + dark mode)
77
+ - Create a helper file for icon customization
78
+
79
+ ### 3. Use Components
80
+
81
+ ```erb
82
+ <%= render "components/card" do %>
83
+ <%= render "components/card/header" do %>
84
+ <%= render "components/card/title", text: "Account Settings" %>
85
+ <%= render "components/card/description", text: "Manage your preferences" %>
86
+ <% end %>
87
+ <%= render "components/card/content" do %>
88
+ <!-- Your content -->
89
+ <% end %>
90
+ <% end %>
91
+ ```
92
+
93
+ For form elements, use data attributes with Rails helpers:
94
+
95
+ ```erb
96
+ <%= form_with model: @user do |f| %>
97
+ <%= f.text_field :name, data: { component: "input" } %>
98
+ <%= f.email_field :email, data: { component: "input" } %>
99
+ <%= f.submit "Save", data: { component: "button", variant: "primary" } %>
100
+ <% end %>
101
+ ```
102
+
103
+ **[Full Getting Started Guide](https://maquina.app/documentation/components/)**
104
+
105
+ ---
106
+
107
+ ## Generator Options
108
+
109
+ ```bash
110
+ # Default: adds everything
111
+ bin/rails generate maquina_components:install
112
+
113
+ # Skip theme variables (if you have your own)
114
+ bin/rails generate maquina_components:install --skip-theme
115
+
116
+ # Skip helper file
117
+ bin/rails generate maquina_components:install --skip-helper
118
+ ```
119
+
120
+ **Prerequisite:** [tailwindcss-rails](https://github.com/rails/tailwindcss-rails) must be installed first.
121
+
122
+ ---
123
+
124
+ ## Available Components
125
+
126
+ ### Layout Components
127
+
128
+ | Component | Description | Documentation |
129
+ |-----------|-------------|---------------|
130
+ | **Sidebar** | Collapsible navigation with cookie persistence | [Sidebar](https://maquina.app/documentation/components/sidebar/) |
131
+ | **Header** | Top navigation bar | [Header](https://maquina.app/documentation/components/header/) |
132
+
133
+ ### Content Components
134
+
135
+ | Component | Description | Documentation |
136
+ |-----------|-------------|---------------|
137
+ | **Card** | Content container with header, content, footer | [Card](https://maquina.app/documentation/components/card/) |
138
+ | **Alert** | Callout messages (info, warning, error) | [Alert](https://maquina.app/documentation/components/alert/) |
139
+ | **Badge** | Status indicators and labels | [Badge](https://maquina.app/documentation/components/badge/) |
140
+ | **Table** | Data tables with sorting support | [Table](https://maquina.app/documentation/components/table/) |
141
+ | **Empty State** | Placeholder for empty lists | [Empty State](https://maquina.app/documentation/components/empty/) |
142
+
143
+ ### Navigation Components
144
+
145
+ | Component | Description | Documentation |
146
+ |-----------|-------------|---------------|
147
+ | **Breadcrumbs** | Navigation trail with overflow handling | [Breadcrumbs](https://maquina.app/documentation/components/breadcrumbs/) |
148
+ | **Dropdown Menu** | Accessible dropdown with keyboard navigation | [Dropdown Menu](https://maquina.app/documentation/components/dropdown-menu/) |
149
+ | **Pagination** | Page navigation with Pagy integration | [Pagination](https://maquina.app/documentation/components/pagination/) |
150
+
151
+ ### Interactive Components
152
+
153
+ | Component | Description | Documentation |
154
+ |-----------|-------------|---------------|
155
+ | **Toggle Group** | Single/multiple selection button group | [Toggle Group](https://maquina.app/documentation/components/toggle-group/) |
156
+
157
+ ### Form Components
158
+
159
+ | Component | Data Attribute | Variants |
160
+ |-----------|----------------|----------|
161
+ | **Button** | `data-component="button"` | default, primary, secondary, destructive, outline, ghost, link |
162
+ | **Input** | `data-component="input"` | — |
163
+ | **Textarea** | `data-component="textarea"` | — |
164
+ | **Select** | `data-component="select"` | — |
165
+ | **Checkbox** | `data-component="checkbox"` | — |
166
+ | **Radio** | `data-component="radio"` | — |
167
+ | **Switch** | `data-component="switch"` | — |
168
+
169
+ **[Form Components Guide](https://maquina.app/documentation/components/form/)**
170
+
171
+ ---
172
+
173
+ ## Examples
174
+
175
+ ### Cards with Actions
176
+
177
+ ```erb
178
+ <%= render "components/card" do %>
179
+ <%= render "components/card/header", layout: :row do %>
180
+ <div>
181
+ <%= render "components/card/title", text: "Team Members" %>
182
+ <%= render "components/card/description", text: "Manage your team" %>
183
+ </div>
184
+ <%= render "components/card/action" do %>
185
+ <%= link_to "Add Member", new_member_path,
186
+ data: { component: "button", variant: "primary", size: "sm" } %>
187
+ <% end %>
188
+ <% end %>
189
+ <%= render "components/card/content" do %>
190
+ <!-- Table or list -->
191
+ <% end %>
192
+ <% end %>
193
+ ```
194
+
195
+ ### Alerts
196
+
197
+ ```erb
198
+ <%= render "components/alert", variant: :destructive do %>
199
+ <%= render "components/alert/title", text: "Error" %>
200
+ <%= render "components/alert/description" do %>
201
+ Your session has expired. Please log in again.
202
+ <% end %>
203
+ <% end %>
204
+ ```
205
+
206
+ ### Badges
207
+
208
+ ```erb
209
+ <%= render "components/badge", variant: :success do %>Active<% end %>
210
+ <%= render "components/badge", variant: :warning do %>Pending<% end %>
211
+ <%= render "components/badge", variant: :destructive do %>Failed<% end %>
212
+ ```
213
+
214
+ ### Toggle Group
215
+
216
+ ```erb
217
+ <%= render "components/toggle_group", type: :single, variant: :outline do %>
218
+ <%= render "components/toggle_group/item", value: "left", aria_label: "Align left" do %>
219
+ <%= icon_for :align_left %>
220
+ <% end %>
221
+ <%= render "components/toggle_group/item", value: "center", aria_label: "Align center" do %>
222
+ <%= icon_for :align_center %>
223
+ <% end %>
224
+ <%= render "components/toggle_group/item", value: "right", aria_label: "Align right" do %>
225
+ <%= icon_for :align_right %>
226
+ <% end %>
227
+ <% end %>
228
+ ```
229
+
230
+ ### Dropdown Menu
231
+
232
+ ```erb
233
+ <%= render "components/dropdown_menu" do %>
234
+ <%= render "components/dropdown_menu/trigger" do %>Options<% end %>
235
+ <%= render "components/dropdown_menu/content" do %>
236
+ <%= render "components/dropdown_menu/item", href: profile_path do %>
237
+ <%= icon_for :user %>
238
+ Profile
239
+ <% end %>
240
+ <%= render "components/dropdown_menu/separator" %>
241
+ <%= render "components/dropdown_menu/item", href: logout_path, method: :delete, variant: :destructive do %>
242
+ <%= icon_for :log_out %>
243
+ Logout
244
+ <% end %>
245
+ <% end %>
246
+ <% end %>
247
+ ```
248
+
249
+ ### Pagination
250
+
251
+ ```erb
252
+ <%= pagination_nav(@pagy, :users_path) %>
253
+ ```
254
+
255
+ ### Tables
256
+
257
+ ```erb
258
+ <%= render "components/table" do %>
259
+ <%= render "components/table/header" do %>
260
+ <%= render "components/table/row" do %>
261
+ <%= render "components/table/head" do %>Name<% end %>
262
+ <%= render "components/table/head" do %>Email<% end %>
263
+ <%= render "components/table/head" do %>Role<% end %>
264
+ <% end %>
265
+ <% end %>
266
+ <%= render "components/table/body" do %>
267
+ <% @users.each do |user| %>
268
+ <%= render "components/table/row" do %>
269
+ <%= render "components/table/cell" do %><%= user.name %><% end %>
270
+ <%= render "components/table/cell" do %><%= user.email %><% end %>
271
+ <%= render "components/table/cell" do %>
272
+ <%= render "components/badge", variant: :outline do %><%= user.role %><% end %>
273
+ <% end %>
274
+ <% end %>
275
+ <% end %>
276
+ <% end %>
277
+ <% end %>
278
+ ```
279
+
280
+ ### Sidebar Layout
281
+
282
+ ```erb
283
+ <%= render "components/sidebar/provider", default_open: app_sidebar_open? do %>
284
+ <%= render "components/sidebar" do %>
285
+ <%= render "components/sidebar/header" do %>
286
+ <span class="font-semibold">My App</span>
287
+ <% end %>
288
+
289
+ <%= render "components/sidebar/content" do %>
290
+ <%= render "components/sidebar/group", title: "Navigation" do %>
291
+ <%= render "components/sidebar/menu" do %>
292
+ <%= render "components/sidebar/menu_item" do %>
293
+ <%= render "components/sidebar/menu_button",
294
+ title: "Dashboard",
295
+ url: dashboard_path,
296
+ icon_name: :home,
297
+ active: current_page?(dashboard_path) %>
298
+ <% end %>
299
+ <% end %>
300
+ <% end %>
301
+ <% end %>
302
+ <% end %>
303
+
304
+ <%= render "components/sidebar/inset" do %>
305
+ <%= render "components/header" do %>
306
+ <%= render "components/sidebar/trigger", icon_name: :panel_left %>
307
+ <% end %>
308
+
309
+ <main class="flex-1 p-6">
310
+ <%= yield %>
311
+ </main>
312
+ <% end %>
313
+ <% end %>
314
+ ```
315
+
316
+ ---
317
+
318
+ ## Theming
319
+
320
+ Components use CSS variables following the [shadcn/ui theming convention](https://ui.shadcn.com/docs/theming).
321
+
322
+ The install generator adds default theme variables. Customize them in `app/assets/tailwind/application.css`:
323
+
324
+ ```css
325
+ :root {
326
+ /* Change primary to blue */
327
+ --primary: oklch(0.488 0.243 264.376);
328
+ --primary-foreground: oklch(0.985 0 0);
329
+
330
+ /* Add custom colors */
331
+ --success: oklch(0.6 0.2 145);
332
+ --success-foreground: oklch(0.985 0 0);
333
+ }
334
+
335
+ @theme {
336
+ --color-success: var(--success);
337
+ --color-success-foreground: var(--success-foreground);
338
+ }
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Helper Methods
344
+
345
+ | Helper | Purpose |
346
+ |--------|---------|
347
+ | `icon_for(name, options)` | Render an SVG icon |
348
+ | `sidebar_state(cookie_name)` | Get sidebar state (`:expanded` or `:collapsed`) |
349
+ | `sidebar_open?(cookie_name)` | Check if the sidebar is expanded |
350
+ | `pagination_nav(pagy, route)` | Render pagination from Pagy object |
351
+ | `pagination_simple(pagy, route)` | Render simple Previous/Next pagination |
352
+
353
+ ---
354
+
355
+ ## Documentation
356
+
357
+ ### Getting Started
358
+
359
+ - **[Getting Started](https://maquina.app/documentation/components/)** — Installation and setup
360
+
361
+ ### Layout
362
+
363
+ - **[Sidebar](https://maquina.app/documentation/components/sidebar/)** — Navigation sidebar
364
+ - **[Header](https://maquina.app/documentation/components/header/)** — Top navigation bar
365
+
366
+ ### Content
367
+
368
+ - **[Card](https://maquina.app/documentation/components/card/)** — Content containers
369
+ - **[Alert](https://maquina.app/documentation/components/alert/)** — Callout messages
370
+ - **[Badge](https://maquina.app/documentation/components/badge/)** — Status indicators
371
+ - **[Table](https://maquina.app/documentation/components/table/)** — Data tables
372
+ - **[Empty State](https://maquina.app/documentation/components/empty/)** — Empty state placeholders
373
+
374
+ ### Navigation
375
+
376
+ - **[Breadcrumbs](https://maquina.app/documentation/components/breadcrumbs/)** — Navigation trails
377
+ - **[Dropdown Menu](https://maquina.app/documentation/components/dropdown-menu/)** — Dropdown menus
378
+ - **[Pagination](https://maquina.app/documentation/components/pagination/)** — Page navigation
379
+
380
+ ### Interactive
381
+
382
+ - **[Toggle Group](https://maquina.app/documentation/components/toggle-group/)** — Toggle button groups
383
+
384
+ ### Forms
385
+
386
+ - **[Form Components](https://maquina.app/documentation/components/form/)** — Buttons, inputs, and form styling
387
+
388
+ ---
389
+
390
+ ## Development
391
+
392
+ Run the dummy app:
393
+
394
+ ```bash
395
+ cd test/dummy
396
+ bin/rails server
397
+ ```
398
+
399
+ Run tests:
400
+
401
+ ```bash
402
+ bin/rails test
403
+ ```
404
+
405
+ ---
406
+
24
407
  ## Contributing
25
- Contribution directions go here.
408
+
409
+ Bug reports and pull requests are welcome on GitHub at [github.com/maquina-app/maquina_components](https://github.com/maquina-app/maquina_components).
410
+
411
+ ---
26
412
 
27
413
  ## License
28
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
414
+
415
+ Copyright (c) [Mario Alberto Chávez Cárdenas](https://mariochavez.io)
416
+
417
+ The gem is available as open source under the terms of the [MIT License](MIT-LICENSE).
418
+
419
+ ---
420
+
421
+ ## Credits
422
+
423
+ - Design patterns from [shadcn/ui](https://ui.shadcn.com/)
424
+ - Built with [TailwindCSS](https://tailwindcss.com/)
425
+ - Powered by [Ruby on Rails](https://rubyonrails.org/)
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1268" height="326"><defs><linearGradient id="b" x1="21.152%" x2="100%" y1="21.848%" y2="93.468%"><stop offset="0%" stop-color="#50B1FD" stop-opacity=".96"/><stop offset="100%" stop-color="#DE77DE" stop-opacity=".96"/></linearGradient><filter id="a" width="109.8%" height="109.8%" x="-4.9%" y="-4.3%" filterUnits="objectBoundingBox"><feOffset dy="2" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="5"/><feColorMatrix in="shadowBlurOuter1" result="shadowMatrixOuter1" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><g fill="none" fill-rule="evenodd"><g fill="url(#b)" filter="url(#a)"><path d="M163 0c90.022 0 163 72.978 163 163s-72.978 163-163 163S0 253.022 0 163 72.978 0 163 0Zm-3.035 32.001-2.3.033C82.529 33.836 7.373 106.038 39.71 209.826l.128-.06.17-.085c.666-.337 2.097-1.105 4.294-2.305l.648-.355c7.567-4.142 23.12-12.79 46.658-25.942 8.07 31.143 36.39 54.144 70.088 54.144 11.29 0 21.975-2.582 31.498-7.186l38.287 21.06c-67.582 40.567-122.657 31.134-165.224-28.3l-17.485 10.496c38.51 66.185 141.812 96.167 215.685 13.364-1.55-1.057-18.929-11.076-52.136-30.058 13.432-13.13 21.768-31.441 21.768-51.698 0-24.865-12.561-46.8-31.69-59.816l-.125-44.132c68.28 39.383 86.722 92.078 55.326 158.086l17.666 10.189c39.273-65.736 15.44-170.532-92.866-194.936-.176 1.88-.526 22.209-1.052 60.983a72.517 72.517 0 0 0-19.652-2.696c-38.356 0-69.744 29.799-72.234 67.487L52.886 179.3c0-78.766 36.46-121.07 109.378-126.91V32.012l-2.3-.01Zm2.067 100.096c17.214 0 31.17 13.941 31.17 31.139 0 17.197-13.956 31.138-31.17 31.138-17.215 0-31.17-13.94-31.17-31.138s13.955-31.139 31.17-31.139Z"/></g><g fill="#50B1FD" fill-rule="nonzero"><path d="M424.59 217V102.97h23.1v48.93h-2.1c0-11.48 1.47-21.105 4.41-28.875 2.94-7.77 7.315-13.65 13.125-17.64S476.18 99.4 484.86 99.4h1.26c8.82 0 16.135 1.995 21.945 5.985 5.81 3.99 10.15 9.87 13.02 17.64 2.87 7.77 4.305 17.395 4.305 28.875h-7.35c0-11.48 1.505-21.105 4.515-28.875s7.42-13.65 13.23-17.64c5.81-3.99 13.055-5.985 21.735-5.985h1.26c8.82 0 16.17 1.995 22.05 5.985 5.88 3.99 10.325 9.87 13.335 17.64 3.01 7.77 4.515 17.395 4.515 28.875V217h-29.19v-67.83c0-7.14-1.82-12.845-5.46-17.115-3.64-4.27-8.82-6.405-15.54-6.405-6.72 0-12.11 2.205-16.17 6.615-4.06 4.41-6.09 10.325-6.09 17.745V217h-29.19v-67.83c0-7.14-1.82-12.845-5.46-17.115-3.64-4.27-8.82-6.405-15.54-6.405-6.72 0-12.11 2.205-16.17 6.615-4.06 4.41-6.09 10.325-6.09 17.745V217h-29.19ZM688.56 217v-33.81h-4.83V145.6c0-6.58-1.61-11.48-4.83-14.7-3.22-3.22-8.19-4.83-14.91-4.83-3.5 0-7.7.07-12.6.21-4.9.14-9.835.315-14.805.525-4.97.21-9.415.455-13.335.735v-24.78c3.22-.28 6.86-.56 10.92-.84 4.06-.28 8.225-.455 12.495-.525s8.295-.105 12.075-.105c11.76 0 21.525 1.54 29.295 4.62 7.77 3.08 13.65 7.91 17.64 14.49s5.985 15.19 5.985 25.83V217h-23.1Zm-36.75 2.94c-8.26 0-15.505-1.47-21.735-4.41-6.23-2.94-11.06-7.14-14.49-12.6-3.43-5.46-5.145-12.04-5.145-19.74 0-8.4 2.065-15.26 6.195-20.58 4.13-5.32 9.94-9.31 17.43-11.97s16.275-3.99 26.355-3.99h26.46v17.43H660c-6.72 0-11.865 1.645-15.435 4.935-3.57 3.29-5.355 7.525-5.355 12.705s1.785 9.38 5.355 12.6c3.57 3.22 8.715 4.83 15.435 4.83 4.06 0 7.805-.735 11.235-2.205 3.43-1.47 6.3-3.99 8.61-7.56 2.31-3.57 3.605-8.435 3.885-14.595l7.14 8.19c-.7 7.98-2.625 14.7-5.775 20.16-3.15 5.46-7.49 9.625-13.02 12.495-5.53 2.87-12.285 4.305-20.265 4.305ZM816.87 259v-75.81l8.61-13.44c-.42 10.92-2.66 20.195-6.72 27.825-4.06 7.63-9.52 13.405-16.38 17.325-6.86 3.92-14.77 5.88-23.73 5.88-8.12 0-15.47-1.505-22.05-4.515s-12.215-7.21-16.905-12.6c-4.69-5.39-8.33-11.62-10.92-18.69-2.59-7.07-3.885-14.735-3.885-22.995v-4.41c0-8.12 1.33-15.715 3.99-22.785s6.405-13.23 11.235-18.48c4.83-5.25 10.57-9.38 17.22-12.39 6.65-3.01 14.105-4.515 22.365-4.515 9.52 0 17.78 2.03 24.78 6.09 7 4.06 12.495 9.975 16.485 17.745 3.99 7.77 6.195 17.255 6.615 28.455h-4.62v-48.72h23.1V259h-29.19Zm-30.66-63.21c5.74 0 10.99-1.295 15.75-3.885s8.575-6.37 11.445-11.34c2.87-4.97 4.305-10.815 4.305-17.535v-8.4c0-6.72-1.47-12.355-4.41-16.905-2.94-4.55-6.79-8.05-11.55-10.5-4.76-2.45-9.94-3.675-15.54-3.675-6.3 0-11.865 1.505-16.695 4.515s-8.61 7.28-11.34 12.81c-2.73 5.53-4.095 11.865-4.095 19.005 0 7.14 1.4 13.405 4.2 18.795 2.8 5.39 6.615 9.59 11.445 12.6s10.325 4.515 16.485 4.515ZM907.59 220.57c-13.16 0-23.345-4.34-30.555-13.02-7.21-8.68-10.815-21.56-10.815-38.64v-66.15h29.19v68.67c0 7 1.96 12.565 5.88 16.695 3.92 4.13 9.24 6.195 15.96 6.195 6.72 0 12.215-2.17 16.485-6.51s6.405-10.22 6.405-17.64v-67.41h29.19V217h-23.1v-48.51h2.31c0 11.48-1.47 21.07-4.41 28.77-2.94 7.7-7.35 13.51-13.23 17.43-5.88 3.92-13.23 5.88-22.05 5.88h-1.26ZM997.89 217V102.97h29.19V217h-29.19Zm-15.96-92.19v-21.84h45.15v21.84h-45.15Zm26.67-35.49c-5.74 0-9.975-1.505-12.705-4.515-2.73-3.01-4.095-6.825-4.095-11.445s1.365-8.4 4.095-11.34c2.73-2.94 6.965-4.41 12.705-4.41s9.94 1.47 12.6 4.41c2.66 2.94 3.99 6.72 3.99 11.34s-1.33 8.435-3.99 11.445-6.86 4.515-12.6 4.515ZM1050.18 217V102.97h23.1v48.93h-2.1c0-11.62 1.54-21.315 4.62-29.085s7.665-13.615 13.755-17.535c6.09-3.92 13.685-5.88 22.785-5.88h1.26c13.58 0 23.87 4.375 30.87 13.125s10.5 21.805 10.5 39.165V217h-29.19v-67.83c0-7-1.995-12.67-5.985-17.01-3.99-4.34-9.485-6.51-16.485-6.51-7.14 0-12.915 2.205-17.325 6.615s-6.615 10.325-6.615 17.745V217h-29.19ZM1244.85 217v-33.81h-4.83V145.6c0-6.58-1.61-11.48-4.83-14.7-3.22-3.22-8.19-4.83-14.91-4.83-3.5 0-7.7.07-12.6.21-4.9.14-9.835.315-14.805.525-4.97.21-9.415.455-13.335.735v-24.78c3.22-.28 6.86-.56 10.92-.84 4.06-.28 8.225-.455 12.495-.525s8.295-.105 12.075-.105c11.76 0 21.525 1.54 29.295 4.62 7.77 3.08 13.65 7.91 17.64 14.49s5.985 15.19 5.985 25.83V217h-23.1Zm-36.75 2.94c-8.26 0-15.505-1.47-21.735-4.41-6.23-2.94-11.06-7.14-14.49-12.6-3.43-5.46-5.145-12.04-5.145-19.74 0-8.4 2.065-15.26 6.195-20.58 4.13-5.32 9.94-9.31 17.43-11.97s16.275-3.99 26.355-3.99h26.46v17.43h-26.88c-6.72 0-11.865 1.645-15.435 4.935-3.57 3.29-5.355 7.525-5.355 12.705s1.785 9.38 5.355 12.6c3.57 3.22 8.715 4.83 15.435 4.83 4.06 0 7.805-.735 11.235-2.205 3.43-1.47 6.3-3.99 8.61-7.56 2.31-3.57 3.605-8.435 3.885-14.595l7.14 8.19c-.7 7.98-2.625 14.7-5.775 20.16-3.15 5.46-7.49 9.625-13.02 12.495-5.53 2.87-12.285 4.305-20.265 4.305Z"/></g></g></svg>
@@ -0,0 +1,143 @@
1
+ /* ===== Alert Component Styles ===== */
2
+ /*
3
+ * Alert component for displaying callouts, messages, and notifications.
4
+ * Uses data attributes for styling to maintain consistency with other components.
5
+ * Fully compatible with dark mode via CSS variables.
6
+ */
7
+
8
+ /* ===== Base Alert Styles ===== */
9
+ [data-component="alert"] {
10
+ position: relative;
11
+ display: grid;
12
+ grid-template-columns: 1fr;
13
+ @apply w-full rounded-lg border p-4 text-sm;
14
+
15
+ /* Default colors */
16
+ background-color: var(--background);
17
+ color: var(--foreground);
18
+ border-color: var(--border);
19
+ }
20
+
21
+ /* Alert with icon - add left padding for icon space */
22
+ [data-component="alert"][data-has-icon="true"] {
23
+ grid-template-columns: auto 1fr;
24
+ @apply gap-3;
25
+ }
26
+
27
+ /* ===== Icon Support ===== */
28
+ [data-component="alert"] > svg:first-child,
29
+ [data-component="alert"] [data-alert-part="icon"] {
30
+ @apply size-4 shrink-0;
31
+ color: var(--foreground);
32
+ /* Align with first line of text */
33
+ margin-top: 0.125rem;
34
+ }
35
+
36
+ /* ===== Alert Title ===== */
37
+ [data-component="alert"] [data-alert-part="title"] {
38
+ @apply font-medium leading-none tracking-tight;
39
+ color: var(--foreground);
40
+ }
41
+
42
+ /* Title followed by description needs margin */
43
+ [data-component="alert"] [data-alert-part="title"]:has(+ [data-alert-part="description"]) {
44
+ @apply mb-1;
45
+ }
46
+
47
+ /* ===== Alert Description ===== */
48
+ [data-component="alert"] [data-alert-part="description"] {
49
+ @apply text-sm;
50
+ color: var(--muted-foreground);
51
+ }
52
+
53
+ /* Nested paragraphs */
54
+ [data-component="alert"] [data-alert-part="description"] p {
55
+ @apply leading-relaxed;
56
+ }
57
+
58
+ /* Lists inside description */
59
+ [data-component="alert"] [data-alert-part="description"] ul {
60
+ @apply mt-2 list-inside list-disc;
61
+ }
62
+
63
+ /* ===== Variant: Default ===== */
64
+ [data-component="alert"][data-variant="default"] {
65
+ background-color: var(--background);
66
+ color: var(--foreground);
67
+ border-color: var(--border);
68
+ }
69
+
70
+ [data-component="alert"][data-variant="default"] > svg:first-child,
71
+ [data-component="alert"][data-variant="default"] [data-alert-part="icon"] {
72
+ color: var(--foreground);
73
+ }
74
+
75
+ /* ===== Variant: Destructive ===== */
76
+ [data-component="alert"][data-variant="destructive"] {
77
+ background-color: var(--destructive);
78
+ color: var(--destructive-foreground);
79
+ border-color: var(--destructive);
80
+ }
81
+
82
+ [data-component="alert"][data-variant="destructive"] [data-alert-part="title"] {
83
+ color: var(--destructive-foreground);
84
+ }
85
+
86
+ [data-component="alert"][data-variant="destructive"] [data-alert-part="description"] {
87
+ color: var(--destructive-foreground);
88
+ opacity: 0.9;
89
+ }
90
+
91
+ [data-component="alert"][data-variant="destructive"] > svg:first-child,
92
+ [data-component="alert"][data-variant="destructive"] [data-alert-part="icon"] {
93
+ color: var(--destructive-foreground);
94
+ }
95
+
96
+ /* ===== Variant: Success ===== */
97
+ [data-component="alert"][data-variant="success"] {
98
+ background-color: var(--success);
99
+ color: var(--success-foreground);
100
+ border-color: var(--success);
101
+ }
102
+
103
+ [data-component="alert"][data-variant="success"] [data-alert-part="title"] {
104
+ color: var(--success-foreground);
105
+ }
106
+
107
+ [data-component="alert"][data-variant="success"] [data-alert-part="description"] {
108
+ color: var(--success-foreground);
109
+ opacity: 0.9;
110
+ }
111
+
112
+ [data-component="alert"][data-variant="success"] > svg:first-child,
113
+ [data-component="alert"][data-variant="success"] [data-alert-part="icon"] {
114
+ color: var(--success-foreground);
115
+ }
116
+
117
+ /* ===== Variant: Warning ===== */
118
+ [data-component="alert"][data-variant="warning"] {
119
+ background-color: var(--warning);
120
+ color: var(--warning-foreground);
121
+ border-color: var(--warning);
122
+ }
123
+
124
+ [data-component="alert"][data-variant="warning"] [data-alert-part="title"] {
125
+ color: var(--warning-foreground);
126
+ }
127
+
128
+ [data-component="alert"][data-variant="warning"] [data-alert-part="description"] {
129
+ color: var(--warning-foreground);
130
+ opacity: 0.9;
131
+ }
132
+
133
+ [data-component="alert"][data-variant="warning"] > svg:first-child,
134
+ [data-component="alert"][data-variant="warning"] [data-alert-part="icon"] {
135
+ color: var(--warning-foreground);
136
+ }
137
+
138
+ /* ===== Dark Mode ===== */
139
+ /*
140
+ * Dark mode is handled automatically through CSS variables.
141
+ * The theme variables change based on the .dark class on html/body.
142
+ * No additional dark mode styles needed here.
143
+ */