eksa-framework 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dd935a9e6ef4c2873496c96eac7b209180f6745789efc34c82dd1695bef46a9c
4
+ data.tar.gz: b737c65117b5a2263ad9d2fb4fae2f7ebf9c97ec0296bbe76b379d24bfbc2a3c
5
+ SHA512:
6
+ metadata.gz: 40c3b4c98b336b078ff1cdaef039a4eb4d0827f904f2e158cb59ced2a8f345cb0a5be2c0b9bd36a9ae7be4531ff6fd2d7001a04378cb50f0ff105555664bea65
7
+ data.tar.gz: 90a0aaf449c9c8519112da50157fdd9d216f796fb0cd4ec38584debbf81e24099a2d4ec0cdd93c3a30e902cc6e9db3422ca75d49b73322ebda2d1af9fd27b11d
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rack'
4
+ gem 'puma'
5
+ gem 'sqlite3'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 IshikawaUta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # ✨ Eksa Framework
2
+
3
+ [![Ruby Version](https://img.shields.io/badge/ruby-3.0+-red.svg)](https://www.ruby-lang.org/)
4
+ [![Rack Version](https://img.shields.io/badge/rack-3.0+-blue.svg)](https://rack.github.io/)
5
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
6
+ [![Framework Role](https://img.shields.io/badge/UI-Glassmorphism-indigo.svg)](#)
7
+
8
+ **Eksa Framework** adalah *micro-framework* MVC (Model-View-Controller) modern yang dibangun di atas Ruby dan Rack. Didesain untuk pengembang yang menginginkan kecepatan, kode yang bersih, dan tampilan antarmuka **Glassmorphism** yang elegan secara *out-of-the-box*.
9
+
10
+ ---
11
+
12
+ ## 🚀 Fitur Unggulan
13
+ - 💎 **Modern Glassmorphism UI**: Tampilan transparan yang indah dengan Tailwind CSS & Lucide Icons.
14
+ - ⚡ **Rack 3 Ready**: Menggunakan standar terbaru dengan penanganan header modern.
15
+ - 🛠️ **CLI Generator**: Siapkan struktur project instan dengan perintah `eksa-init`.
16
+ - 💾 **Auto-Migration DB**: Database SQLite otomatis dibuat saat server pertama kali dijalankan.
17
+ - 🔔 **Flash Messages**: Notifikasi animasi elegan yang kompatibel dengan cookie Rack 3.
18
+ - 🛤️ **Simple Routing**: Sistem routing yang eksplisit dan mudah dikelola di `config.ru`.
19
+
20
+ ---
21
+
22
+ ## 🛠️ Instalasi Cepat
23
+
24
+ ### 1. Install via Gem
25
+ Anda bisa menginstal framework ini langsung dengan `gem`:
26
+
27
+ ```bash
28
+ gem install eksa-framework
29
+ ```
30
+
31
+ ### 2. Inisialisasi Project Baru
32
+
33
+ Masuk ke folder baru, lalu jalankan generator Eksa:
34
+
35
+ ```bash
36
+ mkdir my-awesome-app
37
+ cd my-awesome-app
38
+ eksa-init
39
+ ```
40
+
41
+ ### 3. Jalankan Server
42
+
43
+ ```bash
44
+ bundle install
45
+ rackup config.ru
46
+ ```
47
+
48
+ Buka browser dan akses `http://localhost:9292`.
49
+
50
+ ---
51
+
52
+ ## 💻 Panduan Pengembangan
53
+
54
+ ### 1. Struktur Folder
55
+
56
+ Eksa memisahkan data dari logika aplikasi dengan folder `db` di level root:
57
+
58
+ * `app/`: Logic & Views (Controllers, Models, Views).
59
+ * `db/`: File database SQLite `eksa_app.db` (Terpisah dari app).
60
+ * `lib/eksa/`: Core Engine (The magic happens here).
61
+ * `public/`: File statis (CSS, Images, JS).
62
+
63
+ ### 2. Menambah Route & Controller
64
+
65
+ Daftarkan rute di `config.ru`:
66
+
67
+ ```ruby
68
+ app.add_route "/profil", PagesController, :profil
69
+ ```
70
+
71
+ Buat method di `app/controllers/pages_controller.rb`:
72
+
73
+ ```ruby
74
+ def profil
75
+ render :profil # Merujuk ke app/views/profil.html.erb
76
+ end
77
+ ```
78
+
79
+ ### 3. Database & Model
80
+
81
+ Eksa akan otomatis membuat tabel saat Anda mendefinisikannya di `lib/eksa/model.rb`. Untuk menggunakan data di controller:
82
+
83
+ ```ruby
84
+ @pesan = Pesan.all # Menggunakan model app/models/pesan.rb
85
+ ```
86
+
87
+ ---
88
+
89
+ ## 🎨 Kustomisasi Visual
90
+
91
+ Eksa menggunakan **Tailwind CSS** dan **Animate.css**. Anda dapat mengatur efek kaca pada class `.glass` di `app/views/layout.html.erb`:
92
+
93
+ ```css
94
+ .glass {
95
+ background: rgba(255, 255, 255, 0.05);
96
+ backdrop-filter: blur(16px);
97
+ border: 1px solid rgba(255, 255, 255, 0.1);
98
+ }
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 📜 Lisensi
104
+
105
+ Proyek ini dilisensikan di bawah **MIT License**. Lihat file [LICENSE](https://www.google.com/search?q=LICENSE) untuk detail lebih lanjut.
@@ -0,0 +1,50 @@
1
+ require './app/models/pesan'
2
+
3
+ class PagesController < Eksa::Controller
4
+ def index
5
+ if request.post? && params['konten']
6
+ Pesan.buat(params['konten'], params['pengirim'])
7
+ return redirect_to "/", notice: "Pesan berhasil terkirim ke database!"
8
+ end
9
+
10
+ if params['q'] && !params['q'].empty?
11
+ @semua_pesan = Pesan.cari_kata(params['q'])
12
+ @keyword = params['q']
13
+ else
14
+ @semua_pesan = Pesan.semua
15
+ end
16
+
17
+ @nama = params['nama'] || "Developer"
18
+ render :index
19
+ end
20
+
21
+ def about
22
+ render :about
23
+ end
24
+
25
+ def docs
26
+ render :docs
27
+ end
28
+
29
+ def edit
30
+ @id = params['id']
31
+ @pesan = Pesan.cari(@id)
32
+
33
+ return redirect_to "/", notice: "Pesan tidak ditemukan!" if @pesan.nil?
34
+
35
+ if request.post?
36
+ Pesan.update(@id, params['konten'], params['pengirim'])
37
+ return redirect_to "/", notice: "Perubahan pesan berhasil disimpan."
38
+ end
39
+
40
+ render :edit
41
+ end
42
+
43
+ def hapus_pesan
44
+ if params['id']
45
+ Pesan.hapus(params['id'])
46
+ return redirect_to "/", notice: "Pesan telah berhasil dihapus."
47
+ end
48
+ redirect_to "/"
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ class Pesan < Eksa::Model
2
+ def self.semua
3
+ db.execute("SELECT * FROM pesan ORDER BY id DESC")
4
+ end
5
+
6
+ def self.buat(konten, pengirim)
7
+ db.execute("INSERT INTO pesan (konten, pengirim) VALUES (?, ?)", [konten.strip, pengirim.strip])
8
+ end
9
+
10
+ def self.cari(id)
11
+ db.execute("SELECT * FROM pesan WHERE id = ?", [id]).first
12
+ end
13
+
14
+ def self.update(id, konten, pengirim)
15
+ db.execute("UPDATE pesan SET konten = ?, pengirim = ? WHERE id = ?", [konten.strip, pengirim.strip, id])
16
+ end
17
+
18
+ def self.hapus(id)
19
+ db.execute("DELETE FROM pesan WHERE id = ?", [id])
20
+ end
21
+
22
+ def self.cari_kata(keyword)
23
+ db.execute("SELECT * FROM pesan WHERE konten LIKE ? OR pengirim LIKE ? ORDER BY id DESC", ["%#{keyword}%", "%#{keyword}%"])
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ <div class="glass rounded-3xl p-10 text-white animate__animated animate__fadeIn">
2
+ <div class="flex items-center gap-4 mb-8">
3
+ <div class="p-4 bg-indigo-500 rounded-2xl shadow-xl">
4
+ <i data-lucide="rocket" class="w-8 h-8"></i>
5
+ </div>
6
+ <h1 class="text-4xl font-extrabold tracking-tight">Tentang <span class="text-indigo-300">Eksa</span></h1>
7
+ </div>
8
+
9
+ <div class="space-y-6 text-white/80 leading-relaxed">
10
+ <p class="text-lg">
11
+ <strong>Eksa Framework</strong> adalah sebuah <strong>micro-framework</strong> Ruby yang dibangun dari nol untuk mendemonstrasikan kekuatan arsitektur MVC dan kesederhanaan Ruby.
12
+ </p>
13
+
14
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-8">
15
+ <div class="bg-white/5 p-6 rounded-2xl border border-white/10">
16
+ <i data-lucide="cpu" class="w-6 h-6 text-indigo-300 mb-3"></i>
17
+ <h3 class="font-bold text-white mb-2">Core Ruby</h3>
18
+ <p class="text-sm">Dibangun di atas Rack tanpa menggunakan framework besar lainnya.</p>
19
+ </div>
20
+ <div class="bg-white/5 p-6 rounded-2xl border border-white/10">
21
+ <i data-lucide="database" class="w-6 h-6 text-indigo-300 mb-3"></i>
22
+ <h3 class="font-bold text-white mb-2">SQLite Engine</h3>
23
+ <p class="text-sm">Penyimpanan data yang ringan, cepat, dan handal.</p>
24
+ </div>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="mt-12 pt-8 border-t border-white/10 flex justify-between items-center">
29
+ <a href="/" class="flex items-center gap-2 text-indigo-300 hover:text-white transition">
30
+ <i data-lucide="arrow-left" class="w-4 h-4"></i> Kembali ke Home
31
+ </a>
32
+ <span class="text-xs opacity-40 italic">Handcrafted with Ruby</span>
33
+ </div>
34
+ </div>
35
+
36
+ <script>lucide.createIcons();</script>
@@ -0,0 +1,120 @@
1
+ <div class="glass rounded-3xl p-8 md:p-12 animate__animated animate__fadeIn">
2
+ <div class="border-b border-white/10 pb-8 mb-8">
3
+ <div class="flex items-center gap-4 mb-4">
4
+ <div class="p-3 bg-indigo-500 rounded-2xl shadow-lg">
5
+ <i data-lucide="book-open" class="w-8 h-8"></i>
6
+ </div>
7
+ <h1 class="text-4xl font-extrabold tracking-tight">Dokumentasi <span class="text-indigo-300">Eksa</span></h1>
8
+ </div>
9
+ <p class="text-white/60 text-lg">Panduan profesional instalasi dan pengembangan aplikasi menggunakan Eksa Framework.</p>
10
+ </div>
11
+
12
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-8 mb-12">
13
+ <div class="space-y-4">
14
+ <h3 class="font-bold text-indigo-300 uppercase text-xs tracking-widest">Memulai</h3>
15
+ <ul class="space-y-2 text-sm">
16
+ <li><a href="#instalasi" class="hover:text-indigo-300 transition flex items-center gap-2"><i data-lucide="download" class="w-3 h-3"></i> Instalasi Gem</a></li>
17
+ <li><a href="#struktur" class="hover:text-indigo-300 transition flex items-center gap-2"><i data-lucide="folder" class="w-3 h-3"></i> Struktur Project</a></li>
18
+ </ul>
19
+ </div>
20
+ <div class="space-y-4">
21
+ <h3 class="font-bold text-indigo-300 uppercase text-xs tracking-widest">Pengembangan</h3>
22
+ <ul class="space-y-2 text-sm">
23
+ <li><a href="#routing" class="hover:text-indigo-300 transition flex items-center gap-2"><i data-lucide="git-branch" class="w-3 h-3"></i> Routing System</a></li>
24
+ <li><a href="#build" class="hover:text-indigo-300 transition flex items-center gap-2"><i data-lucide="package" class="w-3 h-3"></i> Build Framework</a></li>
25
+ </ul>
26
+ </div>
27
+ <div class="space-y-4">
28
+ <h3 class="font-bold text-indigo-300 uppercase text-xs tracking-widest">Fitur Core</h3>
29
+ <ul class="space-y-2 text-sm">
30
+ <li><a href="#database" class="hover:text-indigo-300 transition flex items-center gap-2"><i data-lucide="database" class="w-3 h-3"></i> Auto-Migration</a></li>
31
+ <li><a href="#flash" class="hover:text-indigo-300 transition flex items-center gap-2"><i data-lucide="bell" class="w-3 h-3"></i> Flash UI</a></li>
32
+ </ul>
33
+ </div>
34
+ </div>
35
+
36
+ <section id="instalasi" class="mb-12 scroll-mt-24">
37
+ <h2 class="text-2xl font-bold mb-4 flex items-center gap-2">
38
+ <i data-lucide="terminal" class="w-6 h-6 text-indigo-400"></i> Instalasi Cepat
39
+ </h2>
40
+ <div class="bg-black/40 rounded-2xl p-6 font-mono text-sm border border-white/10 space-y-3">
41
+ <div>
42
+ <p class="text-white/30"># 1. Install gem secara lokal</p>
43
+ <p class="text-indigo-300">gem install ./eksa-framework-0.1.0.gem</p>
44
+ </div>
45
+ <div>
46
+ <p class="text-white/30"># 2. Inisialisasi project baru</p>
47
+ <p class="text-indigo-300">eksa-init</p>
48
+ </div>
49
+ <div>
50
+ <p class="text-white/30"># 3. Jalankan server</p>
51
+ <p class="text-indigo-300">rackup config.ru</p>
52
+ </div>
53
+ </div>
54
+ </section>
55
+
56
+ <section id="routing" class="mb-12 scroll-mt-24">
57
+ <h2 class="text-2xl font-bold mb-4 flex items-center gap-2">
58
+ <i data-lucide="git-branch" class="w-6 h-6 text-indigo-400"></i> Routing System
59
+ </h2>
60
+ <p class="text-white/60 mb-4 text-sm">Definisikan rute aplikasi Anda di dalam file <code class="text-indigo-200">config.ru</code>. Eksa mendukung pemetaan URL ke Controller dan Action secara eksplisit.</p>
61
+ <div class="bg-black/40 rounded-2xl p-6 font-mono text-sm border border-white/10">
62
+ <p class="text-white/30"># app.add_route(path, controller_class, action_symbol)</p>
63
+ <p class="text-indigo-300 italic">app.add_route "/", PagesController, :index</p>
64
+ <p class="text-indigo-300 italic">app.add_route "/about", PagesController, :about</p>
65
+ </div>
66
+ </section>
67
+
68
+ <section id="database" class="mb-12 scroll-mt-24">
69
+ <h2 class="text-2xl font-bold mb-4 flex items-center gap-2">
70
+ <i data-lucide="database" class="w-6 h-6 text-indigo-400"></i> Auto-Migration
71
+ </h2>
72
+ <p class="text-white/60 mb-4 text-sm">Eksa secara otomatis membuat file database dan tabel saat aplikasi pertama kali dijalankan melalui <code class="text-indigo-200">Eksa::Model</code>.</p>
73
+ <div class="bg-black/40 rounded-2xl p-6 font-mono text-sm border border-white/10">
74
+ <p class="text-indigo-300">def self.setup_initial_schema</p>
75
+ <p class="text-white/70 ml-4">@db.execute "CREATE TABLE IF NOT EXISTS pesan (...)"</p>
76
+ <p class="text-indigo-300">end</p>
77
+ </div>
78
+ <p class="text-xs text-white/40 mt-3 italic">* Database tersimpan secara persisten di folder /db/eksa_app.db</p>
79
+ </section>
80
+
81
+ <section id="flash" class="mb-12 scroll-mt-24">
82
+ <h2 class="text-2xl font-bold mb-4 flex items-center gap-2">
83
+ <i data-lucide="bell" class="w-6 h-6 text-indigo-400"></i> Flash UI Notification
84
+ </h2>
85
+ <p class="text-white/60 mb-4 text-sm">Kirim feedback instan ke user menggunakan fitur redirect dengan notice.</p>
86
+ <div class="bg-black/40 rounded-2xl p-6 font-mono text-sm border border-white/10">
87
+ <p class="text-white/30"># Di dalam Controller</p>
88
+ <p class="text-indigo-300">redirect_to "/", notice: "Data berhasil disimpan!"</p>
89
+ </div>
90
+ <div class="mt-4 p-4 bg-emerald-500/10 border border-emerald-500/20 rounded-xl flex items-center gap-3">
91
+ <i data-lucide="info" class="w-5 h-5 text-emerald-400"></i>
92
+ <p class="text-xs text-emerald-200/80">Sistem Flash Eksa menggunakan cookie sementara yang otomatis dihapus setelah notifikasi muncul (Standar Rack 3).</p>
93
+ </div>
94
+ </section>
95
+
96
+ <section id="build" class="mb-12 scroll-mt-24">
97
+ <h2 class="text-2xl font-bold mb-4 flex items-center gap-2">
98
+ <i data-lucide="package-check" class="w-6 h-6 text-indigo-400"></i> Build ke RubyGems
99
+ </h2>
100
+ <div class="bg-black/40 rounded-2xl p-6 font-mono text-sm border border-white/10">
101
+ <p class="text-indigo-300">gem build eksa-framework.gemspec</p>
102
+ <p class="text-indigo-300 mt-2">gem install ./eksa-framework-0.1.0.gem</p>
103
+ </div>
104
+ </section>
105
+
106
+ <div class="mt-12 pt-8 border-t border-white/10 text-center">
107
+ <div class="flex justify-center gap-4 mb-4">
108
+ <span class="bg-indigo-500/20 text-indigo-300 text-[10px] px-3 py-1 rounded-full border border-indigo-500/30 uppercase tracking-tighter">Rack 3.0 Compatible</span>
109
+ <span class="bg-emerald-500/20 text-emerald-300 text-[10px] px-3 py-1 rounded-full border border-emerald-500/30 uppercase tracking-tighter">SQLite3 Auto-Ready</span>
110
+ </div>
111
+ <p class="text-white/40 text-sm italic">Eksa Framework v<%= Eksa::VERSION %> Alpha Documentation</p>
112
+ <a href="/" class="inline-block mt-6 text-indigo-300 hover:text-white transition font-bold flex items-center justify-center gap-2">
113
+ <i data-lucide="arrow-left" class="w-4 h-4"></i> Kembali ke Beranda
114
+ </a>
115
+ </div>
116
+ </div>
117
+
118
+ <script>
119
+ lucide.createIcons();
120
+ </script>
@@ -0,0 +1,50 @@
1
+ <div class="glass rounded-3xl p-8 max-w-xl mx-auto animate__animated animate__zoomIn">
2
+ <div class="flex items-center gap-4 mb-6">
3
+ <div class="p-3 bg-indigo-500/20 rounded-2xl border border-indigo-500/30 text-indigo-300">
4
+ <i data-lucide="edit-3" class="w-6 h-6"></i>
5
+ </div>
6
+ <div>
7
+ <span class="text-xs font-bold uppercase tracking-widest text-indigo-300 opacity-80">Mode Edit</span>
8
+ <h1 class="text-3xl font-bold tracking-tight text-white">Revisi Pesan <span class="text-indigo-300">#<%= @id %></span></h1>
9
+ </div>
10
+ </div>
11
+
12
+ <p class="text-white/60 mb-8">
13
+ Lakukan perubahan pada konten atau pengirim. Perubahan akan langsung diperbarui di database SQLite.
14
+ </p>
15
+
16
+ <form action="/edit?id=<%= @id %>" method="post" class="space-y-6">
17
+ <div class="space-y-2">
18
+ <label class="text-sm font-semibold text-white/80 ml-1 flex items-center gap-2">
19
+ <i data-lucide="user" class="w-4 h-4 text-indigo-300"></i> Nama Pengirim
20
+ </label>
21
+ <input type="text" name="pengirim" value="<%= @pesan[2] %>" required
22
+ class="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition text-white placeholder-white/20">
23
+ </div>
24
+
25
+ <div class="space-y-2">
26
+ <label class="text-sm font-semibold text-white/80 ml-1 flex items-center gap-2">
27
+ <i data-lucide="message-circle" class="w-4 h-4 text-indigo-300"></i> Isi Pesan
28
+ </label>
29
+ <textarea name="konten" required
30
+ class="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition text-white placeholder-white/20 h-40 resize-none"><%= @pesan[1] %></textarea>
31
+ </div>
32
+
33
+ <div class="flex flex-col sm:flex-row gap-4 pt-4">
34
+ <button type="submit"
35
+ class="flex-[2] bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-3 px-6 rounded-xl transition duration-300 flex items-center justify-center gap-2 shadow-lg shadow-indigo-900/20">
36
+ <i data-lucide="save" class="w-5 h-5"></i> Simpan Perubahan
37
+ </button>
38
+
39
+ <a href="/"
40
+ class="flex-[1] bg-white/5 hover:bg-white/10 text-white text-center font-bold py-3 px-6 rounded-xl border border-white/10 transition flex items-center justify-center gap-2">
41
+ <i data-lucide="arrow-left" class="w-4 h-4 text-white/60"></i> Batal
42
+ </a>
43
+ </div>
44
+ </form>
45
+ </div>
46
+
47
+ <script>
48
+ // Inisialisasi ikon untuk halaman ini
49
+ lucide.createIcons();
50
+ </script>
@@ -0,0 +1,108 @@
1
+ <div class="glass rounded-3xl p-8 animate__animated animate__fadeIn">
2
+ <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8 gap-4">
3
+ <div>
4
+ <span class="inline-block bg-indigo-500/20 text-indigo-200 text-xs font-bold px-3 py-1 rounded-full mb-3 border border-indigo-500/30">
5
+ v0.1.0 Alpha
6
+ </span>
7
+ <h1 class="text-4xl font-extrabold tracking-tight">
8
+ Halo, <span class="text-indigo-300"><%= @nama %></span>!
9
+ </h1>
10
+ <p class="text-white/60 mt-2">
11
+ Selamat datang di dunia pengembangan web yang bersih dan cepat dengan <strong>Eksa Framework</strong>.
12
+ </p>
13
+ </div>
14
+
15
+ <form action="/" method="get" class="flex w-full md:w-auto">
16
+ <div class="relative w-full">
17
+ <input type="text" name="q" placeholder="Cari pesan..." value="<%= @keyword %>"
18
+ class="w-full md:w-48 bg-white/5 border border-white/10 rounded-xl py-2 pl-4 pr-10 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:w-64 transition-all duration-300 placeholder-white/30 text-sm">
19
+ <button type="submit" class="absolute right-2 top-1.5 p-1 text-white/40 hover:text-white transition">
20
+ <i data-lucide="search" class="w-4 h-4"></i>
21
+ </button>
22
+ </div>
23
+ </form>
24
+ </div>
25
+
26
+ <div class="grid grid-cols-1 lg:grid-cols-5 gap-8">
27
+
28
+ <div class="lg:col-span-2 space-y-6">
29
+ <div class="bg-white/5 border border-white/10 rounded-2xl p-6">
30
+ <h2 class="text-lg font-bold mb-4 flex items-center gap-2">
31
+ <i data-lucide="pen-tool" class="w-5 h-5 text-indigo-300"></i> Kirim Pesan
32
+ </h2>
33
+ <form action="/" method="post" class="space-y-4">
34
+ <div>
35
+ <input type="text" name="pengirim" placeholder="Nama Anda" required
36
+ class="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition placeholder-white/20">
37
+ </div>
38
+ <div>
39
+ <textarea name="konten" placeholder="Tulis pesan kreatifmu di sini..." required
40
+ class="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 transition placeholder-white/20 h-32 resize-none"></textarea>
41
+ </div>
42
+ <button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-500 text-white font-bold py-3 rounded-xl transition duration-300 flex items-center justify-center gap-2 shadow-lg shadow-indigo-900/20">
43
+ <i data-lucide="send" class="w-4 h-4"></i> Simpan ke SQLite
44
+ </button>
45
+ </form>
46
+ </div>
47
+ </div>
48
+
49
+ <div class="lg:col-span-3">
50
+ <div class="flex items-center justify-between mb-4">
51
+ <h2 class="text-lg font-bold flex items-center gap-2">
52
+ <i data-lucide="message-square" class="w-5 h-5 text-indigo-300"></i> Pesan Terbaru
53
+ </h2>
54
+ <% if @keyword && !@keyword.empty? %>
55
+ <a href="/" class="text-xs bg-white/10 hover:bg-white/20 px-3 py-1 rounded-lg transition flex items-center gap-1">
56
+ <i data-lucide="x" class="w-3 h-3"></i> Bersihkan Filter
57
+ </a>
58
+ <% end %>
59
+ </div>
60
+
61
+ <% if @keyword && !@keyword.empty? %>
62
+ <p class="text-sm text-white/40 mb-4 italic">Menampilkan hasil pencarian untuk "<%= @keyword %>"</p>
63
+ <% end %>
64
+
65
+ <div class="space-y-4 overflow-y-auto max-h-[500px] pr-2 custom-scrollbar">
66
+ <% if @semua_pesan.any? %>
67
+ <% @semua_pesan.each do |p| %>
68
+ <div class="bg-white/5 border border-white/10 p-5 rounded-2xl flex justify-between items-start group hover:bg-white/10 transition duration-300 animate__animated animate__fadeInUp">
69
+ <div class="max-w-[70%]">
70
+ <div class="flex items-center gap-2 mb-1">
71
+ <div class="w-2 h-2 bg-indigo-400 rounded-full"></div>
72
+ <strong class="text-indigo-200"><%= p[2] %></strong>
73
+ </div>
74
+ <p class="text-white/70 text-sm leading-relaxed"><%= p[1] %></p>
75
+ </div>
76
+
77
+ <div class="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity duration-300">
78
+ <a href="/edit?id=<%= p[0] %>" title="Edit"
79
+ class="p-2 bg-white/10 hover:bg-indigo-500 rounded-lg transition">
80
+ <i data-lucide="edit-3" class="w-4 h-4 text-white"></i>
81
+ </a>
82
+ <a href="/hapus?id=<%= p[0] %>"
83
+ onclick="return confirm('Yakin ingin menghapus pesan dari <%= p[2] %>?')"
84
+ title="Hapus"
85
+ class="p-2 bg-white/10 hover:bg-red-500 rounded-lg transition">
86
+ <i data-lucide="trash-2" class="w-4 h-4 text-white"></i>
87
+ </a>
88
+ </div>
89
+ </div>
90
+ <% end %>
91
+ <% else %>
92
+ <div class="flex flex-col items-center justify-center py-20 bg-white/5 rounded-2xl border border-dashed border-white/10">
93
+ <i data-lucide="ghost" class="w-12 h-12 text-white/10 mb-2"></i>
94
+ <p class="text-white/30 italic text-sm">
95
+ <%= @keyword ? "Tidak ada pesan yang cocok." : "Database masih kosong." %>
96
+ </p>
97
+ </div>
98
+ <% end %>
99
+ </div>
100
+ </div>
101
+
102
+ </div>
103
+ </div>
104
+
105
+ <script>
106
+ // Refresh icons for new content
107
+ lucide.createIcons();
108
+ </script>
@@ -0,0 +1,127 @@
1
+ <!DOCTYPE html>
2
+ <html lang="id">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Eksa Framework | Modern Ruby Development</title>
7
+
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
11
+ <script src="https://cdn.tailwindcss.com"></script>
12
+ <link rel="icon" href="/img/logo.png" type="image/png">
13
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
14
+ <script src="https://unpkg.com/lucide@latest"></script>
15
+
16
+ <style>
17
+ body {
18
+ font-family: 'Inter', sans-serif;
19
+ background: radial-gradient(circle at top left, #4f46e5, #764ba2, #2d3748);
20
+ background-attachment: fixed;
21
+ min-height: 100vh;
22
+ display: flex;
23
+ flex-direction: column;
24
+ }
25
+
26
+ .glass {
27
+ background: rgba(255, 255, 255, 0.1);
28
+ backdrop-filter: blur(16px) saturate(180%);
29
+ -webkit-backdrop-filter: blur(16px) saturate(180%);
30
+ border: 1px solid rgba(255, 255, 255, 0.2);
31
+ }
32
+
33
+ .nav-blur {
34
+ background: rgba(255, 255, 255, 0.05);
35
+ backdrop-filter: blur(10px);
36
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
37
+ }
38
+
39
+ .nav-link {
40
+ position: relative;
41
+ transition: all 0.3s ease;
42
+ }
43
+ .nav-link::after {
44
+ content: '';
45
+ position: absolute;
46
+ width: 0;
47
+ height: 2px;
48
+ bottom: -4px;
49
+ left: 0;
50
+ background-color: #a5b4fc;
51
+ transition: width 0.3s ease;
52
+ }
53
+ .nav-link:hover::after {
54
+ width: 100%;
55
+ }
56
+
57
+ /* Custom Scrollbar untuk list pesan */
58
+ .custom-scrollbar::-webkit-scrollbar {
59
+ width: 6px;
60
+ }
61
+ .custom-scrollbar::-webkit-scrollbar-track {
62
+ background: rgba(255, 255, 255, 0.05);
63
+ }
64
+ .custom-scrollbar::-webkit-scrollbar-thumb {
65
+ background: rgba(255, 255, 255, 0.2);
66
+ border-radius: 10px;
67
+ }
68
+ </style>
69
+ </head>
70
+ <body class="text-white antialiased">
71
+
72
+ <% if @flash && @flash[:notice] %>
73
+ <div id="flash-msg" class="fixed top-24 left-1/2 -translate-x-1/2 z-[60] animate__animated animate__fadeInDown">
74
+ <div class="flex items-center gap-3 bg-emerald-500/90 backdrop-blur-md text-white px-6 py-3 rounded-2xl shadow-2xl border border-emerald-400/50 shadow-emerald-900/40">
75
+ <i data-lucide="check-circle" class="w-5 h-5"></i>
76
+ <span class="font-bold text-sm tracking-wide"><%= @flash[:notice] %></span>
77
+ <button onclick="closeFlash()" class="ml-4 opacity-50 hover:opacity-100 transition">
78
+ <i data-lucide="x" class="w-4 h-4"></i>
79
+ </button>
80
+ </div>
81
+ </div>
82
+ <script>
83
+ function closeFlash() {
84
+ const msg = document.getElementById('flash-msg');
85
+ if(msg) {
86
+ msg.classList.replace('animate__fadeInDown', 'animate__fadeOutUp');
87
+ setTimeout(() => msg.remove(), 800);
88
+ }
89
+ }
90
+ // Otomatis tutup setelah 4 detik
91
+ setTimeout(closeFlash, 4000);
92
+ </script>
93
+ <% end %>
94
+
95
+ <nav class="nav-blur sticky top-0 z-50 px-6 py-4 flex items-center justify-between animate__animated animate__fadeInDown">
96
+ <div onclick="window.location.href='/'" class="flex items-center gap-3 group cursor-pointer">
97
+ <div class="p-2 bg-indigo-500 rounded-xl shadow-lg shadow-indigo-500/50 group-hover:rotate-12 transition-transform">
98
+ <i data-lucide="layers" class="w-6 h-6"></i>
99
+ </div>
100
+ <span class="text-xl font-extrabold tracking-tight">Eksa<span class="text-indigo-300">Framework</span></span>
101
+ </div>
102
+
103
+ <ul class="hidden md:flex items-center gap-8 font-medium text-sm">
104
+ <li><a href="/" class="nav-link flex items-center gap-2"><i data-lucide="home" class="w-4 h-4"></i> Home</a></li>
105
+ <li><a href="/about" class="nav-link flex items-center gap-2"><i data-lucide="info" class="w-4 h-4"></i> About</a></li>
106
+ <li><a href="/docs" class="nav-link flex items-center gap-2"><i data-lucide="book-open" class="w-4 h-4"></i> Docs</a></li>
107
+ </ul>
108
+
109
+ <div class="flex items-center gap-4">
110
+ <a href="https://github.com/IshikawaUta" target="_blank" class="p-2 hover:bg-white/10 rounded-full transition"><i data-lucide="github" class="w-5 h-5"></i></a>
111
+ </div>
112
+ </nav>
113
+
114
+ <main class="max-w-6xl mx-auto py-12 px-6 flex-grow animate__animated animate__fadeInUp">
115
+ <%= @content %>
116
+ </main>
117
+
118
+ <footer class="py-8 text-center text-white/40 text-sm border-t border-white/5">
119
+ <p>&copy; <%= Time.now.year %> <span class="font-bold text-white/60">Eksa Framework</span>. Crafted for speed.</p>
120
+ </footer>
121
+
122
+ <script>
123
+ // Inisialisasi ikon Lucide
124
+ lucide.createIcons();
125
+ </script>
126
+ </body>
127
+ </html>
data/config.ru ADDED
@@ -0,0 +1,15 @@
1
+ require './lib/eksa'
2
+ require './app/controllers/pages_controller'
3
+
4
+ use Rack::Static, urls: ["/css", "/img"], root: "public"
5
+ use Rack::ShowExceptions
6
+
7
+ app = Eksa::Application.new
8
+
9
+ app.add_route "/", PagesController, :index
10
+ app.add_route "/hapus", PagesController, :hapus_pesan
11
+ app.add_route "/edit", PagesController, :edit
12
+ app.add_route "/about", PagesController, :about
13
+ app.add_route "/docs", PagesController, :docs
14
+
15
+ run app
data/db/eksa_app.db ADDED
Binary file
data/db/setup.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'sqlite3'
2
+
3
+ db = SQLite3::Database.new "eksa_app.db"
4
+
5
+ db.execute <<-SQL
6
+ CREATE TABLE IF NOT EXISTS pesan (
7
+ id INTEGER PRIMARY KEY,
8
+ konten TEXT,
9
+ pengirim TEXT
10
+ );
11
+ SQL
12
+
13
+ puts "Database Eksa berhasil disiapkan!"
data/exe/eksa-init ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'fileutils'
5
+
6
+ gem_root = File.expand_path("../..", __FILE__)
7
+ target_dir = Dir.pwd
8
+
9
+ puts "\n✨ Eksa Framework Generator ✨"
10
+ puts "-----------------------------"
11
+ puts "🚀 Menginisialisasi project di: #{target_dir}"
12
+
13
+ items_to_init = ['app', 'lib', 'public', 'db', 'config.ru', 'Gemfile', 'README.md']
14
+
15
+ items_to_init.each do |item|
16
+ source = File.join(gem_root, item)
17
+ destination = File.join(target_dir, item)
18
+
19
+ if File.exist?(source)
20
+ if File.directory?(source)
21
+ FileUtils.cp_r(source, target_dir)
22
+ puts " [OK] Folder '#{item}' berhasil disalin."
23
+ else
24
+ FileUtils.cp(source, destination)
25
+ puts " [OK] File '#{item}' berhasil disalin."
26
+ end
27
+ else
28
+ if item == 'db'
29
+ FileUtils.mkdir_p(destination)
30
+ puts " [OK] Folder 'db' baru berhasil dibuat."
31
+ else
32
+ puts " [!] Warning: Sumber '#{item}' tidak ditemukan."
33
+ end
34
+ end
35
+ end
36
+
37
+ puts "\n✅ Inisialisasi Selesai!"
38
+ puts "-----------------------------"
39
+ puts "Instruksi selanjutnya:"
40
+ puts "1. Jalankan: bundle install"
41
+ puts "2. Jalankan server: rackup config.ru"
42
+ puts "3. Buka browser: http://localhost:9292"
43
+ puts "-----------------------------\n"
@@ -0,0 +1,43 @@
1
+ require 'erb'
2
+
3
+ module Eksa
4
+ class Controller
5
+ attr_reader :request
6
+ attr_accessor :status, :redirect_url, :flash
7
+
8
+ def initialize(request)
9
+ @request = request
10
+ @status = 200
11
+ @flash = {}
12
+ end
13
+
14
+ def params
15
+ @request.params
16
+ end
17
+
18
+ def redirect_to(url, notice: nil)
19
+ @status = 302
20
+ @redirect_url = url
21
+ @flash[:notice] = notice if notice
22
+ nil
23
+ end
24
+
25
+ def render(template_name, variables = {})
26
+ variables.each { |k, v| instance_variable_set("@#{k}", v) }
27
+
28
+ content_path = File.expand_path("./app/views/#{template_name}.html.erb")
29
+ layout_path = File.expand_path("./app/views/layout.html.erb")
30
+
31
+ if File.exist?(content_path)
32
+ @content = ERB.new(File.read(content_path)).result(binding)
33
+ if File.exist?(layout_path)
34
+ ERB.new(File.read(layout_path)).result(binding)
35
+ else
36
+ @content
37
+ end
38
+ else
39
+ "Error: View '#{template_name}' tidak ditemukan."
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/eksa/model.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'sqlite3'
2
+ require 'fileutils'
3
+
4
+ module Eksa
5
+ class Model
6
+ def self.db
7
+ db_dir = File.expand_path("../../db", __dir__)
8
+ db_path = File.join(db_dir, "eksa_app.db")
9
+ FileUtils.mkdir_p(db_dir) unless Dir.exist?(db_dir)
10
+ @db ||= SQLite3::Database.new(db_path)
11
+ setup_initial_schema
12
+ @db
13
+ end
14
+
15
+ def self.setup_initial_schema
16
+ @db.execute <<-SQL
17
+ CREATE TABLE IF NOT EXISTS pesan (
18
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
19
+ konten TEXT,
20
+ pengirim TEXT
21
+ );
22
+ SQL
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Eksa
2
+ VERSION = "0.1.0"
3
+ end
data/lib/eksa.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'rack'
2
+ require_relative 'eksa/version'
3
+ require_relative 'eksa/controller'
4
+ require_relative 'eksa/model'
5
+
6
+ module Eksa
7
+ class Application
8
+ def initialize
9
+ @routes = {}
10
+ end
11
+
12
+ def add_route(path, controller_class, action)
13
+ @routes[path] = { controller: controller_class, action: action }
14
+ end
15
+
16
+ def call(env)
17
+ request = Rack::Request.new(env)
18
+ flash_message = request.cookies['eksa_flash']
19
+ route = @routes[request.path_info]
20
+
21
+ if route
22
+ controller_instance = route[:controller].new(request)
23
+ controller_instance.flash[:notice] = flash_message if flash_message
24
+
25
+ response_body = controller_instance.send(route[:action])
26
+
27
+ response = Rack::Response.new
28
+
29
+ if controller_instance.status == 302
30
+ response.redirect(controller_instance.redirect_url, 302)
31
+ else
32
+ response.write(response_body)
33
+ response['content-type'] = 'text/html'
34
+ end
35
+
36
+ response.delete_cookie('eksa_flash') if flash_message
37
+ response.finish
38
+ else
39
+ [404, { 'content-type' => 'text/html' }, ["<h1>404 - Not Found</h1>"]]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,111 @@
1
+ /* public/css/style.css */
2
+
3
+ * {
4
+ margin: 0;
5
+ padding: 0;
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ body {
10
+ background-color: #f8fafc; /* Abu-abu sangat muda yang bersih */
11
+ font-family: 'Inter', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
12
+ color: #1e293b;
13
+ display: flex;
14
+ flex-direction: column;
15
+ min-height: 100vh;
16
+ }
17
+
18
+ .main-content {
19
+ flex: 1;
20
+ display: flex;
21
+ justify-content: center;
22
+ align-items: center;
23
+ padding: 20px;
24
+ }
25
+
26
+
27
+ ul.nav-links {
28
+ list-style: none;
29
+ display: flex;
30
+ gap: 20px;
31
+ }
32
+
33
+ .modern-nav {
34
+ background: #ffffff;
35
+ padding: 1rem 10%;
36
+ display: flex;
37
+ justify-content: space-between;
38
+ align-items: center;
39
+ box-shadow: 0 1px 3px rgba(0,0,0,0.05);
40
+ }
41
+
42
+ .brand {
43
+ font-weight: 800;
44
+ font-size: 1.4rem;
45
+ color: #4f46e5; /* Indigo modern */
46
+ letter-spacing: -1px;
47
+ }
48
+
49
+ .modern-card {
50
+ background: white;
51
+ padding: 3.5rem 2.5rem;
52
+ border-radius: 24px;
53
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.05);
54
+ text-align: center;
55
+ max-width: 500px;
56
+ width: 100%;
57
+ border: 1px solid #f1f5f9;
58
+ position: relative;
59
+ overflow: hidden;
60
+ }
61
+
62
+ .modern-card::before {
63
+ content: "";
64
+ position: absolute;
65
+ top: 0;
66
+ left: 0;
67
+ right: 0;
68
+ height: 6px;
69
+ background: linear-gradient(90deg, #4f46e5, #ec4899); /* Gradien Indigo ke Pink */
70
+ }
71
+
72
+ h1 {
73
+ font-size: 2.2rem;
74
+ font-weight: 800;
75
+ margin-bottom: 1rem;
76
+ color: #0f172a;
77
+ letter-spacing: -0.025em;
78
+ }
79
+
80
+ p {
81
+ color: #64748b;
82
+ line-height: 1.6;
83
+ margin-bottom: 1.5rem;
84
+ }
85
+
86
+ .badge {
87
+ display: inline-block;
88
+ padding: 4px 12px;
89
+ background: #eef2ff;
90
+ color: #4f46e5;
91
+ border-radius: 99px;
92
+ font-size: 0.75rem;
93
+ font-weight: 600;
94
+ margin-bottom: 1rem;
95
+ }
96
+
97
+ code {
98
+ background: #f1f5f9;
99
+ padding: 3px 6px;
100
+ border-radius: 6px;
101
+ color: #e11d48;
102
+ font-family: 'Fira Code', monospace;
103
+ font-size: 0.9em;
104
+ }
105
+
106
+ .modern-footer {
107
+ padding: 2rem;
108
+ text-align: center;
109
+ font-size: 0.85rem;
110
+ color: #94a3b8;
111
+ }
Binary file
Binary file
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eksa-framework
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - IshikawaUta
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: sqlite3
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.4'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.4'
40
+ - !ruby/object:Gem::Dependency
41
+ name: puma
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '6.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '6.0'
54
+ description: Framework MVC ringan dengan tema modern, sistem routing, dan auto-database
55
+ SQLite.
56
+ email:
57
+ - komikers09@gmail.com
58
+ executables:
59
+ - eksa-init
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - Gemfile
64
+ - LICENSE
65
+ - README.md
66
+ - app/controllers/pages_controller.rb
67
+ - app/models/pesan.rb
68
+ - app/views/about.html.erb
69
+ - app/views/docs.html.erb
70
+ - app/views/edit.html.erb
71
+ - app/views/index.html.erb
72
+ - app/views/layout.html.erb
73
+ - config.ru
74
+ - db/eksa_app.db
75
+ - db/setup.rb
76
+ - exe/eksa-init
77
+ - lib/eksa.rb
78
+ - lib/eksa/controller.rb
79
+ - lib/eksa/model.rb
80
+ - lib/eksa/version.rb
81
+ - public/css/style.css
82
+ - public/img/favicon.ico
83
+ - public/img/logo.png
84
+ homepage: https://github.com/IshikawaUta/eksa-framework
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 3.0.0
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.6.7
103
+ specification_version: 4
104
+ summary: Modern Glassmorphism Ruby MVC Framework.
105
+ test_files: []