Class: Fluxbit::Form::UploadImageComponent

Inherits:
FieldComponent
  • Object
show all
Defined in:
app/components/fluxbit/form/upload_image_component.rb

Overview

The ‘Fluxbit::Form::UploadImageComponent` renders a stylized image upload field with live preview, drag-and-drop UI, support for both mobile and desktop layouts, labels, helper text, and integration with Rails form builders and Active Storage attachments. It provides custom title/subtitle, placeholder, and image preview, and is fully configurable via props.

Examples:

Basic usage

= render Fluxbit::Form::UploadImageComponent.new(attribute: :avatar, label: "Profile photo")

See Also:

  • For detailed documentation and examples.

Instance Method Summary collapse

Constructor Details

#initialize(**props) ⇒ UploadImageComponent

Initializes the upload image component with the given properties.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    The form builder (optional, for Rails forms)

  • attribute (Symbol)

    The model attribute to be used in the form (required if using form builder)

  • id (String)

    The id of the input element (optional)

  • label (String)

    The label for the input field (optional)

  • help_text (String)

    Additional help text for the input field (optional)

  • helper_popover (String)

    Content for a popover helper (optional)

  • helper_popover_placement (String)

    Placement of the popover (default: “right”)

  • image_path (String)

    Path to the image to be displayed (optional)

  • image_placeholder (String)

    Placeholder image path if no image is attached (optional)

  • initials (String)

    Initials to display as placeholder (e.g., “JD” for John Doe) - overrides image_placeholder

  • title (Boolean, String)

    Whether to show a title (true for default, false to hide, or custom string)

  • rounded (Boolean)

    Whether to show image as circle (true, default) or square with rounded edges (false)

  • class (String)

    Additional CSS classes for the input element

  • ...

    any other HTML attribute supported by file_field_tag



29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'app/components/fluxbit/form/upload_image_component.rb', line 29

def initialize(**props)
  super(**props)
  @title = @props.delete(:title) || "Change"
  @rounded = @props.delete(:rounded)
  @rounded = true if @rounded.nil?
  @initials = @props.delete(:initials)
  @image_path = @props.delete(:image_path) ||
    (if @object&.send(@attribute).respond_to?(:attached?) && @object&.send(@attribute)&.send("attached?")
      @object&.send(@attribute)&.variant(resize_to_fit: [ 160, 160 ])
     end) || @props.delete(:image_placeholder) || ""

  @props["class"] = "absolute inset-0 h-full w-full cursor-pointer rounded-md border-gray-300 opacity-0"
end

Instance Method Details

#container_rounded_classObject



56
57
58
# File 'app/components/fluxbit/form/upload_image_component.rb', line 56

def container_rounded_class
  @rounded ? "rounded-full" : "rounded-lg"
end

#gradient_optionsObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'app/components/fluxbit/form/upload_image_component.rb', line 96

def gradient_options
  [
    "bg-gradient-to-br from-blue-500 to-purple-600",
    "bg-gradient-to-br from-green-500 to-teal-600",
    "bg-gradient-to-br from-pink-500 to-rose-600",
    "bg-gradient-to-br from-orange-500 to-red-600",
    "bg-gradient-to-br from-indigo-500 to-blue-600",
    "bg-gradient-to-br from-purple-500 to-pink-600",
    "bg-gradient-to-br from-cyan-500 to-blue-600",
    "bg-gradient-to-br from-emerald-500 to-green-600",
    "bg-gradient-to-br from-amber-500 to-orange-600",
    "bg-gradient-to-br from-violet-500 to-purple-600"
  ]
end

#has_initials?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'app/components/fluxbit/form/upload_image_component.rb', line 64

def has_initials?
  @initials.present?
end

#image_elementObject



50
51
52
53
54
# File 'app/components/fluxbit/form/upload_image_component.rb', line 50

def image_element
  image_tag @image_path,
            class: "img_photo_#{id} img_photo absolute inset-0 w-full h-full object-cover #{image_rounded_class}",
            alt: @attribute&.to_s&.humanize
end

#image_rounded_classObject



60
61
62
# File 'app/components/fluxbit/form/upload_image_component.rb', line 60

def image_rounded_class
  @rounded ? "rounded-full" : "rounded-lg"
end

#initials_elementObject



68
69
70
71
72
73
74
75
76
# File 'app/components/fluxbit/form/upload_image_component.rb', line 68

def initials_element
  return unless has_initials?

   :div,
              class: "img_photo_#{id} img_photo absolute inset-0 w-full h-full flex items-center justify-center #{image_rounded_class} #{initials_gradient_class}",
              data: { initials_placeholder: true } do
     :span, @initials.upcase, class: "text-white font-bold #{initials_text_size_class}"
  end
end

#initials_gradient_classObject



78
79
80
81
82
# File 'app/components/fluxbit/form/upload_image_component.rb', line 78

def initials_gradient_class
  # Generate a consistent gradient based on the initials hash
  gradient_index = @initials.sum { |c| c.ord } % gradient_options.length
  gradient_options[gradient_index]
end

#initials_text_size_classObject



84
85
86
87
88
89
90
91
92
93
94
# File 'app/components/fluxbit/form/upload_image_component.rb', line 84

def initials_text_size_class
  # Smaller initials (1-2 chars) get larger text, longer ones get smaller text
  case @initials.length
  when 1..2
    "text-4xl"
  when 3
    "text-3xl"
  else
    "text-2xl"
  end
end

#input_element(input_id: nil) ⇒ Object



43
44
45
46
47
48
# File 'app/components/fluxbit/form/upload_image_component.rb', line 43

def input_element(input_id: nil)
  @props["onchange"] = "loadFile(event, '#{id}')"
  return file_field_tag @name, @props.merge(id: input_id || id) if @form.nil?

  @form.file_field(@attribute, **@props, id: input_id || id)
end