active_canvas 0.0.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +318 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/active_canvas/editor/ai_panel.js +1607 -0
- data/app/assets/javascripts/active_canvas/editor/asset_manager.js +498 -0
- data/app/assets/javascripts/active_canvas/editor/blocks.js +1083 -0
- data/app/assets/javascripts/active_canvas/editor/code_panel.js +572 -0
- data/app/assets/javascripts/active_canvas/editor/component_toolbar.js +394 -0
- data/app/assets/javascripts/active_canvas/editor/panels.js +460 -0
- data/app/assets/javascripts/active_canvas/editor/utils.js +56 -0
- data/app/assets/javascripts/active_canvas/editor.js +295 -0
- data/app/assets/stylesheets/active_canvas/application.css +15 -0
- data/app/assets/stylesheets/active_canvas/editor.css +2929 -0
- data/app/controllers/active_canvas/admin/ai_controller.rb +181 -0
- data/app/controllers/active_canvas/admin/application_controller.rb +56 -0
- data/app/controllers/active_canvas/admin/media_controller.rb +61 -0
- data/app/controllers/active_canvas/admin/page_types_controller.rb +57 -0
- data/app/controllers/active_canvas/admin/page_versions_controller.rb +23 -0
- data/app/controllers/active_canvas/admin/pages_controller.rb +133 -0
- data/app/controllers/active_canvas/admin/partials_controller.rb +88 -0
- data/app/controllers/active_canvas/admin/settings_controller.rb +256 -0
- data/app/controllers/active_canvas/application_controller.rb +20 -0
- data/app/controllers/active_canvas/pages_controller.rb +18 -0
- data/app/controllers/concerns/active_canvas/current_user.rb +12 -0
- data/app/controllers/concerns/active_canvas/rate_limitable.rb +75 -0
- data/app/controllers/concerns/active_canvas/tailwind_compilation.rb +39 -0
- data/app/helpers/active_canvas/application_helper.rb +4 -0
- data/app/jobs/active_canvas/application_job.rb +4 -0
- data/app/jobs/active_canvas/compile_tailwind_job.rb +64 -0
- data/app/mailers/active_canvas/application_mailer.rb +6 -0
- data/app/models/active_canvas/ai_model.rb +136 -0
- data/app/models/active_canvas/application_record.rb +5 -0
- data/app/models/active_canvas/media.rb +141 -0
- data/app/models/active_canvas/page.rb +85 -0
- data/app/models/active_canvas/page_type.rb +22 -0
- data/app/models/active_canvas/page_version.rb +80 -0
- data/app/models/active_canvas/partial.rb +73 -0
- data/app/models/active_canvas/setting.rb +292 -0
- data/app/services/active_canvas/ai_configuration.rb +40 -0
- data/app/services/active_canvas/ai_models.rb +128 -0
- data/app/services/active_canvas/ai_service.rb +289 -0
- data/app/services/active_canvas/content_sanitizer.rb +112 -0
- data/app/services/active_canvas/tailwind_compiler.rb +156 -0
- data/app/views/active_canvas/admin/media/index.html.erb +401 -0
- data/app/views/active_canvas/admin/media/show.html.erb +297 -0
- data/app/views/active_canvas/admin/page_types/_form.html.erb +25 -0
- data/app/views/active_canvas/admin/page_types/edit.html.erb +13 -0
- data/app/views/active_canvas/admin/page_types/index.html.erb +29 -0
- data/app/views/active_canvas/admin/page_types/new.html.erb +9 -0
- data/app/views/active_canvas/admin/page_types/show.html.erb +18 -0
- data/app/views/active_canvas/admin/page_versions/show.html.erb +469 -0
- data/app/views/active_canvas/admin/pages/_form.html.erb +62 -0
- data/app/views/active_canvas/admin/pages/content.html.erb +139 -0
- data/app/views/active_canvas/admin/pages/edit.html.erb +335 -0
- data/app/views/active_canvas/admin/pages/editor.html.erb +710 -0
- data/app/views/active_canvas/admin/pages/index.html.erb +149 -0
- data/app/views/active_canvas/admin/pages/new.html.erb +19 -0
- data/app/views/active_canvas/admin/pages/show.html.erb +258 -0
- data/app/views/active_canvas/admin/pages/versions.html.erb +333 -0
- data/app/views/active_canvas/admin/partials/edit.html.erb +182 -0
- data/app/views/active_canvas/admin/partials/editor.html.erb +703 -0
- data/app/views/active_canvas/admin/partials/index.html.erb +131 -0
- data/app/views/active_canvas/admin/settings/show.html.erb +1864 -0
- data/app/views/active_canvas/pages/no_homepage.html.erb +45 -0
- data/app/views/active_canvas/pages/show.html.erb +113 -0
- data/app/views/layouts/active_canvas/admin/application.html.erb +960 -0
- data/app/views/layouts/active_canvas/admin/editor.html.erb +826 -0
- data/app/views/layouts/active_canvas/application.html.erb +55 -0
- data/config/routes.rb +48 -0
- data/db/migrate/20260202000001_create_active_canvas_tables.rb +113 -0
- data/db/migrate/20260202000002_create_active_canvas_ai_models.rb +26 -0
- data/lib/active_canvas/configuration.rb +232 -0
- data/lib/active_canvas/engine.rb +44 -0
- data/lib/active_canvas/version.rb +3 -0
- data/lib/active_canvas.rb +26 -0
- data/lib/generators/active_canvas/install/install_generator.rb +263 -0
- data/lib/generators/active_canvas/install/templates/initializer.rb.tt +163 -0
- data/lib/tasks/active_canvas_tasks.rake +69 -0
- metadata +150 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
<% content_for :page_title, @medium.filename %>
|
|
2
|
+
|
|
3
|
+
<!-- Page Header -->
|
|
4
|
+
<div class="page-header">
|
|
5
|
+
<div class="page-header-left">
|
|
6
|
+
<h2><%= truncate(@medium.filename, length: 40) %></h2>
|
|
7
|
+
<p class="page-header-subtitle">
|
|
8
|
+
Uploaded <%= time_ago_in_words(@medium.created_at) %> ago
|
|
9
|
+
</p>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="page-header-actions">
|
|
12
|
+
<button type="button" class="btn btn-secondary" onclick="copyMediaUrl('<%= @medium.url %>')">
|
|
13
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
14
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
15
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
16
|
+
</svg>
|
|
17
|
+
Copy URL
|
|
18
|
+
</button>
|
|
19
|
+
<%= link_to @medium.url, target: "_blank", class: "btn btn-secondary" do %>
|
|
20
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
21
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
|
|
22
|
+
<polyline points="15 3 21 3 21 9"/>
|
|
23
|
+
<line x1="10" y1="14" x2="21" y2="3"/>
|
|
24
|
+
</svg>
|
|
25
|
+
Open Original
|
|
26
|
+
<% end %>
|
|
27
|
+
<%= link_to admin_media_path, class: "btn btn-ghost" do %>
|
|
28
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
29
|
+
<line x1="19" y1="12" x2="5" y2="12"/>
|
|
30
|
+
<polyline points="12 19 5 12 12 5"/>
|
|
31
|
+
</svg>
|
|
32
|
+
Back to Library
|
|
33
|
+
<% end %>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div style="display: grid; grid-template-columns: 1fr 380px; gap: 1.5rem;">
|
|
38
|
+
<!-- Preview -->
|
|
39
|
+
<div class="card">
|
|
40
|
+
<div class="card-header">
|
|
41
|
+
<span class="card-title">Preview</span>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="media-preview-container">
|
|
44
|
+
<% if @medium.file.attached? %>
|
|
45
|
+
<%= image_tag @medium.url, alt: @medium.filename, class: "media-preview-image" %>
|
|
46
|
+
<% end %>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Details Sidebar -->
|
|
51
|
+
<div>
|
|
52
|
+
<!-- File Information -->
|
|
53
|
+
<div class="card" style="margin-bottom: 1.5rem;">
|
|
54
|
+
<div class="card-header">
|
|
55
|
+
<span class="card-title">File Information</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="card-body" style="padding: 0;">
|
|
58
|
+
<div class="detail-row">
|
|
59
|
+
<div class="detail-label">Filename</div>
|
|
60
|
+
<div class="detail-value" style="word-break: break-all;"><%= @medium.filename %></div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="detail-row">
|
|
63
|
+
<div class="detail-label">Type</div>
|
|
64
|
+
<div class="detail-value">
|
|
65
|
+
<span class="badge badge-gray"><%= @medium.content_type %></span>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="detail-row">
|
|
69
|
+
<div class="detail-label">Size</div>
|
|
70
|
+
<div class="detail-value"><%= number_to_human_size(@medium.byte_size) %></div>
|
|
71
|
+
</div>
|
|
72
|
+
<% if @medium.metadata["width"].present? && @medium.metadata["height"].present? %>
|
|
73
|
+
<div class="detail-row">
|
|
74
|
+
<div class="detail-label">Dimensions</div>
|
|
75
|
+
<div class="detail-value"><%= @medium.metadata["width"] %> × <%= @medium.metadata["height"] %> px</div>
|
|
76
|
+
</div>
|
|
77
|
+
<% end %>
|
|
78
|
+
<div class="detail-row">
|
|
79
|
+
<div class="detail-label">Uploaded</div>
|
|
80
|
+
<div class="detail-value"><%= @medium.created_at.strftime("%B %d, %Y at %l:%M %p") %></div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<!-- URL -->
|
|
86
|
+
<div class="card" style="margin-bottom: 1.5rem;">
|
|
87
|
+
<div class="card-header">
|
|
88
|
+
<span class="card-title">URL</span>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="card-body">
|
|
91
|
+
<div class="url-display">
|
|
92
|
+
<code id="media-url"><%= @medium.url %></code>
|
|
93
|
+
<button type="button" class="btn btn-sm btn-secondary" onclick="copyMediaUrl('<%= @medium.url %>')">
|
|
94
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
95
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
96
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
97
|
+
</svg>
|
|
98
|
+
Copy
|
|
99
|
+
</button>
|
|
100
|
+
</div>
|
|
101
|
+
<p class="help-text" style="margin-top: 0.75rem;">Use this URL in your pages or external applications.</p>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<!-- Usage (placeholder for future) -->
|
|
106
|
+
<div class="card" style="margin-bottom: 1.5rem;">
|
|
107
|
+
<div class="card-header">
|
|
108
|
+
<span class="card-title">Embed Code</span>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="card-body">
|
|
111
|
+
<div class="embed-code">
|
|
112
|
+
<pre><code><img src="<%= @medium.url %>" alt="<%= @medium.filename %>" /></code></pre>
|
|
113
|
+
</div>
|
|
114
|
+
<button type="button" class="btn btn-sm btn-secondary" style="margin-top: 0.75rem;" onclick="copyEmbedCode()">
|
|
115
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
116
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
117
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
118
|
+
</svg>
|
|
119
|
+
Copy Embed Code
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- Danger Zone -->
|
|
125
|
+
<div class="card" style="border-color: #fecaca;">
|
|
126
|
+
<div class="card-header" style="background: var(--danger-light);">
|
|
127
|
+
<span class="card-title" style="color: var(--danger);">Danger Zone</span>
|
|
128
|
+
</div>
|
|
129
|
+
<div class="card-body">
|
|
130
|
+
<p style="font-size: 0.875rem; color: var(--text-muted); margin-bottom: 1rem;">
|
|
131
|
+
Deleting this file will remove it permanently. Any pages using this image will show a broken image.
|
|
132
|
+
</p>
|
|
133
|
+
<%= button_to admin_medium_path(@medium), method: :delete, class: "btn btn-danger", style: "width: 100%;", data: { confirm: "Are you sure you want to delete this file? This action cannot be undone." } do %>
|
|
134
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
135
|
+
<polyline points="3 6 5 6 21 6"/>
|
|
136
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
|
137
|
+
<line x1="10" y1="11" x2="10" y2="17"/>
|
|
138
|
+
<line x1="14" y1="11" x2="14" y2="17"/>
|
|
139
|
+
</svg>
|
|
140
|
+
Delete File
|
|
141
|
+
<% end %>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<style>
|
|
148
|
+
.media-preview-container {
|
|
149
|
+
background: var(--sidebar-bg);
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
min-height: 400px;
|
|
154
|
+
padding: 2rem;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.media-preview-image {
|
|
158
|
+
max-width: 100%;
|
|
159
|
+
max-height: 500px;
|
|
160
|
+
object-fit: contain;
|
|
161
|
+
border-radius: var(--radius);
|
|
162
|
+
box-shadow: var(--shadow-md);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.detail-row {
|
|
166
|
+
padding: 0.875rem 1.25rem;
|
|
167
|
+
border-bottom: 1px solid var(--border);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.detail-row:last-child {
|
|
171
|
+
border-bottom: none;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.detail-row .detail-label {
|
|
175
|
+
font-size: 0.6875rem;
|
|
176
|
+
text-transform: uppercase;
|
|
177
|
+
letter-spacing: 0.05em;
|
|
178
|
+
color: var(--text-muted);
|
|
179
|
+
font-weight: 600;
|
|
180
|
+
margin-bottom: 0.25rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.detail-row .detail-value {
|
|
184
|
+
font-size: 0.875rem;
|
|
185
|
+
color: var(--text);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.url-display {
|
|
189
|
+
display: flex;
|
|
190
|
+
gap: 0.75rem;
|
|
191
|
+
align-items: flex-start;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.url-display code {
|
|
195
|
+
flex: 1;
|
|
196
|
+
padding: 0.625rem 0.875rem;
|
|
197
|
+
background: var(--bg-main);
|
|
198
|
+
border: 1px solid var(--border);
|
|
199
|
+
border-radius: var(--radius);
|
|
200
|
+
font-size: 0.75rem;
|
|
201
|
+
word-break: break-all;
|
|
202
|
+
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.embed-code {
|
|
206
|
+
background: var(--sidebar-bg);
|
|
207
|
+
border-radius: var(--radius);
|
|
208
|
+
padding: 0.875rem;
|
|
209
|
+
overflow-x: auto;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.embed-code pre {
|
|
213
|
+
margin: 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.embed-code code {
|
|
217
|
+
color: #e2e8f0;
|
|
218
|
+
font-size: 0.75rem;
|
|
219
|
+
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
|
220
|
+
white-space: pre-wrap;
|
|
221
|
+
word-break: break-all;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Toast notification */
|
|
225
|
+
.toast {
|
|
226
|
+
position: fixed;
|
|
227
|
+
bottom: 2rem;
|
|
228
|
+
right: 2rem;
|
|
229
|
+
background: var(--sidebar-bg);
|
|
230
|
+
color: white;
|
|
231
|
+
padding: 0.875rem 1.25rem;
|
|
232
|
+
border-radius: var(--radius);
|
|
233
|
+
font-size: 0.875rem;
|
|
234
|
+
box-shadow: var(--shadow-md);
|
|
235
|
+
z-index: 1000;
|
|
236
|
+
animation: slideIn 0.3s ease;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.toast.success {
|
|
240
|
+
background: var(--success);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@keyframes slideIn {
|
|
244
|
+
from {
|
|
245
|
+
transform: translateY(1rem);
|
|
246
|
+
opacity: 0;
|
|
247
|
+
}
|
|
248
|
+
to {
|
|
249
|
+
transform: translateY(0);
|
|
250
|
+
opacity: 1;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@media (max-width: 900px) {
|
|
255
|
+
div[style*="grid-template-columns: 1fr 380px"] {
|
|
256
|
+
grid-template-columns: 1fr !important;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
</style>
|
|
260
|
+
|
|
261
|
+
<script>
|
|
262
|
+
function copyMediaUrl(url) {
|
|
263
|
+
const fullUrl = window.location.origin + url;
|
|
264
|
+
navigator.clipboard.writeText(fullUrl).then(() => {
|
|
265
|
+
showToast('URL copied to clipboard!');
|
|
266
|
+
}).catch(() => {
|
|
267
|
+
// Fallback
|
|
268
|
+
const input = document.createElement('input');
|
|
269
|
+
input.value = fullUrl;
|
|
270
|
+
document.body.appendChild(input);
|
|
271
|
+
input.select();
|
|
272
|
+
document.execCommand('copy');
|
|
273
|
+
document.body.removeChild(input);
|
|
274
|
+
showToast('URL copied to clipboard!');
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function copyEmbedCode() {
|
|
279
|
+
const code = document.querySelector('.embed-code code').textContent;
|
|
280
|
+
navigator.clipboard.writeText(code).then(() => {
|
|
281
|
+
showToast('Embed code copied!');
|
|
282
|
+
}).catch(() => {
|
|
283
|
+
showToast('Failed to copy');
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function showToast(message) {
|
|
288
|
+
const toast = document.createElement('div');
|
|
289
|
+
toast.className = 'toast success';
|
|
290
|
+
toast.textContent = message;
|
|
291
|
+
document.body.appendChild(toast);
|
|
292
|
+
|
|
293
|
+
setTimeout(() => {
|
|
294
|
+
toast.remove();
|
|
295
|
+
}, 3000);
|
|
296
|
+
}
|
|
297
|
+
</script>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<% if page_type.errors.any? %>
|
|
2
|
+
<div class="error-messages">
|
|
3
|
+
<strong><%= pluralize(page_type.errors.count, "error") %> prohibited this page type from being saved:</strong>
|
|
4
|
+
<ul>
|
|
5
|
+
<% page_type.errors.full_messages.each do |message| %>
|
|
6
|
+
<li><%= message %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<div class="form-group">
|
|
13
|
+
<%= form.label :name %>
|
|
14
|
+
<%= form.text_field :name, class: "form-control" %>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="form-group">
|
|
18
|
+
<%= form.label :key %>
|
|
19
|
+
<%= form.text_field :key, class: "form-control", placeholder: "Leave blank for auto-generated key" %>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="form-actions">
|
|
23
|
+
<%= form.submit class: "btn btn-primary" %>
|
|
24
|
+
<%= link_to "Cancel", admin_page_types_path, class: "btn btn-secondary" %>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div class="page-header">
|
|
2
|
+
<h2>Edit Page Type</h2>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<div class="card" style="padding: 1.5rem;">
|
|
6
|
+
<%= form_with model: @page_type, url: admin_page_type_path(@page_type) do |form| %>
|
|
7
|
+
<%= render "form", form: form, page_type: @page_type %>
|
|
8
|
+
<% end %>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div style="margin-top: 1rem;">
|
|
12
|
+
<%= button_to "Delete Page Type", admin_page_type_path(@page_type), method: :delete, class: "btn btn-danger", data: { turbo_confirm: "Are you sure you want to delete this page type?" } %>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<div class="page-header">
|
|
2
|
+
<h2>Page Types</h2>
|
|
3
|
+
<%= link_to "New Page Type", new_admin_page_type_path, class: "btn btn-primary" %>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="card">
|
|
7
|
+
<table>
|
|
8
|
+
<thead>
|
|
9
|
+
<tr>
|
|
10
|
+
<th>Name</th>
|
|
11
|
+
<th>Key</th>
|
|
12
|
+
<th>Pages</th>
|
|
13
|
+
<th></th>
|
|
14
|
+
</tr>
|
|
15
|
+
</thead>
|
|
16
|
+
<tbody>
|
|
17
|
+
<% @page_types.each do |page_type| %>
|
|
18
|
+
<tr>
|
|
19
|
+
<td><%= link_to page_type.name, admin_page_type_path(page_type) %></td>
|
|
20
|
+
<td><code><%= page_type.key %></code></td>
|
|
21
|
+
<td><%= page_type.pages.count %></td>
|
|
22
|
+
<td class="actions">
|
|
23
|
+
<%= link_to "Edit", edit_admin_page_type_path(page_type), class: "btn btn-secondary" %>
|
|
24
|
+
</td>
|
|
25
|
+
</tr>
|
|
26
|
+
<% end %>
|
|
27
|
+
</tbody>
|
|
28
|
+
</table>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<div class="page-header">
|
|
2
|
+
<h2><%= @page_type.name %></h2>
|
|
3
|
+
<div class="actions">
|
|
4
|
+
<%= link_to "Edit", edit_admin_page_type_path(@page_type), class: "btn btn-secondary" %>
|
|
5
|
+
<%= link_to "Back", admin_page_types_path, class: "btn btn-secondary" %>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="card">
|
|
10
|
+
<div class="detail-row">
|
|
11
|
+
<div class="detail-label">Key</div>
|
|
12
|
+
<div class="detail-value"><code><%= @page_type.key %></code></div>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="detail-row">
|
|
15
|
+
<div class="detail-label">Pages using this type</div>
|
|
16
|
+
<div class="detail-value"><%= @page_type.pages.count %></div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|