one-for-all-framework 1.0.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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +4 -0
  3. data/Dockerfile +19 -0
  4. data/Gemfile +20 -0
  5. data/LICENSE +21 -0
  6. data/Procfile +1 -0
  7. data/README.md +99 -0
  8. data/app/controllers/api_controller.rb +19 -0
  9. data/app/controllers/application_controller.rb +77 -0
  10. data/app/controllers/auth_controller.rb +35 -0
  11. data/app/controllers/dashboard_controller.rb +41 -0
  12. data/app/controllers/pages_controller.rb +49 -0
  13. data/app/controllers/posts_controller.rb +48 -0
  14. data/app/controllers/projects_controller.rb +48 -0
  15. data/app/helpers/cloudinary_helper.rb +14 -0
  16. data/app/middleware/auth_middleware.rb +52 -0
  17. data/app/middleware/csrf_middleware.rb +27 -0
  18. data/app/models/page.rb +8 -0
  19. data/app/models/post.rb +8 -0
  20. data/app/models/project.rb +7 -0
  21. data/app/models/user.rb +83 -0
  22. data/app/views/blog_home.erb +70 -0
  23. data/app/views/cms/pages_form.erb +156 -0
  24. data/app/views/cms/pages_index.erb +104 -0
  25. data/app/views/cms/posts_form.erb +182 -0
  26. data/app/views/cms/posts_index.erb +100 -0
  27. data/app/views/cms/projects_form.erb +176 -0
  28. data/app/views/cms/projects_index.erb +96 -0
  29. data/app/views/dashboard.erb +122 -0
  30. data/app/views/docs.erb +140 -0
  31. data/app/views/error.erb +159 -0
  32. data/app/views/index.erb +70 -0
  33. data/app/views/layout.erb +251 -0
  34. data/app/views/login.erb +45 -0
  35. data/app/views/page.erb +21 -0
  36. data/app/views/portfolio.erb +73 -0
  37. data/app/views/post.erb +33 -0
  38. data/app/views/posts/hello_world.erb +3 -0
  39. data/app/views/project.erb +39 -0
  40. data/bin/ofa +499 -0
  41. data/config/boot.rb +134 -0
  42. data/config/database.json +4 -0
  43. data/config/database.rb +142 -0
  44. data/config/features.json +7 -0
  45. data/config/locales/en.json +6 -0
  46. data/config/locales/id.json +6 -0
  47. data/config/routes.rb +87 -0
  48. data/config.eks +11 -0
  49. data/config.ru +11 -0
  50. data/db/data.sqlite3 +0 -0
  51. data/db/development.sqlite3 +0 -0
  52. data/ofa +2 -0
  53. data/public/css/cms.css +134 -0
  54. data/public/images/logo.jpg +0 -0
  55. data/public/images/logo.png +0 -0
  56. metadata +259 -0
