codengage_view_components 0.1.6 → 0.1.8
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/app/components/codengage_view_components/body_component.html.haml +5 -0
- data/app/components/codengage_view_components/body_component.rb +12 -0
- data/app/components/codengage_view_components/card_component.css +16 -0
- data/app/components/codengage_view_components/card_component.html.haml +13 -0
- data/app/components/codengage_view_components/card_component.rb +14 -0
- data/app/components/codengage_view_components/column_component.html.haml +6 -0
- data/app/components/codengage_view_components/column_component.rb +11 -0
- data/app/components/codengage_view_components/dropdown_component.rb +1 -1
- data/app/components/codengage_view_components/empty_state_action_component.html.haml +4 -0
- data/app/components/codengage_view_components/empty_state_action_component.rb +11 -0
- data/app/components/codengage_view_components/empty_state_component.html.haml +15 -0
- data/app/components/codengage_view_components/empty_state_component.rb +14 -0
- data/app/components/codengage_view_components/flash_component.css +1 -1
- data/app/components/codengage_view_components/flash_component.html.haml +1 -1
- data/app/components/codengage_view_components/flash_component.rb +4 -3
- data/app/components/codengage_view_components/header_component.html.haml +4 -0
- data/app/components/codengage_view_components/header_component.rb +11 -0
- data/app/components/codengage_view_components/item_table_component.html.haml +15 -0
- data/app/components/codengage_view_components/item_table_component.rb +11 -0
- data/app/components/codengage_view_components/paginator_component.html.haml +42 -0
- data/app/components/codengage_view_components/paginator_component.rb +10 -0
- data/app/components/codengage_view_components/search_form_component.css +81 -0
- data/app/components/codengage_view_components/search_form_component.html.haml +12 -0
- data/app/components/codengage_view_components/search_form_component.rb +11 -0
- data/app/components/codengage_view_components/tab_item_component.css +11 -0
- data/app/components/codengage_view_components/tab_item_component.html.haml +3 -0
- data/app/components/codengage_view_components/tab_item_component.rb +21 -0
- data/app/components/codengage_view_components/table_component.css +182 -0
- data/app/components/codengage_view_components/table_component.html.haml +7 -0
- data/app/components/codengage_view_components/table_component.rb +13 -0
- data/app/components/codengage_view_components/toggle_component.css +31 -0
- data/app/components/codengage_view_components/toggle_component.html.haml +43 -0
- data/app/components/codengage_view_components/toggle_component.rb +66 -0
- data/app/components/codengage_view_components/turbo_drawer_component.html.erb +46 -0
- data/app/components/codengage_view_components/turbo_drawer_component.rb +12 -0
- data/app/components/codengage_view_components/turbo_modal_component.html.erb +103 -0
- data/app/components/codengage_view_components/turbo_modal_component.rb +46 -0
- data/app/javascript/controllers/search_controller.js +79 -0
- data/app/javascript/controllers/toggle_controller.js +26 -0
- data/config/importmap.rb +3 -1
- data/lib/codengage_view_components/version.rb +1 -1
- metadata +36 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd28f76bd68a94bd05d84dca6be35e5acae3974cbb4fcadae89d9a5d1460999d
|
|
4
|
+
data.tar.gz: 4f6de8757125a6c496dc40620671c15ed922ac47fcd41d1879cb6a51cba1f112
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b995a430a14fa6838130a73115e70129819d3e0f6e70d8ff5478001e84ca1d149ec624881923e96458751fd60ba702e2cbffe9469c489a21eff0e2d3f65f3362
|
|
7
|
+
data.tar.gz: 5ded5f4f31659036aefdb0e72ce0d02765966dba5018a83dfcb400df75a4dea61ac4ec82cac5cec63e3e7bea630e25331e138cfa1e31f8949c9b5685ffb1765a
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class BodyComponent < ApplicationComponent
|
|
5
|
+
renders_many :items, "CodengageViewComponents::ItemTableComponent"
|
|
6
|
+
|
|
7
|
+
def initialize(id: "items", classes: "")
|
|
8
|
+
@id = id
|
|
9
|
+
@classes = classes
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.card{ class: @options.fetch(:class, ''), data: @options.fetch(:data, {}) }
|
|
2
|
+
- if header?
|
|
3
|
+
%div{ class: @options.fetch(:header_class, 'card__header') }
|
|
4
|
+
= header
|
|
5
|
+
- if body?
|
|
6
|
+
.card__body
|
|
7
|
+
= body
|
|
8
|
+
- if table?
|
|
9
|
+
.card__table
|
|
10
|
+
= table
|
|
11
|
+
= if footer?
|
|
12
|
+
.card__footer
|
|
13
|
+
= footer
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class CardComponent < ApplicationComponent
|
|
5
|
+
renders_one :header
|
|
6
|
+
renders_one :body
|
|
7
|
+
renders_one :table
|
|
8
|
+
renders_one :footer
|
|
9
|
+
|
|
10
|
+
def initialize(options: {})
|
|
11
|
+
@options = options
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.my-10{ id: :empty_state, class: @options.fetch(:hidden, false) && 'hidden' }
|
|
2
|
+
.min-h-full.px-3.py-3.sm:px-6.sm:py-3.md:grid.md:place-items-center.lg:px-8{ class: @options.fetch(:class, '') }
|
|
3
|
+
.mx-auto.max-w-max
|
|
4
|
+
.sm:flex.sm:flex-col.sm:items-center.sm:justify-center.gap-y-2
|
|
5
|
+
%p.sm:flex-1.flex.justify-center.sm:justify-end.font-bold.tracking-tight.text-primary
|
|
6
|
+
.text-gray-300
|
|
7
|
+
= lucide_icon @icon, size: 40
|
|
8
|
+
.sm:flex-1.mt-6.sm:mt-0
|
|
9
|
+
%h5.text-gray-500.font-semibold.text-center.sm:text-lg= @title
|
|
10
|
+
%p.text-sm.text-gray-500.text-center.mt-1= @message
|
|
11
|
+
.mt-6.flex.sm:space-x-6
|
|
12
|
+
- actions.each do |action|
|
|
13
|
+
= action
|
|
14
|
+
|
|
15
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class EmptyStateComponent < ApplicationComponent
|
|
5
|
+
renders_many :actions, CodengageViewComponents::EmptyStateActionComponent
|
|
6
|
+
|
|
7
|
+
def initialize(title:, message:, icon:, options: {})
|
|
8
|
+
@title = title
|
|
9
|
+
@message = message
|
|
10
|
+
@icon = icon
|
|
11
|
+
@options = options
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
.flash {
|
|
2
|
-
@apply flex items-center w-full max-w-sm p-4 rounded-base gap-4 text-
|
|
2
|
+
@apply flex items-center w-full max-w-sm p-4 rounded-base gap-4 text-white fixed right-0 bottom-12 mr-4 transition-transform transform translate-x-full;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.flash.flash--visible {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
- @messages.each do |message|
|
|
2
|
-
.flash{ class: message.bg, data: { controller: "flash-component" } }
|
|
2
|
+
.flash{ class: "#{message.bg} #{@classes}", data: { controller: "flash-component" } }
|
|
3
3
|
.flash__icon
|
|
4
4
|
= lucide_icon(message.icon, stroke: message.stroke)
|
|
5
5
|
.flash__text
|
|
@@ -5,11 +5,12 @@ module CodengageViewComponents
|
|
|
5
5
|
Message = Struct.new(:type, :text, :bg, :stroke, :icon, keyword_init: true)
|
|
6
6
|
|
|
7
7
|
STYLES = {
|
|
8
|
-
"notice" => { bg: "bg-
|
|
9
|
-
"alert" => { bg: "bg-
|
|
8
|
+
"notice" => { bg: "bg-green-700", stroke: "#48BB78", icon: "check" },
|
|
9
|
+
"alert" => { bg: "bg-red-700", stroke: "#DC3545", icon: "circle-alert" }
|
|
10
10
|
}.freeze
|
|
11
11
|
|
|
12
|
-
def initialize(flash:)
|
|
12
|
+
def initialize(flash:, classes:)
|
|
13
|
+
@classes = classes
|
|
13
14
|
@messages = flash.map do |type, text|
|
|
14
15
|
style = STYLES[type]
|
|
15
16
|
Message.new(type:, text: text.to_s, **style)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
- if @options.fetch(:href, false)
|
|
2
|
+
%tr.hoverable.group.print:break-inside-avoid{ id: @options.fetch(:id, object_id),
|
|
3
|
+
data: { controller: 'clickable',
|
|
4
|
+
clickable_url_value: @options.fetch(:href, ''),
|
|
5
|
+
clickable_turbo_value: @options.fetch(:turbo, true),
|
|
6
|
+
clickable_frame_value: @options.fetch(:frame, '_top')
|
|
7
|
+
}.merge(@options.fetch(:data, {})) }
|
|
8
|
+
- cols.each do |col|
|
|
9
|
+
= col
|
|
10
|
+
= content
|
|
11
|
+
- else
|
|
12
|
+
%tr.print:break-inside-avoid{ id: @options.fetch(:id, object_id), class: "#{@options.fetch(:class, '')}", data: @options.fetch(:data, {}) }
|
|
13
|
+
- cols.each do |col|
|
|
14
|
+
= col
|
|
15
|
+
= content
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
- return unless @paginator && @paginator.pages > 1
|
|
2
|
+
|
|
3
|
+
%nav#series-nav.pagy.series-nav.flex.items-center.justify-end.gap-4.mt-5{"aria-label" => "Pages series_nav"}
|
|
4
|
+
- if @paginator.page == 1
|
|
5
|
+
%span.text-gray-300.cursor-not-allowed.text-base= lucide_icon('chevrons-left', class: 'w-4 h-4')
|
|
6
|
+
%span.text-gray-300.cursor-not-allowed.text-base= lucide_icon('chevron-left', class: 'w-4 h-4')
|
|
7
|
+
- else
|
|
8
|
+
= link_to lucide_icon('chevrons-left', class: 'w-4 h-4'), @paginator.page_url(:first), aria: { label: "First" }
|
|
9
|
+
= link_to lucide_icon('chevron-left', class: 'w-4 h-4'), @paginator.page_url(:previous), aria: { label: "Previous" }
|
|
10
|
+
|
|
11
|
+
- current = @paginator.page
|
|
12
|
+
- last = @paginator.last
|
|
13
|
+
|
|
14
|
+
- if last <= 3
|
|
15
|
+
- pages_to_show = (1..last).to_a
|
|
16
|
+
- else
|
|
17
|
+
- case current
|
|
18
|
+
- when 1
|
|
19
|
+
- pages_to_show = [1, 2, 3]
|
|
20
|
+
- when last
|
|
21
|
+
- pages_to_show = [last - 2, last - 1, last]
|
|
22
|
+
- else
|
|
23
|
+
- pages_to_show = [current - 1, current, current + 1]
|
|
24
|
+
|
|
25
|
+
- pages_to_show = pages_to_show.map { _1.clamp(1, last) }.uniq
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
- pages_to_show.each do |num|
|
|
29
|
+
- if num == current
|
|
30
|
+
.bg-primary.text-white.px-2.py-1.font-semibold.text-sm{class: 'rounded-[10px]'}= num
|
|
31
|
+
- else
|
|
32
|
+
= link_to num, @paginator.page_url(num),
|
|
33
|
+
class: "rounded-[10px] px-2 py-1 hover:bg-gray-100 text-sm text-gray-500 font-semibold"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
- if @paginator.last == @paginator.page
|
|
38
|
+
%span.page.text-gray-300.cursor-not-allowed= lucide_icon('chevron-right', class: 'w-4 h-4')
|
|
39
|
+
%span.page.text-gray-300.cursor-not-allowed= lucide_icon('chevrons-right', class: 'w-4 h-4')
|
|
40
|
+
- else
|
|
41
|
+
= link_to lucide_icon('chevron-right', class: 'w-4 h-4'), @paginator.page_url(:next), aria: { label: "Next" }
|
|
42
|
+
= link_to lucide_icon('chevrons-right', class: 'w-4 h-4'), @paginator.page_url(:last), aria: { label: "Last" }
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
.search-form {
|
|
2
|
+
@apply relative w-full text-gray-400 focus-within:text-gray-600;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.search-form__container {
|
|
6
|
+
@apply flex items-center w-full p-1;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.search-form__icon {
|
|
10
|
+
@apply pointer-events-none absolute inset-y-0 flex items-center pl-3;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.search-form__input {
|
|
14
|
+
@apply block outline-none w-full h-12 rounded-base border-0 border-[#E5E7EB] bg-[#F3F3F5] pl-12 pr-3 text-gray-700 ring-1 ring-gray-200 focus:ring-4 focus:ring-gray-300;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* dropdown dentro de .search-form */
|
|
18
|
+
.search-form .dropdown > button > div:not(.active) > svg {
|
|
19
|
+
animation: filter-arrow-reverse 0.2s cubic-bezier(1, 0, 0, 1) 0s 1 forwards;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.search-form .dropdown > button > div.active > svg {
|
|
23
|
+
animation: filter-arrow 0.2s cubic-bezier(1, 0, 0, 1) 0s 1 forwards;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.clear-filter__container {
|
|
27
|
+
@apply w-fit ml-1 text-primary gap-x-2 items-center mt-3 cursor-pointer hover:text-brand-blue
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@keyframes filter-arrow {
|
|
31
|
+
0% {
|
|
32
|
+
transform: rotateX(0deg);
|
|
33
|
+
}
|
|
34
|
+
49% {
|
|
35
|
+
transform: rotateX(45deg);
|
|
36
|
+
}
|
|
37
|
+
50% {
|
|
38
|
+
transform: rotateX(135deg);
|
|
39
|
+
}
|
|
40
|
+
100% {
|
|
41
|
+
transform: rotateX(180deg);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@keyframes filter-arrow-reverse {
|
|
46
|
+
0% {
|
|
47
|
+
transform: rotateX(180deg);
|
|
48
|
+
}
|
|
49
|
+
49% {
|
|
50
|
+
transform: rotateX(135deg);
|
|
51
|
+
}
|
|
52
|
+
50% {
|
|
53
|
+
transform: rotateX(45deg);
|
|
54
|
+
}
|
|
55
|
+
100% {
|
|
56
|
+
transform: rotateX(0deg);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/*!* ss-main.always_dropdown *!*/
|
|
61
|
+
/*.ss-main.always_dropdown,*/
|
|
62
|
+
/*.ss-main.always_dropdown:focus,*/
|
|
63
|
+
/*.ss-main.always_dropdown:hover {*/
|
|
64
|
+
/* @apply gap-1.5 text-base font-bold drop-shadow-none ring-0 shadow-none cursor-pointer flex relative mt-0;*/
|
|
65
|
+
/*}*/
|
|
66
|
+
|
|
67
|
+
/*.ss-main.always_dropdown::before {*/
|
|
68
|
+
/* content: "";*/
|
|
69
|
+
/* margin-right: calc(0.375rem + 1px);*/
|
|
70
|
+
/* @apply max-w-5 max-h-5 w-5 h-5 absolute bg-gray-300 rounded-full right-0 -z-10;*/
|
|
71
|
+
/*}*/
|
|
72
|
+
|
|
73
|
+
/*.ss-main.always_dropdown .ss-arrow path {*/
|
|
74
|
+
/* @apply brightness-[0.30] stroke-[14px];*/
|
|
75
|
+
/*}*/
|
|
76
|
+
|
|
77
|
+
/*!* ss-content.always_dropdown *!*/
|
|
78
|
+
/*.ss-content.always_dropdown {*/
|
|
79
|
+
/* --tw-ring-shadow: none;*/
|
|
80
|
+
/* @apply border-gray-200 shadow-md rounded-md bg-white;*/
|
|
81
|
+
/*}*/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
= turbo_frame_tag :search_form, class: @options.fetch(:class, '') do
|
|
2
|
+
.flex.justify-between
|
|
3
|
+
.search-form__container
|
|
4
|
+
.search-form__icon
|
|
5
|
+
= lucide_icon 'search'
|
|
6
|
+
= @form.search_field :q, value: params[:q], class: "search-form__input", placeholder: @options.fetch(:placeholder, ''), data: { action: 'input->search#onType' }
|
|
7
|
+
- if defined?(form_params) && form_params.any?
|
|
8
|
+
- form_params.each do |k, v|
|
|
9
|
+
- next if v.blank?
|
|
10
|
+
= @form.hidden_field k, value: v
|
|
11
|
+
.flex.items-center.gap-4
|
|
12
|
+
= content
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.tab__selected{
|
|
2
|
+
@apply bg-linear-to-r from-[#0046CE] to-[#7A5AF8] rounded-base py-1 px-4 text-white font-semibold flex items-center gap-2;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.tab__not-selected{
|
|
6
|
+
@apply hover:bg-gray-300 rounded-base py-1 px-4 text-gray-500 font-semibold flex items-center gap-2;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.tab__box{
|
|
10
|
+
@apply bg-gray-100 border border-gray-200 shadow-sm w-fit p-2 rounded-base flex items-center gap-5;
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class TabItemComponent < ApplicationComponent
|
|
5
|
+
def initialize(url:, tab:, icon:, text:, classes:)
|
|
6
|
+
@url = url
|
|
7
|
+
@tab = tab
|
|
8
|
+
@icon = icon
|
|
9
|
+
@text = text
|
|
10
|
+
@classes = classes
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def active?
|
|
14
|
+
params[:tab] == @tab
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def tab_item_class
|
|
18
|
+
active? ? "tab__selected #{@classes}" : "tab__not-selected #{@classes}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
.c-table {
|
|
2
|
+
@apply block divide-y divide-gray-200 rounded-lg w-auto print:text-black print:w-full;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.c-table__head,
|
|
6
|
+
.c-table__body {
|
|
7
|
+
@apply flex flex-col divide-y;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.c-table__head {
|
|
11
|
+
@apply font-semibold overflow-hidden bg-gray-500 rounded-t-lg print:font-bold;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.c-table__item {
|
|
15
|
+
@apply flex flex-row items-center box-border flex-nowrap px-1.5;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.c-table__body .c-table__item {
|
|
19
|
+
@apply hover:bg-gray-50;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.c-table__body .c-table__item.disable-hover {
|
|
23
|
+
@apply hover:bg-white;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.c-table__head .c-table__item:first-child {
|
|
27
|
+
@apply rounded-t-lg;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.c-table__body > turbo-frame:last-of-type > li > .c-table__item,
|
|
31
|
+
.c-table__body > turbo-frame:last-of-type > .c-table__item {
|
|
32
|
+
@apply rounded-b-lg;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.c-table__column {
|
|
36
|
+
@apply flex items-center px-1.5 py-1.5 print:py-1.5 leading-4 whitespace-normal box-border flex-shrink-0;
|
|
37
|
+
min-height: 3rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.c-table__column--check {
|
|
41
|
+
@apply justify-center flex-shrink-0;
|
|
42
|
+
width: 3.5rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.c-table__column--flag {
|
|
46
|
+
@apply justify-center text-center flex-shrink-0;
|
|
47
|
+
width: 8rem;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.c-table__column--avatar {
|
|
51
|
+
@apply justify-start flex-shrink-0 w-14;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.c-table__column--name {
|
|
55
|
+
@apply items-center font-bold text-left;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.c-table__column--description {
|
|
59
|
+
@apply flex flex-col justify-center items-start flex-1 space-y-1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.c-table__column--amount,
|
|
63
|
+
.c-table__column--type{
|
|
64
|
+
@apply w-32 xl:w-36 font-bold text-left;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.c-table__column--status {
|
|
68
|
+
@apply xl:w-52 font-bold text-left;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.c-table__column--date {
|
|
72
|
+
@apply w-24 xl:w-28;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.c-table__column--contact {
|
|
76
|
+
@apply w-24 xl:w-40;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.c-table__column--others {
|
|
80
|
+
@apply truncate flex-shrink-0;
|
|
81
|
+
width: 10rem;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.c-table__column--phone-number {
|
|
85
|
+
@apply truncate flex-shrink-0;
|
|
86
|
+
width: 10rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.c-table__column--person-type,
|
|
90
|
+
.c-table__column--seller {
|
|
91
|
+
@apply items-center font-bold text-center justify-center;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.c-table__column--cell_phone-number {
|
|
95
|
+
@apply truncate flex-shrink-0;
|
|
96
|
+
width: 10rem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.c-table__column--email {
|
|
100
|
+
@apply truncate flex-shrink-0 w-[30%];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.c-table__column--datetime {
|
|
104
|
+
@apply whitespace-nowrap font-bold;
|
|
105
|
+
width: 11rem;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.c-table__column--document-1,
|
|
109
|
+
.c-table__column--document-2,
|
|
110
|
+
.c-table__column--id {
|
|
111
|
+
@apply text-left font-bold justify-center;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.c-table__column--actions {
|
|
115
|
+
@apply text-right font-bold justify-center;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.table-component {
|
|
119
|
+
@apply rounded-xl table-auto sm:table-fixed w-full print:text-black print:w-full divide-y divide-gray-200 border border-gray-200 overflow-hidden shadow-md;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.table-component > thead {
|
|
123
|
+
@apply font-semibold;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.table-component > thead > tr > td a:hover {
|
|
127
|
+
@apply text-primary underline;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.table-component > tbody {
|
|
131
|
+
@apply divide-y divide-gray-200;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.table-component > tbody > tr.disabled {
|
|
135
|
+
@apply opacity-50 cursor-not-allowed pointer-events-none line-through;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.table-component > tbody > tr.hoverable:hover > td {
|
|
139
|
+
@apply bg-gray-100;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.table-component > tbody > tr > td:first-child,
|
|
143
|
+
.table-component > thead > tr > td:first-child {
|
|
144
|
+
@apply pl-3;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.table-component > tbody > tr > td:last-child,
|
|
148
|
+
.table-component > thead > tr > td:last-child {
|
|
149
|
+
@apply pr-3;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.table-component td {
|
|
153
|
+
@apply px-1.5 py-1.5 h-12 leading-4;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.table-component__actions {
|
|
157
|
+
@apply flex items-center justify-center space-x-1.5;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.table-component__content {
|
|
161
|
+
@apply w-auto relative;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.table-component__content .tooltip {
|
|
165
|
+
@apply truncate cursor-default;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.table-component__content .tooltip-text {
|
|
169
|
+
@apply invisible bg-gray-900 text-white cursor-default text-center absolute -bottom-4 z-10 rounded-md px-3 py-1.5 w-max left-1/3;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.table-component__content:hover .tooltip-text {
|
|
173
|
+
@apply visible;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.table-component__form-buttons {
|
|
177
|
+
@apply flex items-center justify-end space-x-1.5;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.table-component__role-value {
|
|
181
|
+
@apply bg-white rounded-md h-6 w-fit border border-gray-300 text-xs font-semibold text-gray-900 flex items-center p-2;
|
|
182
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class TableComponent < ApplicationComponent
|
|
5
|
+
renders_one :header, "CodengageViewComponents::HeaderComponent"
|
|
6
|
+
renders_many :bodies, "CodengageViewComponents::BodyComponent"
|
|
7
|
+
|
|
8
|
+
def initialize(variant: :normal, options: {})
|
|
9
|
+
@variant = variant
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
.toggle {
|
|
2
|
+
@apply relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.toggle:disabled {
|
|
6
|
+
@apply opacity-50 cursor-not-allowed;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.toggle__bg {
|
|
10
|
+
@apply pointer-events-none absolute h-full w-full rounded-md bg-transparent;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.toggle__bar {
|
|
14
|
+
@apply bg-gray-200 pointer-events-none absolute mx-2 h-4 w-9 rounded-full transition-colors duration-200 ease-in-out;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.toggle__pin {
|
|
18
|
+
@apply translate-x-0 pointer-events-none absolute left-0 inline-block h-5 w-5 transform rounded-full border border-gray-200 bg-white shadow ring-0 transition-transform duration-200 ease-in-out;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.toggle__pin--active {
|
|
22
|
+
@apply translate-x-5;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.toggle--active > .toggle__bar {
|
|
26
|
+
@apply bg-primary;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.toggle--active > .toggle__pin {
|
|
30
|
+
@apply translate-x-5;
|
|
31
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
- if form_mode?
|
|
2
|
+
.nav.flex.items-center{ data: { controller: "toggle" } }
|
|
3
|
+
= @form.hidden_field @attribute,
|
|
4
|
+
value: @value,
|
|
5
|
+
data: { toggle_target: "input" }
|
|
6
|
+
|
|
7
|
+
- button_data = @options.fetch(:data, {}).merge(toggle_target: "button").compact
|
|
8
|
+
- extra_action = @options.fetch(:data, {})[:action]
|
|
9
|
+
- action_value = ["click->toggle#switch", extra_action].reject(&:blank?).join(" ")
|
|
10
|
+
|
|
11
|
+
- button_data[:action] = action_value if action_value.present?
|
|
12
|
+
|
|
13
|
+
= button_tag type: "button",
|
|
14
|
+
class: "toggle",
|
|
15
|
+
disabled: @disabled,
|
|
16
|
+
role: "switch",
|
|
17
|
+
id: @id,
|
|
18
|
+
data: button_data do
|
|
19
|
+
%span.toggle__bg{ "aria-hidden": true }
|
|
20
|
+
%span.toggle__bar{ "aria-hidden": true, data: { toggle_target: :bar } }
|
|
21
|
+
%span.toggle__pin{ "aria-hidden": true, data: { toggle_target: :pin } }
|
|
22
|
+
|
|
23
|
+
- elsif remote_mode?
|
|
24
|
+
- button_data = @options.fetch(:data, {}).merge(toggle_target: "button")
|
|
25
|
+
- action_value = @options.fetch(:action, "click->toggle#switch")
|
|
26
|
+
|
|
27
|
+
- button_data[:action] = action_value if action_value.present?
|
|
28
|
+
|
|
29
|
+
%div{ data: { controller: "toggle" } }
|
|
30
|
+
= button_to url,
|
|
31
|
+
method: @method,
|
|
32
|
+
value: @enabled,
|
|
33
|
+
params: @params,
|
|
34
|
+
class: "toggle",
|
|
35
|
+
role: "switch",
|
|
36
|
+
disabled: @disabled,
|
|
37
|
+
onclick: "event.stopPropagation()",
|
|
38
|
+
id: @id,
|
|
39
|
+
"aria-checked": @enabled,
|
|
40
|
+
data: button_data do
|
|
41
|
+
%span.toggle__bg{ "aria-hidden": true }
|
|
42
|
+
%span.toggle__bar{ "aria-hidden": true, data: { toggle_target: :bar } }
|
|
43
|
+
%span.toggle__pin{ "aria-hidden": true, data: { toggle_target: :pin } }
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class ToggleComponent < ViewComponent::Base
|
|
5
|
+
# Uso:
|
|
6
|
+
# - Form mode:
|
|
7
|
+
# = render Form::ToggleComponent.new(form: f, attribute: :status, options: { id: "user-active-toggle" })
|
|
8
|
+
#
|
|
9
|
+
# - Remote mode:
|
|
10
|
+
# = render Form::ToggleComponent.new(url: user_path(user), options: { method: :patch, enabled: user.active? })
|
|
11
|
+
|
|
12
|
+
def initialize(form: nil, attribute: nil, url: nil, value: nil, options: {})
|
|
13
|
+
@form = form
|
|
14
|
+
@attribute = attribute
|
|
15
|
+
@url = url
|
|
16
|
+
@value = value
|
|
17
|
+
|
|
18
|
+
# Defaults centralizados aqui
|
|
19
|
+
@id = options.fetch(:id, nil)
|
|
20
|
+
@disabled = options.fetch(:disabled, false)
|
|
21
|
+
|
|
22
|
+
@method = options.fetch(:method, :patch)
|
|
23
|
+
@enabled = options.fetch(:enabled, false)
|
|
24
|
+
@params = options.fetch(:params, {})
|
|
25
|
+
|
|
26
|
+
@options = options.except(:id, :value, :disabled, :method, :enabled, :params)
|
|
27
|
+
|
|
28
|
+
validate_configuration!
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def validate_configuration!
|
|
34
|
+
if form_mode?
|
|
35
|
+
validate_form_mode!
|
|
36
|
+
elsif remote_mode?
|
|
37
|
+
validate_remote_mode!
|
|
38
|
+
else
|
|
39
|
+
raise ArgumentError,
|
|
40
|
+
"Você precisa fornecer `form` e `attribute`, ou `url` (modo remoto)."
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def form_mode?
|
|
45
|
+
@form.present? && @attribute.present?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def remote_mode?
|
|
49
|
+
@url.present?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def validate_form_mode!
|
|
53
|
+
if @url.present?
|
|
54
|
+
raise ArgumentError,
|
|
55
|
+
"No modo form, não use `url`. Use apenas `form:` e `attribute:`."
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def validate_remote_mode!
|
|
60
|
+
unless @method.respond_to?(:to_sym)
|
|
61
|
+
raise ArgumentError,
|
|
62
|
+
"O método HTTP deve ser algo como :get, :post, :patch, :put ou :delete."
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<%= turbo_frame_tag :drawer do %>
|
|
2
|
+
<%= tag.div data: { controller: "turbo-drawer", action: token_list(
|
|
3
|
+
@close_on_submit ? "turbo:submit-end->turbo-drawer#submitEnd" : nil,
|
|
4
|
+
"keyup@window->turbo-drawer#closeWithKeyboard",
|
|
5
|
+
"mousedown@window->turbo-drawer#closeBackground"
|
|
6
|
+
) }, class: "relative z-auto" do %>
|
|
7
|
+
<%= tag.div class: "fixed inset-0 bg-black/50 z-40 hidden", data: { turbo_drawer_target: :backdrop, action: "click->turbo-drawer#hideDrawer" } %>
|
|
8
|
+
<%= tag.div class: "z-50 pointer-events-none fixed inset-y-0 right-0 flex #{@options.fetch(:max_w, 'max-w-md')} sm:max-w-full sm:pl-10" do %>
|
|
9
|
+
<%= tag.div id: 'drawer_body', class: "pointer-events-auto w-screen #{@options.fetch(:max_w, 'max-w-md')} hidden",
|
|
10
|
+
data: { turbo_drawer_target: :drawer,
|
|
11
|
+
transition_enter: "transition ease-in-out duration-200 transform",
|
|
12
|
+
transition_enter_start: "translate-x-full",
|
|
13
|
+
transition_enter_end: "translate-x-0",
|
|
14
|
+
transition_leave: "transition ease-in-out duration-100 transform",
|
|
15
|
+
transition_leave_start: "translate-x-0",
|
|
16
|
+
transition_leave_end: "translate-x-full" } do %>
|
|
17
|
+
<%= tag.div class: 'flex h-full flex-col bg-white shadow-xl overflow-auto' do %>
|
|
18
|
+
<%= tag.div class: 'py-6 px-3 sm:px-6 sticky top-0 bg-white z-50 border-b border-gray-200' do %>
|
|
19
|
+
<%= tag.div class: 'flex items-start justify-between' do %>
|
|
20
|
+
<%= tag.div class: 'block space-y-2' do %>
|
|
21
|
+
<%= tag.div class: 'text-2xl font-semibold text-gray-40 items-center flex gap-x-2' do %>
|
|
22
|
+
<%= @title %>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% if @subtitle.present? %>
|
|
25
|
+
<%= tag.div class: 'text-sm text-gray-30' do %>
|
|
26
|
+
<%= @subtitle %>
|
|
27
|
+
<% end %>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% end %>
|
|
30
|
+
<%= tag.div class: 'ml-3 flex h-8 items-center' do %>
|
|
31
|
+
<%= button_tag data: { action: "turbo-drawer#hideDrawer" }, type: "button", class: 'cursor-pointer', id: 'close_drawer' do %>
|
|
32
|
+
<%= lucide_icon "x" %>
|
|
33
|
+
<% end %>
|
|
34
|
+
<% end %>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% end %>
|
|
37
|
+
<%= tag.div class: 'flex-1 mb-6 flex flex-col' do %>
|
|
38
|
+
<%= tag.div class: 'px-10 pt-10 sm:px-6 flex-1 flex flex-col' do %>
|
|
39
|
+
<%= content %>
|
|
40
|
+
<% end %>
|
|
41
|
+
<% end %>
|
|
42
|
+
<% end %>
|
|
43
|
+
<% end %>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
<% end %>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class TurboDrawerComponent < ApplicationComponent
|
|
5
|
+
def initialize(title:, subtitle: nil, close_on_submit: true, options: {})
|
|
6
|
+
@title = title
|
|
7
|
+
@subtitle = subtitle
|
|
8
|
+
@close_on_submit = close_on_submit
|
|
9
|
+
@options = options
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<%= turbo_frame_tag :modal, class: "overflow-hidden print:hidden" do %>
|
|
2
|
+
<%= tag.div class: "relative z-30", role: "dialog",
|
|
3
|
+
aria: { labelledby: "modal-title", modal: true },
|
|
4
|
+
data: { controller: "turbo-modal #{@options.fetch(:controller, '')}",
|
|
5
|
+
action: token_list("turbo:submit-end->turbo-modal#submitEnd") } do %>
|
|
6
|
+
<!--
|
|
7
|
+
Background backdrop, show/hide based on modal state.
|
|
8
|
+
Entering: "ease-out duration-300"
|
|
9
|
+
From: "opacity-0"
|
|
10
|
+
To: "opacity-100"
|
|
11
|
+
Leaving: "ease-in duration-200"
|
|
12
|
+
From: "opacity-100"
|
|
13
|
+
To: "opacity-0"
|
|
14
|
+
-->
|
|
15
|
+
<%= tag.div(
|
|
16
|
+
class: "fixed inset-0 bg-black/60 hidden",
|
|
17
|
+
data: {
|
|
18
|
+
turbo_modal_target: "backdrop",
|
|
19
|
+
action: "click->turbo-modal#hideModal",
|
|
20
|
+
transition_enter: "transition-opacity ease-out duration-300",
|
|
21
|
+
transition_enter_start: "opacity-0",
|
|
22
|
+
transition_enter_end: "opacity-100",
|
|
23
|
+
transition_leave: "transition-opacity ease-in duration-200",
|
|
24
|
+
transition_leave_start: "opacity-100",
|
|
25
|
+
transition_leave_end: "opacity-0"
|
|
26
|
+
}
|
|
27
|
+
) %>
|
|
28
|
+
<%= tag.div class: "fixed inset-0 z-40 overflow-y-auto" do %>
|
|
29
|
+
<%= tag.div class: "flex min-h-full items-stretch justify-center text-center sm:items-center" do %>
|
|
30
|
+
<!--
|
|
31
|
+
Modal panel, show/hide based on modal state.
|
|
32
|
+
Entering: "ease-out duration-300"
|
|
33
|
+
From: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
34
|
+
To: "opacity-100 translate-y-0 sm:scale-100"
|
|
35
|
+
Leaving: "ease-in duration-200"
|
|
36
|
+
From: "opacity-100 translate-y-0 sm:scale-100"
|
|
37
|
+
To: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
38
|
+
-->
|
|
39
|
+
<!-- HEADER -->
|
|
40
|
+
<%= tag.div class: "relative transform sm:rounded-lg bg-white text-left shadow-xl transition-all sm:m-6 w-full #{modal_size_class} hidden",
|
|
41
|
+
data: { turbo_modal_target: 'modal',
|
|
42
|
+
transition_enter: "ease-out duration-300",
|
|
43
|
+
transition_enter_start: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
|
|
44
|
+
transition_enter_end: "opacity-100 translate-y-0 sm:scale-100",
|
|
45
|
+
transition_leave: "ease-in duration-200",
|
|
46
|
+
transition_leave_start: "opacity-100 translate-y-0 sm:scale-100",
|
|
47
|
+
transition_leave_end: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" } do %>
|
|
48
|
+
|
|
49
|
+
<% if @title.present? %>
|
|
50
|
+
<!-- HEADER normal (com título) -->
|
|
51
|
+
<%= tag.div class: "flex items-center space-x-3 pl-7 pr-3 pt-1 print:hidden" do %>
|
|
52
|
+
<%= tag.div class: "block flex-1 truncate" do %>
|
|
53
|
+
<div class="flex items-center gap-x-2">
|
|
54
|
+
<% if @icon.present? %>
|
|
55
|
+
<%= lucide_icon @icon %>
|
|
56
|
+
<% end %>
|
|
57
|
+
<h5 class="text-primary w-fit text-nowrap font-semibold leading-6 pt-6 mt-0 <%= @options.fetch(:title_class, '') %>">
|
|
58
|
+
<%= @title %>
|
|
59
|
+
</h5>
|
|
60
|
+
</div>
|
|
61
|
+
<% end %>
|
|
62
|
+
|
|
63
|
+
<% unless @without_close.present? %>
|
|
64
|
+
<%= tag.div class: "block flex-shrink-0" do %>
|
|
65
|
+
<%= button_tag id: 'close_modal',
|
|
66
|
+
data: { action: "turbo-modal#hideModal" },
|
|
67
|
+
type: "button" do %>
|
|
68
|
+
<%= lucide_icon 'x' %>
|
|
69
|
+
<% end %>
|
|
70
|
+
<% end %>
|
|
71
|
+
<% end %>
|
|
72
|
+
<% end %>
|
|
73
|
+
<% else %>
|
|
74
|
+
<!-- Sem header: só o X absoluto no canto superior direito -->
|
|
75
|
+
<% unless @without_close.present? %>
|
|
76
|
+
<%= button_tag id: 'close_modal',
|
|
77
|
+
class: "absolute top-4 right-4 inline-flex items-center cursor-pointer justify-center print:hidden",
|
|
78
|
+
data: { action: "turbo-modal#hideModal" },
|
|
79
|
+
type: "button" do %>
|
|
80
|
+
<%= lucide_icon 'x' %>
|
|
81
|
+
<% end %>
|
|
82
|
+
<% end %>
|
|
83
|
+
<% end %>
|
|
84
|
+
|
|
85
|
+
<!-- BODY -->
|
|
86
|
+
<% if bodies.present? %>
|
|
87
|
+
<% bodies.each do |body| %>
|
|
88
|
+
<%= tag.div id: 'modal_body', class: "block sm:p-3 " do %>
|
|
89
|
+
<%= body %>
|
|
90
|
+
<% end %>
|
|
91
|
+
<% end %>
|
|
92
|
+
<% end %>
|
|
93
|
+
|
|
94
|
+
<% if content.present? %>
|
|
95
|
+
<%= tag.div class: "block p-7" do %>
|
|
96
|
+
<%= content %>
|
|
97
|
+
<% end %>
|
|
98
|
+
<% end %>
|
|
99
|
+
<% end %>
|
|
100
|
+
<% end %>
|
|
101
|
+
<% end %>
|
|
102
|
+
<% end %>
|
|
103
|
+
<% end %>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CodengageViewComponents
|
|
4
|
+
class TurboModalComponent < ApplicationComponent
|
|
5
|
+
renders_many :bodies, "CodengageViewComponents::BodyComponent"
|
|
6
|
+
|
|
7
|
+
def initialize(title: nil, icon: nil, size: :lg, without_close: false, options: {})
|
|
8
|
+
@title = title
|
|
9
|
+
@icon = icon
|
|
10
|
+
@size = size
|
|
11
|
+
@without_close = without_close
|
|
12
|
+
@options = options
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def modal_size_class
|
|
16
|
+
case @size
|
|
17
|
+
when :sm
|
|
18
|
+
"sm:max-w-sm"
|
|
19
|
+
when :md
|
|
20
|
+
"sm:max-w-md"
|
|
21
|
+
when :lg
|
|
22
|
+
"sm:max-w-lg"
|
|
23
|
+
when :xl
|
|
24
|
+
"sm:max-w-xl"
|
|
25
|
+
when :xl2
|
|
26
|
+
"sm:max-w-2xl"
|
|
27
|
+
when :xl3
|
|
28
|
+
"sm:max-w-3xl"
|
|
29
|
+
when :xl4
|
|
30
|
+
"sm:max-w-4xl"
|
|
31
|
+
when :xl5
|
|
32
|
+
"sm:max-w-5xl"
|
|
33
|
+
when :xl6
|
|
34
|
+
"sm:max-w-6xl"
|
|
35
|
+
when :xl7
|
|
36
|
+
"sm:max-w-7xl"
|
|
37
|
+
when :xl8
|
|
38
|
+
"sm:max-w-[1500px]"
|
|
39
|
+
when :full
|
|
40
|
+
"sm:max-w-full"
|
|
41
|
+
else
|
|
42
|
+
"sm:max-w-lg"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
import debounce from "lodash/debounce"
|
|
3
|
+
|
|
4
|
+
export default class extends Controller {
|
|
5
|
+
static targets = ["clear"]
|
|
6
|
+
|
|
7
|
+
connect() {
|
|
8
|
+
this.debouncedSubmit = debounce(() => {
|
|
9
|
+
this.element.querySelector("form")?.requestSubmit()
|
|
10
|
+
}, 300)
|
|
11
|
+
|
|
12
|
+
this.updateClearButtonVisibility()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
onType(event) {
|
|
16
|
+
this.updateClearButtonVisibility()
|
|
17
|
+
this.debouncedSubmit()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
onFilterChange(event) {
|
|
21
|
+
this.updateClearButtonVisibility()
|
|
22
|
+
this.element.querySelector("form")?.requestSubmit()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
resetFilters(event) {
|
|
26
|
+
event.preventDefault()
|
|
27
|
+
const form = this.element.querySelector("form")
|
|
28
|
+
if (!form) return
|
|
29
|
+
|
|
30
|
+
form.reset()
|
|
31
|
+
|
|
32
|
+
const qInput = form.querySelector("input[name='q']")
|
|
33
|
+
if (qInput) qInput.value = ""
|
|
34
|
+
|
|
35
|
+
const selects = Array.from(form.querySelectorAll("select"))
|
|
36
|
+
|
|
37
|
+
selects.forEach(select => {
|
|
38
|
+
select.value = ""
|
|
39
|
+
select.dispatchEvent(new Event("change"))
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if (this.hasClearTarget) {
|
|
44
|
+
this.clearTarget.classList.add("hidden")
|
|
45
|
+
this.clearTarget.classList.remove("flex")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
form.requestSubmit()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
updateClearButtonVisibility() {
|
|
52
|
+
if (!this.hasClearTarget) return
|
|
53
|
+
|
|
54
|
+
const form = this.element.querySelector("form")
|
|
55
|
+
const qInput = form.querySelector("input[name='q']")
|
|
56
|
+
const selects = Array.from(form.querySelectorAll("select"))
|
|
57
|
+
|
|
58
|
+
const hasSearch = qInput && qInput.value.trim().length > 0
|
|
59
|
+
const hasSelect = selects.some(select => select.value !== "")
|
|
60
|
+
|
|
61
|
+
const shouldShow = hasSearch || hasSelect
|
|
62
|
+
|
|
63
|
+
this.clearTarget.classList.toggle("hidden", !shouldShow)
|
|
64
|
+
|
|
65
|
+
if (shouldShow) {
|
|
66
|
+
this.clearTarget.classList.remove("hidden")
|
|
67
|
+
this.clearTarget.classList.add("flex")
|
|
68
|
+
} else {
|
|
69
|
+
this.clearTarget.classList.add("hidden")
|
|
70
|
+
this.clearTarget.classList.remove("flex")
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
disconnect() {
|
|
75
|
+
if (this.debouncedSubmit?.cancel) {
|
|
76
|
+
this.debouncedSubmit.cancel()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {Controller} from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["bar", "pin", "button", "input"]
|
|
5
|
+
|
|
6
|
+
connect() {
|
|
7
|
+
if (this.hasInputTarget) {
|
|
8
|
+
if (this.inputTarget.value === 'true') {
|
|
9
|
+
this.buttonTarget.classList.add('toggle--active')
|
|
10
|
+
this.buttonTarget.dispatchEvent(new Event('change', { bubbles: true }))
|
|
11
|
+
}
|
|
12
|
+
} else {
|
|
13
|
+
if (this.buttonTarget.value === 'true') {
|
|
14
|
+
this.buttonTarget.classList.add('toggle--active')
|
|
15
|
+
this.buttonTarget.dispatchEvent(new Event('change', { bubbles: true }))
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
switch(event) {
|
|
22
|
+
this.buttonTarget.classList.toggle('toggle--active')
|
|
23
|
+
this.buttonTarget.dispatchEvent(new Event('change', { bubbles: true }))
|
|
24
|
+
this.inputTarget.value = this.buttonTarget.classList.contains('toggle--active')
|
|
25
|
+
}
|
|
26
|
+
}
|
data/config/importmap.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
pin_all_from File.expand_path("../app/javascript/controllers", __dir__), under: "controllers"
|
|
2
2
|
|
|
3
3
|
pin "flowbite-datepicker", to: "https://cdn.jsdelivr.net/npm/flowbite-datepicker@1.3.0/dist/js/datepicker-full.js"
|
|
4
|
-
pin "flowbite-datepicker-pt-BR", to: "https://cdn.jsdelivr.net/npm/flowbite-datepicker@1.3.0/dist/js/locales/pt-BR.js"
|
|
4
|
+
pin "flowbite-datepicker-pt-BR", to: "https://cdn.jsdelivr.net/npm/flowbite-datepicker@1.3.0/dist/js/locales/pt-BR.js"
|
|
5
|
+
pin "lodash", to: "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js" # @4.17.21
|
|
6
|
+
pin "lodash/debounce", to: "https://ga.jspm.io/npm:lodash@4.17.21/debounce.js" # @4.17.21
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: codengage_view_components
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gabriel Karlinski Baldo
|
|
@@ -92,16 +92,49 @@ files:
|
|
|
92
92
|
- Rakefile
|
|
93
93
|
- app/assets/stylesheets/codengage_view_components/application.css
|
|
94
94
|
- app/components/codengage_view_components/application_component.rb
|
|
95
|
+
- app/components/codengage_view_components/body_component.html.haml
|
|
96
|
+
- app/components/codengage_view_components/body_component.rb
|
|
97
|
+
- app/components/codengage_view_components/card_component.css
|
|
98
|
+
- app/components/codengage_view_components/card_component.html.haml
|
|
99
|
+
- app/components/codengage_view_components/card_component.rb
|
|
100
|
+
- app/components/codengage_view_components/column_component.html.haml
|
|
101
|
+
- app/components/codengage_view_components/column_component.rb
|
|
95
102
|
- app/components/codengage_view_components/date_field_component.css
|
|
96
103
|
- app/components/codengage_view_components/date_field_component.html.haml
|
|
97
104
|
- app/components/codengage_view_components/date_field_component.rb
|
|
98
105
|
- app/components/codengage_view_components/dropdown_component.html.haml
|
|
99
106
|
- app/components/codengage_view_components/dropdown_component.rb
|
|
107
|
+
- app/components/codengage_view_components/empty_state_action_component.html.haml
|
|
108
|
+
- app/components/codengage_view_components/empty_state_action_component.rb
|
|
109
|
+
- app/components/codengage_view_components/empty_state_component.html.haml
|
|
110
|
+
- app/components/codengage_view_components/empty_state_component.rb
|
|
100
111
|
- app/components/codengage_view_components/flash_component.css
|
|
101
112
|
- app/components/codengage_view_components/flash_component.html.haml
|
|
102
113
|
- app/components/codengage_view_components/flash_component.rb
|
|
114
|
+
- app/components/codengage_view_components/header_component.html.haml
|
|
115
|
+
- app/components/codengage_view_components/header_component.rb
|
|
103
116
|
- app/components/codengage_view_components/item_component.html.haml
|
|
104
117
|
- app/components/codengage_view_components/item_component.rb
|
|
118
|
+
- app/components/codengage_view_components/item_table_component.html.haml
|
|
119
|
+
- app/components/codengage_view_components/item_table_component.rb
|
|
120
|
+
- app/components/codengage_view_components/paginator_component.html.haml
|
|
121
|
+
- app/components/codengage_view_components/paginator_component.rb
|
|
122
|
+
- app/components/codengage_view_components/search_form_component.css
|
|
123
|
+
- app/components/codengage_view_components/search_form_component.html.haml
|
|
124
|
+
- app/components/codengage_view_components/search_form_component.rb
|
|
125
|
+
- app/components/codengage_view_components/tab_item_component.css
|
|
126
|
+
- app/components/codengage_view_components/tab_item_component.html.haml
|
|
127
|
+
- app/components/codengage_view_components/tab_item_component.rb
|
|
128
|
+
- app/components/codengage_view_components/table_component.css
|
|
129
|
+
- app/components/codengage_view_components/table_component.html.haml
|
|
130
|
+
- app/components/codengage_view_components/table_component.rb
|
|
131
|
+
- app/components/codengage_view_components/toggle_component.css
|
|
132
|
+
- app/components/codengage_view_components/toggle_component.html.haml
|
|
133
|
+
- app/components/codengage_view_components/toggle_component.rb
|
|
134
|
+
- app/components/codengage_view_components/turbo_drawer_component.html.erb
|
|
135
|
+
- app/components/codengage_view_components/turbo_drawer_component.rb
|
|
136
|
+
- app/components/codengage_view_components/turbo_modal_component.html.erb
|
|
137
|
+
- app/components/codengage_view_components/turbo_modal_component.rb
|
|
105
138
|
- app/controllers/codengage_view_components/application_controller.rb
|
|
106
139
|
- app/controllers/codengage_view_components/pages_controller.rb
|
|
107
140
|
- app/helpers/codengage_view_components/application_helper.rb
|
|
@@ -109,6 +142,8 @@ files:
|
|
|
109
142
|
- app/javascript/controllers/datepicker_controller.js
|
|
110
143
|
- app/javascript/controllers/flash_component_controller.js
|
|
111
144
|
- app/javascript/controllers/index.js
|
|
145
|
+
- app/javascript/controllers/search_controller.js
|
|
146
|
+
- app/javascript/controllers/toggle_controller.js
|
|
112
147
|
- app/jobs/codengage_view_components/application_job.rb
|
|
113
148
|
- app/mailers/codengage_view_components/application_mailer.rb
|
|
114
149
|
- app/models/codengage_view_components/application_record.rb
|