one-for-all-framework 1.0.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7da16da0dd7fd64c3418a570d9d9c2f366fe487a464cd524214ead23b249a932
4
- data.tar.gz: 43e95c18a2a0adc29c1c1fb39f95e175a11db8dd9fb70979b9ee04156d49c6f7
3
+ metadata.gz: 55f0f757d3582b86a7b3c4f3f55ed0074b66f680540d38dc6b7e0bcda9f484ed
4
+ data.tar.gz: 74c31da1387582d610f8b78aa5f174d22517921719623fc74f57e4c71adb077e
5
5
  SHA512:
6
- metadata.gz: 7e770e771c8cfd8e8e2c7d62a6b46e3a06cada5144a60a35c3d5348a06040a59158de1c2b9c807026c982fd74ea4c1e0f1be8e114f36f91b420955706a9b2e50
7
- data.tar.gz: 28c6bc05a32ddf5af5c78e74939adc3886b811c31a812e7fcba9d1b6b437f8f34bc7858917e1f7ef8463dbe93c93c05b7b8927e074b03838cbe1966fc7760761
6
+ metadata.gz: b28e6c8a6530c27c2d25121cc9ecf7bafaa2cb8c16f3d702893918bcf02e5f29890aeb35a2112293592c5104bb8ade48a51c468cd4712921e033965e6dde8b78
7
+ data.tar.gz: 3f69537492a02ddf4c559b358d6af8ebaef7e95ddaf034899ba84ba95e5e4a59c20764f44ca41334b50b49f8d51617ebab0ddc06600ffbc5ce9c3f7580484e9a
data/README.md CHANGED
@@ -56,16 +56,36 @@ Your app is now live at `http://localhost:3000` ⚡
56
56
 
57
57
  The `ofa` CLI is your best friend. Use it to manage your entire application lifecycle:
58
58
 
59
+ ### Project Management
59
60
  | Command | Description |
60
61
  | :--- | :--- |
61
- | `ofa new NAME` | Create a brand new project from scratch. |
62
- | `ofa g controller Name` | Generate a RESTful controller. |
63
- | `ofa g model Name` | Generate a database model and migration. |
64
- | `ofa db migrate` | Sync your database with the latest schema. |
65
- | `ofa type [blog\|portfolio]` | Switch application mode instantly. |
66
- | `ofa theme [dark\|light]` | Toggle between premium UI themes. |
67
- | `ofa storage cloudinary` | Enable automated Cloudinary image hosting. |
68
- | `ofa reset-password USR PWD`| Securely reset admin credentials. |
62
+ | `ofa new NAME [TYPE]` | Create a new project with automatic bundle install. |
63
+ | `ofa init [TYPE]` | Initialize project in current folder with interactive wizard. |
64
+ | `ofa run` | Start the high-performance development server. |
65
+ | `ofa deploy` | Deploy project to production (Railway/Docker ready). |
66
+
67
+ ### Generators (Scaffolding)
68
+ | Command | Description |
69
+ | :--- | :--- |
70
+ | `ofa g controller NAME` | Generate a RESTful controller in `app/controllers`. |
71
+ | `ofa g model NAME` | Generate a database model and migration. |
72
+ | `ofa g migration NAME` | Generate a new database migration file. |
73
+ | `ofa g post TITLE` | Create a new Markdown post (Supports `--category`, `--author`). |
74
+
75
+ ### Configuration & Features
76
+ | Command | Description |
77
+ | :--- | :--- |
78
+ | `ofa type [TYPE]` | Set app type: `portfolio`, `blog`, or `landing_page`. |
79
+ | `ofa theme [THEME]` | Set UI theme: `light_glass`, `dark_glass`, `cyber_sidebar`, etc. |
80
+ | `ofa feature enable [F]` | Toggle features like `cms` or `auth`. |
81
+ | `ofa storage [local\|cloudinary]` | Set image storage provider. |
82
+ | `ofa reset-password USR PWD`| Reset or create admin account credentials. |
83
+
84
+ ### Database Management
85
+ | Command | Description |
86
+ | :--- | :--- |
87
+ | `ofa db switch [ADAPTER]` | Switch DB: `sqlite`, `mysql`, `postgres`, `mongodb`. |
88
+ | `ofa db migrate` | Run all pending database migrations. |
69
89
 
70
90
  ---
71
91
 
@@ -9,7 +9,7 @@ class ApiController < ApplicationController
9
9
  end
10
10
 
11
11
  def status
