solidcrud 0.1.0
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +1285 -0
- data/app/assets/javascripts/controllers/dashboard_controller.js +96 -0
- data/app/assets/javascripts/controllers/modal_controller.js +217 -0
- data/app/assets/javascripts/controllers/navigation_controller.js +117 -0
- data/app/assets/javascripts/controllers/notification_controller.js +85 -0
- data/app/assets/javascripts/controllers/search_controller.js +189 -0
- data/app/assets/javascripts/controllers/table_controller.js +272 -0
- data/app/assets/javascripts/solidcrud/application.js +9475 -0
- data/app/assets/stylesheets/solidcrud/_components.scss +267 -0
- data/app/assets/stylesheets/solidcrud/_forms.scss +69 -0
- data/app/assets/stylesheets/solidcrud/_layout.scss +149 -0
- data/app/assets/stylesheets/solidcrud/_tables.scss +90 -0
- data/app/assets/stylesheets/solidcrud/_variables.scss +21 -0
- data/app/assets/stylesheets/solidcrud/application.css +10 -0
- data/app/assets/stylesheets/solidcrud/application.css.map +1 -0
- data/app/assets/stylesheets/solidcrud/application.scss +10 -0
- data/app/assets/stylesheets/solidcrud/temp.css.map +1 -0
- data/app/assets/stylesheets/solidcrud/temp2.css.map +1 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-brands-400.ttf +0 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-brands-400.woff2 +0 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-regular-400.ttf +0 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-regular-400.woff2 +0 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-solid-900.ttf +0 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-solid-900.woff2 +0 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-v4compatibility.ttf +0 -0
- data/app/assets/stylesheets/solidcrud/webfonts/fa-v4compatibility.woff2 +0 -0
- data/app/assets/stylesheets/webfonts/fa-brands-400.ttf +0 -0
- data/app/assets/stylesheets/webfonts/fa-brands-400.woff2 +0 -0
- data/app/assets/stylesheets/webfonts/fa-regular-400.ttf +0 -0
- data/app/assets/stylesheets/webfonts/fa-regular-400.woff2 +0 -0
- data/app/assets/stylesheets/webfonts/fa-solid-900.ttf +0 -0
- data/app/assets/stylesheets/webfonts/fa-solid-900.woff2 +0 -0
- data/app/assets/stylesheets/webfonts/fa-v4compatibility.ttf +0 -0
- data/app/assets/stylesheets/webfonts/fa-v4compatibility.woff2 +0 -0
- data/app/controllers/solidcrud/admin_controller.rb +215 -0
- data/app/controllers/solidcrud/application_controller.rb +19 -0
- data/app/controllers/solidcrud/assets_controller.rb +59 -0
- data/app/controllers/solidcrud/sessions_controller.rb +84 -0
- data/app/helpers/solidcrud/application_helper.rb +153 -0
- data/app/javascript/solidcrud/application.js +14 -0
- data/app/javascript/solidcrud/controllers/crud_controller.js +64 -0
- data/app/javascript/solidcrud/controllers/index.js +33 -0
- data/app/views/layouts/solidcrud/application.html.erb +70 -0
- data/app/views/solidcrud/admin/edit.html.erb +294 -0
- data/app/views/solidcrud/admin/index.html.erb +128 -0
- data/app/views/solidcrud/admin/model.html.erb +353 -0
- data/app/views/solidcrud/admin/new.html.erb +275 -0
- data/app/views/solidcrud/admin/shared/_dashboard_stats.html.erb +49 -0
- data/app/views/solidcrud/admin/shared/_edit_form_sidebar.html.erb +9 -0
- data/app/views/solidcrud/admin/shared/_flash_messages.html.erb +27 -0
- data/app/views/solidcrud/admin/shared/_full_sidebar.html.erb +56 -0
- data/app/views/solidcrud/admin/shared/_modal.html.erb +45 -0
- data/app/views/solidcrud/admin/shared/_new_form_sidebar.html.erb +6 -0
- data/app/views/solidcrud/admin/shared/_record_row.html.erb +35 -0
- data/app/views/solidcrud/admin/shared/_records_table.html.erb +85 -0
- data/app/views/solidcrud/sessions/new.html.erb +262 -0
- data/config/routes.rb +24 -0
- data/lib/generators/solidcrud/install/install_generator.rb +21 -0
- data/lib/generators/solidcrud/install/templates/INSTALL.md +80 -0
- data/lib/generators/solidcrud/install/templates/solidcrud.rb +31 -0
- data/lib/generators/solidcrud/install_generator.rb +17 -0
- data/lib/generators/solidcrud/templates/solidcrud.rb +4 -0
- data/lib/solidcrud/authentication.rb +143 -0
- data/lib/solidcrud/configuration.rb +64 -0
- data/lib/solidcrud/engine.rb +49 -0
- data/lib/solidcrud/version.rb +5 -0
- data/lib/solidcrud.rb +10 -0
- metadata +177 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
<div class="flex h-screen bg-gradient-to-br from-slate-50 to-slate-100">
|
|
2
|
+
<!-- Sidebar -->
|
|
3
|
+
<div class="w-80 bg-white border-r border-slate-200/50 flex flex-col" data-controller="navigation">
|
|
4
|
+
<!-- Logo Section -->
|
|
5
|
+
<div class="p-6 border-b border-slate-200/50">
|
|
6
|
+
<div class="flex items-center space-x-3">
|
|
7
|
+
<div class="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
|
|
8
|
+
<span class="text-white">đ§</span>
|
|
9
|
+
</div>
|
|
10
|
+
<div>
|
|
11
|
+
<h2 class="text-lg font-bold text-slate-900">SolidCRUD</h2>
|
|
12
|
+
<p class="text-xs text-slate-500">Admin Panel</p>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<!-- Navigation Menu -->
|
|
18
|
+
<nav class="flex-1 p-4">
|
|
19
|
+
<div class="space-y-1">
|
|
20
|
+
<a href="<%= solidcrud.root_path %>"
|
|
21
|
+
class="nav-item flex items-center space-x-3 px-4 py-3 text-slate-700 hover:bg-slate-100 rounded-xl transition-all duration-200 group"
|
|
22
|
+
data-path="/admin"
|
|
23
|
+
data-action="navigation#handleNavClick">
|
|
24
|
+
<div class="w-8 h-8 bg-slate-100 rounded-lg flex items-center justify-center group-hover:bg-blue-100 transition-colors duration-200">
|
|
25
|
+
<span class="text-slate-500 group-hover:text-blue-600">đ</span>
|
|
26
|
+
</div>
|
|
27
|
+
<span class="font-medium">Dashboard</span>
|
|
28
|
+
</a>
|
|
29
|
+
|
|
30
|
+
<div class="pt-4">
|
|
31
|
+
<h3 class="px-4 text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2">Models</h3>
|
|
32
|
+
<div class="space-y-1">
|
|
33
|
+
<% @models.each do |model| %>
|
|
34
|
+
<a href="<%= solidcrud.admin_model_path(model.name) %>"
|
|
35
|
+
class="nav-item flex items-center space-x-3 px-4 py-3 text-slate-700 hover:bg-slate-100 rounded-xl transition-all duration-200 group"
|
|
36
|
+
data-path="/admin/<%= model.name %>"
|
|
37
|
+
data-action="navigation#handleNavClick">
|
|
38
|
+
<div class="w-8 h-8 bg-slate-100 rounded-lg flex items-center justify-center group-hover:bg-blue-100 transition-colors duration-200">
|
|
39
|
+
<span class="text-slate-500 group-hover:text-blue-600">đ</span>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="flex-1 min-w-0">
|
|
42
|
+
<div class="font-medium truncate"><%= model.name.pluralize %></div>
|
|
43
|
+
<div class="text-xs text-slate-500"><%= model.count %> records</div>
|
|
44
|
+
</div>
|
|
45
|
+
</a>
|
|
46
|
+
<% end %>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</nav>
|
|
51
|
+
|
|
52
|
+
<!-- Footer -->
|
|
53
|
+
<div class="p-4 border-t border-slate-200/50">
|
|
54
|
+
<div class="text-xs text-slate-500 text-center">
|
|
55
|
+
Rails <%= Rails.version %> âĸ SolidCRUD
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<!-- Main Content Area -->
|
|
61
|
+
<div class="flex-1 flex flex-col overflow-hidden">
|
|
62
|
+
<!-- Content Header with Flash Messages -->
|
|
63
|
+
<div class="bg-white border-b border-slate-200/50 px-8 py-6">
|
|
64
|
+
<!-- Flash Messages -->
|
|
65
|
+
<div id="flash-messages">
|
|
66
|
+
<% if flash[:notice] %>
|
|
67
|
+
<div class="mb-6 bg-green-50 border border-green-200 rounded-xl p-4 flex items-start space-x-3 animate-in slide-in-from-top-2 duration-300">
|
|
68
|
+
<div class="flex-shrink-0">
|
|
69
|
+
<span class="text-green-500 text-lg">â</span>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="flex-1">
|
|
72
|
+
<p class="text-green-800 font-medium"><%= flash[:notice] %></p>
|
|
73
|
+
</div>
|
|
74
|
+
<button class="flex-shrink-0 text-green-400 hover:text-green-600 transition-colors duration-200">
|
|
75
|
+
<span class="text-lg">Ã</span>
|
|
76
|
+
</button>
|
|
77
|
+
</div>
|
|
78
|
+
<% end %>
|
|
79
|
+
|
|
80
|
+
<% if flash[:alert] %>
|
|
81
|
+
<div class="mb-6 bg-red-50 border border-red-200 rounded-xl p-4 flex items-start space-x-3 animate-in slide-in-from-top-2 duration-300">
|
|
82
|
+
<div class="flex-shrink-0">
|
|
83
|
+
<span class="text-red-500 text-lg">â ī¸</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="flex-1">
|
|
86
|
+
<p class="text-red-800 font-medium"><%= flash[:alert] %></p>
|
|
87
|
+
</div>
|
|
88
|
+
<button class="flex-shrink-0 text-red-400 hover:text-red-600 transition-colors duration-200">
|
|
89
|
+
<span class="text-lg">Ã</span>
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
<% end %>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<!-- Scrollable Content -->
|
|
97
|
+
<div class="flex-1 overflow-y-auto">
|
|
98
|
+
<div class="px-8 py-6">
|
|
99
|
+
<!-- Header Section -->
|
|
100
|
+
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between mb-8">
|
|
101
|
+
<div class="mb-4 sm:mb-0">
|
|
102
|
+
<!-- Breadcrumb -->
|
|
103
|
+
<nav class="flex items-center space-x-2 text-sm text-slate-500 mb-2">
|
|
104
|
+
<a href="<%= solidcrud.root_path %>" class="hover:text-slate-700 transition-colors duration-200">
|
|
105
|
+
<span class="mr-1">đ </span>Dashboard
|
|
106
|
+
</a>
|
|
107
|
+
<span class="text-slate-400">âē</span>
|
|
108
|
+
<span class="text-slate-900 font-medium"><%= @model_name.pluralize %></span>
|
|
109
|
+
</nav>
|
|
110
|
+
|
|
111
|
+
<div class="flex items-center space-x-4">
|
|
112
|
+
<div class="w-12 h-12 bg-gradient-to-r from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
|
|
113
|
+
<span class="text-white text-lg">đ</span>
|
|
114
|
+
</div>
|
|
115
|
+
<div>
|
|
116
|
+
<h1 class="text-3xl font-bold text-slate-900"><%= @model_name.pluralize %></h1>
|
|
117
|
+
<p class="text-slate-600 mt-1">Manage your <%= @model_name.downcase %> records</p>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<%= link_to solidcrud.new_admin_model_path(@model_name),
|
|
123
|
+
class: "inline-flex items-center px-6 py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white font-medium rounded-xl shadow-lg hover:shadow-xl transition-all duration-200 hover:scale-105" do %>
|
|
124
|
+
<span class="mr-2">+</span>New <%= @model_name %>
|
|
125
|
+
<% end %>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<!-- Search and Filter Section -->
|
|
129
|
+
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/50 p-6 mb-6" data-controller="search">
|
|
130
|
+
<%= form_with url: solidcrud.admin_model_path(@model_name), method: :get, local: true,
|
|
131
|
+
class: 'grid grid-cols-1 md:grid-cols-4 gap-4',
|
|
132
|
+
data: { turbo_frame: "_top" } do |f| %>
|
|
133
|
+
|
|
134
|
+
<div class="md:col-span-2">
|
|
135
|
+
<label class="block text-sm font-medium text-slate-700 mb-2">
|
|
136
|
+
<span class="mr-2 text-slate-400">đ</span>Search
|
|
137
|
+
</label>
|
|
138
|
+
<div class="relative">
|
|
139
|
+
<%= f.text_field :search,
|
|
140
|
+
value: params[:search],
|
|
141
|
+
placeholder: "Search #{ @model_name.pluralize.downcase }...",
|
|
142
|
+
class: 'w-full pl-4 pr-4 py-3 border border-slate-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-slate-50 focus:bg-white',
|
|
143
|
+
data: { search_target: "input", action: "input->search#handleInput" } %>
|
|
144
|
+
<button type="button"
|
|
145
|
+
class="absolute right-3 top-3 text-slate-400 hover:text-slate-600 hidden"
|
|
146
|
+
data-search-target="clear"
|
|
147
|
+
data-action="search#clearSearch">
|
|
148
|
+
<span>Ã</span>
|
|
149
|
+
</button>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<div>
|
|
154
|
+
<label class="block text-sm font-medium text-slate-700 mb-2">
|
|
155
|
+
<span class="mr-2 text-slate-400">â</span>Sort by
|
|
156
|
+
</label>
|
|
157
|
+
<%= f.select :sort,
|
|
158
|
+
options_for_select(
|
|
159
|
+
@model_klass.column_names.map { |col| [col.humanize, col] },
|
|
160
|
+
params[:sort]
|
|
161
|
+
),
|
|
162
|
+
{ prompt: 'Sort by...' },
|
|
163
|
+
{ class: 'w-full px-4 py-3 border border-slate-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-slate-50 focus:bg-white' } %>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<div class="flex items-end space-x-2">
|
|
167
|
+
<%= f.submit "Search",
|
|
168
|
+
class: 'flex-1 px-6 py-3 bg-slate-600 text-white font-medium rounded-xl hover:bg-slate-700 transition-all duration-200 shadow-sm hover:shadow-md',
|
|
169
|
+
data: { search_target: "loading", search_loading_class: "hidden" } %>
|
|
170
|
+
|
|
171
|
+
<% if params[:search].present? || params[:sort].present? %>
|
|
172
|
+
<%= link_to solidcrud.admin_model_path(@model_name),
|
|
173
|
+
class: 'px-4 py-3 bg-slate-100 text-slate-600 font-medium rounded-xl hover:bg-slate-200 transition-all duration-200',
|
|
174
|
+
data: { turbo_frame: "_top" } do %>
|
|
175
|
+
<span>Ã</span>
|
|
176
|
+
<% end %>
|
|
177
|
+
<% end %>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<%= f.hidden_field :direction, value: params[:direction] %>
|
|
181
|
+
<% end %>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<!-- Column Selection Section -->
|
|
185
|
+
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/50 p-6 mb-6">
|
|
186
|
+
<div class="flex items-center justify-between mb-4">
|
|
187
|
+
<div class="flex items-center space-x-3">
|
|
188
|
+
<div class="w-10 h-10 bg-gradient-to-r from-purple-500 to-pink-600 rounded-xl flex items-center justify-center shadow-lg">
|
|
189
|
+
<span class="text-white">đ</span>
|
|
190
|
+
</div>
|
|
191
|
+
<div>
|
|
192
|
+
<h3 class="text-lg font-semibold text-slate-900">Table Columns</h3>
|
|
193
|
+
<p class="text-sm text-slate-600">Select which columns to display</p>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
<div class="flex items-center space-x-2">
|
|
197
|
+
<button type="button" id="select-all-columns" class="px-3 py-2 text-sm bg-slate-100 text-slate-700 rounded-lg hover:bg-slate-200 transition-all duration-200" data-action="click->table#selectAllColumns">
|
|
198
|
+
<span class="mr-1">â</span>Select All
|
|
199
|
+
</button>
|
|
200
|
+
<button type="button" id="deselect-all-columns" class="px-3 py-2 text-sm bg-slate-100 text-slate-700 rounded-lg hover:bg-slate-200 transition-all duration-200" data-action="click->table#deselectAllColumns">
|
|
201
|
+
<span class="mr-1">â</span>Deselect All
|
|
202
|
+
</button>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-3" id="column-checkboxes">
|
|
207
|
+
<% @model_klass.column_names.each do |col| %>
|
|
208
|
+
<label class="flex items-center space-x-2 p-2 rounded-lg hover:bg-slate-50 transition-colors duration-200 cursor-pointer">
|
|
209
|
+
<input type="checkbox"
|
|
210
|
+
class="column-checkbox w-4 h-4 text-blue-600 bg-slate-100 border-slate-300 rounded focus:ring-blue-500 focus:ring-2"
|
|
211
|
+
value="<%= col %>"
|
|
212
|
+
data-table-target="checkbox"
|
|
213
|
+
<%= 'checked' if column_visible?(col, @model_name) %>>
|
|
214
|
+
<span class="text-sm text-slate-700 flex items-center space-x-1">
|
|
215
|
+
<span class="text-slate-400"><%= column_icon(col) %></span>
|
|
216
|
+
<span><%= col.humanize %></span>
|
|
217
|
+
</span>
|
|
218
|
+
</label>
|
|
219
|
+
<% end %>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<!-- Data Table -->
|
|
224
|
+
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/50 overflow-hidden" data-controller="table" id="records-table">
|
|
225
|
+
<% if @records.any? %>
|
|
226
|
+
<div class="overflow-x-auto">
|
|
227
|
+
<table class="w-full">
|
|
228
|
+
<thead class="bg-gradient-to-r from-slate-50 to-slate-100 border-b border-slate-200/50">
|
|
229
|
+
<tr>
|
|
230
|
+
<% @model_klass.column_names.each do |col| %>
|
|
231
|
+
<th class="px-6 py-4 text-left text-xs font-semibold text-slate-600 uppercase tracking-wider column-header column-visible"
|
|
232
|
+
data-column="<%= col %>"
|
|
233
|
+
data-table-target="header">
|
|
234
|
+
<%= link_to solidcrud.admin_model_path(@model_name,
|
|
235
|
+
search: params[:search],
|
|
236
|
+
sort: col,
|
|
237
|
+
direction: (params[:sort] == col && params[:direction] != 'desc') ? 'desc' : 'asc'
|
|
238
|
+
), class: 'group flex items-center space-x-2 hover:text-slate-900 transition-colors duration-200',
|
|
239
|
+
data: { turbo_frame: "_top" } do %>
|
|
240
|
+
<span class="text-slate-400 group-hover:text-slate-600"><%= column_icon(col) %></span>
|
|
241
|
+
<span><%= col.humanize %></span>
|
|
242
|
+
<% if params[:sort] == col %>
|
|
243
|
+
<span class="text-blue-500"><%= params[:direction] == 'desc' ? 'â' : 'â' %></span>
|
|
244
|
+
<% else %>
|
|
245
|
+
<span class="text-slate-300 group-hover:text-slate-400">â</span>
|
|
246
|
+
<% end %>
|
|
247
|
+
<% end %>
|
|
248
|
+
</th>
|
|
249
|
+
<% end %>
|
|
250
|
+
<th class="px-6 py-4 text-center text-xs font-semibold text-slate-600 uppercase tracking-wider w-32">
|
|
251
|
+
Actions
|
|
252
|
+
</th>
|
|
253
|
+
</tr>
|
|
254
|
+
</thead>
|
|
255
|
+
|
|
256
|
+
<tbody class="divide-y divide-slate-200/50">
|
|
257
|
+
<% @records.each do |record| %>
|
|
258
|
+
<tr class="hover:bg-slate-50 transition-colors duration-200" data-table-target="row" data-id="<%= record.id %>">
|
|
259
|
+
<% @model_klass.column_names.each do |col| %>
|
|
260
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-slate-900 column-cell column-visible"
|
|
261
|
+
data-column="<%= col %>"
|
|
262
|
+
data-table-target="column">
|
|
263
|
+
<%= format_value(record.send(col), col, @model_klass) %>
|
|
264
|
+
</td>
|
|
265
|
+
<% end %>
|
|
266
|
+
<td class="px-6 py-4 whitespace-nowrap text-center">
|
|
267
|
+
<div class="flex items-center justify-center space-x-2">
|
|
268
|
+
<%= link_to solidcrud.edit_admin_model_path(@model_name, record),
|
|
269
|
+
class: 'inline-flex items-center px-3 py-2 bg-blue-50 text-blue-700 font-medium rounded-lg hover:bg-blue-100 transition-all duration-200 hover:shadow-sm',
|
|
270
|
+
title: 'Edit',
|
|
271
|
+
data: { turbo_frame: "_top" } do %>
|
|
272
|
+
<span class="text-lg">âī¸</span>
|
|
273
|
+
<% end %>
|
|
274
|
+
|
|
275
|
+
<%= link_to "#",
|
|
276
|
+
data: {
|
|
277
|
+
modal_title: "Delete #{record.class.name}",
|
|
278
|
+
modal_message: "Are you sure you want to delete this #{record.class.name.downcase}? This action cannot be undone.",
|
|
279
|
+
modal_confirm_text: "Delete",
|
|
280
|
+
modal_cancel_text: "Cancel",
|
|
281
|
+
modal_url: solidcrud.admin_model_path(@model_name, id: record.id),
|
|
282
|
+
action: "modal#confirmDelete"
|
|
283
|
+
},
|
|
284
|
+
class: 'inline-flex items-center px-3 py-2 bg-red-50 text-red-700 font-medium rounded-lg hover:bg-red-100 transition-all duration-200 hover:shadow-sm delete-record-btn',
|
|
285
|
+
title: 'Delete' do %>
|
|
286
|
+
<span class="text-lg">đī¸</span>
|
|
287
|
+
<% end %>
|
|
288
|
+
</div>
|
|
289
|
+
</td>
|
|
290
|
+
</tr>
|
|
291
|
+
<% end %>
|
|
292
|
+
</tbody>
|
|
293
|
+
</table>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<!-- Pagination Footer -->
|
|
297
|
+
<div class="bg-slate-50 px-6 py-4 border-t border-slate-200/50">
|
|
298
|
+
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between space-y-4 sm:space-y-0">
|
|
299
|
+
<div class="text-sm text-slate-600">
|
|
300
|
+
Showing <%= (@page - 1) * @per_page + 1 %>-<%= [(@page - 1) * @per_page + @records.count, @total_count].min %>
|
|
301
|
+
of <%= @total_count %> <%= @model_name.pluralize.downcase %>
|
|
302
|
+
<% if params[:search].present? %>
|
|
303
|
+
<span class="text-blue-600 font-medium">(filtered)</span>
|
|
304
|
+
<% end %>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<% if @total_pages > 1 %>
|
|
308
|
+
<div class="flex items-center space-x-2">
|
|
309
|
+
<% if @page > 1 %>
|
|
310
|
+
<%= link_to solidcrud.admin_model_path(@model_name, search: params[:search], sort: params[:sort], direction: params[:direction], page: @page - 1),
|
|
311
|
+
class: 'inline-flex items-center px-3 py-2 bg-white border border-slate-300 text-slate-700 font-medium rounded-lg hover:bg-slate-50 transition-all duration-200' do %>
|
|
312
|
+
<span class="mr-1">âš</span>Previous
|
|
313
|
+
<% end %>
|
|
314
|
+
<% end %>
|
|
315
|
+
|
|
316
|
+
<% start_page = [@page - 2, 1].max %>
|
|
317
|
+
<% end_page = [start_page + 4, @total_pages].min %>
|
|
318
|
+
<% start_page = [end_page - 4, 1].max if end_page - start_page < 4 %>
|
|
319
|
+
|
|
320
|
+
<% (start_page..end_page).each do |page_num| %>
|
|
321
|
+
<%= link_to page_num,
|
|
322
|
+
solidcrud.admin_model_path(@model_name, search: params[:search], sort: params[:sort], direction: params[:direction], page: page_num),
|
|
323
|
+
class: "inline-flex items-center px-3 py-2 font-medium rounded-lg transition-all duration-200 #{'bg-blue-500 text-white shadow-sm' if page_num == @page} #{'bg-white border border-slate-300 text-slate-700 hover:bg-slate-50' if page_num != @page}" %>
|
|
324
|
+
<% end %>
|
|
325
|
+
|
|
326
|
+
<% if @page < @total_pages %>
|
|
327
|
+
<%= link_to solidcrud.admin_model_path(@model_name, search: params[:search], sort: params[:sort], direction: params[:direction], page: @page + 1),
|
|
328
|
+
class: 'inline-flex items-center px-3 py-2 bg-white border border-slate-300 text-slate-700 font-medium rounded-lg hover:bg-slate-50 transition-all duration-200' do %>
|
|
329
|
+
Next<span class="ml-1">âē</span>
|
|
330
|
+
<% end %>
|
|
331
|
+
<% end %>
|
|
332
|
+
</div>
|
|
333
|
+
<% end %>
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
<% else %>
|
|
337
|
+
<div class="px-6 py-16 text-center">
|
|
338
|
+
<div class="w-20 h-20 bg-slate-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
|
339
|
+
<span class="text-3xl">đ</span>
|
|
340
|
+
</div>
|
|
341
|
+
<h6 class="text-xl font-semibold text-slate-900 mb-2">No <%= @model_name.pluralize.downcase %> found</h6>
|
|
342
|
+
<p class="text-slate-500 mb-6">Get started by creating your first <%= @model_name.downcase %>.</p>
|
|
343
|
+
<%= link_to solidcrud.new_admin_model_path(@model_name),
|
|
344
|
+
class: "inline-flex items-center px-6 py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white font-medium rounded-xl shadow-lg hover:shadow-xl transition-all duration-200 hover:scale-105" do %>
|
|
345
|
+
<span class="mr-2">+</span>Create First <%= @model_name %>
|
|
346
|
+
<% end %>
|
|
347
|
+
</div>
|
|
348
|
+
<% end %>
|
|
349
|
+
</div>
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
<div class="flex h-screen bg-gradient-to-br from-slate-50 to-slate-100">
|
|
2
|
+
<!-- Sidebar -->
|
|
3
|
+
<div class="w-80 bg-white border-r border-slate-200/50 flex flex-col" data-controller="navigation">
|
|
4
|
+
<!-- Logo Section -->
|
|
5
|
+
<div class="p-6 border-b border-slate-200/50">
|
|
6
|
+
<div class="flex items-center space-x-3">
|
|
7
|
+
<div class="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
|
|
8
|
+
<span class="text-white">đ§</span>
|
|
9
|
+
</div>
|
|
10
|
+
<div>
|
|
11
|
+
<h2 class="text-lg font-bold text-slate-900">SolidCRUD</h2>
|
|
12
|
+
<p class="text-xs text-slate-500">Admin Panel</p>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<!-- Navigation Menu -->
|
|
18
|
+
<nav class="flex-1 p-4">
|
|
19
|
+
<div class="space-y-1">
|
|
20
|
+
<a href="<%= solidcrud.root_path %>"
|
|
21
|
+
class="nav-item flex items-center space-x-3 px-4 py-3 text-slate-700 hover:bg-slate-100 rounded-xl transition-all duration-200 group"
|
|
22
|
+
data-path="/admin"
|
|
23
|
+
data-action="navigation#handleNavClick">
|
|
24
|
+
<div class="w-8 h-8 bg-slate-100 rounded-lg flex items-center justify-center group-hover:bg-blue-100 transition-colors duration-200">
|
|
25
|
+
<span class="text-slate-500 group-hover:text-blue-600">đ</span>
|
|
26
|
+
</div>
|
|
27
|
+
<span class="font-medium">Dashboard</span>
|
|
28
|
+
</a>
|
|
29
|
+
|
|
30
|
+
<div class="pt-4">
|
|
31
|
+
<h3 class="px-4 text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2">Models</h3>
|
|
32
|
+
<div class="space-y-1">
|
|
33
|
+
<% @models.each do |model| %>
|
|
34
|
+
<a href="<%= solidcrud.admin_model_path(model.name) %>"
|
|
35
|
+
class="nav-item flex items-center space-x-3 px-4 py-3 text-slate-700 hover:bg-slate-100 rounded-xl transition-all duration-200 group"
|
|
36
|
+
data-path="/admin/<%= model.name %>"
|
|
37
|
+
data-action="navigation#handleNavClick">
|
|
38
|
+
<div class="w-8 h-8 bg-slate-100 rounded-lg flex items-center justify-center group-hover:bg-blue-100 transition-colors duration-200">
|
|
39
|
+
<span class="text-slate-500 group-hover:text-blue-600">đ</span>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="flex-1 min-w-0">
|
|
42
|
+
<div class="font-medium truncate"><%= model.name.pluralize %></div>
|
|
43
|
+
<div class="text-xs text-slate-500"><%= model.count %> records</div>
|
|
44
|
+
</div>
|
|
45
|
+
</a>
|
|
46
|
+
<% end %>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</nav>
|
|
51
|
+
|
|
52
|
+
<!-- Footer -->
|
|
53
|
+
<div class="p-4 border-t border-slate-200/50">
|
|
54
|
+
<div class="text-xs text-slate-500 text-center">
|
|
55
|
+
Rails <%= Rails.version %> âĸ SolidCRUD
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<!-- Main Content Area -->
|
|
61
|
+
<div class="flex-1 flex flex-col overflow-hidden">
|
|
62
|
+
<!-- Content Header with Flash Messages -->
|
|
63
|
+
<div class="bg-white border-b border-slate-200/50 px-8 py-6">
|
|
64
|
+
<!-- Flash Messages -->
|
|
65
|
+
<% if flash[:notice] %>
|
|
66
|
+
<div class="mb-6 bg-green-50 border border-green-200 rounded-xl p-4 flex items-start space-x-3 animate-in slide-in-from-top-2 duration-300">
|
|
67
|
+
<div class="flex-shrink-0">
|
|
68
|
+
<span class="text-green-500 text-lg">â</span>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="flex-1">
|
|
71
|
+
<p class="text-green-800 font-medium"><%= flash[:notice] %></p>
|
|
72
|
+
</div>
|
|
73
|
+
<button class="flex-shrink-0 text-green-400 hover:text-green-600 transition-colors duration-200">
|
|
74
|
+
<span class="text-lg">Ã</span>
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
<% end %>
|
|
78
|
+
|
|
79
|
+
<% if flash[:alert] %>
|
|
80
|
+
<div class="mb-6 bg-red-50 border border-red-200 rounded-xl p-4 flex items-start space-x-3 animate-in slide-in-from-top-2 duration-300">
|
|
81
|
+
<div class="flex-shrink-0">
|
|
82
|
+
<span class="text-red-500 text-lg">â ī¸</span>
|
|
83
|
+
</div>
|
|
84
|
+
<div class="flex-1">
|
|
85
|
+
<p class="text-red-800 font-medium"><%= flash[:alert] %></p>
|
|
86
|
+
</div>
|
|
87
|
+
<button class="flex-shrink-0 text-red-400 hover:text-red-600 transition-colors duration-200">
|
|
88
|
+
<span class="text-lg">Ã</span>
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
|
+
<% end %>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<!-- Scrollable Content -->
|
|
95
|
+
<div class="flex-1 overflow-y-auto">
|
|
96
|
+
<div class="px-8 py-6">
|
|
97
|
+
<!-- Header Section -->
|
|
98
|
+
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between mb-8">
|
|
99
|
+
<div class="mb-4 sm:mb-0">
|
|
100
|
+
<!-- Breadcrumb -->
|
|
101
|
+
<nav class="flex items-center space-x-2 text-sm text-slate-500 mb-2">
|
|
102
|
+
<a href="<%= solidcrud.root_path %>" class="hover:text-slate-700 transition-colors duration-200">
|
|
103
|
+
<span class="mr-1">đ </span>Dashboard
|
|
104
|
+
</a>
|
|
105
|
+
<span class="text-slate-400">âē</span>
|
|
106
|
+
<a href="<%= solidcrud.admin_model_path(@model_name) %>" class="hover:text-slate-700 transition-colors duration-200">
|
|
107
|
+
<%= @model_name.pluralize %>
|
|
108
|
+
</a>
|
|
109
|
+
<span class="text-slate-400">âē</span>
|
|
110
|
+
<span class="text-slate-900 font-medium">New</span>
|
|
111
|
+
</nav>
|
|
112
|
+
|
|
113
|
+
<div class="flex items-center space-x-4">
|
|
114
|
+
<div class="w-12 h-12 bg-gradient-to-r from-green-500 to-emerald-600 rounded-xl flex items-center justify-center shadow-lg">
|
|
115
|
+
<span class="text-white text-lg">+</span>
|
|
116
|
+
</div>
|
|
117
|
+
<div>
|
|
118
|
+
<h1 class="text-3xl font-bold text-slate-900">Create New <%= @model_name %></h1>
|
|
119
|
+
<p class="text-slate-600 mt-1">Add a new <%= @model_name.downcase %> to your database</p>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
126
|
+
<!-- Main Form -->
|
|
127
|
+
<div class="lg:col-span-2">
|
|
128
|
+
<!-- Information Cards -->
|
|
129
|
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
|
130
|
+
<!-- Model Info Card -->
|
|
131
|
+
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/50 p-6">
|
|
132
|
+
<div class="flex items-center space-x-3 mb-4">
|
|
133
|
+
<div class="w-10 h-10 bg-gradient-to-r from-blue-500 to-indigo-600 rounded-xl flex items-center justify-center shadow-lg">
|
|
134
|
+
<span class="text-white">âšī¸</span>
|
|
135
|
+
</div>
|
|
136
|
+
<div>
|
|
137
|
+
<h6 class="text-lg font-semibold text-slate-900">Model Info</h6>
|
|
138
|
+
<p class="text-sm text-slate-600">Basic information</p>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
<div class="space-y-3">
|
|
142
|
+
<div class="flex justify-between items-center">
|
|
143
|
+
<span class="text-sm text-slate-600">Name</span>
|
|
144
|
+
<span class="text-sm font-medium text-slate-900"><%= @model_name %></span>
|
|
145
|
+
</div>
|
|
146
|
+
<div class="flex justify-between items-center">
|
|
147
|
+
<span class="text-sm text-slate-600">Table</span>
|
|
148
|
+
<span class="text-sm font-medium text-slate-900"><%= @model_klass.table_name %></span>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="flex justify-between items-center">
|
|
151
|
+
<span class="text-sm text-slate-600">Fields</span>
|
|
152
|
+
<span class="text-sm font-medium text-slate-900"><%= @model_klass.column_names.size %></span>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<!-- Model Stats Card -->
|
|
158
|
+
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/50 p-6">
|
|
159
|
+
<div class="flex items-center space-x-3 mb-4">
|
|
160
|
+
<div class="w-10 h-10 bg-gradient-to-r from-green-500 to-emerald-600 rounded-xl flex items-center justify-center shadow-lg">
|
|
161
|
+
<span class="text-white">đ</span>
|
|
162
|
+
</div>
|
|
163
|
+
<div>
|
|
164
|
+
<h6 class="text-lg font-semibold text-slate-900">Model Stats</h6>
|
|
165
|
+
<p class="text-sm text-slate-600">Database overview</p>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="space-y-3">
|
|
169
|
+
<div class="flex justify-between items-center">
|
|
170
|
+
<span class="text-sm text-slate-600">Total Records</span>
|
|
171
|
+
<span class="text-sm font-medium text-slate-900"><%= @model_klass.count %></span>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="flex justify-between items-center">
|
|
174
|
+
<span class="text-sm text-slate-600">Required Fields</span>
|
|
175
|
+
<span class="text-sm font-medium text-slate-900"><%= @model_klass.columns.reject { |c| c.null }.size %></span>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="flex justify-between items-center">
|
|
178
|
+
<span class="text-sm text-slate-600">Optional Fields</span>
|
|
179
|
+
<span class="text-sm font-medium text-slate-900"><%= @model_klass.columns.select { |c| c.null }.size %></span>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<!-- Quick Actions Card -->
|
|
185
|
+
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/50 p-6">
|
|
186
|
+
<div class="flex items-center space-x-3 mb-4">
|
|
187
|
+
<div class="w-10 h-10 bg-gradient-to-r from-purple-500 to-pink-600 rounded-xl flex items-center justify-center shadow-lg">
|
|
188
|
+
<span class="text-white">âĄ</span>
|
|
189
|
+
</div>
|
|
190
|
+
<div>
|
|
191
|
+
<h6 class="text-lg font-semibold text-slate-900">Quick Actions</h6>
|
|
192
|
+
<p class="text-sm text-slate-600">Common tasks</p>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
<div class="space-y-2">
|
|
196
|
+
<%= link_to solidcrud.admin_model_path(@model_name),
|
|
197
|
+
class: 'block w-full text-left px-3 py-2 text-sm text-slate-700 hover:bg-slate-50 rounded-lg transition-colors duration-200' do %>
|
|
198
|
+
<span class="mr-2 text-slate-400">â</span>Back to List
|
|
199
|
+
<% end %>
|
|
200
|
+
<%= link_to solidcrud.root_path,
|
|
201
|
+
class: 'block w-full text-left px-3 py-2 text-sm text-slate-700 hover:bg-slate-50 rounded-lg transition-colors duration-200' do %>
|
|
202
|
+
<span class="mr-2 text-slate-400">đ </span>Dashboard
|
|
203
|
+
<% end %>
|
|
204
|
+
<%= link_to solidcrud.admin_model_path(@model_name) + '?sort=created_at&direction=desc',
|
|
205
|
+
class: 'block w-full text-left px-3 py-2 text-sm text-slate-700 hover:bg-slate-50 rounded-lg transition-colors duration-200' do %>
|
|
206
|
+
<span class="mr-2 text-slate-400">đ</span>Recent Records
|
|
207
|
+
<% end %>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/50 p-8">
|
|
213
|
+
<div class="flex items-center space-x-3 mb-8">
|
|
214
|
+
<div class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center">
|
|
215
|
+
<span class="text-blue-600">âī¸</span>
|
|
216
|
+
</div>
|
|
217
|
+
<h6 class="text-xl font-semibold text-slate-900"><%= @model_name %> Details</h6>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<%= form_with model: @record, url: solidcrud.admin_model_path(@model_name), local: true, class: 'space-y-6',
|
|
221
|
+
data: { turbo_frame: "_top" } do |f| %>
|
|
222
|
+
<% if @record.errors.any? %>
|
|
223
|
+
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
|
|
224
|
+
<div class="flex items-start space-x-3">
|
|
225
|
+
<div class="flex-shrink-0">
|
|
226
|
+
<span class="text-red-500 text-lg">â ī¸</span>
|
|
227
|
+
</div>
|
|
228
|
+
<div class="flex-1">
|
|
229
|
+
<h6 class="text-red-800 font-semibold mb-2">Please fix the following errors:</h6>
|
|
230
|
+
<ul class="text-red-700 text-sm space-y-1">
|
|
231
|
+
<% @record.errors.full_messages.each do |message| %>
|
|
232
|
+
<li>âĸ <%= message %></li>
|
|
233
|
+
<% end %>
|
|
234
|
+
</ul>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
<% end %>
|
|
239
|
+
|
|
240
|
+
<% editable_columns = @model_klass.column_names.reject { |c| ["id", "created_at", "updated_at"].include?(c) } %>
|
|
241
|
+
<% editable_columns.each do |col| %>
|
|
242
|
+
<% column_obj = @model_klass.columns_hash[col] %>
|
|
243
|
+
<div>
|
|
244
|
+
<%= f.label col, class: 'block text-sm font-semibold text-slate-700 mb-2' do %>
|
|
245
|
+
<span class="mr-2 text-slate-400"><%= column_icon(col) %></span>
|
|
246
|
+
<%= col.humanize %>
|
|
247
|
+
<% if column_obj&.null == false %>
|
|
248
|
+
<span class="text-red-500 ml-1">*</span>
|
|
249
|
+
<% end %>
|
|
250
|
+
<% end %>
|
|
251
|
+
<%= render_form_field(f, col, @model_klass) %>
|
|
252
|
+
<% if column_obj&.comment.present? %>
|
|
253
|
+
<p class="mt-1 text-sm text-slate-500"><%= column_obj.comment %></p>
|
|
254
|
+
<% end %>
|
|
255
|
+
</div>
|
|
256
|
+
<% end %>
|
|
257
|
+
|
|
258
|
+
<!-- Form Actions -->
|
|
259
|
+
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between pt-6 border-t border-slate-200 space-y-4 sm:space-y-0">
|
|
260
|
+
<%= link_to solidcrud.admin_model_path(@model_name),
|
|
261
|
+
class: 'inline-flex items-center px-6 py-3 bg-slate-100 text-slate-700 font-medium rounded-xl hover:bg-slate-200 transition-all duration-200' do %>
|
|
262
|
+
<span class="mr-2">â</span>Cancel
|
|
263
|
+
<% end %>
|
|
264
|
+
|
|
265
|
+
<%= f.submit "Create #{@model_name}",
|
|
266
|
+
class: 'inline-flex items-center px-8 py-3 bg-gradient-to-r from-green-500 to-emerald-600 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-200 hover:scale-105' do %>
|
|
267
|
+
<span class="mr-2">đž</span>Create <%= @model_name %>
|
|
268
|
+
<% end %>
|
|
269
|
+
</div>
|
|
270
|
+
<% end %>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
<!-- Sidebar -->
|
|
275
|
+
<%= render 'solidcrud/admin/shared/new_form_sidebar' %>
|