madmin 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -0
  3. data/app/controllers/madmin/base_controller.rb +0 -5
  4. data/app/controllers/madmin/resource_controller.rb +20 -1
  5. data/app/helpers/madmin/application_helper.rb +4 -0
  6. data/app/helpers/madmin/nav_helper.rb +30 -0
  7. data/app/helpers/madmin/sort_helper.rb +3 -2
  8. data/app/views/layouts/madmin/application.html.erb +5 -5
  9. data/app/views/madmin/application/_form.html.erb +6 -8
  10. data/app/views/madmin/application/_javascript.html.erb +34 -3
  11. data/app/views/madmin/application/_navigation.html.erb +31 -5
  12. data/app/views/madmin/application/edit.html.erb +5 -1
  13. data/app/views/madmin/application/index.html.erb +34 -22
  14. data/app/views/madmin/application/new.html.erb +5 -1
  15. data/app/views/madmin/application/show.html.erb +24 -17
  16. data/app/views/madmin/fields/attachment/_form.html.erb +3 -1
  17. data/app/views/madmin/fields/attachment/_show.html.erb +7 -1
  18. data/app/views/madmin/fields/attachments/_form.html.erb +3 -1
  19. data/app/views/madmin/fields/attachments/_show.html.erb +7 -3
  20. data/app/views/madmin/fields/belongs_to/_form.html.erb +4 -2
  21. data/app/views/madmin/fields/belongs_to/_show.html.erb +1 -1
  22. data/app/views/madmin/fields/boolean/_form.html.erb +3 -1
  23. data/app/views/madmin/fields/date/_form.html.erb +3 -1
  24. data/app/views/madmin/fields/date_time/_form.html.erb +3 -1
  25. data/app/views/madmin/fields/decimal/_form.html.erb +3 -1
  26. data/app/views/madmin/fields/enum/_form.html.erb +4 -2
  27. data/app/views/madmin/fields/float/_form.html.erb +3 -1
  28. data/app/views/madmin/fields/has_many/_form.html.erb +4 -2
  29. data/app/views/madmin/fields/has_many/_show.html.erb +1 -1
  30. data/app/views/madmin/fields/has_one/_form.html.erb +3 -2
  31. data/app/views/madmin/fields/integer/_form.html.erb +3 -1
  32. data/app/views/madmin/fields/json/_form.html.erb +3 -1
  33. data/app/views/madmin/fields/nested_has_many/_form.html.erb +3 -1
  34. data/app/views/madmin/fields/nested_has_many/_show.html.erb +1 -1
  35. data/app/views/madmin/fields/password/_form.html.erb +3 -1
  36. data/app/views/madmin/fields/polymorphic/_form.html.erb +3 -1
  37. data/app/views/madmin/fields/polymorphic/_show.html.erb +1 -1
  38. data/app/views/madmin/fields/rich_text/_form.html.erb +3 -1
  39. data/app/views/madmin/fields/string/_form.html.erb +3 -1
  40. data/app/views/madmin/fields/text/_form.html.erb +3 -1
  41. data/app/views/madmin/fields/time/_form.html.erb +3 -1
  42. data/app/views/madmin/shared/_label.html.erb +4 -0
  43. data/lib/generators/madmin/field/field_generator.rb +31 -0
  44. data/lib/generators/madmin/field/templates/_form.html.erb +2 -0
  45. data/lib/generators/madmin/field/templates/_index.html.erb +1 -0
  46. data/lib/generators/madmin/field/templates/_show.html.erb +1 -0
  47. data/lib/generators/madmin/field/templates/field.rb.tt +26 -0
  48. data/lib/generators/madmin/install/install_generator.rb +6 -1
  49. data/lib/generators/madmin/install/templates/routes.rb.tt +3 -0
  50. data/lib/generators/madmin/resource/resource_generator.rb +1 -1
  51. data/lib/generators/madmin/resource/templates/controller.rb.tt +6 -0
  52. data/lib/madmin/engine.rb +1 -1
  53. data/lib/madmin/field.rb +4 -0
  54. data/lib/madmin/fields/belongs_to.rb +9 -6
  55. data/lib/madmin/fields/has_many.rb +10 -6
  56. data/lib/madmin/fields/string.rb +3 -0
  57. data/lib/madmin/fields/text.rb +3 -0
  58. data/lib/madmin/generator_helpers.rb +22 -4
  59. data/lib/madmin/resource.rb +19 -13
  60. data/lib/madmin/search.rb +60 -0
  61. data/lib/madmin/version.rb +1 -1
  62. data/lib/madmin.rb +19 -5
  63. metadata +14 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e868d17abd508729232e7ebeebd4b79a8e69545b853276a700c60e61e5d6348c