12
- render_json({ status: 'ok', version: '1.0.0', type: FEATURES_CONFIG['type'] })
12
+ render_json({ status: 'ok', version: '2.0.0', type: FEATURES_CONFIG['type'] })
13
13
  end
14
14
 
15
15
  def halt_error(message, status: 400)
@@ -58,7 +58,7 @@ class ApplicationController
58
58
  rescue => e
59
59
  puts "⚠ Error deleting from Cloudinary: #{e.message}"
60
60
  end
61
- elsif url.start_with?('/img/uploads/')
61
+ elsif url.start_with?('/images/uploads/')
62
62
  path = File.join(APP_ROOT, 'public', url)
63
63
  FileUtils.rm(path) if File.exist?(path) rescue nil
64
64
  end
@@ -71,7 +71,7 @@ class ApplicationController
71
71
  urls.each { |url| delete_from_storage(url) }
72
72
 
73
73
  # Also find local uploads
74
- local_urls = content.scan(/\/img\/uploads\/[^\s\)]+/)
74
+ local_urls = content.scan(/\/images\/uploads\/[^\s\)]+/)
75
75
  local_urls.each { |url| delete_from_storage(url) }
76
76
  end
77
77
  end
@@ -27,9 +27,9 @@ class DashboardController < ApplicationController
27
27
  end
28
28
  else
29
29
  filename = "#{Time.now.to_i}_#{file[:filename]}"
30
- target = File.join(APP_ROOT, 'public/img/uploads', filename)
30
+ target = File.join(APP_ROOT, 'public/images/uploads', filename)
31
31
  FileUtils.cp(file[:tempfile].path, target)
32
- @res.body << { url: "/img/uploads/#{filename}" }.to_json
32
+ @res.body << { url: "/images/uploads/#{filename}" }.to_json
33
33
  end
34
34
  else
35
35
  @res.status = 400
data/app/views/docs.erb CHANGED
@@ -1,6 +1,6 @@
1
1
  <div class="space-y-12 pb-20">
2
2
  <div class="text-left">
3
- <div class="badge-premium">Documentation v1.0</div>
3
+ <div class="badge-premium">Documentation v2.0</div>
4
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
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
6
  </div>
@@ -45,21 +45,58 @@
45
45
  </tr>
46
46
  </thead>
47
47
  <tbody class="divide-y divide-white/5">
48
+ <tr class="bg-slate-500/5"><td colspan="2" class="px-6 py-2 text-[10px] font-black uppercase tracking-tighter text-slate-400">Project Management</td></tr>
49
+ <tr>
50
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa new [name]</td>
51
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Creates a new project from scratch.</td>
52
+ </tr>
48
53
  <tr>
49
54
  <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>
55
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Initializes environment & DB via wizard.</td>
51
56
  </tr>
52
57
  <tr>
53
58
  <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>
59
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Starts the development server.</td>
55
60
  </tr>
61
+ <tr>
62
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa deploy</td>
63
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Deploys to production environment.</td>
64
+ </tr>
65
+
66
+ <tr class="bg-slate-500/5"><td colspan="2" class="px-6 py-2 text-[10px] font-black uppercase tracking-tighter text-slate-400">Generators</td></tr>
56
67
  <tr>
57
68
  <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>
69
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Generates a RESTful controller.</td>
70
+ </tr>
71
+ <tr>
72
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa g model [name]</td>
73
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Generates a model & migration.</td>
74
+ </tr>
75
+ <tr>
76
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa g migration [name]</td>
77
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Creates a new schema migration.</td>
78
+ </tr>
79
+ <tr>
80
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa g post [title]</td>
81
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Creates a Markdown-based blog post.</td>
82
+ </tr>
83
+
84
+ <tr class="bg-slate-500/5"><td colspan="2" class="px-6 py-2 text-[10px] font-black uppercase tracking-tighter text-slate-400">Configuration</td></tr>
85
+ <tr>
86
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa theme [name]</td>
87
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Switch between UI themes instantly.</td>
88
+ </tr>
89
+ <tr>
90
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa type [type]</td>
91
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Change app mode (blog, portfolio, etc).</td>
92
+ </tr>
93
+ <tr>
94
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa storage [name]</td>
95
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Configure Local or Cloudinary storage.</td>
59
96
  </tr>
60
97
  <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>
98
+ <td class="px-6 py-4 font-mono text-sm text-primary">./ofa db switch [name]</td>
99
+ <td class="px-6 py-4 text-slate-600 dark:text-slate-400">Switch DB adapter (SQLite, MySQL, etc).</td>
63
100
  </tr>
64
101
  </tbody>
65
102
  </table>
@@ -79,8 +116,10 @@
79
116
  /models # Database entities
