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.
- checksums.yaml +7 -0
- data/.env.example +4 -0
- data/Dockerfile +19 -0
- data/Gemfile +20 -0
- data/LICENSE +21 -0
- data/Procfile +1 -0
- data/README.md +99 -0
- data/app/controllers/api_controller.rb +19 -0
- data/app/controllers/application_controller.rb +77 -0
- data/app/controllers/auth_controller.rb +35 -0
- data/app/controllers/dashboard_controller.rb +41 -0
- data/app/controllers/pages_controller.rb +49 -0
- data/app/controllers/posts_controller.rb +48 -0
- data/app/controllers/projects_controller.rb +48 -0
- data/app/helpers/cloudinary_helper.rb +14 -0
- data/app/middleware/auth_middleware.rb +52 -0
- data/app/middleware/csrf_middleware.rb +27 -0
- data/app/models/page.rb +8 -0
- data/app/models/post.rb +8 -0
- data/app/models/project.rb +7 -0
- data/app/models/user.rb +83 -0
- data/app/views/blog_home.erb +70 -0
- data/app/views/cms/pages_form.erb +156 -0
- data/app/views/cms/pages_index.erb +104 -0
- data/app/views/cms/posts_form.erb +182 -0
- data/app/views/cms/posts_index.erb +100 -0
- data/app/views/cms/projects_form.erb +176 -0
- data/app/views/cms/projects_index.erb +96 -0
- data/app/views/dashboard.erb +122 -0
- data/app/views/docs.erb +140 -0
- data/app/views/error.erb +159 -0
- data/app/views/index.erb +70 -0
- data/app/views/layout.erb +251 -0
- data/app/views/login.erb +45 -0
- data/app/views/page.erb +21 -0
- data/app/views/portfolio.erb +73 -0
- data/app/views/post.erb +33 -0
- data/app/views/posts/hello_world.erb +3 -0
- data/app/views/project.erb +39 -0
- data/bin/ofa +499 -0
- data/config/boot.rb +134 -0
- data/config/database.json +4 -0
- data/config/database.rb +142 -0
- data/config/features.json +7 -0
- data/config/locales/en.json +6 -0
- data/config/locales/id.json +6 -0
- data/config/routes.rb +87 -0
- data/config.eks +11 -0
- data/config.ru +11 -0
- data/db/data.sqlite3 +0 -0
- data/db/development.sqlite3 +0 -0
- data/ofa +2 -0
- data/public/css/cms.css +134 -0
- data/public/images/logo.jpg +0 -0
- data/public/images/logo.png +0 -0
- metadata +259 -0
data/app/views/docs.erb
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<div class="space-y-12 pb-20">
|
|
2
|
+
<div class="text-left">
|
|
3
|
+
<div class="badge-premium">Documentation v1.0</div>
|
|
4
|
+
<h1 class="text-5xl font-black tracking-tighter mb-4 text-slate-700 dark:text-white">Framework <span class="text-primary">Guide</span></h1>
|
|
5
|
+
<p class="text-xl text-slate-500 max-w-2xl leading-relaxed">Everything you need to know about building premium web applications with the One-For-All framework.</p>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div class="grid grid-cols-1 md:grid-cols-4 gap-8">
|
|
9
|
+
<!-- Sidebar Navigation -->
|
|
10
|
+
<aside class="md:col-span-1 space-y-4 sticky top-28 h-fit hidden md:block">
|
|
11
|
+
<h4 class="text-xs font-black uppercase tracking-widest text-slate-400 mb-4 ml-4">Table of Contents</h4>
|
|
12
|
+
<nav class="space-y-1">
|
|
13
|
+
<a href="#intro" class="block px-4 py-2 rounded-xl hover:bg-primary/5 text-slate-600 hover:text-primary transition-all font-semibold border-l-2 border-transparent hover:border-primary">Introduction</a>
|
|
14
|
+
<a href="#cli" class="block px-4 py-2 rounded-xl hover:bg-primary/5 text-slate-600 hover:text-primary transition-all font-semibold border-l-2 border-transparent hover:border-primary">CLI Power Tools</a>
|
|
15
|
+
<a href="#structure" class="block px-4 py-2 rounded-xl hover:bg-primary/5 text-slate-600 hover:text-primary transition-all font-semibold border-l-2 border-transparent hover:border-primary">Project Structure</a>
|
|
16
|
+
<a href="#routing" class="block px-4 py-2 rounded-xl hover:bg-primary/5 text-slate-600 hover:text-primary transition-all font-semibold border-l-2 border-transparent hover:border-primary">Routing System</a>
|
|
17
|
+
<a href="#cms" class="block px-4 py-2 rounded-xl hover:bg-primary/5 text-slate-600 hover:text-primary transition-all font-semibold border-l-2 border-transparent hover:border-primary">CMS & Features</a>
|
|
18
|
+
</nav>
|
|
19
|
+
</aside>
|
|
20
|
+
|
|
21
|
+
<!-- Main Content -->
|
|
22
|
+
<div class="md:col-span-3 space-y-16">
|
|
23
|
+
<!-- Introduction -->
|
|
24
|
+
<section id="intro" class="glass-panel p-8 md:p-12 text-left">
|
|
25
|
+
<h2 class="text-3xl font-black tracking-tight mb-6 flex items-center gap-3">
|
|
26
|
+
<i class="fas fa-star text-primary"></i> Introduction
|
|
27
|
+
</h2>
|
|
28
|
+
<div class="markdown-content">
|
|
29
|
+
<p><strong>One-For-All (OFA)</strong> is a high-performance Ruby web framework focused on speed and aesthetics. It uses a modular architecture built on top of the <em>Eks-Cent</em> engine, allowing you to scale from simple landing pages to complex CMS-driven sites effortlessly.</p>
|
|
30
|
+
<p>Our philosophy is "Premium by Default". You shouldn't have to spend hours tweaking CSS just to get a modern look. With OFA, you get Glassmorphism, animations, and responsive layouts baked in.</p>
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
|
|
34
|
+
<!-- CLI Commands -->
|
|
35
|
+
<section id="cli" class="space-y-6 text-left">
|
|
36
|
+
<h2 class="text-3xl font-black tracking-tight flex items-center gap-3 ml-2">
|
|
37
|
+
<i class="fas fa-terminal text-primary"></i> CLI Power Tools
|
|
38
|
+
</h2>
|
|
39
|
+
<div class="glass-panel overflow-hidden">
|
|
40
|
+
<table class="w-full text-left border-collapse">
|
|
41
|
+
<thead class="bg-primary/5 border-b border-white/10">
|
|
42
|
+
<tr>
|
|
43
|
+
<th class="px-6 py-4 text-xs font-black uppercase text-slate-400">Command</th>
|
|
44
|
+
<th class="px-6 py-4 text-xs font-black uppercase text-slate-400">Action</th>
|
|
45
|
+
</tr>
|
|
46
|
+
</thead>
|
|
47
|
+
<tbody class="divide-y divide-white/5">
|
|
48
|
+
<tr>
|
|
49
|
+
<td class="px-6 py-4 font-mono text-sm text-primary">./ofa init</td>
|
|
50
|
+
<td class="px-6 py-4 text-slate-600 dark:text-slate-400">Initializes the project environment and DB.</td>
|
|
51
|
+
</tr>
|
|
52
|
+
<tr>
|
|
53
|
+
<td class="px-6 py-4 font-mono text-sm text-primary">./ofa run</td>
|
|
54
|
+
<td class="px-6 py-4 text-slate-600 dark:text-slate-400">Starts the Eksa development server.</td>
|
|
55
|
+
</tr>
|
|
56
|
+
<tr>
|
|
57
|
+
<td class="px-6 py-4 font-mono text-sm text-primary">./ofa g controller [name]</td>
|
|
58
|
+
<td class="px-6 py-4 text-slate-600 dark:text-slate-400">Generates a new controller in app/controllers.</td>
|
|
59
|
+
</tr>
|
|
60
|
+
<tr>
|
|
61
|
+
<td class="px-6 py-4 font-mono text-sm text-primary">./ofa theme [light|dark]</td>
|
|
62
|
+
<td class="px-6 py-4 text-slate-600 dark:text-slate-400">Instantly toggles between UI themes.</td>
|
|
63
|
+
</tr>
|
|
64
|
+
</tbody>
|
|
65
|
+
</table>
|
|
66
|
+
</div>
|
|
67
|
+
</section>
|
|
68
|
+
|
|
69
|
+
<!-- Structure -->
|
|
70
|
+
<section id="structure" class="glass-panel p-8 md:p-12 text-left">
|
|
71
|
+
<h2 class="text-3xl font-black tracking-tight mb-6 flex items-center gap-3">
|
|
72
|
+
<i class="fas fa-folder-tree text-primary"></i> Project Structure
|
|
73
|
+
</h2>
|
|
74
|
+
<div class="space-y-4">
|
|
75
|
+
<div class="p-4 bg-slate-900 rounded-2xl font-mono text-sm text-blue-400 overflow-x-auto">
|
|
76
|
+
<pre>
|
|
77
|
+
/app
|
|
78
|
+
/controllers # Logic handlers
|
|
79
|
+
/models # Database entities
|
|
80
|
+
/views # ERB templates
|
|
81
|
+
/config
|
|
82
|
+
/database.rb # DB connections
|
|
83
|
+
/routes.rb # URL mapping
|
|
84
|
+
/public
|
|
85
|
+
/images # Static assets
|
|
86
|
+
/css # Custom styles
|
|
87
|
+
</pre>
|
|
88
|
+
</div>
|
|
89
|
+
<p class="text-slate-500 text-sm">Most of your work will happen inside the <code>/app</code> directory following the standard MVC pattern.</p>
|
|
90
|
+
</div>
|
|
91
|
+
</section>
|
|
92
|
+
|
|
93
|
+
<!-- Routing -->
|
|
94
|
+
<section id="routing" class="space-y-6 text-left">
|
|
95
|
+
<h2 class="text-3xl font-black tracking-tight flex items-center gap-3 ml-2">
|
|
96
|
+
<i class="fas fa-route text-primary"></i> Routing System
|
|
97
|
+
</h2>
|
|
98
|
+
<div class="glass-panel p-8">
|
|
99
|
+
<p class="text-slate-600 dark:text-slate-400 mb-6">Routes are defined in <code>config/routes.rb</code> using a clean Ruby DSL. You can map simple URLs or use the <code>resources</code> helper for full CRUD.</p>
|
|
100
|
+
<div class="p-4 bg-slate-900 rounded-2xl font-mono text-sm text-green-400">
|
|
101
|
+
<pre>
|
|
102
|
+
# config/routes.rb
|
|
103
|
+
get "/" do |req, res|
|
|
104
|
+
res.render "home"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
resources :posts
|
|
108
|
+
</pre>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</section>
|
|
112
|
+
|
|
113
|
+
<!-- CMS -->
|
|
114
|
+
<section id="cms" class="glass-panel p-8 md:p-12 text-left bg-gradient-to-br from-primary/10 to-transparent">
|
|
115
|
+
<h2 class="text-3xl font-black tracking-tight mb-6 flex items-center gap-3">
|
|
116
|
+
<i class="fas fa-shield-halved text-primary"></i> CMS & Auth
|
|
117
|
+
</h2>
|
|
118
|
+
<div class="markdown-content">
|
|
119
|
+
<p>OFA comes with a secure built-in CMS dashboard accessible at <code>/dashboard</code>. To manage features, use the CLI:</p>
|
|
120
|
+
<div class="p-4 bg-white/5 border border-white/10 rounded-2xl mb-4 font-mono text-sm">
|
|
121
|
+
./ofa feature enable auth<br>
|
|
122
|
+
./ofa feature enable cms
|
|
123
|
+
</div>
|
|
124
|
+
<p>Authentication is handled via BCrypt hashing with an 8-hour session sliding expiration window for optimal security.</p>
|
|
125
|
+
</div>
|
|
126
|
+
</section>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<script>
|
|
132
|
+
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
133
|
+
anchor.addEventListener('click', function (e) {
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
document.querySelector(this.getAttribute('href')).scrollIntoView({
|
|
136
|
+
behavior: 'smooth'
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
</script>
|
data/app/views/error.erb
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= @code || "Error" %> — <%= @title || "One-For-All Framework" %></title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap" rel="stylesheet">
|
|
10
|
+
<style>
|
|
11
|
+
:root {
|
|
12
|
+
<% if FEATURES_CONFIG['theme'] == 'light_glass' %>
|
|
13
|
+
--primary: #4f46e5;
|
|
14
|
+
--bg: #f8fafc;
|
|
15
|
+
--card-bg: rgba(255, 255, 255, 0.7);
|
|
16
|
+
--text: #1e293b;
|
|
17
|
+
--text-muted: #64748b;
|
|
18
|
+
--accent: #8b5cf6;
|
|
19
|
+
--border: rgba(0, 0, 0, 0.05);
|
|
20
|
+
--error-color: #ef4444;
|
|
21
|
+
<% else %>
|
|
22
|
+
--primary: #818cf8;
|
|
23
|
+
--bg: #030712;
|
|
24
|
+
--card-bg: rgba(17, 24, 39, 0.7);
|
|
25
|
+
--text: #f9fafb;
|
|
26
|
+
--text-muted: #9ca3af;
|
|
27
|
+
--accent: #c084fc;
|
|
28
|
+
--border: rgba(255, 255, 255, 0.1);
|
|
29
|
+
--error-color: #f87171;
|
|
30
|
+
<% end %>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
font-family: 'Outfit', sans-serif;
|
|
37
|
+
background-color: var(--bg);
|
|
38
|
+
<% if FEATURES_CONFIG['theme'] == 'light_glass' %>
|
|
39
|
+
background-image: radial-gradient(at 0% 0%, hsla(220,100%,95%,1) 0, transparent 50%),
|
|
40
|
+
radial-gradient(at 100% 0%, hsla(320,100%,95%,0.5) 0, transparent 50%);
|
|
41
|
+
<% else %>
|
|
42
|
+
background-image: radial-gradient(at 0% 0%, hsla(253,16%,7%,1) 0, transparent 50%),
|
|
43
|
+
radial-gradient(at 100% 0%, hsla(339,49%,30%,0.1) 0, transparent 50%);
|
|
44
|
+
<% end %>
|
|
45
|
+
color: var(--text);
|
|
46
|
+
min-height: 100vh;
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
justify-content: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.error-card {
|
|
53
|
+
width: 100%;
|
|
54
|
+
max-width: 520px;
|
|
55
|
+
padding: 4rem 3rem;
|
|
56
|
+
border-radius: 3rem;
|
|
57
|
+
background: var(--card-bg);
|
|
58
|
+
backdrop-filter: blur(30px);
|
|
59
|
+
-webkit-backdrop-filter: blur(30px);
|
|
60
|
+
border: 1px solid var(--border);
|
|
61
|
+
box-shadow: 0 50px 100px -20px rgba(0,0,0,0.5);
|
|
62
|
+
text-align: center;
|
|
63
|
+
animation: fadeIn 0.8s cubic-bezier(0.16, 1, 0.3, 1);
|
|
64
|
+
position: relative;
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@keyframes fadeIn {
|
|
69
|
+
from { opacity: 0; transform: translateY(30px); }
|
|
70
|
+
to { opacity: 1; transform: translateY(0); }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.error-code {
|
|
74
|
+
font-size: 8rem;
|
|
75
|
+
font-weight: 900;
|
|
76
|
+
line-height: 1;
|
|
77
|
+
background: linear-gradient(135deg, var(--error-color), var(--accent));
|
|
78
|
+
-webkit-background-clip: text;
|
|
79
|
+
-webkit-text-fill-color: transparent;
|
|
80
|
+
margin-bottom: 1.5rem;
|
|
81
|
+
letter-spacing: -0.05em;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
h1 {
|
|
85
|
+
font-size: 2rem;
|
|
86
|
+
font-weight: 800;
|
|
87
|
+
color: var(--text);
|
|
88
|
+
margin-bottom: 1rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
p {
|
|
92
|
+
color: var(--text-muted);
|
|
93
|
+
margin-bottom: 3rem;
|
|
94
|
+
line-height: 1.8;
|
|
95
|
+
font-size: 1.1rem;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.btn-group {
|
|
99
|
+
display: flex;
|
|
100
|
+
gap: 1rem;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
flex-wrap: wrap;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
a {
|
|
106
|
+
display: inline-flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
padding: 1rem 2rem;
|
|
110
|
+
border-radius: 1.25rem;
|
|
111
|
+
text-decoration: none;
|
|
112
|
+
font-weight: 800;
|
|
113
|
+
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
114
|
+
font-size: 0.95rem;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.btn-primary {
|
|
118
|
+
background: var(--primary);
|
|
119
|
+
color: white;
|
|
120
|
+
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.btn-primary:hover {
|
|
124
|
+
transform: scale(1.05) translateY(-2px);
|
|
125
|
+
box-shadow: 0 20px 35px -5px rgba(0, 0, 0, 0.4);
|
|
126
|
+
filter: brightness(1.1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.btn-secondary {
|
|
130
|
+
background: rgba(255, 255, 255, 0.05);
|
|
131
|
+
color: var(--text-muted);
|
|
132
|
+
border: 1px solid var(--border);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.btn-secondary:hover {
|
|
136
|
+
background: rgba(255, 255, 255, 0.1);
|
|
137
|
+
color: var(--text);
|
|
138
|
+
border-color: var(--primary);
|
|
139
|
+
transform: scale(1.05);
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
142
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
143
|
+
</head>
|
|
144
|
+
<body>
|
|
145
|
+
<div class="error-card">
|
|
146
|
+
<div class="error-code"><%= @code || "???" %></div>
|
|
147
|
+
<h1><%= @title || "System Error" %></h1>
|
|
148
|
+
<p><%= @message || "An unexpected anomaly occurred." %></p>
|
|
149
|
+
<div class="btn-group">
|
|
150
|
+
<a href="/" class="btn-primary">
|
|
151
|
+
<i class="fas fa-home mr-2"></i> Home
|
|
152
|
+
</a>
|
|
153
|
+
<a href="javascript:history.back()" class="btn-secondary">
|
|
154
|
+
<i class="fas fa-chevron-left mr-2"></i> Back
|
|
155
|
+
</a>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</body>
|
|
159
|
+
</html>
|
data/app/views/index.erb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<div class="text-center space-y-6 max-w-2xl mx-auto py-12">
|
|
2
|
+
<div class="inline-flex items-center px-4 py-1.5 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-bold uppercase tracking-wider animate-pulse">
|
|
3
|
+
Framework Version 1.0.0
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<h1 class="text-5xl md:text-7xl font-black tracking-tight leading-tight">
|
|
7
|
+
One-For-All
|
|
8
|
+
</h1>
|
|
9
|
+
|
|
10
|
+
<p class="text-lg md:text-xl text-slate-500 dark:text-slate-400 max-w-xl mx-auto">
|
|
11
|
+
The high-performance MVC framework for modern Rubyists. Built for speed, aesthetics, and developer happiness.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<div class="flex flex-wrap justify-center gap-4 pt-4">
|
|
15
|
+
<% if session[:user_id] || session[:username] %>
|
|
16
|
+
<a href="/dashboard" class="btn-premium">
|
|
17
|
+
<i class="fas fa-gauge-high mr-2"></i> Dashboard
|
|
18
|
+
</a>
|
|
19
|
+
<form action="/logout" method="POST" class="inline">
|
|
20
|
+
<%= csrf_tag if defined?(csrf_tag) %>
|
|
21
|
+
<button type="submit" class="px-8 py-3 rounded-2xl border border-white/10 dark:border-white/5 font-semibold text-slate-600 dark:text-slate-300 hover:bg-white/5 transition-all">
|
|
22
|
+
Logout
|
|
23
|
+
</button>
|
|
24
|
+
</form>
|
|
25
|
+
<% else %>
|
|
26
|
+
<a href="/login" class="btn-premium">
|
|
27
|
+
Get Started <i class="fas fa-arrow-right ml-2 text-sm"></i>
|
|
28
|
+
</a>
|
|
29
|
+
<a href="/docs" class="px-8 py-3 rounded-2xl border border-white/10 dark:border-white/5 font-semibold text-slate-600 dark:text-slate-300 hover:bg-white/5 transition-all">
|
|
30
|
+
Read Documentation
|
|
31
|
+
</a>
|
|
32
|
+
<% end %>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 mt-24">
|
|
37
|
+
<div class="glass-card !p-10 group">
|
|
38
|
+
<div class="card-glow"></div>
|
|
39
|
+
<div class="w-16 h-16 bg-primary/10 rounded-2xl flex items-center justify-center text-primary text-3xl mb-8 group-hover:scale-110 group-hover:bg-primary group-hover:text-white transition-all duration-500 shadow-xl shadow-primary/10">
|
|
40
|
+
<i class="fas fa-rocket"></i>
|
|
41
|
+
</div>
|
|
42
|
+
<h3 class="text-2xl font-black mb-4 tracking-tighter">Lightning Fast</h3>
|
|
43
|
+
<p class="text-slate-500 dark:text-slate-400 leading-relaxed">
|
|
44
|
+
Optimized runtime performance and zero-config caching out of the box. Experience 100/100 Lighthouse scores.
|
|
45
|
+
</p>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="glass-card !p-10 group">
|
|
49
|
+
<div class="card-glow !bg-secondary/10"></div>
|
|
50
|
+
<div class="w-16 h-16 bg-secondary/10 rounded-2xl flex items-center justify-center text-secondary text-3xl mb-8 group-hover:scale-110 group-hover:bg-secondary group-hover:text-white transition-all duration-500 shadow-xl shadow-secondary/10">
|
|
51
|
+
<i class="fas fa-gem"></i>
|
|
52
|
+
</div>
|
|
53
|
+
<h3 class="text-2xl font-black mb-4 tracking-tighter">Clean MVC</h3>
|
|
54
|
+
<p class="text-slate-500 dark:text-slate-400 leading-relaxed">
|
|
55
|
+
Beautifully structured code inspired by the best modern web paradigms. Scalable, maintainable, and elegant.
|
|
56
|
+
</p>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="glass-card !p-10 group">
|
|
60
|
+
<div class="card-glow"></div>
|
|
61
|
+
<div class="w-16 h-16 bg-primary/10 rounded-2xl flex items-center justify-center text-primary text-3xl mb-8 group-hover:scale-110 group-hover:bg-primary group-hover:text-white transition-all duration-500 shadow-xl shadow-primary/10">
|
|
62
|
+
<i class="fas fa-shield-halved"></i>
|
|
63
|
+
</div>
|
|
64
|
+
<h3 class="text-2xl font-black mb-4 tracking-tighter">Secure by Default</h3>
|
|
65
|
+
<p class="text-slate-500 dark:text-slate-400 leading-relaxed">
|
|
66
|
+
Built-in protection against common vulnerabilities. CSRF, XSS, and SQL Injection mitigation ready.
|
|
67
|
+
</p>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= @title || "One-For-All Framework" %></title>
|
|
7
|
+
<link rel="icon" type="image/png" href="/images/logo.png">
|
|
8
|
+
|
|
9
|
+
<!-- Fonts & Icons -->
|
|
10
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
11
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
12
|
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Fira+Code&display=swap" rel="stylesheet">
|
|
13
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
14
|
+
|
|
15
|
+
<!-- Tailwind CSS CDN -->
|
|
16
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
17
|
+
|
|
18
|
+
<!-- Anime.js & Prism.js -->
|
|
19
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
|
|
20
|
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
|
|
21
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
|
|
22
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-ruby.min.js"></script>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
tailwind.config = {
|
|
26
|
+
darkMode: 'class',
|
|
27
|
+
theme: {
|
|
28
|
+
extend: {
|
|
29
|
+
colors: {
|
|
30
|
+
primary: '<%= FEATURES_CONFIG["theme"] == "light_glass" ? "#4f46e5" : "#818cf8" %>',
|
|
31
|
+
secondary: '<%= FEATURES_CONFIG["theme"] == "light_glass" ? "#8b5cf6" : "#c084fc" %>',
|
|
32
|
+
surface: '<%= FEATURES_CONFIG["theme"] == "light_glass" ? "rgba(255, 255, 255, 0.7)" : "rgba(17, 24, 39, 0.6)" %>',
|
|
33
|
+
bg: '<%= FEATURES_CONFIG["theme"] == "light_glass" ? "#f8fafc" : "#030712" %>',
|
|
34
|
+
},
|
|
35
|
+
fontFamily: {
|
|
36
|
+
sans: ['Outfit', 'sans-serif'],
|
|
37
|
+
mono: ['Fira Code', 'monospace'],
|
|
38
|
+
},
|
|
39
|
+
backdropBlur: {
|
|
40
|
+
xs: '2px',
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
:root {
|
|
49
|
+
--primary: <%= FEATURES_CONFIG["theme"] == "light_glass" ? "#4f46e5" : "#818cf8" %>;
|
|
50
|
+
--secondary: <%= FEATURES_CONFIG["theme"] == "light_glass" ? "#8b5cf6" : "#c084fc" %>;
|
|
51
|
+
--surface: <%= FEATURES_CONFIG["theme"] == "light_glass" ? "rgba(255, 255, 255, 0.7)" : "rgba(17, 24, 39, 0.6)" %>;
|
|
52
|
+
--bg-color: <%= FEATURES_CONFIG["theme"] == "light_glass" ? "#f8fafc" : "#030712" %>;
|
|
53
|
+
--glass-border: <%= FEATURES_CONFIG["theme"] == "light_glass" ? "rgba(0, 0, 0, 0.05)" : "rgba(255, 255, 255, 0.1)" %>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
body {
|
|
57
|
+
background-color: var(--bg-color);
|
|
58
|
+
background-image:
|
|
59
|
+
<% if FEATURES_CONFIG['theme'] == 'light_glass' %>
|
|
60
|
+
radial-gradient(at 0% 0%, hsla(220,100%,95%,1) 0, transparent 50%),
|
|
61
|
+
radial-gradient(at 50% 0%, hsla(250,100%,95%,0.8) 0, transparent 50%),
|
|
62
|
+
radial-gradient(at 100% 0%, hsla(320,100%,95%,0.8) 0, transparent 50%);
|
|
63
|
+
<% else %>
|
|
64
|
+
radial-gradient(at 0% 0%, hsla(253,16%,7%,1) 0, transparent 50%),
|
|
65
|
+
radial-gradient(at 50% 0%, hsla(225,39%,30%,0.15) 0, transparent 50%),
|
|
66
|
+
radial-gradient(at 100% 0%, hsla(339,49%,30%,0.15) 0, transparent 50%);
|
|
67
|
+
<% end %>
|
|
68
|
+
background-attachment: fixed;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.glass-panel {
|
|
72
|
+
background: var(--surface);
|
|
73
|
+
backdrop-filter: blur(20px);
|
|
74
|
+
-webkit-backdrop-filter: blur(20px);
|
|
75
|
+
border: 1px solid var(--glass-border);
|
|
76
|
+
border-radius: 1.5rem;
|
|
77
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.glass-card {
|
|
81
|
+
background: var(--surface);
|
|
82
|
+
backdrop-filter: blur(24px);
|
|
83
|
+
-webkit-backdrop-filter: blur(24px);
|
|
84
|
+
border: 1px solid var(--glass-border);
|
|
85
|
+
border-radius: 2.5rem;
|
|
86
|
+
padding: 2rem;
|
|
87
|
+
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
|
88
|
+
position: relative;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.glass-card:hover {
|
|
93
|
+
transform: translateY(-8px);
|
|
94
|
+
box-shadow: 0 30px 60px -12px rgba(0, 0, 0, 0.2), 0 0 40px var(--primary);
|
|
95
|
+
border-color: rgba(255, 255, 255, 0.2);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.card-glow {
|
|
99
|
+
position: absolute;
|
|
100
|
+
top: -50px;
|
|
101
|
+
right: -50px;
|
|
102
|
+
width: 200px;
|
|
103
|
+
height: 200px;
|
|
104
|
+
background: var(--primary);
|
|
105
|
+
filter: blur(80px);
|
|
106
|
+
opacity: 0.1;
|
|
107
|
+
border-radius: 50%;
|
|
108
|
+
transition: opacity 0.5s;
|
|
109
|
+
pointer-events: none;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.glass-card:hover .card-glow {
|
|
113
|
+
opacity: 0.2;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.btn-premium {
|
|
117
|
+
background: var(--primary);
|
|
118
|
+
color: white;
|
|
119
|
+
padding: 0.85rem 2rem;
|
|
120
|
+
border-radius: 1rem;
|
|
121
|
+
font-weight: 800;
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
transition: all 0.3s;
|
|
126
|
+
box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.2);
|
|
127
|
+
position: relative;
|
|
128
|
+
overflow: hidden;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.btn-premium:hover {
|
|
132
|
+
transform: scale(1.05);
|
|
133
|
+
box-shadow: 0 15px 30px -5px rgba(0, 0, 0, 0.3);
|
|
134
|
+
filter: brightness(1.1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.btn-secondary {
|
|
138
|
+
background: rgba(255, 255, 255, 0.05);
|
|
139
|
+
color: var(--text-muted);
|
|
140
|
+
padding: 0.85rem 2rem;
|
|
141
|
+
border-radius: 1rem;
|
|
142
|
+
font-weight: 700;
|
|
143
|
+
display: inline-flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
transition: all 0.3s;
|
|
147
|
+
border: 1px solid var(--glass-border);
|
|
148
|
+
backdrop-filter: blur(10px);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.btn-secondary:hover {
|
|
152
|
+
background: rgba(255, 255, 255, 0.1);
|
|
153
|
+
color: var(--primary);
|
|
154
|
+
border-color: var(--primary);
|
|
155
|
+
transform: translateX(-5px);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.badge-premium {
|
|
159
|
+
display: inline-flex;
|
|
160
|
+
padding: 0.25rem 0.75rem;
|
|
161
|
+
border-radius: 9999px;
|
|
162
|
+
background: rgba(79, 70, 229, 0.1);
|
|
163
|
+
color: var(--primary);
|
|
164
|
+
font-size: 0.65rem;
|
|
165
|
+
font-weight: 900;
|
|
166
|
+
text-transform: uppercase;
|
|
167
|
+
letter-spacing: 0.1em;
|
|
168
|
+
border: 1px solid rgba(79, 70, 229, 0.2);
|
|
169
|
+
margin-bottom: 1rem;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.nav-item {
|
|
173
|
+
color: #64748b;
|
|
174
|
+
font-weight: 600;
|
|
175
|
+
transition: color 0.3s;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.nav-item:hover, .nav-item.active {
|
|
179
|
+
color: var(--primary);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Markdown Overrides */
|
|
183
|
+
.markdown-content { text-align: left; line-height: 1.6; }
|
|
184
|
+
.markdown-content h1 { font-size: 2.25rem; font-weight: 800; margin: 2rem 0 1rem; color: var(--primary); }
|
|
185
|
+
.markdown-content p { font-size: 1.125rem; color: #475569; margin-bottom: 1.5rem; }
|
|
186
|
+
.dark .markdown-content p { color: #cbd5e1; }
|
|
187
|
+
</style>
|
|
188
|
+
</head>
|
|
189
|
+
<body class="<%= FEATURES_CONFIG['theme'] == 'dark_glass' ? 'dark' : '' %>">
|
|
190
|
+
|
|
191
|
+
<!-- Animated Background Shapes -->
|
|
192
|
+
<div class="fixed inset-0 -z-10 overflow-hidden opacity-30 pointer-events-none">
|
|
193
|
+
<div class="absolute -top-24 -left-24 w-96 h-96 bg-primary rounded-full blur-[120px] animate-pulse"></div>
|
|
194
|
+
<div class="absolute top-1/2 -right-24 w-80 h-80 bg-secondary rounded-full blur-[100px] delay-700 animate-bounce"></div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<!-- Navigation -->
|
|
198
|
+
<header class="w-full flex justify-center p-4 sticky top-0 z-50">
|
|
199
|
+
<nav class="glass-panel w-full max-w-4xl px-8 py-4 flex items-center justify-between">
|
|
200
|
+
<div class="flex items-center gap-3">
|
|
201
|
+
<span class="text-xl font-extrabold tracking-tighter">OFA<span class="text-primary">.framework</span></span>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
<ul class="hidden md:flex items-center gap-8">
|
|
205
|
+
<li><a href="/" class="nav-item <%= req.path == '/' ? 'active' : '' %>">Home</a></li>
|
|
206
|
+
<% Page.where(is_nav: true, is_active: true).all.each do |p| %>
|
|
207
|
+
<li><a href="/<%= p.slug %>" class="nav-item <%= req.path == "/#{p.slug}" ? 'active' : '' %>"><%= p.title %></a></li>
|
|
208
|
+
<% end %>
|
|
209
|
+
<li><a href="/dashboard" class="nav-item <%= req.path.start_with?('/dashboard') ? 'active' : '' %>">Dashboard</a></li>
|
|
210
|
+
</ul>
|
|
211
|
+
|
|
212
|
+
<div class="flex items-center gap-4">
|
|
213
|
+
<a href="https://github.com" class="text-slate-400 hover:text-primary transition-colors"><i class="fab fa-github text-xl"></i></a>
|
|
214
|
+
<button class="md:hidden text-slate-400"><i class="fas fa-bars text-xl"></i></button>
|
|
215
|
+
</div>
|
|
216
|
+
</nav>
|
|
217
|
+
</header>
|
|
218
|
+
|
|
219
|
+
<main class="container mx-auto max-w-4xl px-6 py-12">
|
|
220
|
+
<%= @content %>
|
|
221
|
+
</main>
|
|
222
|
+
|
|
223
|
+
<!-- Footer -->
|
|
224
|
+
<footer class="w-full py-12 mt-20 border-t border-white/5 text-center text-slate-500 text-sm">
|
|
225
|
+
<p>© <%= Time.now.year %> One-For-All Framework.</p>
|
|
226
|
+
</footer>
|
|
227
|
+
|
|
228
|
+
<script>
|
|
229
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
230
|
+
// Initial Page Load Animation
|
|
231
|
+
anime({
|
|
232
|
+
targets: 'header nav',
|
|
233
|
+
translateY: [-50, 0],
|
|
234
|
+
opacity: [0, 1],
|
|
235
|
+
duration: 1200,
|
|
236
|
+
easing: 'easeOutElastic(1, .8)'
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
anime({
|
|
240
|
+
targets: 'main > *',
|
|
241
|
+
translateY: [30, 0],
|
|
242
|
+
opacity: [0, 1],
|
|
243
|
+
delay: anime.stagger(100, {start: 300}),
|
|
244
|
+
duration: 1000,
|
|
245
|
+
easing: 'easeOutCubic'
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
</script>
|
|
249
|
+
</body>
|
|
250
|
+
</html>
|
|
251
|
+
|
data/app/views/login.erb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<div class="glass-panel max-w-md mx-auto p-10 space-y-8">
|
|
2
|
+
<div class="text-center">
|
|
3
|
+
<h2 class="text-3xl font-black tracking-tight">Welcome Back</h2>
|
|
4
|
+
<p class="text-slate-500 dark:text-slate-400 mt-2">Sign in to manage your framework.</p>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<% if @error %>
|
|
8
|
+
<div class="bg-red-500/10 border border-red-500/20 text-red-500 p-4 rounded-2xl text-sm font-semibold flex items-center gap-3">
|
|
9
|
+
<i class="fas fa-circle-exclamation"></i>
|
|
10
|
+
<%= @error %>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<form action="/login" method="POST" class="space-y-4">
|
|
15
|
+
<%= csrf_tag %>
|
|
16
|
+
<div class="space-y-1">
|
|
17
|
+
<label class="text-xs font-bold uppercase tracking-wider text-slate-400 ml-1">Username</label>
|
|
18
|
+
<div class="relative">
|
|
19
|
+
<i class="fas fa-user absolute left-4 top-1/2 -translate-y-1/2 text-slate-400 text-sm"></i>
|
|
20
|
+
<input type="text" name="username" placeholder="admin" required autofocus
|
|
21
|
+
class="w-full pl-12 pr-4 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">
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="space-y-1">
|
|
26
|
+
<label class="text-xs font-bold uppercase tracking-wider text-slate-400 ml-1">Password</label>
|
|
27
|
+
<div class="relative">
|
|
28
|
+
<i class="fas fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-slate-400 text-sm"></i>
|
|
29
|
+
<input type="password" name="password" placeholder="••••••••" required
|
|
30
|
+
class="w-full pl-12 pr-4 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">
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<button type="submit" class="btn-premium w-full mt-4">
|
|
35
|
+
Sign In <i class="fas fa-sign-in-alt ml-2"></i>
|
|
36
|
+
</button>
|
|
37
|
+
</form>
|
|
38
|
+
|
|
39
|
+
<div class="text-center pt-4 border-t border-white/5">
|
|
40
|
+
<p class="text-sm text-slate-500 dark:text-slate-400">
|
|
41
|
+
Forgot password? <a href="#" class="text-primary font-bold hover:underline">Contact System Admin</a>
|
|
42
|
+
</p>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|