maquina 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/images/maquina/maquina.svg +18 -0
- data/app/assets/javascripts/maquina/application.js +4 -0
- data/app/assets/javascripts/maquina/controllers/alert_controller.js +29 -0
- data/app/assets/javascripts/maquina/controllers/application.js +9 -0
- data/app/assets/javascripts/maquina/controllers/file_controller.js +60 -0
- data/app/assets/javascripts/maquina/controllers/index.js +11 -0
- data/app/assets/javascripts/maquina/controllers/mobile_menu_controller.js +31 -0
- data/app/assets/javascripts/maquina/controllers/modal_controller.js +39 -0
- data/app/assets/javascripts/maquina/controllers/modal_open_controller.js +15 -0
- data/app/assets/javascripts/maquina/controllers/popup_menu_controller.js +17 -0
- data/app/assets/javascripts/maquina/controllers/submit_form_controller.js +11 -0
- data/app/assets/stylesheets/maquina/application.css +15 -0
- data/app/assets/stylesheets/maquina/application.tailwind.css +102 -0
- data/app/controllers/concerns/maquina/authenticate.rb +41 -0
- data/app/controllers/concerns/maquina/create.rb +27 -0
- data/app/controllers/concerns/maquina/destroy.rb +28 -0
- data/app/controllers/concerns/maquina/edit.rb +29 -0
- data/app/controllers/concerns/maquina/index.rb +33 -0
- data/app/controllers/concerns/maquina/new.rb +22 -0
- data/app/controllers/concerns/maquina/resourceful.rb +180 -0
- data/app/controllers/concerns/maquina/show.rb +27 -0
- data/app/controllers/concerns/maquina/update.rb +31 -0
- data/app/controllers/maquina/accept_invitations_controller.rb +28 -0
- data/app/controllers/maquina/application_controller.rb +19 -0
- data/app/controllers/maquina/dashboard_controller.rb +16 -0
- data/app/controllers/maquina/invitations_controller.rb +51 -0
- data/app/controllers/maquina/plans_controller.rb +56 -0
- data/app/controllers/maquina/sessions_controller.rb +56 -0
- data/app/controllers/maquina/unauthorized_controller.rb +9 -0
- data/app/controllers/maquina/users_controller.rb +24 -0
- data/app/helpers/maquina/application_helper.rb +19 -0
- data/app/helpers/maquina/navbar_menu_helper.rb +29 -0
- data/app/helpers/maquina/views_helper.rb +9 -0
- data/app/jobs/maquina/application_job.rb +4 -0
- data/app/mailers/maquina/application_mailer.rb +8 -0
- data/app/mailers/maquina/user_notifications_mailer.rb +16 -0
- data/app/models/concerns/maquina/authenticate_by.rb +33 -0
- data/app/models/concerns/maquina/blockeable.rb +28 -0
- data/app/models/concerns/maquina/multifactor.rb +80 -0
- data/app/models/concerns/maquina/retain_passwords.rb +32 -0
- data/app/models/concerns/maquina/searchable.rb +24 -0
- data/app/models/maquina/active_session.rb +33 -0
- data/app/models/maquina/application_record.rb +11 -0
- data/app/models/maquina/current.rb +21 -0
- data/app/models/maquina/invitation.rb +15 -0
- data/app/models/maquina/plan.rb +38 -0
- data/app/models/maquina/used_password.rb +17 -0
- data/app/models/maquina/user.rb +33 -0
- data/app/policies/maquina/application_policy.rb +50 -0
- data/app/policies/maquina/invitation_policy.rb +13 -0
- data/app/policies/maquina/navigation_policy.rb +13 -0
- data/app/policies/maquina/plan_policy.rb +49 -0
- data/app/policies/maquina/user_policy.rb +27 -0
- data/app/views/layouts/maquina/application.html.erb +26 -0
- data/app/views/layouts/maquina/mailer.html.erb +377 -0
- data/app/views/layouts/maquina/mailer.text.erb +12 -0
- data/app/views/layouts/maquina/sessions.html.erb +24 -0
- data/app/views/maquina/accept_invitations/new.html.erb +9 -0
- data/app/views/maquina/accept_invitations/new_view.rb +41 -0
- data/app/views/maquina/application/_navbar.html.erb +21 -0
- data/app/views/maquina/application/alert.rb +104 -0
- data/app/views/maquina/application/components/action_text_component.rb +20 -0
- data/app/views/maquina/application/components/checkbox_component.rb +21 -0
- data/app/views/maquina/application/components/component_base.rb +60 -0
- data/app/views/maquina/application/components/file_component.rb +59 -0
- data/app/views/maquina/application/components/input_component.rb +20 -0
- data/app/views/maquina/application/components/select_component.rb +44 -0
- data/app/views/maquina/application/create.turbo_stream.erb +11 -0
- data/app/views/maquina/application/edit.html.erb +9 -0
- data/app/views/maquina/application/edit.rb +17 -0
- data/app/views/maquina/application/form.rb +77 -0
- data/app/views/maquina/application/index.html.erb +10 -0
- data/app/views/maquina/application/index_header.rb +46 -0
- data/app/views/maquina/application/index_modal.rb +43 -0
- data/app/views/maquina/application/index_table.rb +121 -0
- data/app/views/maquina/application/new.html.erb +9 -0
- data/app/views/maquina/application/new.rb +18 -0
- data/app/views/maquina/application/sessions_header.rb +31 -0
- data/app/views/maquina/application/show.html.erb +1 -0
- data/app/views/maquina/application/update.turbo_stream.erb +11 -0
- data/app/views/maquina/application_view.rb +46 -0
- data/app/views/maquina/dashboard/index.html.erb +0 -0
- data/app/views/maquina/invitations/create.turbo_stream.erb +13 -0
- data/app/views/maquina/invitations/new.html.erb +3 -0
- data/app/views/maquina/navbar/menu.rb +62 -0
- data/app/views/maquina/navbar/menu_item_link.rb +34 -0
- data/app/views/maquina/navbar/mobile_button.rb +29 -0
- data/app/views/maquina/navbar/mobile_menu.rb +47 -0
- data/app/views/maquina/navbar/notification.rb +37 -0
- data/app/views/maquina/navbar/profile.rb +16 -0
- data/app/views/maquina/navbar/profile_button.rb +24 -0
- data/app/views/maquina/navbar/profile_menu.rb +108 -0
- data/app/views/maquina/navbar/profile_menu_item_link.rb +41 -0
- data/app/views/maquina/navbar/search.rb +40 -0
- data/app/views/maquina/navbar/title.rb +22 -0
- data/app/views/maquina/sessions/create.turbo_stream.erb +11 -0
- data/app/views/maquina/sessions/form.rb +56 -0
- data/app/views/maquina/sessions/new.html.erb +9 -0
- data/app/views/maquina/unauthorized/401.html.erb +1 -0
- data/app/views/maquina/user_notifications_mailer/invitation_email.html.erb +40 -0
- data/app/views/maquina/user_notifications_mailer/invitation_email.text.erb +12 -0
- data/config/definitions.rb +1 -0
- data/config/initializers/importmap.rb +17 -0
- data/config/initializers/money.rb +116 -0
- data/config/initializers/pagy.rb +235 -0
- data/config/locales/flash.en.yml +44 -0
- data/config/locales/forms.en.yml +58 -0
- data/config/locales/mailers.en.yml +35 -0
- data/config/locales/models.en.yml +34 -0
- data/config/locales/routes.en.yml +7 -0
- data/config/locales/views.en.yml +45 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20221109010726_create_maquina_plans.rb +13 -0
- data/db/migrate/20221113000409_create_maquina_users.rb +19 -0
- data/db/migrate/20221113020108_create_maquina_used_passwords.rb +10 -0
- data/db/migrate/20221115223414_create_maquina_active_sessions.rb +15 -0
- data/db/migrate/20230201203922_create_maquina_invitations.rb +12 -0
- data/db/schema.rb +1 -0
- data/lib/generators/maquina/install_generator.rb +32 -0
- data/lib/generators/maquina/install_templates/install_templates_generator.rb +31 -0
- data/lib/generators/maquina/tailwind_config/tailwind_config_generator.rb +11 -0
- data/lib/generators/maquina/tailwind_config/templates/app/assets/config/maquina/tailwind.config.js.tt +68 -0
- data/lib/generators/maquina/templates/config/initializers/maquina.rb +3 -0
- data/lib/maquina/engine.rb +17 -0
- data/lib/maquina/version.rb +3 -0
- data/lib/maquina.rb +48 -0
- data/lib/tasks/install.rake +19 -0
- data/lib/tasks/maquina_tasks.rake +4 -0
- data/lib/tasks/tailwind.rake +25 -0
- metadata +456 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" xmlns:v="urn:schemas-microsoft-com:vml">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="x-apple-disable-message-reformatting">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no, url=no">
|
|
8
|
+
<meta name="color-scheme" content="light dark">
|
|
9
|
+
<meta name="supported-color-schemes" content="light dark">
|
|
10
|
+
<!--[if mso]>
|
|
11
|
+
<noscript>
|
|
12
|
+
<xml>
|
|
13
|
+
<o:OfficeDocumentSettings xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
14
|
+
<o:PixelsPerInch>96</o:PixelsPerInch>
|
|
15
|
+
</o:OfficeDocumentSettings>
|
|
16
|
+
</xml>
|
|
17
|
+
</noscript>
|
|
18
|
+
<style>
|
|
19
|
+
td,th,div,p,a,h1,h2,h3,h4,h5,h6 {font-family: "Segoe UI", sans-serif; mso-line-height-rule: exactly;}
|
|
20
|
+
</style>
|
|
21
|
+
<![endif]-->
|
|
22
|
+
|
|
23
|
+
<style>
|
|
24
|
+
/* Tailwind components that are generated by plugins */
|
|
25
|
+
/**
|
|
26
|
+
* @import here any custom components - classes that you'd want loaded
|
|
27
|
+
* before the Tailwind utilities, so that the utilities could still
|
|
28
|
+
* override them.
|
|
29
|
+
*/
|
|
30
|
+
.button {
|
|
31
|
+
display: inline-block;
|
|
32
|
+
color: #fff;
|
|
33
|
+
text-decoration-line: none;
|
|
34
|
+
background-color: #3869D4;
|
|
35
|
+
border-top: 10px solid #3869D4;
|
|
36
|
+
border-right: 18px solid #3869D4;
|
|
37
|
+
border-bottom: 10px solid #3869D4;
|
|
38
|
+
border-left: 18px solid #3869D4;
|
|
39
|
+
border-radius: 3px;
|
|
40
|
+
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);
|
|
41
|
+
}
|
|
42
|
+
.button--green {
|
|
43
|
+
background-color: #22BC66;
|
|
44
|
+
border-top: 10px solid #22BC66;
|
|
45
|
+
border-right: 18px solid #22BC66;
|
|
46
|
+
border-bottom: 10px solid #22BC66;
|
|
47
|
+
border-left: 18px solid #22BC66;
|
|
48
|
+
}
|
|
49
|
+
.button--red {
|
|
50
|
+
background-color: #FF6136;
|
|
51
|
+
border-top: 10px solid #FF6136;
|
|
52
|
+
border-right: 18px solid #FF6136;
|
|
53
|
+
border-bottom: 10px solid #FF6136;
|
|
54
|
+
border-left: 18px solid #FF6136;
|
|
55
|
+
}
|
|
56
|
+
@media (max-width: 600px) {
|
|
57
|
+
.button {
|
|
58
|
+
display: block !important;
|
|
59
|
+
text-align: center !important;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
.purchase_heading {
|
|
63
|
+
border-bottom-width: 1px;
|
|
64
|
+
border-bottom-color: #EAEAEC;
|
|
65
|
+
border-bottom-style: solid;
|
|
66
|
+
}
|
|
67
|
+
.purchase_heading p {
|
|
68
|
+
margin: 0;
|
|
69
|
+
font-size: 12px;
|
|
70
|
+
line-height: 24px;
|
|
71
|
+
color: #85878E;
|
|
72
|
+
}
|
|
73
|
+
.purchase_footer {
|
|
74
|
+
padding-top: 16px;
|
|
75
|
+
vertical-align: middle;
|
|
76
|
+
font-size: 16px;
|
|
77
|
+
border-top-width: 1px;
|
|
78
|
+
border-top-color: #EAEAEC;
|
|
79
|
+
border-top-style: solid;
|
|
80
|
+
}
|
|
81
|
+
.body-sub {
|
|
82
|
+
margin-top: 25px;
|
|
83
|
+
border-top-width: 1px;
|
|
84
|
+
padding-top: 25px;
|
|
85
|
+
border-top-color: #EAEAEC;
|
|
86
|
+
border-top-style: solid;
|
|
87
|
+
}
|
|
88
|
+
.discount {
|
|
89
|
+
width: 100%;
|
|
90
|
+
background-color: #F4F4F7;
|
|
91
|
+
padding: 96px;
|
|
92
|
+
border: 2px dashed #cbcccf;
|
|
93
|
+
}
|
|
94
|
+
@media (prefers-color-scheme: dark) {
|
|
95
|
+
body,
|
|
96
|
+
.email-body,
|
|
97
|
+
.email-body_inner,
|
|
98
|
+
.email-content,
|
|
99
|
+
.email-wrapper,
|
|
100
|
+
.email-masthead,
|
|
101
|
+
.email-footer {
|
|
102
|
+
background-color: #333333 !important;
|
|
103
|
+
color: #fff !important;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
p,
|
|
107
|
+
ul,
|
|
108
|
+
ol,
|
|
109
|
+
blockquote,
|
|
110
|
+
h1,
|
|
111
|
+
h2,
|
|
112
|
+
h3 {
|
|
113
|
+
color: #fff !important;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.attributes_content,
|
|
117
|
+
.discount {
|
|
118
|
+
background-color: #222222 !important;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.email-masthead_name {
|
|
122
|
+
text-shadow: none !important;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/* Tailwind utility classes */
|
|
126
|
+
.m-0 {
|
|
127
|
+
margin: 0;
|
|
128
|
+
}
|
|
129
|
+
.w-auto {
|
|
130
|
+
width: auto;
|
|
131
|
+
}
|
|
132
|
+
.mx-auto {
|
|
133
|
+
margin-left: auto;
|
|
134
|
+
margin-right: auto;
|
|
135
|
+
}
|
|
136
|
+
.my-7 {
|
|
137
|
+
margin-top: 28px;
|
|
138
|
+
margin-bottom: 28px;
|
|
139
|
+
}
|
|
140
|
+
.my-7_5 {
|
|
141
|
+
margin-top: 30px;
|
|
142
|
+
margin-bottom: 30px;
|
|
143
|
+
}
|
|
144
|
+
.mb-5 {
|
|
145
|
+
margin-bottom: 20px;
|
|
146
|
+
}
|
|
147
|
+
.mb-21px {
|
|
148
|
+
margin-bottom: 21px;
|
|
149
|
+
}
|
|
150
|
+
.mb-5px {
|
|
151
|
+
margin-bottom: 5px;
|
|
152
|
+
}
|
|
153
|
+
.mt-0 {
|
|
154
|
+
margin-top: 0;
|
|
155
|
+
}
|
|
156
|
+
.mt-1 {
|
|
157
|
+
margin-top: 4px;
|
|
158
|
+
}
|
|
159
|
+
.mt-1_5 {
|
|
160
|
+
margin-top: 6px;
|
|
161
|
+
}
|
|
162
|
+
.m-2_5 {
|
|
163
|
+
margin-top: 10px;
|
|
164
|
+
}
|
|
165
|
+
.h-8 {
|
|
166
|
+
height: 32px;
|
|
167
|
+
}
|
|
168
|
+
.block {
|
|
169
|
+
display: block;
|
|
170
|
+
}
|
|
171
|
+
.table {
|
|
172
|
+
display: table;
|
|
173
|
+
}
|
|
174
|
+
.hidden {
|
|
175
|
+
display: none;
|
|
176
|
+
}
|
|
177
|
+
.w-1-5 {
|
|
178
|
+
width: 20%;
|
|
179
|
+
}
|
|
180
|
+
.w-4-5 {
|
|
181
|
+
width: 80%;
|
|
182
|
+
}
|
|
183
|
+
.w-570px {
|
|
184
|
+
width: 570px;
|
|
185
|
+
}
|
|
186
|
+
.w-full {
|
|
187
|
+
width: 100%;
|
|
188
|
+
}
|
|
189
|
+
.bg-gray-postmark-lighter {
|
|
190
|
+
background-color: #94a3b8;
|
|
191
|
+
}
|
|
192
|
+
.bg-gray-postmark-lightest {
|
|
193
|
+
background-color: #F4F4F7;
|
|
194
|
+
}
|
|
195
|
+
.bg-white {
|
|
196
|
+
background-color: #fff;
|
|
197
|
+
}
|
|
198
|
+
.p-0 {
|
|
199
|
+
padding: 0;
|
|
200
|
+
}
|
|
201
|
+
.p-4 {
|
|
202
|
+
padding: 16px;
|
|
203
|
+
}
|
|
204
|
+
.p-45px {
|
|
205
|
+
padding: 45px;
|
|
206
|
+
}
|
|
207
|
+
.py-2 {
|
|
208
|
+
padding-top: 8px;
|
|
209
|
+
padding-bottom: 8px;
|
|
210
|
+
}
|
|
211
|
+
.py-2_5 {
|
|
212
|
+
padding-top: 10px;
|
|
213
|
+
padding-bottom: 10px;
|
|
214
|
+
}
|
|
215
|
+
.py-25px {
|
|
216
|
+
padding-top: 25px;
|
|
217
|
+
padding-bottom: 25px;
|
|
218
|
+
}
|
|
219
|
+
.py-35px {
|
|
220
|
+
padding-top: 35px;
|
|
221
|
+
padding-bottom: 35px;
|
|
222
|
+
}
|
|
223
|
+
.pb-2 {
|
|
224
|
+
padding-bottom: 8px;
|
|
225
|
+
}
|
|
226
|
+
.pb-4 {
|
|
227
|
+
padding-bottom: 16px;
|
|
228
|
+
}
|
|
229
|
+
.pr-4 {
|
|
230
|
+
padding-right: 16px;
|
|
231
|
+
}
|
|
232
|
+
.pt-25px {
|
|
233
|
+
padding-top: 25px;
|
|
234
|
+
}
|
|
235
|
+
.text-left {
|
|
236
|
+
text-align: left;
|
|
237
|
+
}
|
|
238
|
+
.text-center {
|
|
239
|
+
text-align: center;
|
|
240
|
+
}
|
|
241
|
+
.text-right {
|
|
242
|
+
text-align: right;
|
|
243
|
+
}
|
|
244
|
+
.font-sans {
|
|
245
|
+
font-family: "Nunito Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
246
|
+
}
|
|
247
|
+
.text-2xl {
|
|
248
|
+
font-size: 24px;
|
|
249
|
+
}
|
|
250
|
+
.text-base {
|
|
251
|
+
font-size: 16px;
|
|
252
|
+
}
|
|
253
|
+
.text-sm {
|
|
254
|
+
font-size: 14px;
|
|
255
|
+
}
|
|
256
|
+
.text-xs {
|
|
257
|
+
font-size: 12px;
|
|
258
|
+
}
|
|
259
|
+
.font-bold {
|
|
260
|
+
font-weight: 700;
|
|
261
|
+
}
|
|
262
|
+
.leading-4 {
|
|
263
|
+
line-height: 16px;
|
|
264
|
+
}
|
|
265
|
+
.leading-4_5 {
|
|
266
|
+
line-height: 18px;
|
|
267
|
+
}
|
|
268
|
+
.leading-6 {
|
|
269
|
+
line-height: 24px;
|
|
270
|
+
}
|
|
271
|
+
.text-blue-postmark {
|
|
272
|
+
color: #0063EB;
|
|
273
|
+
}
|
|
274
|
+
.text-gray-postmark-dark {
|
|
275
|
+
color: #51545E;
|
|
276
|
+
}
|
|
277
|
+
.text-gray-postmark-darker {
|
|
278
|
+
color: #333333;
|
|
279
|
+
}
|
|
280
|
+
.text-gray-postmark-light {
|
|
281
|
+
color: #64748b;
|
|
282
|
+
}
|
|
283
|
+
.text-gray-postmark-meta {
|
|
284
|
+
color: #85878E;
|
|
285
|
+
}
|
|
286
|
+
.-webkit-font-smoothing-antialiased {
|
|
287
|
+
-webkit-font-smoothing: antialiased;
|
|
288
|
+
}
|
|
289
|
+
.text-decoration-none {
|
|
290
|
+
text-decoration: none;
|
|
291
|
+
}
|
|
292
|
+
.text-shadow-0_1px_0__FFF {
|
|
293
|
+
text-shadow: 0 1px 0 #FFF;
|
|
294
|
+
}
|
|
295
|
+
.word-break-break-word {
|
|
296
|
+
word-break: break-word;
|
|
297
|
+
}
|
|
298
|
+
/* Your custom utility classes */
|
|
299
|
+
/*
|
|
300
|
+
* Here is where you can define your custom utility classes.
|
|
301
|
+
*
|
|
302
|
+
* We wrap them in the `utilities` @layer directive, so
|
|
303
|
+
* that Tailwind moves them to the correct location.
|
|
304
|
+
*
|
|
305
|
+
* More info:
|
|
306
|
+
* https://tailwindcss.com/docs/functions-and-directives#layer
|
|
307
|
+
*/
|
|
308
|
+
:root {
|
|
309
|
+
color-scheme: light dark;
|
|
310
|
+
}
|
|
311
|
+
@media (max-width: 600px) {
|
|
312
|
+
.sm-w-full {
|
|
313
|
+
width: 100% !important;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
</style>
|
|
318
|
+
</head>
|
|
319
|
+
|
|
320
|
+
<body class="m-0 p-0 w-full word-break-break-word -webkit-font-smoothing-antialiased ">
|
|
321
|
+
<div role="article" aria-roledescription="email" aria-label="" lang="en">
|
|
322
|
+
<table class="email-wrapper w-full font-sans" cellpadding="0" cellspacing="0" role="presentation">
|
|
323
|
+
<tr>
|
|
324
|
+
<td align="center">
|
|
325
|
+
<table class="email-content w-full" cellpadding="0" cellspacing="0" role="presentation">
|
|
326
|
+
<tr>
|
|
327
|
+
<td align="center" class="email-masthead py-25px text-base text-center">
|
|
328
|
+
<%= link_to main_app.root_url, class: "email-masthead_name text-base font-bold text-decoration-none text-gray-postmark-light text-shadow-0_1px_0__FFF" do %>
|
|
329
|
+
<%= image_tag "maquina/maquina.svg", class: "mx-auto h-8 w-auto" %>
|
|
330
|
+
<p class="leading-6"><%= t("application_name") %></p>
|
|
331
|
+
<% end %>
|
|
332
|
+
</td>
|
|
333
|
+
</tr>
|
|
334
|
+
<tr>
|
|
335
|
+
<td class="email-body w-full bg-white">
|
|
336
|
+
<table align="center" class="email-body_inner w-570px bg-white mx-auto sm-w-full" cellpadding="0" cellspacing="0" role="presentation">
|
|
337
|
+
<tr>
|
|
338
|
+
<td class="p-45px">
|
|
339
|
+
<div class="text-base">
|
|
340
|
+
|
|
341
|
+
<%= yield %>
|
|
342
|
+
|
|
343
|
+
</div>
|
|
344
|
+
</td>
|
|
345
|
+
</tr>
|
|
346
|
+
</table>
|
|
347
|
+
</td>
|
|
348
|
+
</tr>
|
|
349
|
+
|
|
350
|
+
<tr>
|
|
351
|
+
<td>
|
|
352
|
+
<table align="center" class="email-footer w-570px mx-auto text-center sm-w-full" cellpadding="0" cellspacing="0" role="presentation">
|
|
353
|
+
<tr>
|
|
354
|
+
<td align="center" class="content-cell p-45px text-base">
|
|
355
|
+
<p class="mt-1_5 mb-5 text-xs leading-6 text-center text-gray-postmark-light">
|
|
356
|
+
<%= t("mailers.copyright") %>
|
|
357
|
+
</p>
|
|
358
|
+
<p class="mt-1_5 mb-5 text-xs leading-6 text-center text-gray-postmark-light">
|
|
359
|
+
<%= t("mailers.company_name") %>
|
|
360
|
+
|
|
361
|
+
<br><%= t("mailers.address_1") %>
|
|
362
|
+
<br><%= t("mailers.address_2") %>
|
|
363
|
+
</p>
|
|
364
|
+
</td>
|
|
365
|
+
</tr>
|
|
366
|
+
</table>
|
|
367
|
+
</td>
|
|
368
|
+
</tr>
|
|
369
|
+
|
|
370
|
+
</table>
|
|
371
|
+
</td>
|
|
372
|
+
</tr>
|
|
373
|
+
</table>
|
|
374
|
+
|
|
375
|
+
</div>
|
|
376
|
+
</body>
|
|
377
|
+
</html>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html class="h-full bg-gray-50">
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= t("application_name") %></title>
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<%= csrf_meta_tags %>
|
|
7
|
+
<%= csp_meta_tag %>
|
|
8
|
+
|
|
9
|
+
<%= stylesheet_link_tag "maquina/tailwind", "inter-font", "data-turbo-track": "reload" %>
|
|
10
|
+
<%= stylesheet_link_tag "maquina/application", "data-turbo-track": "reload" %>
|
|
11
|
+
|
|
12
|
+
<%= maquina_importmap_tags %>
|
|
13
|
+
</head>
|
|
14
|
+
|
|
15
|
+
<body class="h-full">
|
|
16
|
+
<%= turbo_frame_tag :alert do %>
|
|
17
|
+
<%= render Maquina::Application::Alert.new(flash) %>
|
|
18
|
+
<% end %>
|
|
19
|
+
|
|
20
|
+
<main class="container mx-auto">
|
|
21
|
+
<%= yield %>
|
|
22
|
+
</main>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
|
|
2
|
+
<%= render Maquina::Application::SessionsHeader.new(brand_icon: brand_icon) do |component| %>
|
|
3
|
+
<% component.description do %>
|
|
4
|
+
<%= t(".description", org: t("application_name")) %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<% end %>
|
|
7
|
+
|
|
8
|
+
<%= render Maquina::AcceptInvitations::NewView.new(resource: @invitation) %>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maquina
|
|
4
|
+
module AcceptInvitations
|
|
5
|
+
class NewView < Phlex::HTML
|
|
6
|
+
include Maquina::ApplicationView
|
|
7
|
+
include Phlex::Rails::Helpers::FormWith
|
|
8
|
+
include Phlex::Rails::Helpers::HiddenField
|
|
9
|
+
include Phlex::Rails::Helpers::Routes
|
|
10
|
+
|
|
11
|
+
def initialize(resource:)
|
|
12
|
+
@resource = resource
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template
|
|
16
|
+
div(class: "mt-8 sm:mx-auto sm:w-full sm:max-w-md") do
|
|
17
|
+
div(class: "bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10") do
|
|
18
|
+
@resource.new_record? ? invalid_invitation : build_form
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def invalid_invitation
|
|
26
|
+
p(class: "text-center text-skin-muted") { t("maquina.accept_invitations.new.expired") }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def build_form
|
|
30
|
+
form_with(model: @resource, url: accept_invitations_path, method: :patch, local: true, class: "space-y-6", data: {"turbo-frame": "_top"}) do |form|
|
|
31
|
+
form.hidden_field :invitation_token
|
|
32
|
+
div(class: "field") do
|
|
33
|
+
div(class: "control") do
|
|
34
|
+
form.submit t("form.accept_invitations.submit"), class: "button button-accented w-full"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<nav class="transition-all ease-in-out delay-300 backdrop-blur-sm bg-white shadow-sm fixed top-0 left-0 right-0 z-20" data-controller="mobile-menu" data-navbar-target="navbar">
|
|
2
|
+
<div class="max-w-7xl mx-auto px-2 sm:px-4 lg:px-8">
|
|
3
|
+
<div class="flex justify-between h-16">
|
|
4
|
+
<div class="flex px-2 lg:px-0">
|
|
5
|
+
<%= render Maquina::Navbar::Title.new(brand_icon: brand_icon) %>
|
|
6
|
+
<%= render Maquina::Navbar::Menu.new %>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<%= render Maquina::Navbar::Search.new(query: params[:q], url: collection_path) if action_name == "index" && respond_to?(:collection_path) && collection_path.present? %>
|
|
10
|
+
|
|
11
|
+
<%= render Maquina::Navbar::MobileButton.new %>
|
|
12
|
+
|
|
13
|
+
<div class="hidden sm:ml-6 lg:flex sm:items-center">
|
|
14
|
+
<%= render Maquina::Navbar::Notification.new %>
|
|
15
|
+
<%= render Maquina::Navbar::Profile.new %>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<%= render Maquina::Navbar::MobileMenu.new %>
|
|
21
|
+
</nav>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maquina
|
|
4
|
+
module Application
|
|
5
|
+
class Alert < Phlex::HTML
|
|
6
|
+
include Maquina::ApplicationView
|
|
7
|
+
|
|
8
|
+
def initialize(flash)
|
|
9
|
+
notice = flash.notice
|
|
10
|
+
alert = flash.alert
|
|
11
|
+
|
|
12
|
+
@flash = notice || alert
|
|
13
|
+
@success = notice.present?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def template
|
|
17
|
+
return if @flash.blank?
|
|
18
|
+
|
|
19
|
+
div(aria_live: "assertive", class: "pointer-events-none fixed inset-0 flex items-end px-4 py-6 sm:items-start sm:p-6 z-30", data: {controller: "alert", "turbo-cache": false}) do
|
|
20
|
+
div(class: "flex w-full flex-col items-center space-y-4 sm:items-end hidden", data: transition_attributes) do
|
|
21
|
+
div(class: "pointer-events-auto w-full max-w-sm overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5") do
|
|
22
|
+
div(class: "p-4") do
|
|
23
|
+
div(class: "flex items-start") do
|
|
24
|
+
div(class: "flex-shrink-0") do
|
|
25
|
+
svg_icon(:outline, css_class: classes("h-6 w-6", alert_success?: "text-green-400", alert_failure?: "text-red-400").dig(:class), icon: alert_icon)
|
|
26
|
+
end
|
|
27
|
+
div(class: "ml-3 w-0 flex-1 pt-0.5") do
|
|
28
|
+
p(class: "text-sm font-medium text-skin-base") { alert_title }
|
|
29
|
+
p(class: "mt-1 text-sm text-skin-dimmed") { alert_description }
|
|
30
|
+
end
|
|
31
|
+
div(class: "ml-4 flex flex-shrink-0") do
|
|
32
|
+
button(type: "button", class: "inline-flex rounded-md bg-white text-gray-dimmed hover:text-skin-muted focus:outline-none focus:ring-2 focus:ring-skin-accented focus:ring-offset-2", data: {action: "alert#close"}) do
|
|
33
|
+
span(class: "sr-only") { "Close" }
|
|
34
|
+
svg_icon(:fill, view_box: "0 0 20 20", css_class: "h-5 w-5", icon: close_icon)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def alert_title
|
|
47
|
+
return @flash.dig(:title) || @flash.dig("title") if @flash.is_a?(Hash)
|
|
48
|
+
|
|
49
|
+
@flash
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def alert_description
|
|
53
|
+
return @flash.dig(:description) || @flash.dig("description") if @flash.is_a?(Hash)
|
|
54
|
+
|
|
55
|
+
@flash
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def alert_icon
|
|
59
|
+
alert_success? ? success_icon : failure_icon
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def alert_success?
|
|
63
|
+
@success
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def alert_failure?
|
|
67
|
+
!alert_success?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def transition_attributes
|
|
71
|
+
{
|
|
72
|
+
"alert-target": "alert",
|
|
73
|
+
"transition-enter": "transform ease-out duration-300 transition",
|
|
74
|
+
"transition-enter-active": "translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2",
|
|
75
|
+
"transition-enter-to": "translate-y-0 opacity-100 sm:translate-x-0",
|
|
76
|
+
"transition-leave": "transition ease-in duration-100",
|
|
77
|
+
"transition-leave-active": "opacity-100",
|
|
78
|
+
"transition-leave-to": "opacity-0"
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def svg_attributes(attrs = {})
|
|
83
|
+
{
|
|
84
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
85
|
+
viewbox: "0 0 24 24",
|
|
86
|
+
fill: "currentColor",
|
|
87
|
+
aria_hidden: "true"
|
|
88
|
+
}.merge(attrs)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def success_icon
|
|
92
|
+
"M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def failure_icon
|
|
96
|
+
"M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def close_icon
|
|
100
|
+
"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maquina
|
|
4
|
+
module Application
|
|
5
|
+
module Components
|
|
6
|
+
class ActionTextComponent < ComponentBase
|
|
7
|
+
def template
|
|
8
|
+
div(**control_html) do
|
|
9
|
+
@form.label attribute_name, class: "label #{label_css_class}"
|
|
10
|
+
div(class: "mt-1") do
|
|
11
|
+
@form.rich_text_area attribute_name, **input_html
|
|
12
|
+
help_template
|
|
13
|
+
error_template
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maquina
|
|
4
|
+
module Application
|
|
5
|
+
module Components
|
|
6
|
+
class CheckboxComponent < ComponentBase
|
|
7
|
+
def template
|
|
8
|
+
div(**control_html) do
|
|
9
|
+
div(class: "flex h-5 items-center") do
|
|
10
|
+
@form.check_box attribute_name, **input_html
|
|
11
|
+
end
|
|
12
|
+
div(class: "text-sm leading-6") do
|
|
13
|
+
@form.label attribute_name, class: "label #{label_css_class}"
|
|
14
|
+
help_template
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Maquina
|
|
4
|
+
module Application
|
|
5
|
+
module Components
|
|
6
|
+
class ComponentBase < Phlex::HTML
|
|
7
|
+
include ApplicationView
|
|
8
|
+
|
|
9
|
+
def initialize(resource:, form:, options: {})
|
|
10
|
+
@resource = resource
|
|
11
|
+
@form = form
|
|
12
|
+
@options = options
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
protected
|
|
16
|
+
|
|
17
|
+
def control_html
|
|
18
|
+
options = @options.fetch(:control_html, {})
|
|
19
|
+
options[:class] ||= ""
|
|
20
|
+
options[:class] += " control-error" if @resource.errors[attribute_name].any?
|
|
21
|
+
|
|
22
|
+
options
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def input_html(no_helpers: false)
|
|
26
|
+
options = @options.fetch(:input_html, {})
|
|
27
|
+
|
|
28
|
+
if !no_helpers
|
|
29
|
+
options[:maxlength] = t("helpers.maxlength.#{@resource.model_name.i18n_key}.#{attribute_name}", default: t("helpers.maxlength.default"))
|
|
30
|
+
options[:placeholder] = t("helpers.placeholder.#{@resource.model_name.i18n_key}.#{attribute_name}", default: nil)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
options
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def attribute_name
|
|
37
|
+
@attribute_name ||= @options.fetch(:name, "")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def label_css_class
|
|
41
|
+
@options.dig(:control_html, :label_class) || ""
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def help_template
|
|
45
|
+
help = t("helpers.help.#{@resource.model_name.i18n_key}.#{attribute_name}", default: nil)
|
|
46
|
+
return if help.blank?
|
|
47
|
+
|
|
48
|
+
p(class: "help") { unsafe_raw help }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def error_template
|
|
52
|
+
error_message = @resource.errors[attribute_name].first
|
|
53
|
+
return if error_message.blank?
|
|
54
|
+
|
|
55
|
+
p(class: "help help-error") { error_message }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|