@@ -0,0 +1,100 @@
1
+ <div class="flex flex-col md:flex-row gap-8 items-start">
2
+ <!-- CMS Sidebar -->
3
+ <aside class="glass-panel w-full md:w-64 p-6 sticky top-24">
4
+ <div class="flex items-center gap-2 mb-8 px-2">
5
+ <div class="w-6 h-6 bg-primary rounded flex items-center justify-center text-white text-xs">
6
+ <i class="fas fa-user-shield"></i>
7
+ </div>
8
+ <h3 class="font-black tracking-tight text-lg">Admin<span class="text-primary">Panel</span></h3>
9
+ </div>
10
+
11
+ <nav class="space-y-2">
12
+ <a href="/dashboard" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path == '/dashboard' ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
13
+ <i class="fas fa-chart-pie w-5"></i>
14
+ <span class="font-semibold">Dashboard</span>
15
+ </a>
16
+
17
+ <a href="/dashboard/pages" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/pages') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
18
+ <i class="fas fa-file-lines w-5"></i>
19
+ <span class="font-semibold">Pages</span>
20
+ </a>
21
+
22
+ <% if FEATURES_CONFIG['type'] == 'blog' %>
23
+ <a href="/dashboard/posts" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/posts') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
24
+ <i class="fas fa-pen-nib w-5"></i>
25
+ <span class="font-semibold">Blog Posts</span>
26
+ </a>
27
+ <% elsif FEATURES_CONFIG['type'] == 'portfolio' %>
28
+ <a href="/dashboard/projects" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/projects') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
29
+ <i class="fas fa-palette w-5"></i>
30
+ <span class="font-semibold">Projects</span>
31
+ </a>
32
+ <% end %>
33
+
34
+ <div class="h-px bg-white/5 my-4"></div>
35
+
36
+ <form action="/logout" method="POST">
37
+ <%= csrf_tag %>
38
+ <button type="submit" class="w-full flex items-center gap-3 px-4 py-3 rounded-2xl text-red-400 hover:bg-red-500/10 transition-all duration-300 font-semibold">
39
+ <i class="fas fa-door-open w-5"></i>
40
+ <span>Logout</span>
41
+ </button>
42
+ </form>
43
+ </nav>
44
+ </aside>
45
+
46
+ <!-- Main Content -->
47
+ <div class="flex-1 space-y-6 w-full">
48
+ <div class="flex justify-between items-center bg-white/5 p-6 rounded-3xl border border-white/5">
49
+ <div>
50
+ <h2 class="text-2xl font-black tracking-tight">Article Management</h2>
51
+ <p class="text-slate-500 text-sm">Write and manage your blog articles.</p>
52
+ </div>
53
+ <a href="/dashboard/posts/new" class="btn-premium">
54
+ <i class="fas fa-plus mr-2 text-sm"></i> New Article
55
+ </a>
56
+ </div>
57
+
58
+ <div class="glass-panel overflow-hidden border-none shadow-xl">
59
+ <table class="w-full text-left border-collapse">
60
+ <thead>
61
+ <tr class="bg-white/5">
62
+ <th class="px-6 py-4 text-xs font-bold uppercase tracking-wider text-slate-400">Title</th>
63
+ <th class="px-6 py-4 text-xs font-bold uppercase tracking-wider text-slate-400">Category</th>
64
+ <th class="px-6 py-4 text-xs font-bold uppercase tracking-wider text-slate-400 text-right">Action</th>
65
+ </tr>
66
+ </thead>
67
+ <tbody class="divide-y divide-white/5">
68
+ <% if @posts.empty? %>
69
+ <tr>
70
+ <td colspan="3" class="px-6 py-12 text-center text-slate-500 italic">No articles created yet.</td>
71
+ </tr>
72
+ <% end %>
73
+ <% @posts.each do |post| %>
74
+ <tr class="hover:bg-white/[0.02] transition-colors group">
75
+ <td class="px-6 py-4">
76
+ <span class="font-bold text-slate-700 dark:text-slate-200 group-hover:text-primary transition-colors"><%= post.title %></span>
77
+ </td>
78
+ <td class="px-6 py-4">
79
+ <span class="text-xs bg-primary/10 px-2 py-1 rounded-lg text-primary font-bold"><%= post.category %></span>
80
+ </td>
81
+ <td class="px-6 py-4 text-right">
82
+ <div class="flex justify-end gap-2">
83
+ <a href="/dashboard/posts/<%= post.id %>/edit" class="w-9 h-9 flex items-center justify-center rounded-xl bg-primary/10 text-primary hover:bg-primary hover:text-white transition-all shadow-lg shadow-primary/10">
84
+ <i class="fas fa-edit text-sm"></i>
85
+ </a>
86
+ <form action="/dashboard/posts/<%= post.id %>/delete" method="POST" onsubmit="return confirm('Delete this article?')" class="inline">
87
+ <%= csrf_tag %>
88
+ <button type="submit" class="w-9 h-9 flex items-center justify-center rounded-xl bg-red-500/10 text-red-500 hover:bg-red-500 hover:text-white transition-all shadow-lg shadow-red-500/10">
89
+ <i class="fas fa-trash-can text-sm"></i>
90
+ </button>
91
+ </form>
92
+ </div>
93
+ </td>
94
+ </tr>
95
+ <% end %>
96
+ </tbody>
97
+ </table>
98
+ </div>
99
+ </div>
100
+ </div>
@@ -0,0 +1,176 @@
1
+ <div class="flex flex-col md:flex-row gap-8 items-start">
2
+ <!-- CMS Sidebar -->
3
+ <aside class="glass-panel w-full md:w-64 p-6 sticky top-24">
4
+ <div class="flex items-center gap-2 mb-8 px-2">
5
+ <div class="w-6 h-6 bg-primary rounded flex items-center justify-center text-white text-xs">
6
+ <i class="fas fa-user-shield"></i>
7
+ </div>
8
+ <h3 class="font-black tracking-tight text-lg">Admin<span class="text-primary">Panel</span></h3>
9
+ </div>
10
+
11
+ <nav class="space-y-2">
12
+ <a href="/dashboard" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path == '/dashboard' ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
13
+ <i class="fas fa-chart-pie w-5"></i>
14
+ <span class="font-semibold">Dashboard</span>
15
+ </a>
16
+
17
+ <a href="/dashboard/pages" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/pages') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
18
+ <i class="fas fa-file-lines w-5"></i>
19
+ <span class="font-semibold">Pages</span>
20
+ </a>
21
+
22
+ <% if FEATURES_CONFIG['type'] == 'blog' %>
23
+ <a href="/dashboard/posts" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/posts') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
24
+ <i class="fas fa-pen-nib w-5"></i>
25
+ <span class="font-semibold">Blog Posts</span>
26
+ </a>
27
+ <% elsif FEATURES_CONFIG['type'] == 'portfolio' %>
28
+ <a href="/dashboard/projects" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/projects') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
29
+ <i class="fas fa-palette w-5"></i>
30
+ <span class="font-semibold">Projects</span>
31
+ </a>
32
+ <% end %>
33
+
34
+ <div class="h-px bg-white/5 my-4"></div>
35
+
36
+ <form action="/logout" method="POST">
37
+ <%= csrf_tag %>
38
+ <button type="submit" class="w-full flex items-center gap-3 px-4 py-3 rounded-2xl text-red-400 hover:bg-red-500/10 transition-all duration-300 font-semibold">
39
+ <i class="fas fa-door-open w-5"></i>
40
+ <span>Logout</span>
41
+ </button>
42
+ </form>
43
+ </nav>
44
+ </aside>
45
+
46
+ <!-- Main Content -->
47
+ <div class="flex-1 space-y-6 w-full pb-20">
48
+ <div class="flex justify-between items-center bg-white/5 p-6 rounded-3xl border border-white/5">
49
+ <div>
50
+ <h2 class="text-2xl font-black tracking-tight"><%= @project.id ? 'Edit' : 'Add' %> Project</h2>
51
+ <p class="text-slate-500 text-sm">Showcase your best work.</p>
52
+ </div>
53
+ <a href="/dashboard/projects" class="px-6 py-2.5 rounded-xl bg-white/5 text-slate-500 hover:bg-white/10 transition-all font-bold">
54
+ Cancel
55
+ </a>
56
+ </div>
57
+
58
+ <div class="glass-panel p-8">
59
+ <form action="<%= @project.id ? "/dashboard/projects/#{@project.id}/update" : "/dashboard/projects" %>" method="POST" id="main-form" class="space-y-6">
60
+ <%= csrf_tag %>
61
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
62
+ <div class="space-y-2 text-left">
63
+ <label class="text-xs font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400 ml-1">Project Name</label>
64
+ <input type="text" name="project[title]" value="<%= @project.title %>" placeholder="Example: E-Commerce Website" required oninput="generateSlug(this.value)"
65
+ class="w-full px-5 py-3 bg-white/5 border border-white/10 rounded-2xl focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all text-slate-700 dark:text-slate-200 font-bold">
66
+ </div>
67
+ <div class="pb-3 pl-2 flex items-end">
68
+ <label class="flex items-center gap-3 cursor-pointer group">
69
+ <div class="relative">
70
+ <input type="checkbox" name="project[is_active]" <%= @project.is_active ? 'checked' : '' %> class="sr-only peer">
71
+ <div class="w-11 h-6 bg-slate-200 dark:bg-white/10 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-green-500"></div>
72
+ </div>
73
+ <span class="text-sm font-bold text-slate-600 dark:text-slate-400 group-hover:text-green-500 transition-colors">Enable Project</span>
74
+ </label>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
79
+ <div class="space-y-2 text-left">
80
+ <label class="text-xs font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400 ml-1">URL Slug (Automatic)</label>
81
+ <div class="relative">
82
+ <span class="absolute left-5 top-1/2 -translate-y-1/2 text-slate-500 font-mono text-sm">/</span>
83
+ <input type="text" name="project[slug]" id="slug-input" value="<%= @project.slug %>" placeholder="e-commerce-app" required
84
+ class="w-full pl-8 pr-5 py-3 bg-white/5 border border-white/10 rounded-2xl focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all font-mono text-primary">
85
+ </div>
86
+ </div>
87
+ <div class="space-y-2 text-left">
88
+ <label class="text-xs font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400 ml-1">Demo/Github Link</label>
89
+ <input type="text" name="project[link]" value="<%= @project.link %>" placeholder="https://github.com/..." required
90
+ class="w-full px-5 py-3 bg-white/5 border border-white/10 rounded-2xl focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all text-slate-700 dark:text-slate-200">
91
+ </div>
92
+ </div>
93
+
94
+ <div class="space-y-2 text-left">
95
+ <label class="text-xs font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400 ml-1">Thumbnail Proyek</label>
96
+ <div class="flex gap-4">
97
+ <input type="text" name="project[image_url]" id="thumbnail-url" value="<%= @project.image_url %>" placeholder="https://..." onchange="updatePreview(this.value)"
98
+ class="flex-1 px-5 py-3 bg-white/5 border border-white/10 rounded-2xl focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all text-slate-700 dark:text-slate-200">
99
+ <button type="button" class="w-12 h-12 flex items-center justify-center rounded-2xl bg-primary/10 text-primary hover:bg-primary hover:text-white transition-all shadow-lg" onclick="openUploader()">
100
+ <i class="fas fa-image"></i>
101
+ </button>
102
+ </div>
103
+ <div id="image-preview-container" style="<%= @project.image_url && !@project.image_url.empty? ? '' : 'display: none;' %>" class="mt-4 p-2 border-2 border-dashed border-white/10 rounded-2xl text-left">
104
+ <span class="text-[10px] font-bold uppercase text-slate-500 mb-2 block ml-1">Project Preview</span>
105
+ <img id="image-preview" src="<%= @project.image_url %>" class="max-h-40 rounded-xl shadow-lg">
106
+ </div>
107
+ </div>
108
+
109
+ <div class="space-y-2 text-left">
110
+ <div class="flex justify-between items-center px-1">
111
+ <label class="text-xs font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400">Project Description (Markdown)</label>
112
+ </div>
113
+ <textarea name="project[description]" rows="8" placeholder="Tell us about this project..."
114
+ class="w-full px-5 py-4 bg-white/5 border border-white/10 rounded-2xl focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all text-slate-700 dark:text-slate-300 font-mono leading-relaxed"><%= @project.description %></textarea>
115
+ <input type="file" id="image-upload" class="hidden" onchange="handleImageUpload(this)">
116
+ </div>
117
+
118
+ <button type="submit" class="btn-premium w-full py-4 text-lg">
119
+ <i class="fas fa-save mr-2"></i> Save Project
120
+ </button>
121
+ </form>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <script>
127
+ function generateSlug(text) {
128
+ const slug = text.toLowerCase()
129
+ .replace(/[^\w\s-]/g, '')
130
+ .replace(/[\s_-]+/g, '-')
131
+ .replace(/^-+|-+$/g, '');
132
+ document.getElementById('slug-input').value = slug;
133
+ }
134
+
135
+ function openUploader() { document.getElementById('image-upload').click(); }
136
+ function updatePreview(url) {
137
+ const container = document.getElementById('image-preview-container');
138
+ const img = document.getElementById('image-preview');
139
+ if (url) {
140
+ img.src = url;
141
+ container.style.display = 'block';
142
+ } else {
143
+ container.style.display = 'none';
144
+ }
145
+ }
146
+
147
+ async function handleImageUpload(input) {
148
+ if (!input.files || !input.files[0]) return;
149
+
150
+ const btn = document.querySelector('.upload-helper-btn');
151
+ const originalText = btn?.innerHTML || '🖼️';
152
+ if(btn) {
153
+ btn.innerHTML = '⌛';
154
+ btn.disabled = true;
155
+ }
156
+
157
+ const formData = new FormData();
158
+ formData.append('file', input.files[0]);
159
+ formData.append('csrf_token', '<%= csrf_token %>');
160
+ try {
161
+ const response = await fetch('/dashboard/upload', { method: 'POST', body: formData });
162
+ const data = await response.json();
163
+ if (data.url) {
164
+ document.getElementById('thumbnail-url').value = data.url;
165
+ updatePreview(data.url);
166
+ alert('Image uploaded successfully! Don\'t forget to click SAVE below.');
167
+ }
168
+ } catch (e) { alert('An error occurred.'); }
169
+ finally {
170
+ if(btn) {
171
+ btn.innerHTML = originalText;
172
+ btn.disabled = false;
173
+ }
174
+ }
175
+ }
176
+ </script>
@@ -0,0 +1,96 @@
1
+ <div class="flex flex-col md:flex-row gap-8 items-start">
2
+ <!-- CMS Sidebar -->
3
+ <aside class="glass-panel w-full md:w-64 p-6 sticky top-24">
4
+ <div class="flex items-center gap-2 mb-8 px-2">
5
+ <div class="w-6 h-6 bg-primary rounded flex items-center justify-center text-white text-xs">
6
+ <i class="fas fa-user-shield"></i>
7
+ </div>
8
+ <h3 class="font-black tracking-tight text-lg">Admin<span class="text-primary">Panel</span></h3>
9
+ </div>
10
+
11
+ <nav class="space-y-2">
12
+ <a href="/dashboard" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path == '/dashboard' ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
13
+ <i class="fas fa-chart-pie w-5"></i>
14
+ <span class="font-semibold">Dashboard</span>
15
+ </a>
16
+
17
+ <a href="/dashboard/pages" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/pages') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
18
+ <i class="fas fa-file-lines w-5"></i>
19
+ <span class="font-semibold">Pages</span>
20
+ </a>
21
+
22
+ <% if FEATURES_CONFIG['type'] == 'blog' %>
23
+ <a href="/dashboard/posts" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/posts') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
24
+ <i class="fas fa-pen-nib w-5"></i>
25
+ <span class="font-semibold">Blog Posts</span>
26
+ </a>
27
+ <% elsif FEATURES_CONFIG['type'] == 'portfolio' %>
28
+ <a href="/dashboard/projects" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/projects') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
29
+ <i class="fas fa-palette w-5"></i>
30
+ <span class="font-semibold">Projects</span>
31
+ </a>
32
+ <% end %>
33
+
34
+ <div class="h-px bg-white/5 my-4"></div>
35
+
36
+ <form action="/logout" method="POST">
37
+ <%= csrf_tag %>
38
+ <button type="submit" class="w-full flex items-center gap-3 px-4 py-3 rounded-2xl text-red-400 hover:bg-red-500/10 transition-all duration-300 font-semibold">
39
+ <i class="fas fa-door-open w-5"></i>
40
+ <span>Logout</span>
41
+ </button>
42
+ </form>
43
+ </nav>
44
+ </aside>
45
+
46
+ <!-- Main Content -->
47
+ <div class="flex-1 space-y-6 w-full">
48
+ <div class="flex justify-between items-center bg-white/5 p-6 rounded-3xl border border-white/5">
49
+ <div>
50
+ <h2 class="text-2xl font-black tracking-tight">Project Management</h2>
51
+ <p class="text-slate-500 text-sm">Showcase your best work.</p>
52
+ </div>
53
+ <a href="/dashboard/projects/new" class="btn-premium">
54
+ <i class="fas fa-plus mr-2 text-sm"></i> New Project
55
+ </a>
56
+ </div>
57
+
58
+ <div class="glass-panel overflow-hidden border-none shadow-xl">
59
+ <table class="w-full text-left border-collapse">
60
+ <thead>
61
+ <tr class="bg-white/5">
62
+ <th class="px-6 py-4 text-xs font-bold uppercase tracking-wider text-slate-400">Title</th>
63
+ <th class="px-6 py-4 text-xs font-bold uppercase tracking-wider text-slate-400 text-right">Action</th>
64
+ </tr>
65
+ </thead>
66
+ <tbody class="divide-y divide-white/5">
67
+ <% if @projects.empty? %>
68
+ <tr>
69
+ <td colspan="2" class="px-6 py-12 text-center text-slate-500 italic">No projects created yet.</td>
70
+ </tr>
71
+ <% end %>
72
+ <% @projects.each do |project| %>
73
+ <tr class="hover:bg-white/[0.02] transition-colors group">
74
+ <td class="px-6 py-4">
75
+ <span class="font-bold text-slate-700 dark:text-slate-200 group-hover:text-primary transition-colors"><%= project.title %></span>
76
+ </td>
77
+ <td class="px-6 py-4 text-right">
78
+ <div class="flex justify-end gap-2">
79
+ <a href="/dashboard/projects/<%= project.id %>/edit" class="w-9 h-9 flex items-center justify-center rounded-xl bg-primary/10 text-primary hover:bg-primary hover:text-white transition-all shadow-lg shadow-primary/10">
80
+ <i class="fas fa-edit text-sm"></i>
81
+ </a>
82
+ <form action="/dashboard/projects/<%= project.id %>/delete" method="POST" onsubmit="return confirm('Delete this project?')" class="inline">
83
+ <%= csrf_tag %>
84
+ <button type="submit" class="w-9 h-9 flex items-center justify-center rounded-xl bg-red-500/10 text-red-500 hover:bg-red-500 hover:text-white transition-all shadow-lg shadow-red-500/10">
85
+ <i class="fas fa-trash-can text-sm"></i>
86
+ </button>
87
+ </form>
88
+ </div>
89
+ </td>
90
+ </tr>
91
+ <% end %>
92
+ </tbody>
93
+ </table>
94
+ </div>
95
+ </div>
96
+ </div>
@@ -0,0 +1,122 @@
1
+ <div class="flex flex-col md:flex-row gap-8 items-start">
2
+ <!-- CMS Sidebar -->
3
+ <aside class="glass-panel w-full md:w-64 p-6 sticky top-24">
4
+ <div class="flex items-center gap-2 mb-8 px-2">
5
+ <div class="w-6 h-6 bg-primary rounded flex items-center justify-center text-white text-xs">
6
+ <i class="fas fa-user-shield"></i>
7
+ </div>
8
+ <h3 class="font-black tracking-tight text-lg">Admin<span class="text-primary">Panel</span></h3>
9
+ </div>
10
+
11
+ <nav class="space-y-2">
12
+ <a href="/dashboard" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path == '/dashboard' ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
13
+ <i class="fas fa-chart-pie w-5"></i>
14
+ <span class="font-semibold">Dashboard</span>
15
+ </a>
16
+
17
+ <a href="/dashboard/pages" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/pages') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
18
+ <i class="fas fa-file-lines w-5"></i>
19
+ <span class="font-semibold">Pages</span>
20
+ </a>
21
+
22
+ <% if FEATURES_CONFIG['type'] == 'blog' %>
23
+ <a href="/dashboard/posts" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/posts') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
24
+ <i class="fas fa-pen-nib w-5"></i>
25
+ <span class="font-semibold">Blog Posts</span>
26
+ </a>
27
+ <% elsif FEATURES_CONFIG['type'] == 'portfolio' %>
28
+ <a href="/dashboard/projects" class="flex items-center gap-3 px-4 py-3 rounded-2xl transition-all duration-300 <%= @req.path.start_with?('/dashboard/projects') ? 'bg-primary text-white shadow-lg shadow-primary/30' : 'text-slate-500 hover:bg-white/5' %>">
29
+ <i class="fas fa-palette w-5"></i>
30
+ <span class="font-semibold">Projects</span>
31
+ </a>
32
+ <% end %>
33
+
34
+ <div class="h-px bg-white/5 my-4"></div>
35
+
36
+ <form action="/logout" method="POST">
37
+ <%= csrf_tag %>
38
+ <button type="submit" class="w-full flex items-center gap-3 px-4 py-3 rounded-2xl text-red-400 hover:bg-red-500/10 transition-all duration-300 font-semibold">
39
+ <i class="fas fa-door-open w-5"></i>
40
+ <span>Logout</span>
41
+ </button>
42
+ </form>
43
+ </nav>
44
+ </aside>
45
+
46
+ <!-- Main Content -->
47
+ <div class="flex-1 space-y-8 w-full pb-20">
48
+ <div class="glass-card !p-12 bg-gradient-to-br from-primary/10 to-transparent border-primary/20 relative overflow-hidden group">
49
+ <div class="card-glow !opacity-30"></div>
50
+ <div class="relative z-10 text-left">
51
+ <div class="badge-premium">System Operational</div>
52
+ <h2 class="text-4xl md:text-5xl font-black tracking-tighter text-slate-700 dark:text-white mb-4">
53
+ Welcome back, <span class="text-primary"><%= session['username'] || 'Admin' %></span>
54
+ </h2>
55
+ <p class="text-slate-500 dark:text-slate-400 text-lg max-w-xl leading-relaxed">
56
+ Ready to create something amazing? Your dashboard is optimized and synchronized across all nodes.
57
+ </p>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
62
+ <div class="glass-card !p-6 md:!p-8 group">
63
+ <div class="card-glow"></div>
64
+ <div class="w-14 h-14 rounded-2xl bg-blue-500/10 text-blue-500 flex items-center justify-center mb-6 text-2xl group-hover:scale-110 group-hover:bg-blue-500 group-hover:text-white transition-all duration-500 shadow-lg shadow-blue-500/10">
65
+ <i class="fas fa-file-alt"></i>
66
+ </div>
67
+ <h4 class="text-xs font-black uppercase tracking-[0.2em] text-slate-400 mb-2">Total Pages</h4>
68
+ <div class="text-4xl font-black text-slate-700 dark:text-white tracking-tighter truncate"><%= @stats[:pages] %></div>
69
+ </div>
70
+
71
+ <% if @type == 'blog' %>
72
+ <div class="glass-card !p-6 md:!p-8 group">
73
+ <div class="card-glow !bg-green-500/10"></div>
74
+ <div class="w-14 h-14 rounded-2xl bg-green-500/10 text-green-500 flex items-center justify-center mb-6 text-2xl group-hover:scale-110 group-hover:bg-green-500 group-hover:text-white transition-all duration-500 shadow-lg shadow-green-500/10">
75
+ <i class="fas fa-pen-nib"></i>
76
+ </div>
77
+ <h4 class="text-xs font-black uppercase tracking-[0.2em] text-slate-400 mb-2">Blog Articles</h4>
78
+ <div class="text-4xl font-black text-slate-700 dark:text-white tracking-tighter truncate"><%= @stats[:posts] %></div>
79
+ </div>
80
+ <% elsif @type == 'portfolio' %>
81
+ <div class="glass-card !p-6 md:!p-8 group">
82
+ <div class="card-glow !bg-purple-500/10"></div>
83
+ <div class="w-14 h-14 rounded-2xl bg-purple-500/10 text-purple-500 flex items-center justify-center mb-6 text-2xl group-hover:scale-110 group-hover:bg-purple-500 group-hover:text-white transition-all duration-500 shadow-lg shadow-purple-500/10">
84
+ <i class="fas fa-palette"></i>
85
+ </div>
86
+ <h4 class="text-xs font-black uppercase tracking-[0.2em] text-slate-400 mb-2">Total Projects</h4>
87
+ <div class="text-4xl font-black text-slate-700 dark:text-white tracking-tighter truncate"><%= @stats[:projects] %></div>
88
+ </div>
89
+ <% end %>
90
+
91
+ <div class="glass-card !p-6 md:!p-8 group">
92
+ <div class="card-glow !bg-orange-500/10"></div>
93
+ <div class="w-14 h-14 rounded-2xl bg-orange-500/10 text-orange-500 flex items-center justify-center mb-6 text-2xl group-hover:scale-110 group-hover:bg-orange-500 group-hover:text-white transition-all duration-500 shadow-lg shadow-orange-500/10">
94
+ <i class="fas fa-cloud-bolt"></i>
95
+ </div>
96
+ <h4 class="text-xs font-black uppercase tracking-[0.2em] text-slate-400 mb-2">Cloud Node</h4>
97
+ <div class="text-lg font-black text-slate-700 dark:text-white uppercase tracking-wider truncate"><%= FEATURES_CONFIG['storage'] || 'Local Cluster' %></div>
98
+ </div>
99
+ </div>
100
+
101
+ <div class="glass-card !p-12 bg-gradient-to-br from-primary/5 to-transparent border-primary/10 text-left">
102
+ <div class="max-w-xl">
103
+ <h3 class="text-3xl font-black tracking-tighter mb-6 text-slate-700 dark:text-white">Start Building Now</h3>
104
+ <p class="text-slate-600 dark:text-slate-400 mb-10 text-lg leading-relaxed">Your creative workflow is ready. All deployments are optimized for the edge and secured with enterprise-grade encryption.</p>
105
+ <div class="flex flex-wrap gap-4">
106
+ <a href="/dashboard/pages/new" class="btn-premium px-10">
107
+ <i class="fas fa-plus mr-2"></i> Create Page
108
+ </a>
109
+ <% if @type == 'blog' %>
110
+ <a href="/dashboard/posts/new" class="px-8 py-3.5 rounded-2xl bg-white/5 border border-white/10 hover:bg-white/10 transition-all font-bold text-slate-700 dark:text-white flex items-center gap-2">
111
+ <i class="fas fa-pen-fancy mr-2"></i> New Article
112
+ </a>
113
+ <% elsif @type == 'portfolio' %>
114
+ <a href="/dashboard/projects/new" class="px-8 py-3.5 rounded-2xl bg-white/5 border border-white/10 hover:bg-white/10 transition-all font-bold text-slate-700 dark:text-white flex items-center gap-2">
115
+ <i class="fas fa-wand-magic-sparkles mr-2"></i> New Project
116
+ </a>
117
+ <% end %>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>