lesli_view 1.1.2 → 1.1.3
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/lib/lesli_view/charts/bar.rb +10 -0
- data/lib/lesli_view/charts/general.html.erb +38 -52
- data/lib/lesli_view/charts/general.rb +69 -30
- data/lib/lesli_view/charts/line.rb +16 -0
- data/lib/lesli_view/components/header.html.erb +48 -23
- data/lib/lesli_view/components/header.rb +35 -2
- data/lib/lesli_view/components/toolbar.css +52 -0
- data/lib/lesli_view/components/toolbar.html.erb +36 -21
- data/lib/lesli_view/components/toolbar.rb +41 -4
- data/lib/lesli_view/elements/button.css +357 -0
- data/lib/lesli_view/elements/button.html.erb +15 -12
- data/lib/lesli_view/elements/button.rb +74 -34
- data/lib/lesli_view/elements/empty.html.erb +31 -6
- data/lib/lesli_view/elements/empty.rb +8 -1
- data/lib/lesli_view/elements/table-chart.html.erb +42 -0
- data/lib/lesli_view/elements/table.css +91 -0
- data/lib/lesli_view/elements/table.html.erb +24 -21
- data/lib/lesli_view/elements/table.rb +67 -17
- data/lib/lesli_view/forms/builder.rb +16 -3
- data/lib/lesli_view/forms/builder_horizontal.rb +34 -10
- data/lib/lesli_view/forms/fields.rb +103 -70
- data/lib/lesli_view/forms/fieldset.rb +3 -3
- data/lib/lesli_view/forms/form.css +171 -0
- data/lib/lesli_view/forms/form.scss +2 -54
- data/lib/lesli_view/forms/inputs.rb +27 -15
- data/lib/lesli_view/layout/container.html.erb +8 -2
- data/lib/lesli_view/version.rb +2 -2
- data/lib/lesli_view/widgets/calendar.html.erb +42 -133
- data/lib/lesli_view/widgets/calendar.rb +77 -3
- data/lib/lesli_view/widgets/chart.html.erb +25 -26
- data/lib/lesli_view/widgets/chart.rb +46 -3
- data/lib/lesli_view/widgets/count.html.erb +17 -15
- data/lib/lesli_view/widgets/count.rb +13 -1
- data/lib/lesli_view/widgets/date.html.erb +23 -21
- data/lib/lesli_view/widgets/date.rb +27 -2
- data/lib/lesli_view/widgets/weather.html.erb +40 -38
- data/lib/lesli_view/widgets/weather.rb +41 -2
- data/readme.md +158 -29
- metadata +6 -4
- data/lib/lesli_view/components/header.scss +0 -69
- data/lib/lesli_view/components/toolbar.scss +0 -54
- data/lib/lesli_view/elements/table.scss +0 -153
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
|
|
3
|
+
Lesli
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
|
+
|
|
7
|
+
This program is free software: you can redistribute it and/or modify
|
|
8
|
+
it under the terms of the GNU General Public License as published by
|
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
(at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program. If not, see http://www.gnu.org/licenses/.
|
|
19
|
+
|
|
20
|
+
Lesli · Ruby on Rails SaaS Development Framework.
|
|
21
|
+
|
|
22
|
+
Made with ♥ by LesliTech
|
|
23
|
+
Building a better future, one line of code at a time.
|
|
24
|
+
|
|
25
|
+
@contact hello@lesli.tech
|
|
26
|
+
@website https://www.lesli.tech
|
|
27
|
+
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
28
|
+
|
|
29
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
30
|
+
// ·
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@layer components {
|
|
35
|
+
.lesli-button:hover {
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
.lesli-button {
|
|
39
|
+
@apply
|
|
40
|
+
cursor-pointer
|
|
41
|
+
inline-flex
|
|
42
|
+
items-center
|
|
43
|
+
justify-center
|
|
44
|
+
gap-2
|
|
45
|
+
border
|
|
46
|
+
rounded-lg
|
|
47
|
+
h-10
|
|
48
|
+
px-4
|
|
49
|
+
text-sm
|
|
50
|
+
font-medium
|
|
51
|
+
whitespace-nowrap
|
|
52
|
+
transition-colors
|
|
53
|
+
duration-150
|
|
54
|
+
focus:outline-none
|
|
55
|
+
focus-visible:ring-2
|
|
56
|
+
focus-visible:ring-offset-2
|
|
57
|
+
disabled:pointer-events-none
|
|
58
|
+
disabled:opacity-50;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.lesli-button.is-small {
|
|
62
|
+
@apply
|
|
63
|
+
h-8
|
|
64
|
+
rounded-md
|
|
65
|
+
px-3
|
|
66
|
+
text-xs;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.lesli-button.is-icon-only {
|
|
70
|
+
@apply
|
|
71
|
+
w-10
|
|
72
|
+
px-0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.lesli-button.is-icon-only.is-small {
|
|
76
|
+
@apply
|
|
77
|
+
w-8
|
|
78
|
+
px-0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.lesli-button.is-loading {
|
|
82
|
+
@apply
|
|
83
|
+
pointer-events-none
|
|
84
|
+
cursor-wait
|
|
85
|
+
opacity-80;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.lesli-button.is-loading::before {
|
|
89
|
+
width: 1rem;
|
|
90
|
+
height: 1rem;
|
|
91
|
+
content: "";
|
|
92
|
+
border: 2px solid currentColor;
|
|
93
|
+
border-right-color: transparent;
|
|
94
|
+
border-radius: 9999px;
|
|
95
|
+
animation: lesli-button-spin .65s linear infinite;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* Solid variants
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
.lesli-button.is-primary {
|
|
103
|
+
@apply
|
|
104
|
+
border-blue-600
|
|
105
|
+
bg-blue-600
|
|
106
|
+
text-white
|
|
107
|
+
hover:border-blue-700
|
|
108
|
+
hover:bg-blue-700
|
|
109
|
+
focus-visible:ring-blue-500;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.lesli-button.is-info {
|
|
113
|
+
@apply
|
|
114
|
+
border-sky-600
|
|
115
|
+
bg-sky-600
|
|
116
|
+
text-white
|
|
117
|
+
hover:border-sky-700
|
|
118
|
+
hover:bg-sky-700
|
|
119
|
+
focus-visible:ring-sky-500;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.lesli-button.is-success {
|
|
123
|
+
@apply
|
|
124
|
+
border-emerald-600
|
|
125
|
+
bg-emerald-600
|
|
126
|
+
text-white
|
|
127
|
+
hover:border-emerald-700
|
|
128
|
+
hover:bg-emerald-700
|
|
129
|
+
focus-visible:ring-emerald-500;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.lesli-button.is-warning {
|
|
133
|
+
@apply
|
|
134
|
+
border-amber-500
|
|
135
|
+
bg-amber-500
|
|
136
|
+
text-amber-950
|
|
137
|
+
hover:border-amber-600
|
|
138
|
+
hover:bg-amber-600
|
|
139
|
+
focus-visible:ring-amber-500;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.lesli-button.is-danger {
|
|
143
|
+
@apply
|
|
144
|
+
border-rose-600
|
|
145
|
+
bg-rose-600
|
|
146
|
+
text-white
|
|
147
|
+
hover:border-rose-700
|
|
148
|
+
hover:bg-rose-700
|
|
149
|
+
focus-visible:ring-rose-500;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/*
|
|
153
|
+
* Light variants
|
|
154
|
+
*
|
|
155
|
+
* These must come after solid variants.
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
.lesli-button.is-primary.is-light {
|
|
159
|
+
@apply
|
|
160
|
+
border-blue-100
|
|
161
|
+
bg-blue-50
|
|
162
|
+
text-blue-700
|
|
163
|
+
hover:border-blue-200
|
|
164
|
+
hover:bg-blue-100
|
|
165
|
+
focus-visible:ring-blue-500;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.lesli-button.is-info.is-light {
|
|
169
|
+
@apply
|
|
170
|
+
border-sky-100
|
|
171
|
+
bg-sky-50
|
|
172
|
+
text-sky-700
|
|
173
|
+
hover:border-sky-200
|
|
174
|
+
hover:bg-sky-100
|
|
175
|
+
focus-visible:ring-sky-500;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.lesli-button.is-success.is-light {
|
|
179
|
+
@apply
|
|
180
|
+
border-emerald-100
|
|
181
|
+
bg-emerald-50
|
|
182
|
+
text-emerald-700
|
|
183
|
+
hover:border-emerald-200
|
|
184
|
+
hover:bg-emerald-100
|
|
185
|
+
focus-visible:ring-emerald-500;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.lesli-button.is-warning.is-light {
|
|
189
|
+
@apply
|
|
190
|
+
border-amber-100
|
|
191
|
+
bg-amber-50
|
|
192
|
+
text-amber-700
|
|
193
|
+
hover:border-amber-200
|
|
194
|
+
hover:bg-amber-100
|
|
195
|
+
focus-visible:ring-amber-500;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.lesli-button.is-danger.is-light {
|
|
199
|
+
@apply
|
|
200
|
+
border-rose-100
|
|
201
|
+
bg-rose-50
|
|
202
|
+
text-rose-700
|
|
203
|
+
hover:border-rose-200
|
|
204
|
+
hover:bg-rose-100
|
|
205
|
+
focus-visible:ring-rose-500;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/*
|
|
209
|
+
* Outlined variants
|
|
210
|
+
*
|
|
211
|
+
* These must come after solid and light variants.
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
.lesli-button.is-primary.is-outlined {
|
|
215
|
+
@apply
|
|
216
|
+
border-blue-300
|
|
217
|
+
bg-transparent
|
|
218
|
+
text-blue-700
|
|
219
|
+
hover:border-blue-400
|
|
220
|
+
hover:bg-blue-50
|
|
221
|
+
focus-visible:ring-blue-500;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.lesli-button.is-info.is-outlined {
|
|
225
|
+
@apply
|
|
226
|
+
border-sky-300
|
|
227
|
+
bg-transparent
|
|
228
|
+
text-sky-700
|
|
229
|
+
hover:border-sky-400
|
|
230
|
+
hover:bg-sky-50
|
|
231
|
+
focus-visible:ring-sky-500;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.lesli-button.is-success.is-outlined {
|
|
235
|
+
@apply
|
|
236
|
+
border-emerald-300
|
|
237
|
+
bg-transparent
|
|
238
|
+
text-emerald-700
|
|
239
|
+
hover:border-emerald-400
|
|
240
|
+
hover:bg-emerald-50
|
|
241
|
+
focus-visible:ring-emerald-500;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.lesli-button.is-warning.is-outlined {
|
|
245
|
+
@apply
|
|
246
|
+
border-amber-300
|
|
247
|
+
bg-transparent
|
|
248
|
+
text-amber-700
|
|
249
|
+
hover:border-amber-400
|
|
250
|
+
hover:bg-amber-50
|
|
251
|
+
focus-visible:ring-amber-500;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.lesli-button.is-danger.is-outlined {
|
|
255
|
+
@apply
|
|
256
|
+
border-rose-300
|
|
257
|
+
bg-transparent
|
|
258
|
+
text-rose-700
|
|
259
|
+
hover:border-rose-400
|
|
260
|
+
hover:bg-rose-50
|
|
261
|
+
focus-visible:ring-rose-500;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/*
|
|
265
|
+
* Optional: light + outlined
|
|
266
|
+
*/
|
|
267
|
+
|
|
268
|
+
.lesli-button.is-light.is-outlined {
|
|
269
|
+
@apply
|
|
270
|
+
bg-transparent;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@keyframes lesli-button-spin {
|
|
275
|
+
to {
|
|
276
|
+
transform: rotate(360deg);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@layer components {
|
|
283
|
+
.lesli-icon {
|
|
284
|
+
@apply
|
|
285
|
+
inline-flex
|
|
286
|
+
items-center
|
|
287
|
+
justify-center
|
|
288
|
+
shrink-0
|
|
289
|
+
h-6
|
|
290
|
+
w-6
|
|
291
|
+
text-[1.5rem]
|
|
292
|
+
leading-none;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.lesli-icon.is-small {
|
|
296
|
+
@apply
|
|
297
|
+
h-4
|
|
298
|
+
w-4
|
|
299
|
+
text-[1rem];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.lesli-icon.is-medium {
|
|
303
|
+
@apply
|
|
304
|
+
h-8
|
|
305
|
+
w-8
|
|
306
|
+
text-[2rem];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.lesli-icon.is-large {
|
|
310
|
+
@apply
|
|
311
|
+
h-12
|
|
312
|
+
w-12
|
|
313
|
+
text-[3rem];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.lesli-icon .material-symbols,
|
|
317
|
+
.lesli-icon .material-symbols-outlined,
|
|
318
|
+
.lesli-icon .material-symbols-rounded,
|
|
319
|
+
.lesli-icon .material-symbols-sharp {
|
|
320
|
+
@apply
|
|
321
|
+
block
|
|
322
|
+
text-inherit
|
|
323
|
+
leading-none;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/*
|
|
327
|
+
* Button-specific icon sizing.
|
|
328
|
+
* This keeps icons visually balanced inside .lesli-button.
|
|
329
|
+
*/
|
|
330
|
+
.lesli-button .lesli-icon {
|
|
331
|
+
@apply
|
|
332
|
+
h-5
|
|
333
|
+
w-5
|
|
334
|
+
text-[1.25rem];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.lesli-button.is-small .lesli-icon {
|
|
338
|
+
@apply
|
|
339
|
+
h-4
|
|
340
|
+
w-4
|
|
341
|
+
text-[1rem];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.lesli-button.is-icon-only .lesli-icon {
|
|
345
|
+
@apply
|
|
346
|
+
h-5
|
|
347
|
+
w-5
|
|
348
|
+
text-[1.25rem];
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.lesli-button.is-icon-only.is-small .lesli-icon {
|
|
352
|
+
@apply
|
|
353
|
+
h-4
|
|
354
|
+
w-4
|
|
355
|
+
text-[1rem];
|
|
356
|
+
}
|
|
357
|
+
}
|
|
@@ -6,29 +6,32 @@
|
|
|
6
6
|
@url,
|
|
7
7
|
method: @method,
|
|
8
8
|
params: @params,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
disabled: disabled?,
|
|
10
|
+
**common_attributes
|
|
11
|
+
) do %>
|
|
12
12
|
<%= button_content %>
|
|
13
13
|
<% end %>
|
|
14
14
|
|
|
15
15
|
<% elsif mode == :link %>
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<%=
|
|
17
|
+
<% if disabled? %>
|
|
18
|
+
<%= content_tag(:span, role: "link", tabindex: -1, **common_attributes) do %>
|
|
19
|
+
<%= button_content %>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% else %>
|
|
22
|
+
<%= link_to(@url, **common_attributes) do %>
|
|
23
|
+
<%= button_content %>
|
|
24
|
+
<% end %>
|
|
23
25
|
<% end %>
|
|
24
26
|
|
|
25
27
|
<% else %>
|
|
26
28
|
|
|
27
29
|
<%= content_tag(
|
|
28
30
|
:button,
|
|
29
|
-
type:
|
|
30
|
-
|
|
31
|
-
**
|
|
31
|
+
type: button_type,
|
|
32
|
+
disabled: disabled?,
|
|
33
|
+
**common_attributes
|
|
34
|
+
) do %>
|
|
32
35
|
<%= button_content %>
|
|
33
36
|
<% end %>
|
|
34
37
|
|
|
@@ -35,33 +35,38 @@ Building a better future, one line of code at a time.
|
|
|
35
35
|
module LesliView
|
|
36
36
|
module Elements
|
|
37
37
|
class Button < ViewComponent::Base
|
|
38
|
-
attr_reader :label, :url, :icon, :loading, :solid, :
|
|
38
|
+
attr_reader :label, :url, :icon, :loading, :solid, :light,
|
|
39
|
+
:info, :success, :warning, :danger, :small, :dispatch,
|
|
40
|
+
:method, :params, :css_class, :aria_label, :disabled,
|
|
41
|
+
:button_type, :data
|
|
39
42
|
|
|
40
|
-
# Adds two numbers together.
|
|
41
|
-
# @param [Integer] a The first number.
|
|
42
|
-
# @param [Integer] b The second number.
|
|
43
|
-
# @return [Integer] The sum of the two numbers.
|
|
44
43
|
def initialize(
|
|
45
|
-
label=nil,
|
|
46
|
-
url:nil,
|
|
47
|
-
icon: nil,
|
|
48
|
-
loading: false,
|
|
49
|
-
solid:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
label = nil,
|
|
45
|
+
url: nil,
|
|
46
|
+
icon: nil,
|
|
47
|
+
loading: false,
|
|
48
|
+
solid: true,
|
|
49
|
+
light: false,
|
|
50
|
+
info: true,
|
|
51
|
+
success: false,
|
|
52
|
+
warning: false,
|
|
53
|
+
danger: false,
|
|
54
54
|
small: false,
|
|
55
|
-
dispatch:nil,
|
|
55
|
+
dispatch: nil,
|
|
56
56
|
method: nil,
|
|
57
|
-
params:nil,
|
|
58
|
-
css_class:nil
|
|
57
|
+
params: nil,
|
|
58
|
+
css_class: nil,
|
|
59
|
+
aria_label: nil,
|
|
60
|
+
disabled: false,
|
|
61
|
+
type: :button,
|
|
62
|
+
data: {}
|
|
59
63
|
)
|
|
60
64
|
@label = label
|
|
61
65
|
@url = url
|
|
62
66
|
@icon = icon
|
|
63
67
|
@loading = loading
|
|
64
68
|
@solid = solid
|
|
69
|
+
@light = light
|
|
65
70
|
@info = info
|
|
66
71
|
@success = success
|
|
67
72
|
@warning = warning
|
|
@@ -71,6 +76,10 @@ module LesliView
|
|
|
71
76
|
@method = method
|
|
72
77
|
@params = params
|
|
73
78
|
@css_class = css_class
|
|
79
|
+
@aria_label = aria_label
|
|
80
|
+
@disabled = disabled
|
|
81
|
+
@button_type = type
|
|
82
|
+
@data = data
|
|
74
83
|
end
|
|
75
84
|
|
|
76
85
|
def mode
|
|
@@ -80,20 +89,22 @@ module LesliView
|
|
|
80
89
|
end
|
|
81
90
|
|
|
82
91
|
def alpine_attributes
|
|
83
|
-
return {} unless
|
|
92
|
+
return {} unless dispatch.present?
|
|
84
93
|
|
|
85
94
|
{
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
"x-data": "",
|
|
96
|
+
"@click": "$dispatch('#{dispatch}')"
|
|
88
97
|
}
|
|
89
98
|
end
|
|
90
99
|
|
|
91
100
|
def html_classes
|
|
92
|
-
classes = ["button", button_variant]
|
|
93
|
-
classes << "is-
|
|
101
|
+
classes = ["lesli-button", button_variant]
|
|
102
|
+
classes << "is-outlined" unless solid
|
|
103
|
+
classes << "is-light" if light
|
|
94
104
|
classes << "is-loading" if loading
|
|
95
105
|
classes << "is-small" if small
|
|
96
|
-
classes <<
|
|
106
|
+
classes << "is-icon-only" if icon_only?
|
|
107
|
+
classes << css_class if css_class.present?
|
|
97
108
|
classes.join(" ")
|
|
98
109
|
end
|
|
99
110
|
|
|
@@ -106,21 +117,50 @@ module LesliView
|
|
|
106
117
|
end
|
|
107
118
|
|
|
108
119
|
def icon_only?
|
|
109
|
-
icon &&
|
|
120
|
+
icon.present? && visible_label.blank?
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def disabled?
|
|
124
|
+
disabled || loading
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def visible_label
|
|
128
|
+
label.presence || (content if content?)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def accessible_label
|
|
132
|
+
aria_label.presence || (icon.to_s.humanize if icon_only?)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def html_data
|
|
136
|
+
{ turbo_frame: "_top" }.merge(data || {})
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def common_attributes
|
|
140
|
+
attributes = {
|
|
141
|
+
class: html_classes,
|
|
142
|
+
data: html_data,
|
|
143
|
+
aria: {
|
|
144
|
+
label: accessible_label,
|
|
145
|
+
busy: loading || nil,
|
|
146
|
+
disabled: disabled? || nil
|
|
147
|
+
}.compact
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
attributes.merge(alpine_attributes)
|
|
110
151
|
end
|
|
111
152
|
|
|
112
153
|
def button_content
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
(@icon_only ? nil : content_tag(:span, @label))
|
|
120
|
-
].compact)
|
|
121
|
-
else
|
|
122
|
-
@label
|
|
154
|
+
parts = []
|
|
155
|
+
|
|
156
|
+
if icon.present?
|
|
157
|
+
parts << content_tag(:span, class: "lesli-icon", aria: { hidden: true }) do
|
|
158
|
+
content_tag(:span, icon, class: "material-symbols")
|
|
159
|
+
end
|
|
123
160
|
end
|
|
161
|
+
|
|
162
|
+
parts << content_tag(:span, visible_label) if visible_label.present?
|
|
163
|
+
safe_join(parts)
|
|
124
164
|
end
|
|
125
165
|
end
|
|
126
166
|
end
|
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
2
|
+
<div
|
|
3
|
+
class="lesli-empty-state flex w-full flex-col items-center justify-center px-6 py-10 text-center sm:py-12"
|
|
4
|
+
role="region"
|
|
5
|
+
aria-label="<%= text.presence || "Empty state" %>">
|
|
6
|
+
|
|
7
|
+
<div class="mb-5 flex h-36 w-36 items-center justify-center rounded-full bg-slate-100/80 sm:h-40 sm:w-40">
|
|
8
|
+
<svg
|
|
9
|
+
class="h-28 w-28 text-slate-300 sm:h-32 sm:w-32"
|
|
10
|
+
viewBox="0 0 184 184"
|
|
11
|
+
fill="none"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
aria-hidden="true"
|
|
14
|
+
focusable="false">
|
|
15
|
+
<path d="M145.271 90.6522H142.735V89.528C142.735 83.9793 138.222 79.4655 132.673 79.4655H85.7357C84.255 79.4655 82.1132 78.0942 81.4922 76.7515L76.1878 65.2544C74.1523 60.8499 68.9629 57.5293 64.1128 57.5293H39.7012C34.1524 57.5293 29.6387 62.043 29.6387 67.5918V151.809C29.6387 157.358 34.1524 161.872 39.7012 161.872H53.3459C53.5357 161.883 53.7139 161.932 53.9065 161.932H112.945V153.307H108.831H53.9065C53.7197 153.307 53.6219 153.278 53.5587 153.247C53.527 153.232 53.4897 153.215 53.481 153.206C53.458 153.181 53.412 153.045 53.4609 152.772L63.1985 101.419C63.4027 100.338 64.6849 99.2772 65.7803 99.2772H134.11H142.735H145.271C145.553 99.2772 145.679 99.349 145.697 99.3749C145.714 99.4008 145.766 99.533 145.714 99.809L142.735 115.524L135.979 151.159C135.775 152.24 134.493 153.301 133.395 153.301H121.964V161.926H133.395C138.621 161.926 143.48 157.904 144.455 152.767L154.189 101.413C154.713 98.6648 154.037 95.9163 152.341 93.8693C150.645 91.8281 148.069 90.6522 145.271 90.6522ZM134.11 90.6522H65.7832C60.5593 90.6522 55.7005 94.6743 54.7259 99.8119L44.9883 151.168C44.856 151.864 44.8043 152.56 44.8244 153.247H39.7012C38.922 153.247 38.2637 152.588 38.2637 151.809V67.5918C38.2637 66.8127 38.922 66.1543 39.7012 66.1543H64.1128C65.5934 66.1543 67.7353 67.5257 68.3563 68.8683L73.6607 80.3654C75.6962 84.7699 80.8855 88.0905 85.7357 88.0905H132.673C133.452 88.0905 134.11 88.7489 134.11 89.528V90.6522Z" fill="currentColor"/>
|
|
16
|
+
<path d="M145.7 50.5227L153.201 43.0219C154.805 41.4176 154.739 38.7525 153.054 37.0677C151.369 35.383 148.704 35.3197 147.1 36.9211L139.599 44.422L132.098 36.9211C130.494 35.3169 127.829 35.383 126.144 37.0677C124.459 38.7525 124.396 41.4176 125.997 43.0219L133.498 50.5227L125.997 58.0236C124.393 59.6279 124.459 62.293 126.144 63.9777C127.829 65.6625 130.494 65.7257 132.098 64.1244L139.599 56.6235L147.1 64.1244C148.704 65.7286 151.369 65.6625 153.054 63.9777C154.739 62.293 154.802 59.6279 153.201 58.0236L145.7 50.5227Z" fill="currentColor"/>
|
|
17
|
+
</svg>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<% if text.present? %>
|
|
21
|
+
<p class="text-base font-semibold text-slate-700 sm:text-lg"><%= text %></p>
|
|
22
|
+
<% end %>
|
|
23
|
+
|
|
24
|
+
<% if description.present? %>
|
|
25
|
+
<p class="mt-2 max-w-md text-sm leading-6 text-slate-500"><%= description %></p>
|
|
26
|
+
<% end %>
|
|
27
|
+
|
|
28
|
+
<% if content? %>
|
|
29
|
+
<div class="mt-6 flex flex-wrap items-center justify-center gap-3">
|
|
30
|
+
<%= content %>
|
|
31
|
+
</div>
|
|
32
|
+
<% end %>
|
|
8
33
|
</div>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
=begin
|
|
2
4
|
|
|
3
5
|
Lesli
|
|
@@ -32,8 +34,13 @@ Building a better future, one line of code at a time.
|
|
|
32
34
|
module LesliView
|
|
33
35
|
module Elements
|
|
34
36
|
class Empty < ViewComponent::Base
|
|
35
|
-
|
|
37
|
+
attr_reader :text, :description
|
|
38
|
+
|
|
39
|
+
# `text` remains optional for icon-only uses such as error pages.
|
|
40
|
+
# A component block can be supplied to render an action below the message.
|
|
41
|
+
def initialize(text: "No data found", description: nil)
|
|
36
42
|
@text = text
|
|
43
|
+
@description = description
|
|
37
44
|
end
|
|
38
45
|
end
|
|
39
46
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
distribution: [{
|
|
2
|
+
label: "Deactivated_users",
|
|
3
|
+
value: summary[:total_users_deactivated],
|
|
4
|
+
percentage: percentage(summary[:total_users_deactivated], summary[:total_users]),
|
|
5
|
+
color: "#5D7C4D"
|
|
6
|
+
}, {
|
|
7
|
+
label: "Locked_users",
|
|
8
|
+
value: summary[:total_users_locked],
|
|
9
|
+
percentage: percentage(summary[:total_users_locked], summary[:total_users]),
|
|
10
|
+
color: "#B23A3A"
|
|
11
|
+
}, {
|
|
12
|
+
label: "Unconfirmed_users",
|
|
13
|
+
value: summary[:total_users_unconfirmed],
|
|
14
|
+
percentage: percentage(summary[:total_users_unconfirmed], summary[:total_users]),
|
|
15
|
+
color: "#5F6C7D"
|
|
16
|
+
}, {
|
|
17
|
+
label: "Deleted_users",
|
|
18
|
+
value: summary[:total_users_deleted],
|
|
19
|
+
percentage: percentage(summary[:total_users_deleted], summary[:total_users]),
|
|
20
|
+
color: "#4B5FA8"
|
|
21
|
+
}],
|
|
22
|
+
<%= render(LesliView::Elements::Table.new(columns: [])) do |table| %>
|
|
23
|
+
<% @users[:distribution].each do |user| %>
|
|
24
|
+
<% table.with_row do |row| %>
|
|
25
|
+
<% row.with_cell do %>
|
|
26
|
+
<%= user[:label] %>
|
|
27
|
+
<% end %>
|
|
28
|
+
<% row.with_cell(class_name: "w-full p-0") do %>
|
|
29
|
+
<p style="padding:8px;border-radius:4px;background:<%= user[:color] %>;width:<%= user[:percentage] %>%">
|
|
30
|
+
</p>
|
|
31
|
+
<% end %>
|
|
32
|
+
<% row.with_cell(align: :right) do %>
|
|
33
|
+
<%= user[:value] %>
|
|
34
|
+
<% end %>
|
|
35
|
+
<% row.with_cell(align: :right) do %>
|
|
36
|
+
<span class="font-semibold text-slate-400">
|
|
37
|
+
<%= user[:percentage] %>%
|
|
38
|
+
</span>
|
|
39
|
+
<% end %>
|
|
40
|
+
<% end %>
|
|
41
|
+
<% end %>
|
|
42
|
+
<% end %>
|