fluxbit_view_components 0.1.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 +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +86 -0
- data/app/components/fluxbit/alert_component.rb +126 -0
- data/app/components/fluxbit/avatar_component.rb +113 -0
- data/app/components/fluxbit/avatar_group_component.rb +23 -0
- data/app/components/fluxbit/badge_component.rb +79 -0
- data/app/components/fluxbit/button_component.rb +97 -0
- data/app/components/fluxbit/button_group_component.rb +43 -0
- data/app/components/fluxbit/card_component.rb +135 -0
- data/app/components/fluxbit/component.rb +86 -0
- data/app/components/fluxbit/flex_component.rb +93 -0
- data/app/components/fluxbit/form/checkbox_input_component.rb +61 -0
- data/app/components/fluxbit/form/component.rb +71 -0
- data/app/components/fluxbit/form/datepicker_component.rb +7 -0
- data/app/components/fluxbit/form/form_builder_component.rb +117 -0
- data/app/components/fluxbit/form/helper_text_component.rb +29 -0
- data/app/components/fluxbit/form/label_component.rb +65 -0
- data/app/components/fluxbit/form/radio_input_component.rb +21 -0
- data/app/components/fluxbit/form/range_input_component.rb +51 -0
- data/app/components/fluxbit/form/select_free_input_component.rb +77 -0
- data/app/components/fluxbit/form/select_input_component.rb +21 -0
- data/app/components/fluxbit/form/spacer_input_component.rb +12 -0
- data/app/components/fluxbit/form/text_input_component.rb +225 -0
- data/app/components/fluxbit/form/textarea_input_component.rb +57 -0
- data/app/components/fluxbit/form/toggle_input_component.rb +166 -0
- data/app/components/fluxbit/form/upload_image_input_component.html.erb +48 -0
- data/app/components/fluxbit/form/upload_image_input_component.rb +66 -0
- data/app/components/fluxbit/form/upload_input_component.html.erb +12 -0
- data/app/components/fluxbit/form/upload_input_component.rb +47 -0
- data/app/components/fluxbit/gravatar_component.rb +99 -0
- data/app/components/fluxbit/heading_component.rb +47 -0
- data/app/components/fluxbit/modal_component.rb +141 -0
- data/app/components/fluxbit/popover_component.rb +71 -0
- data/app/components/fluxbit/tab_component.rb +142 -0
- data/app/components/fluxbit/text_component.rb +36 -0
- data/app/components/fluxbit/tooltip_component.rb +38 -0
- data/app/helpers/fluxbit/classes_helper.rb +21 -0
- data/app/helpers/fluxbit/components_helper.rb +75 -0
- data/config/deploy.yml +37 -0
- data/config/locales/en.yml +6 -0
- data/lib/fluxbit/config/alert_component.rb +59 -0
- data/lib/fluxbit/config/avatar_component.rb +79 -0
- data/lib/fluxbit/config/badge_component.rb +77 -0
- data/lib/fluxbit/config/button_component.rb +86 -0
- data/lib/fluxbit/config/card_component.rb +32 -0
- data/lib/fluxbit/config/flex_component.rb +63 -0
- data/lib/fluxbit/config/form/helper_text_component.rb +20 -0
- data/lib/fluxbit/config/gravatar_component.rb +19 -0
- data/lib/fluxbit/config/heading_component.rb +39 -0
- data/lib/fluxbit/config/modal_component.rb +71 -0
- data/lib/fluxbit/config/paragraph_component.rb +11 -0
- data/lib/fluxbit/config/popover_component.rb +33 -0
- data/lib/fluxbit/config/tab_component.rb +131 -0
- data/lib/fluxbit/config/text_component.rb +110 -0
- data/lib/fluxbit/config/tooltip_component.rb +11 -0
- data/lib/fluxbit/view_components/codemods/v3_slot_setters.rb +222 -0
- data/lib/fluxbit/view_components/engine.rb +36 -0
- data/lib/fluxbit/view_components/version.rb +7 -0
- data/lib/fluxbit/view_components.rb +30 -0
- data/lib/fluxbit_view_components.rb +3 -0
- data/lib/install/install.rb +64 -0
- data/lib/tasks/fluxbit_view_components_tasks.rake +22 -0
- metadata +238 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 16de56192c4f954e22b5391bbd8e94970a8345ede43ffaf8866050222a8d486a
|
4
|
+
data.tar.gz: fb3a6c03297fc0836ee3c61005e530cc32640e0c97dbc872945b661e6e2b95c6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9127a488dc9bec5cc886886855edb7649e62a9ce36406e0c9aef4f956eb392fd9f21f42473459885eeb9758f19528c3185bd8729398852d91e17a27168a6cb40
|
7
|
+
data.tar.gz: 3bced6391398780c7877563c35f406ede7c4dc838c2ac9e410c99db815c1c58686d79aa034eff979c561010f191701329a7daa9c857ed06b521b6441ff9c502d
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2021 Dan Gamble
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# Fluxbit ViewComponents
|
2
|
+
|
3
|
+
Fluxbit ViewComponents is an implementation of the Fluxbit Design System using [ViewComponent](https://github.com/github/view_component).
|
4
|
+
|
5
|
+
<div style="text-align: center;">
|
6
|
+
<img src="docs/fluxbit.png" alt="Fluxbit ViewComponents" width="300" />
|
7
|
+
</div>
|
8
|
+
|
9
|
+
## Preview
|
10
|
+
|
11
|
+
I don't have a site to host the lookbook. Sorry.
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Render Fluxbit ViewComponents:
|
16
|
+
|
17
|
+
```erb
|
18
|
+
<%= fx_card(title: "Title") do %>
|
19
|
+
<p>Card example</p>
|
20
|
+
<% end %>
|
21
|
+
```
|
22
|
+
|
23
|
+
## Dependencies
|
24
|
+
|
25
|
+
- [Anyicon](https://github.com/arthurmolina/anyicon)
|
26
|
+
|
27
|
+
## Installation
|
28
|
+
|
29
|
+
Add `fluxbit_view_components` to your Gemfile:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
bundle add fluxbit_view_components
|
33
|
+
```
|
34
|
+
|
35
|
+
Run installer:
|
36
|
+
```bash
|
37
|
+
bin/rails fluxbit_view_components:install
|
38
|
+
```
|
39
|
+
|
40
|
+
## Development
|
41
|
+
|
42
|
+
To get started:
|
43
|
+
|
44
|
+
1. Run: `bundle install`
|
45
|
+
2. Run: `yarn install`
|
46
|
+
3. Run: `bin/dev`
|
47
|
+
|
48
|
+
It will open demo app with component previews on `localhost:3000`. You can change components and they will be updated on page reload. Component previews located in `demo/test/components/previews`.
|
49
|
+
|
50
|
+

|
51
|
+
|
52
|
+
To run tests:
|
53
|
+
|
54
|
+
```bash
|
55
|
+
rake
|
56
|
+
```
|
57
|
+
|
58
|
+
## Releases
|
59
|
+
|
60
|
+
The library follows [semantic versioning](https://semver.org/). To draft a new release you need to run `bin/release` with a new version number:
|
61
|
+
|
62
|
+
```bash
|
63
|
+
bin/release VERSION
|
64
|
+
```
|
65
|
+
|
66
|
+
Where the VERSION is the version number you want to release. This script will update the version in the gem and push it to GitHub and Rubygems automatically.
|
67
|
+
|
68
|
+
To release a new version of npm package update the package.json file with the new version number and run:
|
69
|
+
|
70
|
+
```bash
|
71
|
+
npm run release
|
72
|
+
```
|
73
|
+
|
74
|
+
After that make sure to commit changes in package.json.
|
75
|
+
|
76
|
+
## Documentation
|
77
|
+
|
78
|
+
For more information, check out the following resources:
|
79
|
+
|
80
|
+
- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md): Guidelines for contributing to this project and fostering a welcoming community.
|
81
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md): Instructions on how to contribute to the project, including setting up your environment and submitting changes.
|
82
|
+
- [PULL_REQUEST_TEMPLATE.md](PULL_REQUEST_TEMPLATE.md): Template for submitting pull requests to ensure consistency and quality.
|
83
|
+
|
84
|
+
## License
|
85
|
+
|
86
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The `Fluxbit::AlertComponent` is a customizable alert component that extends `Fluxbit::Component`.
|
5
|
+
# It provides various options to display alert messages with different styles, icons, and behaviors
|
6
|
+
# such as close functionality and animations.
|
7
|
+
#
|
8
|
+
# Example usage:
|
9
|
+
# = render Fluxbit::AlertComponent.new(color: :success, icon: "check").with_content("Alert message")
|
10
|
+
#
|
11
|
+
class Fluxbit::AlertComponent < Fluxbit::Component
|
12
|
+
include Fluxbit::Config::AlertComponent
|
13
|
+
|
14
|
+
##
|
15
|
+
# Initializes the alert component with the given properties.
|
16
|
+
#
|
17
|
+
# @param [Hash] props The properties to customize the alert.
|
18
|
+
# @option props [Symbol, String] :color (:info) The color style of the alert.
|
19
|
+
# @option props [Symbol, String, Boolean] :icon (:default) The icon to display in the alert or `false` to omit.
|
20
|
+
# @option props [String] :class_icon ('') Additional CSS classes for the icon.
|
21
|
+
# @option props [Boolean] :can_close (true) Determines if the alert can be closed.
|
22
|
+
# @option props [String] :remove_class ('') Classes to remove from the default class list.
|
23
|
+
# @option props [Integer] :dismiss_timeout (3000) The timeout in milliseconds before the alert dismisses itself.
|
24
|
+
# @option props [Boolean] :fade_in_animation (true) Determines if the alert should fade in.
|
25
|
+
# @option props [Symbol] :out_animation (:fade_out) The type of fade out/dismiss animation.
|
26
|
+
# @option props [Boolean] :all_rounded (true) Determines if the alert has rounded corners.
|
27
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes.
|
28
|
+
#
|
29
|
+
# @return [Fluxbit::AlertComponent]
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# = render Fluxbit::AlertComponent.new(color: :success, icon: "check").with_content("Alert message")
|
33
|
+
#
|
34
|
+
def initialize(**props)
|
35
|
+
super
|
36
|
+
@props = props
|
37
|
+
@color = define_color(@props.delete(:color) || @@color)
|
38
|
+
@icon = define_icon(@props.delete(:icon) || :default, @props.delete(:class_icon) || "")
|
39
|
+
@can_close = @props[:can_close].nil? ? @@can_close : @props.delete(:can_close)
|
40
|
+
@all_rounded = @props[:all_rounded].nil? ? @@all_rounded : @props.delete(:all_rounded)
|
41
|
+
@props["id"] = fx_id if @props["id"].nil?
|
42
|
+
@props[:role] = "alert"
|
43
|
+
prop_fade_in_automation = @props.delete(:fade_in_animation)
|
44
|
+
|
45
|
+
animation_props(
|
46
|
+
dismiss_timeout: [ (@props.delete(:dismiss_timeout) || @@dismiss_timeout).to_i, 0 ].max,
|
47
|
+
fade_in_animation: prop_fade_in_automation.nil? ? @@fade_in_animation : prop_fade_in_automation,
|
48
|
+
out_animation: @props.delete(:out_animation) || @@out_animation
|
49
|
+
)
|
50
|
+
declare_classes
|
51
|
+
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
52
|
+
end
|
53
|
+
|
54
|
+
def animation_props(dismiss_timeout:, fade_in_animation:, out_animation:)
|
55
|
+
return if [ :dont_remove, nil ].include?(out_animation) || dismiss_timeout.to_i == 0
|
56
|
+
|
57
|
+
@props["data-controller"] = "notification"
|
58
|
+
@props["data-action"] = "notification#hide"
|
59
|
+
@props["data-notification-delay-value"] = dismiss_timeout.to_s
|
60
|
+
|
61
|
+
add(to: @props, class: "transition transform duration-1000 hidden")
|
62
|
+
|
63
|
+
if fade_in_animation
|
64
|
+
@props["data-transition-enter-from"] = "opacity-0"
|
65
|
+
@props["data-transition-enter-to"] = "opacity-100"
|
66
|
+
else
|
67
|
+
@props["data-transition-enter-from"] = "opacity-100"
|
68
|
+
@props["data-transition-enter-to"] = "opacity-100"
|
69
|
+
end
|
70
|
+
|
71
|
+
@props["data-transition-leave-from"] = styles[:animations][out_animation.to_sym][:from]
|
72
|
+
@props["data-transition-leave-to"] = styles[:animations][out_animation.to_sym][:to]
|
73
|
+
end
|
74
|
+
|
75
|
+
def call
|
76
|
+
content_tag :div, @props do
|
77
|
+
concat @icon
|
78
|
+
concat content_tag(:div, content, class: "ml-3 text-sm font-medium")
|
79
|
+
concat close_button
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def declare_classes
|
86
|
+
add to: @props,
|
87
|
+
first_element: true,
|
88
|
+
class: [
|
89
|
+
styles[:colors][@color],
|
90
|
+
styles[:all_rounded][@all_rounded ? :on : :off],
|
91
|
+
styles[:base]
|
92
|
+
]
|
93
|
+
end
|
94
|
+
|
95
|
+
def define_color(color)
|
96
|
+
case color.to_sym
|
97
|
+
when :timedout, :alert then :danger
|
98
|
+
when *styles[:colors].keys then color
|
99
|
+
else @@color # :notice included
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def define_icon(icon, class_icon = "")
|
104
|
+
return "" if icon == false
|
105
|
+
icon = icon || @@icon
|
106
|
+
return anyicon(icon: icon, class: class_icon) if icon != :default
|
107
|
+
|
108
|
+
anyicon(icon: "heroicons_solid:#{styles[:default_icons][@color]}", class: class_icon + " w-4 h-4")
|
109
|
+
end
|
110
|
+
|
111
|
+
def close_button
|
112
|
+
return "" unless @can_close
|
113
|
+
|
114
|
+
b_props = {
|
115
|
+
"aria-label" => "Close",
|
116
|
+
"data-dismiss-target" => "##{@props["id"]}",
|
117
|
+
type: "button"
|
118
|
+
}
|
119
|
+
|
120
|
+
add to: b_props, class: [ styles[:close_button][:base], styles[:close_button][:colors][@color] ]
|
121
|
+
content_tag :button, b_props do
|
122
|
+
concat content_tag(:span, "Dismiss", class: "sr-only")
|
123
|
+
concat anyicon(icon: "heroicons_outline:x-mark", class: "w-5 h-5")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
# The `Fluxbit::AvatarComponent` is a component for rendering customizable avatars.
|
5
|
+
# It extends `Fluxbit::Component` and provides options for configuring the avatar's
|
6
|
+
# appearance and behavior. You can control the avatar's color, placeholder initials,
|
7
|
+
# status, size, and other attributes. The avatar can display an image or a placeholder
|
8
|
+
# icon if no image is provided.
|
9
|
+
class Fluxbit::AvatarComponent < Fluxbit::Component
|
10
|
+
include Fluxbit::Config::AvatarComponent
|
11
|
+
|
12
|
+
# Initializes the avatar component with the given properties.
|
13
|
+
#
|
14
|
+
# @param [Hash] props The properties to customize the avatar.
|
15
|
+
# @option props [String] :color The color of the avatar border.
|
16
|
+
# @option props [String] :placeholder_initials The initials to display as a placeholder.
|
17
|
+
# @option props [Symbol] :status The status of the avatar (:online, :busy, :offline, :away).
|
18
|
+
# @option props [String] :status_position The position of the status indicator.
|
19
|
+
# @option props [Boolean] :rounded Whether the avatar should have rounded corners.
|
20
|
+
# @option props [Symbol, String] :size The size of the avatar.
|
21
|
+
# @option props [String] :src The source URL of the avatar image.
|
22
|
+
# @option props [String] :remove_class Classes to be removed from the default avatar class list.
|
23
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes, applied to the avatar container.
|
24
|
+
def initialize(**props)
|
25
|
+
super
|
26
|
+
@props = props
|
27
|
+
@color = @props.delete(:color) || @@color
|
28
|
+
@placeholder_initials = @props.delete(:placeholder_initials) || @@placeholder_initials
|
29
|
+
@status = @props[:status].nil? ? @@status : @props.delete(:status) # online, busy, offline, away
|
30
|
+
@status_position = (@props.delete(:status_position) || @@status_position).to_s.split("_").map(&:to_sym)
|
31
|
+
@rounded = @props[:rounded].nil? ? @@rounded : @props.delete(:rounded)
|
32
|
+
@size = @props.delete(:size) || @@size
|
33
|
+
@src = @props[:src]
|
34
|
+
declare_color
|
35
|
+
declare_classes
|
36
|
+
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
37
|
+
end
|
38
|
+
|
39
|
+
def declare_color
|
40
|
+
return unless @color.present?
|
41
|
+
add to: @props,
|
42
|
+
first_element: true,
|
43
|
+
class: "#{styles[:bordered]} #{@color.in?(styles[:color].keys) ? styles[:color][@color] : styles[:color][:info]}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def declare_classes
|
47
|
+
add to: @props,
|
48
|
+
first_element: true,
|
49
|
+
class: [
|
50
|
+
(!@placeholder_initials && @src.nil? ? styles[:placeholder_icon][:base] : ""),
|
51
|
+
@placeholder_initials ? styles[:initials][:base] : "",
|
52
|
+
styles[@rounded ? :rounded : :not_rounded][:base],
|
53
|
+
(@size.in?(styles[:size].keys) ? styles[:size][@size] : styles[:size][:md])
|
54
|
+
].join(" ")
|
55
|
+
end
|
56
|
+
|
57
|
+
def avatar_itself
|
58
|
+
return content_tag(:img, "", @props) unless @src.nil? || @placeholder_initials
|
59
|
+
|
60
|
+
content_tag :div, @props do
|
61
|
+
if @placeholder_initials
|
62
|
+
content_tag :span, @placeholder_initials, class: styles[:initials][:text]
|
63
|
+
else
|
64
|
+
placeholder_icon
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def placeholder_icon
|
70
|
+
svg_attributes = {
|
71
|
+
class: [ "absolute", "text-gray-400", "-left-1", placeholder_size ].join(" "),
|
72
|
+
fill: "currentColor",
|
73
|
+
viewBox: "0 0 20 20",
|
74
|
+
xmlns: "http://www.w3.org/2000/svg"
|
75
|
+
}
|
76
|
+
|
77
|
+
path_attributes = {
|
78
|
+
"fill-rule": "evenodd",
|
79
|
+
d: "M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z",
|
80
|
+
"clip-rule": "evenodd"
|
81
|
+
}
|
82
|
+
|
83
|
+
content_tag(:svg, svg_attributes) do
|
84
|
+
content_tag(:path, "", path_attributes)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def placeholder_size
|
89
|
+
return styles[:placeholder_icon][:size][@size] if @size.in?(styles[:placeholder_icon][:size].keys)
|
90
|
+
|
91
|
+
styles[:size][:md]
|
92
|
+
end
|
93
|
+
|
94
|
+
def dot_indicator
|
95
|
+
content_tag :span,
|
96
|
+
"",
|
97
|
+
class: [
|
98
|
+
styles[:status][:base],
|
99
|
+
styles[:status][:options][@status],
|
100
|
+
styles[@rounded ? :rounded : :not_rounded][:status_position][@status_position[0]],
|
101
|
+
styles[@rounded ? :rounded : :not_rounded][:status_position][@status_position[1]][@size]
|
102
|
+
].join(" ")
|
103
|
+
end
|
104
|
+
|
105
|
+
def call
|
106
|
+
return avatar_itself unless @status
|
107
|
+
|
108
|
+
content_tag :div, class: "relative" do
|
109
|
+
concat avatar_itself
|
110
|
+
concat dot_indicator
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The `Fluxbit::AvatarGroupComponent` is a component for rendering a group of avatars.
|
4
|
+
# It extends `Fluxbit::Component` and provides options for configuring the appearance
|
5
|
+
# and behavior of the avatar group. You can control the avatars and gravatars displayed
|
6
|
+
# within the group. The component supports rendering multiple avatars and gravatars,
|
7
|
+
# each of which can be styled or customized through various properties.
|
8
|
+
class Fluxbit::AvatarGroupComponent < Fluxbit::Component
|
9
|
+
include Fluxbit::Config::AvatarComponent
|
10
|
+
renders_many :avatars, Fluxbit::AvatarComponent
|
11
|
+
renders_many :gravatars, Fluxbit::GravatarComponent
|
12
|
+
|
13
|
+
def call
|
14
|
+
content_tag :div, class: styles[:group] do
|
15
|
+
avatars.each do |avatar|
|
16
|
+
concat render(avatar)
|
17
|
+
end
|
18
|
+
gravatars.each do |gravatar|
|
19
|
+
concat render(gravatar)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The `Fluxbit::BadgeComponent` is a customizable badge component that extends `Fluxbit::Component`.
|
5
|
+
# It allows you to create badges with different colors, sizes, borders, and shapes (pill).
|
6
|
+
class Fluxbit::BadgeComponent < Fluxbit::Component
|
7
|
+
include Fluxbit::Config::BadgeComponent
|
8
|
+
renders_one :popover, lambda { |**props, &block|
|
9
|
+
@popover_props = props
|
10
|
+
@popover_text = block.call
|
11
|
+
}
|
12
|
+
renders_one :tooltip, lambda { |**props, &block|
|
13
|
+
@tooltip_props = props
|
14
|
+
@tooltip_text = block.call
|
15
|
+
}
|
16
|
+
|
17
|
+
##
|
18
|
+
# Initializes the badge component with the given properties.
|
19
|
+
#
|
20
|
+
# @param [Hash] props The properties to customize the badge.
|
21
|
+
# @option props [Symbol, String] :color The color style of the badge.
|
22
|
+
# @option props [Boolean] :pill (false) Determines if the badge is pill-shaped.
|
23
|
+
# @option props [Symbol, Integer] :size The size of the badge (e.g., `0` to `1`).
|
24
|
+
# @option props [Symbol, String] :perfect_rounded (:none) Define if the bage is a perfect rounded with size (e.g., `0` to `5`).
|
25
|
+
# @option props [Symbol, String] :as The HTML tag to use for the badge (e.g., `:span`, `:div`).
|
26
|
+
# @option props [String] :remove_class ('') Classes to remove from the default class list.
|
27
|
+
# @option props [String] :popover_text (nil) Popover text (from Fluxbit::Component).
|
28
|
+
# @option props [Symbol] :popover_placement (:right) Popover placement (e.g., `:right`, `:left`, `:top`, `:bottom`) (from Fluxbit::Component).
|
29
|
+
# @option props [Symbol] :popover_trigger (:hover) Popover trigger (e.g., `:hover`, `:click`) (from Fluxbit::Component).
|
30
|
+
# @option props [String] :tooltip_text (nil) Tooltip text (from Fluxbit::Component).
|
31
|
+
# @option props [Symbol] :tooltip_placement (:right) Tooltip placement (e.g., `:right`, `:left`, `:top`, `:bottom`) (from Fluxbit::Component).
|
32
|
+
# @option props [Symbol] :tooltip_trigger (:hover) Tooltip trigger (e.g., `:hover`, `:click`) (from Fluxbit::Component).
|
33
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes.
|
34
|
+
#
|
35
|
+
# @return [Fluxbit::BadgeComponent]
|
36
|
+
def initialize(**props)
|
37
|
+
super
|
38
|
+
@props = props
|
39
|
+
@color = @props.delete(:color) || @@color
|
40
|
+
@pill = @props.delete(:pill) || @@pill
|
41
|
+
@size = @props.delete(:size) || @@size
|
42
|
+
@perfect_rounded = @props.delete(:perfect_rounded) || @@perfect_rounded
|
43
|
+
@notification = @props.delete(:notification) || @@notification
|
44
|
+
@as = @props.delete(:as) || @@as
|
45
|
+
add(class: badge_classes, to: @props, first_element: true)
|
46
|
+
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
47
|
+
end
|
48
|
+
|
49
|
+
def before_render
|
50
|
+
add_popover_or_tooltip
|
51
|
+
end
|
52
|
+
|
53
|
+
def call
|
54
|
+
concat(content_tag(@as, content, @props) + render_popover_or_tooltip.to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def badge_classes
|
60
|
+
@badge_classes ||= begin
|
61
|
+
base_classes = [
|
62
|
+
styles[:base],
|
63
|
+
styles[:colors][@color.to_sym],
|
64
|
+
styles[:sizes][@size.to_i],
|
65
|
+
styles[:perfect_rounded][@perfect_rounded.to_i],
|
66
|
+
notification_classes
|
67
|
+
]
|
68
|
+
base_classes << "rounded-full" if @pill
|
69
|
+
base_classes.join(" ")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def notification_classes
|
74
|
+
return "" unless @notification.present?
|
75
|
+
([ styles[:notification][:default] ] + @notification.split(" ").map do |position|
|
76
|
+
styles[:notification][:positions][position.to_sym]
|
77
|
+
end).join(" ")
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# The `Fluxbit::ButtonComponent` is a customizable button component that extends `Fluxbit::Component`.
|
5
|
+
# It allows you to create buttons with various styles, sizes, colors, and supports additional
|
6
|
+
# features like popovers and tooltips.
|
7
|
+
class Fluxbit::ButtonComponent < Fluxbit::Component
|
8
|
+
include Fluxbit::Config::ButtonComponent
|
9
|
+
renders_one :popover, lambda { |**props, &block|
|
10
|
+
@popover_props = props
|
11
|
+
@popover_text = block.call
|
12
|
+
}
|
13
|
+
renders_one :tooltip, lambda { |**props, &block|
|
14
|
+
@tooltip_props = props
|
15
|
+
@tooltip_text = block.call
|
16
|
+
}
|
17
|
+
|
18
|
+
##
|
19
|
+
# Initializes the button component with the given properties.
|
20
|
+
#
|
21
|
+
# @param [Hash] props The properties to customize the button.
|
22
|
+
# @option props [Object] :form (nil) The form object associated with the button.
|
23
|
+
# @option props [Symbol, String] :as The HTML tag to use for the button (e.g., `:button`, `:a`).
|
24
|
+
# @option props [Boolean] :pill (false) Determines if the button has pill-shaped edges.
|
25
|
+
# @option props [Symbol, String] :color The color style of the button.
|
26
|
+
# @option props [Symbol, String] :size The size of the button (e.g., `0` to `4`).
|
27
|
+
# @option props [Boolean] :disabled (false) Sets the button to a disabled state.
|
28
|
+
# @option props [String] :remove_class ('') Classes to remove from the default class list.
|
29
|
+
# @option props [String] :popover_text (nil) Popover text (from Fluxbit::Component).
|
30
|
+
# @option props [Symbol] :popover_placement (:right) Popover placement (e.g., `:right`, `:left`, `:top`, `:bottom`) (from Fluxbit::Component).
|
31
|
+
# @option props [Symbol] :popover_trigger (:hover) Popover trigger (e.g., `:hover`, `:click`) (from Fluxbit::Component).
|
32
|
+
# @option props [String] :tooltip_text (nil) Tooltip text (from Fluxbit::Component).
|
33
|
+
# @option props [Symbol] :tooltip_placement (:right) Tooltip placement (e.g., `:right`, `:left`, `:top`, `:bottom`) (from Fluxbit::Component).
|
34
|
+
# @option props [Symbol] :tooltip_trigger (:hover) Tooltip trigger (e.g., `:hover`, `:click`) (from Fluxbit::Component).
|
35
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes.
|
36
|
+
#
|
37
|
+
# @return [Fluxbit::ButtonComponent]
|
38
|
+
def initialize(**props)
|
39
|
+
super
|
40
|
+
@props = props
|
41
|
+
@form = @props.delete(:form)
|
42
|
+
@as = @props.delete(:as) || @@as
|
43
|
+
@pill = @props.delete(:pill) || @@pill
|
44
|
+
@color = @props.delete(:color) || @@color
|
45
|
+
@grouped = @props.delete(:grouped) || false
|
46
|
+
@first_button = @props.delete(:first_button) || false
|
47
|
+
@last_button = @props.delete(:last_button) || false
|
48
|
+
@outline = @color.end_with?("_outline")
|
49
|
+
declare_size(@props.delete(:size) || @@size)
|
50
|
+
declare_disabled
|
51
|
+
declare_classes
|
52
|
+
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
53
|
+
end
|
54
|
+
|
55
|
+
def declare_size(size)
|
56
|
+
return if size.blank?
|
57
|
+
|
58
|
+
add(
|
59
|
+
class: (styles[:size][size.to_i]),
|
60
|
+
to: @props,
|
61
|
+
first_element: true
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def declare_classes
|
66
|
+
add(class: styles[:pill][@pill ? :on : :off], to: @props, first_element: true) unless @outline
|
67
|
+
add(class: styles[:outline][:pill][@pill ? :on : :off], to: @props, first_element: true) if @outline
|
68
|
+
add(class: styles[:outline][@outline ? :on : :off], to: @props, first_element: true)
|
69
|
+
add(class: styles[:base], to: @props, first_element: true)
|
70
|
+
add(
|
71
|
+
class: (@color.in?(styles[:colors].keys) ? styles[:colors][@color] : styles[:colors][:info]),
|
72
|
+
to: @props,
|
73
|
+
first_element: true
|
74
|
+
)
|
75
|
+
add(class: styles[:inner][:base], to: @props) if @grouped
|
76
|
+
add(class: styles[:inner][:position][:start], to: @props) if @grouped && @first_button
|
77
|
+
add(class: styles[:inner][:position][:end], to: @props) if @grouped && @last_button
|
78
|
+
add(class: styles[:inner][:position][:middle], to: @props) if @grouped && !@last_button && !@first_button
|
79
|
+
end
|
80
|
+
|
81
|
+
def declare_disabled
|
82
|
+
return unless @props[:disabled].present? && @props[:disabled] == true
|
83
|
+
|
84
|
+
add(class: styles[:disabled], to: @props, first_element: true)
|
85
|
+
end
|
86
|
+
|
87
|
+
def before_render
|
88
|
+
add_popover_or_tooltip
|
89
|
+
end
|
90
|
+
|
91
|
+
def call
|
92
|
+
concat(
|
93
|
+
(@form.nil? ? content_tag(@as, content, @props) : @form.submit(**@props)) +
|
94
|
+
render_popover_or_tooltip.to_s
|
95
|
+
)
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The `Fluxbit::ButtonGroupComponent` is a component for rendering a group of buttons.
|
4
|
+
# It extends `Fluxbit::Component` and provides options for configuring the appearance
|
5
|
+
# and behavior of the button group. You can control the buttons displayed
|
6
|
+
# within the group. The component supports rendering multiple buttons,
|
7
|
+
# each of which can be styled or customized through various properties.
|
8
|
+
class Fluxbit::ButtonGroupComponent < Fluxbit::Component
|
9
|
+
attr_accessor :buttons_group
|
10
|
+
include Fluxbit::Config::ButtonComponent
|
11
|
+
# renders_many :buttons, Fluxbit::ButtonComponent
|
12
|
+
|
13
|
+
renders_many :buttons, lambda { |**props, &block|
|
14
|
+
@buttons_group << ComponentObj.new(props, view_context.capture(&block))
|
15
|
+
}
|
16
|
+
|
17
|
+
# Initializes the button group component with the given properties.
|
18
|
+
#
|
19
|
+
# @param [Hash] props The properties to customize the button group.
|
20
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes, applied to the button group container.
|
21
|
+
def initialize(**props)
|
22
|
+
super
|
23
|
+
@props = props
|
24
|
+
@buttons_group = []
|
25
|
+
add class: styles[:group], to: @props
|
26
|
+
end
|
27
|
+
|
28
|
+
def call
|
29
|
+
buttons
|
30
|
+
content_tag :div, **@props do
|
31
|
+
@buttons_group.each_with_index do |button, index|
|
32
|
+
button_props = button.props || {}
|
33
|
+
button_content = button.content
|
34
|
+
|
35
|
+
button_props[:grouped] = true
|
36
|
+
button_props[:first_button] = true if index == 0
|
37
|
+
button_props[:last_button] = true if index == @buttons_group.size - 1
|
38
|
+
|
39
|
+
concat Fluxbit::ButtonComponent.new(**button_props).with_content(button_content).render_in(view_context)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|