wilday_ui 0.6.0 → 0.7.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/app/assets/builds/wilday_ui/index.js +223 -0
- data/app/assets/builds/wilday_ui/index.js.map +3 -3
- data/app/assets/stylesheets/wilday_ui/components/button/features/clipboard.css +108 -0
- data/app/assets/stylesheets/wilday_ui/components/button/features/confirmation.css +136 -0
- data/app/assets/stylesheets/wilday_ui/components/button/features/variants.css +5 -0
- data/app/assets/stylesheets/wilday_ui/components/button/index.css +3 -0
- data/app/assets/stylesheets/wilday_ui/tokens/colors.css +109 -0
- data/app/helpers/wilday_ui/application_helper.rb +1 -0
- data/app/helpers/wilday_ui/components/button_helper.rb +120 -2
- data/app/helpers/wilday_ui/theme_helper.rb +19 -0
- data/app/javascript/wilday_ui/controllers/clipboard_controller.js +76 -0
- data/app/javascript/wilday_ui/controllers/confirmation_controller.js +216 -0
- data/app/javascript/wilday_ui/controllers/index.js +4 -1
- data/lib/wilday_ui/version.rb +1 -1
- metadata +8 -2
@@ -0,0 +1,108 @@
|
|
1
|
+
.w-button-feedback {
|
2
|
+
position: absolute;
|
3
|
+
padding: 0.5rem 1rem;
|
4
|
+
background: rgba(0, 0, 0, 0.8);
|
5
|
+
color: white;
|
6
|
+
border-radius: 4px;
|
7
|
+
font-size: 0.875rem;
|
8
|
+
pointer-events: none;
|
9
|
+
opacity: 0;
|
10
|
+
transition: opacity 0.2s ease;
|
11
|
+
z-index: 50;
|
12
|
+
white-space: nowrap;
|
13
|
+
}
|
14
|
+
|
15
|
+
/* Basic positions */
|
16
|
+
.w-button-feedback-top {
|
17
|
+
bottom: 100%;
|
18
|
+
left: 50%;
|
19
|
+
transform: translateX(-50%);
|
20
|
+
margin-bottom: 0.5rem;
|
21
|
+
}
|
22
|
+
|
23
|
+
.w-button-feedback-bottom {
|
24
|
+
top: 100%;
|
25
|
+
left: 50%;
|
26
|
+
transform: translateX(-50%);
|
27
|
+
margin-top: 0.5rem;
|
28
|
+
}
|
29
|
+
|
30
|
+
.w-button-feedback-left {
|
31
|
+
right: 100%;
|
32
|
+
top: 50%;
|
33
|
+
transform: translateY(-50%);
|
34
|
+
margin-right: 0.5rem;
|
35
|
+
}
|
36
|
+
|
37
|
+
.w-button-feedback-right {
|
38
|
+
left: 100%;
|
39
|
+
top: 50%;
|
40
|
+
transform: translateY(-50%);
|
41
|
+
margin-left: 0.5rem;
|
42
|
+
}
|
43
|
+
|
44
|
+
/* Start/End modifiers */
|
45
|
+
.w-button-feedback-top.w-button-feedback-start,
|
46
|
+
.w-button-feedback-bottom.w-button-feedback-start {
|
47
|
+
left: 0;
|
48
|
+
transform: translateX(0);
|
49
|
+
}
|
50
|
+
|
51
|
+
.w-button-feedback-top.w-button-feedback-end,
|
52
|
+
.w-button-feedback-bottom.w-button-feedback-end {
|
53
|
+
left: auto;
|
54
|
+
right: 0;
|
55
|
+
transform: translateX(0);
|
56
|
+
}
|
57
|
+
|
58
|
+
.w-button-feedback-left.w-button-feedback-start,
|
59
|
+
.w-button-feedback-right.w-button-feedback-start {
|
60
|
+
top: 0;
|
61
|
+
transform: translateY(0);
|
62
|
+
}
|
63
|
+
|
64
|
+
.w-button-feedback-left.w-button-feedback-end,
|
65
|
+
.w-button-feedback-right.w-button-feedback-end {
|
66
|
+
top: auto;
|
67
|
+
bottom: 0;
|
68
|
+
transform: translateY(0);
|
69
|
+
}
|
70
|
+
|
71
|
+
/* Show state */
|
72
|
+
.w-button-feedback-show {
|
73
|
+
opacity: 1;
|
74
|
+
}
|
75
|
+
|
76
|
+
/* Optional: Add arrow indicators */
|
77
|
+
.w-button-feedback::before {
|
78
|
+
content: "";
|
79
|
+
position: absolute;
|
80
|
+
width: 8px;
|
81
|
+
height: 8px;
|
82
|
+
background: inherit;
|
83
|
+
transform: rotate(45deg);
|
84
|
+
}
|
85
|
+
|
86
|
+
.w-button-feedback-top::before {
|
87
|
+
bottom: -4px;
|
88
|
+
left: 50%;
|
89
|
+
margin-left: -4px;
|
90
|
+
}
|
91
|
+
|
92
|
+
.w-button-feedback-bottom::before {
|
93
|
+
top: -4px;
|
94
|
+
left: 50%;
|
95
|
+
margin-left: -4px;
|
96
|
+
}
|
97
|
+
|
98
|
+
.w-button-feedback-left::before {
|
99
|
+
right: -4px;
|
100
|
+
top: 50%;
|
101
|
+
margin-top: -4px;
|
102
|
+
}
|
103
|
+
|
104
|
+
.w-button-feedback-right::before {
|
105
|
+
left: -4px;
|
106
|
+
top: 50%;
|
107
|
+
margin-top: -4px;
|
108
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
.w-button-confirmation-dialog {
|
2
|
+
padding: 0;
|
3
|
+
border: none;
|
4
|
+
border-radius: 0.5rem;
|
5
|
+
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
6
|
+
max-width: 28rem;
|
7
|
+
width: 90vw;
|
8
|
+
background: var(--w-color-light-50, #ffffff);
|
9
|
+
}
|
10
|
+
|
11
|
+
.w-button-confirmation-dialog::backdrop {
|
12
|
+
background-color: rgb(0 0 0 / 0.4);
|
13
|
+
backdrop-filter: blur(4px);
|
14
|
+
}
|
15
|
+
|
16
|
+
.w-button-confirmation-dialog-content {
|
17
|
+
padding: 1.5rem;
|
18
|
+
}
|
19
|
+
|
20
|
+
.w-button-confirmation-dialog-icon {
|
21
|
+
margin-bottom: 1rem;
|
22
|
+
width: 2.5rem;
|
23
|
+
height: 2.5rem;
|
24
|
+
}
|
25
|
+
|
26
|
+
.w-button-confirmation-dialog-icon svg {
|
27
|
+
width: 100%;
|
28
|
+
height: 100%;
|
29
|
+
}
|
30
|
+
|
31
|
+
.w-button-confirmation-dialog-icon.info {
|
32
|
+
color: var(--w-color-info-500);
|
33
|
+
}
|
34
|
+
|
35
|
+
.w-button-confirmation-dialog-icon.success {
|
36
|
+
color: var(--w-color-success-500);
|
37
|
+
}
|
38
|
+
|
39
|
+
.w-button-confirmation-dialog-icon.warning {
|
40
|
+
color: var(--w-color-warning-500);
|
41
|
+
}
|
42
|
+
|
43
|
+
.w-button-confirmation-dialog-icon.danger {
|
44
|
+
color: var(--w-color-danger-500);
|
45
|
+
}
|
46
|
+
|
47
|
+
.w-button-confirmation-dialog-title {
|
48
|
+
font-size: 1.125rem;
|
49
|
+
font-weight: 600;
|
50
|
+
color: var(--w-color-dark-800, #1f2937); /* Darker text for better contrast */
|
51
|
+
margin-bottom: 0.5rem;
|
52
|
+
}
|
53
|
+
|
54
|
+
.w-button-confirmation-dialog-message {
|
55
|
+
color: var(--w-color-dark-600, #4b5563); /* Adjusted for better readability */
|
56
|
+
margin-bottom: 1.5rem;
|
57
|
+
line-height: 1.5;
|
58
|
+
}
|
59
|
+
|
60
|
+
.w-button-confirmation-dialog-actions {
|
61
|
+
display: flex;
|
62
|
+
justify-content: flex-end;
|
63
|
+
gap: 0.75rem;
|
64
|
+
}
|
65
|
+
|
66
|
+
/* Mobile Responsive Styles */
|
67
|
+
@media (max-width: 640px) {
|
68
|
+
.w-button-confirmation-dialog {
|
69
|
+
width: 95vw; /* Slightly wider on mobile */
|
70
|
+
margin: 1rem;
|
71
|
+
max-height: 90vh; /* Prevent overflow on small screens */
|
72
|
+
overflow-y: auto; /* Allow scrolling if content is too tall */
|
73
|
+
position: fixed;
|
74
|
+
top: 50%;
|
75
|
+
left: 50%;
|
76
|
+
transform: translate(-50%, -50%);
|
77
|
+
margin: 0;
|
78
|
+
}
|
79
|
+
|
80
|
+
.w-button-confirmation-dialog-content {
|
81
|
+
padding: 1rem; /* Slightly smaller padding on mobile */
|
82
|
+
}
|
83
|
+
|
84
|
+
.w-button-confirmation-dialog-actions {
|
85
|
+
flex-direction: column-reverse; /* Stack buttons vertically */
|
86
|
+
gap: 0.5rem; /* Smaller gap between buttons */
|
87
|
+
padding: 1rem; /* Add padding around buttons */
|
88
|
+
}
|
89
|
+
|
90
|
+
.w-button-confirmation-dialog-actions button {
|
91
|
+
width: 100%; /* Full width buttons */
|
92
|
+
margin: 0; /* Remove any margins */
|
93
|
+
}
|
94
|
+
|
95
|
+
.w-button-confirmation-dialog-icon {
|
96
|
+
margin-bottom: 0.75rem; /* Slightly reduced spacing */
|
97
|
+
width: 2rem; /* Slightly smaller icon */
|
98
|
+
height: 2rem;
|
99
|
+
}
|
100
|
+
|
101
|
+
.w-button-confirmation-dialog-title {
|
102
|
+
font-size: 1rem; /* Slightly smaller title */
|
103
|
+
}
|
104
|
+
|
105
|
+
.w-button-confirmation-dialog-message {
|
106
|
+
font-size: 0.875rem; /* Slightly smaller message text */
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
/* Handle very small screens */
|
111
|
+
@media (max-width: 360px) {
|
112
|
+
.w-button-confirmation-dialog {
|
113
|
+
width: 98vw;
|
114
|
+
margin: 0.5rem;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
/* Handle landscape orientation */
|
119
|
+
@media (max-height: 600px) and (orientation: landscape) {
|
120
|
+
.w-button-confirmation-dialog {
|
121
|
+
max-height: 95vh;
|
122
|
+
display: flex;
|
123
|
+
flex-direction: row;
|
124
|
+
}
|
125
|
+
|
126
|
+
.w-button-confirmation-dialog-content {
|
127
|
+
flex: 1;
|
128
|
+
padding: 1rem;
|
129
|
+
}
|
130
|
+
|
131
|
+
.w-button-confirmation-dialog-actions {
|
132
|
+
padding: 1rem;
|
133
|
+
flex-direction: column;
|
134
|
+
justify-content: center;
|
135
|
+
}
|
136
|
+
}
|
@@ -152,6 +152,11 @@ a.w-button.w-button-no-underline:hover {
|
|
152
152
|
color: #000000;
|
153
153
|
}
|
154
154
|
|
155
|
+
/* Override underline for plain buttons */
|
156
|
+
a.w-button-plain.w-button-underline {
|
157
|
+
text-decoration: none;
|
158
|
+
}
|
159
|
+
|
155
160
|
.w-button-plain:focus-visible {
|
156
161
|
outline: 2px solid #1a1a1a;
|
157
162
|
outline-offset: 2px;
|
@@ -0,0 +1,109 @@
|
|
1
|
+
:root {
|
2
|
+
/* Primary Colors */
|
3
|
+
--w-color-primary-50: #e5f0ff;
|
4
|
+
--w-color-primary-100: #cce0ff;
|
5
|
+
--w-color-primary-200: #99c2ff;
|
6
|
+
--w-color-primary-300: #66a3ff;
|
7
|
+
--w-color-primary-400: #3385ff;
|
8
|
+
--w-color-primary-500: #0066ff;
|
9
|
+
--w-color-primary-600: #0052cc;
|
10
|
+
--w-color-primary-700: #003d99;
|
11
|
+
--w-color-primary-800: #002966;
|
12
|
+
--w-color-primary-900: #001433;
|
13
|
+
|
14
|
+
/* Secondary Colors */
|
15
|
+
--w-color-secondary-50: #f8f9fa;
|
16
|
+
--w-color-secondary-100: #e9ecef;
|
17
|
+
--w-color-secondary-200: #dee2e6;
|
18
|
+
--w-color-secondary-300: #ced4da;
|
19
|
+
--w-color-secondary-400: #adb5bd;
|
20
|
+
--w-color-secondary-500: #6c757d;
|
21
|
+
--w-color-secondary-600: #5a6268;
|
22
|
+
--w-color-secondary-700: #495057;
|
23
|
+
--w-color-secondary-800: #343a40;
|
24
|
+
--w-color-secondary-900: #212529;
|
25
|
+
|
26
|
+
/* Success Colors */
|
27
|
+
--w-color-success-50: #ecfdf5;
|
28
|
+
--w-color-success-100: #d1fae5;
|
29
|
+
--w-color-success-200: #a7f3d0;
|
30
|
+
--w-color-success-300: #6ee7b7;
|
31
|
+
--w-color-success-400: #34d399;
|
32
|
+
--w-color-success-500: #10b981;
|
33
|
+
--w-color-success-600: #059669;
|
34
|
+
--w-color-success-700: #047857;
|
35
|
+
--w-color-success-800: #065f46;
|
36
|
+
--w-color-success-900: #064e3b;
|
37
|
+
|
38
|
+
/* Danger Colors */
|
39
|
+
--w-color-danger-50: #fee2e2;
|
40
|
+
--w-color-danger-100: #fecaca;
|
41
|
+
--w-color-danger-200: #fca5a5;
|
42
|
+
--w-color-danger-300: #f87171;
|
43
|
+
--w-color-danger-400: #ef4444;
|
44
|
+
--w-color-danger-500: #dc2626;
|
45
|
+
--w-color-danger-600: #b91c1c;
|
46
|
+
--w-color-danger-700: #991b1b;
|
47
|
+
--w-color-danger-800: #7f1d1d;
|
48
|
+
--w-color-danger-900: #450a0a;
|
49
|
+
|
50
|
+
/* Warning Colors */
|
51
|
+
--w-color-warning-50: #fffbeb;
|
52
|
+
--w-color-warning-100: #fef3c7;
|
53
|
+
--w-color-warning-200: #fde68a;
|
54
|
+
--w-color-warning-300: #fcd34d;
|
55
|
+
--w-color-warning-400: #fbbf24;
|
56
|
+
--w-color-warning-500: #f59e0b;
|
57
|
+
--w-color-warning-600: #d97706;
|
58
|
+
--w-color-warning-700: #b45309;
|
59
|
+
--w-color-warning-800: #92400e;
|
60
|
+
--w-color-warning-900: #78350f;
|
61
|
+
|
62
|
+
/* Info Colors */
|
63
|
+
--w-color-info-50: #eff6ff;
|
64
|
+
--w-color-info-100: #dbeafe;
|
65
|
+
--w-color-info-200: #bfdbfe;
|
66
|
+
--w-color-info-300: #93c5fd;
|
67
|
+
--w-color-info-400: #60a5fa;
|
68
|
+
--w-color-info-500: #3b82f6;
|
69
|
+
--w-color-info-600: #2563eb;
|
70
|
+
--w-color-info-700: #1d4ed8;
|
71
|
+
--w-color-info-800: #1e40af;
|
72
|
+
--w-color-info-900: #1e3a8a;
|
73
|
+
|
74
|
+
/* Light Colors */
|
75
|
+
--w-color-light-50: #ffffff;
|
76
|
+
--w-color-light-100: #f8f9fa;
|
77
|
+
--w-color-light-200: #f1f3f5;
|
78
|
+
--w-color-light-300: #e9ecef;
|
79
|
+
--w-color-light-400: #dee2e6;
|
80
|
+
--w-color-light-500: #ced4da;
|
81
|
+
--w-color-light-600: #adb5bd;
|
82
|
+
--w-color-light-700: #868e96;
|
83
|
+
--w-color-light-800: #495057;
|
84
|
+
--w-color-light-900: #212529;
|
85
|
+
|
86
|
+
/* Dark Colors */
|
87
|
+
--w-color-dark-50: #f9fafb;
|
88
|
+
--w-color-dark-100: #f3f4f6;
|
89
|
+
--w-color-dark-200: #e5e7eb;
|
90
|
+
--w-color-dark-300: #d1d5db;
|
91
|
+
--w-color-dark-400: #1f2937;
|
92
|
+
--w-color-dark-500: #111827;
|
93
|
+
--w-color-dark-600: #0f172a;
|
94
|
+
--w-color-dark-700: #0a0f1a;
|
95
|
+
--w-color-dark-800: #060912;
|
96
|
+
--w-color-dark-900: #030509;
|
97
|
+
|
98
|
+
/* Link Colors */
|
99
|
+
--w-color-link-50: #eff6ff;
|
100
|
+
--w-color-link-100: #dbeafe;
|
101
|
+
--w-color-link-200: #bfdbfe;
|
102
|
+
--w-color-link-300: #93c5fd;
|
103
|
+
--w-color-link-400: #60a5fa;
|
104
|
+
--w-color-link-500: #2563eb;
|
105
|
+
--w-color-link-600: #1d4ed8;
|
106
|
+
--w-color-link-700: #1e40af;
|
107
|
+
--w-color-link-800: #1e3a8a;
|
108
|
+
--w-color-link-900: #1e3a8a;
|
109
|
+
}
|
@@ -11,6 +11,16 @@ module WildayUi
|
|
11
11
|
wrapper_required: false,
|
12
12
|
stimulus_controller: "button",
|
13
13
|
default_stimulus_action: "click->button#toggleLoading"
|
14
|
+
},
|
15
|
+
copy_to_clipboard: {
|
16
|
+
wrapper_required: true,
|
17
|
+
stimulus_controller: "clipboard button",
|
18
|
+
default_stimulus_action: "click->clipboard#copy click->button#toggleLoading"
|
19
|
+
},
|
20
|
+
confirm: {
|
21
|
+
wrapper_required: true,
|
22
|
+
stimulus_controller: "confirmation",
|
23
|
+
default_stimulus_action: "click->confirmation#showDialog"
|
14
24
|
}
|
15
25
|
# Add more features here as needed
|
16
26
|
# tooltip: {
|
@@ -42,6 +52,8 @@ module WildayUi
|
|
42
52
|
dropdown_items: nil,
|
43
53
|
dropdown_icon: nil,
|
44
54
|
theme: nil,
|
55
|
+
copy_to_clipboard: nil,
|
56
|
+
confirm: nil,
|
45
57
|
**options
|
46
58
|
)
|
47
59
|
content_for(:head) { stylesheet_link_tag "wilday_ui/components/button/index", media: "all" }
|
@@ -68,7 +80,7 @@ module WildayUi
|
|
68
80
|
gradient_class = get_gradient_class(gradient)
|
69
81
|
|
70
82
|
# Setup features that require Stimulus controllers
|
71
|
-
active_features = determine_active_features(loading, dropdown, loading_text, use_default_controller)
|
83
|
+
active_features = determine_active_features(loading, dropdown, loading_text, copy_to_clipboard, confirm, use_default_controller)
|
72
84
|
|
73
85
|
setup_features(active_features, options, use_default_controller, loading_text)
|
74
86
|
|
@@ -84,6 +96,24 @@ module WildayUi
|
|
84
96
|
)
|
85
97
|
end
|
86
98
|
|
99
|
+
if copy_to_clipboard
|
100
|
+
setup_clipboard_options(
|
101
|
+
options,
|
102
|
+
additional_classes,
|
103
|
+
copy_to_clipboard,
|
104
|
+
wrapper_data
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
if confirm
|
109
|
+
setup_confirmation_options(
|
110
|
+
options,
|
111
|
+
additional_classes,
|
112
|
+
confirm,
|
113
|
+
wrapper_data
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
87
117
|
# Setup wrapper options if any feature requires it
|
88
118
|
wrapper_options = setup_wrapper_options(
|
89
119
|
active_features,
|
@@ -267,10 +297,12 @@ module WildayUi
|
|
267
297
|
styles.map { |k, v| "#{k}: #{v}" }.join(";")
|
268
298
|
end
|
269
299
|
|
270
|
-
def determine_active_features(loading, dropdown, loading_text = nil, use_default_controller = true)
|
300
|
+
def determine_active_features(loading, dropdown, loading_text = nil, copy_to_clipboard = nil, confirm = nil, use_default_controller = true)
|
271
301
|
features = {}
|
272
302
|
features[:loading] = true if (loading || loading_text.present?) && use_default_controller
|
273
303
|
features[:dropdown] = true if dropdown && use_default_controller
|
304
|
+
features[:copy_to_clipboard] = true if copy_to_clipboard.present? && use_default_controller
|
305
|
+
features[:confirm] = true if confirm.present? && use_default_controller
|
274
306
|
features
|
275
307
|
end
|
276
308
|
|
@@ -389,6 +421,92 @@ module WildayUi
|
|
389
421
|
"#{base}#{index}"
|
390
422
|
end
|
391
423
|
|
424
|
+
def setup_clipboard_options(options, additional_classes, copy_to_clipboard, wrapper_data)
|
425
|
+
return unless copy_to_clipboard.present?
|
426
|
+
|
427
|
+
clipboard_config = normalize_clipboard_options(copy_to_clipboard)
|
428
|
+
|
429
|
+
wrapper_data.merge!(
|
430
|
+
controller: "clipboard button",
|
431
|
+
clipboard_text_value: clipboard_config[:text],
|
432
|
+
clipboard_feedback_text_value: clipboard_config[:feedback_text],
|
433
|
+
clipboard_feedback_position_value: clipboard_config[:position],
|
434
|
+
clipboard_feedback_duration_value: clipboard_config[:duration]
|
435
|
+
)
|
436
|
+
|
437
|
+
options[:data][:clipboard_target] = "button"
|
438
|
+
options[:data][:button_target] = "button"
|
439
|
+
end
|
440
|
+
|
441
|
+
def normalize_clipboard_options(options)
|
442
|
+
if options.is_a?(Hash)
|
443
|
+
{
|
444
|
+
text: options[:text],
|
445
|
+
feedback_text: options[:feedback_text] || "Copied!",
|
446
|
+
position: options[:position] || "top",
|
447
|
+
duration: options[:duration] || 2000
|
448
|
+
}
|
449
|
+
else
|
450
|
+
{
|
451
|
+
text: options.to_s,
|
452
|
+
feedback_text: "Copied!",
|
453
|
+
position: "top",
|
454
|
+
duration: 2000
|
455
|
+
}
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
def setup_confirmation_options(options, additional_classes, confirm, wrapper_data)
|
460
|
+
return unless confirm.present?
|
461
|
+
|
462
|
+
confirm_config = normalize_confirmation_options(confirm)
|
463
|
+
|
464
|
+
# Use the same theme processing as regular buttons
|
465
|
+
confirm_theme_styles = process_theme(:solid, { name: confirm_config[:variant] })
|
466
|
+
cancel_theme_styles = process_theme(:subtle, { name: :secondary })
|
467
|
+
|
468
|
+
wrapper_data.merge!(
|
469
|
+
controller: "confirmation",
|
470
|
+
confirmation_title_value: confirm_config[:title],
|
471
|
+
confirmation_message_value: confirm_config[:message],
|
472
|
+
confirmation_icon_color_value: confirm_config[:variant],
|
473
|
+
confirmation_confirm_text_value: confirm_config[:confirm_text],
|
474
|
+
confirmation_cancel_text_value: confirm_config[:cancel_text],
|
475
|
+
confirmation_confirm_styles_value: confirm_theme_styles,
|
476
|
+
confirmation_cancel_styles_value: cancel_theme_styles
|
477
|
+
)
|
478
|
+
|
479
|
+
# Only add loading state if enabled
|
480
|
+
if confirm_config[:loading]
|
481
|
+
wrapper_data.merge!(
|
482
|
+
confirmation_loading_value: "true",
|
483
|
+
confirmation_loading_text_value: confirm_config[:loading_text]
|
484
|
+
)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
def normalize_confirmation_options(options)
|
489
|
+
if options.is_a?(String)
|
490
|
+
{
|
491
|
+
title: "Confirm Action",
|
492
|
+
message: options,
|
493
|
+
variant: :info,
|
494
|
+
confirm_text: "Confirm",
|
495
|
+
cancel_text: "Cancel"
|
496
|
+
}
|
497
|
+
else
|
498
|
+
{
|
499
|
+
title: options[:title] || "Confirm Action",
|
500
|
+
message: options[:message],
|
501
|
+
variant: options[:variant] || :info,
|
502
|
+
confirm_text: options[:confirm_text] || "Confirm",
|
503
|
+
cancel_text: options[:cancel_text] || "Cancel",
|
504
|
+
loading: options[:loading] || false,
|
505
|
+
loading_text: options[:loading_text] || "Processing..."
|
506
|
+
}
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
392
510
|
def render_button(content, variant_class, size_class, radius_class, gradient_class, icon, icon_position, icon_only,
|
393
511
|
loading, loading_text, additional_classes, disabled, options, href, underline,
|
394
512
|
dropdown, dropdown_items, dropdown_icon, wrapper_options)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module WildayUi
|
2
|
+
module ThemeHelper
|
3
|
+
def generate_theme_css_variables
|
4
|
+
colors = WildayUi::Config::Theme.configuration.colors
|
5
|
+
css_vars = colors.map do |color_name, shades|
|
6
|
+
shades.map do |shade, value|
|
7
|
+
"--w-color-#{color_name}-#{shade}: #{value};"
|
8
|
+
end
|
9
|
+
end.flatten.join("\n")
|
10
|
+
|
11
|
+
"<style>:root { #{css_vars} }</style>".html_safe
|
12
|
+
end
|
13
|
+
|
14
|
+
# Helper to get specific color value
|
15
|
+
def theme_color(name, shade = "500")
|
16
|
+
WildayUi::Config::Theme.configuration.colors.dig(name.to_s, shade.to_s)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = ["button", "feedback"];
|
5
|
+
static values = {
|
6
|
+
text: String,
|
7
|
+
feedbackText: { type: String, default: "Copied!" },
|
8
|
+
feedbackPosition: { type: String, default: "top" },
|
9
|
+
feedbackDuration: { type: Number, default: 2000 },
|
10
|
+
};
|
11
|
+
|
12
|
+
connect() {
|
13
|
+
// Optional: Initialize any necessary setup
|
14
|
+
}
|
15
|
+
|
16
|
+
async copy(event) {
|
17
|
+
event.preventDefault();
|
18
|
+
|
19
|
+
try {
|
20
|
+
await navigator.clipboard.writeText(this.textValue);
|
21
|
+
this.showFeedback();
|
22
|
+
} catch (err) {
|
23
|
+
console.error("Failed to copy text:", err);
|
24
|
+
// Fallback for older browsers
|
25
|
+
this.fallbackCopy();
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
fallbackCopy() {
|
30
|
+
const textArea = document.createElement("textarea");
|
31
|
+
textArea.value = this.textValue;
|
32
|
+
textArea.style.position = "fixed";
|
33
|
+
textArea.style.left = "-9999px";
|
34
|
+
document.body.appendChild(textArea);
|
35
|
+
textArea.select();
|
36
|
+
|
37
|
+
try {
|
38
|
+
document.execCommand("copy");
|
39
|
+
this.showFeedback();
|
40
|
+
} catch (err) {
|
41
|
+
console.error("Fallback: Oops, unable to copy", err);
|
42
|
+
}
|
43
|
+
|
44
|
+
document.body.removeChild(textArea);
|
45
|
+
}
|
46
|
+
|
47
|
+
showFeedback() {
|
48
|
+
const feedback = this.hasFeedbackTarget
|
49
|
+
? this.feedbackTarget
|
50
|
+
: this.createFeedbackElement();
|
51
|
+
feedback.textContent = this.feedbackTextValue;
|
52
|
+
|
53
|
+
// Remove any existing position classes
|
54
|
+
feedback.className = "w-button-feedback";
|
55
|
+
|
56
|
+
// Add position-specific classes
|
57
|
+
const positionClasses = this.feedbackPositionValue.split("-");
|
58
|
+
positionClasses.forEach((pos) => {
|
59
|
+
feedback.classList.add(`w-button-feedback-${pos}`);
|
60
|
+
});
|
61
|
+
|
62
|
+
feedback.classList.add("w-button-feedback-show");
|
63
|
+
|
64
|
+
setTimeout(() => {
|
65
|
+
feedback.classList.remove("w-button-feedback-show");
|
66
|
+
}, this.feedbackDurationValue);
|
67
|
+
}
|
68
|
+
|
69
|
+
createFeedbackElement() {
|
70
|
+
const feedback = document.createElement("div");
|
71
|
+
feedback.classList.add("w-button-feedback");
|
72
|
+
feedback.setAttribute("data-clipboard-target", "feedback");
|
73
|
+
this.element.appendChild(feedback);
|
74
|
+
return feedback;
|
75
|
+
}
|
76
|
+
}
|