80
117
  /views # ERB templates
81
118
  /config
82
- /database.rb # DB connections
83
- /routes.rb # URL mapping
119
+ /database.json # DB configurations
120
+ /features.json # Feature toggles
121
+ /db
122
+ /migrations # Schema versions
84
123
  /public
85
124
  /images # Static assets
86
125
  /css # Custom styles
data/app/views/index.erb CHANGED
@@ -1,6 +1,6 @@
1
1
  <div class="text-center space-y-6 max-w-2xl mx-auto py-12">
2
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
3
+ Framework Version 2.0.0
4
4
  </div>
5
5
 
6
6
  <h1 class="text-5xl md:text-7xl font-black tracking-tight leading-tight">
data/app/views/layout.erb CHANGED
@@ -9,7 +9,7 @@
9
9
  <!-- Fonts & Icons -->
10
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
11
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">
12
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Fira+Code&family=VT323&display=swap" rel="stylesheet">
13
13
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
14
14
 
15
15
  <!-- Tailwind CSS CDN -->
@@ -27,13 +27,13 @@
27
27
  theme: {
28
28
  extend: {
29
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" %>',
30
+ primary: '<%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "#4f46e5" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "#f0f" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#0f0" : "#818cf8")) %>',
31
+ secondary: '<%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "#8b5cf6" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "#0ff" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#040" : "#c084fc")) %>',
32
+ surface: '<%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "rgba(255, 255, 255, 0.7)" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "rgba(20, 20, 20, 0.8)" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#050505" : "rgba(17, 24, 39, 0.6)")) %>',
33
+ bg: '<%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "#f8fafc" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "#000" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#0a0a0a" : "#030712")) %>',
34
34
  },
35
35
  fontFamily: {
36
- sans: ['Outfit', 'sans-serif'],
36
+ sans: ['<%= FEATURES_CONFIG["theme"] == "retro_terminal" ? "VT323" : "Outfit" %>', 'sans-serif'],
37
37
  mono: ['Fira Code', 'monospace'],
38
38
  },
39
39
  backdropBlur: {
@@ -46,15 +46,29 @@
46
46
 
47
47
  <style>
48
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)" %>;
49
+ --primary: <%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "#4f46e5" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "#f0f" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#0f0" : "#818cf8")) %>;
50
+ --secondary: <%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "#8b5cf6" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "#0ff" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#040" : "#c084fc")) %>;
51
+ --surface: <%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "rgba(255, 255, 255, 0.7)" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "rgba(20, 20, 20, 0.8)" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#050505" : "rgba(17, 24, 39, 0.6)")) %>;
52
+ --bg-color: <%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "#f8fafc" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "#000" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#0a0a0a" : "#030712")) %>;
53
+ --glass-border: <%= ["light_glass", "light_sidebar"].include?(FEATURES_CONFIG["theme"]) ? "rgba(0, 0, 0, 0.05)" : (FEATURES_CONFIG["theme"] == "cyber_sidebar" ? "#f0f" : (FEATURES_CONFIG["theme"] == "retro_terminal" ? "#0f0" : "rgba(255, 255, 255, 0.1)")) %>;
54
+ --neo-shadow: 8px 8px 0px 0px var(--primary);
54
55
  }
55
56
 
56
57
  body {
57
58
  background-color: var(--bg-color);
59
+ <% if FEATURES_CONFIG['theme'] == 'cyber_sidebar' %>
60
+ background-image:
61
+ linear-gradient(rgba(255, 0, 255, 0.05) 1px, transparent 1px),
62
+ linear-gradient(90deg, rgba(255, 0, 255, 0.05) 1px, transparent 1px);
63
+ background-size: 50px 50px;
64
+ <% elsif FEATURES_CONFIG['theme'] == 'light_sidebar' %>
65
+ background-image:
66
+ radial-gradient(at 0% 0%, hsla(220,100%,95%,1) 0, transparent 50%),
67
+ radial-gradient(at 100% 0%, hsla(320,100%,95%,0.8) 0, transparent 50%);
68
+ <% elsif FEATURES_CONFIG['theme'] == 'retro_terminal' %>
69
+ background-image: radial-gradient(circle, rgba(0, 255, 0, 0.05) 1px, transparent 1px);
70
+ background-size: 20px 20px;
71
+ <% else %>
58
72
  background-image:
59
73
  <% if FEATURES_CONFIG['theme'] == 'light_glass' %>
60
74
  radial-gradient(at 0% 0%, hsla(220,100%,95%,1) 0, transparent 50%),
@@ -65,7 +79,25 @@
65
79
  radial-gradient(at 50% 0%, hsla(225,39%,30%,0.15) 0, transparent 50%),
66
80
  radial-gradient(at 100% 0%, hsla(339,49%,30%,0.15) 0, transparent 50%);
67
81
  <% end %>
82
+ <% end %>
68
83
  background-attachment: fixed;
84
+ <% if FEATURES_CONFIG['theme'] == 'retro_terminal' %>
85
+ overflow-x: hidden;
86
+ <% end %>
87
+ }
88
+
89
+ .neo-card {
90
+ background: var(--surface);
91
+ border: 3px solid var(--primary);
92
+ box-shadow: var(--neo-shadow);
93
+ border-radius: 0px;
94
+ padding: 2rem;
95
+ transition: all 0.2s;
96
+ }
97
+
98
+ .neo-card:hover {
99
+ transform: translate(-4px, -4px);
100
+ box-shadow: 12px 12px 0px 0px var(--secondary);
69
101
  }
