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,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Table — data tables with column accumulator pattern.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Table(striped: true, rows: @users) { |c|
|
|
7
|
+
# c.column(:name, heading: "Name") { |user|
|
|
8
|
+
# Text(weight: :bold) { text user.name }
|
|
9
|
+
# }
|
|
10
|
+
# c.column(:email) { |user|
|
|
11
|
+
# Text(color: :grey) { text user.email }
|
|
12
|
+
# }
|
|
13
|
+
# }
|
|
14
|
+
#
|
|
15
|
+
# Or with manual content:
|
|
16
|
+
# Table(celled: true) { |c|
|
|
17
|
+
# c.header {
|
|
18
|
+
# TableRow {
|
|
19
|
+
# TableCell(heading: true) { text "Name" }
|
|
20
|
+
# TableCell(heading: true) { text "Age" }
|
|
21
|
+
# }
|
|
22
|
+
# }
|
|
23
|
+
# TableRow {
|
|
24
|
+
# TableCell { text "Alice" }
|
|
25
|
+
# TableCell { text "30" }
|
|
26
|
+
# }
|
|
27
|
+
# }
|
|
28
|
+
|
|
29
|
+
class TableComponent < Component
|
|
30
|
+
attribute :rows, default: nil
|
|
31
|
+
attribute :definition, :boolean, default: false
|
|
32
|
+
attribute :structured, :boolean, default: false
|
|
33
|
+
attribute :single_line, :boolean, default: false
|
|
34
|
+
attribute :fixed, :boolean, default: false
|
|
35
|
+
attribute :selectable, :boolean, default: false
|
|
36
|
+
attribute :striped, :boolean, default: false
|
|
37
|
+
attribute :sortable, :boolean, default: false
|
|
38
|
+
attribute :celled, :boolean, default: false
|
|
39
|
+
attribute :basic, :string, default: nil
|
|
40
|
+
attribute :compact, :string, default: nil
|
|
41
|
+
attribute :padded, :string, default: nil
|
|
42
|
+
attribute :collapsing, :boolean, default: false
|
|
43
|
+
attribute :inverted, :boolean, default: false
|
|
44
|
+
attribute :color, :string, default: nil
|
|
45
|
+
attribute :size, :string, default: nil
|
|
46
|
+
attribute :unstackable, :boolean, default: false
|
|
47
|
+
attribute :stackable, :boolean, default: false
|
|
48
|
+
attribute :attached, :string, default: nil
|
|
49
|
+
|
|
50
|
+
slot :header
|
|
51
|
+
slot :footer
|
|
52
|
+
|
|
53
|
+
def columns
|
|
54
|
+
@columns ||= []
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def column(key, heading: key.to_s.titleize, &block)
|
|
58
|
+
columns << { key: key, heading: heading, block: block }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def to_s
|
|
62
|
+
classes = class_names(
|
|
63
|
+
"ui",
|
|
64
|
+
size,
|
|
65
|
+
color,
|
|
66
|
+
basic_class,
|
|
67
|
+
compact_class,
|
|
68
|
+
padded_class,
|
|
69
|
+
attached_class,
|
|
70
|
+
{ "definition" => definition,
|
|
71
|
+
"structured" => structured,
|
|
72
|
+
"single line" => single_line,
|
|
73
|
+
"fixed" => fixed,
|
|
74
|
+
"selectable" => selectable,
|
|
75
|
+
"striped" => striped,
|
|
76
|
+
"sortable" => sortable,
|
|
77
|
+
"celled" => celled,
|
|
78
|
+
"collapsing" => collapsing,
|
|
79
|
+
"inverted" => inverted,
|
|
80
|
+
"unstackable" => unstackable,
|
|
81
|
+
"stackable" => stackable },
|
|
82
|
+
"table"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if columns.any? && rows
|
|
86
|
+
column_table(classes)
|
|
87
|
+
else
|
|
88
|
+
manual_table(classes)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def column_table(classes)
|
|
95
|
+
head_cells = columns.map { |col| tag.th { col[:heading] } }
|
|
96
|
+
|
|
97
|
+
body_rows = Array(rows).map { |row|
|
|
98
|
+
cells = columns.map { |col|
|
|
99
|
+
cell_content = col[:block]
|
|
100
|
+
.then { |b| b && @view_context.capture(row, &b) }
|
|
101
|
+
.then { |c| c || ERB::Util.html_escape(row.public_send(col[:key]).to_s) }
|
|
102
|
+
tag.td { cell_content }
|
|
103
|
+
}
|
|
104
|
+
tag.tr { safe_join(cells) }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
footer_el = @slots[:footer] ? tag.tfoot { @slots[:footer] } : nil
|
|
108
|
+
|
|
109
|
+
tag.table(class: classes) {
|
|
110
|
+
safe_join([
|
|
111
|
+
tag.thead { tag.tr { safe_join(head_cells) } },
|
|
112
|
+
tag.tbody { safe_join(body_rows) },
|
|
113
|
+
footer_el
|
|
114
|
+
])
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def manual_table(classes)
|
|
119
|
+
header_el = @slots[:header] ? tag.thead { @slots[:header] } : nil
|
|
120
|
+
footer_el = @slots[:footer] ? tag.tfoot { @slots[:footer] } : nil
|
|
121
|
+
body_el = @content.presence ? tag.tbody { @content } : nil
|
|
122
|
+
|
|
123
|
+
tag.table(class: classes) {
|
|
124
|
+
safe_join([ header_el, body_el, footer_el ])
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def basic_class
|
|
129
|
+
case basic
|
|
130
|
+
when "very" then "very basic"
|
|
131
|
+
when "true", true then "basic"
|
|
132
|
+
when String then "#{basic} basic"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def compact_class
|
|
137
|
+
case compact
|
|
138
|
+
when "very" then "very compact"
|
|
139
|
+
when "true", true then "compact"
|
|
140
|
+
when String then "#{compact} compact"
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def attached_class
|
|
145
|
+
case attached
|
|
146
|
+
when "top" then "top attached"
|
|
147
|
+
when "bottom" then "bottom attached"
|
|
148
|
+
when "" then "attached"
|
|
149
|
+
when String then "#{attached} attached"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def padded_class
|
|
154
|
+
case padded
|
|
155
|
+
when "very" then "very padded"
|
|
156
|
+
when "true", true then "padded"
|
|
157
|
+
when String then "#{padded} padded"
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# TableRow — a table row.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Table(celled: true) { |c|
|
|
7
|
+
# c.header {
|
|
8
|
+
# TableRow {
|
|
9
|
+
# TableCell(heading: true) { text "Name" }
|
|
10
|
+
# TableCell(heading: true) { text "Age" }
|
|
11
|
+
# }
|
|
12
|
+
# }
|
|
13
|
+
# TableRow {
|
|
14
|
+
# TableCell { text "Alice" }
|
|
15
|
+
# TableCell { text "30" }
|
|
16
|
+
# }
|
|
17
|
+
# }
|
|
18
|
+
|
|
19
|
+
class TableRowComponent < Component
|
|
20
|
+
attribute :active, :boolean, default: false
|
|
21
|
+
attribute :positive, :boolean, default: false
|
|
22
|
+
attribute :negative, :boolean, default: false
|
|
23
|
+
attribute :warning, :boolean, default: false
|
|
24
|
+
attribute :error, :boolean, default: false
|
|
25
|
+
attribute :disabled, :boolean, default: false
|
|
26
|
+
|
|
27
|
+
def to_s
|
|
28
|
+
classes = [
|
|
29
|
+
("active" if active),
|
|
30
|
+
("positive" if positive),
|
|
31
|
+
("negative" if negative),
|
|
32
|
+
("warning" if warning),
|
|
33
|
+
("error" if error),
|
|
34
|
+
("disabled" if disabled)
|
|
35
|
+
].compact
|
|
36
|
+
|
|
37
|
+
if classes.any?
|
|
38
|
+
tag.tr(class: classes.join(" ")) { @content }
|
|
39
|
+
else
|
|
40
|
+
tag.tr { @content }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Text — inline text container. Merges the holy spec primitive with Fomantic-UI text.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Text { text "Hello" }
|
|
7
|
+
# Text(size: :sm, style: :secondary) { text "Muted text" }
|
|
8
|
+
# Text(weight: :bold, color: :red) { text "Important" }
|
|
9
|
+
|
|
10
|
+
class TextComponent < Component
|
|
11
|
+
attribute :style, :string, default: nil
|
|
12
|
+
attribute :size, :string, default: nil
|
|
13
|
+
attribute :weight, :string, default: nil
|
|
14
|
+
attribute :color, :string, default: nil
|
|
15
|
+
|
|
16
|
+
def to_s
|
|
17
|
+
has_fui_class = color || size_fui
|
|
18
|
+
|
|
19
|
+
fui_classes = if has_fui_class
|
|
20
|
+
class_names(
|
|
21
|
+
"ui",
|
|
22
|
+
color,
|
|
23
|
+
size_fui,
|
|
24
|
+
"text"
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
style_parts = [
|
|
29
|
+
(style && "text-#{style}"),
|
|
30
|
+
(size_css && "font-size:#{size_css}"),
|
|
31
|
+
(weight && "font-weight:#{weight_value}")
|
|
32
|
+
].compact
|
|
33
|
+
|
|
34
|
+
opts = {}
|
|
35
|
+
opts[:class] = fui_classes if fui_classes
|
|
36
|
+
opts[:style] = style_parts.join(";") if style_parts.any?
|
|
37
|
+
|
|
38
|
+
tag.span(**opts) { @content }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# Fomantic-UI text size classes
|
|
44
|
+
def size_fui
|
|
45
|
+
case size
|
|
46
|
+
when "mini", "tiny", "small", "medium", "large", "big", "huge", "massive"
|
|
47
|
+
size
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# CSS font-size for spec-style sizes (sm, xs, etc.)
|
|
52
|
+
def size_css
|
|
53
|
+
case size
|
|
54
|
+
when "xs" then "0.75rem"
|
|
55
|
+
when "sm" then "0.875rem"
|
|
56
|
+
when "lg" then "1.125rem"
|
|
57
|
+
when "xl" then "1.25rem"
|
|
58
|
+
when "2xl" then "1.5rem"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def weight_value
|
|
63
|
+
case weight.to_s
|
|
64
|
+
when "light" then "300"
|
|
65
|
+
when "normal" then "400"
|
|
66
|
+
when "medium" then "500"
|
|
67
|
+
when "semibold" then "600"
|
|
68
|
+
when "bold" then "700"
|
|
69
|
+
when "heavy" then "900"
|
|
70
|
+
else weight
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Toast — toast notifications.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Toast(title: "Success", message: "Item saved.", type: :success)
|
|
7
|
+
# Toast(title: "Error", message: "Something went wrong.", type: :error, position: "bottom right")
|
|
8
|
+
|
|
9
|
+
class ToastComponent < Component
|
|
10
|
+
include Positionable
|
|
11
|
+
default position: "top right"
|
|
12
|
+
|
|
13
|
+
attribute :title, :string, default: nil
|
|
14
|
+
attribute :message, :string, default: nil
|
|
15
|
+
attribute :type, :string, default: "neutral"
|
|
16
|
+
attribute :display_time, :integer, default: 3000
|
|
17
|
+
attribute :close_icon, :boolean, default: false
|
|
18
|
+
attribute :compact, :boolean, default: true
|
|
19
|
+
attribute :show_progress, :boolean, default: false
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
data = {
|
|
23
|
+
controller: "fui-toast",
|
|
24
|
+
fui_toast_class_value: type,
|
|
25
|
+
fui_toast_position_value: position,
|
|
26
|
+
fui_toast_display_time_value: display_time
|
|
27
|
+
}
|
|
28
|
+
data[:fui_toast_title_value] = title if title
|
|
29
|
+
data[:fui_toast_message_value] = message if message
|
|
30
|
+
data[:fui_toast_close_icon_value] = "true" if close_icon
|
|
31
|
+
data[:fui_toast_compact_value] = "true" if compact
|
|
32
|
+
data[:fui_toast_show_progress_value] = "true" if show_progress
|
|
33
|
+
|
|
34
|
+
tag.div(data: data) { @content }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Transition — CSS animation framework.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Transition(animation: :fade, visible: true) { text "Fading content" }
|
|
7
|
+
# Transition(animation: :scale, duration: 500) { text "Scaling content" }
|
|
8
|
+
|
|
9
|
+
class TransitionComponent < Component
|
|
10
|
+
attribute :animation, :string, default: "fade"
|
|
11
|
+
attribute :duration, :integer, default: 500
|
|
12
|
+
attribute :visible, :boolean, default: true
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
classes = class_names(
|
|
16
|
+
animation,
|
|
17
|
+
{ "visible" => visible,
|
|
18
|
+
"hidden" => !visible },
|
|
19
|
+
"transition"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
tag.div(
|
|
23
|
+
class: classes,
|
|
24
|
+
style: "animation-duration:#{duration}ms",
|
|
25
|
+
data: {
|
|
26
|
+
controller: "fui-transition",
|
|
27
|
+
fui_transition_animation_value: animation,
|
|
28
|
+
fui_transition_duration_value: duration
|
|
29
|
+
}
|
|
30
|
+
) { @content }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class VStackComponent < Component
|
|
4
|
+
attribute :spacing, :integer, default: 0
|
|
5
|
+
attribute :align, :string, default: "start"
|
|
6
|
+
|
|
7
|
+
def to_s
|
|
8
|
+
style_parts = [
|
|
9
|
+
"display:flex",
|
|
10
|
+
"flex-direction:column",
|
|
11
|
+
("gap:#{spacing}px" if spacing > 0),
|
|
12
|
+
("align-items:#{align_value}" if align != "start")
|
|
13
|
+
].compact.join(";")
|
|
14
|
+
|
|
15
|
+
opts = {}
|
|
16
|
+
opts[:style] = style_parts unless style_parts.empty?
|
|
17
|
+
|
|
18
|
+
tag.div(**opts) { @content }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def align_value
|
|
24
|
+
case align
|
|
25
|
+
when "center" then "center"
|
|
26
|
+
when "end" then "flex-end"
|
|
27
|
+
when "stretch" then "stretch"
|
|
28
|
+
else "flex-start"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Visibility — scroll-based visibility detection.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# Visibility(once: true) { Image(src: "lazy.jpg") }
|
|
7
|
+
# Visibility(offset: 100) { text "I trigger when visible" }
|
|
8
|
+
|
|
9
|
+
class VisibilityComponent < Component
|
|
10
|
+
attribute :type, :string, default: nil
|
|
11
|
+
attribute :offset, :integer, default: 0
|
|
12
|
+
attribute :once, :boolean, default: false
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
data = { controller: "fui-visibility" }
|
|
16
|
+
data[:fui_visibility_type_value] = type if type
|
|
17
|
+
data[:fui_visibility_offset_value] = offset if offset > 0
|
|
18
|
+
data[:fui_visibility_once_value] = "true" if once
|
|
19
|
+
|
|
20
|
+
tag.div(data: data) { @content }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The Registry of Names
|
|
4
|
+
#
|
|
5
|
+
# All components available to views are declared here. There is no
|
|
6
|
+
# method_missing sorcery, no dynamic resolution, no convention-based guessing.
|
|
7
|
+
# If a component is not in the registry, it does not exist.
|
|
8
|
+
#
|
|
9
|
+
# To create a new component: add one line to COMPONENT_MAP and create the class.
|
|
10
|
+
#
|
|
11
|
+
# See: specs/the-holy-view-spec.md, Article 3
|
|
12
|
+
|
|
13
|
+
module ComponentHelper
|
|
14
|
+
COMPONENT_MAP = {
|
|
15
|
+
# Layout Primitives
|
|
16
|
+
VStack: VStackComponent,
|
|
17
|
+
HStack: HStackComponent,
|
|
18
|
+
Column: ColumnComponent,
|
|
19
|
+
Row: RowComponent,
|
|
20
|
+
Pusher: PusherComponent,
|
|
21
|
+
Overlay: OverlayComponent,
|
|
22
|
+
Link: LinkComponent,
|
|
23
|
+
SubHeader: SubHeaderComponent,
|
|
24
|
+
|
|
25
|
+
# Globals
|
|
26
|
+
Reset: ResetComponent,
|
|
27
|
+
Site: SiteComponent,
|
|
28
|
+
|
|
29
|
+
# Elements
|
|
30
|
+
Button: ButtonComponent,
|
|
31
|
+
Container: ContainerComponent,
|
|
32
|
+
Divider: DividerComponent,
|
|
33
|
+
Emoji: EmojiComponent,
|
|
34
|
+
Flag: FlagComponent,
|
|
35
|
+
Header: HeaderComponent,
|
|
36
|
+
Icon: IconComponent,
|
|
37
|
+
Image: ImageComponent,
|
|
38
|
+
Input: InputComponent,
|
|
39
|
+
Label: LabelComponent,
|
|
40
|
+
List: ListComponent,
|
|
41
|
+
Loader: LoaderComponent,
|
|
42
|
+
Placeholder: PlaceholderComponent,
|
|
43
|
+
Rail: RailComponent,
|
|
44
|
+
Reveal: RevealComponent,
|
|
45
|
+
Segment: SegmentComponent,
|
|
46
|
+
SegmentGroup: SegmentGroupComponent,
|
|
47
|
+
Step: StepComponent,
|
|
48
|
+
StepGroup: StepGroupComponent,
|
|
49
|
+
Text: TextComponent,
|
|
50
|
+
|
|
51
|
+
# Collections
|
|
52
|
+
Breadcrumb: BreadcrumbComponent,
|
|
53
|
+
Form: FormComponent,
|
|
54
|
+
Grid: GridComponent,
|
|
55
|
+
Menu: MenuComponent,
|
|
56
|
+
MenuItem: MenuItemComponent,
|
|
57
|
+
SubMenu: SubMenuComponent,
|
|
58
|
+
Message: MessageComponent,
|
|
59
|
+
Table: TableComponent,
|
|
60
|
+
TableRow: TableRowComponent,
|
|
61
|
+
TableCell: TableCellComponent,
|
|
62
|
+
|
|
63
|
+
# Views
|
|
64
|
+
Ad: AdComponent,
|
|
65
|
+
ItemGroup: ItemGroupComponent,
|
|
66
|
+
Card: CardComponent,
|
|
67
|
+
Comment: CommentComponent,
|
|
68
|
+
Feed: FeedComponent,
|
|
69
|
+
Item: ItemComponent,
|
|
70
|
+
Statistic: StatisticComponent,
|
|
71
|
+
|
|
72
|
+
# Modules
|
|
73
|
+
Accordion: AccordionComponent,
|
|
74
|
+
Calendar: CalendarComponent,
|
|
75
|
+
Checkbox: CheckboxComponent,
|
|
76
|
+
Dimmer: DimmerComponent,
|
|
77
|
+
Dropdown: DropdownComponent,
|
|
78
|
+
Embed: EmbedComponent,
|
|
79
|
+
Flyout: FlyoutComponent,
|
|
80
|
+
Modal: ModalComponent,
|
|
81
|
+
Nag: NagComponent,
|
|
82
|
+
Popup: PopupComponent,
|
|
83
|
+
Progress: ProgressComponent,
|
|
84
|
+
Slider: SliderComponent,
|
|
85
|
+
Rating: RatingComponent,
|
|
86
|
+
Search: SearchComponent,
|
|
87
|
+
Shape: ShapeComponent,
|
|
88
|
+
Sidebar: SidebarComponent,
|
|
89
|
+
Sticky: StickyComponent,
|
|
90
|
+
Tab: TabComponent,
|
|
91
|
+
Toast: ToastComponent,
|
|
92
|
+
Transition: TransitionComponent,
|
|
93
|
+
|
|
94
|
+
# Behaviors
|
|
95
|
+
Api: ApiComponent,
|
|
96
|
+
State: StateComponent,
|
|
97
|
+
Visibility: VisibilityComponent
|
|
98
|
+
}.freeze
|
|
99
|
+
|
|
100
|
+
COMPONENT_MAP.each do |name, klass|
|
|
101
|
+
define_method(name) { |**kwargs, &block|
|
|
102
|
+
output_buffer << render(klass.new(**kwargs), &block)
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def text(content)
|
|
107
|
+
output_buffer << content.to_s
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Provides the fui_javascript_tags helper for loading jQuery and
|
|
4
|
+
# Fomantic-UI component scripts in the correct order.
|
|
5
|
+
#
|
|
6
|
+
# Usage (in your application layout, before javascript_importmap_tags):
|
|
7
|
+
#
|
|
8
|
+
# <%= fui_javascript_tags %>
|
|
9
|
+
# <%= javascript_importmap_tags %>
|
|
10
|
+
#
|
|
11
|
+
# This emits <script> tags for jQuery and each Fomantic-UI component.
|
|
12
|
+
# The Stimulus bridge controllers are loaded separately via importmap.
|
|
13
|
+
|
|
14
|
+
module FuiHelper
|
|
15
|
+
# Fomantic component scripts in load order.
|
|
16
|
+
# site and transition must come first — other components depend on them.
|
|
17
|
+
FOMANTIC_SCRIPTS = %w[
|
|
18
|
+
site
|
|
19
|
+
transition
|
|
20
|
+
accordion
|
|
21
|
+
api
|
|
22
|
+
calendar
|
|
23
|
+
checkbox
|
|
24
|
+
dimmer
|
|
25
|
+
dropdown
|
|
26
|
+
embed
|
|
27
|
+
flyout
|
|
28
|
+
form
|
|
29
|
+
modal
|
|
30
|
+
nag
|
|
31
|
+
popup
|
|
32
|
+
progress
|
|
33
|
+
rating
|
|
34
|
+
search
|
|
35
|
+
shape
|
|
36
|
+
sidebar
|
|
37
|
+
slider
|
|
38
|
+
state
|
|
39
|
+
sticky
|
|
40
|
+
tab
|
|
41
|
+
toast
|
|
42
|
+
visibility
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
45
|
+
def fui_javascript_tags
|
|
46
|
+
tags = []
|
|
47
|
+
tags << javascript_include_tag("jquery")
|
|
48
|
+
FOMANTIC_SCRIPTS.each do |name|
|
|
49
|
+
tags << javascript_include_tag(name)
|
|
50
|
+
end
|
|
51
|
+
safe_join(tags, "\n")
|
|
52
|
+
end
|
|
53
|
+
end
|