maquina-components 0.1.2 → 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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +349 -138
  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 +143 -64
  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/{components → maquina_components}/icons_helper.rb +40 -3
  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 +11 -10
  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 +4 -8
  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 +12 -33
  42. data/app/views/components/_separator.html.erb +11 -0
  43. data/app/views/components/_sidebar.html.erb +30 -20
  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 +116 -12
  108. data/app/helpers/components/pagination_helper.rb +0 -15
  109. data/app/views/components/_card_content.html.erb +0 -5
  110. data/app/views/components/_card_header.html.erb +0 -8
  111. data/app/views/components/_sidebar_content.html.erb +0 -8
  112. data/app/views/components/_sidebar_group.html.erb +0 -42
  113. data/app/views/components/_sidebar_header.html.erb +0 -3
@@ -0,0 +1,248 @@
1
+ /* ===== Dropdown Menu Component Styles ===== */
2
+ /*
3
+ * Dropdown menu component for displaying actions triggered by a button.
4
+ * Uses data attributes for styling to avoid inline utility classes.
5
+ * Fully compatible with dark mode via CSS variables.
6
+ *
7
+ * Structure:
8
+ * - dropdown-menu (root with Stimulus controller)
9
+ * - trigger (button that opens menu)
10
+ * - content (positioned menu container)
11
+ * - label (section heading)
12
+ * - group (logical grouping)
13
+ * - item (clickable action)
14
+ * - separator (divider)
15
+ * - shortcut (keyboard hint)
16
+ */
17
+
18
+ /* ===== Root Container ===== */
19
+ [data-component="dropdown-menu"] {
20
+ position: relative;
21
+ display: inline-block;
22
+ }
23
+
24
+ /* ===== Trigger Button ===== */
25
+ /* Trigger uses button component styles via data-component="button" */
26
+ /* Additional dropdown-specific styles */
27
+ [data-component="dropdown-menu"] [data-dropdown-menu-target="trigger"] {
28
+ @apply gap-2;
29
+ }
30
+
31
+ /* Chevron icon rotation when open */
32
+ [data-component="dropdown-menu"] [data-dropdown-menu-target="chevron"] {
33
+ @apply size-4 shrink-0 opacity-50 transition-transform duration-200;
34
+ }
35
+
36
+ [data-component="dropdown-menu"][data-state="open"] [data-dropdown-menu-target="chevron"] {
37
+ transform: rotate(180deg);
38
+ }
39
+
40
+ /* ===== Content Container ===== */
41
+ [data-dropdown-menu-part="content"] {
42
+ position: absolute;
43
+ z-index: 50;
44
+ display: none;
45
+ flex-direction: column;
46
+ overflow: hidden;
47
+ background-color: var(--popover, var(--background));
48
+ color: var(--popover-foreground, var(--foreground));
49
+ @apply min-w-[8rem] rounded-md border p-1 shadow-md;
50
+ border-color: var(--border);
51
+
52
+ /* Animation setup */
53
+ @apply transition-all duration-150 ease-out;
54
+ }
55
+
56
+ /* Visible state */
57
+ [data-dropdown-menu-part="content"][data-state="open"] {
58
+ display: flex;
59
+ }
60
+
61
+ /* Animation states */
62
+ [data-dropdown-menu-part="content"][data-state="open"] {
63
+ animation: dropdown-menu-in 150ms ease-out;
64
+ }
65
+
66
+ [data-dropdown-menu-part="content"][data-state="closing"] {
67
+ display: flex;
68
+ animation: dropdown-menu-out 100ms ease-in forwards;
69
+ }
70
+
71
+ @keyframes dropdown-menu-in {
72
+ from {
73
+ opacity: 0;
74
+ transform: scale(0.95) translateY(-4px);
75
+ }
76
+ to {
77
+ opacity: 1;
78
+ transform: scale(1) translateY(0);
79
+ }
80
+ }
81
+
82
+ @keyframes dropdown-menu-out {
83
+ from {
84
+ opacity: 1;
85
+ transform: scale(1) translateY(0);
86
+ }
87
+ to {
88
+ opacity: 0;
89
+ transform: scale(0.95) translateY(-4px);
90
+ }
91
+ }
92
+
93
+ /* ===== Width Variants ===== */
94
+ [data-dropdown-menu-part="content"][data-width="default"] {
95
+ @apply min-w-[8rem];
96
+ }
97
+
98
+ [data-dropdown-menu-part="content"][data-width="sm"] {
99
+ @apply w-40;
100
+ }
101
+
102
+ [data-dropdown-menu-part="content"][data-width="md"] {
103
+ @apply w-56;
104
+ }
105
+
106
+ [data-dropdown-menu-part="content"][data-width="lg"] {
107
+ @apply w-72;
108
+ }
109
+
110
+ /* ===== Alignment ===== */
111
+ [data-dropdown-menu-part="content"][data-align="start"] {
112
+ left: 0;
113
+ }
114
+
115
+ [data-dropdown-menu-part="content"][data-align="center"] {
116
+ left: 50%;
117
+ transform: translateX(-50%);
118
+ }
119
+
120
+ [data-dropdown-menu-part="content"][data-align="center"][data-state="open"] {
121
+ animation: dropdown-menu-in-center 150ms ease-out;
122
+ }
123
+
124
+ @keyframes dropdown-menu-in-center {
125
+ from {
126
+ opacity: 0;
127
+ transform: translateX(-50%) scale(0.95) translateY(-4px);
128
+ }
129
+ to {
130
+ opacity: 1;
131
+ transform: translateX(-50%) scale(1) translateY(0);
132
+ }
133
+ }
134
+
135
+ [data-dropdown-menu-part="content"][data-align="end"] {
136
+ right: 0;
137
+ }
138
+
139
+ /* ===== Side Positioning ===== */
140
+ [data-dropdown-menu-part="content"][data-side="bottom"] {
141
+ top: 100%;
142
+ @apply mt-1;
143
+ }
144
+
145
+ [data-dropdown-menu-part="content"][data-side="top"] {
146
+ bottom: 100%;
147
+ @apply mb-1;
148
+ }
149
+
150
+ [data-dropdown-menu-part="content"][data-side="left"] {
151
+ right: 100%;
152
+ top: 0;
153
+ @apply mr-1;
154
+ }
155
+
156
+ [data-dropdown-menu-part="content"][data-side="right"] {
157
+ left: 100%;
158
+ top: 0;
159
+ @apply ml-1;
160
+ }
161
+
162
+ /* ===== Menu Item ===== */
163
+ [data-dropdown-menu-part="item"] {
164
+ position: relative;
165
+ display: flex;
166
+ align-items: center;
167
+ cursor: default;
168
+ user-select: none;
169
+ color: var(--popover-foreground, var(--foreground));
170
+ @apply gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors;
171
+ }
172
+
173
+ /* Reset link styles */
174
+ a[data-dropdown-menu-part="item"] {
175
+ text-decoration: none;
176
+ color: inherit;
177
+ }
178
+
179
+ /* Hover state */
180
+ [data-dropdown-menu-part="item"]:hover:not([disabled]):not([aria-disabled="true"]) {
181
+ background-color: var(--accent);
182
+ color: var(--accent-foreground);
183
+ cursor: pointer;
184
+ }
185
+
186
+ /* Focus state (keyboard navigation) */
187
+ [data-dropdown-menu-part="item"]:focus {
188
+ background-color: var(--accent);
189
+ color: var(--accent-foreground);
190
+ }
191
+
192
+ /* Disabled state */
193
+ [data-dropdown-menu-part="item"][disabled],
194
+ [data-dropdown-menu-part="item"][aria-disabled="true"] {
195
+ @apply opacity-50 cursor-not-allowed pointer-events-none;
196
+ }
197
+
198
+ /* Destructive variant */
199
+ [data-dropdown-menu-part="item"][data-variant="destructive"] {
200
+ color: var(--destructive);
201
+ }
202
+
203
+ [data-dropdown-menu-part="item"][data-variant="destructive"]:hover:not([disabled]):not([aria-disabled="true"]),
204
+ [data-dropdown-menu-part="item"][data-variant="destructive"]:focus {
205
+ background-color: var(--destructive);
206
+ color: var(--destructive-foreground);
207
+ }
208
+
209
+ /* Icon support */
210
+ [data-dropdown-menu-part="item"] svg {
211
+ @apply size-4 shrink-0 pointer-events-none;
212
+ }
213
+
214
+ /* ===== Label ===== */
215
+ [data-dropdown-menu-part="label"] {
216
+ @apply px-2 py-1.5 text-sm font-semibold;
217
+ color: var(--foreground);
218
+ }
219
+
220
+ /* Inset variant (aligns with items that have icons) */
221
+ [data-dropdown-menu-part="label"][data-inset="true"] {
222
+ @apply pl-8;
223
+ }
224
+
225
+ /* ===== Separator ===== */
226
+ [data-dropdown-menu-part="separator"] {
227
+ @apply -mx-1 my-1 h-px;
228
+ background-color: var(--muted);
229
+ }
230
+
231
+ /* ===== Group ===== */
232
+ [data-dropdown-menu-part="group"] {
233
+ display: flex;
234
+ flex-direction: column;
235
+ }
236
+
237
+ /* ===== Shortcut ===== */
238
+ [data-dropdown-menu-part="shortcut"] {
239
+ @apply ml-auto text-xs tracking-widest;
240
+ color: var(--muted-foreground);
241
+ }
242
+
243
+ /* ===== Dark Mode ===== */
244
+ /*
245
+ * Dark mode is handled automatically through CSS variables.
246
+ * The theme variables change based on the .dark class on html/body.
247
+ * No additional dark mode styles needed here.
248
+ */
@@ -0,0 +1,133 @@
1
+ /* ===== Empty Component Styles ===== */
2
+ /*
3
+ * Empty state component for displaying placeholder content when no data exists.
4
+ * Uses data attributes for styling to avoid inline utility classes.
5
+ * Fully compatible with dark mode via CSS variables.
6
+ *
7
+ * Structure:
8
+ * - empty (root container)
9
+ * - header (groups media + text)
10
+ * - media (icon or avatar)
11
+ * - title (heading)
12
+ * - description (explanatory text)
13
+ * - content (action buttons/links)
14
+ */
15
+
16
+ /* ===== Root Container ===== */
17
+ [data-component="empty"] {
18
+ display: flex;
19
+ flex-direction: column;
20
+ align-items: center;
21
+ justify-content: center;
22
+ text-align: center;
23
+ @apply px-6 py-12;
24
+ }
25
+
26
+ /* ===== Size Variants ===== */
27
+ [data-component="empty"][data-size="compact"] {
28
+ @apply px-6 py-8;
29
+ }
30
+
31
+ /* ===== Visual Variants ===== */
32
+ [data-component="empty"][data-variant="default"] {
33
+ /* No additional styles for default */
34
+ }
35
+
36
+ [data-component="empty"][data-variant="outline"] {
37
+ @apply rounded-lg;
38
+ border: 1px dashed var(--border);
39
+ }
40
+
41
+ /* ===== Header ===== */
42
+ [data-empty-part="header"] {
43
+ display: flex;
44
+ flex-direction: column;
45
+ align-items: center;
46
+ @apply gap-2;
47
+ }
48
+
49
+ /* ===== Media (Icon/Avatar Container) ===== */
50
+ [data-empty-part="media"] {
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ color: var(--muted-foreground);
55
+ @apply mb-2;
56
+ }
57
+
58
+ /* Icon variant */
59
+ [data-empty-part="media"][data-variant="icon"] {
60
+ @apply opacity-60;
61
+ }
62
+
63
+ [data-empty-part="media"][data-variant="icon"] svg {
64
+ @apply size-12;
65
+ }
66
+
67
+ /* Compact size adjustments */
68
+ [data-component="empty"][data-size="compact"] [data-empty-part="media"][data-variant="icon"] svg {
69
+ @apply size-8;
70
+ }
71
+
72
+ /* Avatar variant */
73
+ [data-empty-part="media"][data-variant="avatar"] {
74
+ @apply size-16 rounded-full overflow-hidden;
75
+ background-color: var(--muted);
76
+ }
77
+
78
+ [data-empty-part="media"][data-variant="avatar"] img {
79
+ @apply size-full object-cover;
80
+ }
81
+
82
+ /* ===== Title ===== */
83
+ [data-empty-part="title"] {
84
+ color: var(--foreground);
85
+ @apply text-base font-medium;
86
+ }
87
+
88
+ /* Compact size */
89
+ [data-component="empty"][data-size="compact"] [data-empty-part="title"] {
90
+ @apply text-sm;
91
+ }
92
+
93
+ /* ===== Description ===== */
94
+ [data-empty-part="description"] {
95
+ color: var(--muted-foreground);
96
+ @apply text-sm mt-1 max-w-md;
97
+ }
98
+
99
+ /* Links in description */
100
+ [data-empty-part="description"] a {
101
+ color: var(--primary);
102
+ text-decoration: underline;
103
+ text-underline-offset: 4px;
104
+ }
105
+
106
+ [data-empty-part="description"] a:hover {
107
+ @apply opacity-80;
108
+ }
109
+
110
+ /* ===== Content (Actions) ===== */
111
+ [data-empty-part="content"] {
112
+ display: flex;
113
+ flex-direction: column;
114
+ align-items: center;
115
+ @apply mt-6 gap-3;
116
+ }
117
+
118
+ /* Compact size */
119
+ [data-component="empty"][data-size="compact"] [data-empty-part="content"] {
120
+ @apply mt-4;
121
+ }
122
+
123
+ /* Flex container for multiple buttons */
124
+ [data-empty-part="content"] > .flex {
125
+ @apply gap-2;
126
+ }
127
+
128
+ /* ===== Dark Mode ===== */
129
+ /*
130
+ * Dark mode is handled automatically through CSS variables.
131
+ * The theme variables change based on the .dark class on html/body.
132
+ * No additional dark mode styles needed here.
133
+ */