70
102
 
71
103
  .glass-panel {
@@ -184,9 +216,95 @@
184
216
  .markdown-content h1 { font-size: 2.25rem; font-weight: 800; margin: 2rem 0 1rem; color: var(--primary); }
185
217
  .markdown-content p { font-size: 1.125rem; color: #475569; margin-bottom: 1.5rem; }
186
218
  .dark .markdown-content p { color: #cbd5e1; }
219
+
220
+ /* Cyber Theme Specifics */
221
+ .cyber-border {
222
+ border: 2px solid var(--primary);
223
+ box-shadow: 4px 4px 0px var(--secondary);
224
+ }
225
+
226
+ .cyber-btn {
227
+ background: var(--primary);
228
+ color: black;
229
+ font-weight: 900;
230
+ text-transform: uppercase;
231
+ padding: 1rem 2rem;
232
+ border: none;
233
+ box-shadow: 6px 6px 0px var(--secondary);
234
+ transition: all 0.1s;
235
+ }
236
+
237
+ .cyber-btn:active {
238
+ transform: translate(2px, 2px);
239
+ box-shadow: 4px 4px 0px var(--secondary);
240
+ }
241
+
242
+ /* Global Text Color for Dark Themes */
243
+ .dark {
244
+ color: #e2e8f0;
245
+ }
246
+
247
+ .dark h1, .dark h2, .dark h3, .dark h4, .dark h5, .dark h6 {
248
+ color: <%= FEATURES_CONFIG['theme'] == 'retro_terminal' ? '#0f0' : '#ffffff' %> !important;
249
+ <% if FEATURES_CONFIG['theme'] == 'retro_terminal' %>
250
+ text-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
251
+ text-transform: uppercase;
252
+ letter-spacing: 2px;
253
+ <% end %>
254
+ }
255
+
256
+ .dark p, .dark span, .dark li, .dark a {
257
+ color: <%= FEATURES_CONFIG['theme'] == 'retro_terminal' ? '#0f0' : 'rgba(255, 255, 255, 0.9)' %>;
258
+ <% if FEATURES_CONFIG['theme'] == 'retro_terminal' %>
259
+ font-family: 'VT323', monospace;
260
+ font-size: 1.25rem;
261
+ <% end %>
262
+ }
263
+
264
+ .dark .text-slate-500, .dark .text-slate-600, .dark .text-slate-700 {
265
+ color: <%= FEATURES_CONFIG['theme'] == 'retro_terminal' ? '#0a0' : 'rgba(255, 255, 255, 0.7)' %> !important;
266
+ }
267
+
268
+ /* Scanlines for Retro Theme */
269
+ <% if FEATURES_CONFIG['theme'] == 'retro_terminal' %>
270
+ body::before {
271
+ content: " ";
272
+ display: block;
273
+ position: fixed;
274
+ top: 0; left: 0; bottom: 0; right: 0;
275
+ background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%),
276
+ linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
277
+ z-index: 999;
278
+ background-size: 100% 2px, 3px 100%;
279
+ pointer-events: none;
280
+ }
281
+
282
+ @keyframes flicker {
283
+ 0% { opacity: 0.97; }
284
+ 5% { opacity: 0.95; }
285
+ 10% { opacity: 0.9; }
286
+ 15% { opacity: 0.95; }
287
+ 20% { opacity: 0.98; }
288
+ 100% { opacity: 1; }
289
+ }
290
+
291
+ .dark main {
292
+ animation: flicker 0.15s infinite;
293
+ }
294
+
295
+ /* Fix visibility for buttons with background in Retro theme */
296
+ .dark .btn-premium,
297
+ .dark .bg-primary,
298
+ .dark .bg-white,
299
+ .dark .bg-primary > *,
300
+ .dark .bg-white > * {
301
+ color: #000000 !important;
302
+ text-shadow: none !important;
303
+ }
304
+ <% end %>
187
305
  </style>
188
306
  </head>
189
- <body class="<%= FEATURES_CONFIG['theme'] == 'dark_glass' ? 'dark' : '' %>">
307
+ <body class="<%= ['dark_glass', 'cyber_sidebar', 'retro_terminal'].include?(FEATURES_CONFIG['theme']) ? 'dark' : '' %>">
190
308
 
191
309
  <!-- Animated Background Shapes -->
192
310
  <div class="fixed inset-0 -z-10 overflow-hidden opacity-30 pointer-events-none">
@@ -194,7 +312,66 @@
194
312
  <div class="absolute top-1/2 -right-24 w-80 h-80 bg-secondary rounded-full blur-[100px] delay-700 animate-bounce"></div>
195
313
  </div>
196
314
 
197
- <!-- Navigation -->
315
+ <% if ['cyber_sidebar', 'light_sidebar'].include?(FEATURES_CONFIG['theme']) %>
316
+ <!-- Sidebar Layout -->
317
+ <div class="flex min-h-screen">
318
+ <!-- Sidebar -->
319
+ <aside class="fixed left-0 top-0 bottom-0 w-64 <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? 'glass-panel !rounded-none border-r border-black/5' : 'bg-black border-r-4 border-primary' %> p-6 z-50 hidden md:flex flex-col gap-10">
320
+ <div class="flex items-center gap-3">
321
+ <% if FEATURES_CONFIG['theme'] == 'light_sidebar' %>
322
+ <div class="w-10 h-10 bg-primary text-white flex items-center justify-center font-black text-xl rounded-xl shadow-lg shadow-primary/20">OF</div>
323
+ <span class="text-2xl font-black tracking-tighter text-slate-800">SYSTEM</span>
324
+ <% else %>
325
+ <div class="w-10 h-10 bg-primary flex items-center justify-center text-white font-black text-xl">OF</div>
326
+ <span class="text-2xl font-black tracking-tighter text-white">SYSTEM</span>
327
+ <% end %>
328
+ </div>
329
+
330
+ <nav class="flex flex-col gap-2">
331
+ <a href="/" class="p-4 <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? (req.path == '/' ? 'bg-primary/10 text-primary rounded-xl' : 'text-slate-600 hover:bg-primary/5 rounded-xl') : (req.path == '/' ? 'bg-primary text-white border-primary border-2 rounded-2xl' : 'border-white/10 text-white hover:border-primary border-2 rounded-2xl') %> font-bold transition-all">
332
+ <i class="fas fa-grid-2 mr-3"></i> OVERVIEW
333
+ </a>
334
+ <% Page.where(is_nav: true, is_active: true).all.each do |p| %>
335
+ <a href="/<%= p.slug %>" class="p-4 <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? (req.path == "/#{p.slug}" ? 'bg-primary/10 text-primary rounded-xl' : 'text-slate-600 hover:bg-primary/5 rounded-xl') : (req.path == "/#{p.slug}" ? 'bg-primary text-white border-primary border-2 rounded-2xl' : 'border-white/10 text-white hover:border-primary border-2 rounded-2xl') %> font-bold transition-all">
336
+ <i class="fas fa-file-code mr-3"></i> <%= p.title.upcase %>
337
+ </a>
338
+ <% end %>
339
+ <a href="/dashboard" class="p-4 <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? (req.path.start_with?('/dashboard') ? 'bg-primary/10 text-primary rounded-xl' : 'text-slate-600 hover:bg-primary/5 rounded-xl') : (req.path.start_with?('/dashboard') ? 'bg-primary text-white border-primary border-2 rounded-2xl' : 'border-white/10 text-white hover:border-primary border-2 rounded-2xl') %> font-bold transition-all">
340
+ <i class="fas fa-terminal mr-3"></i> CONSOLE
341
+ </a>
342
+ </nav>
343
+
344
+ <div class="mt-auto space-y-4">
345
+ <div class="p-4 <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? 'bg-slate-100/50 border border-slate-200 text-slate-500' : 'bg-white/5 border border-white/10 text-slate-400' %> text-[10px] font-mono rounded-xl">
346
+ <% if FEATURES_CONFIG['theme'] == 'light_sidebar' %>
347
+ SYSTEM: <span class="text-indigo-600 font-bold">OPERATIONAL</span><br>
348
+ LICENSE: <span class="text-slate-800">ENTERPRISE</span>
349
+ <% else %>
350
+ PROTOCOL: <span class="text-green-500 animate-pulse">SECURED</span><br>
351
+ UPLINK: <span class="text-primary">ENCRYPTED</span>
352
+ <% end %>
353
+ </div>
354
+ <a href="https://github.com/IshikawaUta/one-for-all-framework" class="flex items-center justify-center w-full p-4 <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? 'bg-slate-900 text-white rounded-xl shadow-lg shadow-slate-200' : 'bg-primary text-black border-2 border-primary rounded-2xl shadow-[4px_4px_0px_var(--secondary)]' %> font-black hover:opacity-90 hover:-translate-y-0.5 transition-all">
355
+ <i class="fab fa-github mr-2 text-lg"></i> <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? 'VIEW SOURCE' : 'ACCESS REPO' %>
356
+ </a>
357
+ </div>
358
+ </aside>
359
+
360
+ <!-- Mobile Header for Sidebar Themes -->
361
+ <header class="md:hidden fixed top-0 left-0 right-0 h-16 <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? 'glass-panel !rounded-none border-b border-black/5' : 'bg-black border-b-4 border-primary' %> z-[60] flex items-center justify-between px-6">
362
+ <span class="font-black <%= FEATURES_CONFIG['theme'] == 'light_sidebar' ? 'text-slate-800' : 'text-white' %>">OFA<span class="text-primary">.SYS</span></span>
363
+ <button id="mobile-menu-btn" class="text-primary"><i class="fas fa-bars text-2xl"></i></button>
364
+ </header>
365
+
366
+ <!-- Main Content Area -->
367
+ <main class="flex-1 md:ml-64 p-6 md:p-12 pt-24 md:pt-12">
368
+ <div class="max-w-5xl mx-auto">
369
+ <%= @content %>
370
+ </div>
371
+ </main>
372
+ </div>
373
+ <% else %>
374
+ <!-- Navigation (Original Top Nav) -->
198
375
  <header class="w-full flex justify-center p-4 sticky top-0 z-50">
199
376
  <nav class="glass-panel w-full max-w-4xl px-8 py-4 flex items-center justify-between">
200
377
  <div class="flex items-center gap-3">
@@ -210,15 +387,53 @@
210
387
  </ul>
211
388
 
212
389
  <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>
390
+ <a href="https://github.com/IshikawaUta/one-for-all-framework" class="text-slate-400 hover:text-primary transition-colors"><i class="fab fa-github text-xl"></i></a>
391
+ <button id="mobile-menu-btn" class="md:hidden text-slate-400 hover:text-primary transition-colors">
392
+ <i class="fas fa-bars text-xl"></i>
393
+ </button>
215
394
  </div>
216
395
  </nav>
217
396
  </header>
218
397
 
398
+
219
399
  <main class="container mx-auto max-w-4xl px-6 py-12">
220
400
  <%= @content %>
221
401
  </main>
402
+ <% end %>
403
+
404
+ <!-- Mobile Menu Overlay (Shared) -->
405
+ <div id="mobile-menu" class="fixed inset-0 z-[100] hidden">
406
+ <div id="mobile-menu-backdrop" class="absolute inset-0 bg-black/40 backdrop-blur-sm opacity-0"></div>
407
+ <div id="mobile-menu-content" class="absolute right-0 top-0 bottom-0 w-72 glass-panel !rounded-none border-l <%= ['light_sidebar', 'light_glass'].include?(FEATURES_CONFIG['theme']) ? 'border-black/5' : 'border-white/10' %> p-8 flex flex-col translate-x-full">
408
+ <div class="flex justify-between items-center mb-10">
409
+ <span class="text-xl font-black tracking-tighter">OFA<span class="text-primary">.menu</span></span>
410
+ <button id="mobile-menu-close" class="text-slate-400 hover:text-red-400 transition-colors">
411
+ <i class="fas fa-times text-2xl"></i>
412
+ </button>
413
+ </div>
414
+
415
+ <nav class="flex flex-col gap-6">
416
+ <a href="/" class="text-lg font-bold <%= req.path == '/' ? 'text-primary' : 'text-slate-500' %>">
417
+ <i class="fas fa-home w-8"></i> Home
418
+ </a>
419
+ <% Page.where(is_nav: true, is_active: true).all.each do |p| %>
420
+ <a href="/<%= p.slug %>" class="text-lg font-bold <%= req.path == "/#{p.slug}" ? 'text-primary' : 'text-slate-500' %>">
421
+ <i class="fas fa-file-alt w-8"></i> <%= p.title %>
422
+ </a>
423
+ <% end %>
424
+ <div class="h-px <%= ['light_sidebar', 'light_glass'].include?(FEATURES_CONFIG['theme']) ? 'bg-black/10' : 'bg-white/5' %> my-2"></div>
425
+ <a href="/dashboard" class="text-lg font-bold <%= req.path.start_with?('/dashboard') ? 'text-primary' : (['light_sidebar', 'light_glass'].include?(FEATURES_CONFIG['theme']) ? 'text-slate-600' : 'text-slate-500') %>">
426
+ <i class="fas fa-gauge-high w-8"></i> Dashboard
427
+ </a>
428
+ </nav>
429
+
430
+ <div class="mt-auto pt-10 border-t <%= ['light_sidebar', 'light_glass'].include?(FEATURES_CONFIG['theme']) ? 'border-black/10' : 'border-white/5' %> flex gap-6 justify-center">
431
+ <a href="#" class="text-slate-400 hover:text-primary text-xl"><i class="fab fa-twitter"></i></a>
432
+ <a href="#" class="text-slate-400 hover:text-primary text-xl"><i class="fab fa-discord"></i></a>
433
+ <a href="https://github.com/IshikawaUta/one-for-all-framework" class="text-slate-400 hover:text-primary text-xl"><i class="fab fa-github"></i></a>
434
+ </div>
435
+ </div>
436
+ </div>
222
437
 
223
438
  <!-- Footer -->
224
439
  <footer class="w-full py-12 mt-20 border-t border-white/5 text-center text-slate-500 text-sm">
@@ -244,6 +459,51 @@
244
459
  duration: 1000,
245
460
  easing: 'easeOutCubic'
246
461
  });
