uchi 0.1.5 → 0.1.6

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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/uchi/application.js +2655 -24
  3. data/app/assets/javascripts/uchi.js +11 -0
  4. data/app/assets/stylesheets/uchi/application.css +982 -1311
  5. data/app/assets/tailwind/uchi.css +4 -4
  6. data/app/components/uchi/field/belongs_to/edit.html.erb +1 -1
  7. data/app/components/uchi/field/belongs_to/index.html.erb +1 -1
  8. data/app/components/uchi/field/belongs_to/show.html.erb +3 -5
  9. data/app/components/uchi/field/belongs_to.rb +30 -7
  10. data/app/components/uchi/field/boolean/edit.html.erb +1 -1
  11. data/app/components/uchi/field/date/edit.html.erb +1 -1
  12. data/app/components/uchi/field/date_time/edit.html.erb +1 -1
  13. data/app/components/uchi/field/file/edit.html.erb +1 -1
  14. data/app/components/uchi/field/file/index.html.erb +2 -1
  15. data/app/components/uchi/field/file/show.html.erb +3 -2
  16. data/app/components/uchi/field/has_and_belongs_to_many/show.html.erb +5 -3
  17. data/app/components/uchi/field/has_many/show.html.erb +5 -3
  18. data/app/components/uchi/field/id/index.html.erb +1 -1
  19. data/app/components/uchi/field/id/show.html.erb +1 -1
  20. data/app/components/uchi/field/image/edit.html.erb +1 -1
  21. data/app/components/uchi/field/image/index.html.erb +2 -1
  22. data/app/components/uchi/field/image/show.html.erb +2 -1
  23. data/app/components/uchi/field/number/edit.html.erb +1 -1
  24. data/app/components/uchi/field/string/edit.html.erb +1 -1
  25. data/app/components/uchi/field/text/edit.html.erb +1 -1
  26. data/app/components/{flowbite → uchi/flowbite}/breadcrumb.rb +5 -5
  27. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_home.rb +2 -2
  28. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/current.rb +3 -3
  29. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/first.rb +4 -4
  30. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item.rb +4 -4
  31. data/app/components/{flowbite → uchi/flowbite}/breadcrumb_separator.rb +7 -5
  32. data/app/components/uchi/flowbite/button/outline.rb +37 -0
  33. data/app/components/uchi/flowbite/button/pill.rb +40 -0
  34. data/app/components/uchi/flowbite/button.rb +93 -0
  35. data/app/components/uchi/flowbite/card/card.html.erb +7 -0
  36. data/app/components/uchi/flowbite/card/title.rb +37 -0
  37. data/app/components/uchi/flowbite/card.rb +84 -0
  38. data/app/components/{flowbite → uchi/flowbite}/input/checkbox.rb +7 -7
  39. data/app/components/{flowbite → uchi/flowbite}/input/date.rb +1 -1
  40. data/app/components/{flowbite → uchi/flowbite}/input/date_time.rb +1 -1
  41. data/app/components/{flowbite → uchi/flowbite}/input/email.rb +1 -1
  42. data/app/components/{flowbite → uchi/flowbite}/input/field.rb +11 -10
  43. data/app/components/uchi/flowbite/input/file.rb +30 -0
  44. data/app/components/{flowbite → uchi/flowbite}/input/hint.rb +6 -5
  45. data/app/components/{flowbite → uchi/flowbite}/input/label.rb +8 -7
  46. data/app/components/{flowbite → uchi/flowbite}/input/number.rb +1 -1
  47. data/app/components/{flowbite → uchi/flowbite}/input/password.rb +1 -1
  48. data/app/components/{flowbite → uchi/flowbite}/input/phone.rb +1 -1
  49. data/app/components/{flowbite → uchi/flowbite}/input/radio_button.rb +7 -7
  50. data/app/components/{flowbite → uchi/flowbite}/input/select.rb +16 -7
  51. data/app/components/uchi/flowbite/input/textarea.rb +42 -0
  52. data/app/components/{flowbite → uchi/flowbite}/input/url.rb +1 -1
  53. data/app/components/uchi/flowbite/input/validation_error.rb +39 -0
  54. data/app/components/uchi/flowbite/input_field/checkbox.html.erb +9 -0
  55. data/app/components/{flowbite → uchi/flowbite}/input_field/checkbox.rb +10 -6
  56. data/app/components/{flowbite → uchi/flowbite}/input_field/date.rb +2 -2
  57. data/app/components/{flowbite → uchi/flowbite}/input_field/date_time.rb +2 -2
  58. data/app/components/{flowbite → uchi/flowbite}/input_field/email.rb +2 -2
  59. data/app/components/{flowbite → uchi/flowbite}/input_field/file.rb +2 -2
  60. data/app/components/uchi/flowbite/input_field/input_field.html.erb +9 -0
  61. data/app/components/{flowbite → uchi/flowbite}/input_field/number.rb +2 -2
  62. data/app/components/{flowbite → uchi/flowbite}/input_field/password.rb +2 -2
  63. data/app/components/{flowbite → uchi/flowbite}/input_field/phone.rb +2 -2
  64. data/app/components/uchi/flowbite/input_field/radio_button.html.erb +9 -0
  65. data/app/components/{flowbite → uchi/flowbite}/input_field/radio_button.rb +13 -9
  66. data/app/components/{flowbite → uchi/flowbite}/input_field/select.rb +7 -3
  67. data/app/components/{flowbite → uchi/flowbite}/input_field/text.rb +1 -1
  68. data/app/components/{flowbite → uchi/flowbite}/input_field/textarea.rb +2 -2
  69. data/app/components/{flowbite → uchi/flowbite}/input_field/url.rb +2 -2
  70. data/app/components/{flowbite → uchi/flowbite}/input_field.rb +19 -5
  71. data/app/components/uchi/flowbite/link.rb +41 -0
  72. data/app/components/{flowbite → uchi/flowbite}/style.rb +1 -1
  73. data/app/components/{flowbite → uchi/flowbite}/toast/icon.rb +1 -1
  74. data/app/components/uchi/flowbite/toast/toast.html.erb +40 -0
  75. data/app/components/{flowbite → uchi/flowbite}/toast.rb +2 -2
  76. data/app/components/uchi/ui/actions/dropdown/dropdown.html.erb +59 -0
  77. data/app/components/uchi/ui/actions/dropdown.rb +32 -0
  78. data/app/components/uchi/ui/breadcrumb/breadcrumb.html.erb +4 -4
  79. data/app/components/uchi/ui/form/input/collection_checkboxes.html.erb +2 -1
  80. data/app/components/uchi/ui/form/input/collection_checkboxes.rb +12 -17
  81. data/app/components/uchi/ui/frame/frame.html.erb +6 -1
  82. data/app/components/uchi/ui/index/records_table/records_table.html.erb +109 -18
  83. data/app/components/uchi/ui/index/records_table/search_form/search_form.html.erb +21 -5
  84. data/app/components/uchi/ui/navigation/navigation.html.erb +9 -0
  85. data/app/components/uchi/ui/navigation.rb +37 -0
  86. data/app/components/uchi/ui/no_value/no_value.html.erb +1 -0
  87. data/app/components/uchi/ui/no_value.rb +8 -0
  88. data/app/components/uchi/ui/page_header/page_header.html.erb +7 -2
  89. data/app/components/uchi/ui/pagination/current_link.html.erb +1 -1
  90. data/app/components/uchi/ui/pagination/gap.html.erb +7 -1
  91. data/app/components/uchi/ui/pagination/link.html.erb +1 -1
  92. data/app/components/uchi/ui/pagination/next_link.html.erb +18 -3
  93. data/app/components/uchi/ui/pagination/pagination.html.erb +3 -1
  94. data/app/components/uchi/ui/pagination/previous_link.html.erb +18 -3
  95. data/app/components/uchi/ui/pagination.rb +1 -1
  96. data/app/components/uchi/ui/show/attribute_fields/attribute_fields.html.erb +4 -3
  97. data/app/components/uchi/ui/spinner/spinner.html.erb +17 -3
  98. data/app/controllers/uchi/actions/executions_controller.rb +107 -0
  99. data/app/controllers/uchi/repository_controller.rb +21 -1
  100. data/app/views/layouts/uchi/_flash_messages.html.erb +1 -1
  101. data/app/views/layouts/uchi/application.html.erb +10 -16
  102. data/app/views/uchi/navigation/_main.html.erb +9 -0
  103. data/app/views/uchi/repository/edit.html.erb +2 -2
  104. data/app/views/uchi/repository/index.html.erb +12 -3
  105. data/app/views/uchi/repository/new.html.erb +2 -2
  106. data/app/views/uchi/repository/show.html.erb +13 -2
  107. data/lib/generators/uchi/controller/templates/controller.rb.tt +0 -5
  108. data/lib/generators/uchi/scaffold/scaffold_generator.rb +15 -0
  109. data/lib/uchi/action.rb +84 -0
  110. data/lib/uchi/action_response.rb +108 -0
  111. data/lib/uchi/repository/translate.rb +14 -0
  112. data/lib/uchi/repository.rb +25 -0
  113. data/lib/uchi/version.rb +1 -1
  114. data/lib/uchi.rb +2 -0
  115. metadata +63 -50
  116. data/app/components/flowbite/button/outline.rb +0 -22
  117. data/app/components/flowbite/button/pill.rb +0 -40
  118. data/app/components/flowbite/button.rb +0 -92
  119. data/app/components/flowbite/card.rb +0 -45
  120. data/app/components/flowbite/input/file.rb +0 -30
  121. data/app/components/flowbite/input/textarea.rb +0 -42
  122. data/app/components/flowbite/input/validation_error.rb +0 -11
  123. data/app/components/flowbite/input_field/checkbox.html.erb +0 -14
  124. data/app/components/flowbite/input_field/input_field.html.erb +0 -8
  125. data/app/components/flowbite/input_field/radio_button.html.erb +0 -14
  126. data/app/components/flowbite/link.rb +0 -21
  127. data/app/components/flowbite/toast/toast.html.erb +0 -11
  128. /data/app/components/{flowbite → uchi/flowbite}/toast/icon.html.erb +0 -0
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Number < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::Number
9
+ Uchi::Flowbite::Input::Number
10
10
  end
