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
42
# 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?")
      attachment = @object.send(@attribute)
      attachment.variable? ? attachment.variant(resize_to_fit: [ 160, 160 ]) : attachment
     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



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

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

#gradient_optionsObject



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

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)


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

def has_initials?
  @initials.present?
end

#image_elementObject



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

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



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

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

#initials_elementObject



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

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



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

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



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

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



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

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