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,333 @@
|
|
|
1
|
+
<% content_for :page_title, "#{@page.title} - Version History" %>
|
|
2
|
+
|
|
3
|
+
<style>
|
|
4
|
+
.version-timeline {
|
|
5
|
+
position: relative;
|
|
6
|
+
padding-left: 2rem;
|
|
7
|
+
}
|
|
8
|
+
.version-timeline::before {
|
|
9
|
+
content: '';
|
|
10
|
+
position: absolute;
|
|
11
|
+
left: 0.5rem;
|
|
12
|
+
top: 0;
|
|
13
|
+
bottom: 0;
|
|
14
|
+
width: 2px;
|
|
15
|
+
background: var(--border);
|
|
16
|
+
}
|
|
17
|
+
.version-item {
|
|
18
|
+
position: relative;
|
|
19
|
+
padding-bottom: 1.5rem;
|
|
20
|
+
}
|
|
21
|
+
.version-item:last-child {
|
|
22
|
+
padding-bottom: 0;
|
|
23
|
+
}
|
|
24
|
+
.version-dot {
|
|
25
|
+
position: absolute;
|
|
26
|
+
left: -1.75rem;
|
|
27
|
+
top: 0.25rem;
|
|
28
|
+
width: 1rem;
|
|
29
|
+
height: 1rem;
|
|
30
|
+
background: var(--primary);
|
|
31
|
+
border-radius: 50%;
|
|
32
|
+
border: 3px solid var(--bg-card);
|
|
33
|
+
box-shadow: 0 0 0 2px var(--primary);
|
|
34
|
+
}
|
|
35
|
+
.version-dot.first {
|
|
36
|
+
background: var(--success);
|
|
37
|
+
box-shadow: 0 0 0 2px var(--success);
|
|
38
|
+
}
|
|
39
|
+
.version-card {
|
|
40
|
+
background: var(--bg-card);
|
|
41
|
+
border: 1px solid var(--border);
|
|
42
|
+
border-radius: var(--radius);
|
|
43
|
+
padding: 1rem;
|
|
44
|
+
transition: box-shadow 0.15s ease;
|
|
45
|
+
}
|
|
46
|
+
.version-card:hover {
|
|
47
|
+
box-shadow: var(--shadow-md);
|
|
48
|
+
}
|
|
49
|
+
.version-header {
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: space-between;
|
|
53
|
+
margin-bottom: 0.75rem;
|
|
54
|
+
}
|
|
55
|
+
.version-number {
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
font-size: 0.9375rem;
|
|
58
|
+
color: var(--text);
|
|
59
|
+
display: inline-flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
transition: color 0.15s ease;
|
|
62
|
+
}
|
|
63
|
+
.version-number:hover {
|
|
64
|
+
color: var(--primary);
|
|
65
|
+
}
|
|
66
|
+
.version-number:hover svg {
|
|
67
|
+
opacity: 1;
|
|
68
|
+
}
|
|
69
|
+
.version-time {
|
|
70
|
+
font-size: 0.75rem;
|
|
71
|
+
color: var(--text-muted);
|
|
72
|
+
}
|
|
73
|
+
.version-meta {
|
|
74
|
+
display: flex;
|
|
75
|
+
gap: 1rem;
|
|
76
|
+
flex-wrap: wrap;
|
|
77
|
+
font-size: 0.8125rem;
|
|
78
|
+
color: var(--text-muted);
|
|
79
|
+
}
|
|
80
|
+
.version-meta-item {
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
gap: 0.375rem;
|
|
84
|
+
}
|
|
85
|
+
.version-meta-item svg {
|
|
86
|
+
width: 14px;
|
|
87
|
+
height: 14px;
|
|
88
|
+
opacity: 0.7;
|
|
89
|
+
}
|
|
90
|
+
.version-changes {
|
|
91
|
+
margin-top: 0.75rem;
|
|
92
|
+
padding-top: 0.75rem;
|
|
93
|
+
border-top: 1px solid var(--border);
|
|
94
|
+
}
|
|
95
|
+
.version-diff {
|
|
96
|
+
margin-top: 0.75rem;
|
|
97
|
+
}
|
|
98
|
+
.version-diff-toggle {
|
|
99
|
+
font-size: 0.75rem;
|
|
100
|
+
color: var(--primary);
|
|
101
|
+
background: none;
|
|
102
|
+
border: none;
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
padding: 0;
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 0.25rem;
|
|
108
|
+
}
|
|
109
|
+
.version-diff-toggle:hover {
|
|
110
|
+
text-decoration: underline;
|
|
111
|
+
}
|
|
112
|
+
.version-diff-content {
|
|
113
|
+
display: none;
|
|
114
|
+
margin-top: 0.5rem;
|
|
115
|
+
background: #1e293b;
|
|
116
|
+
border-radius: var(--radius);
|
|
117
|
+
padding: 0.75rem;
|
|
118
|
+
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
119
|
+
font-size: 0.6875rem;
|
|
120
|
+
line-height: 1.5;
|
|
121
|
+
max-height: 300px;
|
|
122
|
+
overflow: auto;
|
|
123
|
+
}
|
|
124
|
+
.version-diff-content.show {
|
|
125
|
+
display: block;
|
|
126
|
+
}
|
|
127
|
+
.diff-line {
|
|
128
|
+
white-space: pre-wrap;
|
|
129
|
+
word-break: break-all;
|
|
130
|
+
}
|
|
131
|
+
.diff-line.added {
|
|
132
|
+
color: #4ade80;
|
|
133
|
+
background: rgba(74, 222, 128, 0.1);
|
|
134
|
+
}
|
|
135
|
+
.diff-line.removed {
|
|
136
|
+
color: #f87171;
|
|
137
|
+
background: rgba(248, 113, 113, 0.1);
|
|
138
|
+
}
|
|
139
|
+
.diff-line.unchanged {
|
|
140
|
+
color: #94a3b8;
|
|
141
|
+
}
|
|
142
|
+
.size-change {
|
|
143
|
+
display: inline-flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
gap: 0.25rem;
|
|
146
|
+
padding: 0.125rem 0.5rem;
|
|
147
|
+
border-radius: 9999px;
|
|
148
|
+
font-size: 0.6875rem;
|
|
149
|
+
font-weight: 500;
|
|
150
|
+
}
|
|
151
|
+
.size-change.positive {
|
|
152
|
+
background: var(--success-light);
|
|
153
|
+
color: var(--success);
|
|
154
|
+
}
|
|
155
|
+
.size-change.negative {
|
|
156
|
+
background: var(--danger-light);
|
|
157
|
+
color: var(--danger);
|
|
158
|
+
}
|
|
159
|
+
.size-change.neutral {
|
|
160
|
+
background: var(--bg-main);
|
|
161
|
+
color: var(--text-muted);
|
|
162
|
+
}
|
|
163
|
+
.empty-versions {
|
|
164
|
+
text-align: center;
|
|
165
|
+
padding: 3rem;
|
|
166
|
+
color: var(--text-muted);
|
|
167
|
+
}
|
|
168
|
+
.empty-versions svg {
|
|
169
|
+
width: 48px;
|
|
170
|
+
height: 48px;
|
|
171
|
+
margin-bottom: 1rem;
|
|
172
|
+
opacity: 0.5;
|
|
173
|
+
}
|
|
174
|
+
</style>
|
|
175
|
+
|
|
176
|
+
<!-- Page Header -->
|
|
177
|
+
<div class="page-header">
|
|
178
|
+
<div class="page-header-left">
|
|
179
|
+
<h2>Version History</h2>
|
|
180
|
+
<p class="page-header-subtitle">
|
|
181
|
+
<%= @page.title %> · <%= @page.versions.count %> versions
|
|
182
|
+
</p>
|
|
183
|
+
</div>
|
|
184
|
+
<div class="page-header-actions">
|
|
185
|
+
<%= link_to admin_page_path(@page), class: "btn btn-secondary" do %>
|
|
186
|
+
<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">
|
|
187
|
+
<line x1="19" y1="12" x2="5" y2="12"/>
|
|
188
|
+
<polyline points="12 19 5 12 12 5"/>
|
|
189
|
+
</svg>
|
|
190
|
+
Back to Page
|
|
191
|
+
<% end %>
|
|
192
|
+
<%= link_to editor_admin_page_path(@page), class: "btn btn-primary" do %>
|
|
193
|
+
<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">
|
|
194
|
+
<polygon points="12 2 2 7 12 12 22 7 12 2"/>
|
|
195
|
+
<polyline points="2 17 12 22 22 17"/>
|
|
196
|
+
<polyline points="2 12 12 17 22 12"/>
|
|
197
|
+
</svg>
|
|
198
|
+
Open Editor
|
|
199
|
+
<% end %>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<!-- Timeline -->
|
|
204
|
+
<div class="card">
|
|
205
|
+
<div class="card-body">
|
|
206
|
+
<% if @versions.any? %>
|
|
207
|
+
<div class="version-timeline">
|
|
208
|
+
<% @versions.each_with_index do |version, index| %>
|
|
209
|
+
<div class="version-item">
|
|
210
|
+
<div class="version-dot <%= 'first' if index == 0 %>"></div>
|
|
211
|
+
<div class="version-card">
|
|
212
|
+
<div class="version-header">
|
|
213
|
+
<%= link_to admin_page_version_path(@page, version), class: "version-number", style: "text-decoration: none; color: inherit;" do %>
|
|
214
|
+
Version <%= version.version_number %>
|
|
215
|
+
<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" style="margin-left: 0.25rem; opacity: 0.5;">
|
|
216
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
|
|
217
|
+
<polyline points="15 3 21 3 21 9"/>
|
|
218
|
+
<line x1="10" y1="14" x2="21" y2="3"/>
|
|
219
|
+
</svg>
|
|
220
|
+
<% end %>
|
|
221
|
+
<span class="version-time">
|
|
222
|
+
<%= time_ago_in_words(version.created_at) %> ago
|
|
223
|
+
<span style="color: var(--text-light);">· <%= version.created_at.strftime("%b %d, %Y at %l:%M %p") %></span>
|
|
224
|
+
</span>
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
<div class="version-meta">
|
|
228
|
+
<% if version.changed_by.present? %>
|
|
229
|
+
<div class="version-meta-item">
|
|
230
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
231
|
+
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
|
|
232
|
+
<circle cx="12" cy="7" r="4"/>
|
|
233
|
+
</svg>
|
|
234
|
+
<%= version.changed_by %>
|
|
235
|
+
</div>
|
|
236
|
+
<% end %>
|
|
237
|
+
|
|
238
|
+
<div class="version-meta-item">
|
|
239
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
240
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
|
241
|
+
<polyline points="14 2 14 8 20 8"/>
|
|
242
|
+
</svg>
|
|
243
|
+
<%= number_to_human_size(version.content_size_after || 0) %>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
<div class="version-meta-item">
|
|
247
|
+
<% diff = version.size_difference %>
|
|
248
|
+
<% if diff > 0 %>
|
|
249
|
+
<span class="size-change positive">+<%= number_to_human_size(diff) %></span>
|
|
250
|
+
<% elsif diff < 0 %>
|
|
251
|
+
<span class="size-change negative"><%= number_to_human_size(diff) %></span>
|
|
252
|
+
<% else %>
|
|
253
|
+
<span class="size-change neutral">No size change</span>
|
|
254
|
+
<% end %>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<% if version.change_summary.present? %>
|
|
259
|
+
<div class="version-changes">
|
|
260
|
+
<span style="font-size: 0.8125rem; color: var(--text-muted);">
|
|
261
|
+
<%= version.change_summary.capitalize %>
|
|
262
|
+
</span>
|
|
263
|
+
</div>
|
|
264
|
+
<% end %>
|
|
265
|
+
|
|
266
|
+
<div class="version-actions" style="margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--border); display: flex; gap: 0.5rem; align-items: center;">
|
|
267
|
+
<% if version.content_diff.present? %>
|
|
268
|
+
<button type="button" class="version-diff-toggle" onclick="toggleDiff(this)">
|
|
269
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
270
|
+
<polyline points="9 18 15 12 9 6"/>
|
|
271
|
+
</svg>
|
|
272
|
+
Quick diff
|
|
273
|
+
</button>
|
|
274
|
+
<% end %>
|
|
275
|
+
<%= link_to admin_page_version_path(@page, version), class: "btn btn-secondary btn-sm", style: "margin-left: auto;" do %>
|
|
276
|
+
<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">
|
|
277
|
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
|
|
278
|
+
<circle cx="12" cy="12" r="3"/>
|
|
279
|
+
</svg>
|
|
280
|
+
View Details
|
|
281
|
+
<% end %>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<% if version.content_diff.present? %>
|
|
285
|
+
<div class="version-diff-content">
|
|
286
|
+
<% version.content_diff.to_s.lines.first(100).each do |line| %>
|
|
287
|
+
<% css_class = if line.start_with?('+')
|
|
288
|
+
'added'
|
|
289
|
+
elsif line.start_with?('-')
|
|
290
|
+
'removed'
|
|
291
|
+
else
|
|
292
|
+
'unchanged'
|
|
293
|
+
end %>
|
|
294
|
+
<div class="diff-line <%= css_class %>"><%= line %></div>
|
|
295
|
+
<% end %>
|
|
296
|
+
<% if version.content_diff.to_s.lines.size > 100 %>
|
|
297
|
+
<div class="diff-line unchanged" style="color: var(--text-muted); font-style: italic;">
|
|
298
|
+
... <%= version.content_diff.to_s.lines.size - 100 %> more lines
|
|
299
|
+
</div>
|
|
300
|
+
<% end %>
|
|
301
|
+
</div>
|
|
302
|
+
<% end %>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
<% end %>
|
|
306
|
+
</div>
|
|
307
|
+
<% else %>
|
|
308
|
+
<div class="empty-versions">
|
|
309
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
310
|
+
<circle cx="12" cy="12" r="10"/>
|
|
311
|
+
<polyline points="12 6 12 12 16 14"/>
|
|
312
|
+
</svg>
|
|
313
|
+
<h3 style="font-size: 1rem; margin-bottom: 0.5rem;">No version history yet</h3>
|
|
314
|
+
<p style="font-size: 0.875rem;">Changes will be tracked when you edit and save the page.</p>
|
|
315
|
+
</div>
|
|
316
|
+
<% end %>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
<script>
|
|
321
|
+
function toggleDiff(button) {
|
|
322
|
+
const card = button.closest('.version-card');
|
|
323
|
+
const content = card.querySelector('.version-diff-content');
|
|
324
|
+
|
|
325
|
+
if (content.classList.contains('show')) {
|
|
326
|
+
content.classList.remove('show');
|
|
327
|
+
button.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg> Quick diff';
|
|
328
|
+
} else {
|
|
329
|
+
content.classList.add('show');
|
|
330
|
+
button.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg> Hide diff';
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
</script>
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<% content_for :page_title, "Edit #{@partial.name}" %>
|
|
2
|
+
|
|
3
|
+
<!-- Page Header -->
|
|
4
|
+
<div class="page-header">
|
|
5
|
+
<div class="page-header-left">
|
|
6
|
+
<div style="display: flex; align-items: center; gap: 0.75rem;">
|
|
7
|
+
<h2>Edit <%= @partial.name %></h2>
|
|
8
|
+
<% if @partial.active? %>
|
|
9
|
+
<span class="badge badge-success">
|
|
10
|
+
<span class="badge-dot"></span>
|
|
11
|
+
Active
|
|
12
|
+
</span>
|
|
13
|
+
<% else %>
|
|
14
|
+
<span class="badge badge-gray">
|
|
15
|
+
<span class="badge-dot"></span>
|
|
16
|
+
Inactive
|
|
17
|
+
</span>
|
|
18
|
+
<% end %>
|
|
19
|
+
</div>
|
|
20
|
+
<p class="page-header-subtitle">
|
|
21
|
+
<span style="display: inline-flex; align-items: center; gap: 0.5rem;">
|
|
22
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="<%= @partial.header? ? '#6366f1' : '#10b981' %>" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
23
|
+
<% if @partial.header? %>
|
|
24
|
+
<rect x="3" y="3" width="18" height="6" rx="2"/>
|
|
25
|
+
<rect x="3" y="13" width="18" height="8" rx="2" opacity="0.3"/>
|
|
26
|
+
<% else %>
|
|
27
|
+
<rect x="3" y="3" width="18" height="8" rx="2" opacity="0.3"/>
|
|
28
|
+
<rect x="3" y="15" width="18" height="6" rx="2"/>
|
|
29
|
+
<% end %>
|
|
30
|
+
</svg>
|
|
31
|
+
<%= @partial.partial_type.capitalize %> partial
|
|
32
|
+
</span>
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="page-header-actions">
|
|
36
|
+
<%= link_to editor_admin_partial_path(@partial), class: "btn btn-primary" do %>
|
|
37
|
+
<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">
|
|
38
|
+
<polygon points="12 2 2 7 12 12 22 7 12 2"/>
|
|
39
|
+
<polyline points="2 17 12 22 22 17"/>
|
|
40
|
+
<polyline points="2 12 12 17 22 12"/>
|
|
41
|
+
</svg>
|
|
42
|
+
Open Designer
|
|
43
|
+
<% end %>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<!-- Two Column Layout -->
|
|
48
|
+
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem; align-items: start;">
|
|
49
|
+
<!-- Main Column -->
|
|
50
|
+
<div>
|
|
51
|
+
<%= form_with model: @partial, url: admin_partial_path(@partial), method: :patch do |f| %>
|
|
52
|
+
<% if @partial.errors.any? %>
|
|
53
|
+
<div class="error-messages" style="margin-bottom: 1.5rem;">
|
|
54
|
+
<strong><%= pluralize(@partial.errors.count, "error") %> prohibited this partial from being saved:</strong>
|
|
55
|
+
<ul>
|
|
56
|
+
<% @partial.errors.full_messages.each do |message| %>
|
|
57
|
+
<li><%= message %></li>
|
|
58
|
+
<% end %>
|
|
59
|
+
</ul>
|
|
60
|
+
</div>
|
|
61
|
+
<% end %>
|
|
62
|
+
|
|
63
|
+
<!-- Settings Card -->
|
|
64
|
+
<div class="card" style="margin-bottom: 1.5rem;">
|
|
65
|
+
<div class="card-header">
|
|
66
|
+
<span class="card-title">
|
|
67
|
+
<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" style="vertical-align: -2px; margin-right: 0.5rem;">
|
|
68
|
+
<circle cx="12" cy="12" r="3"/>
|
|
69
|
+
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
|
70
|
+
</svg>
|
|
71
|
+
Settings
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="card-body">
|
|
75
|
+
<div class="form-group">
|
|
76
|
+
<%= f.label :name %>
|
|
77
|
+
<%= f.text_field :name, class: "form-control", placeholder: "e.g., Main Header" %>
|
|
78
|
+
<p class="help-text">A friendly name to identify this partial in the admin.</p>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div class="form-group" style="margin-bottom: 0;">
|
|
82
|
+
<label style="font-weight: 500; margin-bottom: 0.5rem; display: block;">Visibility</label>
|
|
83
|
+
<div style="background: var(--bg-main, #f8fafc); padding: 1rem; border-radius: 0.5rem; border: 1px solid var(--border, #e2e8f0);">
|
|
84
|
+
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
|
85
|
+
<%= f.check_box :active, id: "partial_active" %>
|
|
86
|
+
<label for="partial_active" style="font-weight: 500; margin: 0;">
|
|
87
|
+
Active
|
|
88
|
+
</label>
|
|
89
|
+
</div>
|
|
90
|
+
<p class="help-text" style="margin-top: 0.5rem; margin-bottom: 0;">
|
|
91
|
+
When active, this <%= @partial.partial_type %> will appear on pages that have it enabled.
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<!-- Form Actions -->
|
|
99
|
+
<div class="form-actions" style="background: var(--bg-card, white); padding: 1.25rem; border-radius: 0.5rem; border: 1px solid var(--border, #e2e8f0);">
|
|
100
|
+
<%= f.submit "Save Settings", class: "btn btn-primary" %>
|
|
101
|
+
<%= link_to "Cancel", admin_partials_path, class: "btn btn-secondary" %>
|
|
102
|
+
</div>
|
|
103
|
+
<% end %>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<!-- Sidebar Column -->
|
|
107
|
+
<div>
|
|
108
|
+
<!-- Quick Actions -->
|
|
109
|
+
<div class="card" style="margin-bottom: 1.5rem;">
|
|
110
|
+
<div class="card-header">
|
|
111
|
+
<span class="card-title">Actions</span>
|
|
112
|
+
</div>
|
|
113
|
+
<div style="padding: 1rem;">
|
|
114
|
+
<%= link_to editor_admin_partial_path(@partial), class: "btn btn-primary", style: "width: 100%; justify-content: center; margin-bottom: 0.75rem;" do %>
|
|
115
|
+
<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">
|
|
116
|
+
<polygon points="12 2 2 7 12 12 22 7 12 2"/>
|
|
117
|
+
<polyline points="2 17 12 22 22 17"/>
|
|
118
|
+
<polyline points="2 12 12 17 22 12"/>
|
|
119
|
+
</svg>
|
|
120
|
+
Open Designer
|
|
121
|
+
<% end %>
|
|
122
|
+
<%= link_to admin_partials_path, class: "btn btn-secondary", style: "width: 100%; justify-content: center;" do %>
|
|
123
|
+
<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">
|
|
124
|
+
<line x1="19" y1="12" x2="5" y2="12"/>
|
|
125
|
+
<polyline points="12 19 5 12 12 5"/>
|
|
126
|
+
</svg>
|
|
127
|
+
Back to Partials
|
|
128
|
+
<% end %>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<!-- Status Info -->
|
|
133
|
+
<div class="card" style="margin-bottom: 1.5rem;">
|
|
134
|
+
<div class="card-header">
|
|
135
|
+
<span class="card-title">Status</span>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="card-body" style="padding: 0;">
|
|
138
|
+
<div style="padding: 0.875rem 1rem; border-bottom: 1px solid var(--border);">
|
|
139
|
+
<div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Content</div>
|
|
140
|
+
<div style="font-size: 0.9375rem;">
|
|
141
|
+
<% if @partial.content.present? %>
|
|
142
|
+
<span style="color: var(--success);">Configured</span>
|
|
143
|
+
<span style="color: var(--text-muted); font-size: 0.8125rem; margin-left: 0.5rem;">(<%= number_to_human_size(@partial.content.bytesize) %>)</span>
|
|
144
|
+
<% else %>
|
|
145
|
+
<span style="color: var(--text-muted);">Empty</span>
|
|
146
|
+
<% end %>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
<div style="padding: 0.875rem 1rem; border-bottom: 1px solid var(--border);">
|
|
150
|
+
<div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Tailwind CSS</div>
|
|
151
|
+
<div style="font-size: 0.9375rem;">
|
|
152
|
+
<% if @partial.compiled_css.present? %>
|
|
153
|
+
<span style="color: var(--success);"><%= number_to_human_size(@partial.compiled_css.bytesize) %></span>
|
|
154
|
+
<% else %>
|
|
155
|
+
<span style="color: var(--text-muted);">Not compiled</span>
|
|
156
|
+
<% end %>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
<div style="padding: 0.875rem 1rem;">
|
|
160
|
+
<div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Last Updated</div>
|
|
161
|
+
<div style="font-size: 0.9375rem;"><%= @partial.updated_at.strftime("%b %d, %Y at %l:%M %p") %></div>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<!-- Info Box -->
|
|
167
|
+
<div class="card">
|
|
168
|
+
<div style="padding: 1rem;">
|
|
169
|
+
<div style="display: flex; align-items: flex-start; gap: 0.75rem;">
|
|
170
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--text-muted)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink: 0; margin-top: 2px;">
|
|
171
|
+
<circle cx="12" cy="12" r="10"/>
|
|
172
|
+
<path d="M12 16v-4"/>
|
|
173
|
+
<path d="M12 8h.01"/>
|
|
174
|
+
</svg>
|
|
175
|
+
<div style="font-size: 0.8125rem; color: var(--text-muted); line-height: 1.5;">
|
|
176
|
+
This <%= @partial.partial_type %> appears at the <%= @partial.header? ? 'top' : 'bottom' %> of pages that have it enabled.
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|