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.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +318 -0
  4. data/Rakefile +6 -0
  5. data/app/assets/javascripts/active_canvas/editor/ai_panel.js +1607 -0
  6. data/app/assets/javascripts/active_canvas/editor/asset_manager.js +498 -0
  7. data/app/assets/javascripts/active_canvas/editor/blocks.js +1083 -0
  8. data/app/assets/javascripts/active_canvas/editor/code_panel.js +572 -0
  9. data/app/assets/javascripts/active_canvas/editor/component_toolbar.js +394 -0
  10. data/app/assets/javascripts/active_canvas/editor/panels.js +460 -0
  11. data/app/assets/javascripts/active_canvas/editor/utils.js +56 -0
  12. data/app/assets/javascripts/active_canvas/editor.js +295 -0
  13. data/app/assets/stylesheets/active_canvas/application.css +15 -0
  14. data/app/assets/stylesheets/active_canvas/editor.css +2929 -0
  15. data/app/controllers/active_canvas/admin/ai_controller.rb +181 -0
  16. data/app/controllers/active_canvas/admin/application_controller.rb +56 -0
  17. data/app/controllers/active_canvas/admin/media_controller.rb +61 -0
  18. data/app/controllers/active_canvas/admin/page_types_controller.rb +57 -0
  19. data/app/controllers/active_canvas/admin/page_versions_controller.rb +23 -0
  20. data/app/controllers/active_canvas/admin/pages_controller.rb +133 -0
  21. data/app/controllers/active_canvas/admin/partials_controller.rb +88 -0
  22. data/app/controllers/active_canvas/admin/settings_controller.rb +256 -0
  23. data/app/controllers/active_canvas/application_controller.rb +20 -0
  24. data/app/controllers/active_canvas/pages_controller.rb +18 -0
  25. data/app/controllers/concerns/active_canvas/current_user.rb +12 -0
  26. data/app/controllers/concerns/active_canvas/rate_limitable.rb +75 -0
  27. data/app/controllers/concerns/active_canvas/tailwind_compilation.rb +39 -0
  28. data/app/helpers/active_canvas/application_helper.rb +4 -0
  29. data/app/jobs/active_canvas/application_job.rb +4 -0
  30. data/app/jobs/active_canvas/compile_tailwind_job.rb +64 -0
  31. data/app/mailers/active_canvas/application_mailer.rb +6 -0
  32. data/app/models/active_canvas/ai_model.rb +136 -0
  33. data/app/models/active_canvas/application_record.rb +5 -0
  34. data/app/models/active_canvas/media.rb +141 -0
  35. data/app/models/active_canvas/page.rb +85 -0
  36. data/app/models/active_canvas/page_type.rb +22 -0
  37. data/app/models/active_canvas/page_version.rb +80 -0
  38. data/app/models/active_canvas/partial.rb +73 -0
  39. data/app/models/active_canvas/setting.rb +292 -0
  40. data/app/services/active_canvas/ai_configuration.rb +40 -0
  41. data/app/services/active_canvas/ai_models.rb +128 -0
  42. data/app/services/active_canvas/ai_service.rb +289 -0
  43. data/app/services/active_canvas/content_sanitizer.rb +112 -0
  44. data/app/services/active_canvas/tailwind_compiler.rb +156 -0
  45. data/app/views/active_canvas/admin/media/index.html.erb +401 -0
  46. data/app/views/active_canvas/admin/media/show.html.erb +297 -0
  47. data/app/views/active_canvas/admin/page_types/_form.html.erb +25 -0
  48. data/app/views/active_canvas/admin/page_types/edit.html.erb +13 -0
  49. data/app/views/active_canvas/admin/page_types/index.html.erb +29 -0
  50. data/app/views/active_canvas/admin/page_types/new.html.erb +9 -0
  51. data/app/views/active_canvas/admin/page_types/show.html.erb +18 -0
  52. data/app/views/active_canvas/admin/page_versions/show.html.erb +469 -0
  53. data/app/views/active_canvas/admin/pages/_form.html.erb +62 -0
  54. data/app/views/active_canvas/admin/pages/content.html.erb +139 -0
  55. data/app/views/active_canvas/admin/pages/edit.html.erb +335 -0
  56. data/app/views/active_canvas/admin/pages/editor.html.erb +710 -0
  57. data/app/views/active_canvas/admin/pages/index.html.erb +149 -0
  58. data/app/views/active_canvas/admin/pages/new.html.erb +19 -0
  59. data/app/views/active_canvas/admin/pages/show.html.erb +258 -0
  60. data/app/views/active_canvas/admin/pages/versions.html.erb +333 -0
  61. data/app/views/active_canvas/admin/partials/edit.html.erb +182 -0
  62. data/app/views/active_canvas/admin/partials/editor.html.erb +703 -0
  63. data/app/views/active_canvas/admin/partials/index.html.erb +131 -0
  64. data/app/views/active_canvas/admin/settings/show.html.erb +1864 -0
  65. data/app/views/active_canvas/pages/no_homepage.html.erb +45 -0
  66. data/app/views/active_canvas/pages/show.html.erb +113 -0
  67. data/app/views/layouts/active_canvas/admin/application.html.erb +960 -0
  68. data/app/views/layouts/active_canvas/admin/editor.html.erb +826 -0
  69. data/app/views/layouts/active_canvas/application.html.erb +55 -0
  70. data/config/routes.rb +48 -0
  71. data/db/migrate/20260202000001_create_active_canvas_tables.rb +113 -0
  72. data/db/migrate/20260202000002_create_active_canvas_ai_models.rb +26 -0
  73. data/lib/active_canvas/configuration.rb +232 -0
  74. data/lib/active_canvas/engine.rb +44 -0
  75. data/lib/active_canvas/version.rb +3 -0
  76. data/lib/active_canvas.rb +26 -0
  77. data/lib/generators/active_canvas/install/install_generator.rb +263 -0
  78. data/lib/generators/active_canvas/install/templates/initializer.rb.tt +163 -0
  79. data/lib/tasks/active_canvas_tasks.rake +69 -0
  80. metadata +150 -0
