flowbite-components 0.3.0 → 0.4.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -2
  3. data/README.md +3 -5
  4. data/app/components/flowbite/alert/alert.html.erb +36 -0
  5. data/app/components/flowbite/alert/icon.rb +53 -0
  6. data/app/components/flowbite/alert.rb +156 -0
  7. data/app/components/flowbite/avatar/avatar.html.erb +23 -0
  8. data/app/components/flowbite/avatar/dot.rb +85 -0
  9. data/app/components/flowbite/avatar/placeholder_icon.html.erb +13 -0
  10. data/app/components/flowbite/avatar/placeholder_icon.rb +44 -0
  11. data/app/components/flowbite/avatar.rb +132 -0
  12. data/app/components/flowbite/badge/badge.html.erb +4 -1
  13. data/app/components/flowbite/card.rb +4 -8
  14. data/app/components/flowbite/input_field/input_field.html.erb +1 -0
  15. data/app/components/flowbite/pagination/chevron_left_icon.rb +34 -0
  16. data/app/components/flowbite/pagination/chevron_right_icon.rb +34 -0
  17. data/app/components/flowbite/pagination/gap.rb +24 -0
  18. data/app/components/flowbite/pagination/link.rb +52 -0
  19. data/app/components/flowbite/pagination/next_link.rb +67 -0
  20. data/app/components/flowbite/pagination/pagination.html.erb +11 -0
  21. data/app/components/flowbite/pagination/previous_link.rb +67 -0
  22. data/app/components/flowbite/pagination.rb +63 -0
  23. data/app/components/flowbite/progress/progress.html.erb +14 -0
  24. data/app/components/flowbite/progress.rb +163 -0
  25. data/app/components/flowbite/rating/rating.html.erb +13 -0
  26. data/app/components/flowbite/rating/star.html.erb +13 -0
  27. data/app/components/flowbite/rating/star.rb +59 -0
  28. data/app/components/flowbite/rating.rb +64 -0
  29. data/app/components/flowbite/spinner/spinner.html.erb +20 -0
  30. data/app/components/flowbite/spinner.rb +66 -0
  31. data/app/components/flowbite/toast/close_button.html.erb +17 -0
  32. data/app/components/flowbite/toast/close_button.rb +32 -0
  33. data/app/components/flowbite/toast/icon.html.erb +8 -2
  34. data/app/components/flowbite/toast/toast.html.erb +1 -28
  35. data/app/components/flowbite/toast.rb +39 -1
  36. data/lib/flowbite/components/version.rb +1 -1
  37. metadata +32 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2df1ff6599a8e3fa6a41cd9b6329654d3ebb532eae460f37dceb1c8e9b3e0be5
4
- data.tar.gz: 33362285ce24f76a7490f646dffb524a66f3c44c584e8da5d66abad27a74f809
3
+ metadata.gz: a29d44c915146870abbd45cd6a839a0948877dfdf8590fed7eef8e528a382964
4
+ data.tar.gz: fbe0bc1142849ec153628cb781776ddea678f5391bd42ab7f71ba891174dbd4f
5
5
  SHA512:
