madmin 1.2.0 → 1.2.1

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 (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>