11
11
  end
12
12
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Password < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::Password
9
+ Uchi::Flowbite::Input::Password
10
10
  end
11
11
  end
12
12
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Phone < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::Phone
9
+ Uchi::Flowbite::Input::Phone
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,9 @@
1
+ <div class="<%= classes.join(" ") %>">
2
+ <div class="flex items-center h-5"><%= input %></div>
3
+
4
+ <div class="ms-2 text-sm"><%= label %><%= hint %></div>
5
+
6
+ <% errors.each do |error| %>
7
+ <%= render(Uchi::Flowbite::Input::ValidationError.new) { error.upcase_first } %>
8
+ <% end %>
9
+ </div>
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class RadioButton < InputField
6
- def initialize(attribute:, form:, value:, disabled: false, hint: nil, input: {}, label: {})
7
- super(attribute: attribute, form: form, disabled: disabled, hint: hint, input: input, label: label)
6
+ def initialize(attribute:, form:, value:, class: nil, disabled: false, hint: nil, input: {}, label: {}, options: {})
7
+ super(attribute: attribute, class: binding.local_variable_get(:class), form: form, disabled: disabled, hint: hint, input: input, label: label, options: options)
8
8
  @value = value
9
9
  end
10
10
 
11
11
  protected
12
12
 
13
+ def default_container_classes
14
+ ["flex"]
15
+ end
16
+
13
17
  def default_input