462
+
463
+ // Mobile Menu Logic
464
+ const menuBtn = document.getElementById('mobile-menu-btn');
465
+ const menuClose = document.getElementById('mobile-menu-close');
466
+ const menu = document.getElementById('mobile-menu');
467
+ const backdrop = document.getElementById('mobile-menu-backdrop');
468
+ const content = document.getElementById('mobile-menu-content');
469
+ let isMenuOpen = false;
470
+
471
+ const toggleMenu = () => {
472
+ isMenuOpen = !isMenuOpen;
473
+ if (isMenuOpen) {
474
+ menu.classList.remove('hidden');
475
+ anime({
476
+ targets: backdrop,
477
+ opacity: [0, 1],
478
+ duration: 400,
479
+ easing: 'easeOutQuad'
480
+ });
481
+ anime({
482
+ targets: content,
483
+ translateX: ['100%', '0%'],
484
+ duration: 600,
485
+ easing: 'easeOutExpo'
486
+ });
487
+ } else {
488
+ anime({
489
+ targets: backdrop,
490
+ opacity: 0,
491
+ duration: 300,
492
+ easing: 'easeInQuad'
493
+ });
494
+ anime({
495
+ targets: content,
496
+ translateX: '100%',
497
+ duration: 400,
498
+ easing: 'easeInExpo',
499
+ complete: () => menu.classList.add('hidden')
500
+ });
501
+ }
502
+ };
503
+
504
+ menuBtn.addEventListener('click', toggleMenu);
505
+ menuClose.addEventListener('click', toggleMenu);
506
+ backdrop.addEventListener('click', toggleMenu);
247
507
  });
