okonomi_ui_kit 0.1.8 → 0.1.10
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 +50 -6
- data/app/assets/builds/okonomi_ui_kit/application.tailwind.css +508 -225
- data/app/helpers/okonomi_ui_kit/CLAUDE.md +619 -0
- data/app/helpers/okonomi_ui_kit/application_helper.rb +8 -0
- data/app/helpers/okonomi_ui_kit/attribute_section_helper.rb +5 -5
- data/app/helpers/okonomi_ui_kit/component.rb +14 -6
- data/app/helpers/okonomi_ui_kit/components/alert.rb +1 -1
- data/app/helpers/okonomi_ui_kit/components/badge.rb +4 -4
- data/app/helpers/okonomi_ui_kit/components/breadcrumbs.rb +4 -4
- data/app/helpers/okonomi_ui_kit/components/button_base.rb +94 -22
- data/app/helpers/okonomi_ui_kit/components/button_tag.rb +14 -8
- data/app/helpers/okonomi_ui_kit/components/button_to.rb +8 -7
- data/app/helpers/okonomi_ui_kit/components/code.rb +41 -37
- data/app/helpers/okonomi_ui_kit/components/confirmation_modal.rb +130 -0
- data/app/helpers/okonomi_ui_kit/components/dropdown_button.rb +147 -0
- data/app/helpers/okonomi_ui_kit/components/forms/check_box_with_label.rb +38 -0
- data/app/helpers/okonomi_ui_kit/components/forms/collection_select.rb +57 -0
- data/app/helpers/okonomi_ui_kit/components/forms/date_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/datetime_local_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/email_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/field.rb +24 -0
- data/app/helpers/okonomi_ui_kit/components/forms/field_set.rb +17 -0
- data/app/helpers/okonomi_ui_kit/components/forms/input_base.rb +57 -0
- data/app/helpers/okonomi_ui_kit/components/forms/label.rb +27 -0
- data/app/helpers/okonomi_ui_kit/components/forms/multi_select.rb +18 -0
- data/app/helpers/okonomi_ui_kit/components/forms/number_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/password_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/search_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/select.rb +57 -0
- data/app/helpers/okonomi_ui_kit/components/forms/show_if.rb +28 -0
- data/app/helpers/okonomi_ui_kit/components/forms/telephone_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/text_area.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/text_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/time_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms/upload_field.rb +25 -0
- data/app/helpers/okonomi_ui_kit/components/forms/url_field.rb +9 -0
- data/app/helpers/okonomi_ui_kit/components/forms.rb +6 -0
- data/app/helpers/okonomi_ui_kit/components/icon.rb +6 -6
- data/app/helpers/okonomi_ui_kit/components/link_to.rb +11 -10
- data/app/helpers/okonomi_ui_kit/components/navigation.rb +98 -0
- data/app/helpers/okonomi_ui_kit/components/page.rb +18 -203
- data/app/helpers/okonomi_ui_kit/components/page_header.rb +111 -0
- data/app/helpers/okonomi_ui_kit/components/page_section.rb +145 -0
- data/app/helpers/okonomi_ui_kit/components/table.rb +7 -8
- data/app/helpers/okonomi_ui_kit/components/typography.rb +16 -16
- data/app/helpers/okonomi_ui_kit/components.rb +4 -0
- data/app/helpers/okonomi_ui_kit/configs.rb +4 -0
- data/app/helpers/okonomi_ui_kit/form_builder.rb +39 -130
- data/app/helpers/okonomi_ui_kit/form_component.rb +7 -0
- data/app/helpers/okonomi_ui_kit/svg_icons.rb +5 -5
- data/app/helpers/okonomi_ui_kit/t_w_merge.rb +33 -27
- data/app/helpers/okonomi_ui_kit/ui_helper.rb +17 -58
- data/app/javascript/okonomi_ui_kit/controllers/dropdown_controller.js +6 -0
- data/app/views/okonomi/components/confirmation_modal/_confirmation_modal.html.erb +76 -0
- data/app/views/okonomi/components/dropdown_button/_dropdown_button.html.erb +282 -0
- data/app/views/okonomi/components/forms/check_box_with_label/_check_box_with_label.html.erb +6 -0
- data/app/views/okonomi/{forms/tailwind → components/forms/field}/_field.html.erb +7 -7
- data/app/views/okonomi/components/forms/field_set/_field_set.html.erb +3 -0
- data/app/views/okonomi/components/forms/upload_field/_upload_field.html.erb +1 -0
- data/app/views/okonomi/components/navigation/_link.html.erb +18 -0
- data/app/views/okonomi/components/navigation/_navigation.html.erb +4 -0
- data/app/views/okonomi/components/page/_page.html.erb +1 -1
- data/app/views/okonomi/components/page_header/_page_header.html.erb +4 -0
- data/app/views/okonomi/components/page_section/_page_section.html.erb +4 -0
- data/app/views/okonomi/forms/tailwind/_checkbox_label.html.erb +2 -2
- data/app/views/okonomi/forms/tailwind/_multi_select.html.erb +2 -4
- data/app/views/okonomi/forms/tailwind/_upload_field.html.erb +10 -10
- data/config/importmap.rb +1 -1
- data/lib/okonomi_ui_kit/engine.rb +0 -1
- data/lib/okonomi_ui_kit/version.rb +1 -1
- metadata +47 -16
- data/app/helpers/okonomi_ui_kit/navigation_helper.rb +0 -72
- data/app/helpers/okonomi_ui_kit/theme.rb +0 -136
- data/app/helpers/okonomi_ui_kit/theme_helper.rb +0 -17
- data/app/views/okonomi/forms/tailwind/_field_set.html.erb +0 -3
- data/app/views/okonomi/modals/_confirmation_modal.html.erb +0 -77
- data/app/views/okonomi/navigation/_link.html.erb +0 -15
- data/app/views/okonomi/navigation/_menu.html.erb +0 -3
- data/app/views/okonomi/navigation/_navbar.html.erb +0 -105
- data/app/views/okonomi/page_builder/_page.html.erb +0 -3
@@ -0,0 +1,57 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class CollectionSelect < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, method, collection, value_method, text_method, options = {}, html_options = {})
|
6
|
+
html_options = html_options.with_indifferent_access
|
7
|
+
css = build_select_classes(form, method, html_options)
|
8
|
+
|
9
|
+
select_html = form.collection_select(method, collection, value_method, text_method, options, html_options.merge(class: css))
|
10
|
+
icon_html = view.ui.icon(
|
11
|
+
style(:icon, :file),
|
12
|
+
class: style(:icon, :class)
|
13
|
+
)
|
14
|
+
|
15
|
+
view.content_tag(:div, class: style(:wrapper)) do
|
16
|
+
view.concat(select_html)
|
17
|
+
view.concat(icon_html)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
register_styles :default do
|
22
|
+
{
|
23
|
+
wrapper: "relative",
|
24
|
+
root: "w-full appearance-none border-0 pl-3 pr-10 py-2 rounded-md ring-1 focus:outline-none focus-within:ring-1",
|
25
|
+
error: "bg-danger-100 text-danger-400 ring-danger-400 focus:ring-danger-600",
|
26
|
+
valid: "text-default-700 ring-gray-300 focus-within:ring-gray-400",
|
27
|
+
icon: {
|
28
|
+
file: "heroicons/mini/chevron-down",
|
29
|
+
class: "absolute right-2 top-1/2 -translate-y-1/2 size-5 text-gray-400 pointer-events-none"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def build_select_classes(form, method, html_options)
|
37
|
+
css = [
|
38
|
+
style(:root),
|
39
|
+
when_errors(form, method, style(:error), style(:valid)),
|
40
|
+
html_options[:class]
|
41
|
+
].compact.join(" ").split(" ").uniq
|
42
|
+
|
43
|
+
TWMerge.merge(css)
|
44
|
+
end
|
45
|
+
|
46
|
+
def when_errors(form, method, value, default_value = nil)
|
47
|
+
key = method.to_s.gsub("_id", "").to_sym
|
48
|
+
if form.object.errors.include?(key) || form.object.errors.include?(method)
|
49
|
+
value
|
50
|
+
else
|
51
|
+
default_value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class Field < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, field_id = nil, options = {}, &block)
|
6
|
+
view.render(template_path, component: self, form: form, field_id: field_id, options: options, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
register_styles :default do
|
10
|
+
{
|
11
|
+
wrapper: "w-full flex flex-col gap-2",
|
12
|
+
header: "flex justify-between items-center",
|
13
|
+
hint: {
|
14
|
+
trigger: "text-primary-600 text-sm hover:cursor-help",
|
15
|
+
content: "text-xs absolute border rounded-md bg-gray-100 border-gray-600 text-gray-600 p-1 z-10"
|
16
|
+
},
|
17
|
+
content: "block",
|
18
|
+
error: "mt-1 text-danger-600 text-sm"
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class FieldSet < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, options = {}, &block)
|
6
|
+
view.render(template_path, component: self, options: options, form: form, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
register_styles :default do
|
10
|
+
{
|
11
|
+
root: "w-full flex flex-col gap-4 col-span-1 sm:col-span-3 md:col-span-5"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class InputBase < OkonomiUiKit::FormComponent
|
5
|
+
def render_arguments(object, method, options = {})
|
6
|
+
css = input_field_classes(object, method, self.class.type_value, options)
|
7
|
+
[ method, { autocomplete: "off" }.merge(options).merge(class: css) ]
|
8
|
+
end
|
9
|
+
|
10
|
+
register_styles :default do
|
11
|
+
{
|
12
|
+
root: "w-full border-0 px-3 py-2 rounded-md ring-1 focus:outline-none focus-within:ring-1",
|
13
|
+
error: "bg-danger-100 text-danger-400 ring-danger-400 focus:ring-danger-600",
|
14
|
+
valid: "text-default-700 ring-gray-300 focus-within:ring-gray-400",
|
15
|
+
disabled: "disabled:bg-gray-50 disabled:cursor-not-allowed"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.type(type)
|
20
|
+
@type = type
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.type_value
|
24
|
+
@type || :text
|
25
|
+
end
|
26
|
+
|
27
|
+
def input_field_classes(object, method, type, options, include_disabled: true)
|
28
|
+
css_classes = OkonomiUiKit::TWMerge.merge_all(
|
29
|
+
style(:root),
|
30
|
+
when_errors(
|
31
|
+
object,
|
32
|
+
method,
|
33
|
+
style(:error),
|
34
|
+
style(:valid)
|
35
|
+
),
|
36
|
+
options[:class]
|
37
|
+
)
|
38
|
+
|
39
|
+
if include_disabled
|
40
|
+
css_classes = OkonomiUiKit::TWMerge.merge_all(css_classes, style(:disabled))
|
41
|
+
end
|
42
|
+
|
43
|
+
css_classes
|
44
|
+
end
|
45
|
+
|
46
|
+
def when_errors(object, method, value, default_value = nil)
|
47
|
+
key = method.to_s.gsub("_id", "").to_sym
|
48
|
+
if object.errors.include?(key) || object.errors.include?(method)
|
49
|
+
value
|
50
|
+
else
|
51
|
+
default_value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class Label < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, method, text = nil, options = {}, &block)
|
6
|
+
options = options.with_indifferent_access
|
7
|
+
base_classes = style(:root)
|
8
|
+
# Call the parent class label method directly to avoid infinite loop
|
9
|
+
ActionView::Helpers::FormBuilder.instance_method(:label).bind(form).call(method, text, merge_class(options, base_classes), &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
register_styles :default do
|
13
|
+
{
|
14
|
+
root: "block text-sm/6 font-medium text-gray-900"
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def merge_class(options, new_class)
|
21
|
+
options[:class] = TWMerge.merge(options[:class] || "", new_class)
|
22
|
+
options
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class MultiSelect < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, method, options = {})
|
6
|
+
view.render(template_path, component: self, form: form, method: method, options: options)
|
7
|
+
end
|
8
|
+
|
9
|
+
register_styles :default do
|
10
|
+
{
|
11
|
+
wrapper: "grid grid-cols-2 gap-2",
|
12
|
+
item: "flex items-center"
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class Select < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, method, choices = nil, options = {}, html_options = {}, &block)
|
6
|
+
html_options = html_options.with_indifferent_access
|
7
|
+
css = build_select_classes(form, method, html_options)
|
8
|
+
|
9
|
+
select_html = ActionView::Helpers::FormBuilder.instance_method(:select).bind(form).call(method, choices, options, html_options.merge(class: css), &block)
|
10
|
+
icon_html = view.ui.icon(
|
11
|
+
style(:icon, :file),
|
12
|
+
class: style(:icon, :class)
|
13
|
+
)
|
14
|
+
|
15
|
+
view.content_tag(:div, class: style(:wrapper)) do
|
16
|
+
view.concat(select_html)
|
17
|
+
view.concat(icon_html)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
register_styles :default do
|
22
|
+
{
|
23
|
+
wrapper: "relative",
|
24
|
+
root: "w-full appearance-none border-0 pl-3 pr-10 py-2 rounded-md ring-1 focus:outline-none focus-within:ring-1",
|
25
|
+
error: "bg-danger-100 text-danger-400 ring-danger-400 focus:ring-danger-600",
|
26
|
+
valid: "text-default-700 ring-gray-300 focus-within:ring-gray-400",
|
27
|
+
icon: {
|
28
|
+
file: "heroicons/mini/chevron-down",
|
29
|
+
class: "absolute right-2 top-1/2 -translate-y-1/2 size-5 text-gray-400 pointer-events-none"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def build_select_classes(form, method, html_options)
|
37
|
+
css = [
|
38
|
+
style(:root),
|
39
|
+
when_errors(form, method, style(:error), style(:valid)),
|
40
|
+
html_options[:class]
|
41
|
+
].compact.join(" ").split(" ").uniq
|
42
|
+
|
43
|
+
css.join(" ")
|
44
|
+
end
|
45
|
+
|
46
|
+
def when_errors(form, method, value, default_value = nil)
|
47
|
+
key = method.to_s.gsub("_id", "").to_sym
|
48
|
+
if form.object.errors.include?(key) || form.object.errors.include?(method)
|
49
|
+
value
|
50
|
+
else
|
51
|
+
default_value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class ShowIf < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, options = {}, &block)
|
6
|
+
field = options[:field]
|
7
|
+
equals = options[:equals]
|
8
|
+
field_id = "#{form.object_name}_#{field}"
|
9
|
+
view.tag.div(
|
10
|
+
class: style(:root),
|
11
|
+
data: {
|
12
|
+
controller: "form-field-visibility",
|
13
|
+
"form-field-visibility-field-id-value": field_id,
|
14
|
+
"form-field-visibility-equals-value": equals
|
15
|
+
},
|
16
|
+
&block
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
register_styles :default do
|
21
|
+
{
|
22
|
+
root: "hidden"
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
class UploadField < OkonomiUiKit::FormComponent
|
5
|
+
def render(form, method, options = {})
|
6
|
+
view.render(template_path, component: self, form: form, method: method, options: options)
|
7
|
+
end
|
8
|
+
|
9
|
+
register_styles :default do
|
10
|
+
{
|
11
|
+
dropzone: "border-2 border-dashed border-gray-300 rounded-md p-6 text-center cursor-pointer hover:bg-gray-50 relative",
|
12
|
+
label: "block cursor-pointer",
|
13
|
+
content: "flex flex-col items-center text-gray-600 space-y-2",
|
14
|
+
preview: "w-full flex justify-center items-center",
|
15
|
+
preview_image: "max-h-32",
|
16
|
+
icon: "size-12 text-gray-400",
|
17
|
+
filename: "text-sm text-gray-500",
|
18
|
+
file_input: "hidden",
|
19
|
+
clear_button: "absolute top-2 right-2 bg-red-100 text-red-700 px-2 py-1 text-xs rounded hover:bg-red-200"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -3,18 +3,18 @@ module OkonomiUiKit
|
|
3
3
|
class Icon < OkonomiUiKit::Component
|
4
4
|
def render(name, options = {})
|
5
5
|
options = options.with_indifferent_access
|
6
|
-
|
6
|
+
|
7
7
|
# Extract specific icon options
|
8
8
|
variant = options.delete(:variant) || :outlined
|
9
9
|
width = options.delete(:width)
|
10
10
|
height = options.delete(:height)
|
11
|
-
|
11
|
+
|
12
12
|
# Build classes array
|
13
13
|
classes = [
|
14
14
|
style(:base),
|
15
15
|
options.delete(:class)
|
16
|
-
].compact.join(
|
17
|
-
|
16
|
+
].compact.join(" ")
|
17
|
+
|
18
18
|
view.render(
|
19
19
|
template_path,
|
20
20
|
name: name,
|
@@ -25,7 +25,7 @@ module OkonomiUiKit
|
|
25
25
|
options: options
|
26
26
|
)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
register_styles :default do
|
30
30
|
{
|
31
31
|
base: "inline-block"
|
@@ -33,4 +33,4 @@ module OkonomiUiKit
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
@@ -3,21 +3,22 @@ module OkonomiUiKit
|
|
3
3
|
class LinkTo < OkonomiUiKit::Components::ButtonBase
|
4
4
|
def render(name = nil, options = nil, html_options = nil, &block)
|
5
5
|
html_options, options, name = options, name, block if block_given?
|
6
|
-
|
6
|
+
|
7
7
|
html_options ||= {}
|
8
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
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
# Extract icon configuration
|
14
|
+
icon_config, html_options = extract_icon_config(html_options)
|
15
|
+
|
13
16
|
html_options[:class] = build_button_class(variant: variant, color: color, classes: html_options[:class])
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
else
|
18
|
-
view.link_to(name, options, html_options)
|
17
|
+
|
18
|
+
view.link_to(options, html_options) do
|
19
|
+
render_button_content(icon_config, name, &block)
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
23
|
-
end
|
24
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
module Components
|
3
|
+
class Navigation < OkonomiUiKit::Component
|
4
|
+
def render(options = {}, &block)
|
5
|
+
options = options.with_indifferent_access
|
6
|
+
builder = NavigationBuilder.new(view, self)
|
7
|
+
|
8
|
+
view.render(template_path, builder: builder, options: options, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
register_styles :default do
|
12
|
+
{
|
13
|
+
menu: {
|
14
|
+
base: "flex flex-1 flex-col gap-y-7"
|
15
|
+
},
|
16
|
+
group: {
|
17
|
+
title: "text-xs/6 font-semibold text-gray-400",
|
18
|
+
list: "-mx-2 mt-2 space-y-1"
|
19
|
+
},
|
20
|
+
link: {
|
21
|
+
base: "group flex gap-x-3 rounded-md p-2 text-sm/6 font-semibold hover:bg-gray-50 hover:text-primary-600 text-gray-700",
|
22
|
+
active: "group flex gap-x-3 rounded-md p-2 text-sm/6 font-semibold hover:bg-gray-50 hover:text-primary-600 bg-gray-50 text-primary-600",
|
23
|
+
icon: "size-6 text-gray-400 group-hover:text-primary-600",
|
24
|
+
initials: {
|
25
|
+
base: "flex size-6 shrink-0 items-center justify-center rounded-lg border border-gray-200 bg-white text-[0.625rem] font-medium text-gray-400 group-hover:border-primary-600 group-hover:text-primary-600"
|
26
|
+
}
|
27
|
+
},
|
28
|
+
profile_section: {
|
29
|
+
base: "-mx-6 mt-auto"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class NavigationBuilder
|
36
|
+
attr_reader :view, :navigation_component, :groups
|
37
|
+
|
38
|
+
def initialize(view, navigation_component)
|
39
|
+
@view = view
|
40
|
+
@navigation_component = navigation_component
|
41
|
+
@groups = []
|
42
|
+
end
|
43
|
+
|
44
|
+
def group(title, &block)
|
45
|
+
group_builder = NavigationGroupBuilder.new(view, navigation_component)
|
46
|
+
yield(group_builder)
|
47
|
+
|
48
|
+
@groups << view.tag.li do
|
49
|
+
view.tag.div(title, class: style(:group, :title)) +
|
50
|
+
view.tag.ul(group_builder.render_links, role: "list", class: style(:group, :list))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def profile_section(&block)
|
55
|
+
content = view.capture(&block)
|
56
|
+
@groups << view.tag.li(content, class: style(:profile_section, :base))
|
57
|
+
end
|
58
|
+
|
59
|
+
def style(*args)
|
60
|
+
navigation_component.style(*args)
|
61
|
+
end
|
62
|
+
|
63
|
+
def render_groups
|
64
|
+
view.safe_join(@groups)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class NavigationGroupBuilder
|
69
|
+
attr_reader :view, :navigation_component, :links
|
70
|
+
|
71
|
+
def initialize(view, navigation_component)
|
72
|
+
@view = view
|
73
|
+
@navigation_component = navigation_component
|
74
|
+
@links = []
|
75
|
+
end
|
76
|
+
|
77
|
+
def nav_link(title, path, icon: nil, initials: nil, exact: false)
|
78
|
+
@links << view.tag.li do
|
79
|
+
view.render "okonomi/components/navigation/link",
|
80
|
+
path: path,
|
81
|
+
title: title,
|
82
|
+
icon: icon,
|
83
|
+
initials: initials,
|
84
|
+
exact: exact,
|
85
|
+
style_helper: self
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def style(*args)
|
90
|
+
navigation_component.style(*args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def render_links
|
94
|
+
view.safe_join(@links)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|