okonomi_ui_kit 0.1.7 → 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 +262 -7
- data/app/helpers/okonomi_ui_kit/component.rb +35 -16
- data/app/helpers/okonomi_ui_kit/components/badge.rb +2 -2
- 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 +1 -12
- data/app/helpers/okonomi_ui_kit/components/icon.rb +36 -0
- data/app/helpers/okonomi_ui_kit/components/link_to.rb +1 -12
- data/app/helpers/okonomi_ui_kit/components/page.rb +1 -1
- data/app/helpers/okonomi_ui_kit/components/table.rb +2 -2
- data/app/helpers/okonomi_ui_kit/config.rb +5 -1
- 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 +0 -23
- data/app/views/okonomi/components/breadcrumbs/_breadcrumbs.html.erb +46 -0
- data/app/views/okonomi/components/icon/_icon.html.erb +38 -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 -2
- data/lib/okonomi_ui_kit/version.rb +1 -1
- metadata +8 -3
- data/app/helpers/okonomi_ui_kit/breadcrumbs_helper.rb +0 -60
- data/app/helpers/okonomi_ui_kit/icon_helper.rb +0 -39
@@ -30,7 +30,7 @@ module OkonomiUiKit
|
|
30
30
|
internal_styles = internal_styles_registry[internal_name] || {}
|
31
31
|
config_styles = config_styles_registry[config_name] || {}
|
32
32
|
|
33
|
-
{}
|
33
|
+
deep_merge({}, internal_styles, config_styles)
|
34
34
|
end
|
35
35
|
|
36
36
|
def internal_styles_registry
|
@@ -45,16 +45,42 @@ module OkonomiUiKit
|
|
45
45
|
:default
|
46
46
|
end
|
47
47
|
|
48
|
+
def self.register_styles(theme = :default, &block)
|
49
|
+
styles = block.call if block_given?
|
50
|
+
|
51
|
+
raise ArgumentError, "Styles must be a Hash" unless styles.is_a?(Hash)
|
52
|
+
|
53
|
+
internal_styles_registry[theme] = styles if styles.is_a?(Hash)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.internal_styles_registry
|
57
|
+
@internal_styles_registry ||= deep_merge({}, parent_styles_registry)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.parent_styles_registry
|
61
|
+
if superclass.respond_to?(:internal_styles_registry)
|
62
|
+
superclass.internal_styles_registry
|
63
|
+
else
|
64
|
+
{}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
48
68
|
def self.config_styles_registry
|
49
|
-
|
69
|
+
@config_styles_registry ||= config_classes.reverse.reduce({}) do |hash, klass|
|
70
|
+
deep_merge(hash, klass.styles_registry)
|
71
|
+
end
|
72
|
+
end
|
50
73
|
|
51
|
-
|
74
|
+
def self.config_classes
|
75
|
+
@config_classes ||= resolve_config_classes
|
52
76
|
end
|
53
77
|
|
54
|
-
def self.
|
55
|
-
|
78
|
+
def self.resolve_config_classes
|
79
|
+
classes = []
|
80
|
+
classes << Object.const_get(config_class_name) if config_class?
|
81
|
+
classes += superclass.config_classes if superclass <= OkonomiUiKit::Component
|
56
82
|
|
57
|
-
|
83
|
+
classes.compact
|
58
84
|
end
|
59
85
|
|
60
86
|
def self.config_class_name
|
@@ -65,16 +91,9 @@ module OkonomiUiKit
|
|
65
91
|
Object.const_defined?(config_class_name)
|
66
92
|
end
|
67
93
|
|
68
|
-
def self.
|
69
|
-
|
70
|
-
|
71
|
-
raise ArgumentError, "Styles must be a Hash" unless styles.is_a?(Hash)
|
72
|
-
|
73
|
-
internal_styles_registry[theme] = styles if styles.is_a?(Hash)
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.internal_styles_registry
|
77
|
-
@internal_styles_registry ||= {}
|
94
|
+
def self.deep_merge(*hashes)
|
95
|
+
OkonomiUiKit::TWMerge.deep_merge_all(*hashes)
|
78
96
|
end
|
97
|
+
delegate :deep_merge, to: :class
|
79
98
|
end
|
80
99
|
end
|
@@ -3,8 +3,8 @@ module OkonomiUiKit
|
|
3
3
|
class Badge < OkonomiUiKit::Component
|
4
4
|
def render(text, options = {})
|
5
5
|
options = options.with_indifferent_access
|
6
|
-
severity = (options.delete(:severity) || :default).to_sym
|
7
|
-
|
6
|
+
severity = (options.delete(:severity) || options.delete(:variant) || :default).to_sym
|
7
|
+
|
8
8
|
classes = [
|
9
9
|
style(:base),
|
10
10
|
style(:severities, severity) || '',
|
@@ -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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module OkonomiUiKit
|
2
2
|
module Components
|
3
|
-
class ButtonTo < OkonomiUiKit::
|
3
|
+
class ButtonTo < 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
|
|
@@ -18,17 +18,6 @@ module OkonomiUiKit
|
|
18
18
|
view.button_to(name, options, html_options)
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def build_button_class(variant:, color:, classes: '')
|
25
|
-
[
|
26
|
-
theme.dig(:components, :link, :root) || '',
|
27
|
-
theme.dig(:components, :link, variant.to_sym, :root) || '',
|
28
|
-
theme.dig(:components, :link, variant.to_sym, :colors, color.to_sym) || '',
|
29
|
-
classes,
|
30
|
-
].reject(&:blank?).join(' ')
|
31
|
-
end
|
32
21
|
end
|
33
22
|
end
|
34
23
|
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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module OkonomiUiKit
|
2
2
|
module Components
|
3
|
-
class LinkTo < OkonomiUiKit::
|
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
|
|
@@ -18,17 +18,6 @@ module OkonomiUiKit
|
|
18
18
|
view.link_to(name, options, html_options)
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def build_button_class(variant:, color:, classes: '')
|
25
|
-
[
|
26
|
-
theme.dig(:components, :link, :root) || '',
|
27
|
-
theme.dig(:components, :link, variant.to_sym, :root) || '',
|
28
|
-
theme.dig(:components, :link, variant.to_sym, :colors, color.to_sym) || '',
|
29
|
-
classes,
|
30
|
-
].reject(&:blank?).join(' ')
|
31
|
-
end
|
32
21
|
end
|
33
22
|
end
|
34
23
|
end
|
@@ -127,8 +127,8 @@ module OkonomiUiKit
|
|
127
127
|
capture(&block)
|
128
128
|
else
|
129
129
|
tag.div(class: style(:empty_state, :wrapper)) do
|
130
|
-
icon_content = if @template.respond_to?(:
|
131
|
-
@template.
|
130
|
+
icon_content = if @template.respond_to?(:ui)
|
131
|
+
@template.ui.icon(icon, class: style(:empty_state, :icon))
|
132
132
|
else
|
133
133
|
tag.div(class: style(:empty_state, :icon))
|
134
134
|
end
|
@@ -6,11 +6,15 @@ module OkonomiUiKit
|
|
6
6
|
raise ArgumentError, "Styles must be a Hash" unless styles.is_a?(Hash)
|
7
7
|
|
8
8
|
styles_registry[theme] ||= {}
|
9
|
-
styles_registry[theme] = styles_registry[theme]
|
9
|
+
styles_registry[theme] = deep_merge({}, styles_registry[theme], styles)
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.styles_registry
|
13
13
|
@styles_registry ||= {}
|
14
14
|
end
|
15
|
+
|
16
|
+
def self.deep_merge(*hashes)
|
17
|
+
OkonomiUiKit::TWMerge.deep_merge_all(*hashes)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
@@ -85,7 +85,7 @@ module OkonomiUiKit
|
|
85
85
|
].compact.join(' ').split(' ').uniq
|
86
86
|
|
87
87
|
select_html = super(method, choices, options, html_options.merge(class: css), &block)
|
88
|
-
icon_html = @template.
|
88
|
+
icon_html = @template.ui.icon(
|
89
89
|
ui.get_theme.dig(:components, :select, :icon, :file),
|
90
90
|
class: ui.get_theme.dig(:components, :select, :icon, :class)
|
91
91
|
)
|
@@ -108,7 +108,7 @@ module OkonomiUiKit
|
|
108
108
|
].compact.join(' ').split(' ').uniq
|
109
109
|
|
110
110
|
select_html = super(method, collection, value_method, text_method, options, html_options.merge(class: css))
|
111
|
-
icon_html = @template.
|
111
|
+
icon_html = @template.ui.icon(
|
112
112
|
ui.get_theme.dig(:components, :select, :icon, :file),
|
113
113
|
class: ui.get_theme.dig(:components, :select, :icon, :class)
|
114
114
|
)
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module OkonomiUiKit
|
2
|
+
class TWMerge
|
3
|
+
# ---- Public API -----------------------------------------------------------
|
4
|
+
|
5
|
+
# Merge two Tailwind class strings with conflict resolution.
|
6
|
+
def self.merge(a, b)
|
7
|
+
tokens = "#{a} #{b}".split(/\s+/).reject(&:empty?)
|
8
|
+
result = []
|
9
|
+
index_by_key = {}
|
10
|
+
|
11
|
+
tokens.each do |tok|
|
12
|
+
variants, base = split_variants(tok)
|
13
|
+
group = conflict_group_for(base)
|
14
|
+
key = [variants, group || "literal:#{base}"]
|
15
|
+
|
16
|
+
if index_by_key.key?(key)
|
17
|
+
pos = index_by_key[key]
|
18
|
+
result[pos] = tok
|
19
|
+
else
|
20
|
+
index_by_key[key] = result.length
|
21
|
+
result << tok
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
result.join(' ')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Deep-merge two hashes; when both values are strings, merge as Tailwind classes.
|
29
|
+
# For other types, the right-hand value wins unless it is nil.
|
30
|
+
def self.deep_merge(a, b)
|
31
|
+
if a.is_a?(Hash) && b.is_a?(Hash)
|
32
|
+
(a.keys | b.keys).each_with_object({}) do |k, h|
|
33
|
+
h[k] = deep_merge(a[k], b[k])
|
34
|
+
end
|
35
|
+
elsif a.is_a?(String) && b.is_a?(String)
|
36
|
+
merge(a, b)
|
37
|
+
else
|
38
|
+
b.nil? ? a : b
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.deep_merge_all(*hashes)
|
43
|
+
hashes.reduce({}) do |result, hash|
|
44
|
+
if hash.is_a?(Hash)
|
45
|
+
deep_merge(result, hash)
|
46
|
+
else
|
47
|
+
raise ArgumentError, "All arguments must be Hashes"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# ---- Implementation details ----------------------------------------------
|
53
|
+
|
54
|
+
# Conflict groups (minimal, extensible). More specific patterns first.
|
55
|
+
CONFLICT_RULES = [
|
56
|
+
# Typography
|
57
|
+
[/^text-(?:xs|sm|base|lg|xl|\d+xl|\[\S+\])$/, :text_size],
|
58
|
+
[/^text-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :text_color],
|
59
|
+
[/^font-(?:thin|extralight|light|normal|medium|semibold|bold|extrabold|black)$/, :font_weight],
|
60
|
+
[/^leading-(?:none|tight|snug|normal|relaxed|loose|\d+|\[.+\])$/, :line_height],
|
61
|
+
[/^tracking-(?:tighter|tight|normal|wide|widest|\[.+\])$/, :letter_spacing],
|
62
|
+
|
63
|
+
# Display & position
|
64
|
+
[/^(?:hidden|block|inline|inline-block|flex|inline-flex|grid|inline-grid|table|inline-table|flow-root)$/, :display],
|
65
|
+
[/^(?:static|fixed|absolute|relative|sticky)$/, :position],
|
66
|
+
|
67
|
+
# Flexbox
|
68
|
+
[/^flex-(?:row|col|row-reverse|col-reverse)$/, :flex_direction],
|
69
|
+
[/^flex-(?:wrap|nowrap|wrap-reverse)$/, :flex_wrap],
|
70
|
+
[/^items-(?:start|end|center|baseline|stretch)$/, :align_items],
|
71
|
+
[/^justify-(?:start|end|center|between|around|evenly)$/, :justify_content],
|
72
|
+
|
73
|
+
# Borders
|
74
|
+
[/^(?:border|border-(?:\d+|\[\S+\]))$/, :border_width_overall],
|
75
|
+
[/^border-[trblxy](?:-\d+|\[\S+\])?$/, :border_width_side],
|
76
|
+
[/^border-(?:solid|dashed|dotted|double|none)$/, :border_style],
|
77
|
+
[/^border-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :border_color],
|
78
|
+
|
79
|
+
# Radius
|
80
|
+
[/^rounded(?:-(?:none|sm|md|lg|xl|2xl|3xl|full|\[.+\]))?$/, :rounded_overall],
|
81
|
+
[/^rounded-(?:t|r|b|l|tl|tr|br|bl)-(?:none|sm|md|lg|xl|2xl|3xl|full|\[.+\])$/, :rounded_corner],
|
82
|
+
|
83
|
+
# Background
|
84
|
+
[/^bg-(?:inherit|current|transparent|black|white|[a-z]+-\d{2,3}|[a-z]+-950|\[.+\])$/, :bg_color],
|
85
|
+
|
86
|
+
# Overflow & opacity
|
87
|
+
[/^overflow-(?:auto|hidden|visible|scroll|clip)$/, :overflow],
|
88
|
+
[/^overflow-[xy]-(?:auto|hidden|visible|scroll|clip)$/, :overflow_axis],
|
89
|
+
[/^opacity-(?:\d{1,3}|\[.+\])$/, :opacity],
|
90
|
+
].freeze
|
91
|
+
|
92
|
+
class << self
|
93
|
+
private
|
94
|
+
|
95
|
+
# "sm:hover:text-lg" -> ["sm:hover", "text-lg"]
|
96
|
+
def split_variants(token)
|
97
|
+
parts = token.split(':')
|
98
|
+
return ["", token] if parts.size == 1
|
99
|
+
[parts[0..-2].join(':'), parts[-1]]
|
100
|
+
end
|
101
|
+
|
102
|
+
def conflict_group_for(base)
|
103
|
+
rule = CONFLICT_RULES.find { |(rx, _)| base.match?(rx) }
|
104
|
+
rule ? rule[1] : nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -2,29 +2,6 @@ module OkonomiUiKit
|
|
2
2
|
module Theme
|
3
3
|
LIGHT_THEME = {
|
4
4
|
components: {
|
5
|
-
typography: {
|
6
|
-
variants: {
|
7
|
-
body1: "text-base font-normal",
|
8
|
-
body2: "text-sm font-normal",
|
9
|
-
h1: "text-3xl font-bold",
|
10
|
-
h2: "text-2xl font-bold",
|
11
|
-
h3: "text-xl font-semibold",
|
12
|
-
h4: "text-lg font-semibold",
|
13
|
-
h5: "text-base font-semibold",
|
14
|
-
h6: "text-sm font-semibold"
|
15
|
-
},
|
16
|
-
colors: {
|
17
|
-
default: "text-default-700",
|
18
|
-
dark: "text-default-900",
|
19
|
-
muted: "text-default-500",
|
20
|
-
primary: "text-primary-600",
|
21
|
-
secondary: "text-secondary-600",
|
22
|
-
success: "text-success-600",
|
23
|
-
danger: "text-danger-600",
|
24
|
-
warning: "text-warning-600",
|
25
|
-
info: "text-info-600"
|
26
|
-
}
|
27
|
-
},
|
28
5
|
link: {
|
29
6
|
root: "hover:cursor-pointer text-sm",
|
30
7
|
outlined: {
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<%= tag.nav(**options.merge(class: component.style(:nav), 'aria-label': 'Breadcrumb')) do %>
|
2
|
+
<ol role="list" class="<%= component.style(:list) %>">
|
3
|
+
<% items.each_with_index do |item, index| %>
|
4
|
+
<li>
|
5
|
+
<div class="flex items-center">
|
6
|
+
<% if index == 0 %>
|
7
|
+
<% if item[:icon] %>
|
8
|
+
<% if item[:path] %>
|
9
|
+
<%= link_to item[:path], class: "text-gray-400 hover:text-gray-500", 'aria-current': (item[:current] ? 'page' : nil) do %>
|
10
|
+
<%= item[:icon] %>
|
11
|
+
<span class="sr-only"><%= item[:text] %></span>
|
12
|
+
<% end %>
|
13
|
+
<% else %>
|
14
|
+
<span class="text-gray-400" aria-current="<%= item[:current] ? 'page' : nil %>">
|
15
|
+
<%= item[:icon] %>
|
16
|
+
<span class="sr-only"><%= item[:text] %></span>
|
17
|
+
</span>
|
18
|
+
<% end %>
|
19
|
+
<% else %>
|
20
|
+
<div class="flex items-center">
|
21
|
+
<% if item[:path] && !item[:current] %>
|
22
|
+
<%= link_to item[:text], item[:path], class: component.style(:link, :first), 'aria-current': nil %>
|
23
|
+
<% else %>
|
24
|
+
<span class="<%= component.style(:link, :first) %>" aria-current="<%= item[:current] ? 'page' : nil %>">
|
25
|
+
<%= item[:text] %>
|
26
|
+
</span>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
30
|
+
<% else %>
|
31
|
+
<svg class="<%= component.style(:separator, :base) %>" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
32
|
+
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
33
|
+
</svg>
|
34
|
+
<% if item[:path] && !item[:current] %>
|
35
|
+
<%= link_to item[:text], item[:path], class: component.style(:link, :base), 'aria-current': nil %>
|
36
|
+
<% else %>
|
37
|
+
<span class="<%= component.style(:link, :current) %>" aria-current="<%= item[:current] ? 'page' : nil %>">
|
38
|
+
<%= item[:text] %>
|
39
|
+
</span>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
</li>
|
44
|
+
<% end %>
|
45
|
+
</ol>
|
46
|
+
<% end %>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<%
|
2
|
+
# Load the SVG content
|
3
|
+
svg_content = if OkonomiUiKit::SvgIcons.exist?(name)
|
4
|
+
OkonomiUiKit::SvgIcons.read(name)
|
5
|
+
else
|
6
|
+
"<!-- SVG #{name} not found -->"
|
7
|
+
end
|
8
|
+
|
9
|
+
# Parse and modify the SVG
|
10
|
+
if svg_content.start_with?("<!--")
|
11
|
+
%><%= raw svg_content %><%
|
12
|
+
else
|
13
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(svg_content)
|
14
|
+
svg = doc.at_css('svg')
|
15
|
+
|
16
|
+
if svg
|
17
|
+
# Apply classes
|
18
|
+
svg['class'] = classes if classes.present?
|
19
|
+
|
20
|
+
# Apply dimensions
|
21
|
+
svg['width'] = width if width.present?
|
22
|
+
svg['height'] = height if height.present?
|
23
|
+
|
24
|
+
# Apply any additional options as attributes
|
25
|
+
options.each do |key, value|
|
26
|
+
if key.to_s == 'data' && value.is_a?(Hash)
|
27
|
+
# Handle data attributes specially
|
28
|
+
value.each do |data_key, data_value|
|
29
|
+
svg["data-#{data_key.to_s.dasherize}"] = data_value
|
30
|
+
end
|
31
|
+
else
|
32
|
+
svg[key.to_s.dasherize] = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
%><%= raw doc.to_html %><%
|
37
|
+
end
|
38
|
+
%>
|
@@ -11,10 +11,10 @@
|
|
11
11
|
<% if blob.image? %>
|
12
12
|
<%= image_tag url_for(blob), class: "max-h-32" %>
|
13
13
|
<% else %>
|
14
|
-
<%=
|
14
|
+
<%= ui.icon("heroicons/solid/document", class: "size-12 text-gray-400") %>
|
15
15
|
<% end %>
|
16
16
|
<% else %>
|
17
|
-
<%=
|
17
|
+
<%= ui.icon("heroicons/solid/plus", class: "size-12 w-12 text-gray-400") %>
|
18
18
|
<% end %>
|
19
19
|
</div>
|
20
20
|
|
@@ -28,7 +28,7 @@
|
|
28
28
|
class="<%= ui.get_theme.dig(:components, :modal, :close_button, :button) %>"
|
29
29
|
data-action="click->modal#close">
|
30
30
|
<span class="sr-only">Close</span>
|
31
|
-
<%=
|
31
|
+
<%= ui.icon(ui.get_theme.dig(:components, :modal, :close_button, :icon, :file),
|
32
32
|
class: ui.get_theme.dig(:components, :modal, :close_button, :icon, :class)) %>
|
33
33
|
</button>
|
34
34
|
</div>
|
@@ -37,7 +37,7 @@
|
|
37
37
|
<div class="<%= ui.get_theme.dig(:components, :modal, :content, :wrapper) %>">
|
38
38
|
<!-- Icon -->
|
39
39
|
<div class="<%= ui.modal_icon_wrapper_class(options[:variant]) %>">
|
40
|
-
<%=
|
40
|
+
<%= ui.icon(ui.get_theme.dig(:components, :modal, :icon, :variants, options[:variant], :file),
|
41
41
|
class: [ui.get_theme.dig(:components, :modal, :icon, :class),
|
42
42
|
ui.get_theme.dig(:components, :modal, :icon, :variants, options[:variant], :icon)].join(' ')) %>
|
43
43
|
</div>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<% if defined?(initials) && initials.present? %>
|
10
10
|
<span class="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"><%= initials %></span>
|
11
11
|
<% elsif defined?(icon) && icon.present? %>
|
12
|
-
<%=
|
12
|
+
<%= ui.icon icon, class: "size-6 text-gray-400 group-hover:text-primary-600" %>
|
13
13
|
<% end %>
|
14
14
|
<%= title %>
|
15
15
|
<% end %>
|
@@ -22,8 +22,6 @@ module OkonomiUiKit
|
|
22
22
|
ActiveSupport.on_load(:action_view) do
|
23
23
|
include OkonomiUiKit::ApplicationHelper
|
24
24
|
include OkonomiUiKit::AttributeSectionHelper
|
25
|
-
include OkonomiUiKit::BreadcrumbsHelper
|
26
|
-
include OkonomiUiKit::IconHelper
|
27
25
|
include OkonomiUiKit::NavigationHelper
|
28
26
|
include OkonomiUiKit::UiHelper
|
29
27
|
|