248
508
  </script>
249
509
  </body>
data/app/views/login.erb CHANGED
@@ -38,7 +38,7 @@
38
38
 
39
39
  <div class="text-center pt-4 border-t border-white/5">
40
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>
41
+ Forgot password? <a href="mailto:komikers09@gmail.com" class="text-primary font-bold hover:underline">Contact System Admin</a>
42
42
  </p>
43
43
  </div>
44
44
  </div>
data/bin/ofa CHANGED
@@ -17,6 +17,13 @@ rescue LoadError
17
17
  end
18
18
 
19
19
  def help
20
+ puts " "
21
+ puts " ____ _______ ___ "
22
+ puts " / __ \\/ ____/ / | "
23
+ puts " / / / / /_ / /| | Framework "
24
+ puts "/ /_/ / __/ / ___ | Premium MVC "
25
+ puts "\\____/_/ /_/ |_| v2.0.0 "
26
+ puts " "
20
27
  puts "✨ One-For-All Framework CLI ✨"
21
28
  puts "-----------------------------"
22
29
  puts "Usage:"
@@ -28,7 +35,7 @@ def help
28
35
  puts " ofa g post TITLE - Create a new post [args: --category, --author, --image]"
29
36
  puts " ofa feature ACTION F - Toggle features: action=enable/disable, F=cms/auth"
