neo_components 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/app/assets/icons/academy.svg +3 -0
- data/app/assets/icons/adjustments-horizontal.svg +3 -0
- data/app/assets/icons/adjustments-vertical.svg +3 -0
- data/app/assets/icons/arrow-down-tray.svg +3 -0
- data/app/assets/icons/arrow-left.svg +3 -0
- data/app/assets/icons/arrow-long-down.svg +3 -0
- data/app/assets/icons/arrow-long-right.svg +3 -0
- data/app/assets/icons/arrow-long-up.svg +3 -0
- data/app/assets/icons/arrow-right.svg +3 -0
- data/app/assets/icons/arrow-up-tray.svg +3 -0
- data/app/assets/icons/arrow-uturn-left.svg +3 -0
- data/app/assets/icons/arrow-uturn-right.svg +3 -0
- data/app/assets/icons/assign-user.svg +13 -0
- data/app/assets/icons/at-symbol.svg +3 -0
- data/app/assets/icons/bars-4.svg +3 -0
- data/app/assets/icons/bell.svg +3 -0
- data/app/assets/icons/book.svg +3 -0
- data/app/assets/icons/bookmark.svg +3 -0
- data/app/assets/icons/building-office-2.svg +3 -0
- data/app/assets/icons/calendar.svg +3 -0
- data/app/assets/icons/celebration.svg +15 -0
- data/app/assets/icons/check-badge-solid.svg +3 -0
- data/app/assets/icons/check-circle-solid.svg +3 -0
- data/app/assets/icons/check-circle.svg +3 -0
- data/app/assets/icons/check-list.svg +12 -0
- data/app/assets/icons/check.svg +3 -0
- data/app/assets/icons/chevron-double-right.svg +3 -0
- data/app/assets/icons/chevron-down.svg +3 -0
- data/app/assets/icons/chevron-left.svg +3 -0
- data/app/assets/icons/chevron-right.svg +3 -0
- data/app/assets/icons/chevron-up.svg +3 -0
- data/app/assets/icons/circle-stack.svg +3 -0
- data/app/assets/icons/clipboard-document-check-solid.svg +4 -0
- data/app/assets/icons/clipboard-document-check.svg +3 -0
- data/app/assets/icons/clock.svg +3 -0
- data/app/assets/icons/complete.svg +3 -0
- data/app/assets/icons/course.svg +3 -0
- data/app/assets/icons/device-phone-mobile.svg +3 -0
- data/app/assets/icons/document-arrow-up.svg +4 -0
- data/app/assets/icons/document-text.svg +4 -0
- data/app/assets/icons/ellipsis-vertical.svg +3 -0
- data/app/assets/icons/exclaimation-circle-solid.svg +3 -0
- data/app/assets/icons/eye.svg +4 -0
- data/app/assets/icons/flag.svg +3 -0
- data/app/assets/icons/funnel.svg +3 -0
- data/app/assets/icons/green-circle.svg +3 -0
- data/app/assets/icons/green-tick.svg +3 -0
- data/app/assets/icons/grid.svg +6 -0
- data/app/assets/icons/home.svg +3 -0
- data/app/assets/icons/i-vector.svg +3 -0
- data/app/assets/icons/lessons.svg +11 -0
- data/app/assets/icons/magnifying-glass.svg +3 -0
- data/app/assets/icons/minus.svg +3 -0
- data/app/assets/icons/numbered-list.svg +3 -0
- data/app/assets/icons/pencil.svg +3 -0
- data/app/assets/icons/play.svg +3 -0
- data/app/assets/icons/plus.svg +3 -0
- data/app/assets/icons/power.svg +3 -0
- data/app/assets/icons/question-mark-circle.svg +3 -0
- data/app/assets/icons/quiz-score.svg +15 -0
- data/app/assets/icons/re-invite.svg +3 -0
- data/app/assets/icons/red-circle.svg +3 -0
- data/app/assets/icons/share.svg +3 -0
- data/app/assets/icons/smiley-five.svg +5 -0
- data/app/assets/icons/smiley-four.svg +5 -0
- data/app/assets/icons/smiley-one.svg +5 -0
- data/app/assets/icons/smiley-three.svg +5 -0
- data/app/assets/icons/smiley-two.svg +5 -0
- data/app/assets/icons/sparkle.svg +3 -0
- data/app/assets/icons/star-transparent.svg +3 -0
- data/app/assets/icons/stop.svg +4 -0
- data/app/assets/icons/support-placeholder.svg +4 -0
- data/app/assets/icons/tag.svg +4 -0
- data/app/assets/icons/timer.svg +5 -0
- data/app/assets/icons/transcript.svg +31 -0
- data/app/assets/icons/trash.svg +3 -0
- data/app/assets/icons/upload-info.svg +7 -0
- data/app/assets/icons/user-circle.svg +3 -0
- data/app/assets/icons/user-group.svg +3 -0
- data/app/assets/icons/user.svg +3 -0
- data/app/assets/icons/users.svg +3 -0
- data/app/assets/icons/winner.svg +35 -0
- data/app/assets/icons/x-circle-solid.svg +3 -0
- data/app/assets/icons/x-circle.svg +3 -0
- data/app/assets/icons/x-mark.svg +3 -0
- data/app/assets/stylesheets/breadcrumbs.tailwind.css +45 -0
- data/app/assets/stylesheets/buttons.tailwind.css +98 -0
- data/app/assets/stylesheets/course_progress.css +75 -0
- data/app/assets/stylesheets/custom.css +67 -0
- data/app/assets/stylesheets/date_picker.tailwind.css +7 -0
- data/app/assets/stylesheets/directives.tailwind.css +3 -0
- data/app/assets/stylesheets/dropdown.tailwind.css +11 -0
- data/app/assets/stylesheets/file_selector.tailwind.css +47 -0
- data/app/assets/stylesheets/icons.css.erb +244 -0
- data/app/assets/stylesheets/inputs.tailwind.css +53 -0
- data/app/assets/stylesheets/menu_component.tailwind.css +39 -0
- data/app/assets/stylesheets/mobile_inputs.tailwind.css +11 -0
- data/app/assets/stylesheets/modalbox.tailwind.css +35 -0
- data/app/assets/stylesheets/profile_icon.tailwind.css +15 -0
- data/app/assets/stylesheets/textarea.tailwind.css +43 -0
- data/app/assets/stylesheets/tooltip.css +88 -0
- data/app/assets/stylesheets/typography.tailwind.css +70 -0
- data/app/helpers/ui_helper.rb +31 -0
- data/app/helpers/view_component/accordion_component.rb +12 -0
- data/app/helpers/view_component/breadcrumbs_component.rb +30 -0
- data/app/helpers/view_component/button_component.rb +180 -0
- data/app/helpers/view_component/chip_component.rb +54 -0
- data/app/helpers/view_component/component_helper.rb +21 -0
- data/app/helpers/view_component/course_card_component.rb +9 -0
- data/app/helpers/view_component/course_carousal_component.rb +14 -0
- data/app/helpers/view_component/course_select_component.rb +32 -0
- data/app/helpers/view_component/doc_section_component.rb +10 -0
- data/app/helpers/view_component/icon_component.rb +24 -0
- data/app/helpers/view_component/input_component/date_picker_component.rb +127 -0
- data/app/helpers/view_component/input_component/dropdown_component.rb +99 -0
- data/app/helpers/view_component/input_component/file_selector_component.rb +123 -0
- data/app/helpers/view_component/input_component/input_checkbox_component.rb +54 -0
- data/app/helpers/view_component/input_component/input_mobile_component.rb +68 -0
- data/app/helpers/view_component/input_component/input_radio_component.rb +54 -0
- data/app/helpers/view_component/input_component/input_text_component.rb +137 -0
- data/app/helpers/view_component/input_component/textarea_component.rb +101 -0
- data/app/helpers/view_component/input_component.rb +290 -0
- data/app/helpers/view_component/input_textarea_component.rb +28 -0
- data/app/helpers/view_component/long_course_card_component.rb +10 -0
- data/app/helpers/view_component/member_list_component.rb +17 -0
- data/app/helpers/view_component/menu_component.rb +31 -0
- data/app/helpers/view_component/menu_component_helper.rb +22 -0
- data/app/helpers/view_component/menu_item.rb +12 -0
- data/app/helpers/view_component/modal_box_component.rb +29 -0
- data/app/helpers/view_component/modal_component.rb +12 -0
- data/app/helpers/view_component/notification_bar_component.rb +22 -0
- data/app/helpers/view_component/paginator_component.rb +9 -0
- data/app/helpers/view_component/profile_icon_component.rb +46 -0
- data/app/helpers/view_component/progress_component.rb +12 -0
- data/app/helpers/view_component/table_component.rb +22 -0
- data/app/helpers/view_component/typography_component.rb +83 -0
- data/app/javascript/neo_components/controllers/collapsible_controller.js +37 -0
- data/app/javascript/neo_components/controllers/date_picker_controller.js +17 -0
- data/app/javascript/neo_components/controllers/file_selector_controller.js +145 -0
- data/app/javascript/neo_components/controllers/input_mobile_controller.js +7 -0
- data/app/javascript/neo_components/controllers/menu_component_controller.js +26 -0
- data/app/javascript/neo_components/controllers/modal_loader_controller.js +13 -0
- data/app/javascript/neo_components/controllers/modals_controller.js +26 -0
- data/app/javascript/neo_components/controllers/notification_bar_controller.js +9 -0
- data/app/javascript/neo_components/controllers/pagination_controller.js +11 -0
- data/app/javascript/neo_components/controllers/tab_change_controller.js +23 -0
- data/app/javascript/neo_components/controllers/tabs_controller.js +29 -0
- data/app/javascript/neo_components/controllers/text_clamp_controller.js +29 -0
- data/app/views/shared/components/_progress_bar_short.html.erb +8 -0
- data/app/views/shared/components/_tooltip.html.erb +7 -0
- data/app/views/view_components/accordion_component/_accordion.html.erb +22 -0
- data/app/views/view_components/breadcrumbs_component/_breadcrumbs.html.erb +38 -0
- data/app/views/view_components/button_component/_button.html.erb +13 -0
- data/app/views/view_components/buttons/_danger.html.erb +30 -0
- data/app/views/view_components/buttons/_primary.html.erb +31 -0
- data/app/views/view_components/buttons/_secondary.html.erb +29 -0
- data/app/views/view_components/chip_component/_chip_component.html.erb +9 -0
- data/app/views/view_components/course_carousal/_course_card_component.html.erb +65 -0
- data/app/views/view_components/course_carousal/_course_carousal_body_component.html.erb +25 -0
- data/app/views/view_components/course_carousal/_course_carousal_component.html.erb +8 -0
- data/app/views/view_components/course_carousal/_long_course_card_component.html.erb +70 -0
- data/app/views/view_components/course_select/_course_select_component.html.erb +19 -0
- data/app/views/view_components/course_select/_list_component.html.erb +14 -0
- data/app/views/view_components/course_select/_list_item_component.html.erb +86 -0
- data/app/views/view_components/course_select/_load_more.html.erb +17 -0
- data/app/views/view_components/course_select/_search_component.html.erb +48 -0
- data/app/views/view_components/course_select/_sidebar_component.html.erb +41 -0
- data/app/views/view_components/doc_section/_doc_section_component.html.erb +6 -0
- data/app/views/view_components/inputs/_checkbox_field.html.erb +19 -0
- data/app/views/view_components/inputs/_date_select_component.html.erb +37 -0
- data/app/views/view_components/inputs/_dropdown_field.html.erb +22 -0
- data/app/views/view_components/inputs/_file_selector.html.erb +16 -0
- data/app/views/view_components/inputs/_input_checkbox_component.html.erb +7 -0
- data/app/views/view_components/inputs/_input_mobile_component.html.erb +16 -0
- data/app/views/view_components/inputs/_input_radio_component.html.erb +7 -0
- data/app/views/view_components/inputs/_input_text_component.html.erb +16 -0
- data/app/views/view_components/inputs/_mobile_field.html.erb +31 -0
- data/app/views/view_components/inputs/_radio_field.html.erb +25 -0
- data/app/views/view_components/inputs/_text_field.html.erb +52 -0
- data/app/views/view_components/inputs/_textarea.html.erb +26 -0
- data/app/views/view_components/inputs/date_picker_component/_date_picker.html.erb +16 -0
- data/app/views/view_components/inputs/date_picker_component/_input_box.html.erb +34 -0
- data/app/views/view_components/inputs/dropdown_component/_dropdown.html.erb +16 -0
- data/app/views/view_components/inputs/dropdown_component/_select_box.html.erb +10 -0
- data/app/views/view_components/inputs/file_selector_component/_file_selector_box.html.erb +76 -0
- data/app/views/view_components/inputs/input_checkbox/_checkbox.html.erb +20 -0
- data/app/views/view_components/inputs/input_mobile/_code.html.erb +13 -0
- data/app/views/view_components/inputs/input_mobile/_mobile_box.html.erb +4 -0
- data/app/views/view_components/inputs/input_mobile/_number.html.erb +13 -0
- data/app/views/view_components/inputs/input_radio/_radio_button.html.erb +14 -0
- data/app/views/view_components/inputs/input_text/_text_box.html.erb +33 -0
- data/app/views/view_components/inputs/textarea_component/_text_area_box.html.erb +16 -0
- data/app/views/view_components/inputs/textarea_component/_textarea.html.erb +16 -0
- data/app/views/view_components/member_list/_member_list.html.erb +4 -0
- data/app/views/view_components/member_list/_member_search.html.erb +15 -0
- data/app/views/view_components/member_list/_members.html.erb +65 -0
- data/app/views/view_components/menu_component/_menu_component.html.erb +16 -0
- data/app/views/view_components/menu_component/_menu_item_button.html.erb +17 -0
- data/app/views/view_components/menu_component/_menu_item_link.html.erb +5 -0
- data/app/views/view_components/menu_component_old/_menu_component.html.erb +17 -0
- data/app/views/view_components/menu_component_old/_menu_item_button.html.erb +7 -0
- data/app/views/view_components/menu_component_old/_menu_item_link.html.erb +5 -0
- data/app/views/view_components/modal_component/_modal_box_component.html.erb +28 -0
- data/app/views/view_components/modals/_modal_component.html.erb +25 -0
- data/app/views/view_components/notification_bar/_notification_bar.html.erb +17 -0
- data/app/views/view_components/paginator/_next_page.html.erb +7 -0
- data/app/views/view_components/paginator/_paginator_component.html.erb +6 -0
- data/app/views/view_components/paginator/_prev_page.html.erb +7 -0
- data/app/views/view_components/profile_icon_component/_profile_icon.html.erb +3 -0
- data/app/views/view_components/progress_component/_progressbar.html.erb +5 -0
- data/app/views/view_components/typography/_h1_component.html.erb +1 -0
- data/app/views/view_components/typography/_h2_component.html.erb +1 -0
- data/app/views/view_components/typography/_h3_component.html.erb +1 -0
- data/app/views/view_components/typography/_heading_component.html.erb +3 -0
- data/app/views/view_components/typography/_link_component.html.erb +1 -0
- data/app/views/view_components/typography/_linked_text_component.html.erb +3 -0
- data/app/views/view_components/typography/_text_component.html.erb +1 -0
- data/config/importmap.rb +5 -0
- data/lib/neo_components/engine.rb +38 -0
- data/lib/neo_components/version.rb +5 -0
- data/lib/neo_components.rb +4 -0
- metadata +327 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module ButtonComponent
|
|
5
|
+
class ButtonComponent
|
|
6
|
+
BUTTON_TYPES = %w[solid outline].freeze
|
|
7
|
+
BUTTON_SIZES = %w[sm md lg].freeze
|
|
8
|
+
COLOR_SCHEMES = %w[primary secondary danger].freeze
|
|
9
|
+
ICON_POSITIONS = %w[left right].freeze
|
|
10
|
+
TOOLTIP_POSITIONS = %w[top left bottom right].freeze
|
|
11
|
+
DISABLED_CLASS = %w[opacity-50 cursor-not-allowed].freeze
|
|
12
|
+
|
|
13
|
+
BUTTON_SIZE_MAPPING = {
|
|
14
|
+
sm: 'btn-sm',
|
|
15
|
+
md: 'btn-md',
|
|
16
|
+
lg: 'btn-lg'
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
BUTTON_COLOUR_SCHEME_MAPPING = {
|
|
20
|
+
solid: {
|
|
21
|
+
primary: 'btn-solid-primary',
|
|
22
|
+
secondary: 'btn-solid-secondary',
|
|
23
|
+
danger: 'btn-solid-danger'
|
|
24
|
+
},
|
|
25
|
+
outline: {
|
|
26
|
+
primary: 'btn-outline-primary',
|
|
27
|
+
secondary: 'btn-outline-secondary',
|
|
28
|
+
danger: 'btn-outline-danger'
|
|
29
|
+
}
|
|
30
|
+
}.freeze
|
|
31
|
+
|
|
32
|
+
BUTTON_DISABLED_MAPPING = {
|
|
33
|
+
solid: {
|
|
34
|
+
primary: 'btn-solid-primary-disabled',
|
|
35
|
+
secondary: 'btn-solid-secondary-disabled',
|
|
36
|
+
danger: 'btn-solid-danger-disabled'
|
|
37
|
+
},
|
|
38
|
+
outline: {
|
|
39
|
+
primary: 'btn-outline-primary-disabled',
|
|
40
|
+
secondary: 'btn-outline-secondary-disabled',
|
|
41
|
+
danger: 'btn-outline-danger-disabled'
|
|
42
|
+
}
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
ICON_STYLES_MAPPING = {
|
|
46
|
+
sm: 'btn-icon-sm',
|
|
47
|
+
md: 'btn-icon-md',
|
|
48
|
+
lg: 'btn-icon-lg'
|
|
49
|
+
}.freeze
|
|
50
|
+
|
|
51
|
+
BUTTON_TEXT_STYLE_MAPPING = {
|
|
52
|
+
sm: 'btn-text-sm',
|
|
53
|
+
md: 'btn-text-md',
|
|
54
|
+
lg: 'btn-text-lg'
|
|
55
|
+
}.freeze
|
|
56
|
+
|
|
57
|
+
attr_accessor :text, :type, :colorscheme, :size, :icon_name, :icon_position, :tooltip_text, :tooltip_position,
|
|
58
|
+
:disabled, :hide_label_in_mobile, :html_options, :color_mapping
|
|
59
|
+
|
|
60
|
+
def initialize(text:, type:, colorscheme:, size:, icon_name:, icon_position:, tooltip_text:, tooltip_position:,
|
|
61
|
+
disabled:, hide_label_in_mobile:, html_options:)
|
|
62
|
+
self.text = text
|
|
63
|
+
self.type = type
|
|
64
|
+
self.size = size
|
|
65
|
+
self.colorscheme = colorscheme
|
|
66
|
+
self.icon_name = icon_name
|
|
67
|
+
self.icon_position = icon_position
|
|
68
|
+
self.tooltip_text = tooltip_text
|
|
69
|
+
self.tooltip_position = tooltip_position
|
|
70
|
+
self.disabled = disabled
|
|
71
|
+
self.hide_label_in_mobile = hide_label_in_mobile
|
|
72
|
+
self.html_options = html_options
|
|
73
|
+
# validation
|
|
74
|
+
raise "Incorrect button type: #{type}" unless BUTTON_TYPES.include? type
|
|
75
|
+
raise "Incorrect button size: #{size}" unless BUTTON_SIZES.include? size
|
|
76
|
+
raise "Incorrect color scheme: #{colorscheme}" unless COLOR_SCHEMES.include? colorscheme
|
|
77
|
+
raise "Incorrect icon_position: #{icon_position}" unless ICON_POSITIONS.include? icon_position
|
|
78
|
+
raise "Incorrect tooltip_position: #{tooltip_position}" unless TOOLTIP_POSITIONS.include? tooltip_position
|
|
79
|
+
|
|
80
|
+
self.color_mapping = color_scheme_mapping
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def base_styles
|
|
84
|
+
styles = ['btn-base']
|
|
85
|
+
styles.append('btn-disabled') if disabled
|
|
86
|
+
styles.join(' ')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def color_styles
|
|
90
|
+
color_mapping
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def sizing_styles
|
|
94
|
+
BUTTON_SIZE_MAPPING[size.to_sym]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def text_styles
|
|
98
|
+
size_styles = BUTTON_TEXT_STYLE_MAPPING[size.to_sym]
|
|
99
|
+
styles = ['btn-text-base']
|
|
100
|
+
styles.append('hidden md:flex') if hide_label_in_mobile
|
|
101
|
+
styles.append(size_styles)
|
|
102
|
+
styles.join(' ')
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def icon_styles
|
|
106
|
+
ICON_STYLES_MAPPING[size.to_sym]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def color_scheme_mapping
|
|
112
|
+
if disabled
|
|
113
|
+
['btn-disabled', BUTTON_DISABLED_MAPPING[type.to_sym][colorscheme.to_sym]]
|
|
114
|
+
else
|
|
115
|
+
BUTTON_COLOUR_SCHEME_MAPPING[type.to_sym][colorscheme.to_sym]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def button(
|
|
121
|
+
label: nil,
|
|
122
|
+
type: 'primary',
|
|
123
|
+
size: 'md',
|
|
124
|
+
icon_name: nil,
|
|
125
|
+
icon_position: 'left',
|
|
126
|
+
tooltip_text: '',
|
|
127
|
+
tooltip_position: 'bottom',
|
|
128
|
+
disabled: false,
|
|
129
|
+
html_options: {}
|
|
130
|
+
)
|
|
131
|
+
render(
|
|
132
|
+
partial: "view_components/buttons/#{type}",
|
|
133
|
+
locals: {
|
|
134
|
+
label:,
|
|
135
|
+
type:,
|
|
136
|
+
size:,
|
|
137
|
+
icon_name:,
|
|
138
|
+
icon_position:,
|
|
139
|
+
tooltip_text:,
|
|
140
|
+
tooltip_position:,
|
|
141
|
+
disabled:,
|
|
142
|
+
html_options:
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def button_component(
|
|
148
|
+
text: '',
|
|
149
|
+
type: 'solid',
|
|
150
|
+
size: 'md',
|
|
151
|
+
colorscheme: 'primary',
|
|
152
|
+
icon_name: '',
|
|
153
|
+
icon_position: 'left',
|
|
154
|
+
tooltip_text: '',
|
|
155
|
+
tooltip_position: 'bottom',
|
|
156
|
+
disabled: false,
|
|
157
|
+
hide_label_in_mobile: false,
|
|
158
|
+
html_options: {}
|
|
159
|
+
)
|
|
160
|
+
button = ButtonComponent.new(
|
|
161
|
+
text:,
|
|
162
|
+
type:,
|
|
163
|
+
size:,
|
|
164
|
+
colorscheme:,
|
|
165
|
+
icon_name:,
|
|
166
|
+
icon_position:,
|
|
167
|
+
tooltip_text:,
|
|
168
|
+
tooltip_position:,
|
|
169
|
+
disabled:,
|
|
170
|
+
hide_label_in_mobile:,
|
|
171
|
+
html_options:
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
render(
|
|
175
|
+
partial: 'view_components/button_component/button',
|
|
176
|
+
locals: { button: }
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module ChipComponent
|
|
5
|
+
COLOR_SCHEMES = {
|
|
6
|
+
'primary' => %w[
|
|
7
|
+
bg-primary-light-100
|
|
8
|
+
text-primary-dark
|
|
9
|
+
text-primary
|
|
10
|
+
text-primary
|
|
11
|
+
border-0
|
|
12
|
+
],
|
|
13
|
+
'primary_lite' => %w[
|
|
14
|
+
bg-primary-light-50
|
|
15
|
+
text-primary-dark
|
|
16
|
+
text-primary
|
|
17
|
+
text-primary
|
|
18
|
+
border-0
|
|
19
|
+
],
|
|
20
|
+
'danger' => %w[
|
|
21
|
+
bg-danger-light
|
|
22
|
+
text-primary-dark
|
|
23
|
+
text-danger-dark
|
|
24
|
+
text-danger-dark
|
|
25
|
+
border-0
|
|
26
|
+
],
|
|
27
|
+
'input' => %w[
|
|
28
|
+
bg-primary-light-50
|
|
29
|
+
text-primary-dark
|
|
30
|
+
text-primary
|
|
31
|
+
text-primary
|
|
32
|
+
border-slate-grey-light
|
|
33
|
+
]
|
|
34
|
+
}.freeze
|
|
35
|
+
|
|
36
|
+
def chip_component(text: '', icon_name: nil, close: false, colorscheme: 'primary')
|
|
37
|
+
styles = COLOR_SCHEMES[colorscheme]
|
|
38
|
+
raise "Incorrect color scheme #{colorscheme}" unless styles
|
|
39
|
+
|
|
40
|
+
bg_style, text_style, icon_style, close_style, border_style = styles
|
|
41
|
+
|
|
42
|
+
render partial: 'view_components/chip_component/chip_component', locals: {
|
|
43
|
+
text:,
|
|
44
|
+
icon_name:,
|
|
45
|
+
close:,
|
|
46
|
+
bg_style:,
|
|
47
|
+
text_style:,
|
|
48
|
+
icon_style:,
|
|
49
|
+
close_style:,
|
|
50
|
+
border_style:
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
# To be used only within a component class such as ButtonComponent
|
|
5
|
+
module ComponentHelper
|
|
6
|
+
def class_list(base, *styles)
|
|
7
|
+
base.concat(styles.compact)
|
|
8
|
+
base.join(' ')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def resolve_error(form, name, explicit_error)
|
|
12
|
+
return explicit_error if explicit_error.present?
|
|
13
|
+
return if form.blank? || form.object.blank? || name.blank?
|
|
14
|
+
|
|
15
|
+
attribute = name.to_s.split('[').last.delete(']').humanize
|
|
16
|
+
message = form.object.errors[name].first
|
|
17
|
+
|
|
18
|
+
message.present? ? "#{attribute} #{message}" : nil
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module CourseCarousalComponent
|
|
5
|
+
def course_carousal_component(courses:, title:, count:, load_path:)
|
|
6
|
+
render partial: 'view_components/course_carousal/course_carousal_component',
|
|
7
|
+
locals: { courses:, title:, count:, load_path: }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def course_carousal_body_component(courses:)
|
|
11
|
+
render partial: 'view_components/course_carousal/course_carousal_body_component', locals: { courses: }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module CourseSelectComponent
|
|
5
|
+
def course_select_component(search_context:, submit_path:, courses: [], tags: [], cancel_link: nil,
|
|
6
|
+
show_duration: false)
|
|
7
|
+
render partial: 'view_components/course_select/course_select_component',
|
|
8
|
+
locals: { search_context:, courses:, tags:, cancel_link:, show_duration:, submit_path: }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def _course_select_search_component(search_context:, tags:)
|
|
12
|
+
render partial: 'view_components/course_select/search_component', locals: { search_context:, tags: }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def _course_select_sidebar_component(form:, tags:)
|
|
16
|
+
render partial: 'view_components/course_select/sidebar_component', locals: { form:, tags: }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def _course_select_list_component(search_context:, courses:)
|
|
20
|
+
render partial: 'view_components/course_select/list_component',
|
|
21
|
+
locals: { search_context:, courses: }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def _course_select_list_item_component(course:)
|
|
25
|
+
render partial: 'view_components/course_select/list_item_component', locals: { course: }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def _course_select_load_more(search_context:, courses:)
|
|
29
|
+
render partial: 'view_components/course_select/load_more', locals: { search_context:, courses: }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module DocSectionComponent
|
|
5
|
+
def doc_section_component(title: '', &)
|
|
6
|
+
block_content = capture(&) if block_given?
|
|
7
|
+
render partial: 'view_components/doc_section/doc_section_component', locals: { title:, block: block_content }
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module IconComponent
|
|
5
|
+
ICONS_PATH = NeoComponents::Engine.gem_root.join("app", "assets", "icons")
|
|
6
|
+
|
|
7
|
+
def icon(icon_name, css: nil, span_css: nil, stroke_width: nil)
|
|
8
|
+
file = Rails.cache.fetch("neo_components:icon:#{icon_name}") do
|
|
9
|
+
ICONS_PATH.join("#{icon_name}.svg").read
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
svg = Nokogiri::HTML::DocumentFragment.parse(file).at_css('svg')
|
|
13
|
+
svg['class'] = css
|
|
14
|
+
if stroke_width.present?
|
|
15
|
+
# Use the stroke_width passed from helper
|
|
16
|
+
svg['stroke-width'] = stroke_width
|
|
17
|
+
elsif svg['stroke-width'].blank?
|
|
18
|
+
# Use default only if SVG does not have stroke-width
|
|
19
|
+
svg['stroke-width'] = '1.5'
|
|
20
|
+
end
|
|
21
|
+
content_tag(:span, svg.to_html.html_safe, class: "flex justify-center items-center #{span_css}".strip) # rubocop:disable Rails/OutputSafety
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module InputComponent
|
|
5
|
+
class DatePickerComponent
|
|
6
|
+
include ViewComponent::ComponentHelper
|
|
7
|
+
|
|
8
|
+
DATE_PICKER_SIZES = %w[md lg].freeze
|
|
9
|
+
|
|
10
|
+
DATE_PICKER_SIZE_STYLE = {
|
|
11
|
+
md: 'input-text-div-base-md main-text-md-normal',
|
|
12
|
+
lg: 'input-text-div-base-lg main-text-lg-medium'
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
LABEL_STYLES = {
|
|
16
|
+
md: 'input-text-label-md general-text-sm-normal',
|
|
17
|
+
lg: 'input-text-label-lg general-text-md-normal'
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
SUPPORT_TEXT_STYLES = {
|
|
21
|
+
md: 'input-text-subtext-md general-text-sm-normal',
|
|
22
|
+
lg: 'input-text-subtext-lg general-text-md-normal'
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
ICON_SIZE = {
|
|
26
|
+
md: 'input-text-icon-md',
|
|
27
|
+
lg: 'input-text-icon-lg'
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
attr_accessor :form, :name, :label, :value, :placeholder, :size,
|
|
31
|
+
:support_text, :error, :disabled, :html_options
|
|
32
|
+
|
|
33
|
+
def initialize(form:, name:, label:, value:, placeholder:, size:, support_text:, error:, disabled:, html_options:)
|
|
34
|
+
raise "Incorrect date picker size: #{size}" unless DATE_PICKER_SIZES.include?(size)
|
|
35
|
+
|
|
36
|
+
error_message = resolve_error(form, name, error)
|
|
37
|
+
|
|
38
|
+
self.form = form
|
|
39
|
+
self.name = name
|
|
40
|
+
self.label = label
|
|
41
|
+
self.value = value
|
|
42
|
+
self.placeholder = placeholder
|
|
43
|
+
self.size = size
|
|
44
|
+
self.support_text = (error_message.presence || support_text)
|
|
45
|
+
self.error = error_message
|
|
46
|
+
self.disabled = disabled
|
|
47
|
+
self.html_options = html_options
|
|
48
|
+
|
|
49
|
+
self.html_options[:disabled] = true if disabled
|
|
50
|
+
self.html_options[:class] = date_picker_style
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def date_picker_style
|
|
54
|
+
base = ['w-full border']
|
|
55
|
+
size_style = DATE_PICKER_SIZE_STYLE[size.to_sym]
|
|
56
|
+
|
|
57
|
+
color_style =
|
|
58
|
+
if disabled
|
|
59
|
+
'border-disabled-color text-disabled-color placeholder-disabled-color'
|
|
60
|
+
elsif error.present?
|
|
61
|
+
'text-danger focus:text-danger-dark border-danger focus:border-danger focus:ring-danger'
|
|
62
|
+
else
|
|
63
|
+
'text-letter-color-light border-slate-grey-50 focus:ring-primary'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
class_list(base, size_style, color_style)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def label_style
|
|
70
|
+
size_style = LABEL_STYLES[size.to_sym]
|
|
71
|
+
|
|
72
|
+
color_style =
|
|
73
|
+
if disabled
|
|
74
|
+
'text-disabled-color'
|
|
75
|
+
elsif error.present?
|
|
76
|
+
'text-danger-dark'
|
|
77
|
+
else
|
|
78
|
+
'text-letter-color-light group-focus-within:text-primary'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class_list([], size_style, color_style)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def support_text_style
|
|
85
|
+
size_style = SUPPORT_TEXT_STYLES[size.to_sym]
|
|
86
|
+
|
|
87
|
+
color_style =
|
|
88
|
+
if disabled
|
|
89
|
+
'text-disabled-color'
|
|
90
|
+
elsif error.present?
|
|
91
|
+
'text-danger-dark'
|
|
92
|
+
else
|
|
93
|
+
'text-letter-color-light'
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class_list([], size_style, color_style)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def icon_wrapper_style
|
|
100
|
+
base = ['date-picker-icon-wrapper']
|
|
101
|
+
|
|
102
|
+
disabled_style =
|
|
103
|
+
if disabled
|
|
104
|
+
'date-picker-icon-wrapper-disabled'
|
|
105
|
+
else
|
|
106
|
+
''
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class_list(base, disabled_style)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def icon_style
|
|
113
|
+
size_style = ICON_SIZE[size.to_sym]
|
|
114
|
+
|
|
115
|
+
color_style =
|
|
116
|
+
if disabled
|
|
117
|
+
'text-disabled-color'
|
|
118
|
+
elsif error.present?
|
|
119
|
+
'text-danger'
|
|
120
|
+
else
|
|
121
|
+
'text-letter-color-light hover:text-primary'
|
|
122
|
+
end
|
|
123
|
+
class_list([], size_style, color_style)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module InputComponent
|
|
5
|
+
class DropdownComponent
|
|
6
|
+
include ViewComponent::ComponentHelper
|
|
7
|
+
|
|
8
|
+
DROPDOWN_SIZES = %w[md lg].freeze
|
|
9
|
+
|
|
10
|
+
DROPDOWN_SIZE_STYLE = {
|
|
11
|
+
md: 'dropdown-component-md main-text-md-normal',
|
|
12
|
+
lg: 'dropdown-component-lg main-text-lg-medium'
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
LABEL_STYLES = {
|
|
16
|
+
md: 'input-text-label-md general-text-sm-normal',
|
|
17
|
+
lg: 'input-text-label-lg general-text-md-normal'
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
SUPPORT_TEXT_STYLES = {
|
|
21
|
+
md: 'input-text-subtext-md general-text-sm-normal',
|
|
22
|
+
lg: 'input-text-subtext-lg general-text-md-normal'
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
attr_accessor :form, :name, :label, :options, :value, :size,
|
|
26
|
+
:support_text, :error, :disabled, :html_options, :prompt
|
|
27
|
+
|
|
28
|
+
def initialize(form:, name:, label:, options:, value:, size:, support_text:, error:, disabled:, html_options:,
|
|
29
|
+
prompt:)
|
|
30
|
+
raise "Incorrect dropdown size: #{size}" unless DROPDOWN_SIZES.include?(size)
|
|
31
|
+
|
|
32
|
+
error_message = resolve_error(form, name, error)
|
|
33
|
+
|
|
34
|
+
self.form = form
|
|
35
|
+
self.name = name
|
|
36
|
+
self.label = label
|
|
37
|
+
self.options = options
|
|
38
|
+
self.value = value
|
|
39
|
+
self.size = size
|
|
40
|
+
self.support_text = (error_message.presence || support_text)
|
|
41
|
+
self.error = error_message
|
|
42
|
+
self.disabled = disabled
|
|
43
|
+
self.html_options = html_options
|
|
44
|
+
self.prompt = prompt
|
|
45
|
+
|
|
46
|
+
self.html_options[:disabled] = true if disabled
|
|
47
|
+
self.html_options[:class] = dropdown_style
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def dropdown_style
|
|
51
|
+
base = ['dropdown-component-base']
|
|
52
|
+
size_style = DROPDOWN_SIZE_STYLE[size.to_sym]
|
|
53
|
+
|
|
54
|
+
color_style =
|
|
55
|
+
if disabled
|
|
56
|
+
'text-disabled-color border-disabled-color'
|
|
57
|
+
elsif error.present?
|
|
58
|
+
'text-danger focus:text-danger-dark border-danger focus:border-danger focus:ring-danger'
|
|
59
|
+
else
|
|
60
|
+
'text-letter-color-light border-slate-grey-50 focus:ring-primary'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class_list(base, size_style, color_style)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def label_style
|
|
67
|
+
base = []
|
|
68
|
+
size_style = LABEL_STYLES[size.to_sym]
|
|
69
|
+
|
|
70
|
+
color_style =
|
|
71
|
+
if disabled
|
|
72
|
+
'text-disabled-color'
|
|
73
|
+
elsif error.present?
|
|
74
|
+
'text-danger-dark'
|
|
75
|
+
else
|
|
76
|
+
'text-letter-color-light group-focus-within:text-primary'
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class_list(base, size_style, color_style)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def support_text_style
|
|
83
|
+
base = []
|
|
84
|
+
size_style = SUPPORT_TEXT_STYLES[size.to_sym]
|
|
85
|
+
|
|
86
|
+
color_style =
|
|
87
|
+
if disabled
|
|
88
|
+
'text-disabled-color'
|
|
89
|
+
elsif error.present?
|
|
90
|
+
'text-danger-dark'
|
|
91
|
+
else
|
|
92
|
+
'text-letter-color-light'
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class_list(base, size_style, color_style)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ViewComponent
|
|
4
|
+
module InputComponent
|
|
5
|
+
class FileSelectorComponent
|
|
6
|
+
include ViewComponent::ComponentHelper
|
|
7
|
+
|
|
8
|
+
FILE_SELECTOR_TYPES = %w[image document video].freeze
|
|
9
|
+
|
|
10
|
+
attr_accessor :form, :name, :label, :support_text,
|
|
11
|
+
:support_text_two, :error, :disabled, :html_options, :type
|
|
12
|
+
|
|
13
|
+
def initialize(type:, form: nil, name: nil, label: nil,
|
|
14
|
+
support_text: nil, support_text_two: nil, error: nil, disabled: false, html_options: {})
|
|
15
|
+
raise "Invalid or missing file type: #{type}" unless FILE_SELECTOR_TYPES.include?(type)
|
|
16
|
+
|
|
17
|
+
error_message = resolve_error(form, name, error)
|
|
18
|
+
|
|
19
|
+
self.form = form
|
|
20
|
+
self.name = name
|
|
21
|
+
self.label = label
|
|
22
|
+
self.support_text = (error_message.presence || support_text)
|
|
23
|
+
self.support_text_two = support_text_two
|
|
24
|
+
self.error = error_message
|
|
25
|
+
self.disabled = disabled
|
|
26
|
+
self.html_options = html_options
|
|
27
|
+
self.type = type
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def accepted_types
|
|
31
|
+
case type
|
|
32
|
+
when 'image'
|
|
33
|
+
'image/*'
|
|
34
|
+
when 'document'
|
|
35
|
+
'.csv,.pdf,.doc,.docx'
|
|
36
|
+
when 'video'
|
|
37
|
+
'video/*,.mp4,.mov,.avi,.mkv'
|
|
38
|
+
else
|
|
39
|
+
'*/*'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def wrapper_style
|
|
44
|
+
base = ['file-selector-component-base radius-lg md:radius-xl']
|
|
45
|
+
|
|
46
|
+
color_style =
|
|
47
|
+
if disabled
|
|
48
|
+
'textarea-disabled-state pointer-events-none cursor-not-allowed'
|
|
49
|
+
elsif error.present?
|
|
50
|
+
'border-danger'
|
|
51
|
+
else
|
|
52
|
+
'border-slate-grey-50 hover:border-primary-light focus:border-primary-light'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class_list(base, color_style)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def label_style
|
|
59
|
+
base = ['general-text-sm-normal px-1']
|
|
60
|
+
|
|
61
|
+
color_style =
|
|
62
|
+
if disabled
|
|
63
|
+
'text-disabled-color'
|
|
64
|
+
elsif error.present?
|
|
65
|
+
'text-danger-dark'
|
|
66
|
+
else
|
|
67
|
+
'text-letter-color-light'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class_list(base, color_style)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def preview_style
|
|
74
|
+
base = ['file-selector-preview']
|
|
75
|
+
|
|
76
|
+
class_list(base)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def upload_icon_style
|
|
80
|
+
base = ['file-selector-upload-icon']
|
|
81
|
+
|
|
82
|
+
color_style =
|
|
83
|
+
if disabled
|
|
84
|
+
'fill-disabled-color'
|
|
85
|
+
elsif error.present?
|
|
86
|
+
'fill-danger'
|
|
87
|
+
else
|
|
88
|
+
'fill-primary'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class_list(base, color_style)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def choose_file_style
|
|
95
|
+
base = ['general-text-md-normal ']
|
|
96
|
+
|
|
97
|
+
color_style =
|
|
98
|
+
if disabled
|
|
99
|
+
'text-disabled-color'
|
|
100
|
+
else
|
|
101
|
+
'text-primary'
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class_list(base, color_style)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def support_text_style
|
|
108
|
+
base = ['file-selector-support-text general-text-sm-normal']
|
|
109
|
+
|
|
110
|
+
color_style =
|
|
111
|
+
if disabled
|
|
112
|
+
'text-disabled-color'
|
|
113
|
+
elsif error.present?
|
|
114
|
+
'text-danger-dark'
|
|
115
|
+
else
|
|
116
|
+
'text-slate-grey-50'
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class_list(base, color_style)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|