6
- metadata.gz: 9968e1c9ad9230e73475ddc85d1069395444700af804f5712b8f3bef027fd4744b3eec136cd3edc737f947aaf478b5fa22279ed3f9494735684c8d66e93690c4
7
- data.tar.gz: 3d3f420dbf18ceb93de989ea5818aff5551279cc29e11e4c326ccb2148ca76dfaf8c451571c911c0149ff129f772d674752ec7b126ece767bd7f34d3b1a43503
6
+ metadata.gz: fd37a866269767b5607d75453cacf38d4832dbdd82b5097a18531d7f576b8849b335f48a6e7ce743aa1b3251c40baa316379780299564213b2d02ddb7461705f
7
+ data.tar.gz: 83f821ca6081890355483066c64308c3388c783785da725a1546390404528d5a5478ea642facb7fca627eb61a13c4fbd85939343f9f94ab043d32fb003d5fb4a
data/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project adheres to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## [0.4.0]
7
+
8
+ ### Added
9
+
10
+ - Avatar component, with image, initials and placeholder icon fallbacks, sizes, shapes, border and status dot
11
+ - Spinner component
12
+ - Progress component
13
+ - Pagination component
14
+ - Rating component, including `Flowbite::Rating::Star` for the individual stars
15
+ - `Flowbite::Toast::CloseButton` component for the close button of toasts
16
+ - `Flowbite::Toast` accepts `button: {options: {...}}` for passing HTML options, e.g. data attributes, to the default close button, or a `button` slot for rendering your own
17
+ - Alert component
18
+
19
+ ### Fixed
20
+
21
+ - `Flowbite::Card` no longer renders an empty `h5` element when card title is blank.
22
+
6
23
  ## [0.3.0]
7
24
 
8
25
  ### Added
