maquina-components 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +197 -11
- data/app/assets/stylesheets/maquina_components.css +99 -0
- data/app/helpers/components/icons_helper.rb +124 -0
- data/app/helpers/components/pagination_helper.rb +15 -0
- data/app/views/components/_alert.html.erb +11 -0
- data/app/views/components/_card.html.erb +10 -0
- data/app/views/components/_card_content.html.erb +5 -0
- data/app/views/components/_card_header.html.erb +8 -0
- data/app/views/components/_pagination.html.erb +34 -0
- data/app/views/components/_sidebar.html.erb +30 -0
- data/app/views/components/_sidebar_content.html.erb +8 -0
- data/app/views/components/_sidebar_group.html.erb +42 -0
- data/app/views/components/_sidebar_header.html.erb +3 -0
- data/lib/maquina_components/version.rb +1 -1
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61b5b2a30e1774c16e25bc87743e5b29e1e8ede10e55f76fbd0ab953108921f4
|
4
|
+
data.tar.gz: 7d932af15e3e997b0e369e54e5189c18f7ebb6ce407150957323444f70199aa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4476d4fa6fa5cd882706e2a64a25ae8a5537b1f8d5d214f7d0960a7fc2b294f1d3f034b283be0979cd9e8f23290b4e7b46c2baf81c011727fa0b33551dea0a60
|
7
|
+
data.tar.gz: 53cd0563b8e6ce33ab34fd38ba19cec938514a1d0be558b4c6e95a36fffcd2068b25f9f7e07e2fde12f61c9a30e62f6e16f5b41bb56233b1b9fe5bd77a5adeee
|
data/README.md
CHANGED
@@ -1,28 +1,214 @@
|
|
1
|
-
#
|
2
|
-
Short description and motivation.
|
1
|
+
# Maquina Components
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
Modern UI components for Ruby on Rails, powered by TailwindCSS and Stimulus
|
4
|
+
|
5
|
+
![Dashboard Example](/imgs/home.png)
|
6
|
+
|
7
|
+
![Form Example](/imgs/new.png)
|
8
|
+
|
9
|
+
## Overview
|
10
|
+
|
11
|
+
Maquina Components provides a collection of ready-to-use UI components for Ruby on Rails applications. Built with ERB,
|
12
|
+
TailwindCSS 4.0, and Stimulus, it offers a modern and maintainable approach to building beautiful user interfaces
|
13
|
+
without the complexity of JavaScript frameworks.
|
14
|
+
|
15
|
+
### Key Features
|
16
|
+
|
17
|
+
- 🎨 Pre-built UI components based on shadcn/ui design system
|
18
|
+
- ⚡️ Powered by TailwindCSS 4.0
|
19
|
+
- 🧩 Seamless Rails integration with ERB partials
|
20
|
+
- 📱 Fully responsive components
|
21
|
+
- 🎯 Interactive behaviors with Stimulus controllers
|
22
|
+
- 🌙 Dark mode support out of the box
|
23
|
+
- ♿️ Accessibility-first components
|
6
24
|
|
7
25
|
## Installation
|
26
|
+
|
8
27
|
Add this line to your application's Gemfile:
|
9
28
|
|
10
29
|
```ruby
|
11
|
-
gem
|
30
|
+
gem 'maquina-components'
|
12
31
|
```
|
13
32
|
|
14
|
-
|
33
|
+
Then execute:
|
34
|
+
|
15
35
|
```bash
|
16
|
-
|
36
|
+
bundle install
|
17
37
|
```
|
18
38
|
|
19
|
-
|
20
|
-
|
21
|
-
|
39
|
+
### Setup
|
40
|
+
|
41
|
+
1. Install TailwindCSS 4.0 in your Rails application
|
42
|
+
2. Add the required Stimulus controllers to your application
|
43
|
+
3. Use Shadcn/UI standard color variables:
|
44
|
+
|
45
|
+
```css
|
46
|
+
/* app/assets/stylesheets/application.css */
|
47
|
+
|
48
|
+
@theme {
|
49
|
+
/* Default background color of <body />...etc */
|
50
|
+
--color-background: var(--background);
|
51
|
+
--color-foreground: var(--foreground);
|
52
|
+
|
53
|
+
/* Primary colors for Button */
|
54
|
+
--color-primary: var(--primary-color);
|
55
|
+
--color-primary-foreground: var(--primary-foreground-color);
|
56
|
+
|
57
|
+
/* Muted colors */
|
58
|
+
--color-muted: var(--muted);
|
59
|
+
--color-muted-foreground: var(--muted-foreground);
|
60
|
+
|
61
|
+
/* Secondary colors */
|
62
|
+
--color-secondary: var(--secondary);
|
63
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
64
|
+
|
65
|
+
/* Accent colors */
|
66
|
+
--color-accent: var(--accent);
|
67
|
+
--color-accent-foreground: var(--accent-foreground);
|
68
|
+
|
69
|
+
/* Destructive colors */
|
70
|
+
--color-destructive: var(--destructive);
|
71
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
72
|
+
|
73
|
+
/* Default input color */
|
74
|
+
--color-input: var(--input);
|
75
|
+
|
76
|
+
/* Default border color */
|
77
|
+
--color-border: var(--border);
|
78
|
+
|
79
|
+
/* Default ring color */
|
80
|
+
--color-ring: var(--ring);
|
81
|
+
--color-ring-destructive: var(--destructive);
|
82
|
+
|
83
|
+
/* Background color for Card */
|
84
|
+
--color-card: var(--card);
|
85
|
+
--color-card-foreground: var(--card-foreground);
|
86
|
+
|
87
|
+
/* Sidebar colors */
|
88
|
+
--color-sidebar: var(--sidebar-background);
|
89
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
90
|
+
|
91
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
92
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
93
|
+
|
94
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
95
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
96
|
+
|
97
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
98
|
+
--color-sidebar-border: var(--sidebar-border);
|
99
|
+
}
|
100
|
+
```
|
101
|
+
|
102
|
+
## Usage
|
103
|
+
|
104
|
+
### Basic Layout Example
|
105
|
+
|
106
|
+
```erb
|
107
|
+
<%# app/views/layouts/application.html.erb %>
|
108
|
+
<body class="bg-background text-primary font-display antialiased">
|
109
|
+
<div class="flex min-h-screen">
|
110
|
+
<%= render "components/sidebar" do %>
|
111
|
+
<%= render "components/sidebar_header" do %>
|
112
|
+
<%= render "shared/ui/menu_button",
|
113
|
+
title: "My App",
|
114
|
+
subtitle: "Dashboard",
|
115
|
+
text_icon: "MA" %>
|
116
|
+
<% end %>
|
117
|
+
|
118
|
+
<%= render "components/sidebar_content" do %>
|
119
|
+
<!-- Sidebar content here -->
|
120
|
+
<% end %>
|
121
|
+
<% end %>
|
122
|
+
|
123
|
+
<main class="flex-1 pl-(--sidebar-width)">
|
124
|
+
<%= yield %>
|
125
|
+
</main>
|
126
|
+
</div>
|
127
|
+
</body>
|
128
|
+
```
|
129
|
+
|
130
|
+
### Components
|
131
|
+
|
132
|
+
#### Cards
|
133
|
+
|
134
|
+
```erb
|
135
|
+
<%= render "components/card" do %>
|
136
|
+
<%= render "components/card_header",
|
137
|
+
title: "Account Balance",
|
138
|
+
icon: :dollar %>
|
139
|
+
|
140
|
+
<%= render "components/card_content" do %>
|
141
|
+
<p class="text-2xl font-bold">
|
142
|
+
<%= number_to_currency(@balance) %>
|
143
|
+
</p>
|
144
|
+
<p class="text-xs text-muted-foreground">
|
145
|
+
Current balance
|
146
|
+
</p>
|
147
|
+
<% end %>
|
148
|
+
<% end %>
|
149
|
+
```
|
150
|
+
|
151
|
+
#### Buttons
|
152
|
+
|
153
|
+
```erb
|
154
|
+
<%= link_to new_transaction_path, class: "button-primary" do %>
|
155
|
+
New Transaction
|
156
|
+
<%= icon_for(:money) %>
|
157
|
+
<% end %>
|
158
|
+
```
|
159
|
+
|
160
|
+
## Available Components
|
161
|
+
|
162
|
+
Work in progress...
|
163
|
+
|
164
|
+
- Layout
|
165
|
+
- Sidebar
|
166
|
+
- Card
|
167
|
+
- Navigation
|
168
|
+
- Menu Button
|
169
|
+
- Navigation Menu
|
170
|
+
- Elements
|
171
|
+
- Button
|
172
|
+
- Alert
|
173
|
+
- Badge
|
174
|
+
- Forms
|
175
|
+
- Input
|
176
|
+
- Select
|
177
|
+
- Checkbox
|
178
|
+
- Radio
|
179
|
+
|
180
|
+
## Customization
|
181
|
+
|
182
|
+
### Theme Configuration
|
183
|
+
|
184
|
+
Customize the look and feel of your components by modifying the theme variables:
|
185
|
+
|
186
|
+
```css
|
187
|
+
@theme {
|
188
|
+
/* Colors */
|
189
|
+
--color-primary: oklch(21.34% 0 0);
|
190
|
+
--color-primary-foreground: oklch(98.48% 0 0);
|
191
|
+
|
192
|
+
/* Typography */
|
193
|
+
--font-display: "Inter var", "sans-serif";
|
194
|
+
|
195
|
+
/* Spacing */
|
196
|
+
--sidebar-width: 16rem;
|
197
|
+
|
198
|
+
/* ... other customizations ... */
|
199
|
+
}
|
22
200
|
```
|
23
201
|
|
24
202
|
## Contributing
|
25
|
-
|
203
|
+
|
204
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/maquina-app/maquina_components>.
|
26
205
|
|
27
206
|
## License
|
207
|
+
|
28
208
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
209
|
+
|
210
|
+
## Acknowledgments
|
211
|
+
|
212
|
+
- Design system inspired by [shadcn/ui](https://ui.shadcn.com/)
|
213
|
+
- Built with [TailwindCSS](https://tailwindcss.com/)
|
214
|
+
- Powered by [Ruby on Rails](https://rubyonrails.org/)
|
@@ -0,0 +1,99 @@
|
|
1
|
+
@utility button-base {
|
2
|
+
display: inline-flex;
|
3
|
+
align-items: center;
|
4
|
+
justify-content: center;
|
5
|
+
gap: 0.5rem;
|
6
|
+
/* gap-2 */
|
7
|
+
white-space: nowrap;
|
8
|
+
border-radius: 0.375rem;
|
9
|
+
/* rounded-md */
|
10
|
+
font-size: 0.875rem;
|
11
|
+
/* text-sm */
|
12
|
+
font-weight: 500;
|
13
|
+
/* font-medium */
|
14
|
+
height: 2.25rem;
|
15
|
+
/* h-9 */
|
16
|
+
padding: 0.5rem 1rem;
|
17
|
+
/* px-4 py-2 */
|
18
|
+
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
|
19
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
20
|
+
transition-duration: 150ms;
|
21
|
+
|
22
|
+
&:focus-visible {
|
23
|
+
outline: none;
|
24
|
+
ring-width: 1px;
|
25
|
+
ring-color: var(--color-ring);
|
26
|
+
}
|
27
|
+
|
28
|
+
&:disabled {
|
29
|
+
pointer-events: none;
|
30
|
+
opacity: 0.5;
|
31
|
+
}
|
32
|
+
|
33
|
+
& svg {
|
34
|
+
pointer-events: none;
|
35
|
+
width: 1rem;
|
36
|
+
/* size-4 */
|
37
|
+
height: 1rem;
|
38
|
+
/* size-4 */
|
39
|
+
flex-shrink: 0;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
/* Form */
|
44
|
+
.form-base {
|
45
|
+
@apply flex flex-col w-full gap-6;
|
46
|
+
}
|
47
|
+
|
48
|
+
.form-group {
|
49
|
+
@apply flex flex-col gap-2;
|
50
|
+
}
|
51
|
+
|
52
|
+
.form-label {
|
53
|
+
@apply text-foreground text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70;
|
54
|
+
}
|
55
|
+
|
56
|
+
.form-input {
|
57
|
+
@apply flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm;
|
58
|
+
}
|
59
|
+
|
60
|
+
.form-select {
|
61
|
+
@apply col-start-1 row-start-1 w-full appearance-none rounded-md bg-transparent py-1.5 pl-3 pr-8 text-base text-foreground border border-input shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm/6;
|
62
|
+
}
|
63
|
+
|
64
|
+
.form-select-group {
|
65
|
+
@apply grid grid-cols-1;
|
66
|
+
|
67
|
+
& svg {
|
68
|
+
@apply pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-muted-foreground sm:size-4;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
.form-help-text {
|
73
|
+
@apply text-sm text-muted-foreground;
|
74
|
+
}
|
75
|
+
|
76
|
+
.form-error-text {
|
77
|
+
@apply text-sm text-destructive;
|
78
|
+
}
|
79
|
+
|
80
|
+
/* Buttons */
|
81
|
+
.button-primary {
|
82
|
+
@apply button-base bg-primary text-primary-foreground hover:bg-primary/90;
|
83
|
+
}
|
84
|
+
|
85
|
+
.button-secondary {
|
86
|
+
@apply button-base bg-secondary text-secondary-foreground hover:bg-secondary/80;
|
87
|
+
}
|
88
|
+
|
89
|
+
.button-ghost {
|
90
|
+
@apply button-base hover:bg-secondary hover:text-secondary-foreground;
|
91
|
+
}
|
92
|
+
|
93
|
+
.button-outline {
|
94
|
+
@apply button-base border border-border bg-background shadow-sm hover:bg-secondary/40 hover:text-secondary-foreground;
|
95
|
+
}
|
96
|
+
|
97
|
+
.button-destructive {
|
98
|
+
@apply button-base bg-destructive text-destructive shadow-sm hover:bg-destructive/90;
|
99
|
+
}
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Components
|
2
|
+
module IconsHelper
|
3
|
+
def icon_for(name, options = {})
|
4
|
+
return nil unless name
|
5
|
+
|
6
|
+
svg = 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
|
+
private
|
20
|
+
|
21
|
+
def icon_svg_for(name)
|
22
|
+
case name
|
23
|
+
when :dollar
|
24
|
+
<<~SVG.freeze
|
25
|
+
<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="">
|
26
|
+
<line x1="12" y1="2" x2="12" y2="22"></line>
|
27
|
+
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>
|
28
|
+
</svg>
|
29
|
+
SVG
|
30
|
+
when :users
|
31
|
+
<<~SVG.freeze
|
32
|
+
<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">
|
33
|
+
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path>
|
34
|
+
<circle cx="9" cy="7" r="4"></circle>
|
35
|
+
<path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"></path>
|
36
|
+
</svg>
|
37
|
+
SVG
|
38
|
+
when :credit_card
|
39
|
+
<<~SVG.freeze
|
40
|
+
<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">
|
41
|
+
<rect width="20" height="14" x="2" y="5" rx="2"></rect>
|
42
|
+
<line x1="2" y1="10" x2="22" y2="10"></line>
|
43
|
+
</svg>
|
44
|
+
SVG
|
45
|
+
when :activity
|
46
|
+
<<~SVG.freeze
|
47
|
+
<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">
|
48
|
+
<path d="M22 12h-4l-3 9L9 3l-3 9H2"></path>
|
49
|
+
</svg>
|
50
|
+
SVG
|
51
|
+
when :trend_up
|
52
|
+
<<~SVG.freeze
|
53
|
+
<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="">
|
54
|
+
<polyline points="22 7 13.5 15.5 8.5 10.5 2 17"></polyline>
|
55
|
+
<polyline points="16 7 22 7 22 13"></polyline>
|
56
|
+
</svg>
|
57
|
+
SVG
|
58
|
+
when :trend_down
|
59
|
+
<<~SVG.freeze
|
60
|
+
<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="">
|
61
|
+
<polyline points="22 17 13.5 8.5 8.5 13.5 2 7"></polyline>
|
62
|
+
<polyline points="16 17 22 17 22 11"></polyline>
|
63
|
+
</svg>
|
64
|
+
SVG
|
65
|
+
when :clock
|
66
|
+
<<~SVG.freeze
|
67
|
+
<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="">
|
68
|
+
<circle cx="12" cy="12" r="10"></circle>
|
69
|
+
<polyline points="12 6 12 12 16 14"></polyline>
|
70
|
+
</svg>
|
71
|
+
SVG
|
72
|
+
when :money
|
73
|
+
<<~SVG.freeze
|
74
|
+
<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="">
|
75
|
+
<rect width="20" height="12" x="2" y="6" rx="2"></rect>
|
76
|
+
<circle cx="12" cy="12" r="2"></circle>
|
77
|
+
<path d="M6 12h.01M18 12h.01"></path>
|
78
|
+
</svg>
|
79
|
+
SVG
|
80
|
+
when :line_chart
|
81
|
+
<<~SVG.freeze
|
82
|
+
<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="">
|
83
|
+
<path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/>
|
84
|
+
</svg>
|
85
|
+
SVG
|
86
|
+
when :piggy_bank
|
87
|
+
<<~SVG.freeze
|
88
|
+
<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="">
|
89
|
+
<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"/>
|
90
|
+
<path d="M2 9v1c0 1.1.9 2 2 2h1"/>
|
91
|
+
<path d="M16 11h0"/>
|
92
|
+
</svg>
|
93
|
+
SVG
|
94
|
+
when :arrow_left
|
95
|
+
<<~SVG.freeze
|
96
|
+
<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="">
|
97
|
+
<line x1="19" y1="12" x2="5" y2="12"></line>
|
98
|
+
<polyline points="12 19 5 12 12 5"></polyline>
|
99
|
+
</svg>
|
100
|
+
SVG
|
101
|
+
when :select_chevron
|
102
|
+
<<~SVG.freeze
|
103
|
+
<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">
|
104
|
+
<path d="m6 9 6 6 6-6"></path>
|
105
|
+
</svg>
|
106
|
+
SVG
|
107
|
+
when :check
|
108
|
+
<<~SVG.freeze
|
109
|
+
<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="">
|
110
|
+
<path d="M20 6 9 17l-5-5"/>
|
111
|
+
</svg>
|
112
|
+
SVG
|
113
|
+
when :circle_alert
|
114
|
+
<<~SVG.freeze
|
115
|
+
<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="">
|
116
|
+
<circle cx="12" cy="12" r="10"/>
|
117
|
+
<line x1="12" x2="12" y1="8" y2="12"/>
|
118
|
+
<line x1="12" x2="12.01" y1="16" y2="16"/>
|
119
|
+
</svg>
|
120
|
+
SVG
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Components
|
2
|
+
module PaginationHelper
|
3
|
+
def paginated_page_param(pagy, page)
|
4
|
+
@page_param ||= pagy.vars[:page_param] || Pagy::VARS[:page_param]
|
5
|
+
@query_parameters ||= request.query_parameters
|
6
|
+
|
7
|
+
@query_parameters.merge(@page_param => page)
|
8
|
+
end
|
9
|
+
|
10
|
+
def paginated_path(path_helper, pagy, page, param)
|
11
|
+
page_query = paginated_page_param(pagy, page)
|
12
|
+
send(path_helper, param, page_query)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%# locals: (title: nil) %>
|
2
|
+
<% if notice || alert %>
|
3
|
+
<div
|
4
|
+
role="alert"
|
5
|
+
class="<%= class_names('relative w-full rounded-lg border px-4 py-3 text-sm mx-auto mb-4 [&>svg]:size-4 [&>svg+div]:translate-y-(-3px) [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg~*]:pl-7 max-w-lg', '[&>svg]:text-foreground bg-background text-foreground': notice.present?, 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive': alert.present?) %>"
|
6
|
+
>
|
7
|
+
<%= icon_for(notice.present? ? :check : :circle_alert) %>
|
8
|
+
<h5 class="mb-1 font-medium leading-none tracking-tight"><%= title || (notice.present? ? "Éxito" : "Error") %></h5>
|
9
|
+
<div class="text-sm [&_p]:leading-relaxed"><%= notice %></div>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%# locals: (title:, custom_classes: "", icon: nil, icon_classes: "h-4 w-4 text-muted-foreground") -%>
|
2
|
+
|
3
|
+
<div
|
4
|
+
class="<%= class_names("p-6 flex flex-row items-center justify-between space-y-0 pb-2", custom_classes) %>"
|
5
|
+
>
|
6
|
+
<h3 class="tracking-tight text-sm font-medium"><%= title %></h3>
|
7
|
+
<%= icon_for(icon, class: icon_classes) if icon.present? %>
|
8
|
+
</div>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<%# locals: (pagy:, route_helper:, param: nil, data: {turbo_action: :replace}) %>
|
2
|
+
<nav class="mx-auto flex w-full justify-center mt-4">
|
3
|
+
<ul class="flex flex-row items-center gap-1">
|
4
|
+
<li>
|
5
|
+
<% if pagy.prev.present? %>
|
6
|
+
<%= link_to "Previo",
|
7
|
+
paginated_path(route_helper, pagy, pagy.prev, param),
|
8
|
+
class: "button-ghost",
|
9
|
+
data: data %>
|
10
|
+
<% else %>
|
11
|
+
<button class="button-ghost" disabled>Previo</button>
|
12
|
+
<% end %>
|
13
|
+
</li>
|
14
|
+
<% pagy.series.each do |page| %>
|
15
|
+
<li>
|
16
|
+
<%= link_to page,
|
17
|
+
paginated_path(route_helper, pagy, page, param),
|
18
|
+
class: class_names("button-ghost", "button-outline": page.is_a?(String)),
|
19
|
+
data: data %>
|
20
|
+
</li>
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<li>
|
24
|
+
<% if pagy.next.present? %>
|
25
|
+
<%= link_to "Siguiente",
|
26
|
+
paginated_path(route_helper, pagy, pagy.next, param),
|
27
|
+
class: "button-ghost",
|
28
|
+
data: data %>
|
29
|
+
<% else %>
|
30
|
+
<button class="button-ghost" disabled>Siguiente</button>
|
31
|
+
<% end %>
|
32
|
+
</li>
|
33
|
+
</ul>
|
34
|
+
</nav>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<aside
|
2
|
+
class="group peer hidden md:block text-sidebar-foreground"
|
3
|
+
data-controller="sidebars"
|
4
|
+
data-state="expanded"
|
5
|
+
data-collapsible=""
|
6
|
+
id="sidebar"
|
7
|
+
>
|
8
|
+
<!-- Mobile overlay -->
|
9
|
+
<div
|
10
|
+
class="
|
11
|
+
inset-0 bg-black/80 lg:hidden transition-opacity duration-300 hidden
|
12
|
+
"
|
13
|
+
data-sidebar-target="overlay"
|
14
|
+
data-action="click->sidebar#toggleMobile"
|
15
|
+
>
|
16
|
+
</div>
|
17
|
+
<!-- Sidebar container -->
|
18
|
+
<div
|
19
|
+
class="
|
20
|
+
duration-200 fixed inset-y-0 z-10 h-svh w-(--sidebar-width)
|
21
|
+
transition-[left,right,width] ease-linear md:flex left-0 border-r
|
22
|
+
border-sidebar-border group-data-[collapsible=icon]:w-[--sidebar-width-icon]
|
23
|
+
"
|
24
|
+
data-sidebar-target="container"
|
25
|
+
>
|
26
|
+
<div class=" flex h-full w-full flex-col bg-sidebar">
|
27
|
+
<%= yield %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</aside>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%# locals: (title: nil, title_action: {}, menu: []) -%>
|
2
|
+
<%- title ||= nil -%>
|
3
|
+
<%- title_action ||= {} -%>
|
4
|
+
<%- menu ||= [] -%>
|
5
|
+
|
6
|
+
<div class="relative flex w-full min-w-0 flex-col p-2">
|
7
|
+
<% if title.present? %>
|
8
|
+
<div
|
9
|
+
class="
|
10
|
+
duration-200 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium
|
11
|
+
text-sidebar-foreground/70 outline-none ring-sidebar-ring
|
12
|
+
transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4
|
13
|
+
[&>svg]:shrink-0 group-data-[collapsible=icon]:-mt-8
|
14
|
+
group-data-[collapsible=icon]:opacity-0
|
15
|
+
"
|
16
|
+
>
|
17
|
+
<%= title %>
|
18
|
+
|
19
|
+
<% if title_action.any? %>
|
20
|
+
<%= link_to title_action[:url], class: "flex aspect-square w-5 items-center justify-center rounded-md p-0 ml-auto text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0 after:absolute after:-inset-2 after:md:hidden" do %>
|
21
|
+
<%= render_icon(title_action[:icon]) %>
|
22
|
+
<span class="sr-only"><%= title_action[:title] %></span>
|
23
|
+
<% end %>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
27
|
+
|
28
|
+
<% if menu.any? %>
|
29
|
+
<ul class="flex w-full min-w-0 flex-col gap-1">
|
30
|
+
<% menu.each do |item| %>
|
31
|
+
<li class="group/menu-item relative">
|
32
|
+
<%= sidebar_menu_item(
|
33
|
+
title: item[:title],
|
34
|
+
url: item[:url],
|
35
|
+
icon: item[:icon],
|
36
|
+
current: item[:active],
|
37
|
+
) %>
|
38
|
+
</li>
|
39
|
+
<% end %>
|
40
|
+
</ul>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maquina-components
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mario Alberto Chávez
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-01-
|
10
|
+
date: 2025-01-17 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rails
|
@@ -33,6 +33,18 @@ files:
|
|
33
33
|
- MIT-LICENSE
|
34
34
|
- README.md
|
35
35
|
- Rakefile
|
36
|
+
- app/assets/stylesheets/maquina_components.css
|
37
|
+
- app/helpers/components/icons_helper.rb
|
38
|
+
- app/helpers/components/pagination_helper.rb
|
39
|
+
- app/views/components/_alert.html.erb
|
40
|
+
- app/views/components/_card.html.erb
|
41
|
+
- app/views/components/_card_content.html.erb
|
42
|
+
- app/views/components/_card_header.html.erb
|
43
|
+
- app/views/components/_pagination.html.erb
|
44
|
+
- app/views/components/_sidebar.html.erb
|
45
|
+
- app/views/components/_sidebar_content.html.erb
|
46
|
+
- app/views/components/_sidebar_group.html.erb
|
47
|
+
- app/views/components/_sidebar_header.html.erb
|
36
48
|
- lib/maquina-components.rb
|
37
49
|
- lib/maquina_components/engine.rb
|
38
50
|
- lib/maquina_components/version.rb
|