30
37
  puts " ofa type NAME - Set application type: portfolio, blog, landing_page"
31
- puts " ofa theme NAME - Set UI theme: light_glass, dark_glass"
38
+ puts " ofa theme NAME - Set UI theme: light_glass, dark_glass, cyber_sidebar, retro_terminal, light_sidebar"
32
39
  puts " ofa storage NAME - Set image storage: local, cloudinary"
33
40
  puts " ofa reset-password USR PWD - Reset admin account password"
34
41
  puts " ofa db switch TYPE [NAME] - Switch DB: sqlite, mysql, mariadb, mongodb, postgres"
@@ -101,6 +108,13 @@ when 'new'
101
108
 
102
109
  when 'init'
103
110
  app_type = ARGV.shift || 'landing_page'
111
+ puts " "
112
+ puts " ____ _______ ___ "
113
+ puts " / __ \\/ ____/ / | "
114
+ puts " / / / / /_ / /| | Framework "
115
+ puts "/ /_/ / __/ / ___ | Premium MVC "
116
+ puts "\\____/_/ /_/ |_| v2.0.0 "
117
+ puts " "
104
118
  puts "Initializing One-For-All project as '#{app_type}' in #{PROJECT_ROOT}..."
105
119
 
106
120
  # --- Interactive Wizard ---
