-
Notifications
You must be signed in to change notification settings - Fork 0
Add Badge component #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Flowbite | ||
| # Renders a badge component for displaying labels, counts, or status | ||
| # indicators. | ||
| # | ||
| # @example Basic usage | ||
| # <%= render(Flowbite::Badge.new) { "Default" } %> | ||
| # | ||
| # @example With border | ||
| # <%= render(Flowbite::Badge.new(bordered: true, style: :success)) { "Success" } %> | ||
| # | ||
| # @see https://flowbite.com/docs/components/badge/ | ||
| # @lookbook_embed BadgePreview | ||
| class Badge < ViewComponent::Base | ||
| SIZES = { | ||
| default: ["text-xs", "font-medium", "px-1.5", "py-0.5"], | ||
| lg: ["text-sm", "font-medium", "px-2", "py-1"] | ||
| }.freeze | ||
|
|
||
| BORDER_CLASSES = { | ||
| alternative: ["border", "border-default"], | ||
| brand: ["border", "border-brand-subtle"], | ||
| danger: ["border", "border-danger-subtle"], | ||
| gray: ["border", "border-default-medium"], | ||
| success: ["border", "border-success-subtle"], | ||
| warning: ["border", "border-warning-subtle"] | ||
| }.freeze | ||
|
|
||
| class << self | ||
| def classes(size: :default, state: :default, style: :brand) | ||
| styles.fetch(style).fetch(state) + sizes.fetch(size) | ||
| end | ||
|
|
||
| def sizes | ||
| SIZES | ||
| end | ||
|
Comment on lines
+30
to
+37
|
||
|
|
||
| # rubocop:disable Layout/LineLength | ||
| def styles | ||
| Flowbite::Styles.from_hash({ | ||
| alternative: { | ||
| default: ["bg-neutral-primary-soft", "hover:bg-neutral-secondary-medium", "rounded", "text-heading"] | ||
| }, | ||
| brand: { | ||
| default: ["bg-brand-softer", "hover:bg-brand-soft", "rounded", "text-fg-brand-strong"] | ||
| }, | ||
| danger: { | ||
| default: ["bg-danger-soft", "hover:bg-danger-medium", "rounded", "text-fg-danger-strong"] | ||
| }, | ||
| gray: { | ||
| default: ["bg-neutral-secondary-medium", "hover:bg-neutral-tertiary-medium", "rounded", "text-heading"] | ||
| }, | ||
| success: { | ||
| default: ["bg-success-soft", "hover:bg-success-medium", "rounded", "text-fg-success-strong"] | ||
| }, | ||
| warning: { | ||
| default: ["bg-warning-soft", "hover:bg-warning-medium", "rounded", "text-fg-warning"] | ||
| } | ||
| }.freeze) | ||
| end | ||
| # rubocop:enable Layout/LineLength | ||
| end | ||
|
|
||
| attr_reader :options | ||
|
|
||
| # @param bordered [Boolean] Whether to add a border to the badge. | ||
| # @param class [String, Array<String>] Additional CSS classes. | ||
| # @param dot [Boolean] Whether to show a dot indicator. | ||
| # @param href [String] If provided, renders the badge as a link. | ||
| # @param size [Symbol] The size of the badge (:default or :lg). | ||
| # @param style [Symbol] The color style (:alternative, :brand, :danger, | ||
| # :gray, :success, :warning). | ||
| def initialize(bordered: false, class: nil, dot: false, href: nil, | ||
| size: :default, style: :brand, **options) | ||
| @bordered = bordered | ||
| @class = Array.wrap(binding.local_variable_get(:class)) | ||
| @dot = dot | ||
| @href = href | ||
| @size = size | ||
| @style = style | ||
| @options = options | ||
| end | ||
|
|
||
| def bordered? | ||
| !!@bordered | ||
| end | ||
|
|
||
| def dot? | ||
| !!@dot | ||
| end | ||
|
|
||
| def link? | ||
| @href.present? | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def classes | ||
| result = self.class.classes(size: @size, state: :default, style: @style) | ||
| result += BORDER_CLASSES.fetch(@style) if bordered? | ||
| result += ["inline-flex", "items-center"] if dot? | ||
| result + @class | ||
| end | ||
|
|
||
| def tag_name | ||
| link? ? :a : :span | ||
| end | ||
|
|
||
| def tag_options | ||
| opts = {class: classes} | ||
| opts[:href] = @href if link? | ||
| opts.merge(options) | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| <%= content_tag(tag_name, **tag_options) do %> | ||
| <% if dot? %><%= render(Flowbite::Badge::Dot.new(style: @style)) %><% end %> | ||
| <%= content %> | ||
| <% end %> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Flowbite | ||
| class Badge | ||
| # Renders a colored dot indicator for use inside a badge. | ||
| # | ||
| # @param style [Symbol] The color style of the dot (:alternative, :brand, | ||
| # :danger, :gray, :success, :warning). | ||
| class Dot < ViewComponent::Base | ||
| CLASSES = { | ||
| alternative: ["bg-heading", "me-1", "rounded-full"], | ||
| brand: ["bg-fg-brand-strong", "me-1", "rounded-full"], | ||
| danger: ["bg-fg-danger-strong", "me-1", "rounded-full"], | ||
| gray: ["bg-heading", "me-1", "rounded-full"], | ||
| success: ["bg-fg-success-strong", "me-1", "rounded-full"], | ||
| warning: ["bg-fg-warning", "me-1", "rounded-full"] | ||
| }.freeze | ||
|
|
||
| SIZES = { | ||
| default: ["h-1.5", "w-1.5"] | ||
| }.freeze | ||
|
|
||
| class << self | ||
| def classes(size: :default, style: :brand) | ||
| CLASSES.fetch(style) + sizes.fetch(size) | ||
| end | ||
|
|
||
| def sizes | ||
| SIZES | ||
| end | ||
| end | ||
|
|
||
| attr_reader :size, :style | ||
|
|
||
| def initialize(size: :default, style: :brand) | ||
| @size = size | ||
| @style = style | ||
| end | ||
|
|
||
| def call | ||
| content_tag(:span, nil, class: self.class.classes(size: size, style: style)) | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Flowbite | ||
| class Badge | ||
| # Renders a pill-shaped badge with fully rounded corners. | ||
| # | ||
| # @example Basic usage | ||
| # <%= render(Flowbite::Badge::Pill.new) { "Default" } %> | ||
| # | ||
| # @see https://flowbite.com/docs/components/badge/ | ||
| class Pill < Flowbite::Badge | ||
| class << self | ||
| # rubocop:disable Layout/LineLength | ||
| def styles | ||
| Flowbite::Styles.from_hash({ | ||
| alternative: { | ||
| default: ["bg-neutral-primary-soft", "hover:bg-neutral-secondary-medium", "rounded-full", "text-heading"] | ||
| }, | ||
| brand: { | ||
| default: ["bg-brand-softer", "hover:bg-brand-soft", "rounded-full", "text-fg-brand-strong"] | ||
| }, | ||
| danger: { | ||
| default: ["bg-danger-soft", "hover:bg-danger-medium", "rounded-full", "text-fg-danger-strong"] | ||
| }, | ||
| gray: { | ||
| default: ["bg-neutral-secondary-medium", "hover:bg-neutral-tertiary-medium", "rounded-full", "text-heading"] | ||
| }, | ||
| success: { | ||
| default: ["bg-success-soft", "hover:bg-success-medium", "rounded-full", "text-fg-success-strong"] | ||
| }, | ||
| warning: { | ||
| default: ["bg-warning-soft", "hover:bg-warning-medium", "rounded-full", "text-fg-warning"] | ||
| } | ||
| }.freeze) | ||
| end | ||
| # rubocop:enable Layout/LineLength | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class BadgePreview < Lookbook::Preview | ||
| def example | ||
| render(Flowbite::Badge.new) { "Default" } | ||
| end | ||
|
|
||
| # @!group Styles | ||
| # | ||
| # Use these badge styles with multiple colors to indicate status or categories. | ||
| # | ||
| # @display classes flex flex-wrap gap-2 | ||
|
|
||
| def alternative | ||
| render(Flowbite::Badge.new(style: :alternative)) { "Alternative" } | ||
| end | ||
|
|
||
| def brand | ||
| render(Flowbite::Badge.new(style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| def danger | ||
| render(Flowbite::Badge.new(style: :danger)) { "Danger" } | ||
| end | ||
|
|
||
| def gray | ||
| render(Flowbite::Badge.new(style: :gray)) { "Gray" } | ||
| end | ||
|
|
||
| def success | ||
| render(Flowbite::Badge.new(style: :success)) { "Success" } | ||
| end | ||
|
|
||
| def warning | ||
| render(Flowbite::Badge.new(style: :warning)) { "Warning" } | ||
| end | ||
|
|
||
| # @!endgroup | ||
|
|
||
| # @!group Bordered | ||
| # | ||
| # Add a border accent in a matching color scheme. | ||
| # | ||
| # @display classes flex flex-wrap gap-2 | ||
|
|
||
| def bordered_alternative | ||
| render(Flowbite::Badge.new(bordered: true, style: :alternative)) { "Alternative" } | ||
| end | ||
|
|
||
| def bordered_brand | ||
| render(Flowbite::Badge.new(bordered: true, style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| def bordered_danger | ||
| render(Flowbite::Badge.new(bordered: true, style: :danger)) { "Danger" } | ||
| end | ||
|
|
||
| def bordered_gray | ||
| render(Flowbite::Badge.new(bordered: true, style: :gray)) { "Gray" } | ||
| end | ||
|
|
||
| def bordered_success | ||
| render(Flowbite::Badge.new(bordered: true, style: :success)) { "Success" } | ||
| end | ||
|
|
||
| def bordered_warning | ||
| render(Flowbite::Badge.new(bordered: true, style: :warning)) { "Warning" } | ||
| end | ||
|
|
||
| # @!endgroup | ||
|
|
||
| # @!group Large | ||
| # | ||
| # Increase the paddings to create a larger badge variant. | ||
| # | ||
| # @display classes flex flex-wrap gap-2 | ||
|
|
||
| def large_brand | ||
| render(Flowbite::Badge.new(size: :lg, style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| def large_bordered | ||
| render(Flowbite::Badge.new(bordered: true, size: :lg, style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| # @!endgroup | ||
|
|
||
| # @!group Pill | ||
| # | ||
| # Make the corners even more rounded like pills. | ||
| # | ||
| # @display classes flex flex-wrap gap-2 | ||
|
|
||
| def pill_alternative | ||
| render(Flowbite::Badge::Pill.new(style: :alternative)) { "Alternative" } | ||
| end | ||
|
|
||
| def pill_brand | ||
| render(Flowbite::Badge::Pill.new(style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| def pill_danger | ||
| render(Flowbite::Badge::Pill.new(style: :danger)) { "Danger" } | ||
| end | ||
|
|
||
| def pill_gray | ||
| render(Flowbite::Badge::Pill.new(style: :gray)) { "Gray" } | ||
| end | ||
|
|
||
| def pill_success | ||
| render(Flowbite::Badge::Pill.new(style: :success)) { "Success" } | ||
| end | ||
|
|
||
| def pill_warning | ||
| render(Flowbite::Badge::Pill.new(style: :warning)) { "Warning" } | ||
| end | ||
|
|
||
| # @!endgroup | ||
|
|
||
| # @!group Link | ||
| # | ||
| # Use badges as anchor elements to link to another page. | ||
| # | ||
| # @display classes flex flex-wrap gap-2 | ||
|
|
||
| def link_badge | ||
| render(Flowbite::Badge.new(bordered: true, href: "#", style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| def link_pill | ||
| render(Flowbite::Badge::Pill.new(bordered: true, href: "#", style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| # @!endgroup | ||
|
|
||
| # @!group Dot | ||
| # | ||
| # Add a colored dot indicator before the badge text. | ||
| # | ||
| # @display classes flex flex-wrap gap-2 | ||
|
|
||
| def dot_alternative | ||
| render(Flowbite::Badge.new(bordered: true, dot: true, style: :alternative)) { "Alternative" } | ||
| end | ||
|
|
||
| def dot_brand | ||
| render(Flowbite::Badge.new(bordered: true, dot: true, style: :brand)) { "Brand" } | ||
| end | ||
|
|
||
| def dot_danger | ||
| render(Flowbite::Badge.new(bordered: true, dot: true, style: :danger)) { "Danger" } | ||
| end | ||
|
|
||
| def dot_gray | ||
| render(Flowbite::Badge.new(bordered: true, dot: true, style: :gray)) { "Gray" } | ||
| end | ||
|
|
||
| def dot_success | ||
| render(Flowbite::Badge.new(bordered: true, dot: true, style: :success)) { "Success" } | ||
| end | ||
|
|
||
| def dot_warning | ||
| render(Flowbite::Badge.new(bordered: true, dot: true, style: :warning)) { "Warning" } | ||
| end | ||
|
|
||
| # @!endgroup | ||
| end |
Uh oh!
There was an error while loading. Please reload this page.