flowbite-components 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ca94dfc5af1c662f4a7cfb77f038f60402daf411673078c30b77672280c6055
4
- data.tar.gz: 60ad1e86847bd59c9b8ba598d44562cbd8f24776b9e696bc55e60550da9cfc0b
3
+ metadata.gz: 2df1ff6599a8e3fa6a41cd9b6329654d3ebb532eae460f37dceb1c8e9b3e0be5
4
+ data.tar.gz: 33362285ce24f76a7490f646dffb524a66f3c44c584e8da5d66abad27a74f809
5
5
  SHA512:
6
- metadata.gz: 2676a2b3da22cae60d35793a71d2e24637edb9cd61f5d3096c95352b1f6426d3e1116d124a474f05fa5198f4ce7935b1f0499f1ee82eb756101a9229a1ecf6bc
7
- data.tar.gz: 18fc7aaad24ffad2d9ec01a5ae772bf0b7194a24d3d91800a535fa3b3fd22017f1fac025791ff59a4a6de249d931abf2d30d16e88e3e1f50e78fc04d747a9899
6
+ metadata.gz: 9968e1c9ad9230e73475ddc85d1069395444700af804f5712b8f3bef027fd4744b3eec136cd3edc737f947aaf478b5fa22279ed3f9494735684c8d66e93690c4
7
+ data.tar.gz: 3d3f420dbf18ceb93de989ea5818aff5551279cc29e11e4c326ccb2148ca76dfaf8c451571c911c0149ff129f772d674752ec7b126ece767bd7f34d3b1a43503
data/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
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.3.0]
7
+
8
+ ### Added
9
+
10
+ * Badge component.
11
+ * Sidebar component.
12
+
13
+ ### Changed
14
+
15
+ ### Fixed
16
+
17
+ * `: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.
18
+
19
+
6
20
  ## [0.2.0]
7
21
 
8
22
  ### Added
@@ -0,0 +1,4 @@
1
+ <%= content_tag(tag_name, **tag_options) do %>
2
+ <% if dot? %><%= render(Flowbite::Badge::Dot.new(style: @style)) %><% end %>
3
+ <%= content %>
4
+ <% end %>
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Badge
5
+ # Renders a colored dot indicator for use inside a badge.
6
+ #
7
+ # @param style [Symbol] The color style of the dot (:alternative, :brand,
8
+ # :danger, :gray, :success, :warning).
9
+ class Dot < ViewComponent::Base
10
+ CLASSES = {
11
+ alternative: ["bg-heading", "me-1", "rounded-full"],
12
+ brand: ["bg-fg-brand-strong", "me-1", "rounded-full"],
13
+ danger: ["bg-fg-danger-strong", "me-1", "rounded-full"],
14
+ gray: ["bg-heading", "me-1", "rounded-full"],
15
+ success: ["bg-fg-success-strong", "me-1", "rounded-full"],
16
+ warning: ["bg-fg-warning", "me-1", "rounded-full"]
17
+ }.freeze
18
+
19
+ SIZES = {
20
+ default: ["h-1.5", "w-1.5"]
21
+ }.freeze
22
+
23
+ class << self
24
+ def classes(size: :default, style: :brand)
25
+ CLASSES.fetch(style) + sizes.fetch(size)
26
+ end
27
+
28
+ def sizes
29
+ SIZES
30
+ end
31
+ end
32
+
33
+ attr_reader :size, :style
34
+
35
+ def initialize(size: :default, style: :brand)
36
+ @size = size
37
+ @style = style
38
+ end
39
+
40
+ def call
41
+ content_tag(:span, nil, class: self.class.classes(size: size, style: style))
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Badge
5
+ # Renders a pill-shaped badge with fully rounded corners.
6
+ #
7
+ # @example Basic usage
8
+ # <%= render(Flowbite::Badge::Pill.new) { "Default" } %>
9
+ #
10
+ # @see https://flowbite.com/docs/components/badge/
11
+ class Pill < Flowbite::Badge
12
+ class << self
13
+ # rubocop:disable Layout/LineLength
14
+ def styles
15
+ Flowbite::Styles.from_hash({
16
+ alternative: {
17
+ default: ["bg-neutral-primary-soft", "hover:bg-neutral-secondary-medium", "rounded-full", "text-heading"]
18
+ },
19
+ brand: {
20
+ default: ["bg-brand-softer", "hover:bg-brand-soft", "rounded-full", "text-fg-brand-strong"]
21
+ },
22
+ danger: {
23
+ default: ["bg-danger-soft", "hover:bg-danger-medium", "rounded-full", "text-fg-danger-strong"]
24
+ },
25
+ gray: {
26
+ default: ["bg-neutral-secondary-medium", "hover:bg-neutral-tertiary-medium", "rounded-full", "text-heading"]
27
+ },
28
+ success: {
29
+ default: ["bg-success-soft", "hover:bg-success-medium", "rounded-full", "text-fg-success-strong"]
30
+ },
31
+ warning: {
32
+ default: ["bg-warning-soft", "hover:bg-warning-medium", "rounded-full", "text-fg-warning"]
33
+ }
34
+ }.freeze)
35
+ end
36
+ # rubocop:enable Layout/LineLength
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ # Renders a badge component for displaying labels, counts, or status
5
+ # indicators.
6
+ #
7
+ # @example Basic usage
8
+ # <%= render(Flowbite::Badge.new) { "Default" } %>
9
+ #
10
+ # @example With border
11
+ # <%= render(Flowbite::Badge.new(bordered: true, style: :success)) { "Success" } %>
12
+ #
13
+ # @see https://flowbite.com/docs/components/badge/
14
+ # @lookbook_embed BadgePreview
15
+ class Badge < ViewComponent::Base
16
+ SIZES = {
17
+ default: ["text-xs", "font-medium", "px-1.5", "py-0.5"],
18
+ lg: ["text-sm", "font-medium", "px-2", "py-1"]
19
+ }.freeze
20
+
21
+ BORDER_CLASSES = {
22
+ alternative: ["border", "border-default"],
23
+ brand: ["border", "border-brand-subtle"],
24
+ danger: ["border", "border-danger-subtle"],
25
+ gray: ["border", "border-default-medium"],
26
+ success: ["border", "border-success-subtle"],
27
+ warning: ["border", "border-warning-subtle"]
28
+ }.freeze
29
+
30
+ class << self
31
+ def classes(size: :default, state: :default, style: :brand)
32
+ styles.fetch(style).fetch(state) + sizes.fetch(size)
33
+ end
34
+
35
+ def sizes
36
+ SIZES
37
+ end
38
+
39
+ # rubocop:disable Layout/LineLength
40
+ def styles
41
+ Flowbite::Styles.from_hash({
42
+ alternative: {
43
+ default: ["bg-neutral-primary-soft", "hover:bg-neutral-secondary-medium", "rounded", "text-heading"]
44
+ },
45
+ brand: {
46
+ default: ["bg-brand-softer", "hover:bg-brand-soft", "rounded", "text-fg-brand-strong"]
47
+ },
48
+ danger: {
49
+ default: ["bg-danger-soft", "hover:bg-danger-medium", "rounded", "text-fg-danger-strong"]
50
+ },
51
+ gray: {
52
+ default: ["bg-neutral-secondary-medium", "hover:bg-neutral-tertiary-medium", "rounded", "text-heading"]
53
+ },
54
+ success: {
55
+ default: ["bg-success-soft", "hover:bg-success-medium", "rounded", "text-fg-success-strong"]
56
+ },
57
+ warning: {
58
+ default: ["bg-warning-soft", "hover:bg-warning-medium", "rounded", "text-fg-warning"]
59
+ }
60
+ }.freeze)
61
+ end
62
+ # rubocop:enable Layout/LineLength
63
+ end
64
+
65
+ attr_reader :options
66
+
67
+ # @param bordered [Boolean] Whether to add a border to the badge.
68
+ # @param class [String, Array<String>] Additional CSS classes.
69
+ # @param dot [Boolean] Whether to show a dot indicator.
70
+ # @param href [String] If provided, renders the badge as a link.
71
+ # @param size [Symbol] The size of the badge (:default or :lg).
72
+ # @param style [Symbol] The color style (:alternative, :brand, :danger,
73
+ # :gray, :success, :warning).
74
+ def initialize(bordered: false, class: nil, dot: false, href: nil,
75
+ size: :default, style: :brand, **options)
76
+ @bordered = bordered
77
+ @class = Array.wrap(binding.local_variable_get(:class))
78
+ @dot = dot
79
+ @href = href
80
+ @size = size
81
+ @style = style
82
+ @options = options
83
+ end
84
+
85
+ def bordered?
86
+ !!@bordered
87
+ end
88
+
89
+ def dot?
90
+ !!@dot
91
+ end
92
+
93
+ def link?
94
+ @href.present?
95
+ end
96
+
97
+ private
98
+
99
+ def classes
100
+ result = self.class.classes(size: @size, state: :default, style: @style)
101
+ result += BORDER_CLASSES.fetch(@style) if bordered?
102
+ result += ["inline-flex", "items-center"] if dot?
103
+ result + @class
104
+ end
105
+
106
+ def tag_name
107
+ link? ? :a : :span
108
+ end
109
+
110
+ def tag_options
111
+ opts = {class: classes}
112
+ opts[:href] = @href if link?
113
+ opts.merge(options)
114
+ end
115
+ end
116
+ end
@@ -31,6 +31,13 @@ module Flowbite
31
31
 
32
32
  private
33
33
 
34
+ def default_input_arguments
35
+ args = super
36
+ args[:unchecked_value] = @input[:unchecked_value] if @input.key?(:unchecked_value)
37
+ args[:value] = @input[:value] if @input.key?(:value)
38
+ args
39
+ end
40
+
34
41
  def hint_classes
35
42
  if disabled?
36
43
  "text-xs font-normal text-fg-disabled"
@@ -39,13 +46,6 @@ module Flowbite
39
46
  end
40
47
  end
41
48
 
42
- def input_arguments
43
- args = super
44
- args[:unchecked_value] = @input[:unchecked_value] if @input.key?(:unchecked_value)
45
- args[:value] = @input[:value] if @input.key?(:value)
46
- args
47
- end
48
-
49
49
  def label_classes
50
50
  if disabled?
51
51
  "font-medium text-fg-disabled"
@@ -19,7 +19,7 @@ module Flowbite
19
19
  form: @form,
20
20
  include_blank: @include_blank,
21
21
  multiple: @multiple,
22
- options: input_options,
22
+ options: default_input_options,
23
23
  size: @size
24
24
  )
25
25
  )
@@ -155,11 +155,19 @@ module Flowbite
155
155
  return unless hint?
156
156
 
157
157
  component = Flowbite::Input::Hint.new(
158
+ **default_hint_arguments
159
+ ).with_content(default_hint_content)
160
+ render(component)
161
+ end
162
+
163
+ # @return [Hash] The keyword arguments for the hint component.
164
+ def default_hint_arguments
165
+ {
158
166
  attribute: @attribute,
167
+ class: @hint[:class],
159
168
  form: @form,
160
169
  options: default_hint_options
161
- ).with_content(default_hint_content)
162
- render(component)
170
+ }
163
171
  end
164
172
 
165
173
  def default_hint_content
@@ -180,23 +188,37 @@ module Flowbite
180
188
  }.merge(@hint[:options] || {})
181
189
  end
182
190
 
191
+ # Returns the HTML to use for the default input element.
192
+ def default_input
193
+ render(input_component.new(**default_input_arguments))
194
+ end
195
+
196
+ # @return [Hash] The keyword arguments for the default input component.
197
+ def default_input_arguments
198
+ {
199
+ attribute: @attribute,
200
+ class: @input[:class],
201
+ disabled: @disabled,
202
+ form: @form,
203
+ options: default_input_options,
204
+ size: @size
205
+ }
206
+ end
207
+
183
208
  # Returns a Hash with the default attributes to apply to the input element.
184
209
  #
185
210
  # The default attributes can be overriden by passing the `input[options]`
186
211
  # argument to the constructor.
187
212
  def default_input_options
188
- if hint?
213
+ options = if hint?
189
214
  {
190
215
  "aria-describedby": id_for_hint_element
191
216
  }
192
217
  else
193
218
  {}
194
219
  end
195
- end
196
220
 
197
- # Returns the HTML to use for the default input element.
198
- def default_input
199
- render(input_component.new(**input_arguments))
221
+ options.merge(@input[:options] || {})
200
222
  end
201
223
 
202
224
  def default_label
@@ -241,20 +263,5 @@ module Flowbite
241
263
  .compact_blank
242
264
  .join("_")
243
265
  end
244
-
245
- # @return [Hash] The keyword arguments for the input component.
246
- def input_arguments
247
- {
248
- attribute: @attribute,
249
- disabled: @disabled,
250
- form: @form,
251
- options: input_options,
252
- size: @size
253
- }
254
- end
255
-
256
- def input_options
257
- default_input_options.merge(@input[:options] || {})
258
- end
259
266
  end
260
267
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Sidebar
5
+ # Renders a sidebar navigation item.
6
+ #
7
+ # Each item renders as a list item containing a link. Optionally, an icon
8
+ # can be provided using the +icon+ slot, which will be displayed before the
9
+ # label text.
10
+ #
11
+ # @example Basic item
12
+ # <%= render Flowbite::Sidebar::Item.new(href: "/dashboard") { "Dashboard" } %>
13
+ #
14
+ # @example Item with icon
15
+ # <%= render(Flowbite::Sidebar::Item.new(href: "/dashboard")) do |item| %>
16
+ # <% item.with_icon do %>
17
+ # <svg class="w-5 h-5" ...>...</svg>
18
+ # <% end %>
19
+ # Dashboard
20
+ # <% end %>
21
+ #
22
+ # @viewcomponent_slot icon An optional icon displayed before the label text.
23
+ class Item < ViewComponent::Base
24
+ renders_one :icon
25
+
26
+ attr_reader :href, :options
27
+
28
+ class << self
29
+ def classes
30
+ [
31
+ "flex", "items-center", "px-2", "py-1.5", "text-body",
32
+ "rounded-base", "hover:bg-neutral-tertiary", "hover:text-fg-brand", "group"
33
+ ]
34
+ end
35
+ end
36
+
37
+ # @param class [Array<String>] Additional CSS classes for the link element.
38
+ # @param href [String] The URL for the navigation link.
39
+ # @param options [Hash] Additional HTML attributes for the link element.
40
+ def initialize(href:, class: nil, **options)
41
+ super()
42
+ @class = Array.wrap(binding.local_variable_get(:class))
43
+ @href = href
44
+ @options = options
45
+ end
46
+
47
+ def call
48
+ content_tag(:li) do
49
+ link_options = {class: link_classes}.merge(options)
50
+ content_tag(:a, href: href, **link_options) do
51
+ concat(icon) if icon?
52
+ concat(content_tag(:span, content, class: label_classes))
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def label_classes
60
+ "ms-3" if icon?
61
+ end
62
+
63
+ def link_classes
64
+ self.class.classes + @class
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ class Sidebar
5
+ # Renders the navigation list for a sidebar.
6
+ #
7
+ # This component renders a +<ul>+ with navigation items. It can be used
8
+ # inside a {Flowbite::Sidebar} for a fixed-position sidebar, or standalone
9
+ # in any layout that needs sidebar-style navigation.
10
+ #
11
+ # @example Inside a Sidebar
12
+ # <%= render(Flowbite::Sidebar.new) do %>
13
+ # <%= render(Flowbite::Sidebar::Navigation.new) do |nav| %>
14
+ # <% nav.with_item do %>
15
+ # <%= render(Flowbite::Sidebar::Item.new(href: "/")) { "Home" } %>
16
+ # <% end %>
17
+ # <% end %>
18
+ # <% end %>
19
+ #
20
+ # @example Standalone
21
+ # <%= render(Flowbite::Sidebar::Navigation.new) do |nav| %>
22
+ # <% nav.with_item do %>
23
+ # <%= render(Flowbite::Sidebar::Item.new(href: "/")) { "Home" } %>
24
+ # <% end %>
25
+ # <% end %>
26
+ class Navigation < ViewComponent::Base
27
+ renders_many :items
28
+
29
+ class << self
30
+ def classes
31
+ ["space-y-2", "font-medium"]
32
+ end
33
+ end
34
+
35
+ # @param class [Array<String>] Additional CSS classes for the list element.
36
+ # @param options [Hash] Additional HTML options for the list element.
37
+ def initialize(class: nil, **options)
38
+ super()
39
+ @class = Array.wrap(binding.local_variable_get(:class))
40
+ @options = options
41
+ end
42
+
43
+ def call
44
+ content_tag(:ul, list_options) do
45
+ items.each do |item|
46
+ concat(item)
47
+ end
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def list_classes
54
+ self.class.classes + @class
55
+ end
56
+
57
+ def list_options
58
+ {class: list_classes}.merge(@options)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Flowbite
4
+ # Renders a fixed-position sidebar container.
5
+ #
6
+ # Use {Flowbite::Sidebar} as the outer shell and
7
+ # {Flowbite::Sidebar::Navigation} inside it to render the list of
8
+ # {Flowbite::Sidebar::Item}s.
9
+ #
10
+ # @example Usage
11
+ # <%= render(Flowbite::Sidebar.new) do %>
12
+ # <%= render(Flowbite::Sidebar::Navigation.new) do |nav| %>
13
+ # <% nav.with_item do %>
14
+ # <%= render(Flowbite::Sidebar::Item.new(href: "/dashboard")) { "Dashboard" } %>
15
+ # <% end %>
16
+ # <% end %>
17
+ # <% end %>
18
+ #
19
+ # @see https://flowbite.com/docs/components/sidebar/
20
+ # @lookbook_embed SidebarPreview
21
+ class Sidebar < ViewComponent::Base
22
+ class << self
23
+ def classes
24
+ [
25
+ "fixed", "top-0", "left-0", "z-40", "w-64", "h-screen",
26
+ "transition-transform", "-translate-x-full", "sm:translate-x-0"
27
+ ]
28
+ end
29
+ end
30
+
31
+ # @param class [Array<String>] Additional CSS classes for the sidebar
32
+ # container.
33
+ # @param options [Hash] Additional HTML options for the sidebar container.
34
+ def initialize(class: nil, **options)
35
+ super()
36
+ @class = Array.wrap(binding.local_variable_get(:class))
37
+ @options = options
38
+ end
39
+
40
+ def call
41
+ content_tag(:aside, aside_options) do
42
+ content_tag(:div, class: wrapper_classes) do
43
+ content
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def aside_classes
51
+ self.class.classes + @class
52
+ end
53
+
54
+ def aside_options
55
+ {class: aside_classes, "aria-label": "Sidebar"}.merge(@options)
56
+ end
57
+
58
+ def wrapper_classes
59
+ ["h-full", "px-3", "py-4", "overflow-y-auto", "bg-neutral-primary-soft"]
60
+ end
61
+ end
62
+ end
@@ -1,8 +1,8 @@
1
- <div
2
- class="<%= container_classes.join(" ") %>"
3
- role="alert"
4
- <%= options.map { |k, v| "#{k}=\"#{v}\"" }.join(" ").html_safe %>
5
- >
1
+ <%= tag.div(
2
+ class: container_classes.join(" "),
3
+ role: "alert",
4
+ **options,
5
+ ) do %>
6
6
  <%= render Flowbite::Toast::Icon.new(style: style) %>
7
7
 
8
8
  <div class="ms-3 text-sm font-normal"><%= message %></div>
@@ -37,4 +37,4 @@
37
37
  </svg>
38
38
  </button>
39
39
  <% end %>
40
- </div>
40
+ <% end %>
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Flowbite
4
4
  module Components
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flowbite-components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakob Skjerning
@@ -49,6 +49,10 @@ files:
49
49
  - LICENSE
50
50
  - README.md
51
51
  - app/assets/tailwind/flowbite_components/engine.css
52
+ - app/components/flowbite/badge.rb
53
+ - app/components/flowbite/badge/badge.html.erb
54
+ - app/components/flowbite/badge/dot.rb
55
+ - app/components/flowbite/badge/pill.rb
52
56
  - app/components/flowbite/breadcrumb.rb
53
57
  - app/components/flowbite/breadcrumb/home_icon.rb
54
58
  - app/components/flowbite/breadcrumb/item.rb
@@ -95,6 +99,9 @@ files:
95
99
  - app/components/flowbite/input_field/textarea.rb
96
100
  - app/components/flowbite/input_field/url.rb
97
101
  - app/components/flowbite/link.rb
102
+ - app/components/flowbite/sidebar.rb
103
+ - app/components/flowbite/sidebar/item.rb
104
+ - app/components/flowbite/sidebar/navigation.rb
98
105
  - app/components/flowbite/style.rb
99
106
  - app/components/flowbite/styles.rb
100
107
  - app/components/flowbite/toast.rb
@@ -128,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
135
  - !ruby/object:Gem::Version
129
136
  version: '0'
130
137
  requirements: []
131
- rubygems_version: 4.0.3
138
+ rubygems_version: 4.0.6
132
139
  specification_version: 4
133
140
  summary: ViewComponents using the Flowbite design system
134
141
  test_files: []