@@ -10,8 +27,6 @@ This project adheres to [Semantic Versioning](http://semver.org/).
10
27
  * Badge component.
11
28
  * Sidebar component.
12
29
 
13
- ### Changed
14
-
15
30
  ### Fixed
16
31
 
17
32
  * `:class` arguments to subcomponents (ie `hint` and `input`) of Flowbite::InputField are now forwarded correctly. If passed as `:class` the given value is added to the existing class names, if passed in `options[:class]` the existing class attribute is replaced.
data/README.md CHANGED
@@ -272,7 +272,7 @@ bundle exec rake test
272
272
  To check code style:
273
273
 
274
274
  ```bash
275
- bundle exec rake standard
275
+ bundle exec rake lint
276
276
  ```
277
277
 
278
278
  To install this gem onto your local machine:
@@ -285,10 +285,8 @@ bundle exec rake install
285
285
 
286
286
  This library includes a demo application with previews for all components. To view them:
287
287
 
288
- 1. cd demo
289
- 2. Run `bundle && npm install`
290
- 3. Run `rails server`
291
- 4. Visit `http://localhost:3000/lookbook`
288
+ 1. Run `./demo/run` from the project root.
289
+ 2. Visit `http://localhost:3000/lookbook`
292
290
 
293
291
  ## Contributing
294
292
 
@@ -0,0 +1,36 @@
1
+ <%= tag.div(
2
+ class: container_classes.join(" "),
3
+ role: "alert",
4
+ **options,
5
+ ) do %>
6
+ <% if additional_content? %>
7
+ <% if icon? || title? %>
8
+ <div class="flex items-center">
9
+ <% if icon? %>
10
+ <%= render Flowbite::Alert::Icon.new(class: icon_classes) %>
11
+ <span class="sr-only"><%= style_label %></span>
12
+ <% end %>
13
+
14
+ <% if title? %>
15
+ <h3 class="font-medium"><%= title %></h3>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+ <% if content.present? %>
20
+ <div class="mt-2 mb-4"><%= content %></div>
21
+ <% end %>
22
+ <%= additional_content %>
23
+ <% elsif icon? %>
24
+ <%= render Flowbite::Alert::Icon.new(class: icon_classes) %>
25
+ <span class="sr-only"><%= style_label %></span>
26
+ <div>
27
+ <% if title? %>
28
+ <span class="font-medium me-1"><%= title %></span>
29
+ <% end %><%= content %>
30
+ </div>
31
+ <% else %>
32
+ <% if title? %>
33
+ <span class="font-medium"><%= title %></span>
34
+ <% end %><%= content %>
35
+ <% end %>
36
+ <% end %>
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Alert
5
+ # Renders the info icon shown inside an alert.
6
+ #
7
+ # Flowbite uses the same outlined info icon for all alert styles; the
8
+ # icon inherits its color from the alert via +currentColor+.
9
+ #
10
+ # @param class [String, Array<String>] Additional CSS classes for the svg
11
+ # element.
12
+ #
13
+ # @see https://flowbite.com/docs/components/alerts/
14
+ class Icon < ViewComponent::Base
15
+ SVG_PATH = "M10 11h2v5m-2 0h4m-2.592-8.5h.01M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
16
+
17
+ class << self
18
+ def classes
19
+ ["w-4", "h-4", "shrink-0"]
20
+ end
21
+ end
22
+
23
+ def initialize(class: nil)
24
+ @class = Array.wrap(binding.local_variable_get(:class))
25
+ end
26
+
27
+ def call
28
+ tag.svg(
29
+ tag.path(
30
+ d: svg_path,
31
+ stroke: "currentColor",
32
+ "stroke-linecap": "round",
33
+ "stroke-linejoin": "round",
34
+ "stroke-width": "2"
35
+ ),
36
+ "aria-hidden": "true",
37
+ class: svg_classes,
38
+ fill: "none",
39
+ viewBox: "0 0 24 24",
40
+ xmlns: "http://www.w3.org/2000/svg"
41
+ )
42
+ end
43
+
44
+ def svg_classes
45
+ self.class.classes + @class
46
+ end
47
+
48
+ def svg_path
49
+ SVG_PATH
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ # Renders an alert element for showing feedback messages to the user.
5
+ #
6
+ # The block given to the alert is used as its message.
7
+ #
8
+ # @example Usage
9
+ # <%= render(Flowbite::Alert.new) { "Something has happened!" } %>
10
+ #
11
+ # @example With title and style
12
+ # <%= render(Flowbite::Alert.new(style: :danger, title: "Danger alert!")) do %>
13
+ # Change a few things up and try submitting again.
14
+ # <% end %>
15
+ #
16
+ # @example With a list
17
+ # <%= render(Flowbite::Alert.new(title: "Ensure that these requirements are met:")) do %>
18
+ # <ul class="mt-2 list-disc list-outside space-y-1 ps-2.5">
19
+ # <li>At least 10 characters</li>
20
+ # </ul>
21
+ # <% end %>
22
+ #
23
+ # @example With additional content
24
+ # <%= render(Flowbite::Alert.new(bordered: true, title: "This is an info alert")) do |alert| %>
25
+ # <% alert.with_additional_content do %>
26
+ # <%= render(Flowbite::Button.new(size: :xs)) { "View more" } %>
27
+ # <% end %>
28
+ # More info about this alert.
29
+ # <% end %>
30
+ #
31
+ # @viewcomponent_slot additional_content Content rendered below the
32
+ # message, for example action buttons. When given, the title is rendered
33
+ # as a heading next to the icon and the message below it.
34
+ #
35
+ # @see https://flowbite.com/docs/components/alerts/
36
+ # @lookbook_embed AlertPreview
37
+ class Alert < ViewComponent::Base
38
+ renders_one :additional_content
39
+
40
+ class << self
41
+ # @return [Array<String>] The color classes for the given style and state.
42
+ def classes(state: :default, style: :info)
43
+ styles.fetch(style).fetch(state)
44
+ end
45
+
46
+ # rubocop:disable Layout/LineLength
47
+ def styles
48
+ Flowbite::Styles.from_hash({
49
+ danger: {
50
+ border: ["border-danger-subtle"],
51
+ default: ["bg-danger-soft", "text-fg-danger-strong"]
52
+ },
53
+ dark: {
54
+ border: ["border-default-medium"],
55
+ default: ["bg-neutral-secondary-medium", "text-heading"]
56
+ },
57
+ info: {
58
+ border: ["border-brand-subtle"],
59
+ default: ["bg-brand-softer", "text-fg-brand-strong"]
60
+ },
61
+ success: {
62
+ border: ["border-success-subtle"],
63
+ default: ["bg-success-soft", "text-fg-success-strong"]
64
+ },
65
+ warning: {
66
+ border: ["border-warning-subtle"],
67
+ default: ["bg-warning-soft", "text-fg-warning"]
68
+ }
69
+ }.freeze)
70
+ end
71
+ # rubocop:enable Layout/LineLength
72
+ end
73
+
74
+ attr_reader :options, :style, :title
75
+
76
+ # @param border_accent [Boolean] Whether to show a thick top border
77
+ # accent instead of rounded corners (default: false).
78
+ # @param bordered [Boolean] Whether to add a border in the color of the
79
+ # style (default: false).
80
+ # @param class [String, Array<String>] Additional CSS classes for the
81
+ # alert container.
82
+ # @param icon [Boolean] Whether to show an info icon (default: true).
83
+ # @param options [Hash] Additional HTML options for the alert container.
84
+ # @param style [Symbol] The color style of the alert (:danger, :dark,
85
+ # :info, :success, :warning).
86
+ # @param title [String] An optional bold title shown before the message.
87
+ def initialize(border_accent: false, bordered: false, class: nil,
88
+ icon: true, style: :info, title: nil, **options)
89
+ @border_accent = border_accent
90
+ @bordered = bordered
91
+ @class = Array.wrap(binding.local_variable_get(:class))
92
+ @icon = icon
93
+ @options = options
94
+ @style = style
95
+ @title = title
96
+ end
97
+
98
+ def border_accent?
99
+ !!@border_accent
100
+ end
101
+
102
+ def bordered?
103
+ !!@bordered
104
+ end
105
+
106
+ def container_classes
107
+ result = ["p-4", "text-sm"]
108
+ result += layout_classes
109
+ result += self.class.classes(style: style)
110
+ result += border_classes
111
+ result += ["rounded-base"] unless border_accent?
112
+ result + @class
113
+ end
114
+
115
+ # @return [Array<String>] The CSS classes for the icon in the current
116
+ # layout.
117
+ def icon_classes
118
+ if additional_content?
119
+ ["me-2"]
120
+ else
121
+ ["me-2", "mt-0.5"]
122
+ end
123
+ end
124
+
125
+ def icon?
126
+ !!@icon
127
+ end
128
+
129
+ # @return [String] The screen reader label describing the alert style.
130
+ def style_label
131
+ style.to_s.capitalize
132
+ end
133
+
134
+ def title?
135
+ title.present?
136
+ end
137
+
138
+ private
139
+
140
+ def border_classes
141
+ if border_accent?
142
+ ["border-t-4"] + self.class.classes(state: :border, style: style)
143
+ elsif bordered?
144
+ ["border"] + self.class.classes(state: :border, style: style)
145
+ else
146
+ []
147
+ end
148
+ end
149
+
150
+ def layout_classes
151
+ return [] if additional_content? || !icon?
152
+
153
+ ["flex", "items-start"]
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,23 @@
1
+ <% avatar = capture do %>
2
+ <% if image? %>
3
+ <%= tag.img(alt: alt, class: image_classes, src: src, **options) %>
4
+ <% elsif initials? %>
5
+ <%= tag.div(class: initials_classes, **options) do %>
6
+ <span class="font-medium text-body"><%= initials %></span>
7
+ <% end %>
8
+ <% else %>
9
+ <%= tag.div(class: placeholder_classes, **options) do %>
10
+ <%= render(Flowbite::Avatar::PlaceholderIcon.new(size: size)) %>
11
+ <% end %>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <% if dot? %>
16
+ <div class="relative flex h-fit w-fit">
17
+ <%= avatar %>
18
+ <%= top_dot %>
19
+ <%= bottom_dot %>
20
+ </div>
21
+ <% else %>
22
+ <%= avatar %>
23
+ <% end %>
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Avatar
5
+ # Renders a status dot indicator positioned on top of an avatar.
6
+ #
7
+ # Usually added through the +top_dot+ or +bottom_dot+ slots of
8
+ # Flowbite::Avatar, which set the position and size. When rendered on its
9
+ # own, the dot must be placed inside a relatively positioned container
10
+ # together with the avatar.
11
+ #
12
+ # @example Through an Avatar slot
13
+ # <%= render(Flowbite::Avatar.new(src: user.avatar_url)) do |avatar| %>
14
+ # <% avatar.with_top_dot(label: "Online", style: :success) %>
15
+ # <% end %>
16
+ #
17
+ # @example Standalone
18
+ # <div class="relative">
19
+ # <%= render(Flowbite::Avatar.new(src: user.avatar_url)) %>
20
+ # <%= render(Flowbite::Avatar::Dot.new(label: "Online", position: :bottom, style: :success)) %>
21
+ # </div>
22
+ #
23
+ # @see https://flowbite.com/docs/components/avatar/
24
+ class Dot < ViewComponent::Base
25
+ POSITIONS = {
26
+ bottom: ["bottom-0"],
27
+ top: ["top-0"]
28
+ }.freeze
29
+
30
+ # Horizontal offsets placing the dot at the right edge of an avatar of
31
+ # the given size.
32
+ SIZES = {
33
+ xs: ["left-1.5"],
34
+ sm: ["left-3"],
35
+ base: ["left-5"],
36
+ default: ["left-7"],
37
+ lg: ["left-8"],
38
+ xl: ["left-11"],
39
+ "2xl": ["left-13"]
40
+ }.freeze
41
+
42
+ class << self
43
+ def classes(position: :top, size: :default, style: :success)
44
+ POSITIONS.fetch(position) + sizes.fetch(size) +
45
+ ["absolute", "w-3.5", "h-3.5"] +
46
+ styles.fetch(style).fetch(:default) +
47
+ ["border-2", "border-buffer", "rounded-full"]
48
+ end
49
+
50
+ def sizes
51
+ SIZES
52
+ end
53
+
54
+ def styles
55
+ Flowbite::Styles.from_hash(
56
+ {
57
+ danger: {default: ["bg-danger"]},
58
+ success: {default: ["bg-success"]}
59
+ }.freeze
60
+ )
61
+ end
62
+ end
63
+
64
+ attr_reader :label, :position, :size, :style
65
+
66
+ # @param label [String] Text describing the status for screen readers,
67
+ # since the dot otherwise only conveys it through color.
68
+ # @param position [Symbol] Where to place the dot (:bottom, :top).
69
+ # @param size [Symbol] The size of the avatar the dot is placed on.
70
+ # @param style [Symbol] The color of the dot (:danger, :success).
71
+ def initialize(label: nil, position: :top, size: :default, style: :success)
72
+ @label = label
73
+ @position = position
74
+ @size = size
75
+ @style = style
76
+ end
77
+
78
+ def call
79
+ content_tag(:span, class: self.class.classes(position: position, size: size, style: style)) do
80
+ content_tag(:span, label, class: "sr-only") if label.present?
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,13 @@
1
+ <svg
2
+ aria-hidden="true"
3
+ class="<%= classes.join(" ") %>"
4
+ fill="currentColor"
5
+ viewBox="0 0 20 20"
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ >
8
+ <path
9
+ clip-rule="evenodd"
10
+ d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
11
+ fill-rule="evenodd"
12
+ />
13
+ </svg>
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Avatar
5
+ # Renders the person icon shown in an avatar without an image or
6
+ # initials.
7
+ #
8
+ # @see https://flowbite.com/docs/components/avatar/
9
+ class PlaceholderIcon < ViewComponent::Base
10
+ # The icon is slightly larger than the avatar and offset to the left,
11
+ # so the person is centered and cropped by the container.
12
+ SIZES = {
13
+ xs: ["w-5.5", "h-5.5", "-left-0.5"],
14
+ sm: ["w-7", "h-7", "-left-0.5"],
15
+ base: ["w-10", "h-10", "-left-1"],
16
+ default: ["w-12", "h-12", "-left-1"],
17
+ lg: ["w-13", "h-13", "-left-1"],
18
+ xl: ["w-17", "h-17", "-left-1.5"],
19
+ "2xl": ["w-19", "h-19", "-left-1.5"]
20
+ }.freeze
21
+
22
+ class << self
23
+ def classes(size: :default)
24
+ ["absolute"] + sizes.fetch(size) + ["text-body-subtle"]
25
+ end
26
+
27
+ def sizes
28
+ SIZES
29
+ end
30
+ end
31
+
32
+ attr_reader :size
33
+
34
+ # @param size [Symbol] The size of the avatar the icon is placed in.
35
+ def initialize(size: :default)
36
+ @size = size
37
+ end
38
+
39
+ def classes
40
+ self.class.classes(size: size)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ # Renders an avatar representing a user.
5
+ #
6
+ # The avatar shows an image when +src+ is given. Without an image it falls
7
+ # back to the given +initials+, and without initials it renders a
8
+ # placeholder person icon.
9
+ #
10
+ # @example Image
11
+ # <%= render(Flowbite::Avatar.new(alt: "Jese Leos", src: user.avatar_url)) %>
12
+ #
13
+ # @example Initials with a rounded square shape
14
+ # <%= render(Flowbite::Avatar.new(initials: "JL", shape: :rounded)) %>
15
+ #
16
+ # @example Placeholder icon with a status dot
17
+ # <%= render(Flowbite::Avatar.new) do |avatar| %>
18
+ # <% avatar.with_bottom_dot(label: "Online", style: :success) %>
19
+ # <% end %>
20
+ #
21
+ # @viewcomponent_slot [Flowbite::Avatar::Dot] bottom_dot A status dot placed
22
+ # at the bottom of the avatar. Use +with_bottom_dot+ to add one.
23
+ # @viewcomponent_slot [Flowbite::Avatar::Dot] top_dot A status dot placed at
24
+ # the top of the avatar. Use +with_top_dot+ to add one.
25
+ #
26
+ # @see https://flowbite.com/docs/components/avatar/
27
+ # @lookbook_embed AvatarPreview
28
+ class Avatar < ViewComponent::Base
29
+ renders_one :bottom_dot, ->(**options) { Flowbite::Avatar::Dot.new(position: :bottom, size: size, **options) }
30
+ renders_one :top_dot, ->(**options) { Flowbite::Avatar::Dot.new(position: :top, size: size, **options) }
31
+
32
+ BORDERED_CLASSES = ["p-1", "ring-2", "ring-default"].freeze
33
+
34
+ INITIALS_CLASSES = ["relative", "inline-flex", "items-center", "justify-center", "overflow-hidden", "bg-neutral-tertiary"].freeze
35
+
36
+ PLACEHOLDER_CLASSES = ["relative", "overflow-hidden", "bg-neutral-secondary-medium"].freeze
37
+
38
+ SIZES = {
39
+ xs: ["w-4.5", "h-4.5"],
40
+ sm: ["w-6", "h-6"],
41
+ base: ["w-8", "h-8"],
42
+ default: ["w-10", "h-10"],
43
+ lg: ["w-11", "h-11"],
44
+ xl: ["w-14", "h-14"],
45
+ "2xl": ["w-16", "h-16"]
46
+ }.freeze
47
+
48
+ class << self
49
+ def classes(bordered: false, shape: :circle, size: :default)
50
+ result = sizes.fetch(size) + shape_classes(shape: shape, size: size)
51
+ result += BORDERED_CLASSES if bordered
52
+ result
53
+ end
54
+
55
+ # @return [Array<String>] The classes defining the corners of the
56
+ # avatar. Small rounded avatars get smaller corners.
57
+ def shape_classes(shape: :circle, size: :default)
58
+ case shape
59
+ when :circle then ["rounded-full"]
60
+ when :rounded then [:xs, :sm].include?(size) ? ["rounded-sm"] : ["rounded-base"]
61
+ else raise ArgumentError, "Unknown shape: #{shape}. Available shapes: circle, rounded"
62
+ end
63
+ end
64
+
65
+ def sizes
66
+ SIZES
67
+ end
68
+ end
69
+
70
+ attr_reader :alt, :initials, :options, :size, :src
71
+
72
+ # @param alt [String] Alternative text for the image. Defaults to an
73
+ # empty string, marking the image as decorative.
74
+ # @param bordered [Boolean] Whether to add a ring around the avatar.
75
+ # @param class [String, Array<String>] Additional CSS classes for the
76
+ # avatar element.
77
+ # @param initials [String] Initials to show when there is no image.
78
+ # @param options [Hash] Additional HTML options for the avatar element.
79
+ # @param shape [Symbol] The shape of the avatar (:circle, :rounded).
80
+ # @param size [Symbol] The size of the avatar (:xs, :sm, :base, :default,
81
+ # :lg, :xl, :"2xl").
82
+ # @param src [String] The URL of the avatar image. When blank, the avatar
83
+ # falls back to initials or a placeholder icon.
84
+ def initialize(alt: nil, bordered: false, class: nil, initials: nil, shape: :circle, size: :default, src: nil, **options)
85
+ @alt = alt.to_s
86
+ @bordered = bordered
87
+ @class = Array.wrap(binding.local_variable_get(:class))
88
+ @initials = initials
89
+ @shape = shape
90
+ @size = size
91
+ @src = src
92
+ @options = options
93
+ end
94
+
95
+ def bordered?
96
+ !!@bordered
97
+ end
98
+
99
+ def dot?
100
+ top_dot? || bottom_dot?
101
+ end
102
+
103
+ def image?
104
+ @src.present?
105
+ end
106
+
107
+ # @return [Array<String>] The classes for the image element.
108
+ def image_classes
109
+ classes + @class
110
+ end
111
+
112
+ def initials?
113
+ @initials.present?
114
+ end
115
+
116
+ # @return [Array<String>] The classes for the initials container.
117
+ def initials_classes
118
+ INITIALS_CLASSES + classes + @class
119
+ end
120
+
121
+ # @return [Array<String>] The classes for the placeholder icon container.
122
+ def placeholder_classes
123
+ PLACEHOLDER_CLASSES + classes + @class
124
+ end
125
+
126
+ private
127
+
128
+ def classes
129
+ self.class.classes(bordered: bordered?, shape: @shape, size: @size)
130
+ end
131
+ end
132
+ end
@@ -1,4 +1,7 @@
1
1
  <%= content_tag(tag_name, **tag_options) do %>
2
- <% if dot? %><%= render(Flowbite::Badge::Dot.new(style: @style)) %><% end %>
2
+ <% if dot? %>
3
+ <%= render(Flowbite::Badge::Dot.new(style: @style)) %>
4
+ <% end %>
5
+
3
6
  <%= content %>
4
7
  <% end %>
@@ -70,14 +70,10 @@ module Flowbite
70
70
 
71
71
  # Returns the HTML to use for the title element if any
72
72
  def default_title
73
- component = Flowbite::Card::Title.new(**default_title_options)
74
-
75
- if default_title_content
76
- component.with_content(default_title_content)
77
- else
78
- component
79
- end
73
+ return unless title?
80
74
 
75
+ component = Flowbite::Card::Title.new(**default_title_options)
76
+ component.with_content(default_title_content)
81
77
  render(component)
82
78
  end
83
79
 
@@ -94,7 +90,7 @@ module Flowbite
94
90
  end
95
91
 
96
92
  def title?
97
- @title.present?
93
+ default_title_content.present?
98
94
  end
99
95
  end
100
96
  end
@@ -2,6 +2,7 @@
2
2
  <%= label %>
3
3
  <%= input %>
4
4
  <%= hint %>
5
+
5
6
  <% errors.each do |error| %>
6
7
  <%= render(Flowbite::Input::ValidationError.new) { error.upcase_first } %>
7
8
  <% end %>