4
- data.tar.gz: b19043a0a2e7dd0ad6392f995b76812b434e54f73682eb163ca28e1aaeb4ad34
3
+ metadata.gz: 1f3bd8e986e4859620b06401c531dc24ca84bb02e4e2284a34918b5a088c126c
4
+ data.tar.gz: 9bf59b4f93849feda832005caa748e02b4227ea2552cd6e94264d3b7d170f5a9
5
5
  SHA512:
6
- metadata.gz: '09b7ec920a1c8ae8a1429db77cff71ca45574e379563db5a06648d5cd5434950597b99eed5b836f7834cdc5c71e9d68411f064cc78d363da848efde9a0ef1b1a'
7
- data.tar.gz: 51b2b25ddabe18e8777c9eab9e34dd1b8afd74a05aae5671f2f94c85cb404043bcde8423d996033a9dd4fa07ee672ad36240e65e195166586afabc02d756237a
6
+ metadata.gz: 3181e8f05aad7af36b905a4a04ffb2ddd63419b347e699b0b9ea6d8d2fb9a880f12ebbd7b12d05770e02dc7508e4789a1cb8250b11b6eed26878b6ef71d7fc1b
7
+ data.tar.gz: '0019a725b02cde9e007190917381da718a139662d1d9094a0e49ccc69b799437865a4170658b99492947ce1d6d2ae04f71dde97886212a8dd728c3a9aa2275f3'
data/README.md CHANGED
@@ -79,6 +79,31 @@ rails generate madmin:views:index Book
79
79
  # -> app/views/madmin/books/index.html.erb
