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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ff7c36152723efea00fcb464ac64ca6462b5f2a0f80cd7eab5298f5129bab1a
4
- data.tar.gz: aa51123027b44b8e2a268275c15ed192bcb8bc111f5ec82d1d9ad74597b3f0c1
3
+ metadata.gz: bd7bed7240f33dbb0940a142d872dc031c7ad7bd2f065f1051ef2b2eb5dd4abe
4
+ data.tar.gz: dad11a6840d1835cbf7f7c2ff03d37bf70f1d1bc708c00785bf0b0e09f954796
5
5
  SHA512:
6
- metadata.gz: 2051c7d64576f3a0f8996475e184b164adc767241c52e33837472b7a28f011a2fe5e67fc86ad122599a7679dd252a019834489a795fae7b4bb558f4a444200d5
7
- data.tar.gz: 5d62cc33db45e466341d46fbef8c35b128c4c16d8311a66ec0052a7133e4d7a344527577c66df08a609a48fa142e051a952dda15f041bada8c2ecc54919706a0
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="mt-6 grow lg:mt-0 lg:ml-6 lg:shrink-0 lg:grow-0">
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="inline-block h-40 w-40 shrink-0 overflow-hidden <%= container_rounded_class %> relative" aria-hidden="true">
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 h-full w-full items-center justify-center bg-blue-800/75 text-sm font-medium text-white opacity-0 hover:opacity-100">
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 images = document.querySelectorAll('.img_photo_' + id);
39
+ const elements = document.querySelectorAll('.img_photo_' + id);
40
40
  if (event.target.files && event.target.files[0]) {
41
- images.forEach(function(img) {
42
- img.src = URL.createObjectURL(event.target.files[0]);
43
- img.onload = function() {
44
- URL.revokeObjectURL(img.src);
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]
@@ -1,5 +1,5 @@
1
1
  module Fluxbit
2
2
  module ViewComponents
3
- VERSION = "0.5.1"
3
+ VERSION = "0.5.2"
4
4
  end
5
5
  end
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.1
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