fluxbit_view_components 0.5.1 → 0.5.2
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/fluxbit/form/upload_image_component.html.erb +24 -11
- data/app/components/fluxbit/form/upload_image_component.rb +49 -0
- data/app/components/fluxbit/gravatar_component.rb +7 -1
- data/lib/fluxbit/config/gravatar_component.rb +2 -2
- data/lib/fluxbit/view_components/version.rb +1 -1
- metadata +1 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd7bed7240f33dbb0940a142d872dc031c7ad7bd2f065f1051ef2b2eb5dd4abe
|
|
4
|
+
data.tar.gz: dad11a6840d1835cbf7f7c2ff03d37bf70f1d1bc708c00785bf0b0e09f954796
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0c2278a2d6995c3247cadc40c50baa567f4dccade78c4e6aea44d0df001c206dd9cea61a2b94ef3644e9badb1f0b6c090843e6cf5c1be7b7b9cb675d3ebee3bb
|
|
7
|
+
data.tar.gz: eb413e15da3790ed9c5b39b2966153b23ec8d88ddb9fa8b0a452318cdf15304f60ac75066ef92f7a65ff7f3fb78cf4c28a671962a63f5487d7a3417fd28ae8ed
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<%= content_tag :div, **@wrapper_html do %>
|
|
2
|
-
<div id="<%= id %>" class="
|
|
2
|
+
<div id="<%= id %>" class="grow lg:mt-0 lg:shrink-0 lg:grow-0">
|
|
3
3
|
<%= label %>
|
|
4
4
|
<div class="mt-1 lg:hidden">
|
|
5
5
|
<div class="flex items-center">
|
|
6
6
|
<div class="inline-block h-12 w-12 shrink-0 overflow-hidden <%= container_rounded_class %> relative" aria-hidden="true">
|
|
7
|
-
<%= image_element %>
|
|
7
|
+
<%= has_initials? ? initials_element : image_element %>
|
|
8
8
|
</div>
|
|
9
9
|
<div class="ml-5 rounded-md shadow-xs">
|
|
10
10
|
<div class="group relative flex items-center justify-center rounded-md border border-slate-300 py-2 px-3 focus-within:ring-2 focus-within:ring-sky-500 focus-within:ring-offset-2 hover:bg-slate-50">
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
|
-
<div class="relative hidden overflow-hidden <%= container_rounded_class %> lg:block w-40">
|
|
22
|
-
<div class="
|
|
23
|
-
<%= image_element %>
|
|
21
|
+
<div class="relative hidden overflow-hidden <%= container_rounded_class %> lg:block w-40 h-40">
|
|
22
|
+
<div class="absolute inset-0 w-full h-full overflow-hidden <%= container_rounded_class %>" aria-hidden="true">
|
|
23
|
+
<%= has_initials? ? initials_element : image_element %>
|
|
24
24
|
</div>
|
|
25
|
-
<label for="desktop-<%= id %>" class="absolute inset-0 flex flex-col
|
|
25
|
+
<label for="desktop-<%= id %>" class="absolute inset-0 flex flex-col items-center justify-center bg-blue-800/75 text-sm font-medium text-white opacity-0 hover:opacity-100 <%= container_rounded_class %>">
|
|
26
26
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-white mb-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
27
27
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
|
28
28
|
</svg>
|
|
@@ -36,12 +36,25 @@
|
|
|
36
36
|
|
|
37
37
|
<script>
|
|
38
38
|
function loadFile(event, id) {
|
|
39
|
-
const
|
|
39
|
+
const elements = document.querySelectorAll('.img_photo_' + id);
|
|
40
40
|
if (event.target.files && event.target.files[0]) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
elements.forEach(function(element) {
|
|
42
|
+
if (element.hasAttribute('data-initials-placeholder')) {
|
|
43
|
+
const img = document.createElement('img');
|
|
44
|
+
img.className = element.className.replace('flex items-center justify-center', '');
|
|
45
|
+
img.alt = element.querySelector('span')?.textContent || 'Uploaded image';
|
|
46
|
+
img.classList.remove('bg-gradient-to-br', 'from-blue-500', 'to-purple-600', 'from-green-500', 'to-teal-600', 'from-pink-500', 'to-rose-600', 'from-orange-500', 'to-red-600', 'from-indigo-500', 'to-blue-600', 'from-purple-500', 'to-pink-600', 'from-cyan-500', 'to-blue-600', 'from-emerald-500', 'to-green-600', 'from-amber-500', 'to-orange-600', 'from-violet-500', 'to-purple-600');
|
|
47
|
+
img.classList.add('object-cover');
|
|
48
|
+
img.src = URL.createObjectURL(event.target.files[0]);
|
|
49
|
+
img.onload = function() {
|
|
50
|
+
URL.revokeObjectURL(img.src);
|
|
51
|
+
}
|
|
52
|
+
element.parentNode.replaceChild(img, element);
|
|
53
|
+
} else {
|
|
54
|
+
element.src = URL.createObjectURL(event.target.files[0]);
|
|
55
|
+
element.onload = function() {
|
|
56
|
+
URL.revokeObjectURL(element.src);
|
|
57
|
+
}
|
|
45
58
|
}
|
|
46
59
|
});
|
|
47
60
|
}
|
|
@@ -21,6 +21,7 @@ class Fluxbit::Form::UploadImageComponent < Fluxbit::Form::FieldComponent
|
|
|
21
21
|
# @param helper_popover_placement [String] Placement of the popover (default: "right")
|
|
22
22
|
# @param image_path [String] Path to the image to be displayed (optional)
|
|
23
23
|
# @param image_placeholder [String] Placeholder image path if no image is attached (optional)
|
|
24
|
+
# @param initials [String] Initials to display as placeholder (e.g., "JD" for John Doe) - overrides image_placeholder
|
|
24
25
|
# @param title [Boolean, String] Whether to show a title (true for default, false to hide, or custom string)
|
|
25
26
|
# @param rounded [Boolean] Whether to show image as circle (true, default) or square with rounded edges (false)
|
|
26
27
|
# @param class [String] Additional CSS classes for the input element
|
|
@@ -30,6 +31,7 @@ class Fluxbit::Form::UploadImageComponent < Fluxbit::Form::FieldComponent
|
|
|
30
31
|
@title = @props.delete(:title) || "Change"
|
|
31
32
|
@rounded = @props.delete(:rounded)
|
|
32
33
|
@rounded = true if @rounded.nil?
|
|
34
|
+
@initials = @props.delete(:initials)
|
|
33
35
|
@image_path = @props.delete(:image_path) ||
|
|
34
36
|
(if @object&.send(@attribute).respond_to?(:attached?) && @object&.send(@attribute)&.send("attached?")
|
|
35
37
|
@object&.send(@attribute)&.variant(resize_to_fit: [ 160, 160 ])
|
|
@@ -58,4 +60,51 @@ class Fluxbit::Form::UploadImageComponent < Fluxbit::Form::FieldComponent
|
|
|
58
60
|
def image_rounded_class
|
|
59
61
|
@rounded ? "rounded-full" : "rounded-lg"
|
|
60
62
|
end
|
|
63
|
+
|
|
64
|
+
def has_initials?
|
|
65
|
+
@initials.present?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def initials_element
|
|
69
|
+
return unless has_initials?
|
|
70
|
+
|
|
71
|
+
content_tag :div,
|
|
72
|
+
class: "img_photo_#{id} img_photo absolute inset-0 w-full h-full flex items-center justify-center #{image_rounded_class} #{initials_gradient_class}",
|
|
73
|
+
data: { initials_placeholder: true } do
|
|
74
|
+
content_tag :span, @initials.upcase, class: "text-white font-bold #{initials_text_size_class}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def initials_gradient_class
|
|
79
|
+
# Generate a consistent gradient based on the initials hash
|
|
80
|
+
gradient_index = @initials.sum { |c| c.ord } % gradient_options.length
|
|
81
|
+
gradient_options[gradient_index]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initials_text_size_class
|
|
85
|
+
# Smaller initials (1-2 chars) get larger text, longer ones get smaller text
|
|
86
|
+
case @initials.length
|
|
87
|
+
when 1..2
|
|
88
|
+
"text-4xl"
|
|
89
|
+
when 3
|
|
90
|
+
"text-3xl"
|
|
91
|
+
else
|
|
92
|
+
"text-2xl"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def gradient_options
|
|
97
|
+
[
|
|
98
|
+
"bg-gradient-to-br from-blue-500 to-purple-600",
|
|
99
|
+
"bg-gradient-to-br from-green-500 to-teal-600",
|
|
100
|
+
"bg-gradient-to-br from-pink-500 to-rose-600",
|
|
101
|
+
"bg-gradient-to-br from-orange-500 to-red-600",
|
|
102
|
+
"bg-gradient-to-br from-indigo-500 to-blue-600",
|
|
103
|
+
"bg-gradient-to-br from-purple-500 to-pink-600",
|
|
104
|
+
"bg-gradient-to-br from-cyan-500 to-blue-600",
|
|
105
|
+
"bg-gradient-to-br from-emerald-500 to-green-600",
|
|
106
|
+
"bg-gradient-to-br from-amber-500 to-orange-600",
|
|
107
|
+
"bg-gradient-to-br from-violet-500 to-purple-600"
|
|
108
|
+
]
|
|
109
|
+
end
|
|
61
110
|
end
|
|
@@ -19,6 +19,8 @@ class Fluxbit::GravatarComponent < Fluxbit::AvatarComponent
|
|
|
19
19
|
#
|
|
20
20
|
# @param [Hash] props The properties to customize the Gravatar.
|
|
21
21
|
# @option props [String] :email The email address associated with the Gravatar.
|
|
22
|
+
# @option props [String] :name The display name for the Gravatar (used with :initials and :color defaults).
|
|
23
|
+
# @option props [String] :initials Custom initials to display (used with :initials default).
|
|
22
24
|
# @option props [Symbol] :rating (:g) The rating of the Gravatar (:g, :pg, :r, :x).
|
|
23
25
|
# @option props [Boolean] :secure (true) Whether to use HTTPS for the Gravatar URL.
|
|
24
26
|
# @option props [Symbol] :filetype (:png) The filetype of the Gravatar (:png, :jpg, :gif).
|
|
@@ -34,7 +36,9 @@ class Fluxbit::GravatarComponent < Fluxbit::AvatarComponent
|
|
|
34
36
|
secure: options(@props.delete(:secure), default: true),
|
|
35
37
|
filetype: options((@props.delete(:filetype)|| "").to_sym, collection: gravatar_styles[:filetype], default: @@filetype),
|
|
36
38
|
default: options((@props.delete(:default)|| "").to_sym, collection: gravatar_styles[:default], default: @@default),
|
|
37
|
-
size: gravatar_styles[:size][options(@props[:size], collection: gravatar_styles[:size], default: @@size)]
|
|
39
|
+
size: gravatar_styles[:size][options(@props[:size], collection: gravatar_styles[:size], default: @@size)],
|
|
40
|
+
name: @props.delete(:name),
|
|
41
|
+
initials: @props.delete(:initials)
|
|
38
42
|
}
|
|
39
43
|
add class: gravatar_styles[:base], to: @props
|
|
40
44
|
@email = @props.delete(:email)
|
|
@@ -88,6 +92,8 @@ class Fluxbit::GravatarComponent < Fluxbit::AvatarComponent
|
|
|
88
92
|
case key
|
|
89
93
|
when :forcedefault
|
|
90
94
|
processed_options[key] = "y" if val
|
|
95
|
+
when :name, :initials
|
|
96
|
+
processed_options[key] = val if val.present?
|
|
91
97
|
else
|
|
92
98
|
processed_options[key] = val
|
|
93
99
|
end
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
module Fluxbit::Config::GravatarComponent
|
|
4
4
|
mattr_accessor :rating, default: :pg
|
|
5
5
|
mattr_accessor :filetype, default: :png
|
|
6
|
-
mattr_accessor :default, default: :robohash # options: 404, mp (mystery person), identicon, monsterid, wavatar, retro, robohash, blank
|
|
6
|
+
mattr_accessor :default, default: :robohash # options: 404, mp (mystery person), identicon, monsterid, wavatar, retro, robohash, blank, initials, color
|
|
7
7
|
|
|
8
8
|
# rubocop: disable Layout/LineLength, Metrics/BlockLength
|
|
9
9
|
mattr_accessor :gravatar_styles do
|
|
10
10
|
{
|
|
11
11
|
base: "bg-gray-200 dark:bg-gray-600",
|
|
12
|
-
default: %i[404 mp identicon monsterid wavatar retro robohash blank],
|
|
12
|
+
default: %i[404 mp identicon monsterid wavatar retro robohash blank initials color],
|
|
13
13
|
size: { xs: 30, sm: 40, md: 50, lg: 100, xl: 200 },
|
|
14
14
|
rating: %i[g pg r x],
|
|
15
15
|
filetype: %i[jpg jpeg gif png heic]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluxbit_view_components
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Arthur Molina
|
|
@@ -44,9 +44,6 @@ dependencies:
|
|
|
44
44
|
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
46
|
version: 3.0.0
|
|
47
|
-
- - "<"
|
|
48
|
-
- !ruby/object:Gem::Version
|
|
49
|
-
version: 4.0.0
|
|
50
47
|
type: :runtime
|
|
51
48
|
prerelease: false
|
|
52
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -54,9 +51,6 @@ dependencies:
|
|
|
54
51
|
- - ">="
|
|
55
52
|
- !ruby/object:Gem::Version
|
|
56
53
|
version: 3.0.0
|
|
57
|
-
- - "<"
|
|
58
|
-
- !ruby/object:Gem::Version
|
|
59
|
-
version: 4.0.0
|
|
60
54
|
- !ruby/object:Gem::Dependency
|
|
61
55
|
name: webdrivers
|
|
62
56
|
requirement: !ruby/object:Gem::Requirement
|