80
80
  ```
81
81
 
82
+ ## Custom Fields
83
+
84
+ You can generate a custom field with:
85
+
86
+ ```bash
87
+ rails g madmin:field Custom
88
+ ```
89
+
90
+ This will create a `CustomField` class in `app/madmin/fields/custom_field.rb`
91
+ And the related views:
92
+
93
+ ```bash
94
+ # -> app/views/madmin/fields/custom_field/_form.html.erb
95
+ # -> app/views/madmin/fields/custom_field/_index.html.erb
96
+ # -> app/views/madmin/fields/custom_field/_show.html.erb
97
+ ```
98
+
99
+ You can then use this field on our resource:
100
+
101
+ ```ruby
102
+ class PostResource < Madmin::Resource
103
+ attribute :title, field: CustomField
104
+ end
105
+ ```
106
+
82
107
  ## Authentication
83
108
 
84
109
  You can use a couple of strategies to authenticate users who are trying to
@@ -3,10 +3,5 @@ module Madmin
3
3
  include Pagy::Backend
4
4
 
5
5
  protect_from_forgery with: :exception
6
-
7
- # Loads all the models for the sidebar
8
- before_action do
9
- Rails.application.eager_load!
10
- end
11
6
  end
12
7
  end
@@ -4,8 +4,21 @@ module Madmin
4
4
 
5
5
  before_action :set_record, except: [:index, :new, :create]
6
6
 
7
+ # Assign current_user for paper_trail gem
8
+ before_action :set_paper_trail_whodunnit, if: -> { respond_to?(:set_paper_trail_whodunnit, true) }
9
+
7
10
  def index
8
11
  @pagy, @records = pagy(scoped_resources)
12
+
13
+ respond_to do |format|
14
+ format.html
15
+ format.json {
16
+ render json: @records.map { |r| {name: @resource.display_name(r), id: r.id} }
17
+ }
18
+ end
19
+ rescue Pagy::OverflowError
20
+ params[:page] = 1
21
+ retry
9
22
  end
10
23
 
11
24
  def show
@@ -56,7 +69,9 @@ module Madmin
56
69
  end
57
70
 
58
71
  def scoped_resources
59
- resource.model.send(valid_scope).order(sort_column => sort_direction)
72
+ resources = resource.model.send(valid_scope)
73
+ resources = Madmin::Search.new(resources, resource, search_term).run
74
+ resources.reorder(sort_column => sort_direction)
60
75
  end
61
76
 
62
77
  def valid_scope
@@ -79,5 +94,9 @@ module Madmin
79
94
  raise "Unrecognised param data: #{data.inspect}"
80
95
  end
81
96
  end
97
+
98
+ def search_term
99
+ @search_term ||= params[:q].to_s.strip
100
+ end
82
101
  end
83
102
  end
@@ -13,5 +13,9 @@ module Madmin
13
13
  version += "-#{Rails::VERSION::PRE}" if Rails::VERSION::PRE
14
14
  version
15
15
  end
16
+
17
+ def clear_search_params
18
+ params.except(:q, :_page).permit(:page, :sort, :direction)
19
+ end
16
20
  end
17
21
  end
@@ -0,0 +1,30 @@
1
+ module Madmin::NavHelper
2
+ def nav_link_to(name = nil, options = {}, html_options = {}, &block)
3
+ if block
4
+ html_options = options
5
+ options = name
6
+ name = block
7
+ end
8
+
9
+ url = url_for(options)
10
+ starts_with = html_options.delete(:starts_with)
11
+ html_options[:class] = Array.wrap(html_options[:class])
12
+ active_class = html_options.delete(:active_class) || "active"
13
+ inactive_class = html_options.delete(:inactive_class) || ""
14
+
15
+ active = if (paths = Array.wrap(starts_with)) && paths.present?
16
+ paths.any? { |path| request.path.start_with?(path) }
17
+ else
18
+ request.path == url
19
+ end
20
+
21
+ classes = active ? active_class : inactive_class
22
+ html_options[:class] << classes unless classes.empty?
23
+
24
+ html_options.except!(:class) if html_options[:class].empty?
25
+
26
+ return link_to url, html_options, &block if block
27
+
28
+ link_to name, url, html_options
29
+ end
30
+ end
@@ -2,8 +2,9 @@ module Madmin
2
2
  module SortHelper
3
3
  def sortable(column, title, options = {})
4
4
  matching_column = (column.to_s == sort_column)
5
+ direction = sort_direction == "asc" ? "desc" : "asc"
5
6
 
6
- link_to request.params.merge(sort: column, direction: sort_direction), options do
7
+ link_to request.params.merge(sort: column, direction: direction), options do
7
8
  concat title
8
9
  if matching_column
9
10
  concat " "
@@ -21,7 +22,7 @@ module Madmin
21
22
  end
22
23
 
23
24
  def default_sort_column
24
- resource.try(:default_sort_column) || "created_at"
25
+ resource.try(:default_sort_column) || (["created_at", "id", "uuid"] & resource.model.column_names).first
25
26
  end
26
27
 
27
28
  def default_sort_direction
@@ -7,19 +7,19 @@
7
7
  <title>
8
8
  Madmin: <%= Rails.application.class %>
9
9
  </title>
10
- <link href="https://unpkg.com/tailwindcss@^2.0/dist/tailwind.min.css" rel="stylesheet" />
11
10
  <link href="https://unpkg.com/@tailwindcss/forms/dist/forms.min.css" rel="stylesheet" />
11
+ <link href="https://unpkg.com/tailwindcss@^2.0/dist/tailwind.min.css" rel="stylesheet" />
12
12
  <link href="https://unpkg.com/@tailwindcss/typography/dist/typography.min.css" rel="stylesheet" />
13
13
  <%= csrf_meta_tags %>
14
14
 
15
15
  <%= render "javascript" %>
16
16
  </head>
17
- <body class="prose" style="max-width:none">
18
- <div class="flex w-full p-4">
19
- <div id="sidebar" class="w-64 flex-shrink-0">
17
+ <body class="min-h-screen">
18
+ <div class="md:flex w-full min-h-screen">
19
+ <div id="sidebar" class="md:w-64 p-4 flex-shrink-0 border-r">
20
20
  <%= render "navigation" -%>
21
21
  </div>
22
- <main class="w-full" role="main">
22
+ <main class="flex-grow p-4" role="main">
23
23
  <%#= render "flashes" -%>
24
24
  <%= yield %>
25
25
  </main>
@@ -9,15 +9,13 @@
9
9
  </div>
10
10
  <% end %>
11
11
 
12
- <% resource.attributes.each do |attribute| %>
13
- <% next if attribute[:field].nil? %>
14
- <% next unless attribute[:field].visible?(action_name) %>
15
- <% next unless attribute[:field].visible?(:form) %>
12
+ <% resource.attributes.values.each do |attribute| %>
13
+ <% next if attribute.field.nil? %>
14
+ <% next unless attribute.field.visible?(action_name) %>
15
+ <% next unless attribute.field.visible?(:form) %>
16
16
 
17
- <% field = attribute[:field] %>
18
-
19
- <div class="mb-4 flex">
20
- <%= render partial: field.to_partial_path("form"), locals: { field: field, record: record, form: form, resource: resource } %>
17
+ <div class="mb-4 md:flex">
18
+ <%= render partial: attribute.field.to_partial_path("form"), locals: { field: attribute.field, record: record, form: form, resource: resource } %>
21
19
  </div>
22
20
  <% end %>
23
21
 
@@ -1,16 +1,18 @@
1
1
  <%= stylesheet_link_tag "https://unpkg.com/flatpickr/dist/flatpickr.min.css", "data-turbo-track": "reload" %>
2
2
  <%= stylesheet_link_tag "https://unpkg.com/trix/dist/trix.css", "data-turbo-track": "reload" %>
3
- <%= stylesheet_link_tag "https://unpkg.com/slim-select@1.27.0/dist/slimselect.min.css", "data-turbo-track": "reload" %>
3
+ <%= stylesheet_link_tag "https://unpkg.com/tom-select/dist/css/tom-select.min.css", "data-turbo-track": "reload" %>
4
4
 
5
5
  <script type="module">
6
6
  import { Application, Controller } from 'https://cdn.skypack.dev/stimulus'
7
7
  const application = Application.start()
8
8
 
9
+ import { Dropdown } from "https://cdn.skypack.dev/tailwindcss-stimulus-components"
10
+ application.register("dropdown", Dropdown)
11
+
9
12
  import stimulusFlatpickr from 'https://cdn.skypack.dev/stimulus-flatpickr'
10
13
  application.register("flatpickr", stimulusFlatpickr)
11
14
 
12
- import stimulusSlimselect from 'https://cdn.skypack.dev/stimulus-slimselect'
13
- application.register("slimselect", stimulusSlimselect)
15
+ import TomSelect from 'https://cdn.skypack.dev/tom-select'
14
16
 
15
17
  import Rails from 'https://cdn.skypack.dev/@rails/ujs@<%= npm_rails_version %>'
16
18
  import * as ActiveStorage from 'https://cdn.skypack.dev/@rails/activestorage@<%= npm_rails_version %>'
@@ -23,6 +25,35 @@
23
25
  import * as Turbo from "https://cdn.skypack.dev/@hotwired/turbo"
24
26
 
25
27
  (() => {
28
+ application.register('select', class extends Controller {
29
+ static values = {
30
+ options: Object,
31
+ url: String
32
+ }
33
+
34
+ connect() {
35
+ this.select = new TomSelect(this.element, {
36
+ plugins: ['remove_button'],
37
+ valueField: 'id',
38
+ labelField: 'name',
39
+ searchField: 'name',
40
+ load: (search, callback) => {
41
+ fetch(this.urlValue)
42
+ .then(response => response.json())
43
+ .then(json => {
44
+ callback(json);
45
+ }).catch(() => {
46
+ callback();
47
+ });
48
+ }
49
+ })
50
+ }
51
+
52
+ disconnect() {
53
+ this.select.destroy()
54
+ }
55
+ })
56
+
26
57
  application.register('nested-form', class extends Controller {
27
58
  static get targets() {
28
59
  return [ "links", "template" ]
@@ -1,6 +1,32 @@
1
- <div class="text-sm">
2
- <%= link_to " Back to App", main_app.root_url, class: "block p-1", data: { turbo: false } if main_app.respond_to?(:root_url) %>
3
- <% Madmin.resources.each do |resource| %>
4
- <%= link_to resource.friendly_name.pluralize, resource.index_path, class: "block p-1" %>
5
- <% end %>
1
+ <div class="flex flex-col h-full text-sm" data-controller="dropdown">
2
+ <div class="flex md:block justify-between items-center">
3
+ <div class="flex md:block items-center">
4
+ <h1 class="mr-2 md:p-2 text-xl font-semibold">Madmin</h1>
5
+ <% if main_app.respond_to?(:root_url) %>
6
+ <%= link_to main_app.root_url, class: "block p-2 rounded hover:bg-gray-200", data: { turbo: false } do %>
7
+ ← Back <span class="hidden md:inline">to App</span>
8
+ <% end %>
9
+ <% end %>
10
+ </div>
11
+
12
+ <div class="-mr-2 flex items-center md:hidden">
13
+ <button data-action="click->dropdown#toggle touch->dropdown#toggle click@window->dropdown#hide touch@window#dropdown->hide" type="button" class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:bg-gray-200 focus:outline-none focus:ring-2 focus-ring-inset focus:ring-white" id="main-menu" aria-haspopup="true">
14
+ <span class="sr-only">Open main menu</span>
15
+ <!-- Heroicon name: outline/menu -->
16
+ <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
17
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
18
+ </svg>
19
+ </button>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="hidden md:flex flex-col flex-grow justify-between" data-dropdown-target="menu">
24
+ <% Madmin.resources.each do |resource| %>
25
+ <%= nav_link_to resource.friendly_name.pluralize, resource.index_path, class: "block p-2 rounded hover:bg-gray-100", starts_with: resource.index_path, active_class: "font-bold text-black" %>
26
+ <% end %>
27
+
28
+ <div class="mt-auto">
29
+ <%= link_to "View Madmin on GitHub", "https://github.com/excid3/madmin", target: :_blank, class: "block p-2 rounded text-gray-500 hover:bg-gray-100" %>
30
+ </div>
31
+ </div>
6
32
  </div>
@@ -1,3 +1,7 @@
1
- <h1><%= link_to resource.friendly_name.pluralize, resource.index_path %> / Edit <%= resource.friendly_name %> #<%= @record.id %></h1>
1
+ <h1 class="text-xl mb-4">
2
+ <%= link_to resource.friendly_name.pluralize, resource.index_path, class: "text-indigo-500" %>
3
+ /
4
+ <strong>Edit <%= link_to resource.display_name(@record), resource.show_path(@record), class: "text-indigo-500" %></strong>
5
+ </h1>
2
6
 
3
7
  <%= render partial: "form", locals: { record: @record, resource: resource } %>
@@ -1,44 +1,56 @@
1
- <div class="flex justify-between">
2
- <h1><%= resource.friendly_name.pluralize %></h1>
3
- <%= link_to "New #{resource.friendly_name}", resource.new_path %>
1
+ <div class="md:flex justify-between items-center space-y-4 md:space-y-0">
2
+ <h1 class="text-xl font-semibold"><%= resource.friendly_name.pluralize %></h1>
3
+
4
+ <div class="flex-grow flex md:justify-end gap-4">
5
+ <form class="flex items-center gap-2 relative">
6
+ <%= hidden_field_tag :page, params[:page], value: 1, class: "hidden" %>
7
+ <%= search_field_tag :q, params[:q], placeholder: "Search", class: "rounded-full px-4 focus:bg-white focus:border-indigo-500" %>
8
+ <%= link_to clear_search_params, class: "absolute top-1/2 right-3 text-gray-500 bg-white transform -translate-y-1/2" do %>
9
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
10
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
11
+ </svg>
12
+ <% end %>
13
+ </form>
14
+
15
+ <%= link_to resource.new_path, class: "bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow" do %>
16
+ New <span class="hidden md:inline"><%= resource.friendly_name %></span>
17
+ <% end %>
18
+ </div>
4
19
  </div>
5
20
 
6
- <div>
21
+ <div class="mb-4">
7
22
  <% if resource.scopes.any? %>
8
- <%= link_to "All", resource.index_path %>
23
+ <%= link_to "All", resource.index_path, class: class_names("p-2 rounded", {"bg-gray-100" => params[:scope].blank?}) %>
9
24
  <% end %>
10
25
 
11
26
  <% resource.scopes.each do |scope| %>
12
- <%= link_to scope.to_s.humanize, resource.index_path(scope: scope) %>
27
+ <%= link_to scope.to_s.humanize, resource.index_path(scope: scope), class: class_names("p-2 rounded", {"bg-gray-100" => params[:scope] == scope.to_s}) %>
13
28
  <% end %>
14
29
  </div>
15
30
 
16
- <table class="table-auto">
31
+ <table class="min-w-full divide-y divide-gray-200">
17
32
  <thead>
18
- <tr>
19
- <% resource.attributes.each do |attribute| %>
20
- <% next if attribute[:field].nil? %>
21
- <% next unless attribute[:field].visible?(action_name) %>
33
+ <tr class="border-b border-gray-200">
34
+ <% resource.attributes.values.each do |attribute| %>
35
+ <% next if attribute.field.nil? %>
36
+ <% next unless attribute.field.visible?(action_name) %>
22
37
 
23
- <th><%= sortable attribute[:name], attribute[:name].to_s.titleize %></th>
38
+ <th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase whitespace-nowrap"><%= sortable attribute.name, attribute.name.to_s.titleize %></th>
24
39
  <% end %>
25
- <th>Actions</th>
40
+ <th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase">Actions</th>
26
41
  </tr>
27
42
  </thead>
28
43
 
29
- <tbody>
44
+ <tbody class="text-sm divide-y">
30
45
  <% @records.each do |record| %>
31
46
  <tr>
32
- <% resource.attributes.each do |attribute| %>
33
- <% next if attribute[:field].nil? %>
34
- <% next unless attribute[:field].visible?(action_name) %>
35
-
36
- <% field = attribute[:field] %>
37
-
38
- <td><%= render partial: field.to_partial_path("index"), locals: { field: field, record: record } %></td>
47
+ <% resource.attributes.values.each do |attribute| %>
48
+ <% next if attribute.field.nil? %>
49
+ <% next unless attribute.field.visible?(action_name) %>
50
+ <td class="px-4 py-2"><%= render partial: attribute.field.to_partial_path("index"), locals: { field: attribute.field, record: record } %></td>
39
51
  <% end %>
40
52
 
41
- <td><%= link_to "View", resource.show_path(record) %></td>
53
+ <td class="px-4 py-2 text-center"><%= link_to "View", resource.show_path(record), class: "text-indigo-500" %></td>
42
54
  </tr>
43
55
  <% end %>
44
56
  </tbody>
@@ -1,3 +1,7 @@
1
- <h1><%= link_to resource.friendly_name.pluralize, resource.index_path %> / New <%= resource.friendly_name %></h1>
1
+ <h1 class="text-xl mb-4">
2
+ <%= link_to resource.friendly_name.pluralize, resource.index_path, class: "text-indigo-500" %>
3
+ /
4
+ <strong>New <%= resource.friendly_name %></strong>
5
+ </h1>
2
6
 
3
7
  <%= render partial: "form", locals: { record: @record, resource: resource } %>
@@ -1,24 +1,31 @@
1
- <div class="flex justify-between">
2
- <h1><%= link_to resource.friendly_name.pluralize, resource.index_path %> / <%= resource.model.name.singularize %> #<%= @record.id %></h1>
1
+ <div class="md:flex items-center justify-between mb-4">
2
+ <h1 class="text-xl">
3
+ <%= link_to resource.friendly_name.pluralize, resource.index_path, class: "text-indigo-500" %>
4
+ /
5
+ <%= link_to resource.display_name(@record), resource.show_path(@record), class: "text-indigo-500 font-bold" %>
6
+ </h1>
3
7
 
4
- <div class="flex px-4">
5
- <%= link_to "Edit", resource.edit_path(@record), class: "mr-2" %>
6
- <%= button_to "Delete", resource.show_path(@record), method: :delete, data: { confirm: "Are you sure?" }, class: "inline-block" %>
8
+ <div class="flex items-center px-4">
9
+ <div class="mr-2">
10
+ <%= link_to "Edit", resource.edit_path(@record), class: "block bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow" %>
11
+ </div>
12
+ <%= button_to "Delete", resource.show_path(@record), method: :delete, data: { confirm: "Are you sure?" }, class: "bg-white hover:bg-gray-100 text-red-500 font-semibold py-2 px-4 border border-red-500 rounded shadow pointer-cursor" %>
7
13
  </div>
8
14
  </div>
9
15
 
10
- <% resource.attributes.each do |attribute| %>
11
- <% next if attribute[:field].nil? %>
12
- <% next unless attribute[:field].visible?(action_name) %>
13
- <% field = attribute[:field] %>
16
+ <div class="divide-y">
17
+ <% resource.attributes.values.each do |attribute| %>
18
+ <% next if attribute.field.nil? %>
19
+ <% next unless attribute.field.visible?(action_name) %>
14
20
 
15
- <div class="flex py-2">
16
- <div class="w-32 flex-shrink-0 text-gray-700 uppercase tracking-wide text-sm">
17
- <%= field.attribute_name.to_s.titleize %>
18
- </div>
21
+ <div class="px-4 py-3 md:grid md:grid-cols-4 md:gap-4 md:px-6">
22
+ <div class="text-sm font-medium text-gray-500">
23
+ <%= attribute.field.attribute_name.to_s.titleize %>
24
+ </div>
19
25
 
20
- <div>
21
- <%= render partial: field.to_partial_path("show"), locals: { field: field, record: @record } %>
26
+ <div class="md:col-span-3">
27
+ <%= render partial: attribute.field.to_partial_path("show"), locals: { field: attribute.field, record: @record } %>
28
+ </div>
22
29
  </div>
23
- </div>
24
- <% end %>
30
+ <% end %>
31
+ </div>