fluxbit_view_components 0.3.0 → 0.4.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 +4 -4
- data/README.md +10 -0
- data/app/assets/javascripts/fluxbit_view_components/assigner_controller.js +49 -0
- data/app/assets/javascripts/fluxbit_view_components/auto_submit_controller.js +39 -0
- data/app/assets/javascripts/fluxbit_view_components/drawer_controller.js +135 -0
- data/app/assets/javascripts/fluxbit_view_components/index.js +56 -0
- data/app/assets/javascripts/fluxbit_view_components/method_link_controller.js +143 -0
- data/app/assets/javascripts/fluxbit_view_components/modal_controller.js +118 -0
- data/app/assets/javascripts/fluxbit_view_components/password_controller.js +170 -0
- data/app/assets/javascripts/fluxbit_view_components/progress_controller.js +374 -0
- data/app/assets/javascripts/fluxbit_view_components/row_click_controller.js +32 -0
- data/app/assets/javascripts/fluxbit_view_components/select_all_controller.js +122 -0
- data/app/assets/javascripts/fluxbit_view_components/spinner_percent_controller.js +174 -0
- data/app/assets/javascripts/fluxbit_view_components/theme_button_controller.js +90 -0
- data/app/assets/javascripts/fluxbit_view_components.js +1175 -0
- data/app/components/fluxbit/accordion_component.rb +125 -0
- data/app/components/fluxbit/alert_component.rb +8 -8
- data/app/components/fluxbit/avatar_component.rb +11 -12
- data/app/components/fluxbit/avatar_group_component.rb +1 -1
- data/app/components/fluxbit/badge_component.rb +8 -7
- data/app/components/fluxbit/banner_component.rb +139 -0
- data/app/components/fluxbit/bottom_navigation_component.rb +437 -0
- data/app/components/fluxbit/breadcrumb_component.rb +66 -0
- data/app/components/fluxbit/button_component.rb +39 -11
- data/app/components/fluxbit/button_group_component.rb +1 -1
- data/app/components/fluxbit/card_component.rb +26 -23
- data/app/components/fluxbit/carousel_component.rb +154 -0
- data/app/components/fluxbit/component.rb +24 -3
- data/app/components/fluxbit/drawer_component.html.erb +30 -0
- data/app/components/fluxbit/drawer_component.rb +125 -0
- data/app/components/fluxbit/dropdown_component.rb +41 -0
- data/app/components/fluxbit/dropdown_item_component.rb +68 -0
- data/app/components/fluxbit/flex_component.rb +1 -1
- data/app/components/fluxbit/form/component.rb +15 -8
- data/app/components/fluxbit/form/dropzone_component.rb +3 -3
- data/app/components/fluxbit/form/field_component.rb +4 -2
- data/app/components/fluxbit/form/help_text_component.rb +1 -1
- data/app/components/fluxbit/form/label_component.rb +10 -3
- data/app/components/fluxbit/form/password_component.rb +247 -0
- data/app/components/fluxbit/form/radio_group_button_component.rb +126 -0
- data/app/components/fluxbit/form/select_component.rb +108 -11
- data/app/components/fluxbit/form/text_field_component.rb +40 -23
- data/app/components/fluxbit/form/toggle_component.rb +2 -2
- data/app/components/fluxbit/form/upload_image_component.html.erb +3 -3
- data/app/components/fluxbit/form/upload_image_component.rb +12 -1
- data/app/components/fluxbit/gravatar_component.rb +7 -0
- data/app/components/fluxbit/icon_helpers.rb +167 -0
- data/app/components/fluxbit/link_component.rb +42 -0
- data/app/components/fluxbit/modal_component.rb +28 -31
- data/app/components/fluxbit/pagination_component.rb +206 -0
- data/app/components/fluxbit/popover_component.rb +14 -14
- data/app/components/fluxbit/progress_component.rb +196 -0
- data/app/components/fluxbit/skeleton_component.rb +237 -0
- data/app/components/fluxbit/speed_dial_action_component.html.erb +30 -0
- data/app/components/fluxbit/speed_dial_action_component.rb +59 -0
- data/app/components/fluxbit/speed_dial_component.html.erb +33 -0
- data/app/components/fluxbit/speed_dial_component.rb +73 -0
- data/app/components/fluxbit/spinner_component.rb +71 -0
- data/app/components/fluxbit/spinner_percent_component.rb +174 -0
- data/app/components/fluxbit/stepper_component.rb +223 -0
- data/app/components/fluxbit/tab_component.rb +44 -25
- data/app/components/fluxbit/table_component.rb +186 -0
- data/app/components/fluxbit/table_group_component.rb +28 -0
- data/app/components/fluxbit/theme_button_component.rb +64 -0
- data/app/components/fluxbit/timeline_component.rb +63 -0
- data/app/components/fluxbit/timeline_item_component.html.erb +64 -0
- data/app/components/fluxbit/timeline_item_component.rb +78 -0
- data/app/components/fluxbit/tooltip_component.rb +2 -2
- data/app/helpers/fluxbit/components_helper.rb +74 -4
- data/app/helpers/fluxbit/form_builder.rb +64 -15
- data/app/helpers/fluxbit/view_helper.rb +71 -0
- data/config/locales/en.yml +37 -4
- data/config/locales/pt-BR.yml +36 -0
- data/lib/fluxbit/config/accordion_component.rb +73 -0
- data/lib/fluxbit/config/avatar_component.rb +11 -11
- data/lib/fluxbit/config/badge_component.rb +14 -11
- data/lib/fluxbit/config/banner_component.rb +60 -0
- data/lib/fluxbit/config/bottom_navigation_component.rb +74 -0
- data/lib/fluxbit/config/breadcrumb_component.rb +24 -0
- data/lib/fluxbit/config/button_component.rb +6 -4
- data/lib/fluxbit/config/card_component.rb +23 -12
- data/lib/fluxbit/config/carousel_component.rb +33 -0
- data/lib/fluxbit/config/drawer_component.rb +48 -0
- data/lib/fluxbit/config/dropdown_component.rb +29 -0
- data/lib/fluxbit/config/form/check_box_component.rb +1 -1
- data/lib/fluxbit/config/form/dropzone_component.rb +1 -1
- data/lib/fluxbit/config/form/help_text_component.rb +1 -1
- data/lib/fluxbit/config/form/label_component.rb +3 -2
- data/lib/fluxbit/config/form/password_component.rb +19 -0
- data/lib/fluxbit/config/form/radio_group_button_component.rb +24 -0
- data/lib/fluxbit/config/form/text_field_component.rb +11 -11
- data/lib/fluxbit/config/form/toggle_component.rb +5 -5
- data/lib/fluxbit/config/link_component.rb +24 -0
- data/lib/fluxbit/config/modal_component.rb +1 -1
- data/lib/fluxbit/config/pagination_component.rb +31 -0
- data/lib/fluxbit/config/popover_component.rb +1 -1
- data/lib/fluxbit/config/progress_component.rb +63 -0
- data/lib/fluxbit/config/skeleton_component.rb +82 -0
- data/lib/fluxbit/config/speed_dial_component.rb +50 -0
- data/lib/fluxbit/config/spinner_component.rb +30 -0
- data/lib/fluxbit/config/spinner_percent_component.rb +61 -0
- data/lib/fluxbit/config/stepper_component.rb +299 -0
- data/lib/fluxbit/config/tab_component.rb +6 -0
- data/lib/fluxbit/config/table_component.rb +75 -0
- data/lib/fluxbit/config/theme_button_component.rb +19 -0
- data/lib/fluxbit/config/timeline_component.rb +77 -0
- data/lib/fluxbit/view_components/engine.rb +11 -3
- data/lib/fluxbit/view_components/version.rb +1 -1
- data/lib/fluxbit/view_components.rb +20 -0
- data/lib/generators/fluxbit/devise_views_generator.rb +116 -0
- data/lib/generators/fluxbit/pagy_generator.rb +39 -0
- data/lib/generators/fluxbit/scaffold_generator.rb +165 -0
- data/lib/generators/fluxbit/templates/_alert.html.erb.tt +1 -0
- data/lib/generators/fluxbit/templates/_flash.html.erb.tt +15 -0
- data/lib/generators/fluxbit/templates/_form.html.erb.tt +38 -0
- data/lib/generators/fluxbit/templates/_metadata.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/controller.rb.tt +406 -0
- data/lib/generators/fluxbit/templates/create.turbo_stream.erb.tt +7 -0
- data/lib/generators/fluxbit/templates/destroy.turbo_stream.erb.tt +3 -0
- data/lib/generators/fluxbit/templates/destroy_all.turbo_stream.erb.tt +9 -0
- data/lib/generators/fluxbit/templates/devise_views/confirmations/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/layouts/devise.html.erb +64 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/confirmation_instructions.html.erb +5 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/email_changed.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/password_changed.html.erb +3 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/reset_password_instructions.html.erb +8 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/unlock_instructions.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/edit.html.erb +29 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/edit.html.erb +43 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/new.html.erb +34 -0
- data/lib/generators/fluxbit/templates/devise_views/sessions/new.html.erb +15 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_error_messages.html.erb +14 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_links.html.erb +25 -0
- data/lib/generators/fluxbit/templates/devise_views/unlocks/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/edit.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/fluxbit_pagy.css +27 -0
- data/lib/generators/fluxbit/templates/i18n.en.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/i18n.pt-BR.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/index.html.erb.tt +254 -0
- data/lib/generators/fluxbit/templates/index.json.jbuilder.tt +33 -0
- data/lib/generators/fluxbit/templates/new.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/partial.html.erb.tt +61 -0
- data/lib/generators/fluxbit/templates/policy.rb.tt +36 -0
- data/lib/generators/fluxbit/templates/send_alert_via_drawer.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/show.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/show.json.jbuilder.tt +6 -0
- data/lib/generators/fluxbit/templates/update.turbo_stream.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/update_all.turbo_stream.erb.tt +20 -0
- data/lib/install/install.rb +58 -0
- metadata +107 -18
- data/app/helpers/fluxbit/classes_helper.rb +0 -9
|
@@ -5,6 +5,7 @@ module Fluxbit::Config::TabComponent
|
|
|
5
5
|
mattr_accessor :color, default: :blue
|
|
6
6
|
mattr_accessor :vertical, default: false
|
|
7
7
|
mattr_accessor :tab_panel, default: :default
|
|
8
|
+
mattr_accessor :align, default: :left
|
|
8
9
|
|
|
9
10
|
# rubocop: disable Layout/LineLength, Metrics/BlockLength
|
|
10
11
|
mattr_accessor :styles do
|
|
@@ -18,6 +19,11 @@ module Fluxbit::Config::TabComponent
|
|
|
18
19
|
horizontal: "flex text-center",
|
|
19
20
|
vertical: "flex-column space-y space-y-4 text-sm font-medium text-gray-500 dark:text-gray-400 md:me-4 mb-4 md:mb-0"
|
|
20
21
|
},
|
|
22
|
+
align: {
|
|
23
|
+
left: "justify-start",
|
|
24
|
+
center: "justify-center",
|
|
25
|
+
right: "justify-end"
|
|
26
|
+
},
|
|
21
27
|
li: "",
|
|
22
28
|
variant: {
|
|
23
29
|
default: "flex-wrap text-sm font-medium text-gray-500 border-b border-gray-200 dark:border-gray-700 dark:text-gray-400",
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fluxbit::Config::TableComponent
|
|
4
|
+
mattr_accessor :striped, default: false
|
|
5
|
+
mattr_accessor :bordered, default: false
|
|
6
|
+
mattr_accessor :hover, default: false
|
|
7
|
+
mattr_accessor :shadow, default: false
|
|
8
|
+
|
|
9
|
+
# rubocop: disable Layout/LineLength, Metrics/BlockLength
|
|
10
|
+
mattr_accessor :styles do
|
|
11
|
+
{
|
|
12
|
+
root: {
|
|
13
|
+
base: "w-full text-left text-sm rtl:text-right text-gray-500 dark:text-gray-400",
|
|
14
|
+
shadow: "absolute left-0 top-0 -z-10 h-full w-full rounded-lg bg-white drop-shadow-md dark:bg-black"
|
|
15
|
+
},
|
|
16
|
+
wrapper: {
|
|
17
|
+
base: "overflow-x-auto relative",
|
|
18
|
+
shadow: "shadow-md sm:rounded-lg"
|
|
19
|
+
},
|
|
20
|
+
head: {
|
|
21
|
+
base: "text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400",
|
|
22
|
+
cell: "px-6 py-3"
|
|
23
|
+
},
|
|
24
|
+
footer: {
|
|
25
|
+
base: "text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400",
|
|
26
|
+
cell: "px-6 py-3"
|
|
27
|
+
},
|
|
28
|
+
body: {
|
|
29
|
+
base: "bg-white border-b dark:bg-gray-800 dark:border-gray-700 border-gray-200"
|
|
30
|
+
},
|
|
31
|
+
row: {
|
|
32
|
+
base: "",
|
|
33
|
+
bordered: "border-b dark:border-gray-700 border-gray-200",
|
|
34
|
+
hovered: {
|
|
35
|
+
default: "hover:bg-gray-200 dark:hover:bg-gray-600",
|
|
36
|
+
primary: "hover:bg-blue-200 dark:hover:bg-blue-700",
|
|
37
|
+
secondary: "hover:bg-gray-200 dark:hover:bg-gray-700",
|
|
38
|
+
success: "hover:bg-green-200 dark:hover:bg-green-700",
|
|
39
|
+
danger: "hover:bg-red-200 dark:hover:bg-red-700",
|
|
40
|
+
warning: "hover:bg-yellow-200 dark:hover:bg-yellow-700",
|
|
41
|
+
info: "hover:bg-cyan-200 dark:hover:bg-cyan-700",
|
|
42
|
+
light: "hover:bg-gray-300 dark:hover:bg-gray-700",
|
|
43
|
+
dark: "hover:bg-gray-700 dark:hover:bg-gray-200"
|
|
44
|
+
},
|
|
45
|
+
striped: {
|
|
46
|
+
default: "odd:bg-white even:bg-gray-50 odd:dark:bg-gray-900 even:dark:bg-gray-800",
|
|
47
|
+
primary: "odd:bg-blue-50 even:bg-blue-100 odd:dark:bg-blue-900 even:dark:bg-blue-800",
|
|
48
|
+
secondary: "odd:bg-gray-50 even:bg-gray-100 odd:dark:bg-gray-900 even:dark:bg-gray-800",
|
|
49
|
+
success: "odd:bg-green-50 even:bg-green-100 odd:dark:bg-green-900 even:dark:bg-green-800",
|
|
50
|
+
danger: "odd:bg-red-50 even:bg-red-100 odd:dark:bg-red-900 even:dark:bg-red-800",
|
|
51
|
+
warning: "odd:bg-yellow-50 even:bg-yellow-100 odd:dark:bg-yellow-900 even:dark:bg-yellow-800",
|
|
52
|
+
info: "odd:bg-cyan-50 even:bg-cyan-100 odd:dark:bg-cyan-900 even:dark:bg-cyan-800",
|
|
53
|
+
light: "odd:bg-gray-100 even:bg-gray-200 odd:dark:bg-gray-700 even:dark:bg-gray-600",
|
|
54
|
+
dark: "odd:bg-gray-800 even:bg-gray-900 odd:dark:bg-gray-200 even:dark:bg-gray-100"
|
|
55
|
+
},
|
|
56
|
+
colors: {
|
|
57
|
+
default: "",
|
|
58
|
+
primary: "bg-blue-50 dark:bg-blue-900",
|
|
59
|
+
secondary: "bg-gray-50 dark:bg-gray-800",
|
|
60
|
+
success: "bg-green-50 dark:bg-green-900",
|
|
61
|
+
danger: "bg-red-50 dark:bg-red-900",
|
|
62
|
+
warning: "bg-yellow-50 dark:bg-yellow-900",
|
|
63
|
+
info: "bg-cyan-50 dark:bg-cyan-900",
|
|
64
|
+
light: "bg-gray-100 dark:bg-gray-700",
|
|
65
|
+
dark: "bg-gray-800 dark:bg-gray-200"
|
|
66
|
+
},
|
|
67
|
+
cell: {
|
|
68
|
+
base: "px-6 py-2",
|
|
69
|
+
selected: "font-medium text-gray-900 whitespace-nowrap dark:text-white"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
# rubocop: enable Layout/LineLength, Metrics/BlockLength
|
|
75
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fluxbit::Config::ThemeButtonComponent
|
|
4
|
+
# Theme button specific defaults
|
|
5
|
+
mattr_accessor :color, default: :transparent
|
|
6
|
+
mattr_accessor :pill, default: true
|
|
7
|
+
mattr_accessor :size, default: 2
|
|
8
|
+
mattr_accessor :as, default: :button
|
|
9
|
+
|
|
10
|
+
# Delegate styles to ButtonComponent (class method)
|
|
11
|
+
def self.styles
|
|
12
|
+
Fluxbit::Config::ButtonComponent.styles
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Delegate styles to ButtonComponent (instance method for tests)
|
|
16
|
+
def styles
|
|
17
|
+
Fluxbit::Config::ButtonComponent.styles
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fluxbit::Config::TimelineComponent
|
|
4
|
+
mattr_accessor :variant, default: :default
|
|
5
|
+
mattr_accessor :position, default: :left
|
|
6
|
+
|
|
7
|
+
mattr_accessor :styles do
|
|
8
|
+
{
|
|
9
|
+
base: "relative",
|
|
10
|
+
variants: {
|
|
11
|
+
default: "space-y-8 border-l border-gray-200 dark:border-gray-700",
|
|
12
|
+
vertical: "space-y-6 border-l border-gray-200 dark:border-gray-700",
|
|
13
|
+
stepper: "items-center sm:flex",
|
|
14
|
+
activity: "space-y-4 border-l border-gray-200 dark:border-gray-700"
|
|
15
|
+
},
|
|
16
|
+
positions: {
|
|
17
|
+
left: "ml-3",
|
|
18
|
+
center: "",
|
|
19
|
+
right: "mr-3"
|
|
20
|
+
},
|
|
21
|
+
item: {
|
|
22
|
+
base: "relative flex items-start",
|
|
23
|
+
indicator: {
|
|
24
|
+
base: "absolute flex items-center justify-center w-6 h-6 -left-3 rounded-full bg-white dark:bg-gray-900",
|
|
25
|
+
status: {
|
|
26
|
+
default: "bg-blue-100 dark:bg-blue-900",
|
|
27
|
+
completed: "bg-green-100 dark:bg-green-900",
|
|
28
|
+
current: "bg-blue-600",
|
|
29
|
+
pending: "bg-gray-100 dark:bg-gray-700"
|
|
30
|
+
},
|
|
31
|
+
colors: {
|
|
32
|
+
blue: "text-blue-800 dark:text-blue-300",
|
|
33
|
+
green: "text-green-800 dark:text-green-300",
|
|
34
|
+
red: "text-red-800 dark:text-red-300",
|
|
35
|
+
yellow: "text-yellow-800 dark:text-yellow-300",
|
|
36
|
+
purple: "text-purple-800 dark:text-purple-300",
|
|
37
|
+
indigo: "text-indigo-800 dark:text-indigo-300"
|
|
38
|
+
},
|
|
39
|
+
rings: {
|
|
40
|
+
none: "",
|
|
41
|
+
small: "ring-1 ring-white dark:ring-gray-900",
|
|
42
|
+
default: "ring-2 ring-white dark:ring-gray-900",
|
|
43
|
+
large: "ring-4 ring-white dark:ring-gray-900"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
content: {
|
|
47
|
+
base: "ml-6 mb-8",
|
|
48
|
+
title: "mb-1 text-lg font-semibold text-gray-900 dark:text-white",
|
|
49
|
+
description: "mb-4 text-base font-normal text-gray-500 dark:text-gray-400",
|
|
50
|
+
date: "inline-flex items-center px-2.5 py-0.5 text-xs font-medium text-blue-800 bg-blue-100 rounded dark:bg-blue-900 dark:text-blue-300"
|
|
51
|
+
},
|
|
52
|
+
icon: "w-3.5 h-3.5",
|
|
53
|
+
dot: "w-2.5 h-2.5 bg-current rounded-full"
|
|
54
|
+
},
|
|
55
|
+
stepper: {
|
|
56
|
+
item: "relative mb-6 sm:mb-0",
|
|
57
|
+
indicator_container: "flex items-center",
|
|
58
|
+
indicator: "z-10 flex items-center justify-center w-6 h-6 bg-blue-100 rounded-full dark:bg-blue-900 shrink-0",
|
|
59
|
+
indicator_completed: "z-10 flex items-center justify-center w-6 h-6 bg-blue-600 rounded-full dark:bg-blue-900 shrink-0",
|
|
60
|
+
connector: "hidden sm:flex w-full bg-gray-200 h-0.5 dark:bg-gray-700",
|
|
61
|
+
content: "mt-3 sm:pe-8",
|
|
62
|
+
title: "text-lg font-semibold text-gray-900 dark:text-white",
|
|
63
|
+
description: "block mb-2 text-sm font-normal leading-none text-gray-400 dark:text-gray-500",
|
|
64
|
+
description_paragraph: "text-base font-normal text-gray-500 dark:text-gray-400",
|
|
65
|
+
icon: "w-2.5 h-2.5 text-blue-800 dark:text-blue-300",
|
|
66
|
+
icon_completed: "w-2.5 h-2.5 text-white dark:text-blue-300"
|
|
67
|
+
},
|
|
68
|
+
activity: {
|
|
69
|
+
base: "ml-6",
|
|
70
|
+
time: "mb-1 text-sm font-normal leading-none text-gray-400 dark:text-gray-500",
|
|
71
|
+
title: "text-lg font-semibold text-gray-900 dark:text-white",
|
|
72
|
+
description: "mb-4 text-base font-normal text-gray-500 dark:text-gray-400",
|
|
73
|
+
indicator: "absolute w-3 h-3 bg-gray-200 rounded-full mt-1.5 -left-1.5 border border-white dark:border-gray-900 dark:bg-gray-700"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -15,8 +15,16 @@ module Fluxbit
|
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
# Remove default wrapping .field_with_errors for proper Shopify form validations
|
|
18
|
-
config.to_prepare do
|
|
19
|
-
|
|
18
|
+
# config.to_prepare do
|
|
19
|
+
# ActionView::Base.field_error_proc = ->(html_tag, _instance) { html_tag.html_safe }
|
|
20
|
+
# end
|
|
21
|
+
|
|
22
|
+
initializer "fluxbitview_components.assets" do |app|
|
|
23
|
+
if app.config.respond_to?(:assets)
|
|
24
|
+
app.config.assets.precompile += %w[
|
|
25
|
+
fluxbit_view_components.js
|
|
26
|
+
]
|
|
27
|
+
end
|
|
20
28
|
end
|
|
21
29
|
|
|
22
30
|
initializer "fluxbit_view_components.importmap", before: "importmap" do |app|
|
|
@@ -27,8 +35,8 @@ module Fluxbit
|
|
|
27
35
|
|
|
28
36
|
initializer "fluxbit_view_components.helpers" do
|
|
29
37
|
ActiveSupport.on_load(:action_controller_base) do
|
|
30
|
-
helper Fluxbit::ClassesHelper
|
|
31
38
|
helper Fluxbit::ComponentsHelper
|
|
39
|
+
helper Fluxbit::ViewHelper
|
|
32
40
|
end
|
|
33
41
|
end
|
|
34
42
|
end
|
|
@@ -13,24 +13,44 @@ module Fluxbit
|
|
|
13
13
|
require "fluxbit/config/form/check_box_component"
|
|
14
14
|
require "fluxbit/config/form/dropzone_component"
|
|
15
15
|
require "fluxbit/config/form/label_component"
|
|
16
|
+
require "fluxbit/config/form/password_component"
|
|
17
|
+
require "fluxbit/config/form/radio_group_button_component"
|
|
16
18
|
require "fluxbit/config/form/range_component"
|
|
17
19
|
require "fluxbit/config/form/text_field_component"
|
|
18
20
|
require "fluxbit/config/form/toggle_component"
|
|
19
21
|
end
|
|
20
22
|
|
|
23
|
+
require "fluxbit/config/accordion_component"
|
|
21
24
|
require "fluxbit/config/alert_component"
|
|
22
25
|
require "fluxbit/config/avatar_component"
|
|
23
26
|
require "fluxbit/config/badge_component"
|
|
27
|
+
require "fluxbit/config/banner_component"
|
|
28
|
+
require "fluxbit/config/bottom_navigation_component"
|
|
29
|
+
require "fluxbit/config/breadcrumb_component"
|
|
24
30
|
require "fluxbit/config/button_component"
|
|
25
31
|
require "fluxbit/config/card_component"
|
|
32
|
+
require "fluxbit/config/carousel_component"
|
|
33
|
+
require "fluxbit/config/drawer_component"
|
|
34
|
+
require "fluxbit/config/dropdown_component"
|
|
26
35
|
require "fluxbit/config/flex_component"
|
|
27
36
|
require "fluxbit/config/gravatar_component"
|
|
28
37
|
require "fluxbit/config/heading_component"
|
|
38
|
+
require "fluxbit/config/link_component"
|
|
29
39
|
require "fluxbit/config/modal_component"
|
|
40
|
+
require "fluxbit/config/pagination_component"
|
|
30
41
|
require "fluxbit/config/paragraph_component"
|
|
31
42
|
require "fluxbit/config/popover_component"
|
|
43
|
+
require "fluxbit/config/progress_component"
|
|
44
|
+
require "fluxbit/config/skeleton_component"
|
|
45
|
+
require "fluxbit/config/speed_dial_component"
|
|
46
|
+
require "fluxbit/config/spinner_component"
|
|
47
|
+
require "fluxbit/config/spinner_percent_component"
|
|
48
|
+
require "fluxbit/config/stepper_component"
|
|
32
49
|
require "fluxbit/config/tab_component"
|
|
50
|
+
require "fluxbit/config/timeline_component"
|
|
51
|
+
require "fluxbit/config/table_component"
|
|
33
52
|
require "fluxbit/config/text_component"
|
|
53
|
+
require "fluxbit/config/theme_button_component"
|
|
34
54
|
require "fluxbit/config/tooltip_component"
|
|
35
55
|
end
|
|
36
56
|
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/base"
|
|
4
|
+
|
|
5
|
+
module Fluxbit
|
|
6
|
+
module ViewPathTemplates
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
argument :scope, required: false, default: nil, desc: "The scope to copy views to"
|
|
11
|
+
class_option :views, aliases: "-v", type: :array, desc: "Select specific view directories to generate (confirmations, passwords, registrations, sessions, unlocks, mailer)"
|
|
12
|
+
|
|
13
|
+
public_task :copy_views
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def copy_views
|
|
17
|
+
if options[:views]
|
|
18
|
+
options[:views].each do |directory|
|
|
19
|
+
view_directory directory.to_sym
|
|
20
|
+
end
|
|
21
|
+
else
|
|
22
|
+
view_directory :confirmations
|
|
23
|
+
view_directory :passwords
|
|
24
|
+
view_directory :registrations
|
|
25
|
+
view_directory :sessions
|
|
26
|
+
view_directory :unlocks
|
|
27
|
+
view_directory :shared
|
|
28
|
+
view_directory :mailer
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
copy_layout
|
|
32
|
+
configure_layouts
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def copy_layout
|
|
36
|
+
template "layouts/devise.html.erb", "app/views/layouts/devise.html.erb"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def configure_layouts
|
|
40
|
+
layout_config = <<-RUBY
|
|
41
|
+
# Use the Devise layout for all Devise controllers
|
|
42
|
+
config.to_prepare do
|
|
43
|
+
Devise::SessionsController.layout "devise"
|
|
44
|
+
Devise::RegistrationsController.layout "devise"
|
|
45
|
+
Devise::ConfirmationsController.layout "devise"
|
|
46
|
+
Devise::UnlocksController.layout "devise"
|
|
47
|
+
Devise::PasswordsController.layout "devise"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
RUBY
|
|
51
|
+
|
|
52
|
+
inject_into_file(
|
|
53
|
+
"config/application.rb",
|
|
54
|
+
layout_config,
|
|
55
|
+
after: "class Application < Rails::Application\n"
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
protected
|
|
60
|
+
|
|
61
|
+
def view_directory(name, _target_path = nil)
|
|
62
|
+
directory name.to_s, _target_path || "#{target_path}/#{name}" do |content|
|
|
63
|
+
if scope
|
|
64
|
+
content.gsub("devise/shared", "#{plural_scope}/shared")
|
|
65
|
+
else
|
|
66
|
+
content
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def target_path
|
|
72
|
+
@target_path ||= "app/views/#{plural_scope || :devise}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def plural_scope
|
|
76
|
+
@plural_scope ||= scope.presence && scope.underscore.pluralize
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class DeviseViewsGenerator < Rails::Generators::Base
|
|
81
|
+
include ViewPathTemplates
|
|
82
|
+
|
|
83
|
+
source_root File.expand_path("templates/devise_views", __dir__)
|
|
84
|
+
desc "Copies Devise views into your app. Usage: rails g fluxbit:devise_views"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class SharedViewsGenerator < Rails::Generators::Base # :nodoc:
|
|
88
|
+
include ViewPathTemplates
|
|
89
|
+
source_root File.expand_path("./devise_views", __FILE__)
|
|
90
|
+
desc "Copies shared Devise views to your application."
|
|
91
|
+
hide!
|
|
92
|
+
|
|
93
|
+
# Override copy_views to just copy mailer and shared.
|
|
94
|
+
def copy_views
|
|
95
|
+
view_directory :shared
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class FormForGenerator < Rails::Generators::Base # :nodoc:
|
|
100
|
+
include ViewPathTemplates
|
|
101
|
+
source_root File.expand_path("./devise_views", __FILE__)
|
|
102
|
+
desc "Copies default Devise views to your application."
|
|
103
|
+
hide!
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
class ErbGenerator < Rails::Generators::Base # :nodoc:
|
|
107
|
+
include ViewPathTemplates
|
|
108
|
+
source_root File.expand_path("./devise_views", __FILE__)
|
|
109
|
+
desc "Copies Devise mail erb views to your application."
|
|
110
|
+
hide!
|
|
111
|
+
|
|
112
|
+
def copy_views
|
|
113
|
+
view_directory(:mailer) if !options[:views] || options[:views].include?("mailer")
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/base"
|
|
4
|
+
|
|
5
|
+
module Fluxbit
|
|
6
|
+
class PagyGenerator < Rails::Generators::Base
|
|
7
|
+
source_root File.expand_path("templates", __dir__)
|
|
8
|
+
desc "Copies fluxbit_pagy.css and imports it in application.css"
|
|
9
|
+
|
|
10
|
+
def copy_css_file
|
|
11
|
+
copy_file "fluxbit_pagy.css", "app/assets/stylesheets/fluxbit_pagy.css"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def import_into_application_css
|
|
15
|
+
import_line = "@import \"./fluxbit_pagy\";"
|
|
16
|
+
tailwind_path = "app/assets/stylesheets/application.tailwind.css"
|
|
17
|
+
default_path = "app/assets/stylesheets/application.css"
|
|
18
|
+
|
|
19
|
+
target_file = if File.exist?(tailwind_path)
|
|
20
|
+
tailwind_path
|
|
21
|
+
elsif File.exist?(default_path)
|
|
22
|
+
default_path
|
|
23
|
+
else
|
|
24
|
+
say_status :error, "No application CSS file found (expected application.tailwind.css or application.css)", :red
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if File.exist?(target_file)
|
|
29
|
+
unless File.read(target_file).include?(import_line)
|
|
30
|
+
append_to_file target_file, "\n#{import_line}\n"
|
|
31
|
+
else
|
|
32
|
+
say_status :skipped, "#{import_line} already present in #{target_file}"
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
say_status :error, "#{target_file} not found", :red
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/named_base"
|
|
3
|
+
|
|
4
|
+
module Fluxbit
|
|
5
|
+
class ScaffoldGenerator < Rails::Generators::NamedBase
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
|
8
|
+
|
|
9
|
+
# Turbo option
|
|
10
|
+
class_option :turbo, type: :boolean, default: true, desc: "Use Turbo Streams for dynamic updates"
|
|
11
|
+
|
|
12
|
+
# Modal/Drawer option
|
|
13
|
+
class_option :ui, type: :string, default: "drawer", enum: [ "modal", "drawer", "none" ], desc: "Choose UI interaction for forms"
|
|
14
|
+
|
|
15
|
+
# Paginator option
|
|
16
|
+
class_option :paginator, type: :boolean, default: true, desc: "Include pagination using Pagy"
|
|
17
|
+
|
|
18
|
+
# Authorization option
|
|
19
|
+
class_option :pundit, type: :boolean, default: true, desc: "Include Pundit for authorization"
|
|
20
|
+
|
|
21
|
+
# Namespace option
|
|
22
|
+
class_option :namespace, type: :string, default: nil, desc: "Namespace for the controller (e.g., 'admin', 'api/v1')"
|
|
23
|
+
|
|
24
|
+
def generate_model_and_migration
|
|
25
|
+
# Use Rails model generator to create model & migration (if not already present)
|
|
26
|
+
model_args = [ name ] + attributes
|
|
27
|
+
generate("model", *model_args)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def generate_scaffold_files
|
|
31
|
+
# Add resource route
|
|
32
|
+
if namespaced?
|
|
33
|
+
# Build nested namespace blocks
|
|
34
|
+
namespace_parts = namespace_path.split("/")
|
|
35
|
+
namespace_opens = namespace_parts.map.with_index do |part, idx|
|
|
36
|
+
" " * idx + "namespace :#{part} do"
|
|
37
|
+
end.join("\n")
|
|
38
|
+
namespace_closes = namespace_parts.size.times.map { |i| " " * (namespace_parts.size - 1 - i) + "end" }.join("\n")
|
|
39
|
+
indent = " " * namespace_parts.size
|
|
40
|
+
|
|
41
|
+
route %(#{namespace_opens}
|
|
42
|
+
#{indent}resources :#{file_name.pluralize} do
|
|
43
|
+
#{indent} collection do
|
|
44
|
+
#{indent} put "update_all"
|
|
45
|
+
#{indent} patch "update_all"
|
|
46
|
+
#{indent} delete "destroy_all"
|
|
47
|
+
#{indent} end
|
|
48
|
+
#{indent}end
|
|
49
|
+
#{namespace_closes})
|
|
50
|
+
else
|
|
51
|
+
route %(resources :#{file_name.pluralize} do
|
|
52
|
+
collection do
|
|
53
|
+
put "update_all"
|
|
54
|
+
patch "update_all"
|
|
55
|
+
delete "destroy_all"
|
|
56
|
+
end
|
|
57
|
+
end)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Ensure controller directory exists
|
|
61
|
+
empty_directory controller_dir if namespaced?
|
|
62
|
+
|
|
63
|
+
# Generate controller from template
|
|
64
|
+
template "controller.rb.tt", File.join(controller_dir, "#{file_name.pluralize}_controller.rb")
|
|
65
|
+
|
|
66
|
+
# Ensure view directory exists
|
|
67
|
+
empty_directory view_dir
|
|
68
|
+
|
|
69
|
+
# Generate view templates from templates
|
|
70
|
+
template "index.html.erb.tt", File.join(view_dir, "index.html.erb")
|
|
71
|
+
template "show.html.erb.tt", File.join(view_dir, "show.html.erb")
|
|
72
|
+
template "new.html.erb.tt", File.join(view_dir, "new.html.erb")
|
|
73
|
+
template "edit.html.erb.tt", File.join(view_dir, "edit.html.erb")
|
|
74
|
+
template "_form.html.erb.tt", File.join(view_dir, "_form.html.erb")
|
|
75
|
+
template "_metadata.html.erb.tt", File.join(view_dir, "_metadata.html.erb")
|
|
76
|
+
template "partial.html.erb.tt", File.join(view_dir, "_#{file_name.pluralize}.html.erb")
|
|
77
|
+
|
|
78
|
+
# Generate Jbuilder templates
|
|
79
|
+
template "index.json.jbuilder.tt", File.join(view_dir, "index.json.jbuilder")
|
|
80
|
+
template "show.json.jbuilder.tt", File.join(view_dir, "show.json.jbuilder")
|
|
81
|
+
|
|
82
|
+
# Generate Turbo Stream response templates
|
|
83
|
+
template "create.turbo_stream.erb.tt", File.join(view_dir, "create.turbo_stream.erb")
|
|
84
|
+
template "update.turbo_stream.erb.tt", File.join(view_dir, "update.turbo_stream.erb")
|
|
85
|
+
template "update_all.turbo_stream.erb.tt", File.join(view_dir, "update_all.turbo_stream.erb")
|
|
86
|
+
template "destroy.turbo_stream.erb.tt", File.join(view_dir, "destroy.turbo_stream.erb")
|
|
87
|
+
template "destroy_all.turbo_stream.erb.tt", File.join(view_dir, "destroy_all.turbo_stream.erb")
|
|
88
|
+
|
|
89
|
+
# Generate i18n
|
|
90
|
+
template "i18n.en.yml.tt", File.join("config", "locales", "#{file_name.pluralize}.en.yml")
|
|
91
|
+
template "i18n.pt-BR.yml.tt", File.join("config", "locales", "#{file_name.pluralize}.pt-BR.yml")
|
|
92
|
+
|
|
93
|
+
# Generate Policy
|
|
94
|
+
template "policy.rb.tt", File.join("app/policies", "#{file_name.singularize}_policy.rb")
|
|
95
|
+
|
|
96
|
+
# Generate shared partials
|
|
97
|
+
template "_alert.html.erb.tt", File.join("app/views/shared", "_alert.html.erb")
|
|
98
|
+
template "send_alert_via_drawer.html.erb.tt", File.join("app/views/shared", "send_alert_via_drawer_alert.html.erb")
|
|
99
|
+
template "_flash.html.erb.tt", File.join("app/views/shared", "_flash.html.erb")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# Returns the namespace path (e.g., "admin" or "api/v1")
|
|
105
|
+
def namespace_path
|
|
106
|
+
options[:namespace]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Returns true if namespace is present
|
|
110
|
+
def namespaced?
|
|
111
|
+
namespace_path.present?
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Returns the namespace as a module (e.g., "Admin" or "Api::V1")
|
|
115
|
+
def namespace_module
|
|
116
|
+
return nil unless namespaced?
|
|
117
|
+
namespace_path.split("/").map(&:camelize).join("::")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Returns the controller directory path (e.g., "app/controllers/admin")
|
|
121
|
+
def controller_dir
|
|
122
|
+
if namespaced?
|
|
123
|
+
File.join("app/controllers", namespace_path)
|
|
124
|
+
else
|
|
125
|
+
"app/controllers"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Returns the view directory path (e.g., "app/views/admin/products")
|
|
130
|
+
def view_dir
|
|
131
|
+
if namespaced?
|
|
132
|
+
File.join("app/views", namespace_path, file_name.pluralize)
|
|
133
|
+
else
|
|
134
|
+
File.join("app/views", file_name.pluralize)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Returns the namespaced class name (e.g., "Admin::ProductsController")
|
|
139
|
+
def namespaced_class_name
|
|
140
|
+
if namespaced?
|
|
141
|
+
"#{namespace_module}::#{class_name}"
|
|
142
|
+
else
|
|
143
|
+
class_name
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Returns the controller file path (e.g., "admin/products_controller.rb")
|
|
148
|
+
def controller_file_path
|
|
149
|
+
if namespaced?
|
|
150
|
+
File.join(namespace_path, "#{file_name.pluralize}_controller.rb")
|
|
151
|
+
else
|
|
152
|
+
"#{file_name.pluralize}_controller.rb"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Returns the path helper prefix (e.g., "admin_" or "api_v1_")
|
|
157
|
+
def path_prefix
|
|
158
|
+
if namespaced?
|
|
159
|
+
namespace_path.split("/").join("_") + "_"
|
|
160
|
+
else
|
|
161
|
+
""
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%%= fx_alert(color: color) { message } %>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<%% mapping = {
|
|
2
|
+
"notice" => :success,
|
|
3
|
+
"success" => :success,
|
|
4
|
+
"error" => :danger,
|
|
5
|
+
"alert" => :warning,
|
|
6
|
+
"warning" => :warning
|
|
7
|
+
} %>
|
|
8
|
+
|
|
9
|
+
<%% flash.each do |type, msg| %>
|
|
10
|
+
<%% next if msg.blank? %>
|
|
11
|
+
<%% color = mapping[type.to_s] || :info %>
|
|
12
|
+
<%%= fx_alert(color: color) do %>
|
|
13
|
+
<%%= safe_join(Array(msg).map { |m| sanitize(m.to_s, tags: [], attributes: []) }, tag.br) %>
|
|
14
|
+
<%% end %>
|
|
15
|
+
<%% end %>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<% singular = file_name.singularize; plural = file_name.pluralize -%>
|
|
2
|
+
<%%= form_with(model: @<%= singular %>, <% if namespaced? %>url: @<%= singular %>.persisted? ? <%= path_prefix %><%= singular %>_path(@<%= singular %>) : <%= path_prefix %><%= plural %>_path, <% end %>id: "<%= singular %>_form", builder: Fluxbit::FormBuilder, format: turbo_frame_request? ? :turbo_stream : :html) do |form| %>
|
|
3
|
+
<%% if @<%= singular %>.errors.any? %>
|
|
4
|
+
<div class="mb-4">
|
|
5
|
+
<%%= fx_alert(color: :danger) { t("<%= plural %>.messages.errors_message", count: @<%= singular %>.errors.count) } %>
|
|
6
|
+
<ul class="text-sm text-red-600 pl-5 list-disc">
|
|
7
|
+
<%% @<%= singular %>.errors.full_messages.each do |msg| %>
|
|
8
|
+
<li><%%= msg %></li>
|
|
9
|
+
<%% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
12
|
+
<%% end %>
|
|
13
|
+
|
|
14
|
+
<% attributes.each do |att|
|
|
15
|
+
name, type = att.name, att.type.to_s
|
|
16
|
+
next if type == 'password_digest' # handle password fields separately
|
|
17
|
+
-%>
|
|
18
|
+
<% if ['references','belongs_to'].include?(type) -%>
|
|
19
|
+
<%%= form.fx_select :<%= "#{name}_id" %>, <%= name.camelize %>.all.pluck(:name, :id), { prompt: t("<%= plural %>.prompts.<%= name %>") }, {wrapper_html: {class: "mb-4"} } %>
|
|
20
|
+
<% elsif type == 'boolean' -%>
|
|
21
|
+
<%%= form.fx_toggle :<%= name %>, wrapper_html: {class: "mb-4"} %>
|
|
22
|
+
<% elsif type == 'password' -%>
|
|
23
|
+
<%%= form.fx_password_field :<%= name %>, wrapper_html: {class: "mb-4"} %>
|
|
24
|
+
<% elsif type == 'text' -%>
|
|
25
|
+
<%%= form.fx_text_area :<%= name %>, rows: 5, wrapper_html: {class: "mb-4"} %>
|
|
26
|
+
<% elsif type == 'attachment' || type == 'attachments' -%>
|
|
27
|
+
<%%= form.fx_dropzone :<%= name %>, wrapper_html: {class: "mb-4"}, <%= 'multiple: true' if type == 'attachments' %>%>
|
|
28
|
+
<% else -%>
|
|
29
|
+
<%%= form.fx_text_field :<%= name %>, wrapper_html: {class: "mb-4"} %>
|
|
30
|
+
<% end -%>
|
|
31
|
+
<% end -%>
|
|
32
|
+
<% if attributes.any? { |a| a.type == :password_digest } -%>
|
|
33
|
+
<%%= form.fx_password_field :password, wrapper_html: {class: "mb-4"} %>
|
|
34
|
+
<%%= form.fx_password_field :password_confirmation, wrapper_html: {class: "mb-4"} %>
|
|
35
|
+
<% end -%>
|
|
36
|
+
<%%= form.fx_submit value: t(@<%= singular %>.persisted? ? "<%= plural %>.actions.update" : "<%= plural %>.actions.save"), data: { turbo_submits_with: t("<%= plural %>.helpers.submits_with") }, class: "mt-4" %>
|
|
37
|
+
<%%= render "metadata", <%= singular %>: @<%= singular %> %>
|
|
38
|
+
<%% end %>
|