@@ -0,0 +1,149 @@
1
+ <% content_for :page_title, "Pages" %>
2
+
3
+ <!-- Stats -->
4
+ <div class="stats-grid">
5
+ <div class="stat-card">
6
+ <div class="stat-icon stat-icon-primary">
7
+ <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">
8
+ <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
9
+ <polyline points="14 2 14 8 20 8"/>
10
+ </svg>
11
+ </div>
12
+ <div class="stat-content">
13
+ <h3><%= @pages.count %></h3>
14
+ <p>Total Pages</p>
15
+ </div>
16
+ </div>
17
+ <div class="stat-card">
18
+ <div class="stat-icon stat-icon-success">
19
+ <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">
20
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
21
+ <polyline points="22 4 12 14.01 9 11.01"/>
22
+ </svg>
23
+ </div>
24
+ <div class="stat-content">
25
+ <h3><%= @pages.where(published: true).count %></h3>
26
+ <p>Published</p>
27
+ </div>
28
+ </div>
29
+ <div class="stat-card">
30
+ <div class="stat-icon stat-icon-warning">
31
+ <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">
32
+ <path d="M12 20h9"/>
33
+ <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
34
+ </svg>
35
+ </div>
36
+ <div class="stat-content">
37
+ <h3><%= @pages.where(published: false).count %></h3>
38
+ <p>Drafts</p>
39
+ </div>
40
+ </div>
41
+ <div class="stat-card">
42
+ <div class="stat-icon stat-icon-info">
43
+ <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">
44
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
45
+ <circle cx="8.5" cy="8.5" r="1.5"/>
46
+ <polyline points="21 15 16 10 5 21"/>
47
+ </svg>
48
+ </div>
49
+ <div class="stat-content">
50
+ <h3><%= @media_count %></h3>
51
+ <p>Media (<%= number_to_human_size(@media_total_size) %>)</p>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <!-- Page Header -->
57
+ <div class="page-header">
58
+ <div class="page-header-left">
59
+ <h2>All Pages</h2>
60
+ <p class="page-header-subtitle">Manage your website pages and content</p>
61
+ </div>
62
+ </div>
63
+
64
+ <!-- Pages Table -->
65
+ <% if @pages.any? %>
66
+ <div class="card">
67
+ <table>
68
+ <thead>
69
+ <tr>
70
+ <th>Title</th>
71
+ <th>URL</th>
72
+ <th>Status</th>
73
+ <th>Last Updated</th>
74
+ <th></th>
75
+ </tr>
76
+ </thead>
77
+ <tbody>
78
+ <% @pages.each do |page| %>
79
+ <tr>
80
+ <td>
81
+ <div style="display: flex; flex-direction: column; gap: 0.125rem;">
82
+ <%= link_to page.title, admin_page_path(page) %>
83
+ <span style="font-size: 0.75rem; color: var(--text-muted);"><%= page.page_type.name %></span>
84
+ </div>
85
+ </td>
86
+ <td>
87
+ <% if page.slug.present? %>
88
+ <code>/<%= page.slug %></code>
89
+ <% else %>
90
+ <span style="color: var(--text-light);">—</span>
91
+ <% end %>
92
+ </td>
93
+ <td>
94
+ <% if page.published? %>
95
+ <span class="badge badge-success">
96
+ <span class="badge-dot"></span>
97
+ Published
98
+ </span>
99
+ <% else %>
100
+ <span class="badge badge-gray">
101
+ <span class="badge-dot"></span>
102
+ Draft
103
+ </span>
104
+ <% end %>
105
+ </td>
106
+ <td>
107
+ <span style="color: var(--text-muted);"><%= page.updated_at.strftime("%b %d, %Y at %l:%M %p") %></span>
108
+ </td>
109
+ <td class="actions">
110
+ <%= link_to editor_admin_page_path(page), class: "btn btn-primary btn-sm" do %>
111
+ <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">
112
+ <polygon points="12 2 2 7 12 12 22 7 12 2"/>
113
+ <polyline points="2 17 12 22 22 17"/>
114
+ <polyline points="2 12 12 17 22 12"/>
115
+ </svg>
116
+ Design
117
+ <% end %>
118
+ <%= link_to edit_admin_page_path(page), class: "btn btn-secondary btn-sm" do %>
119
+ <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">
120
+ <path d="M12 20h9"/>
121
+ <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
122
+ </svg>
123
+ Edit
124
+ <% end %>
125
+ </td>
126
+ </tr>
127
+ <% end %>
128
+ </tbody>
129
+ </table>
130
+ </div>
131
+ <% else %>
132
+ <div class="card">
133
+ <div class="empty-state">
134
+ <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">
135
+ <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
136
+ <polyline points="14 2 14 8 20 8"/>
137
+ </svg>
138
+ <h3>No pages yet</h3>
139
+ <p>Get started by creating your first page</p>
140
+ <%= link_to new_admin_page_path, class: "btn btn-primary" do %>
141
+ <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">
142
+ <line x1="12" y1="5" x2="12" y2="19"/>
143
+ <line x1="5" y1="12" x2="19" y2="12"/>
144
+ </svg>
145
+ Create Page
146
+ <% end %>
147
+ </div>
148
+ </div>
149
+ <% end %>
@@ -0,0 +1,19 @@
1
+ <% content_for :page_title, "New Page" %>
2
+
3
+ <div class="page-header">
4
+ <div class="page-header-left">
5
+ <h2>New Page</h2>
6
+ <p class="page-header-subtitle">Create a new page for your website</p>
7
+ </div>
8
+ </div>
9
+
10
+ <div class="card">
11
+ <div class="card-header">
12
+ <span class="card-title">Page Details</span>
13
+ </div>
14
+ <div class="card-body">
15
+ <%= form_with model: @page, url: admin_pages_path do |form| %>
16
+ <%= render "form", form: form, page: @page %>
17
+ <% end %>
18
+ </div>
19
+ </div>
@@ -0,0 +1,258 @@
1
+ <% content_for :page_title, @page.title %>
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><%= @page.title %></h2>
8
+ <% if @page.published? %>
9
+ <span class="badge badge-success">
10
+ <span class="badge-dot"></span>
11
+ Published
12
+ </span>
13
+ <% else %>
14
+ <span class="badge badge-gray">
15
+ <span class="badge-dot"></span>
16
+ Draft
17
+ </span>
18
+ <% end %>
19
+ </div>
20
+ <p class="page-header-subtitle">
21
+ <% if @page.slug.present? %>
22
+ <code style="font-size: 0.8125rem; background: var(--bg-main); padding: 0.25rem 0.5rem; border-radius: 4px;">/<%= @page.slug %></code>
23
+ <% else %>
24
+ <span style="color: var(--text-muted);">No URL assigned</span>
25
+ <% end %>
26
+ </p>
27
+ </div>
28
+ <div class="page-header-actions">
29
+ <%= link_to editor_admin_page_path(@page), class: "btn btn-primary" do %>
30
+ <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">
31
+ <polygon points="12 2 2 7 12 12 22 7 12 2"/>
32
+ <polyline points="2 17 12 22 22 17"/>
33
+ <polyline points="2 12 12 17 22 12"/>
34
+ </svg>
35
+ Open Designer
36
+ <% end %>
37
+ <% if @page.published? && @page.slug.present? %>
38
+ <%= link_to public_page_path(@page.slug), target: "_blank", class: "btn btn-secondary" do %>
39
+ <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">
40
+ <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
41
+ <polyline points="15 3 21 3 21 9"/>
42
+ <line x1="10" y1="14" x2="21" y2="3"/>
43
+ </svg>
44
+ View Live
45
+ <% end %>
46
+ <% end %>
47
+ </div>
48
+ </div>
49
+
50
+ <!-- Two Column Layout -->
51
+ <div style="display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem; align-items: start;">
52
+ <!-- Main Column -->
53
+ <div>
54
+ <!-- Quick Actions Card -->
55
+ <div class="card" style="margin-bottom: 1.5rem;">
56
+ <div style="padding: 1.25rem; display: flex; gap: 1rem; flex-wrap: wrap;">
57
+ <%= link_to editor_admin_page_path(@page), class: "btn btn-primary", style: "flex: 1; min-width: 140px; justify-content: center;" do %>
58
+ <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">
59
+ <polygon points="12 2 2 7 12 12 22 7 12 2"/>
60
+ <polyline points="2 17 12 22 22 17"/>
61
+ <polyline points="2 12 12 17 22 12"/>
62
+ </svg>
63
+ Open Designer
64
+ <% end %>
65
+ <%= link_to edit_admin_page_path(@page), class: "btn btn-secondary", style: "flex: 1; min-width: 140px; justify-content: center;" do %>
66
+ <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">
67
+ <path d="M12 20h9"/>
68
+ <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
69
+ </svg>
70
+ Edit Settings
71
+ <% end %>
72
+ <%= link_to versions_admin_page_path(@page), class: "btn btn-secondary", style: "flex: 1; min-width: 140px; justify-content: center;" do %>
73
+ <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">
74
+ <circle cx="12" cy="12" r="10"/>
75
+ <polyline points="12 6 12 12 16 14"/>
76
+ </svg>
77
+ History
78
+ <% if @page.versions.any? %>
79
+ <span class="badge badge-gray" style="margin-left: 0.375rem; padding: 0.125rem 0.5rem; font-size: 0.6875rem;"><%= @page.versions.count %></span>
80
+ <% end %>
81
+ <% end %>
82
+ </div>
83
+ </div>
84
+
85
+ <!-- Content Preview -->
86
+ <div class="card" style="margin-bottom: 1.5rem;">
87
+ <div class="card-header">
88
+ <span class="card-title">Content Preview</span>
89
+ <% if @page.content.present? %>
90
+ <span style="font-size: 0.75rem; color: var(--text-muted);"><%= number_to_human_size(@page.content.bytesize) %></span>
91
+ <% end %>
92
+ </div>
93
+ <div style="padding: 1rem;">
94
+ <% if @page.content.present? %>
95
+ <div class="content-preview" style="max-height: 300px; overflow: auto;"><%= truncate(@page.content, length: 3000) %></div>
96
+ <% else %>
97
+ <div class="empty-state" style="padding: 2rem;">
98
+ <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="opacity: 0.4;">
99
+ <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
100
+ <polyline points="14 2 14 8 20 8"/>
101
+ </svg>
102
+ <h3>No content yet</h3>
103
+ <p>Open the visual designer to start building this page</p>
104
+ <%= link_to editor_admin_page_path(@page), class: "btn btn-primary" do %>
105
+ <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">
106
+ <polygon points="12 2 2 7 12 12 22 7 12 2"/>
107
+ <polyline points="2 17 12 22 22 17"/>
108
+ <polyline points="2 12 12 17 22 12"/>
109
+ </svg>
110
+ Open Designer
111
+ <% end %>
112
+ </div>
113
+ <% end %>
114
+ </div>
115
+ </div>
116
+
117
+ <!-- SEO Overview -->
118
+ <% has_seo = @page.meta_title.present? || @page.meta_description.present? %>
119
+ <div class="card" style="margin-bottom: 1.5rem;">
120
+ <div class="card-header">
121
+ <span class="card-title">
122
+ <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;">
123
+ <circle cx="11" cy="11" r="8"/>
124
+ <path d="m21 21-4.3-4.3"/>
125
+ </svg>
126
+ SEO
127
+ </span>
128
+ <% if has_seo %>
129
+ <span class="badge badge-success"><span class="badge-dot"></span>Configured</span>
130
+ <% else %>
131
+ <%= link_to edit_admin_page_path(@page), class: "btn btn-secondary btn-sm" do %>
132
+ Configure
133
+ <% end %>
134
+ <% end %>
135
+ </div>
136
+ <% if has_seo %>
137
+ <div class="card-body">
138
+ <% if @page.meta_title.present? %>
139
+ <div style="margin-bottom: 1rem;">
140
+ <div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Meta Title</div>
141
+ <div style="font-size: 0.9375rem;"><%= @page.meta_title %></div>
142
+ </div>
143
+ <% end %>
144
+ <% if @page.meta_description.present? %>
145
+ <div>
146
+ <div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Meta Description</div>
147
+ <div style="font-size: 0.875rem; color: var(--text-muted);"><%= @page.meta_description %></div>
148
+ </div>
149
+ <% end %>
150
+ </div>
151
+ <% end %>
152
+ </div>
153
+ </div>
154
+
155
+ <!-- Sidebar Column -->
156
+ <div>
157
+ <!-- Page Details -->
158
+ <div class="card" style="margin-bottom: 1.5rem;">
159
+ <div class="card-header">
160
+ <span class="card-title">Details</span>
161
+ </div>
162
+ <div class="card-body" style="padding: 0;">
163
+ <div style="padding: 0.875rem 1rem; border-bottom: 1px solid var(--border);">
164
+ <div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Page Type</div>
165
+ <div style="font-size: 0.9375rem;"><%= @page.page_type.name %></div>
166
+ </div>
167
+ <div style="padding: 0.875rem 1rem; border-bottom: 1px solid var(--border);">
168
+ <div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Created</div>
169
+ <div style="font-size: 0.9375rem;"><%= @page.created_at.strftime("%b %d, %Y") %></div>
170
+ </div>
171
+ <div style="padding: 0.875rem 1rem;">
172
+ <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 Modified</div>
173
+ <div style="font-size: 0.9375rem;"><%= @page.updated_at.strftime("%b %d, %Y at %l:%M %p") %></div>
174
+ </div>
175
+ </div>
176
+ </div>
177
+
178
+ <% if ActiveCanvas::Partial.table_exists? %>
179
+ <!-- Header & Footer -->
180
+ <div class="card" style="margin-bottom: 1.5rem;">
181
+ <div class="card-header">
182
+ <span class="card-title">Layout</span>
183
+ </div>
184
+ <div class="card-body" style="padding: 0;">
185
+ <div style="padding: 0.875rem 1rem; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between;">
186
+ <span style="font-size: 0.9375rem;">Header</span>
187
+ <% if @page.show_header? %>
188
+ <span class="badge badge-success"><span class="badge-dot"></span>Enabled</span>
189
+ <% else %>
190
+ <span class="badge badge-gray"><span class="badge-dot"></span>Disabled</span>
191
+ <% end %>
192
+ </div>
193
+ <div style="padding: 0.875rem 1rem; display: flex; align-items: center; justify-content: space-between;">
194
+ <span style="font-size: 0.9375rem;">Footer</span>
195
+ <% if @page.show_footer? %>
196
+ <span class="badge badge-success"><span class="badge-dot"></span>Enabled</span>
197
+ <% else %>
198
+ <span class="badge badge-gray"><span class="badge-dot"></span>Disabled</span>
199
+ <% end %>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ <% end %>
204
+
205
+ <% if ActiveCanvas::Setting.css_framework == "tailwind" %>
206
+ <!-- Tailwind CSS Status -->
207
+ <div class="card" style="margin-bottom: 1.5rem;">
208
+ <div class="card-header">
209
+ <span class="card-title">
210
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="#06b6d4" style="vertical-align: -1px; margin-right: 0.375rem;">
211
+ <path d="M12.001 4.8c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624C13.666 10.618 15.027 12 18.001 12c3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C16.337 6.182 14.976 4.8 12.001 4.8zm-6 7.2c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624 1.177 1.194 2.538 2.576 5.512 2.576 3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C10.337 13.382 8.976 12 6.001 12z"/>
212
+ </svg>
213
+ Tailwind
214
+ </span>
215
+ </div>
216
+ <div class="card-body" style="padding: 0;">
217
+ <% if @page.compiled_tailwind_css.present? %>
218
+ <div style="padding: 0.875rem 1rem; border-bottom: 1px solid var(--border);">
219
+ <div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">CSS Size</div>
220
+ <div style="font-size: 0.9375rem; color: var(--success);"><%= number_to_human_size(@page.compiled_tailwind_css.bytesize) %></div>
221
+ </div>
222
+ <div style="padding: 0.875rem 1rem;">
223
+ <div style="font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem;">Compiled</div>
224
+ <div style="font-size: 0.9375rem;"><%= time_ago_in_words(@page.tailwind_compiled_at) %> ago</div>
225
+ </div>
226
+ <% else %>
227
+ <div style="padding: 1rem; text-align: center; color: var(--text-muted);">
228
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="opacity: 0.5; margin-bottom: 0.5rem;">
229
+ <circle cx="12" cy="12" r="10"/>
230
+ <line x1="12" y1="8" x2="12" y2="12"/>
231
+ <line x1="12" y1="16" x2="12.01" y2="16"/>
232
+ </svg>
233
+ <div style="font-size: 0.8125rem;">Not compiled yet</div>
234
+ <div style="font-size: 0.75rem; margin-top: 0.25rem;">Save in Designer to compile</div>
235
+ </div>
236
+ <% end %>
237
+ </div>
238
+ </div>
239
+ <% end %>
240
+
241
+ <!-- Danger Zone -->
242
+ <div class="card" style="border-color: #fecaca;">
243
+ <div class="card-header" style="background: var(--danger-light); padding: 0.75rem 1rem;">
244
+ <span class="card-title" style="color: var(--danger); font-size: 0.8125rem;">Danger Zone</span>
245
+ </div>
246
+ <div class="card-body" style="padding: 1rem;">
247
+ <p style="font-size: 0.8125rem; color: var(--text-muted); margin-bottom: 0.75rem;">Permanently delete this page and all its content.</p>
248
+ <%= button_to admin_page_path(@page), method: :delete, class: "btn btn-danger btn-sm", style: "width: 100%;", data: { confirm: "Are you sure you want to delete this page? This action cannot be undone." } do %>
249
+ <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">
250
+ <polyline points="3 6 5 6 21 6"/>
251
+ <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"/>
252
+ </svg>
253
+ Delete Page
254
+ <% end %>
255
+ </div>
256
+ </div>
257
+ </div>
258
+ </div>