okonomi_ui_kit 0.1.6 → 0.1.7
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/app/assets/builds/okonomi_ui_kit/application.tailwind.css +33 -0
- data/app/helpers/okonomi_ui_kit/component.rb +62 -0
- data/app/helpers/okonomi_ui_kit/components/badge.rb +21 -16
- data/app/helpers/okonomi_ui_kit/components/button_to.rb +34 -0
- data/app/helpers/okonomi_ui_kit/components/code.rb +73 -0
- data/app/helpers/okonomi_ui_kit/components/link_to.rb +34 -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 +16 -0
- data/app/helpers/okonomi_ui_kit/theme.rb +3 -3
- data/app/helpers/okonomi_ui_kit/ui_helper.rb +0 -40
- data/app/views/okonomi/components/code/_code.html.erb +1 -0
- data/app/views/okonomi/components/page/_page.html.erb +5 -0
- data/app/views/okonomi/components/table/_table.html.erb +3 -0
- data/lib/okonomi_ui_kit/engine.rb +0 -3
- data/lib/okonomi_ui_kit/version.rb +1 -1
- metadata +11 -5
- data/app/helpers/okonomi_ui_kit/badge_helper.rb +0 -23
- 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,207 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class Table < OkonomiUiKit::Component
|
4
|
+
def render(options = {}, &block)
|
5
|
+
options = options.with_indifferent_access
|
6
|
+
variant = (options.delete(:variant) || :default).to_sym
|
7
|
+
|
8
|
+
builder = TableBuilder.new(view, theme, self, variant)
|
9
|
+
view.render(template_path, builder: builder, options: options, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
register_styles :default do
|
13
|
+
{
|
14
|
+
default: {
|
15
|
+
body: {
|
16
|
+
base: "divide-y divide-gray-200 bg-white"
|
17
|
+
},
|
18
|
+
th: {
|
19
|
+
base: "text-sm font-semibold text-gray-900",
|
20
|
+
first: "py-3.5 pr-3",
|
21
|
+
last: "relative py-3.5",
|
22
|
+
middle: "pl-3 pr-3 py-3.5"
|
23
|
+
},
|
24
|
+
td: {
|
25
|
+
base: "text-sm whitespace-nowrap",
|
26
|
+
first: "py-4 pr-3 font-medium text-gray-900",
|
27
|
+
last: "relative py-4 font-medium",
|
28
|
+
middle: "pl-3 pr-3 py-4 text-gray-500"
|
29
|
+
},
|
30
|
+
alignment: {
|
31
|
+
left: "text-left",
|
32
|
+
center: "text-center",
|
33
|
+
right: "text-right"
|
34
|
+
},
|
35
|
+
empty_state: {
|
36
|
+
wrapper: "text-center py-8",
|
37
|
+
icon: "mx-auto h-12 w-12 text-gray-400",
|
38
|
+
title: "mt-2 text-sm font-medium text-gray-900",
|
39
|
+
subtitle: "mt-1 text-sm text-gray-500",
|
40
|
+
cell: "text-center py-8 text-gray-500"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class TableBuilder
|
48
|
+
include ActionView::Helpers::TagHelper
|
49
|
+
include ActionView::Helpers::CaptureHelper
|
50
|
+
|
51
|
+
def initialize(template, theme, style_provider, variant = :default)
|
52
|
+
@template = template
|
53
|
+
@theme = theme
|
54
|
+
@style_provider = style_provider
|
55
|
+
@variant = variant
|
56
|
+
@current_row_cells = []
|
57
|
+
@in_header = false
|
58
|
+
@in_body = false
|
59
|
+
end
|
60
|
+
|
61
|
+
def head(&block)
|
62
|
+
@in_header = true
|
63
|
+
@in_body = false
|
64
|
+
result = tag.thead(&block)
|
65
|
+
@in_header = false
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def body(&block)
|
70
|
+
@in_header = false
|
71
|
+
@in_body = true
|
72
|
+
result = tag.tbody(class: style(:body, :base), &block)
|
73
|
+
@in_body = false
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
def tr(&block)
|
78
|
+
@current_row_cells = []
|
79
|
+
|
80
|
+
# Collect all cells first
|
81
|
+
yield if block_given?
|
82
|
+
|
83
|
+
# Now render each cell with proper first/last detection
|
84
|
+
rendered_cells = @current_row_cells.map.with_index do |cell, index|
|
85
|
+
is_first = index == 0
|
86
|
+
is_last = index == @current_row_cells.length - 1
|
87
|
+
|
88
|
+
if cell[:type] == :th
|
89
|
+
render_th(cell, is_first, is_last)
|
90
|
+
else
|
91
|
+
render_td(cell, is_first, is_last)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
result = tag.tr do
|
96
|
+
@template.safe_join(rendered_cells)
|
97
|
+
end
|
98
|
+
|
99
|
+
@current_row_cells = []
|
100
|
+
result
|
101
|
+
end
|
102
|
+
|
103
|
+
def th(scope: "col", align: :left, **options, &block)
|
104
|
+
content = capture(&block) if block_given?
|
105
|
+
|
106
|
+
# Store cell data for later processing in tr
|
107
|
+
cell = { type: :th, scope: scope, align: align, options: options, content: content }
|
108
|
+
@current_row_cells << cell
|
109
|
+
|
110
|
+
# Return empty string for now, actual rendering happens in tr
|
111
|
+
""
|
112
|
+
end
|
113
|
+
|
114
|
+
def td(align: :left, **options, &block)
|
115
|
+
content = capture(&block) if block_given?
|
116
|
+
|
117
|
+
# Store cell data for later processing in tr
|
118
|
+
cell = { type: :td, align: align, options: options, content: content }
|
119
|
+
@current_row_cells << cell
|
120
|
+
|
121
|
+
# Return empty string for now, actual rendering happens in tr
|
122
|
+
""
|
123
|
+
end
|
124
|
+
|
125
|
+
def empty_state(title: "No records found", icon: "heroicons/outline/document", colspan: nil, &block)
|
126
|
+
content = if block_given?
|
127
|
+
capture(&block)
|
128
|
+
else
|
129
|
+
tag.div(class: style(:empty_state, :wrapper)) do
|
130
|
+
icon_content = if @template.respond_to?(:svg_icon)
|
131
|
+
@template.svg_icon(icon, class: style(:empty_state, :icon))
|
132
|
+
else
|
133
|
+
tag.div(class: style(:empty_state, :icon))
|
134
|
+
end
|
135
|
+
|
136
|
+
icon_content + tag.p(title, class: style(:empty_state, :title)) +
|
137
|
+
tag.p("Get started by creating a new record.", class: style(:empty_state, :subtitle))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
tr do
|
142
|
+
td(colspan: colspan, class: style(:empty_state, :cell)) do
|
143
|
+
content
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def tag
|
151
|
+
@template.tag
|
152
|
+
end
|
153
|
+
|
154
|
+
def capture(*args, &block)
|
155
|
+
@template.capture(*args, &block)
|
156
|
+
end
|
157
|
+
|
158
|
+
def render_th(cell, is_first, is_last)
|
159
|
+
align_class = style(:alignment, cell[:align]) || style(:alignment, :left)
|
160
|
+
|
161
|
+
position_class = if is_first
|
162
|
+
style(:th, :first)
|
163
|
+
elsif is_last
|
164
|
+
style(:th, :last)
|
165
|
+
else
|
166
|
+
style(:th, :middle)
|
167
|
+
end
|
168
|
+
|
169
|
+
classes = [
|
170
|
+
style(:th, :base),
|
171
|
+
position_class,
|
172
|
+
align_class,
|
173
|
+
cell[:options][:class]
|
174
|
+
].compact.join(' ')
|
175
|
+
|
176
|
+
options = cell[:options].except(:class)
|
177
|
+
tag.th(cell[:content], scope: cell[:scope], class: classes, **options)
|
178
|
+
end
|
179
|
+
|
180
|
+
def render_td(cell, is_first, is_last)
|
181
|
+
align_class = style(:alignment, cell[:align]) || style(:alignment, :left)
|
182
|
+
|
183
|
+
position_class = if is_first
|
184
|
+
style(:td, :first)
|
185
|
+
elsif is_last
|
186
|
+
style(:td, :last)
|
187
|
+
else
|
188
|
+
style(:td, :middle)
|
189
|
+
end
|
190
|
+
|
191
|
+
classes = [
|
192
|
+
style(:td, :base),
|
193
|
+
position_class,
|
194
|
+
align_class,
|
195
|
+
cell[:options][:class]
|
196
|
+
].compact.join(' ')
|
197
|
+
|
198
|
+
options = cell[:options].except(:class)
|
199
|
+
tag.td(cell[:content], class: classes, **options)
|
200
|
+
end
|
201
|
+
|
202
|
+
def style(*keys)
|
203
|
+
@style_provider.style(@variant, *keys)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -20,10 +20,10 @@ module OkonomiUiKit
|
|
20
20
|
variant = (options.delete(:variant) || 'body1').to_sym
|
21
21
|
component = (TYPOGRAPHY_COMPONENTS[variant] || 'span').to_s
|
22
22
|
color = (options.delete(:color) || 'default').to_sym
|
23
|
-
|
23
|
+
|
24
24
|
classes = [
|
25
|
-
|
26
|
-
|
25
|
+
style(:variants, variant) || '',
|
26
|
+
style(:colors, color) || '',
|
27
27
|
options.delete(:class) || ''
|
28
28
|
].reject(&:blank?).join(' ')
|
29
29
|
|
@@ -37,6 +37,32 @@ module OkonomiUiKit
|
|
37
37
|
&block
|
38
38
|
)
|
39
39
|
end
|
40
|
+
|
41
|
+
register_styles :default do
|
42
|
+
{
|
43
|
+
variants: {
|
44
|
+
body1: "text-base font-normal",
|
45
|
+
body2: "text-sm font-normal",
|
46
|
+
h1: "text-3xl font-bold",
|
47
|
+
h2: "text-2xl font-bold",
|
48
|
+
h3: "text-xl font-semibold",
|
49
|
+
h4: "text-lg font-semibold",
|
50
|
+
h5: "text-base font-semibold",
|
51
|
+
h6: "text-sm font-semibold"
|
52
|
+
},
|
53
|
+
colors: {
|
54
|
+
default: "text-default-700",
|
55
|
+
dark: "text-default-900",
|
56
|
+
muted: "text-default-500",
|
57
|
+
primary: "text-primary-600",
|
58
|
+
secondary: "text-secondary-600",
|
59
|
+
success: "text-success-600",
|
60
|
+
danger: "text-danger-600",
|
61
|
+
warning: "text-warning-600",
|
62
|
+
info: "text-info-600"
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
40
66
|
end
|
41
67
|
end
|
42
68
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
class Config
|
3
|
+
def self.register_styles(theme = :default, &block)
|
4
|
+
styles = block.call if block_given?
|
5
|
+
|
6
|
+
raise ArgumentError, "Styles must be a Hash" unless styles.is_a?(Hash)
|
7
|
+
|
8
|
+
styles_registry[theme] ||= {}
|
9
|
+
styles_registry[theme] = styles_registry[theme].deep_merge(styles)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.styles_registry
|
13
|
+
@styles_registry ||= {}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -26,9 +26,9 @@ module OkonomiUiKit
|
|
26
26
|
}
|
27
27
|
},
|
28
28
|
link: {
|
29
|
-
root: "hover:cursor-pointer",
|
29
|
+
root: "hover:cursor-pointer text-sm",
|
30
30
|
outlined: {
|
31
|
-
root: "inline-flex border items-center justify-center px-
|
31
|
+
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",
|
32
32
|
colors: {
|
33
33
|
default: "bg-white text-default-700 border-default-700 hover:bg-default-50",
|
34
34
|
primary: "bg-white text-primary-600 border-primary-600 hover:bg-primary-50",
|
@@ -40,7 +40,7 @@ module OkonomiUiKit
|
|
40
40
|
}
|
41
41
|
},
|
42
42
|
contained: {
|
43
|
-
root: "inline-flex border items-center justify-center px-
|
43
|
+
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",
|
44
44
|
colors: {
|
45
45
|
default: "border-default-700 bg-default-600 text-white hover:bg-default-700",
|
46
46
|
primary: "border-primary-700 bg-primary-600 text-white hover:bg-primary-700",
|
@@ -26,42 +26,6 @@ module OkonomiUiKit
|
|
26
26
|
@_okonomi_ui_kit_theme ||= OkonomiUiKit::Theme::DEFAULT_THEME
|
27
27
|
end
|
28
28
|
|
29
|
-
def link_to(name = nil, options = nil, html_options = nil, &block)
|
30
|
-
html_options, options, name = options, name, block if block_given?
|
31
|
-
|
32
|
-
html_options ||= {}
|
33
|
-
html_options[:class] ||= ''
|
34
|
-
|
35
|
-
variant = (html_options.delete(:variant) || 'text').to_sym
|
36
|
-
color = (html_options.delete(:color) || 'default').to_sym
|
37
|
-
|
38
|
-
html_options[:class] = button_class(variant:, color:, classes: html_options[:class])
|
39
|
-
|
40
|
-
if block_given?
|
41
|
-
@template.link_to(options, html_options, &block)
|
42
|
-
else
|
43
|
-
@template.link_to(name, options, html_options)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def button_to(name = nil, options = nil, html_options = nil, &block)
|
48
|
-
html_options, options, name = options, name, block if block_given?
|
49
|
-
|
50
|
-
html_options ||= {}
|
51
|
-
html_options[:class] ||= ''
|
52
|
-
|
53
|
-
variant = (html_options.delete(:variant) || 'contained').to_sym
|
54
|
-
color = (html_options.delete(:color) || 'default').to_sym
|
55
|
-
|
56
|
-
html_options[:class] = button_class(variant:, color:, classes: html_options[:class])
|
57
|
-
|
58
|
-
if block_given?
|
59
|
-
@template.button_to(options, html_options, &block)
|
60
|
-
else
|
61
|
-
@template.button_to(name, options, html_options)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
29
|
def button_class(variant: 'contained', color: 'default', classes: '')
|
66
30
|
[
|
67
31
|
get_theme.dig(:components, :link, :root) || '',
|
@@ -71,10 +35,6 @@ module OkonomiUiKit
|
|
71
35
|
].join(' ')
|
72
36
|
end
|
73
37
|
|
74
|
-
def page(&block)
|
75
|
-
@template.page(&block)
|
76
|
-
end
|
77
|
-
|
78
38
|
def confirmation_modal(title:, message:, confirm_text: "Confirm", cancel_text: "Cancel", variant: :warning, size: :md, **options, &block)
|
79
39
|
modal_options = {
|
80
40
|
title: title,
|
@@ -0,0 +1 @@
|
|
1
|
+
<pre<%= language ? " data-language=\"#{language}\"".html_safe : "" %> class="<%= classes %>"<%= tag.attributes(options) %>><code><%= content %></code></pre>
|
@@ -22,12 +22,9 @@ module OkonomiUiKit
|
|
22
22
|
ActiveSupport.on_load(:action_view) do
|
23
23
|
include OkonomiUiKit::ApplicationHelper
|
24
24
|
include OkonomiUiKit::AttributeSectionHelper
|
25
|
-
include OkonomiUiKit::BadgeHelper
|
26
25
|
include OkonomiUiKit::BreadcrumbsHelper
|
27
26
|
include OkonomiUiKit::IconHelper
|
28
27
|
include OkonomiUiKit::NavigationHelper
|
29
|
-
include OkonomiUiKit::PageBuilderHelper
|
30
|
-
include OkonomiUiKit::TableHelper
|
31
28
|
include OkonomiUiKit::UiHelper
|
32
29
|
|
33
30
|
ActionView::Base.field_error_proc = ->(html_tag, _instance) { html_tag.html_safe }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: okonomi_ui_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Okonomi GmbH
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -1357,18 +1357,21 @@ files:
|
|
1357
1357
|
- app/controllers/okonomi_ui_kit/application_controller.rb
|
1358
1358
|
- app/helpers/okonomi_ui_kit/application_helper.rb
|
1359
1359
|
- app/helpers/okonomi_ui_kit/attribute_section_helper.rb
|
1360
|
-
- app/helpers/okonomi_ui_kit/badge_helper.rb
|
1361
1360
|
- app/helpers/okonomi_ui_kit/breadcrumbs_helper.rb
|
1362
1361
|
- app/helpers/okonomi_ui_kit/component.rb
|
1363
1362
|
- app/helpers/okonomi_ui_kit/components/alert.rb
|
1364
1363
|
- app/helpers/okonomi_ui_kit/components/badge.rb
|
1364
|
+
- app/helpers/okonomi_ui_kit/components/button_to.rb
|
1365
|
+
- app/helpers/okonomi_ui_kit/components/code.rb
|
1366
|
+
- app/helpers/okonomi_ui_kit/components/link_to.rb
|
1367
|
+
- app/helpers/okonomi_ui_kit/components/page.rb
|
1368
|
+
- app/helpers/okonomi_ui_kit/components/table.rb
|
1365
1369
|
- app/helpers/okonomi_ui_kit/components/typography.rb
|
1370
|
+
- app/helpers/okonomi_ui_kit/config.rb
|
1366
1371
|
- app/helpers/okonomi_ui_kit/form_builder.rb
|
1367
1372
|
- app/helpers/okonomi_ui_kit/icon_helper.rb
|
1368
1373
|
- app/helpers/okonomi_ui_kit/navigation_helper.rb
|
1369
|
-
- app/helpers/okonomi_ui_kit/page_builder_helper.rb
|
1370
1374
|
- app/helpers/okonomi_ui_kit/svg_icons.rb
|
1371
|
-
- app/helpers/okonomi_ui_kit/table_helper.rb
|
1372
1375
|
- app/helpers/okonomi_ui_kit/theme.rb
|
1373
1376
|
- app/helpers/okonomi_ui_kit/theme_helper.rb
|
1374
1377
|
- app/helpers/okonomi_ui_kit/ui_helper.rb
|
@@ -1386,6 +1389,9 @@ files:
|
|
1386
1389
|
- app/views/layouts/okonomi_ui_kit/application.html.erb
|
1387
1390
|
- app/views/okonomi/attribute_sections/_section.html.erb
|
1388
1391
|
- app/views/okonomi/components/alert/_alert.html.erb
|
1392
|
+
- app/views/okonomi/components/code/_code.html.erb
|
1393
|
+
- app/views/okonomi/components/page/_page.html.erb
|
1394
|
+
- app/views/okonomi/components/table/_table.html.erb
|
1389
1395
|
- app/views/okonomi/components/typography/_typography.html.erb
|
1390
1396
|
- app/views/okonomi/forms/tailwind/_checkbox_label.html.erb
|
1391
1397
|
- app/views/okonomi/forms/tailwind/_field.html.erb
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module OkonomiUiKit
|
2
|
-
module BadgeHelper
|
3
|
-
def badge(text, severity = :default, **options)
|
4
|
-
color_classes = case severity.to_sym
|
5
|
-
when :success
|
6
|
-
"bg-green-100 text-green-800"
|
7
|
-
when :danger
|
8
|
-
"bg-red-100 text-red-800"
|
9
|
-
when :info
|
10
|
-
"bg-blue-100 text-blue-800"
|
11
|
-
when :warning
|
12
|
-
"bg-yellow-100 text-yellow-800"
|
13
|
-
else
|
14
|
-
"bg-gray-100 text-gray-800"
|
15
|
-
end
|
16
|
-
|
17
|
-
base_classes = "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
|
18
|
-
full_classes = "#{base_classes} #{color_classes} #{options[:class] || ''}".strip
|
19
|
-
|
20
|
-
tag.span(text, class: full_classes, **options.except(:class))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,217 +0,0 @@
|
|
1
|
-
module OkonomiUiKit
|
2
|
-
module PageBuilderHelper
|
3
|
-
def page(**options, &block)
|
4
|
-
builder = PageBuilder.new(self)
|
5
|
-
|
6
|
-
render 'okonomi/page_builder/page', builder: builder, options: options, &block
|
7
|
-
end
|
8
|
-
|
9
|
-
class PageBuilder
|
10
|
-
include ActionView::Helpers::TagHelper
|
11
|
-
include ActionView::Helpers::CaptureHelper
|
12
|
-
|
13
|
-
def initialize(template)
|
14
|
-
@template = template
|
15
|
-
end
|
16
|
-
|
17
|
-
def page_header(**options, &block)
|
18
|
-
header_builder = PageHeaderBuilder.new(@template)
|
19
|
-
yield(header_builder) if block_given?
|
20
|
-
header_builder.render
|
21
|
-
end
|
22
|
-
|
23
|
-
def section(**options, &block)
|
24
|
-
section_builder = SectionBuilder.new(@template)
|
25
|
-
yield(section_builder) if block_given?
|
26
|
-
section_builder.render
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def tag
|
32
|
-
@template.tag
|
33
|
-
end
|
34
|
-
|
35
|
-
def capture(*args, &block)
|
36
|
-
@template.capture(*args, &block)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class PageHeaderBuilder
|
41
|
-
include ActionView::Helpers::TagHelper
|
42
|
-
include ActionView::Helpers::CaptureHelper
|
43
|
-
|
44
|
-
def initialize(template)
|
45
|
-
@template = template
|
46
|
-
@breadcrumbs_content = nil
|
47
|
-
@row_content = nil
|
48
|
-
end
|
49
|
-
|
50
|
-
def breadcrumbs(&block)
|
51
|
-
@breadcrumbs_content = @template.breadcrumbs(&block)
|
52
|
-
end
|
53
|
-
|
54
|
-
def row(&block)
|
55
|
-
row_builder = PageHeaderRowBuilder.new(@template)
|
56
|
-
yield(row_builder) if block_given?
|
57
|
-
@row_content = row_builder.render
|
58
|
-
end
|
59
|
-
|
60
|
-
def render
|
61
|
-
content = []
|
62
|
-
content << @breadcrumbs_content if @breadcrumbs_content
|
63
|
-
content << @row_content if @row_content
|
64
|
-
|
65
|
-
tag.div(class: "flex flex-col gap-2") do
|
66
|
-
@template.safe_join(content.compact)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def tag
|
73
|
-
@template.tag
|
74
|
-
end
|
75
|
-
|
76
|
-
def capture(*args, &block)
|
77
|
-
@template.capture(*args, &block)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class PageHeaderRowBuilder
|
82
|
-
include ActionView::Helpers::TagHelper
|
83
|
-
include ActionView::Helpers::CaptureHelper
|
84
|
-
|
85
|
-
def initialize(template)
|
86
|
-
@template = template
|
87
|
-
@title_content = nil
|
88
|
-
@actions_content = nil
|
89
|
-
end
|
90
|
-
|
91
|
-
def title(text, **options)
|
92
|
-
@title_content = tag.h1(text, class: "text-2xl font-bold leading-7 text-gray-900 truncate sm:text-3xl sm:tracking-tight")
|
93
|
-
end
|
94
|
-
|
95
|
-
def actions(&block)
|
96
|
-
@actions_content = tag.div(class: "mt-4 flex md:ml-4 md:mt-0 gap-2") do
|
97
|
-
capture(&block) if block_given?
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def render
|
102
|
-
tag.div(class: "flex w-full justify-between items-center") do
|
103
|
-
content = []
|
104
|
-
content << @title_content if @title_content
|
105
|
-
content << @actions_content if @actions_content
|
106
|
-
@template.safe_join(content.compact)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
private
|
111
|
-
|
112
|
-
def tag
|
113
|
-
@template.tag
|
114
|
-
end
|
115
|
-
|
116
|
-
def capture(*args, &block)
|
117
|
-
@template.capture(*args, &block)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
class SectionBuilder
|
122
|
-
include ActionView::Helpers::TagHelper
|
123
|
-
include ActionView::Helpers::CaptureHelper
|
124
|
-
|
125
|
-
def initialize(template)
|
126
|
-
@template = template
|
127
|
-
@title_content = nil
|
128
|
-
@subtitle_content = nil
|
129
|
-
@actions_content = nil
|
130
|
-
@body_content = nil
|
131
|
-
end
|
132
|
-
|
133
|
-
def title(text, **options)
|
134
|
-
@title_content = tag.h3(text, class: "text-base/7 font-semibold text-gray-900")
|
135
|
-
end
|
136
|
-
|
137
|
-
def subtitle(text, **options)
|
138
|
-
@subtitle_content = tag.p(text, class: "mt-1 max-w-2xl text-sm/6 text-gray-500")
|
139
|
-
end
|
140
|
-
|
141
|
-
def actions(&block)
|
142
|
-
@actions_content = tag.div(class: "mt-4 flex md:ml-4 md:mt-0") do
|
143
|
-
capture(&block) if block_given?
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def body(&block)
|
148
|
-
@body_content = tag.div do
|
149
|
-
tag.dl(class: "divide-y divide-gray-100") do
|
150
|
-
capture(&block) if block_given?
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def attribute(label, value = nil, **options, &block)
|
156
|
-
content = if block_given?
|
157
|
-
capture(&block)
|
158
|
-
elsif value.respond_to?(:call)
|
159
|
-
value.call
|
160
|
-
else
|
161
|
-
value
|
162
|
-
end
|
163
|
-
|
164
|
-
tag.div(class: "py-6 sm:grid sm:grid-cols-3 sm:gap-4") do
|
165
|
-
dt_content = tag.dt(label, class: "text-sm font-medium text-gray-900")
|
166
|
-
dd_content = tag.dd(content, class: "mt-1 text-sm/6 text-gray-700 sm:col-span-2 sm:mt-0")
|
167
|
-
|
168
|
-
dt_content + dd_content
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
def render
|
173
|
-
tag.div(class: "overflow-hidden bg-white") do
|
174
|
-
header_content = build_header
|
175
|
-
content_parts = []
|
176
|
-
content_parts << header_content if header_content.present?
|
177
|
-
content_parts << @body_content if @body_content
|
178
|
-
@template.safe_join(content_parts.compact)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
private
|
183
|
-
|
184
|
-
def build_header
|
185
|
-
return nil unless @title_content || @subtitle_content || @actions_content
|
186
|
-
|
187
|
-
tag.div(class: "py-6") do
|
188
|
-
if @actions_content
|
189
|
-
tag.div(class: "flex w-full justify-between items-start") do
|
190
|
-
title_section = tag.div do
|
191
|
-
content_parts = []
|
192
|
-
content_parts << @title_content if @title_content
|
193
|
-
content_parts << @subtitle_content if @subtitle_content
|
194
|
-
@template.safe_join(content_parts.compact)
|
195
|
-
end
|
196
|
-
|
197
|
-
title_section + @actions_content
|
198
|
-
end
|
199
|
-
else
|
200
|
-
content_parts = []
|
201
|
-
content_parts << @title_content if @title_content
|
202
|
-
content_parts << @subtitle_content if @subtitle_content
|
203
|
-
@template.safe_join(content_parts.compact)
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def tag
|
209
|
-
@template.tag
|
210
|
-
end
|
211
|
-
|
212
|
-
def capture(*args, &block)
|
213
|
-
@template.capture(*args, &block)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|