okonomi_ui_kit 0.1.6 → 0.1.8
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 +4 -4
- data/README.md +163 -7
- data/app/assets/builds/okonomi_ui_kit/application.tailwind.css +292 -4
- data/app/helpers/okonomi_ui_kit/component.rb +81 -0
- data/app/helpers/okonomi_ui_kit/components/badge.rb +21 -16
- data/app/helpers/okonomi_ui_kit/components/breadcrumbs.rb +69 -0
- data/app/helpers/okonomi_ui_kit/components/button_base.rb +56 -0
- data/app/helpers/okonomi_ui_kit/components/button_tag.rb +23 -0
- data/app/helpers/okonomi_ui_kit/components/button_to.rb +23 -0
- data/app/helpers/okonomi_ui_kit/components/code.rb +73 -0
- data/app/helpers/okonomi_ui_kit/components/icon.rb +36 -0
- data/app/helpers/okonomi_ui_kit/components/link_to.rb +23 -0
- data/app/helpers/okonomi_ui_kit/components/page.rb +247 -0
- data/app/helpers/okonomi_ui_kit/components/table.rb +207 -0
- data/app/helpers/okonomi_ui_kit/components/typography.rb +29 -3
- data/app/helpers/okonomi_ui_kit/config.rb +20 -0
- data/app/helpers/okonomi_ui_kit/form_builder.rb +2 -2
- data/app/helpers/okonomi_ui_kit/t_w_merge.rb +108 -0
- data/app/helpers/okonomi_ui_kit/theme.rb +3 -26
- data/app/helpers/okonomi_ui_kit/ui_helper.rb +0 -40
- data/app/views/okonomi/components/breadcrumbs/_breadcrumbs.html.erb +46 -0
- data/app/views/okonomi/components/code/_code.html.erb +1 -0
- data/app/views/okonomi/components/icon/_icon.html.erb +38 -0
- data/app/views/okonomi/components/page/_page.html.erb +5 -0
- data/app/views/okonomi/components/table/_table.html.erb +3 -0
- data/app/views/okonomi/forms/tailwind/_upload_field.html.erb +2 -2
- data/app/views/okonomi/modals/_confirmation_modal.html.erb +2 -2
- data/app/views/okonomi/navigation/_link.html.erb +1 -1
- data/lib/okonomi_ui_kit/engine.rb +0 -5
- data/lib/okonomi_ui_kit/version.rb +1 -1
- metadata +18 -7
- data/app/helpers/okonomi_ui_kit/badge_helper.rb +0 -23
- data/app/helpers/okonomi_ui_kit/breadcrumbs_helper.rb +0 -60
- data/app/helpers/okonomi_ui_kit/icon_helper.rb +0 -39
- data/app/helpers/okonomi_ui_kit/page_builder_helper.rb +0 -217
- data/app/helpers/okonomi_ui_kit/table_helper.rb +0 -158
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OkonomiUiKit
|
4
|
+
module Components
|
5
|
+
class Breadcrumbs < Component
|
6
|
+
register_styles do
|
7
|
+
{
|
8
|
+
base: "flex",
|
9
|
+
container: "isolate flex -space-x-px rounded-lg shadow-sm",
|
10
|
+
nav: "",
|
11
|
+
list: "flex items-center space-x-4",
|
12
|
+
item: {
|
13
|
+
base: "",
|
14
|
+
first: "",
|
15
|
+
last: "",
|
16
|
+
current: ""
|
17
|
+
},
|
18
|
+
link: {
|
19
|
+
base: "ml-4 text-sm font-medium text-gray-500 hover:text-gray-700",
|
20
|
+
first: "text-sm font-medium text-gray-500 hover:text-gray-700",
|
21
|
+
current: "ml-4 text-sm font-medium text-gray-500"
|
22
|
+
},
|
23
|
+
separator: {
|
24
|
+
base: "size-5 shrink-0 text-gray-400",
|
25
|
+
wrapper: ""
|
26
|
+
},
|
27
|
+
icon: "size-5 text-gray-400"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(template, options = {})
|
32
|
+
super
|
33
|
+
@items = []
|
34
|
+
@builder = BreadcrumbBuilder.new(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def render(options = {}, &block)
|
38
|
+
return "" if block.nil?
|
39
|
+
|
40
|
+
block.call(@builder)
|
41
|
+
view.render("okonomi/components/breadcrumbs/breadcrumbs",
|
42
|
+
component: self,
|
43
|
+
items: @items,
|
44
|
+
options: options
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_item(text, path = nil, current: false, icon: nil)
|
49
|
+
@items << {
|
50
|
+
text: text,
|
51
|
+
path: path,
|
52
|
+
current: current,
|
53
|
+
icon: icon
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
class BreadcrumbBuilder
|
58
|
+
def initialize(component)
|
59
|
+
@component = component
|
60
|
+
end
|
61
|
+
|
62
|
+
def link(text, path = nil, current: false, icon: nil, **options)
|
63
|
+
# Ignore extra options for now
|
64
|
+
@component.add_item(text, path, current: current, icon: icon)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class ButtonBase < OkonomiUiKit::Component
|
4
|
+
def build_button_class(variant:, color:, classes: '')
|
5
|
+
[
|
6
|
+
style(:root) || '',
|
7
|
+
style(variant.to_sym, :root) || '',
|
8
|
+
style(variant.to_sym, :colors, color.to_sym) || '',
|
9
|
+
classes,
|
10
|
+
].reject(&:blank?).join(' ')
|
11
|
+
end
|
12
|
+
|
13
|
+
register_styles :default do
|
14
|
+
{
|
15
|
+
root: "hover:cursor-pointer text-sm",
|
16
|
+
outlined: {
|
17
|
+
root: "inline-flex border items-center justify-center px-2 py-1 rounded-md font-medium focus:outline-none focus:ring-2 focus:ring-offset-2",
|
18
|
+
colors: {
|
19
|
+
default: "bg-white text-default-700 border-default-700 hover:bg-default-50",
|
20
|
+
primary: "bg-white text-primary-600 border-primary-600 hover:bg-primary-50",
|
21
|
+
secondary: "bg-white text-secondary-600 border-secondary-600 hover:bg-secondary-50",
|
22
|
+
success: "bg-white text-success-600 border-success-600 hover:bg-success-50",
|
23
|
+
danger: "bg-white text-danger-600 border-danger-600 hover:bg-danger-50",
|
24
|
+
warning: "bg-white text-warning-600 border-warning-600 hover:bg-warning-50",
|
25
|
+
info: "bg-white text-info-600 border-info-600 hover:bg-info-50"
|
26
|
+
}
|
27
|
+
},
|
28
|
+
contained: {
|
29
|
+
root: "inline-flex border items-center justify-center px-2 py-1 rounded-md font-medium focus:outline-none focus:ring-2 focus:ring-offset-2",
|
30
|
+
colors: {
|
31
|
+
default: "border-default-700 bg-default-600 text-white hover:bg-default-700",
|
32
|
+
primary: "border-primary-700 bg-primary-600 text-white hover:bg-primary-700",
|
33
|
+
secondary: "border-secondary-700 bg-secondary-600 text-white hover:bg-secondary-700",
|
34
|
+
success: "border-success-700 bg-success-600 text-white hover:bg-success-700",
|
35
|
+
danger: "border-danger-700 bg-danger-600 text-white hover:bg-danger-700",
|
36
|
+
warning: "border-warning-700 bg-warning-600 text-white hover:bg-warning-700",
|
37
|
+
info: "border-info-700 bg-info-600 text-white hover:bg-info-700"
|
38
|
+
}
|
39
|
+
},
|
40
|
+
text: {
|
41
|
+
root: "text-base",
|
42
|
+
colors: {
|
43
|
+
default: "text-default-700 hover:underline",
|
44
|
+
primary: "text-primary-600 hover:underline",
|
45
|
+
secondary: "text-secondary-600 hover:underline",
|
46
|
+
success: "text-success-600 hover:underline",
|
47
|
+
danger: "text-danger-600 hover:underline",
|
48
|
+
warning: "text-warning-600 hover:underline",
|
49
|
+
info: "text-info-600 hover:underline"
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class ButtonTag < OkonomiUiKit::Components::ButtonBase
|
4
|
+
def render(name = nil, options = {}, &block)
|
5
|
+
options, name = options, block if block_given?
|
6
|
+
|
7
|
+
options ||= {}
|
8
|
+
options = options.with_indifferent_access
|
9
|
+
|
10
|
+
variant = (options.delete(:variant) || 'contained').to_sym
|
11
|
+
color = (options.delete(:color) || 'default').to_sym
|
12
|
+
|
13
|
+
options[:class] = build_button_class(variant: variant, color: color, classes: options[:class])
|
14
|
+
|
15
|
+
if block_given?
|
16
|
+
view.button_tag(options, &block)
|
17
|
+
else
|
18
|
+
view.button_tag(name, options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class ButtonTo < OkonomiUiKit::Components::ButtonBase
|
4
|
+
def render(name = nil, options = nil, html_options = nil, &block)
|
5
|
+
html_options, options, name = options, name, block if block_given?
|
6
|
+
|
7
|
+
html_options ||= {}
|
8
|
+
html_options = html_options.with_indifferent_access
|
9
|
+
|
10
|
+
variant = (html_options.delete(:variant) || 'contained').to_sym
|
11
|
+
color = (html_options.delete(:color) || 'default').to_sym
|
12
|
+
|
13
|
+
html_options[:class] = build_button_class(variant: variant, color: color, classes: html_options[:class])
|
14
|
+
|
15
|
+
if block_given?
|
16
|
+
view.button_to(options, html_options, &block)
|
17
|
+
else
|
18
|
+
view.button_to(name, options, html_options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class Code < OkonomiUiKit::Component
|
4
|
+
def render(content = nil, options = {}, &block)
|
5
|
+
options, content = content, nil if block_given?
|
6
|
+
options ||= {}
|
7
|
+
options = options.with_indifferent_access
|
8
|
+
|
9
|
+
# Extract component-specific options
|
10
|
+
language = options.delete(:language) || options.delete(:lang)
|
11
|
+
variant = (options.delete(:variant) || 'default').to_sym
|
12
|
+
size = (options.delete(:size) || 'default').to_sym
|
13
|
+
wrap = options.delete(:wrap) != false # Default to true
|
14
|
+
|
15
|
+
# Build classes
|
16
|
+
classes = build_classes(variant: variant, size: size, wrap: wrap, custom_class: options.delete(:class))
|
17
|
+
|
18
|
+
# Escape HTML entities in content
|
19
|
+
escaped_content = if block_given?
|
20
|
+
view.capture(&block)
|
21
|
+
elsif content
|
22
|
+
content
|
23
|
+
else
|
24
|
+
""
|
25
|
+
end
|
26
|
+
|
27
|
+
view.render(
|
28
|
+
template_path,
|
29
|
+
content: escaped_content.strip.html_safe,
|
30
|
+
options: options,
|
31
|
+
classes: classes,
|
32
|
+
language: language
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def build_classes(variant:, size:, wrap:, custom_class: nil)
|
39
|
+
base_classes = theme.dig(:components, :code, :base) || "bg-gray-900 text-gray-100 rounded-lg"
|
40
|
+
|
41
|
+
variant_classes = case variant
|
42
|
+
when :inline
|
43
|
+
"bg-gray-100 text-gray-900 px-1 py-0.5 rounded text-sm font-mono"
|
44
|
+
when :minimal
|
45
|
+
"bg-gray-900 text-gray-100 p-3 rounded text-xs"
|
46
|
+
else
|
47
|
+
# :default
|
48
|
+
"bg-gray-900 text-gray-100 p-4 rounded-lg"
|
49
|
+
end
|
50
|
+
|
51
|
+
size_classes = case size
|
52
|
+
when :xs
|
53
|
+
"text-xs"
|
54
|
+
when :sm
|
55
|
+
"text-sm"
|
56
|
+
when :lg
|
57
|
+
"text-base"
|
58
|
+
else
|
59
|
+
# :default
|
60
|
+
"text-sm"
|
61
|
+
end
|
62
|
+
|
63
|
+
wrap_classes = wrap ? "overflow-x-auto" : "overflow-hidden"
|
64
|
+
|
65
|
+
[base_classes, variant_classes, size_classes, wrap_classes, custom_class].compact.join(' ')
|
66
|
+
end
|
67
|
+
|
68
|
+
def html_escape(content)
|
69
|
+
ERB::Util.html_escape(content.to_s.strip)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class Icon < OkonomiUiKit::Component
|
4
|
+
def render(name, options = {})
|
5
|
+
options = options.with_indifferent_access
|
6
|
+
|
7
|
+
# Extract specific icon options
|
8
|
+
variant = options.delete(:variant) || :outlined
|
9
|
+
width = options.delete(:width)
|
10
|
+
height = options.delete(:height)
|
11
|
+
|
12
|
+
# Build classes array
|
13
|
+
classes = [
|
14
|
+
style(:base),
|
15
|
+
options.delete(:class)
|
16
|
+
].compact.join(' ')
|
17
|
+
|
18
|
+
view.render(
|
19
|
+
template_path,
|
20
|
+
name: name,
|
21
|
+
variant: variant,
|
22
|
+
width: width,
|
23
|
+
height: height,
|
24
|
+
classes: classes,
|
25
|
+
options: options
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
register_styles :default do
|
30
|
+
{
|
31
|
+
base: "inline-block"
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class LinkTo < OkonomiUiKit::Components::ButtonBase
|
4
|
+
def render(name = nil, options = nil, html_options = nil, &block)
|
5
|
+
html_options, options, name = options, name, block if block_given?
|
6
|
+
|
7
|
+
html_options ||= {}
|
8
|
+
html_options = html_options.with_indifferent_access
|
9
|
+
|
10
|
+
variant = (html_options.delete(:variant) || 'text').to_sym
|
11
|
+
color = (html_options.delete(:color) || 'default').to_sym
|
12
|
+
|
13
|
+
html_options[:class] = build_button_class(variant: variant, color: color, classes: html_options[:class])
|
14
|
+
|
15
|
+
if block_given?
|
16
|
+
view.link_to(options, html_options, &block)
|
17
|
+
else
|
18
|
+
view.link_to(name, options, html_options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class Page < OkonomiUiKit::Component
|
4
|
+
def render(options = {}, &block)
|
5
|
+
builder = PageBuilder.new(view)
|
6
|
+
|
7
|
+
view.render(template_path, builder: builder, options: options, &block)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class PageBuilder
|
12
|
+
include ActionView::Helpers::TagHelper
|
13
|
+
include ActionView::Helpers::CaptureHelper
|
14
|
+
|
15
|
+
def initialize(template)
|
16
|
+
@template = template
|
17
|
+
@content_parts = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def page_header(**options, &block)
|
21
|
+
header_builder = PageHeaderBuilder.new(@template)
|
22
|
+
yield(header_builder) if block_given?
|
23
|
+
@content_parts << header_builder.render
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def section(**options, &block)
|
28
|
+
section_builder = SectionBuilder.new(@template)
|
29
|
+
section_builder.title(options[:title]) if options[:title]
|
30
|
+
yield(section_builder) if block_given?
|
31
|
+
@content_parts << section_builder.render
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def render_content
|
36
|
+
@template.safe_join(@content_parts)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
render_content
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def tag
|
46
|
+
@template.tag
|
47
|
+
end
|
48
|
+
|
49
|
+
def capture(*args, &block)
|
50
|
+
@template.capture(*args, &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class PageHeaderBuilder
|
55
|
+
include ActionView::Helpers::TagHelper
|
56
|
+
include ActionView::Helpers::CaptureHelper
|
57
|
+
|
58
|
+
def initialize(template)
|
59
|
+
@template = template
|
60
|
+
@breadcrumbs_content = nil
|
61
|
+
@row_content = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def breadcrumbs(&block)
|
65
|
+
@breadcrumbs_content = @template.ui.breadcrumbs(&block)
|
66
|
+
end
|
67
|
+
|
68
|
+
def row(&block)
|
69
|
+
row_builder = PageHeaderRowBuilder.new(@template)
|
70
|
+
yield(row_builder) if block_given?
|
71
|
+
@row_content = row_builder.render
|
72
|
+
end
|
73
|
+
|
74
|
+
def render
|
75
|
+
content = []
|
76
|
+
content << @breadcrumbs_content if @breadcrumbs_content
|
77
|
+
content << @row_content if @row_content
|
78
|
+
|
79
|
+
tag.div(class: "flex flex-col gap-2") do
|
80
|
+
@template.safe_join(content.compact)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def tag
|
87
|
+
@template.tag
|
88
|
+
end
|
89
|
+
|
90
|
+
def capture(*args, &block)
|
91
|
+
@template.capture(*args, &block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class PageHeaderRowBuilder
|
96
|
+
include ActionView::Helpers::TagHelper
|
97
|
+
include ActionView::Helpers::CaptureHelper
|
98
|
+
|
99
|
+
def initialize(template)
|
100
|
+
@template = template
|
101
|
+
@title_content = nil
|
102
|
+
@actions_content = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def title(text, **options)
|
106
|
+
@title_content = tag.h1(text, class: "text-2xl font-bold leading-7 text-gray-900 truncate sm:text-3xl sm:tracking-tight")
|
107
|
+
end
|
108
|
+
|
109
|
+
def actions(&block)
|
110
|
+
@actions_content = tag.div(class: "mt-4 flex md:ml-4 md:mt-0 gap-2") do
|
111
|
+
capture(&block) if block_given?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def render
|
116
|
+
tag.div(class: "flex w-full justify-between items-center") do
|
117
|
+
content = []
|
118
|
+
content << @title_content if @title_content
|
119
|
+
content << @actions_content if @actions_content
|
120
|
+
@template.safe_join(content.compact)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def tag
|
127
|
+
@template.tag
|
128
|
+
end
|
129
|
+
|
130
|
+
def capture(*args, &block)
|
131
|
+
@template.capture(*args, &block)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class SectionBuilder
|
136
|
+
include ActionView::Helpers::TagHelper
|
137
|
+
include ActionView::Helpers::CaptureHelper
|
138
|
+
|
139
|
+
def initialize(template)
|
140
|
+
@template = template
|
141
|
+
@title_content = nil
|
142
|
+
@subtitle_content = nil
|
143
|
+
@actions_content = nil
|
144
|
+
@body_content = nil
|
145
|
+
@attributes = []
|
146
|
+
end
|
147
|
+
|
148
|
+
def title(text, **options)
|
149
|
+
@title_content = tag.h3(text, class: "text-base/7 font-semibold text-gray-900")
|
150
|
+
end
|
151
|
+
|
152
|
+
def subtitle(text, **options)
|
153
|
+
@subtitle_content = tag.p(text, class: "mt-1 max-w-2xl text-sm/6 text-gray-500")
|
154
|
+
end
|
155
|
+
|
156
|
+
def actions(&block)
|
157
|
+
@actions_content = tag.div(class: "mt-4 flex md:ml-4 md:mt-0") do
|
158
|
+
capture(&block) if block_given?
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def body(&block)
|
163
|
+
if block_given?
|
164
|
+
# Capture the content first to see if attributes were used
|
165
|
+
content = capture { yield(self) }
|
166
|
+
|
167
|
+
@body_content = if @attributes.any?
|
168
|
+
# If attributes were added, wrap them in dl
|
169
|
+
tag.div do
|
170
|
+
tag.dl(class: "divide-y divide-gray-100") do
|
171
|
+
@template.safe_join(@attributes)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
else
|
175
|
+
# Otherwise, just return the captured content
|
176
|
+
tag.div do
|
177
|
+
content
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def attribute(label, value = nil, **options, &block)
|
184
|
+
content = if block_given?
|
185
|
+
capture(&block)
|
186
|
+
elsif value.respond_to?(:call)
|
187
|
+
value.call
|
188
|
+
else
|
189
|
+
value
|
190
|
+
end
|
191
|
+
|
192
|
+
attribute_html = tag.div(class: "py-6 sm:grid sm:grid-cols-3 sm:gap-4") do
|
193
|
+
dt_content = tag.dt(label, class: "text-sm font-medium text-gray-900")
|
194
|
+
dd_content = tag.dd(content, class: "mt-1 text-sm/6 text-gray-700 sm:col-span-2 sm:mt-0")
|
195
|
+
|
196
|
+
dt_content + dd_content
|
197
|
+
end
|
198
|
+
|
199
|
+
@attributes << attribute_html
|
200
|
+
end
|
201
|
+
|
202
|
+
def render
|
203
|
+
tag.div(class: "overflow-hidden bg-white") do
|
204
|
+
header_content = build_header
|
205
|
+
content_parts = []
|
206
|
+
content_parts << header_content if header_content.present?
|
207
|
+
content_parts << @body_content if @body_content
|
208
|
+
@template.safe_join(content_parts.compact)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def build_header
|
215
|
+
return nil unless @title_content || @subtitle_content || @actions_content
|
216
|
+
|
217
|
+
tag.div(class: "py-6") do
|
218
|
+
if @actions_content
|
219
|
+
tag.div(class: "flex w-full justify-between items-start") do
|
220
|
+
title_section = tag.div do
|
221
|
+
content_parts = []
|
222
|
+
content_parts << @title_content if @title_content
|
223
|
+
content_parts << @subtitle_content if @subtitle_content
|
224
|
+
@template.safe_join(content_parts.compact)
|
225
|
+
end
|
226
|
+
|
227
|
+
title_section + @actions_content
|
228
|
+
end
|
229
|
+
else
|
230
|
+
content_parts = []
|
231
|
+
content_parts << @title_content if @title_content
|
232
|
+
content_parts << @subtitle_content if @subtitle_content
|
233
|
+
@template.safe_join(content_parts.compact)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def tag
|
239
|
+
@template.tag
|
240
|
+
end
|
241
|
+
|
242
|
+
def capture(*args, &block)
|
243
|
+
@template.capture(*args, &block)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|