@@ -130,7 +144,7 @@ when 'init'
130
144
  puts "-----------------------------\n"
131
145
 
132
146
  # Create directories
133
- dirs = ['app/controllers', 'app/models', 'app/views', 'config', 'db/migrations', 'public/css', 'public/js', 'public/img', 'public/img/uploads']
147
+ dirs = ['app/controllers', 'app/models', 'app/views', 'config', 'db/migrations', 'public/css', 'public/js', 'public/images', 'public/images/uploads']
134
148
  dirs.each { |dir| FileUtils.mkdir_p(File.join(PROJECT_ROOT, dir)) }
135
149
 
136
150
  # Copy framework core migrations
@@ -263,8 +277,6 @@ when 'init'
263
277
  File.write(db_config_path, JSON.pretty_generate(db_default))
264
278
  end
265
279
 
266
- # Premium Scaffolding
267
- puts " Generating premium UI components..."
268
280
  # Copy views from framework to project
269
281
  framework_views = File.join(FRAMEWORK_ROOT, 'app', 'views')
270
282
  project_views = File.join(PROJECT_ROOT, 'app', 'views')
@@ -272,6 +284,14 @@ when 'init'
272
284
  # Recursive copy for views (including cms folder)
273
285
  FileUtils.cp_r(File.join(framework_views, '.'), project_views)
274
286
 
287
+ # Copy public assets from framework to project
288
+ framework_public = File.join(FRAMEWORK_ROOT, 'public')
289
+ project_public = File.join(PROJECT_ROOT, 'public')
290
+ if File.directory?(framework_public)
291
+ # Use cp_r with '.' to copy contents of public, not the public folder itself
292
+ FileUtils.cp_r(File.join(framework_public, '.'), project_public)
293
+ end
294
+
275
295
  # Copy models from framework to project
276
296
  framework_models = File.join(FRAMEWORK_ROOT, 'app', 'models')
277
297
  project_models = File.join(PROJECT_ROOT, 'app', 'models')
@@ -389,8 +409,8 @@ when 'type'
389
409
  when 'theme'
390
410
  ensure_initialized!
391
411
  name = ARGV.shift
392
- unless %w[light_glass dark_glass].include?(name)
393
- puts "❌ Error: Invalid theme '#{name}'. Choose: light_glass, dark_glass."
412
+ unless %w[light_glass dark_glass cyber_sidebar retro_terminal light_sidebar].include?(name)
413
+ puts "❌ Error: Invalid theme '#{name}'. Choose: light_glass, dark_glass, cyber_sidebar, retro_terminal, light_sidebar."
394
414
  exit 1
395
415
  end
396
416
  config_path = File.join(PROJECT_ROOT, 'config', 'features.json')
data/config/features.json CHANGED
@@ -2,6 +2,6 @@
2
2
  "auth": true,
3
3
  "cms": true,
4
4
  "type": "landing_page",
5
- "theme": "light_glass",
5
+ "theme": "light_sidebar",
6
6
  "storage": "cloudinary"
7
7
  }
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: one-for-all-framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ishikawa Uta