uchi 0.1.5 → 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/README.md +7 -0
- data/app/assets/javascripts/controllers/fields/belongs_to_controller.js +130 -0
- data/app/assets/javascripts/controllers/fields/has_many_controller.js +146 -0
- data/app/assets/javascripts/uchi/application.js +3456 -24
- data/app/assets/javascripts/uchi.js +20 -0
- data/app/assets/stylesheets/uchi/application.css +676 -2473
- data/app/assets/tailwind/uchi.css +6 -6
- data/app/components/uchi/field/belongs_to/edit.html.erb +73 -1
- data/app/components/uchi/field/belongs_to/index.html.erb +1 -1
- data/app/components/uchi/field/belongs_to/show.html.erb +3 -5
- data/app/components/uchi/field/belongs_to.rb +53 -30
- data/app/components/uchi/field/boolean/edit.html.erb +1 -1
- data/app/components/uchi/field/date/edit.html.erb +1 -1
- data/app/components/uchi/field/date_time/edit.html.erb +1 -1
- data/app/components/uchi/field/file/edit.html.erb +1 -1
- data/app/components/uchi/field/file/index.html.erb +2 -1
- data/app/components/uchi/field/file/show.html.erb +3 -2
- data/app/components/uchi/field/has_and_belongs_to_many/show.html.erb +6 -4
- data/app/components/uchi/field/has_many/edit.html.erb +86 -1
- data/app/components/uchi/field/has_many/show.html.erb +6 -4
- data/app/components/uchi/field/has_many.rb +59 -11
- data/app/components/uchi/field/id/index.html.erb +1 -1
- data/app/components/uchi/field/id/show.html.erb +1 -1
- data/app/components/uchi/field/image/edit.html.erb +1 -1
- data/app/components/uchi/field/image/index.html.erb +2 -1
- data/app/components/uchi/field/image/show.html.erb +2 -1
- data/app/components/uchi/field/number/edit.html.erb +1 -1
- data/app/components/uchi/field/string/edit.html.erb +1 -1
- data/app/components/uchi/field/text/edit.html.erb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb.rb +5 -5
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_home.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/current.rb +3 -3
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item/first.rb +4 -4
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_item.rb +4 -4
- data/app/components/{flowbite → uchi/flowbite}/breadcrumb_separator.rb +7 -5
- data/app/components/uchi/flowbite/button/outline.rb +37 -0
- data/app/components/uchi/flowbite/button/pill.rb +40 -0
- data/app/components/uchi/flowbite/button.rb +93 -0
- data/app/components/uchi/flowbite/card/card.html.erb +7 -0
- data/app/components/uchi/flowbite/card/title.rb +37 -0
- data/app/components/uchi/flowbite/card.rb +84 -0
- data/app/components/{flowbite → uchi/flowbite}/input/checkbox.rb +7 -7
- data/app/components/{flowbite → uchi/flowbite}/input/date.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/date_time.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/email.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/field.rb +11 -10
- data/app/components/uchi/flowbite/input/file.rb +30 -0
- data/app/components/{flowbite → uchi/flowbite}/input/hint.rb +6 -5
- data/app/components/{flowbite → uchi/flowbite}/input/label.rb +8 -7
- data/app/components/{flowbite → uchi/flowbite}/input/number.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/password.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/phone.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input/radio_button.rb +7 -7
- data/app/components/{flowbite → uchi/flowbite}/input/select.rb +16 -7
- data/app/components/uchi/flowbite/input/textarea.rb +42 -0
- data/app/components/{flowbite → uchi/flowbite}/input/url.rb +1 -1
- data/app/components/uchi/flowbite/input/validation_error.rb +39 -0
- data/app/components/uchi/flowbite/input_field/checkbox.html.erb +9 -0
- data/app/components/{flowbite → uchi/flowbite}/input_field/checkbox.rb +10 -6
- data/app/components/{flowbite → uchi/flowbite}/input_field/date.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/date_time.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/email.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/file.rb +2 -2
- data/app/components/uchi/flowbite/input_field/input_field.html.erb +9 -0
- data/app/components/{flowbite → uchi/flowbite}/input_field/number.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/password.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/phone.rb +2 -2
- data/app/components/uchi/flowbite/input_field/radio_button.html.erb +9 -0
- data/app/components/{flowbite → uchi/flowbite}/input_field/radio_button.rb +13 -9
- data/app/components/{flowbite → uchi/flowbite}/input_field/select.rb +7 -3
- data/app/components/{flowbite → uchi/flowbite}/input_field/text.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/input_field/textarea.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field/url.rb +2 -2
- data/app/components/{flowbite → uchi/flowbite}/input_field.rb +19 -5
- data/app/components/uchi/flowbite/link.rb +41 -0
- data/app/components/{flowbite → uchi/flowbite}/style.rb +1 -1
- data/app/components/{flowbite → uchi/flowbite}/toast/icon.rb +1 -1
- data/app/components/uchi/flowbite/toast/toast.html.erb +40 -0
- data/app/components/{flowbite → uchi/flowbite}/toast.rb +2 -2
- data/app/components/uchi/ui/actions/dropdown/dropdown.html.erb +59 -0
- data/app/components/uchi/ui/actions/dropdown.rb +32 -0
- data/app/components/uchi/ui/breadcrumb/breadcrumb.html.erb +4 -4
- data/app/components/uchi/ui/form/input/collection_checkboxes.html.erb +2 -1
- data/app/components/uchi/ui/form/input/collection_checkboxes.rb +12 -17
- data/app/components/uchi/ui/frame/frame.html.erb +6 -1
- data/app/components/uchi/ui/index/records_table/records_table.html.erb +109 -18
- data/app/components/uchi/ui/index/records_table/search_form/search_form.html.erb +21 -5
- data/app/components/uchi/ui/navigation/navigation.html.erb +9 -0
- data/app/components/uchi/ui/navigation.rb +37 -0
- data/app/components/uchi/ui/no_value/no_value.html.erb +1 -0
- data/app/components/uchi/ui/no_value.rb +8 -0
- data/app/components/uchi/ui/page_header/page_header.html.erb +13 -8
- data/app/components/uchi/ui/pagination/current_link.html.erb +1 -1
- data/app/components/uchi/ui/pagination/gap.html.erb +7 -1
- data/app/components/uchi/ui/pagination/link.html.erb +1 -1
- data/app/components/uchi/ui/pagination/next_link.html.erb +18 -3
- data/app/components/uchi/ui/pagination/pagination.html.erb +3 -1
- data/app/components/uchi/ui/pagination/previous_link.html.erb +18 -3
- data/app/components/uchi/ui/pagination.rb +1 -1
- data/app/components/uchi/ui/show/attribute_fields/attribute_fields.html.erb +4 -3
- data/app/components/uchi/ui/spinner/spinner.html.erb +17 -3
- data/app/controllers/uchi/actions/executions_controller.rb +107 -0
- data/app/controllers/uchi/belongs_to/associated_records_controller.rb +89 -0
- data/app/controllers/uchi/has_many/associated_records_controller.rb +89 -0
- data/app/controllers/uchi/repository_controller.rb +21 -1
- data/app/views/layouts/uchi/_flash_messages.html.erb +1 -1
- data/app/views/layouts/uchi/_javascript.html.erb +1 -0
- data/app/views/layouts/uchi/_stylesheets.html.erb +1 -0
- data/app/views/layouts/uchi/application.html.erb +13 -19
- data/app/views/uchi/belongs_to/associated_records/index.html.erb +13 -0
- data/app/views/uchi/has_many/associated_records/index.html.erb +26 -0
- data/app/views/uchi/navigation/_main.html.erb +92 -0
- data/app/views/uchi/repository/edit.html.erb +2 -2
- data/app/views/uchi/repository/index.html.erb +12 -3
- data/app/views/uchi/repository/new.html.erb +2 -2
- data/app/views/uchi/repository/show.html.erb +13 -2
- data/lib/generators/uchi/controller/controller_generator.rb +0 -4
- data/lib/generators/uchi/controller/templates/controller.rb.tt +0 -5
- data/lib/generators/uchi/install/install_generator.rb +1 -1
- data/lib/generators/uchi/scaffold/scaffold_generator.rb +15 -0
- data/lib/uchi/action.rb +84 -0
- data/lib/uchi/action_response.rb +108 -0
- data/lib/uchi/field/configuration.rb +1 -1
- data/lib/uchi/repository/translate.rb +14 -0
- data/lib/uchi/repository.rb +38 -2
- data/lib/uchi/routes.rb +45 -0
- data/lib/uchi/version.rb +1 -1
- data/lib/uchi.rb +6 -1
- metadata +72 -50
- data/app/components/flowbite/button/outline.rb +0 -22
- data/app/components/flowbite/button/pill.rb +0 -40
- data/app/components/flowbite/button.rb +0 -92
- data/app/components/flowbite/card.rb +0 -45
- data/app/components/flowbite/input/file.rb +0 -30
- data/app/components/flowbite/input/textarea.rb +0 -42
- data/app/components/flowbite/input/validation_error.rb +0 -11
- data/app/components/flowbite/input_field/checkbox.html.erb +0 -14
- data/app/components/flowbite/input_field/input_field.html.erb +0 -8
- data/app/components/flowbite/input_field/radio_button.html.erb +0 -14
- data/app/components/flowbite/link.rb +0 -21
- data/app/components/flowbite/toast/toast.html.erb +0 -11
- /data/app/components/{flowbite → uchi/flowbite}/toast/icon.html.erb +0 -0
|
@@ -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-
|
|
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 = ["
|
|
71
|
+
base = ["select-none ms-2 text-sm font-medium"]
|
|
72
72
|
if disabled?
|
|
73
|
-
base + ["text-
|
|
73
|
+
base + ["text-fg-disabled"]
|
|
74
74
|
elsif errors?
|
|
75
|
-
base + ["text-
|
|
75
|
+
base + ["text-fg-danger-strong"]
|
|
76
76
|
else
|
|
77
|
-
base + ["text-
|
|
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-
|
|
84
|
+
base + ["text-fg-disabled"]
|
|
85
85
|
else
|
|
86
|
-
base + ["text-
|
|
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", "
|
|
95
|
+
base = ["w-4", "h-4", "border", "rounded-xs", "focus:ring-2"]
|
|
96
96
|
if disabled?
|
|
97
|
-
base + ["
|
|
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-
|
|
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 + ["
|
|
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-
|
|
107
|
+
["select-none", "ms-2", "text-sm", "font-medium", "text-fg-disabled"]
|
|
113
108
|
else
|
|
114
|
-
["ms-2", "text-sm", "font-medium", "text-
|
|
109
|
+
["select-none", "ms-2", "text-sm", "font-medium", "text-heading"]
|
|
115
110
|
end
|
|
116
111
|
end
|
|
117
112
|
|
|
@@ -1,31 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
<%# Styles from https://flowbite.com/docs/components/tables/#default-table %>
|
|
2
|
+
<table class="w-full text-sm text-left text-body rtl:text-right">
|
|
3
|
+
<thead
|
|
4
|
+
class="
|
|
5
|
+
text-sm text-body bg-neutral-secondary-soft border-b rounded-base
|
|
6
|
+
border-default
|
|
7
|
+
"
|
|
8
|
+
>
|
|
3
9
|
<tr>
|
|
4
10
|
<% columns.each do |field| %>
|
|
5
11
|
<% component_class = field.index_component_class %>
|
|
6
|
-
|
|
12
|
+
|
|
13
|
+
<th
|
|
14
|
+
scope="col"
|
|
15
|
+
class="px-6 py-3 font-medium whitespace-nowrap <%= component_class.classes_for_table_cell.join(" ") %>"
|
|
16
|
+
>
|
|
7
17
|
<% if field.sortable? %>
|
|
8
18
|
<% if field.name == sort_order&.name %>
|
|
9
19
|
<% if sort_order&.ascending? %>
|
|
10
20
|
<%= link_to(repository.routes.path_for(:index, query: query, scope: scope, sort: {:by => field.name, :direction => :desc})) do %>
|
|
11
21
|
<%= repository.translate.field_label(field) %>
|
|
12
|
-
|
|
13
|
-
|
|
22
|
+
|
|
23
|
+
<svg
|
|
24
|
+
class="inline w-4 h-4 text-heading"
|
|
25
|
+
aria-hidden="true"
|
|
26
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
27
|
+
width="24"
|
|
28
|
+
height="24"
|
|
29
|
+
fill="none"
|
|
30
|
+
viewBox="0 0 24 24"
|
|
31
|
+
>
|
|
32
|
+
<path
|
|
33
|
+
stroke="currentColor"
|
|
34
|
+
stroke-linecap="round"
|
|
35
|
+
stroke-linejoin="round"
|
|
36
|
+
stroke-width="2"
|
|
37
|
+
d="M12 19V5m0 14-4-4m4 4 4-4"
|
|
38
|
+
/>
|
|
14
39
|
</svg>
|
|
15
40
|
<% end %>
|
|
16
41
|
<% else %>
|
|
17
42
|
<%= link_to(repository.routes.path_for(:index, query: query, scope: scope, sort: {:by => field.name, :direction => :asc})) do %>
|
|
18
43
|
<%= repository.translate.field_label(field) %>
|
|
19
|
-
|
|
20
|
-
|
|
44
|
+
|
|
45
|
+
<svg
|
|
46
|
+
class="inline w-4 h-4 text-heading"
|
|
47
|
+
aria-hidden="true"
|
|
48
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
49
|
+
width="24"
|
|
50
|
+
height="24"
|
|
51
|
+
fill="none"
|
|
52
|
+
viewBox="0 0 24 24"
|
|
53
|
+
>
|
|
54
|
+
<path
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
stroke-linecap="round"
|
|
57
|
+
stroke-linejoin="round"
|
|
58
|
+
stroke-width="2"
|
|
59
|
+
d="M12 6v13m0-13 4 4m-4-4-4 4"
|
|
60
|
+
/>
|
|
21
61
|
</svg>
|
|
22
62
|
<% end %>
|
|
23
63
|
<% end %>
|
|
24
64
|
<% else %>
|
|
25
65
|
<%= link_to(repository.routes.path_for(:index, query: query, scope: scope, sort: {:by => field.name, :direction => :asc})) do %>
|
|
26
66
|
<%= repository.translate.field_label(field) %>
|
|
27
|
-
|
|
28
|
-
|
|
67
|
+
|
|
68
|
+
<svg
|
|
69
|
+
class="inline w-4 h-4 text-heading"
|
|
70
|
+
aria-hidden="true"
|
|
71
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
72
|
+
width="24"
|
|
73
|
+
height="24"
|
|
74
|
+
fill="none"
|
|
75
|
+
viewBox="0 0 24 24"
|
|
76
|
+
>
|
|
77
|
+
<path
|
|
78
|
+
stroke="currentColor"
|
|
79
|
+
stroke-linecap="round"
|
|
80
|
+
stroke-linejoin="round"
|
|
81
|
+
stroke-width="2"
|
|
82
|
+
d="M8 20V7m0 13-4-4m4 4 4-4m4-12v13m0-13 4 4m-4-4-4 4"
|
|
83
|
+
/>
|
|
29
84
|
</svg>
|
|
30
85
|
<% end %>
|
|
31
86
|
<% end %>
|
|
@@ -34,29 +89,65 @@
|
|
|
34
89
|
<% end %>
|
|
35
90
|
</th>
|
|
36
91
|
<% end %>
|
|
37
|
-
|
|
92
|
+
|
|
93
|
+
<th scope="col" class="px-6 py-3"></th>
|
|
38
94
|
</tr>
|
|
39
95
|
</thead>
|
|
96
|
+
|
|
40
97
|
<tbody>
|
|
41
98
|
<% records.each do |record| %>
|
|
42
|
-
<tr class="bg-
|
|
99
|
+
<tr class="bg-neutral-primary border-b border-default">
|
|
43
100
|
<% columns.each do |field| %>
|
|
44
101
|
<% component_class = field.index_component_class %>
|
|
45
|
-
|
|
102
|
+
|
|
103
|
+
<td class="px-6 py-4 <%= component_class.classes_for_table_cell.join(" ") %>">
|
|
46
104
|
<%= render(field.index_component(record: record, repository: repository)) %>
|
|
47
105
|
</td>
|
|
48
106
|
<% end %>
|
|
49
|
-
|
|
107
|
+
|
|
108
|
+
<td class="px-6 py-4 text-right">
|
|
50
109
|
<div class="flex justify-end space-x-2">
|
|
51
110
|
<%= link_to(repository.routes.path_for(:show, id: record.id), class: "inline-block hover:text-blue-600 hover:dark:text-blue-500", :data => {:"turbo-frame" => "_top"}) do %>
|
|
52
|
-
<svg
|
|
53
|
-
|
|
54
|
-
|
|
111
|
+
<svg
|
|
112
|
+
class="w-6 h-6"
|
|
113
|
+
aria-hidden="true"
|
|
114
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
115
|
+
width="24"
|
|
116
|
+
height="24"
|
|
117
|
+
fill="none"
|
|
118
|
+
viewBox="0 0 24 24"
|
|
119
|
+
>
|
|
120
|
+
<path
|
|
121
|
+
stroke="currentColor"
|
|
122
|
+
stroke-width="2"
|
|
123
|
+
d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
<path
|
|
127
|
+
stroke="currentColor"
|
|
128
|
+
stroke-width="2"
|
|
129
|
+
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
|
130
|
+
/>
|
|
55
131
|
</svg>
|
|
56
132
|
<% end %>
|
|
133
|
+
|
|
57
134
|
<%= link_to(path_for_edit(record), class: "inline-block hover:text-blue-600 hover:dark:text-blue-500", :data => {:"turbo-frame" => "_top"}) do %>
|
|
58
|
-
<svg
|
|
59
|
-
|
|
135
|
+
<svg
|
|
136
|
+
class="w-6 h-6"
|
|
137
|
+
aria-hidden="true"
|
|
138
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
139
|
+
width="24"
|
|
140
|
+
height="24"
|
|
141
|
+
fill="none"
|
|
142
|
+
viewBox="0 0 24 24"
|
|
143
|
+
>
|
|
144
|
+
<path
|
|
145
|
+
stroke="currentColor"
|
|
146
|
+
stroke-linecap="round"
|
|
147
|
+
stroke-linejoin="round"
|
|
148
|
+
stroke-width="2"
|
|
149
|
+
d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"
|
|
150
|
+
/>
|
|
60
151
|
</svg>
|
|
61
152
|
<% end %>
|
|
62
153
|
</div>
|
|
@@ -1,12 +1,27 @@
|
|
|
1
|
-
<%= form_tag(repository.routes.path_for(:index), class: "flex items-center max-w-sm", method: :get) do %>
|
|
1
|
+
<%= form_tag(repository.routes.path_for(:index), class: "flex items-center max-w-sm space-x-2", method: :get) do %>
|
|
2
2
|
<%= label_tag(:query, repository.translate.search_label, class: "sr-only") %>
|
|
3
|
+
|
|
3
4
|
<div class="relative w-full">
|
|
4
|
-
<%= search_field_tag(:query, query, class: "bg-
|
|
5
|
+
<%= search_field_tag(:query, query, class: "px-3 py-2.5 bg-neutral-secondary-medium border border-default-medium rounded-base text-heading text-sm focus:ring-brand focus:border-brand block w-full placeholder:text-body") %>
|
|
5
6
|
</div>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
|
|
8
|
+
<%= button_tag(class: "inline-flex items-center justify-center shrink-0 text-white bg-brand hover:bg-brand-strong focus:ring-4 focus:ring-brand-medium shadow-xs rounded-base w-10 h-10 focus:outline-none") do %>
|
|
9
|
+
<svg
|
|
10
|
+
class="w-4 h-4"
|
|
11
|
+
aria-hidden="true"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
fill="none"
|
|
14
|
+
viewBox="0 0 20 20"
|
|
15
|
+
>
|
|
16
|
+
<path
|
|
17
|
+
stroke="currentColor"
|
|
18
|
+
stroke-linecap="round"
|
|
19
|
+
stroke-linejoin="round"
|
|
20
|
+
stroke-width="2"
|
|
21
|
+
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
|
|
22
|
+
/>
|
|
9
23
|
</svg>
|
|
24
|
+
|
|
10
25
|
<span class="sr-only"><%= repository.translate.search_button %></span>
|
|
11
26
|
<% end %>
|
|
12
27
|
|
|
@@ -16,6 +31,7 @@
|
|
|
16
31
|
<%= hidden_field_tag("scope[inverse_of]", scope[:inverse_of]) %>
|
|
17
32
|
<%= hidden_field_tag("scope[model]", scope[:model]) %>
|
|
18
33
|
<% end %>
|
|
34
|
+
|
|
19
35
|
<%= hidden_field_tag("sort[by]", sort_by) if sort_by? %>
|
|
20
36
|
<%= hidden_field_tag("sort[direction]", sort_direction) if sort_direction? %>
|
|
21
37
|
<% end %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<ul class="space-y-2 font-medium">
|
|
2
|
+
<% items.each do |item| %>
|
|
3
|
+
<li>
|
|
4
|
+
<%= link_to(item[:path], :class => "flex items-center py-1.5 text-body rounded-base hover:bg-neutral-tertiary hover:text-fg-brand group md:px-2") do %>
|
|
5
|
+
<span class="ms-3"><%= item[:label] %></span>
|
|
6
|
+
<% end %>
|
|
7
|
+
</li>
|
|
8
|
+
<% end %>
|
|
9
|
+
</ul>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uchi
|
|
4
|
+
module Ui
|
|
5
|
+
# Renders the main navigation menu visible at the side of the viewport.
|
|
6
|
+
#
|
|
7
|
+
# The template for this component has access to the following methods:
|
|
8
|
+
#
|
|
9
|
+
# - `items`: Returns an `Array` of `Hashes` containing :label and :path keys
|
|
10
|
+
# for each item to render in the navigation.
|
|
11
|
+
# - `navigatable_repositories`: Returns an `Array` of `Uchi::Repository`
|
|
12
|
+
# instances. The `Array` is sorted alphanumerically by the
|
|
13
|
+
# `navigation_label` for each repository.
|
|
14
|
+
# - `repositories`: Returns an `Array` with an instance of each
|
|
15
|
+
# `Uchi::Repository` in the application.
|
|
16
|
+
class Navigation < ViewComponent::Base
|
|
17
|
+
protected
|
|
18
|
+
|
|
19
|
+
def items
|
|
20
|
+
navigatable_repositories.map do |repository|
|
|
21
|
+
{
|
|
22
|
+
label: repository.translate.navigation_label,
|
|
23
|
+
path: repository.routes.path_for(:index)
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def navigatable_repositories
|
|
29
|
+
repositories.sort_by { |repository| repository.translate.navigation_label.downcase }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def repositories
|
|
33
|
+
Uchi::Repository.all.map(&:new)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<span class="text-body-subtle">—</span>
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
<header class="px-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<header class="px-0 mb-6 space-y-6 md:px-0">
|
|
2
|
+
<% if breadcrumb? %>
|
|
3
|
+
<div class="px-2">
|
|
4
4
|
<%= breadcrumb %>
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
</div>
|
|
6
|
+
<% end %>
|
|
7
7
|
|
|
8
|
-
<div class="items-start justify-between space-x-6 md:flex md:px-0">
|
|
8
|
+
<div class="items-start justify-between space-y-2 space-x-6 md:flex md:px-0 md:space-y-0">
|
|
9
9
|
<div>
|
|
10
|
-
<h1 class="text-3xl font-semibold tracking-tight text-
|
|
10
|
+
<h1 class="px-1 text-3xl font-semibold tracking-tight text-heading group">
|
|
11
|
+
<%= title %>
|
|
12
|
+
</h1>
|
|
13
|
+
|
|
11
14
|
<% if description.present? %>
|
|
12
|
-
<div class="text-lg text-
|
|
15
|
+
<div class="text-lg text-body-subtle lg:mb-0 lg:max-w-2xl">
|
|
16
|
+
<%= description %>
|
|
17
|
+
</div>
|
|
13
18
|
<% end %>
|
|
14
19
|
</div>
|
|
15
20
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<li>
|
|
2
|
-
<%= link_to(@paginator.page, page_url(page_number), aria: { current: "page" }, class: "
|
|
2
|
+
<%= link_to(@paginator.page, page_url(page_number), aria: { current: "page" }, class: "flex items-center justify-center text-fg-brand bg-neutral-tertiary-medium box-border border border-default-medium hover:text-fg-brand font-medium text-sm w-9 h-9 focus:outline-none") %>
|
|
3
3
|
</li>
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
<li
|
|
1
|
+
<li
|
|
2
|
+
class="
|
|
3
|
+
flex items-center justify-center text-body bg-neutral-secondary-medium
|
|
4
|
+
box-border border border-default-medium hover:bg-neutral-tertiary-medium
|
|
5
|
+
hover:text-heading font-medium text-sm w-9 h-9 focus:outline-none
|
|
6
|
+
"
|
|
7
|
+
>
|
|
2
8
|
…
|
|
3
9
|
</li>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<li>
|
|
2
|
-
<%= link_to(page_number, page_url(page_number), class: "flex items-center justify-center
|
|
2
|
+
<%= link_to(page_number, page_url(page_number), class: "flex items-center justify-center text-body bg-neutral-secondary-medium box-border border border-default-medium hover:bg-neutral-tertiary-medium hover:text-heading font-medium text-sm w-9 h-9 focus:outline-none") %>
|
|
3
3
|
</li>
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
<li>
|
|
2
|
-
<%= link_to(url, class: "flex items-center justify-center
|
|
2
|
+
<%= link_to(url, class: "flex items-center justify-center text-body bg-neutral-secondary-medium box-border border border-default-medium hover:bg-neutral-tertiary-medium hover:text-heading font-medium rounded-e-base text-sm w-9 h-9 focus:outline-none") do %>
|
|
3
3
|
<span class="sr-only">Next</span>
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
<svg
|
|
6
|
+
class="w-4 h-4 rtl:rotate-180"
|
|
7
|
+
aria-hidden="true"
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
width="24"
|
|
10
|
+
height="24"
|
|
11
|
+
fill="none"
|
|
12
|
+
viewBox="0 0 24 24"
|
|
13
|
+
>
|
|
14
|
+
<path
|
|
15
|
+
stroke="currentColor"
|
|
16
|
+
stroke-linecap="round"
|
|
17
|
+
stroke-linejoin="round"
|
|
18
|
+
stroke-width="2"
|
|
19
|
+
d="m9 5 7 7-7 7"
|
|
20
|
+
/>
|
|
6
21
|
</svg>
|
|
7
22
|
<% end %>
|
|
8
23
|
</li>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<nav aria-label="<%= aria_label %>">
|
|
2
|
-
<ul class="flex
|
|
2
|
+
<ul class="flex -space-x-px text-sm">
|
|
3
3
|
<%= render(Uchi::Ui::Pagination::PreviousLink.new(paginator: @paginator)) %>
|
|
4
|
+
|
|
4
5
|
<% pages.each do |page_number| %>
|
|
5
6
|
<% if page_number.nil? %>
|
|
6
7
|
<%= render(Uchi::Ui::Pagination::Gap.new(page_number: page_number, paginator: @paginator)) %>
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
<%= render(Uchi::Ui::Pagination::Link.new(page_number: page_number, paginator: @paginator)) %>
|
|
11
12
|
<% end %>
|
|
12
13
|
<% end %>
|
|
14
|
+
|
|
13
15
|
<%= render(Uchi::Ui::Pagination::NextLink.new(paginator: @paginator)) %>
|
|
14
16
|
</ul>
|
|
15
17
|
</nav>
|