14
18
  args = {
15
19
  attribute: @attribute,
@@ -37,7 +41,7 @@ module Flowbite
37
41
  def hint
38
42
  return unless hint?
39
43
 
40
- component = Flowbite::Input::Hint.new(
44
+ component = Uchi::Flowbite::Input::Hint.new(
41
45
  attribute: @attribute,
42
46
  form: @form,
43
47
  options: {
@@ -49,16 +53,16 @@ module Flowbite
49
53
  end
50
54
 
51
55
  def input_component
52
- ::Flowbite::Input::RadioButton
56
+ Uchi::Flowbite::Input::RadioButton
53
57
  end
54
58
 
55
59
  private
56
60
 
57
61
  def hint_classes
58
62
  if disabled?
59
- "text-xs font-normal text-gray-400 dark:text-gray-500"
63
+ "text-xs font-normal text-fg-disabled"
60
64
  else
61
- "text-xs font-normal text-gray-500 dark:text-gray-300"
65
+ "text-xs font-normal text-body"
62
66
  end
63
67
  end
64
68
 
@@ -76,9 +80,9 @@ module Flowbite
76
80
 
77
81
  def label_classes
78
82
  if disabled?
79
- "font-medium text-gray-400 dark:text-gray-500"
83
+ "font-medium text-fg-disabled"
80
84
  else
81
- "font-medium text-gray-900 dark:text-gray-300"
85
+ "font-medium text-heading"
82
86
  end
83
87
  end
84
88
  end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Select < InputField
6
- def initialize(attribute:, form:, collection: [], disabled: false, hint: nil, input: {}, label: {}, size: :default)
6
+ def initialize(attribute:, form:, collection: [], disabled: false, hint: nil, include_blank: false, input: {}, label: {}, multiple: false, size: :default)
7
7
  super(attribute: attribute, disabled: disabled, form: form, hint: hint, input: input, label: label, size: size)
8
8
  @collection = collection
9
+ @include_blank = include_blank
10
+ @multiple = multiple
9
11
  end
10
12
 
11
13
  def input
@@ -15,6 +17,8 @@ module Flowbite
15
17
  collection: @collection,
16
18
  disabled: @disabled,
17
19
  form: @form,
20
+ include_blank: @include_blank,
21
+ multiple: @multiple,
18
22
  options: input_options,
19
23
  size: @size
20
24
  )
@@ -24,7 +28,7 @@ module Flowbite
24
28
  private
25
29
 
26
30
  def input_component
27
- ::Flowbite::Input::Select
31
+ Uchi::Flowbite::Input::Select
28
32
  end
29
33
  end
30
34
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Text < InputField
6
6
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Textarea < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::Textarea
9
+ Uchi::Flowbite::Input::Textarea
10
10
  end
11
11
  end
12
12
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class InputField
5
5
  class Url < InputField
6
6
  protected
7
7
 
8
8
  def input_component
9
- ::Flowbite::Input::Url
9
+ Uchi::Flowbite::Input::Url
10
10
  end
11
11
  end
12
12
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  # A form element for a single field, containing label, input field, error
5
5
  # messages, helper text and whatever else is needed for a user friendly input
6
6
  # experience.
@@ -71,28 +71,42 @@ module Flowbite
71
71
  @object.errors[@attribute] || []
72
72
  end
73
73
 
74
- def initialize(attribute:, form:, disabled: false, hint: nil, input: {}, label: {}, size: :default)
74
+ def initialize(attribute:, form:, class: nil, disabled: false, hint: nil, input: {}, label: {}, options: {}, size: :default)
75
75
  @attribute = attribute
76
+ @class = Array.wrap(binding.local_variable_get(:class))
76
77
  @disabled = disabled
77
78
  @form = form
78
79
  @hint = hint
79
80
  @input = input
80
81
  @label = label
81
82
  @object = form.object
83
+ @options = options || {}
82
84
  @size = size
83
85
  end
84
86
 
85
87
  def input_component
86
- ::Flowbite::Input::Field
88
+ Uchi::Flowbite::Input::Field
87
89
  end
88
90
 
89
91
  protected
90
92
 
93
+ def classes
94
+ if @options[:class]
95
+ Array.wrap(@options[:class])
96
+ else
97
+ [default_container_classes, @class].flatten.compact
98
+ end
99
+ end
100
+
101
+ def default_container_classes
102
+ []
103
+ end
104
+
91
105
  # Returns the HTML to use for the hint element if any
92
106
  def default_hint
93
107
  return unless hint?
94
108
 
95
- component = Flowbite::Input::Hint.new(
109
+ component = Uchi::Flowbite::Input::Hint.new(
96
110
  attribute: @attribute,
97
111
  form: @form,
98
112
  options: default_hint_options
@@ -138,7 +152,7 @@ module Flowbite
138
152
  end
139
153
 
140
154
  def default_label
141
- component = Flowbite::Input::Label.new(**default_label_options)
155
+ component = Uchi::Flowbite::Input::Label.new(**default_label_options)
142
156
  if default_label_content
143
157
  component.with_content(default_label_content)
144
158
  else
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uchi::Flowbite
4
+ # The link component can be used to set hyperlinks from one page to another or
5
+ # to an external website when clicking on an inline text item, button, or card
6
+ #
7
+ # Use this component to add default styles to an inline link element.
8
+ class Link < ViewComponent::Base
9
+ attr_reader :href, :options
10
+
11
+ class << self
12
+ def classes
13
+ ["font-medium", "text-fg-brand", "hover:underline"]
14
+ end
15
+ end
16
+
17
+ # Initialize the Link component.
18
+ #
19
+ # @param href What to link to. This can be a String or anything else that
20
+ # `link_to` supports. See `ActionView::Helpers::UrlHelper#link_to` for more
21
+ # details.
22
+ #
23
+ # @param options [Hash] Additional HTML options for the link element
24
+ def initialize(href:, class: nil, **options)
25
+ super()
26
+ @class = Array.wrap(binding.local_variable_get(:class))
27
+ @href = href
28
+ @options = options
29
+ end
30
+
31
+ def call
32
+ link_to(content, href, {class: classes}.merge(options))
33
+ end
34
+
35
+ private
36
+
37
+ def classes
38
+ self.class.classes + @class
39
+ end
40
+ end
41
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class Style
5
5
  attr_reader :classes
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  class Toast
5
5
  # Renders an icon for a toast notification.
6
6
  #
@@ -0,0 +1,40 @@
1
+ <div
2
+ class="<%= container_classes.join(" ") %>"
3
+ role="alert"
4
+ <%= options.map { |k, v| "#{k}=\"#{v}\"" }.join(" ").html_safe %>
5
+ >
6
+ <%= render Uchi::Flowbite::Toast::Icon.new(style: style) %>
7
+
8
+ <div class="ms-3 text-sm font-normal"><%= message %></div>
9
+
10
+ <% if dismissible %>
11
+ <%# Styles from https://flowbite.com/docs/components/toast/#default-toast %>
12
+ <button
13
+ type="button"
14
+ class="
15
+ ms-auto flex items-center justify-center text-body
16
+ hover:text-heading bg-transparent box-border border
17
+ border-transparent hover:bg-neutral-secondary-medium focus:ring-4
18
+ focus:ring-neutral-tertiary font-medium leading-5 rounded text-sm
19
+ h-8 w-8 focus:outline-none
20
+ "
21
+ aria-label="Close"
22
+ >
23
+ <svg
24
+ class="w-3 h-3"
25
+ aria-hidden="true"
26
+ xmlns="http://www.w3.org/2000/svg"
27
+ fill="none"
28
+ viewBox="0 0 14 14"
29
+ >
30
+ <path
31
+ stroke="currentColor"
32
+ stroke-linecap="round"
33
+ stroke-linejoin="round"
34
+ stroke-width="2"
35
+ d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
36
+ />
37
+ </svg>
38
+ </button>
39
+ <% end %>
40
+ </div>
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Flowbite
3
+ module Uchi::Flowbite
4
4
  # Renders a toast notification element.
5
5
  #
6
6
  # See https://flowbite.com/docs/components/toast/
@@ -13,7 +13,7 @@ module Flowbite
13
13
  class Toast < ViewComponent::Base
14
14
  class << self
15
15
  def classes
16
- ["flex", "items-center", "w-full", "max-w-xs", "p-4", "text-gray-500", "bg-white", "rounded-lg", "shadow-sm", "dark:text-gray-400", "dark:bg-gray-800"]
16
+ ["flex", "items-center", "w-full", "max-w-xs", "p-4", "text-body", "bg-neutral-primary-soft", "rounded-base", "shadow-xs", "border", "border-default"]
17
17
  end
18
18
  end
19
19
 
@@ -0,0 +1,59 @@
1
+ <div class="relative" data-controller="dropdown">
2
+ <%= render(Uchi::Flowbite::Button.new(style: :secondary, :data => {:action => "dropdown#toggle click@window->dropdown#hide"}, id: button_id)) do %>
3
+ <div class="inline-flex items-center">
4
+ <%= repository.translate.actions_button_label %>
5
+
6
+ <svg
7
+ class="w-4 h-4 ms-1.5 -me-0.5"
8
+ aria-hidden="true"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ width="24"
11
+ height="24"
12
+ fill="none"
13
+ viewBox="0 0 24 24"
14
+ >
15
+ <path
16
+ stroke="currentColor"
17
+ stroke-linecap="round"
18
+ stroke-linejoin="round"
19
+ stroke-width="2"
20
+ d="m19 9-7 7-7-7"
21
+ />
22
+ </svg>
23
+ </div>
24
+ <% end %>
25
+
26
+ <!-- Dropdown menu -->
27
+ <div
28
+ aria-orientation="vertical"
29
+ aria-hidden="true"
30
+ data-dropdown-target="menu"
31
+ class="
32
+ transition transform origin-top-right absolute z-10 hidden bg-neutral-primary-medium border border-default-medium
33
+ rounded-base shadow-lg w-44 mt-1 -ml-1/2
34
+ "
35
+ id="actions-dropdown-<%= record.id %>"
36
+ role="menu"
37
+ tabindex="-1"
38
+ >
39
+ <ul
40
+ class="p-2 text-sm text-body font-medium"
41
+ aria-labelledby="<%= button_id %>"
42
+ >
43
+ <% actions.each do |action| %>
44
+ <li role="menuitem">
45
+ <%= form_with url: helpers.actions_executions_path, method: :post, class: "block" do %>
46
+ <%= hidden_field_tag :model, repository.model.name %>
47
+ <%= hidden_field_tag :action_name, action.class.name %>
48
+ <%= hidden_field_tag :id, record.id %>
49
+
50
+ <%= button_tag type: "submit",
51
+ class: "block inline-flex items-center w-full p-2 hover:bg-neutral-tertiary-medium hover:text-heading rounded" do %>
52
+ <%= action.name %>
53
+ <% end %>
54
+ <% end %>
55
+ </li>
56
+ <% end %>
57
+ </ul>
58
+ </div>
59
+ </div>
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uchi
4
+ module Ui
5
+ module Actions
6
+ # Renders a dropdown menu of actions that can be performed on a record.
7
+ #
8
+ # This component displays available actions for a repository in a dropdown
9
+ # menu. Each action can be clicked to execute it on the specified record(s).
10
+ class Dropdown < ViewComponent::Base
11
+ attr_reader :actions, :record, :repository
12
+
13
+ def initialize(actions:, record:, repository:)
14
+ super()
15
+ @actions = actions
16
+ @record = record
17
+ @repository = repository
18
+ end
19
+
20
+ def render?
21
+ actions.any?
22
+ end
23
+
24
+ private
25
+
26
+ def button_id
27
+ "actions-dropdown-button-#{record.id}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,12 +1,12 @@
1
- <%= render(Flowbite::Breadcrumb.new) do |breadcrumb| %>
1
+ <%= render(Uchi::Flowbite::Breadcrumb.new) do |breadcrumb| %>
2
2
  <% items.each.with_index do |item, index| %>
3
3
  <% breadcrumb.with_item do %>
4
4
  <% if index.zero? %>
5
- <%= render Flowbite::BreadcrumbItem::First.new(href: item[:href]).with_content(item[:label]) %>
5
+ <%= render Uchi::Flowbite::BreadcrumbItem::First.new(href: item[:href]).with_content(item[:label]) %>
6
6
  <% elsif index == items.size - 1 %>
7
- <%= render Flowbite::BreadcrumbItem::Current.new.with_content(item[:label]) %>
7
+ <%= render Uchi::Flowbite::BreadcrumbItem::Current.new.with_content(item[:label]) %>
8
8
  <% else %>
9
- <%= render Flowbite::BreadcrumbItem.new(href: item[:href]).with_content(item[:label]) %>
9
+ <%= render Uchi::Flowbite::BreadcrumbItem.new(href: item[:href]).with_content(item[:label]) %>
10
10
  <% end %>
11
11
  <% end %>
12
12
  <% end %>
@@ -15,6 +15,7 @@
15
15
  <div class="flex items-center h-5">
16
16
  <%= b.check_box(class: checkbox_classes.join(" "), disabled: disabled?) %>
17
17
  </div>
18
+
18
19
  <div class="ms-2 text-sm">
19
20
  <%= b.label(class: checkbox_label_classes.join(" ")) %>
20
21
  </div>
@@ -27,6 +28,6 @@
27
28
  <% end %>
28
29
 
29
30
  <% errors.each do |error| %>
30
- <%= render(Flowbite::Input::ValidationError.new) { error.upcase_first } %>
31
+ <%= render(Uchi::Flowbite::Input::ValidationError.new) { error.upcase_first } %>
31
32
  <% end %>
32
33
  </div>
@@ -68,22 +68,22 @@ module Uchi
68
68
  end
69
69
 
70
70
  def label_classes
71
- base = ["block", "mb-2", "text-sm", "font-medium"]
71
+ base = ["select-none ms-2 text-sm font-medium"]
72
72
  if disabled?
73
- base + ["text-gray-400", "dark:text-gray-500"]
73
+ base + ["text-fg-disabled"]
74
74
  elsif errors?
75
- base + ["text-red-700", "dark:text-red-500"]
75
+ base + ["text-fg-danger-strong"]
76
76
  else
77
- base + ["text-gray-900", "dark:text-white"]
77
+ base + ["text-heading"]
78
78
  end
79
79
  end
80
80
 
81
81
  def hint_classes
82
82
  base = ["text-xs", "font-normal", "mt-1"]
83
83
  if disabled?
84
- base + ["text-gray-400", "dark:text-gray-500"]
84
+ base + ["text-fg-disabled"]
85
85
  else
86
- base + ["text-gray-500", "dark:text-gray-300"]
86
+ base + ["text-body"]
87
87
  end
88
88
  end
89
89
 
@@ -92,26 +92,21 @@ module Uchi
92
92
  end
93
93
 
94
94
  def checkbox_classes
95
- base = ["w-4", "h-4", "rounded-sm", "focus:ring-2", "focus:ring-offset-2"]
95
+ base = ["w-4", "h-4", "border", "rounded-xs", "focus:ring-2"]
96
96
  if disabled?
97
- base + ["text-blue-600", "bg-gray-100", "border-gray-300",
98
- "dark:bg-gray-700", "dark:border-gray-600"]
97
+ base + ["border-light", "bg-neutral-secondary-medium", "focus:ring-brand-soft"]
99
98
  elsif errors?
100
- base + ["text-red-600", "bg-red-50", "border-red-500",
101
- "focus:ring-red-500", "dark:focus:ring-red-600",
102
- "dark:bg-gray-700", "dark:border-red-500"]
99
+ base + ["text-fg-danger", "bg-danger-soft", "border-fg-danger", "focus:ring-fg-danger"]
103
100
  else
104
- base + ["text-blue-600", "bg-gray-100", "border-gray-300",
105
- "focus:ring-blue-500", "dark:focus:ring-blue-600",
106
- "dark:bg-gray-700", "dark:border-gray-600"]
101
+ base + ["border-default-medium", "bg-neutral-secondary-medium", "focus:ring-brand-soft"]
107
102
  end
108
103
  end
109
104
 
110
105
  def checkbox_label_classes
111
106
  if disabled?
112
- ["ms-2", "text-sm", "font-medium", "text-gray-400", "dark:text-gray-500"]
107
+ ["select-none", "ms-2", "text-sm", "font-medium", "text-fg-disabled"]
113
108
  else
114
- ["ms-2", "text-sm", "font-medium", "text-gray-900", "dark:text-gray-300"]
109
+ ["select-none", "ms-2", "text-sm", "font-medium", "text-heading"]
115
110
  end
116
111
  end
117
112
 
@@ -1,3 +1,8 @@
1
- <div class="bg-white border border-gray-200 shadow-sm md:rounded-lg dark:bg-gray-800 dark:border-gray-700">
1
+ <div
2
+ class="
3
+ relative overflow-x-auto bg-neutral-primary-soft shadow-xs rounded-base
4
+ border border-default
5
+ "
6
+ >
2
7
  <%= content %>
3
8
  </div>