rails-active-ui 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/Rakefile +6 -0
- data/app/assets/stylesheets.css +73555 -0
- data/app/components/accordion_component.rb +34 -0
- data/app/components/ad_component.rb +28 -0
- data/app/components/api_component.rb +24 -0
- data/app/components/breadcrumb_component.rb +26 -0
- data/app/components/button_component.rb +49 -0
- data/app/components/calendar_component.rb +34 -0
- data/app/components/card_component.rb +56 -0
- data/app/components/checkbox_component.rb +41 -0
- data/app/components/column_component.rb +62 -0
- data/app/components/comment_component.rb +45 -0
- data/app/components/concerns/alignable.rb +21 -0
- data/app/components/concerns/attachable.rb +16 -0
- data/app/components/concerns/orientable.rb +21 -0
- data/app/components/concerns/positionable.rb +21 -0
- data/app/components/concerns/sizeable.rb +18 -0
- data/app/components/container_component.rb +23 -0
- data/app/components/dimmer_component.rb +30 -0
- data/app/components/divider_component.rb +30 -0
- data/app/components/dropdown_component.rb +63 -0
- data/app/components/embed_component.rb +32 -0
- data/app/components/emoji_component.rb +15 -0
- data/app/components/feed_component.rb +22 -0
- data/app/components/flag_component.rb +15 -0
- data/app/components/flyout_component.rb +41 -0
- data/app/components/form_component.rb +39 -0
- data/app/components/grid_component.rb +85 -0
- data/app/components/h_stack_component.rb +67 -0
- data/app/components/header_component.rb +60 -0
- data/app/components/icon_component.rb +41 -0
- data/app/components/image_component.rb +46 -0
- data/app/components/input_component.rb +52 -0
- data/app/components/item_component.rb +39 -0
- data/app/components/item_group_component.rb +30 -0
- data/app/components/label_component.rb +49 -0
- data/app/components/link_component.rb +23 -0
- data/app/components/list_component.rb +39 -0
- data/app/components/loader_component.rb +33 -0
- data/app/components/menu_component.rb +64 -0
- data/app/components/menu_item_component.rb +52 -0
- data/app/components/message_component.rb +54 -0
- data/app/components/modal_component.rb +50 -0
- data/app/components/nag_component.rb +25 -0
- data/app/components/overlay_component.rb +16 -0
- data/app/components/placeholder_component.rb +39 -0
- data/app/components/popup_component.rb +31 -0
- data/app/components/progress_component.rb +48 -0
- data/app/components/pusher_component.rb +18 -0
- data/app/components/rail_component.rb +31 -0
- data/app/components/rating_component.rb +41 -0
- data/app/components/reset_component.rb +12 -0
- data/app/components/reveal_component.rb +39 -0
- data/app/components/row_component.rb +39 -0
- data/app/components/search_component.rb +44 -0
- data/app/components/segment_component.rb +57 -0
- data/app/components/segment_group_component.rb +36 -0
- data/app/components/shape_component.rb +25 -0
- data/app/components/sidebar_component.rb +33 -0
- data/app/components/site_component.rb +12 -0
- data/app/components/slider_component.rb +46 -0
- data/app/components/state_component.rb +25 -0
- data/app/components/statistic_component.rb +43 -0
- data/app/components/step_component.rb +56 -0
- data/app/components/step_group_component.rb +38 -0
- data/app/components/sticky_component.rb +22 -0
- data/app/components/sub_header_component.rb +15 -0
- data/app/components/sub_menu_component.rb +24 -0
- data/app/components/tab_component.rb +24 -0
- data/app/components/table_cell_component.rb +60 -0
- data/app/components/table_component.rb +160 -0
- data/app/components/table_row_component.rb +43 -0
- data/app/components/text_component.rb +73 -0
- data/app/components/toast_component.rb +36 -0
- data/app/components/transition_component.rb +32 -0
- data/app/components/v_stack_component.rb +31 -0
- data/app/components/visibility_component.rb +22 -0
- data/app/helpers/component_helper.rb +109 -0
- data/app/helpers/fui_helper.rb +53 -0
- data/app/javascript/accordion.js +547 -0
- data/app/javascript/accordion.min.js +11 -0
- data/app/javascript/api.js +1112 -0
- data/app/javascript/api.min.js +11 -0
- data/app/javascript/calendar.js +1960 -0
- data/app/javascript/calendar.min.js +11 -0
- data/app/javascript/checkbox.js +819 -0
- data/app/javascript/checkbox.min.js +11 -0
- data/app/javascript/dimmer.js +686 -0
- data/app/javascript/dimmer.min.js +11 -0
- data/app/javascript/dropdown.js +4019 -0
- data/app/javascript/dropdown.min.js +11 -0
- data/app/javascript/embed.js +646 -0
- data/app/javascript/embed.min.js +11 -0
- data/app/javascript/flyout.js +1405 -0
- data/app/javascript/flyout.min.js +11 -0
- data/app/javascript/form.js +2070 -0
- data/app/javascript/form.min.js +11 -0
- data/app/javascript/jquery.js +10716 -0
- data/app/javascript/jquery.min.js +2 -0
- data/app/javascript/modal.js +1507 -0
- data/app/javascript/modal.min.js +11 -0
- data/app/javascript/nag.js +522 -0
- data/app/javascript/nag.min.js +11 -0
- data/app/javascript/popup.js +1457 -0
- data/app/javascript/popup.min.js +11 -0
- data/app/javascript/progress.js +922 -0
- data/app/javascript/progress.min.js +11 -0
- data/app/javascript/rating.js +496 -0
- data/app/javascript/rating.min.js +11 -0
- data/app/javascript/search.js +1519 -0
- data/app/javascript/search.min.js +11 -0
- data/app/javascript/shape.js +721 -0
- data/app/javascript/shape.min.js +11 -0
- data/app/javascript/sidebar.js +952 -0
- data/app/javascript/sidebar.min.js +11 -0
- data/app/javascript/site.js +415 -0
- data/app/javascript/site.min.js +11 -0
- data/app/javascript/slider.js +1449 -0
- data/app/javascript/slider.min.js +11 -0
- data/app/javascript/state.js +653 -0
- data/app/javascript/state.min.js +11 -0
- data/app/javascript/sticky.js +852 -0
- data/app/javascript/sticky.min.js +11 -0
- data/app/javascript/tab.js +867 -0
- data/app/javascript/tab.min.js +11 -0
- data/app/javascript/toast.js +916 -0
- data/app/javascript/toast.min.js +11 -0
- data/app/javascript/transition.js +955 -0
- data/app/javascript/transition.min.js +11 -0
- data/app/javascript/ui/controllers/fui_accordion_controller.js +45 -0
- data/app/javascript/ui/controllers/fui_api_controller.js +80 -0
- data/app/javascript/ui/controllers/fui_calendar_controller.js +66 -0
- data/app/javascript/ui/controllers/fui_checkbox_controller.js +48 -0
- data/app/javascript/ui/controllers/fui_dimmer_controller.js +45 -0
- data/app/javascript/ui/controllers/fui_dropdown_controller.js +68 -0
- data/app/javascript/ui/controllers/fui_embed_controller.js +49 -0
- data/app/javascript/ui/controllers/fui_flyout_controller.js +49 -0
- data/app/javascript/ui/controllers/fui_form_controller.js +62 -0
- data/app/javascript/ui/controllers/fui_modal_controller.js +61 -0
- data/app/javascript/ui/controllers/fui_nag_controller.js +52 -0
- data/app/javascript/ui/controllers/fui_popup_controller.js +58 -0
- data/app/javascript/ui/controllers/fui_progress_controller.js +60 -0
- data/app/javascript/ui/controllers/fui_rating_controller.js +49 -0
- data/app/javascript/ui/controllers/fui_search_controller.js +76 -0
- data/app/javascript/ui/controllers/fui_shape_controller.js +45 -0
- data/app/javascript/ui/controllers/fui_sidebar_controller.js +48 -0
- data/app/javascript/ui/controllers/fui_site_controller.js +29 -0
- data/app/javascript/ui/controllers/fui_slider_controller.js +53 -0
- data/app/javascript/ui/controllers/fui_state_controller.js +63 -0
- data/app/javascript/ui/controllers/fui_sticky_controller.js +50 -0
- data/app/javascript/ui/controllers/fui_tab_controller.js +57 -0
- data/app/javascript/ui/controllers/fui_toast_controller.js +60 -0
- data/app/javascript/ui/controllers/fui_transition_controller.js +60 -0
- data/app/javascript/ui/controllers/fui_visibility_controller.js +55 -0
- data/app/javascript/ui/index.js +114 -0
- data/app/javascript/visibility.js +1196 -0
- data/app/javascript/visibility.min.js +11 -0
- data/app/lib/component.rb +63 -0
- data/config/importmap.rb +27 -0
- data/config/initializers/ruby_template_handler.rb +31 -0
- data/config/routes.rb +2 -0
- data/lib/tasks/ui_tasks.rake +4 -0
- data/lib/ui/engine.rb +27 -0
- data/lib/ui/version.rb +3 -0
- data/lib/ui.rb +6 -0
- metadata +220 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Embed — embedded video/iframe content.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Embed(source: :youtube, embed_id: "dQw4w9WgXcQ")
|
|
7
|
+
# Embed(source: :vimeo, embed_id: "123456", placeholder: "thumb.jpg")
|
|
8
|
+
# Embed(url: "https://example.com/widget")
|
|
9
|
+
|
|
10
|
+
class EmbedComponent < Component
|
|
11
|
+
attribute :source, :string, default: nil
|
|
12
|
+
attribute :embed_id, :string, default: nil
|
|
13
|
+
attribute :url, :string, default: nil
|
|
14
|
+
attribute :placeholder, :string, default: nil
|
|
15
|
+
attribute :icon, :string, default: "video play"
|
|
16
|
+
attribute :autoplay, :boolean, default: true
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
data = { controller: "fui-embed" }
|
|
20
|
+
data[:source] = source if source
|
|
21
|
+
data[:id] = embed_id if embed_id
|
|
22
|
+
data[:url] = url if url
|
|
23
|
+
data[:placeholder] = placeholder if placeholder
|
|
24
|
+
|
|
25
|
+
icon_el = tag.i(class: "#{icon} icon")
|
|
26
|
+
placeholder_el = placeholder ? tag.img(class: "placeholder", src: placeholder) : nil
|
|
27
|
+
|
|
28
|
+
tag.div(class: "ui embed", data: data) {
|
|
29
|
+
safe_join([ icon_el, placeholder_el, @content ])
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Emoji — renders a Fomantic-UI emoji by name.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Emoji(name: "smile")
|
|
7
|
+
# Emoji(name: "thumbsup")
|
|
8
|
+
|
|
9
|
+
class EmojiComponent < Component
|
|
10
|
+
attribute :name, :string, default: nil
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
tag.em(class: "small", data: { emoji: ":#{name}:" })
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Feed — activity/event feed.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Feed(size: :small) {
|
|
7
|
+
# text '<div class="event">...</div>'.html_safe
|
|
8
|
+
# }
|
|
9
|
+
|
|
10
|
+
class FeedComponent < Component
|
|
11
|
+
attribute :size, :string, default: nil
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
classes = class_names(
|
|
15
|
+
"ui",
|
|
16
|
+
size,
|
|
17
|
+
"feed"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
tag.div(class: classes) { @content }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Flag — country flag icon.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Flag(country: "us")
|
|
7
|
+
# Flag(country: "fr")
|
|
8
|
+
|
|
9
|
+
class FlagComponent < Component
|
|
10
|
+
attribute :country, :string, default: nil
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
tag.i(class: "#{country} flag")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Flyout — slide-out panel from screen edge.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Flyout(direction: :right) { |c|
|
|
7
|
+
# c.header { text "Settings" }
|
|
8
|
+
# c.content { text "Flyout body" }
|
|
9
|
+
# c.actions {
|
|
10
|
+
# Button(variant: :primary) { text "Save" }
|
|
11
|
+
# }
|
|
12
|
+
# }
|
|
13
|
+
|
|
14
|
+
class FlyoutComponent < Component
|
|
15
|
+
attribute :direction, :string, default: "right"
|
|
16
|
+
attribute :closable, :boolean, default: true
|
|
17
|
+
|
|
18
|
+
slot :header
|
|
19
|
+
slot :content
|
|
20
|
+
slot :actions
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
classes = class_names(
|
|
24
|
+
"ui",
|
|
25
|
+
direction,
|
|
26
|
+
"flyout"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
data = { controller: "fui-flyout" }
|
|
30
|
+
data[:fui_flyout_closable_value] = "false" unless closable
|
|
31
|
+
|
|
32
|
+
close_el = closable ? tag.i(class: "close icon") : nil
|
|
33
|
+
header_el = @slots[:header] ? tag.div(class: "header") { @slots[:header] } : nil
|
|
34
|
+
content_el = @slots[:content] ? tag.div(class: "content") { @slots[:content] } : nil
|
|
35
|
+
actions_el = @slots[:actions] ? tag.div(class: "actions") { @slots[:actions] } : nil
|
|
36
|
+
|
|
37
|
+
tag.div(class: classes, data: data) {
|
|
38
|
+
safe_join([ close_el, header_el, content_el, @content.presence, actions_el ])
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Form — form layout and validation with Stimulus controller.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Form(action: "/submit", method: :post) {
|
|
7
|
+
# text '<div class="field"><label>Name</label><input type="text"></div>'.html_safe
|
|
8
|
+
# }
|
|
9
|
+
# Form(loading: true, size: :large) { ... }
|
|
10
|
+
|
|
11
|
+
class FormComponent < Component
|
|
12
|
+
attribute :size, :string, default: nil
|
|
13
|
+
attribute :loading, :boolean, default: false
|
|
14
|
+
attribute :success, :boolean, default: false
|
|
15
|
+
attribute :error, :boolean, default: false
|
|
16
|
+
attribute :warning, :boolean, default: false
|
|
17
|
+
attribute :inverted, :boolean, default: false
|
|
18
|
+
attribute :equal_width, :boolean, default: false
|
|
19
|
+
attribute :action, :string, default: nil
|
|
20
|
+
attribute :method_type, :string, default: "post"
|
|
21
|
+
attribute :reply, :boolean, default: false
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
classes = class_names(
|
|
25
|
+
"ui",
|
|
26
|
+
size,
|
|
27
|
+
{ "loading" => loading, "success" => success, "error" => error,
|
|
28
|
+
"warning" => warning, "inverted" => inverted,
|
|
29
|
+
"equal width" => equal_width, "reply" => reply },
|
|
30
|
+
"form"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
opts = { class: classes, data: { controller: "fui-form" } }
|
|
34
|
+
opts[:action] = action if action
|
|
35
|
+
opts[:method] = method_type if action
|
|
36
|
+
|
|
37
|
+
tag.form(**opts) { @content }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Grid — responsive grid system.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Grid(columns: 3, stackable: true) {
|
|
7
|
+
# Column { text "A" }
|
|
8
|
+
# Column { text "B" }
|
|
9
|
+
# Column { text "C" }
|
|
10
|
+
# }
|
|
11
|
+
|
|
12
|
+
class GridComponent < Component
|
|
13
|
+
NUMBERS = %w[one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen].freeze
|
|
14
|
+
|
|
15
|
+
attribute :columns, :integer, default: nil
|
|
16
|
+
attribute :stackable, :boolean, default: false
|
|
17
|
+
attribute :doubling, :boolean, default: false
|
|
18
|
+
attribute :centered, :boolean, default: false
|
|
19
|
+
attribute :divided, :string, default: nil
|
|
20
|
+
attribute :celled, :string, default: nil
|
|
21
|
+
attribute :padded, :string, default: nil
|
|
22
|
+
attribute :relaxed, :string, default: nil
|
|
23
|
+
attribute :equal_width, :boolean, default: false
|
|
24
|
+
attribute :reversed, :string, default: nil
|
|
25
|
+
attribute :container, :boolean, default: false
|
|
26
|
+
attribute :internal, :boolean, default: false
|
|
27
|
+
attribute :inverted, :boolean, default: false
|
|
28
|
+
attribute :aligned, :string, default: nil
|
|
29
|
+
|
|
30
|
+
def to_s
|
|
31
|
+
col_word = columns && columns.between?(1, 16) ? NUMBERS[columns - 1] : nil
|
|
32
|
+
|
|
33
|
+
classes = class_names(
|
|
34
|
+
"ui",
|
|
35
|
+
col_word && "#{col_word} column",
|
|
36
|
+
aligned && "#{aligned} aligned",
|
|
37
|
+
divided_class,
|
|
38
|
+
celled_class,
|
|
39
|
+
padded_class,
|
|
40
|
+
relaxed_class,
|
|
41
|
+
reversed && "#{reversed} reversed",
|
|
42
|
+
{ "stackable" => stackable, "doubling" => doubling, "centered" => centered,
|
|
43
|
+
"equal width" => equal_width, "container" => container,
|
|
44
|
+
"internally" => internal, "inverted" => inverted },
|
|
45
|
+
"grid"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
tag.div(class: classes) { @content }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def divided_class
|
|
54
|
+
case divided
|
|
55
|
+
when "vertically" then "vertically divided"
|
|
56
|
+
when "true", true then "divided"
|
|
57
|
+
when String then "#{divided} divided"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def celled_class
|
|
62
|
+
case celled
|
|
63
|
+
when "internally" then "internally celled"
|
|
64
|
+
when "true", true then "celled"
|
|
65
|
+
when String then "#{celled} celled"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def padded_class
|
|
70
|
+
case padded
|
|
71
|
+
when "vertically" then "vertically padded"
|
|
72
|
+
when "horizontally" then "horizontally padded"
|
|
73
|
+
when "true", true then "padded"
|
|
74
|
+
when String then "#{padded} padded"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def relaxed_class
|
|
79
|
+
case relaxed
|
|
80
|
+
when "very" then "very relaxed"
|
|
81
|
+
when "true", true then "relaxed"
|
|
82
|
+
when String then "#{relaxed} relaxed"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class HStackComponent < Component
|
|
4
|
+
attribute :spacing, :integer, default: 0
|
|
5
|
+
attribute :justify, :string, default: "start"
|
|
6
|
+
attribute :align, :string, default: "start"
|
|
7
|
+
attribute :padding, :integer, default: nil
|
|
8
|
+
attribute :rounded, :string, default: nil
|
|
9
|
+
attribute :shadow, :string, default: nil
|
|
10
|
+
attribute :bg, :string, default: nil
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
style_parts = [
|
|
14
|
+
"display:flex",
|
|
15
|
+
("gap:#{spacing}px" if spacing > 0),
|
|
16
|
+
("justify-content:#{justify_value}" if justify != "start"),
|
|
17
|
+
("align-items:#{align_value}" if align != "start"),
|
|
18
|
+
("padding:#{padding}px" if padding),
|
|
19
|
+
("border-radius:#{rounded_value}" if rounded),
|
|
20
|
+
("background:#{bg}" if bg)
|
|
21
|
+
].compact.join(";")
|
|
22
|
+
|
|
23
|
+
classes = [
|
|
24
|
+
("shadow-border-#{shadow}" if shadow)
|
|
25
|
+
].compact
|
|
26
|
+
|
|
27
|
+
opts = {}
|
|
28
|
+
opts[:class] = classes.join(" ") unless classes.empty?
|
|
29
|
+
opts[:style] = style_parts unless style_parts.empty?
|
|
30
|
+
|
|
31
|
+
tag.div(**opts) { @content }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def justify_value
|
|
37
|
+
case justify
|
|
38
|
+
when "center" then "center"
|
|
39
|
+
when "end" then "flex-end"
|
|
40
|
+
when "between" then "space-between"
|
|
41
|
+
when "around" then "space-around"
|
|
42
|
+
when "evenly" then "space-evenly"
|
|
43
|
+
else "flex-start"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def align_value
|
|
48
|
+
case align
|
|
49
|
+
when "center" then "center"
|
|
50
|
+
when "end" then "flex-end"
|
|
51
|
+
when "stretch" then "stretch"
|
|
52
|
+
when "baseline" then "baseline"
|
|
53
|
+
else "flex-start"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def rounded_value
|
|
58
|
+
case rounded
|
|
59
|
+
when "sm" then "0.125rem"
|
|
60
|
+
when "md" then "0.375rem"
|
|
61
|
+
when "lg" then "0.5rem"
|
|
62
|
+
when "xl" then "0.75rem"
|
|
63
|
+
when "full" then "9999px"
|
|
64
|
+
else "0.25rem"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Header — page and content headers.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Header(size: :h2) { text "Page Title" }
|
|
7
|
+
# Header(size: :h3, sub: true) { text "Subtitle" }
|
|
8
|
+
# Header(icon: "settings", dividing: true) { text "Settings" }
|
|
9
|
+
# Header(size: :h4, image: true) { |c|
|
|
10
|
+
# c.header_image { Image(src: "avatar.png", size: "mini", rounded: true) }
|
|
11
|
+
# text "Lena"
|
|
12
|
+
# SubHeader { text "Human Resources" }
|
|
13
|
+
# }
|
|
14
|
+
|
|
15
|
+
class HeaderComponent < Component
|
|
16
|
+
attribute :size, :string, default: "h2"
|
|
17
|
+
attribute :sub, :boolean, default: false
|
|
18
|
+
attribute :icon, :string, default: nil
|
|
19
|
+
attribute :image, :boolean, default: false
|
|
20
|
+
attribute :dividing, :boolean, default: false
|
|
21
|
+
attribute :block_header, :boolean, default: false
|
|
22
|
+
attribute :inverted, :boolean, default: false
|
|
23
|
+
attribute :color, :string, default: nil
|
|
24
|
+
attribute :aligned, :string, default: nil
|
|
25
|
+
attribute :attached, :string, default: nil
|
|
26
|
+
attribute :disabled, :boolean, default: false
|
|
27
|
+
attribute :floating, :boolean, default: false
|
|
28
|
+
|
|
29
|
+
slot :header_image
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
classes = class_names(
|
|
33
|
+
"ui",
|
|
34
|
+
color,
|
|
35
|
+
aligned && "#{aligned} aligned",
|
|
36
|
+
attached && "#{attached} attached",
|
|
37
|
+
{ "sub" => sub, "dividing" => dividing, "block" => block_header,
|
|
38
|
+
"inverted" => inverted, "disabled" => disabled, "floating" => floating,
|
|
39
|
+
"icon" => icon && !@content, "image" => image },
|
|
40
|
+
"header"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
tag_name = size.to_s.start_with?("h") ? size.to_s.to_sym : :h2
|
|
44
|
+
icon_el = icon ? tag.i(class: "#{icon} icon") : nil
|
|
45
|
+
|
|
46
|
+
if image && @slots[:header_image]
|
|
47
|
+
# Image header: image outside content div, text + sub header inside content div
|
|
48
|
+
tag.public_send(tag_name, class: classes) {
|
|
49
|
+
safe_join([
|
|
50
|
+
@slots[:header_image],
|
|
51
|
+
tag.div(class: "content") { @content }
|
|
52
|
+
])
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
tag.public_send(tag_name, class: classes) {
|
|
56
|
+
safe_join([ icon_el, @content ])
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Icon — icon element using Fomantic-UI icon font.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Icon(name: "home")
|
|
7
|
+
# Icon(name: "heart", color: :red, size: :large)
|
|
8
|
+
# Icon(name: "spinner", loading: true)
|
|
9
|
+
|
|
10
|
+
class IconComponent < Component
|
|
11
|
+
attribute :name, :string, default: nil
|
|
12
|
+
attribute :size, :string, default: nil
|
|
13
|
+
attribute :color, :string, default: nil
|
|
14
|
+
attribute :disabled, :boolean, default: false
|
|
15
|
+
attribute :loading, :boolean, default: false
|
|
16
|
+
attribute :fitted, :boolean, default: false
|
|
17
|
+
attribute :link, :boolean, default: false
|
|
18
|
+
attribute :circular, :boolean, default: false
|
|
19
|
+
attribute :bordered, :boolean, default: false
|
|
20
|
+
attribute :inverted, :boolean, default: false
|
|
21
|
+
attribute :flipped, :string, default: nil
|
|
22
|
+
attribute :rotated, :string, default: nil
|
|
23
|
+
attribute :corner, :string, default: nil
|
|
24
|
+
|
|
25
|
+
def to_s
|
|
26
|
+
classes = class_names(
|
|
27
|
+
name,
|
|
28
|
+
size,
|
|
29
|
+
color,
|
|
30
|
+
flipped && "#{flipped} flipped",
|
|
31
|
+
rotated && "#{rotated} rotated",
|
|
32
|
+
corner && "#{corner} corner",
|
|
33
|
+
{ "disabled" => disabled, "loading" => loading, "fitted" => fitted,
|
|
34
|
+
"link" => link, "circular" => circular, "bordered" => bordered,
|
|
35
|
+
"inverted" => inverted },
|
|
36
|
+
"icon"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
tag.i(class: classes)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Image — image element. Merges the holy spec primitive with Fomantic-UI image.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Image(src: "photo.jpg")
|
|
7
|
+
# Image(src: "avatar.png", avatar: true, size: :mini)
|
|
8
|
+
# Image(src: "logo.svg", circular: true, centered: true)
|
|
9
|
+
|
|
10
|
+
class ImageComponent < Component
|
|
11
|
+
attribute :src, :string, default: nil
|
|
12
|
+
attribute :alt, :string, default: ""
|
|
13
|
+
attribute :size, :string, default: nil
|
|
14
|
+
attribute :width, :integer, default: nil
|
|
15
|
+
attribute :height, :integer, default: nil
|
|
16
|
+
attribute :shrink, :boolean, default: true
|
|
17
|
+
attribute :rounded, :boolean, default: false
|
|
18
|
+
attribute :circular, :boolean, default: false
|
|
19
|
+
attribute :bordered, :boolean, default: false
|
|
20
|
+
attribute :fluid, :boolean, default: false
|
|
21
|
+
attribute :avatar, :boolean, default: false
|
|
22
|
+
attribute :centered, :boolean, default: false
|
|
23
|
+
attribute :spaced, :string, default: nil
|
|
24
|
+
attribute :hidden, :boolean, default: false
|
|
25
|
+
attribute :disabled, :boolean, default: false
|
|
26
|
+
attribute :inline, :boolean, default: false
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
classes = class_names(
|
|
30
|
+
"ui",
|
|
31
|
+
size,
|
|
32
|
+
spaced && "#{spaced} spaced",
|
|
33
|
+
{ "rounded" => rounded, "circular" => circular, "bordered" => bordered,
|
|
34
|
+
"fluid" => fluid, "avatar" => avatar, "centered" => centered,
|
|
35
|
+
"hidden" => hidden, "disabled" => disabled, "inline" => inline },
|
|
36
|
+
"image"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
opts = { class: classes, src: src, alt: alt }
|
|
40
|
+
opts[:width] = width if width
|
|
41
|
+
opts[:height] = height if height
|
|
42
|
+
opts[:style] = "flex-shrink:0" unless shrink
|
|
43
|
+
|
|
44
|
+
tag.img(**opts)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Input — text input fields with icon, labeled, and action variants.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Input(placeholder: "Search...", icon: "search")
|
|
7
|
+
# Input(icon: "users", icon_position: "left", placeholder: "Find users...")
|
|
8
|
+
# Input(labeled: true) { text "$" }
|
|
9
|
+
|
|
10
|
+
class InputComponent < Component
|
|
11
|
+
attribute :icon, :string, default: nil
|
|
12
|
+
attribute :icon_position, :string, default: "right"
|
|
13
|
+
attribute :labeled, :boolean, default: false
|
|
14
|
+
attribute :action, :boolean, default: false
|
|
15
|
+
attribute :transparent, :boolean, default: false
|
|
16
|
+
attribute :fluid, :boolean, default: false
|
|
17
|
+
attribute :size, :string, default: nil
|
|
18
|
+
attribute :loading, :boolean, default: false
|
|
19
|
+
attribute :disabled, :boolean, default: false
|
|
20
|
+
attribute :error, :boolean, default: false
|
|
21
|
+
attribute :inverted, :boolean, default: false
|
|
22
|
+
attribute :placeholder, :string, default: nil
|
|
23
|
+
attribute :input_type, :string, default: "text"
|
|
24
|
+
attribute :name, :string, default: nil
|
|
25
|
+
attribute :value, :string, default: nil
|
|
26
|
+
|
|
27
|
+
def to_s
|
|
28
|
+
classes = class_names(
|
|
29
|
+
"ui",
|
|
30
|
+
size,
|
|
31
|
+
{ "left icon" => icon && icon_position == "left",
|
|
32
|
+
"icon" => icon && icon_position != "left",
|
|
33
|
+
"labeled" => labeled, "action" => action, "transparent" => transparent,
|
|
34
|
+
"fluid" => fluid, "loading" => loading, "disabled" => disabled,
|
|
35
|
+
"error" => error, "inverted" => inverted },
|
|
36
|
+
"input"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
input_opts = { type: input_type }
|
|
40
|
+
input_opts[:placeholder] = placeholder if placeholder
|
|
41
|
+
input_opts[:name] = name if name
|
|
42
|
+
input_opts[:value] = value if value
|
|
43
|
+
input_opts[:disabled] = "disabled" if disabled
|
|
44
|
+
|
|
45
|
+
icon_el = icon ? tag.i(class: "#{icon} icon") : nil
|
|
46
|
+
input_el = tag.input(**input_opts)
|
|
47
|
+
|
|
48
|
+
tag.div(class: classes) {
|
|
49
|
+
safe_join([ @content, input_el, icon_el ])
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Item — individual content item within an ItemGroup.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# ItemGroup(divided: true) {
|
|
7
|
+
# Item { |c|
|
|
8
|
+
# c.image { Image(src: "product.jpg", size: "small") }
|
|
9
|
+
# c.header { text "Product Name" }
|
|
10
|
+
# c.meta { text "$19.99" }
|
|
11
|
+
# c.description { text "A great product." }
|
|
12
|
+
# c.extra { text "In stock" }
|
|
13
|
+
# }
|
|
14
|
+
# }
|
|
15
|
+
|
|
16
|
+
class ItemComponent < Component
|
|
17
|
+
slot :image
|
|
18
|
+
slot :header
|
|
19
|
+
slot :meta
|
|
20
|
+
slot :description
|
|
21
|
+
slot :extra
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
image_el = @slots[:image] ? tag.div(class: "image") { @slots[:image] } : nil
|
|
25
|
+
|
|
26
|
+
content_parts = [
|
|
27
|
+
(@slots[:header] ? tag.div(class: "header") { @slots[:header] } : nil),
|
|
28
|
+
(@slots[:meta] ? tag.div(class: "meta") { @slots[:meta] } : nil),
|
|
29
|
+
(@slots[:description] ? tag.div(class: "description") { @slots[:description] } : nil),
|
|
30
|
+
(@slots[:extra] ? tag.div(class: "extra") { @slots[:extra] } : nil)
|
|
31
|
+
].compact
|
|
32
|
+
|
|
33
|
+
content_el = content_parts.any? ? tag.div(class: "content") { safe_join(content_parts) } : nil
|
|
34
|
+
|
|
35
|
+
tag.div(class: "item") {
|
|
36
|
+
safe_join([ image_el, content_el, @content.presence ])
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ItemGroup — container for grouped content items.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# ItemGroup(divided: true, relaxed: true) {
|
|
7
|
+
# Item { |c|
|
|
8
|
+
# c.image { Image(src: "photo.jpg", size: "small") }
|
|
9
|
+
# c.header { text "Title" }
|
|
10
|
+
# c.description { text "Description" }
|
|
11
|
+
# }
|
|
12
|
+
# }
|
|
13
|
+
|
|
14
|
+
class ItemGroupComponent < Component
|
|
15
|
+
attribute :divided, :boolean, default: false
|
|
16
|
+
attribute :relaxed, :boolean, default: false
|
|
17
|
+
attribute :link, :boolean, default: false
|
|
18
|
+
attribute :unstackable, :boolean, default: false
|
|
19
|
+
|
|
20
|
+
def to_s
|
|
21
|
+
classes = class_names(
|
|
22
|
+
"ui",
|
|
23
|
+
{ "divided" => divided, "relaxed" => relaxed,
|
|
24
|
+
"link" => link, "unstackable" => unstackable },
|
|
25
|
+
"items"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
tag.div(class: classes) { @content }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Label — labels and tags.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Label(color: :blue) { text "New" }
|
|
7
|
+
# Label(tag_style: true, color: :teal) { text "Featured" }
|
|
8
|
+
# Label(ribbon: true, color: :red) { text "Sale" }
|
|
9
|
+
# Label(icon: "mail", detail: "23") { text "Mail" }
|
|
10
|
+
|
|
11
|
+
class LabelComponent < Component
|
|
12
|
+
include Attachable
|
|
13
|
+
|
|
14
|
+
attribute :color, :string, default: nil
|
|
15
|
+
attribute :size, :string, default: nil
|
|
16
|
+
attribute :pointing, :string, default: nil
|
|
17
|
+
attribute :corner, :string, default: nil
|
|
18
|
+
attribute :ribbon, :boolean, default: false
|
|
19
|
+
attribute :circular, :boolean, default: false
|
|
20
|
+
attribute :floating, :boolean, default: false
|
|
21
|
+
attribute :tag_style, :boolean, default: false
|
|
22
|
+
attribute :detail, :string, default: nil
|
|
23
|
+
attribute :icon, :string, default: nil
|
|
24
|
+
attribute :image, :boolean, default: false
|
|
25
|
+
attribute :basic, :boolean, default: false
|
|
26
|
+
attribute :horizontal, :boolean, default: false
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
classes = class_names(
|
|
30
|
+
"ui",
|
|
31
|
+
color,
|
|
32
|
+
size,
|
|
33
|
+
pointing && "#{pointing} pointing",
|
|
34
|
+
corner && "#{corner} corner",
|
|
35
|
+
{ "attached" => attached,
|
|
36
|
+
"ribbon" => ribbon, "circular" => circular, "floating" => floating,
|
|
37
|
+
"tag" => tag_style, "image" => image, "basic" => basic,
|
|
38
|
+
"horizontal" => horizontal },
|
|
39
|
+
"label"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
icon_el = icon ? tag.i(class: "#{icon} icon") : nil
|
|
43
|
+
detail_el = detail ? tag.div(class: "detail") { detail } : nil
|
|
44
|
+
|
|
45
|
+
tag.div(class: classes) {
|
|
46
|
+
safe_join([ icon_el, @content, detail_el ])
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Link — anchor element.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Link(href: "/about") { text "About Us" }
|
|
7
|
+
# Link(href: "/help", target: "_blank") { text "Help" }
|
|
8
|
+
|
|
9
|
+
class LinkComponent < Component
|
|
10
|
+
attribute :href, :string, default: "#"
|
|
11
|
+
attribute :target, :string, default: nil
|
|
12
|
+
attribute :rel, :string, default: nil
|
|
13
|
+
attribute :css_class, :string, default: nil
|
|
14
|
+
|
|
15
|
+
def to_s
|
|
16
|
+
opts = { href: href }
|
|
17
|
+
opts[:class] = css_class if css_class
|
|
18
|
+
opts[:target] = target if target
|
|
19
|
+
opts[:rel] = rel if rel
|
|
20
|
+
|
|
21
|
+
tag.a(**opts) { @content }
|
|
22
|
+
end
|
|
23
|
+
end
|