rails_app_generator 0.1.2 → 0.1.3
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/after_templates/rag_tailwind.rb +2 -4
- data/after_templates/rag_tailwind_daisyui/index.html.erb +181 -0
- data/after_templates/rag_tailwind_daisyui.rb +25 -0
- data/after_templates/rag_tailwind_hotwire_form/_contact.html.erb +8 -0
- data/after_templates/rag_tailwind_hotwire_form/_count.html.erb +1 -0
- data/after_templates/rag_tailwind_hotwire_form/_flash.html.erb +6 -0
- data/after_templates/rag_tailwind_hotwire_form/_form.html.erb +16 -0
- data/after_templates/rag_tailwind_hotwire_form/_list.html.erb +19 -0
- data/after_templates/rag_tailwind_hotwire_form/application.html.erb +24 -0
- data/after_templates/rag_tailwind_hotwire_form/application.js +30 -0
- data/after_templates/rag_tailwind_hotwire_form/application.tailwind.css +111 -0
- data/after_templates/rag_tailwind_hotwire_form/application_helper.rb +15 -0
- data/after_templates/rag_tailwind_hotwire_form/contact.rb +5 -0
- data/after_templates/rag_tailwind_hotwire_form/contacts_controller.rb +98 -0
- data/after_templates/rag_tailwind_hotwire_form/create.turbo_stream.erb +4 -0
- data/after_templates/rag_tailwind_hotwire_form/edit.html.erb +12 -0
- data/after_templates/rag_tailwind_hotwire_form/index.html.erb +5 -0
- data/after_templates/rag_tailwind_hotwire_form/new.html.erb +12 -0
- data/after_templates/rag_tailwind_hotwire_form/show.html.erb +16 -0
- data/after_templates/rag_tailwind_hotwire_form/update.turbo_stream.erb +2 -0
- data/after_templates/rag_tailwind_hotwire_form.rb +54 -0
- data/lib/rails_app_generator/app_generator.rb +21 -0
- data/lib/rails_app_generator/diff/open_in_editor.rb +1 -1
- data/lib/rails_app_generator/diff/processor.rb +7 -1
- data/lib/rails_app_generator/version.rb +1 -1
- data/package-lock.json +1019 -85
- data/package.json +4 -1
- data/profiles/rag-tailwind-daisyui.json +10 -0
- data/profiles/rag-tailwind-hotwire-form.json +13 -0
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1b9515cc01763f710f8f7461e0d8166d5192771ed45267be53c399fa4d0f9c8
|
4
|
+
data.tar.gz: c2c4069a59328153fcab6e5f81c78e39f58a11f759103dda01d0c74571611ea5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3576c0c56cb8efaf50aab437e827a5e8ef973107537b9ae5f8362d91426161d0382b2bc463bae598419af396740eed71ba6720585b4d085f47051b64c3b0d4a0
|
7
|
+
data.tar.gz: 84ee7ac005aa6715de7697ccc8d0a2650f9d49d6dff1bbbc4d0e71ce51337ebe185449612fd3ec4204623f9fed3571427f1f028c3c7e4426d8d1f96b68ccead1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## [0.1.2](https://github.com/klueless-io/rails_app_generator/compare/v0.1.1...v0.1.2) (2022-07-26)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* add profile tailwind_hotwire ([b79bb70](https://github.com/klueless-io/rails_app_generator/commit/b79bb70258c7e312d460961dd98516ddd1e2650c))
|
7
|
+
* add profile tailwind_hotwire ([c9ac471](https://github.com/klueless-io/rails_app_generator/commit/c9ac471e4391fe0ddd4b97977916da25cdc4f33e))
|
8
|
+
|
1
9
|
## [0.1.1](https://github.com/klueless-io/rails_app_generator/compare/v0.1.0...v0.1.1) (2022-07-26)
|
2
10
|
|
3
11
|
|
@@ -16,16 +16,13 @@ add_controller('home', 'index', 'about')
|
|
16
16
|
route("root 'home#index'")
|
17
17
|
|
18
18
|
index_content = join_templates(
|
19
|
-
'component-section-begin.html',
|
20
19
|
'component-nav.html',
|
21
20
|
'component-hero.html',
|
22
21
|
'component-cta.html',
|
23
22
|
'component-faq.html',
|
24
23
|
'component-cta.html',
|
25
|
-
'component-footer.html'
|
26
|
-
'component-section-end.html'
|
24
|
+
'component-footer.html'
|
27
25
|
)
|
28
|
-
# join: "</section>\n\n<section>\n"
|
29
26
|
|
30
27
|
create_file 'app/views/home/index.html.erb', index_content, force: true
|
31
28
|
|
@@ -48,6 +45,7 @@ end
|
|
48
45
|
|
49
46
|
def add_css_customizations
|
50
47
|
# Update the manifest to include the stylesheets
|
48
|
+
# IS THIS CONFIGURED?
|
51
49
|
append_to_file 'app/assets/config/manifest.js' , read_template('manifest.js')
|
52
50
|
|
53
51
|
# This is how you would add custom styling via @import in the application.bootstrap.css
|
@@ -0,0 +1,181 @@
|
|
1
|
+
<div class="lg:flex lg:items-center lg:justify-between">
|
2
|
+
<div class="flex-1 min-w-0">
|
3
|
+
<h2 class="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate">Regular Tailwind CSS</h2>
|
4
|
+
<div class="mt-1 flex flex-col sm:flex-row sm:flex-wrap sm:mt-0 sm:space-x-6">
|
5
|
+
<div class="mt-2 flex items-center text-sm text-gray-500">
|
6
|
+
<!-- Heroicon name: solid/briefcase -->
|
7
|
+
<svg class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
8
|
+
<path fill-rule="evenodd" d="M6 6V5a3 3 0 013-3h2a3 3 0 013 3v1h2a2 2 0 012 2v3.57A22.952 22.952 0 0110 13a22.95 22.95 0 01-8-1.43V8a2 2 0 012-2h2zm2-1a1 1 0 011-1h2a1 1 0 011 1v1H8V5zm1 5a1 1 0 011-1h.01a1 1 0 110 2H10a1 1 0 01-1-1z" clip-rule="evenodd" />
|
9
|
+
<path d="M2 13.692V16a2 2 0 002 2h12a2 2 0 002-2v-2.308A24.974 24.974 0 0110 15c-2.796 0-5.487-.46-8-1.308z" />
|
10
|
+
</svg>
|
11
|
+
Full-time
|
12
|
+
</div>
|
13
|
+
<div class="mt-2 flex items-center text-sm text-gray-500">
|
14
|
+
<!-- Heroicon name: solid/location-marker -->
|
15
|
+
<svg class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
16
|
+
<path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd" />
|
17
|
+
</svg>
|
18
|
+
Remote
|
19
|
+
</div>
|
20
|
+
<div class="mt-2 flex items-center text-sm text-gray-500">
|
21
|
+
<!-- Heroicon name: solid/currency-dollar -->
|
22
|
+
<svg class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
23
|
+
<path d="M8.433 7.418c.155-.103.346-.196.567-.267v1.698a2.305 2.305 0 01-.567-.267C8.07 8.34 8 8.114 8 8c0-.114.07-.34.433-.582zM11 12.849v-1.698c.22.071.412.164.567.267.364.243.433.468.433.582 0 .114-.07.34-.433.582a2.305 2.305 0 01-.567.267z" />
|
24
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-13a1 1 0 10-2 0v.092a4.535 4.535 0 00-1.676.662C6.602 6.234 6 7.009 6 8c0 .99.602 1.765 1.324 2.246.48.32 1.054.545 1.676.662v1.941c-.391-.127-.68-.317-.843-.504a1 1 0 10-1.51 1.31c.562.649 1.413 1.076 2.353 1.253V15a1 1 0 102 0v-.092a4.535 4.535 0 001.676-.662C13.398 13.766 14 12.991 14 12c0-.99-.602-1.765-1.324-2.246A4.535 4.535 0 0011 9.092V7.151c.391.127.68.317.843.504a1 1 0 101.511-1.31c-.563-.649-1.413-1.076-2.354-1.253V5z" clip-rule="evenodd" />
|
25
|
+
</svg>
|
26
|
+
$120k – $140k
|
27
|
+
</div>
|
28
|
+
<div class="mt-2 flex items-center text-sm text-gray-500">
|
29
|
+
<!-- Heroicon name: solid/calendar -->
|
30
|
+
<svg class="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
31
|
+
<path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
|
32
|
+
</svg>
|
33
|
+
Closing on January 9, 2020
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
<div class="mt-5 flex lg:mt-0 lg:ml-4">
|
38
|
+
<span class="hidden sm:block">
|
39
|
+
<button type="button" class="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
40
|
+
<!-- Heroicon name: solid/pencil -->
|
41
|
+
<svg class="-ml-1 mr-2 h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
42
|
+
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
|
43
|
+
</svg>
|
44
|
+
Edit
|
45
|
+
</button>
|
46
|
+
</span>
|
47
|
+
|
48
|
+
<span class="hidden sm:block ml-3">
|
49
|
+
<button type="button" class="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
50
|
+
<!-- Heroicon name: solid/link -->
|
51
|
+
<svg class="-ml-1 mr-2 h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
52
|
+
<path fill-rule="evenodd" d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5zm-5 5a2 2 0 012.828 0 1 1 0 101.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5a2 2 0 11-2.828-2.828l3-3z" clip-rule="evenodd" />
|
53
|
+
</svg>
|
54
|
+
View
|
55
|
+
</button>
|
56
|
+
</span>
|
57
|
+
|
58
|
+
<span class="sm:ml-3">
|
59
|
+
<button type="button" class="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
60
|
+
<!-- Heroicon name: solid/check -->
|
61
|
+
<svg class="-ml-1 mr-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
62
|
+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
63
|
+
</svg>
|
64
|
+
Publish
|
65
|
+
</button>
|
66
|
+
</span>
|
67
|
+
|
68
|
+
<!-- Dropdown -->
|
69
|
+
<div class="ml-3 relative sm:hidden">
|
70
|
+
<button type="button" class="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" id="mobile-menu-button" aria-expanded="false" aria-haspopup="true">
|
71
|
+
More
|
72
|
+
<!-- Heroicon name: solid/chevron-down -->
|
73
|
+
<svg class="-mr-1 ml-2 h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
74
|
+
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
75
|
+
</svg>
|
76
|
+
</button>
|
77
|
+
|
78
|
+
<!--
|
79
|
+
Dropdown menu, show/hide based on menu state.
|
80
|
+
|
81
|
+
Entering: "transition ease-out duration-200"
|
82
|
+
From: "transform opacity-0 scale-95"
|
83
|
+
To: "transform opacity-100 scale-100"
|
84
|
+
Leaving: "transition ease-in duration-75"
|
85
|
+
From: "transform opacity-100 scale-100"
|
86
|
+
To: "transform opacity-0 scale-95"
|
87
|
+
-->
|
88
|
+
<div class="origin-top-right absolute right-0 mt-2 -mr-1 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="mobile-menu-button" tabindex="-1">
|
89
|
+
<!-- Active: "bg-gray-100", Not Active: "" -->
|
90
|
+
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="mobile-menu-item-0">Edit</a>
|
91
|
+
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="mobile-menu-item-1">View</a>
|
92
|
+
</div>
|
93
|
+
</div>
|
94
|
+
</div>
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<br>
|
98
|
+
<hr>
|
99
|
+
<br>
|
100
|
+
|
101
|
+
<div class="navbar bg-base-100">
|
102
|
+
<div class="flex-1">
|
103
|
+
<a class="btn btn-ghost normal-case text-2xl font-bold text-gray-900 sm:text-3xl">DaisyUI Tailwind CSS</a>
|
104
|
+
</div>
|
105
|
+
<div class="flex-none">
|
106
|
+
<ul class="menu menu-horizontal p-0">
|
107
|
+
<li><a>Item 1</a></li>
|
108
|
+
<li tabindex="0">
|
109
|
+
<a>
|
110
|
+
Parent
|
111
|
+
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path d="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"/></svg>
|
112
|
+
</a>
|
113
|
+
<ul class="p-2 bg-base-100">
|
114
|
+
<li><a>Submenu 1</a></li>
|
115
|
+
<li><a>Submenu 2</a></li>
|
116
|
+
</ul>
|
117
|
+
</li>
|
118
|
+
<li><a>Item 3</a></li>
|
119
|
+
</ul>
|
120
|
+
</div>
|
121
|
+
</div>
|
122
|
+
|
123
|
+
<div class="hero bg-base-200">
|
124
|
+
<div class="hero-content flex-col lg:flex-row-reverse">
|
125
|
+
<img src="https://placeimg.com/260/400/arch" class="max-w-sm rounded-lg shadow-2xl" />
|
126
|
+
<div>
|
127
|
+
<h1 class="text-5xl font-bold">Box Office News!</h1>
|
128
|
+
<p class="py-6">Provident cupiditate voluptatem et in. Quaerat fugiat ut assumenda excepturi exercitationem quasi. In deleniti eaque aut repudiandae et a id nisi.</p>
|
129
|
+
<button class="btn btn-primary">Get Started</button>
|
130
|
+
</div>
|
131
|
+
</div>
|
132
|
+
</div>
|
133
|
+
|
134
|
+
<div class="grid grid-cols-4 gap-4 m-8">
|
135
|
+
<div class="card w-96 bg-base-100 shadow-xl">
|
136
|
+
<div class="card-body">
|
137
|
+
<h2 class="card-title">Shoes!</h2>
|
138
|
+
<p>If a dog chews shoes whose shoes does he choose?</p>
|
139
|
+
</div>
|
140
|
+
<figure><img src="https://placeimg.com/400/225/arch" alt="Shoes" /></figure>
|
141
|
+
</div>
|
142
|
+
<div class="card w-96 bg-base-100 shadow-xl">
|
143
|
+
<div class="card-body">
|
144
|
+
<h2 class="card-title">Shoes!</h2>
|
145
|
+
<p>If a dog chews shoes whose shoes does he choose?</p>
|
146
|
+
</div>
|
147
|
+
<figure><img src="https://placeimg.com/400/225/arch" alt="Shoes" /></figure>
|
148
|
+
</div>
|
149
|
+
<div class="card w-96 bg-base-100 shadow-xl">
|
150
|
+
<div class="card-body">
|
151
|
+
<h2 class="card-title">Shoes!</h2>
|
152
|
+
<p>If a dog chews shoes whose shoes does he choose?</p>
|
153
|
+
</div>
|
154
|
+
<figure><img src="https://placeimg.com/400/225/arch" alt="Shoes" /></figure>
|
155
|
+
</div>
|
156
|
+
<div class="card w-96 bg-base-100 shadow-xl">
|
157
|
+
<div class="card-body">
|
158
|
+
<h2 class="card-title">Shoes!</h2>
|
159
|
+
<p>If a dog chews shoes whose shoes does he choose?</p>
|
160
|
+
</div>
|
161
|
+
<figure><img src="https://placeimg.com/400/225/arch" alt="Shoes" /></figure>
|
162
|
+
</div>
|
163
|
+
</div>
|
164
|
+
|
165
|
+
<footer class="footer footer-center p-10 bg-primary text-primary-content">
|
166
|
+
<div>
|
167
|
+
<svg width="50" height="50" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" class="inline-block fill-current"><path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path></svg>
|
168
|
+
<p class="font-bold">
|
169
|
+
ACME Industries Ltd. <br>Providing reliable tech since 1992
|
170
|
+
</p>
|
171
|
+
<p>Copyright © 2022 - All right reserved</p>
|
172
|
+
</div>
|
173
|
+
<div>
|
174
|
+
<div class="grid grid-flow-col gap-4">
|
175
|
+
<a><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg></a>
|
176
|
+
<a><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current"><path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path></svg></a>
|
177
|
+
<a><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path></svg></a>
|
178
|
+
</div>
|
179
|
+
</div>
|
180
|
+
</footer>
|
181
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Daisy
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
# Do NOT use the --css=tailwind option when using DaisyUI or any other custom plugin syste for tailwindcss
|
7
|
+
|
8
|
+
self.local_template_path = File.join(File.dirname(__FILE__), 'rag_tailwind_daisyui')
|
9
|
+
|
10
|
+
gac 'base rails 7 image created'
|
11
|
+
|
12
|
+
add_controller('home', 'index')
|
13
|
+
route("root 'home#index'")
|
14
|
+
|
15
|
+
template 'index.html.erb', 'app/views/home/index.html.erb' , force: true
|
16
|
+
|
17
|
+
after_bundle do
|
18
|
+
gem "cssbundling-rails"
|
19
|
+
|
20
|
+
rails_command('css:install:tailwind')
|
21
|
+
run('npm install daisyui')
|
22
|
+
|
23
|
+
gsub_file 'tailwind.config.js', %(]\n}), "],\n plugins: [require(\"daisyui\")],\n}"
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<tr id="<%= dom_id(contact) %>" data-stream-enter-class="animate-item-in" data-stream-exit-class="animate-item-out">
|
2
|
+
<td><%= contact.id %></td>
|
3
|
+
<td><%= link_to contact.name, contact_path(contact), data: { turbo_frame: "_top" } %></td>
|
4
|
+
<td><%= contact.age %></td>
|
5
|
+
<td><%= contact.email %></td>
|
6
|
+
<td><%= link_to "Edit", edit_contact_path(contact), class: "btn btn-link btn-sm", data: { turbo_frame: "_top" } %></td>
|
7
|
+
<td><%= button_to "Delete", contact_path(contact), method: :delete, class: "btn btn-link btn-sm" %></td>
|
8
|
+
</tr>
|
@@ -0,0 +1 @@
|
|
1
|
+
<span data-stream-enter-class="animate-item-in" data-stream-exit-class="animate-item-out">Showing <%= contacts.length %> <%= "contact".pluralize(contacts.length) %></span>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%= form_for contact do |f| %>
|
2
|
+
<% if contact.errors.any? %>
|
3
|
+
<div class="form-errors">
|
4
|
+
<div class="alert shadow-lg alert-error text-white">
|
5
|
+
Your form's got some errors
|
6
|
+
</div>
|
7
|
+
</div>
|
8
|
+
<% end %>
|
9
|
+
<%= f.text_field :name, placeholder: "Your first name", class: "input input-bordered w-full max-w-xs my-5" %>
|
10
|
+
<%= inline_error_for(:name, contact) %>
|
11
|
+
<%= f.text_field :age, placeholder: "Your age", class: "input input-bordered w-full max-w-xs my-4" %>
|
12
|
+
<%= inline_error_for(:age, contact) %>
|
13
|
+
<%= f.text_field :email, placeholder: "Your email address", class: "input input-bordered w-full max-w-xs my-4" %>
|
14
|
+
<%= inline_error_for(:email, contact) %>
|
15
|
+
<%= f.submit "Save", class: "form-control btn btn-primary my-4" %>
|
16
|
+
<% end %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<table class="table table-zebra mt-0 w-full">
|
2
|
+
<thead>
|
3
|
+
<tr class="w-full">
|
4
|
+
<th class="text-left">ID</th>
|
5
|
+
<th class="text-left">Name</th>
|
6
|
+
<th class="text-left">Age</th>
|
7
|
+
<th class="text-left">Email</th>
|
8
|
+
<th class="text-center" colspan="2">Actions</th>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody id="contacts-list" data-controller="contacts" data-action="">
|
12
|
+
<% contacts.each do |contact| %>
|
13
|
+
<%= render partial: "contact", locals: { contact: contact } %>
|
14
|
+
<% end %>
|
15
|
+
</tbody>
|
16
|
+
</table>
|
17
|
+
<div class="text-gray-400 mt-4 text-xs text-right" id="contacts-count">
|
18
|
+
<%= render partial: "count", locals: { contacts: contacts } %>
|
19
|
+
</div>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html data-theme="emerald">
|
3
|
+
<head>
|
4
|
+
<title>TailwindHotwireForm</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<%= csrf_meta_tags %>
|
7
|
+
<%= csp_meta_tag %>
|
8
|
+
<%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
|
9
|
+
|
10
|
+
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
11
|
+
<%= javascript_importmap_tags %>
|
12
|
+
</head>
|
13
|
+
|
14
|
+
<body>
|
15
|
+
<main class="container mx-auto">
|
16
|
+
<div class="py-8">
|
17
|
+
<div id="flash" class="flash">
|
18
|
+
<%= render partial: "shared/flash" %>
|
19
|
+
</div>
|
20
|
+
<%= yield %>
|
21
|
+
</div>
|
22
|
+
</main>
|
23
|
+
</body>
|
24
|
+
</html>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
|
2
|
+
import "@hotwired/turbo-rails"
|
3
|
+
import "controllers"
|
4
|
+
|
5
|
+
document.addEventListener("turbo:before-stream-render", function(event) {
|
6
|
+
// Add a class to an element we are about to add to the page
|
7
|
+
// as defined by its "data-stream-enter-class"
|
8
|
+
if (event.target.firstElementChild instanceof HTMLTemplateElement) {
|
9
|
+
var enterAnimationClass = event.target.templateContent.firstElementChild.dataset.streamEnterClass
|
10
|
+
if (enterAnimationClass) {
|
11
|
+
event.target.templateElement.content.firstElementChild.classList.add(enterAnimationClass)
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
// Add a class to an element we are about to remove from the page
|
16
|
+
// as defined by its "data-stream-exit-class"
|
17
|
+
var elementToRemove = document.getElementById(event.target.target)
|
18
|
+
if (elementToRemove) {
|
19
|
+
var streamExitClass = elementToRemove.dataset.streamExitClass
|
20
|
+
if (streamExitClass) {
|
21
|
+
// Intercept the removal of the element
|
22
|
+
event.preventDefault()
|
23
|
+
elementToRemove.classList.add(streamExitClass)
|
24
|
+
// Wait for its animation to end before removing the element
|
25
|
+
elementToRemove.addEventListener("animationend", function() {
|
26
|
+
event.target.performAction()
|
27
|
+
})
|
28
|
+
}
|
29
|
+
}
|
30
|
+
})
|
@@ -0,0 +1,111 @@
|
|
1
|
+
@tailwind base;
|
2
|
+
@tailwind components;
|
3
|
+
@tailwind utilities;
|
4
|
+
|
5
|
+
/*
|
6
|
+
|
7
|
+
@layer components {
|
8
|
+
.btn-primary {
|
9
|
+
@apply py-2 px-4 bg-blue-200;
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
*/
|
14
|
+
|
15
|
+
html {
|
16
|
+
font-size: 20px
|
17
|
+
}
|
18
|
+
|
19
|
+
.form-errors {
|
20
|
+
color: red;
|
21
|
+
}
|
22
|
+
|
23
|
+
.field_with_errors .input-bordered {
|
24
|
+
border: 1px solid red;
|
25
|
+
margin-bottom: 0;
|
26
|
+
}
|
27
|
+
|
28
|
+
/* Animation */
|
29
|
+
/* */
|
30
|
+
/* Got it from here: */
|
31
|
+
/* https://edforshaw.co.uk/hotwire-turbo-stream-animations */
|
32
|
+
/* and here: */
|
33
|
+
/* https://stackoverflow.com/a/61306871/4072276 */
|
34
|
+
|
35
|
+
.animate-in {
|
36
|
+
animation: slide-in 0.25s ease-out;
|
37
|
+
}
|
38
|
+
|
39
|
+
.animate-out {
|
40
|
+
animation: slide-out 0.25s ease-out;
|
41
|
+
}
|
42
|
+
|
43
|
+
@keyframes slide-in {
|
44
|
+
from { transform: translateX(4rem); }
|
45
|
+
to { transform: translateX(0); }
|
46
|
+
}
|
47
|
+
|
48
|
+
@keyframes slide-out {
|
49
|
+
from { transform: translateX(0); }
|
50
|
+
to { transform: translateX(4rem); }
|
51
|
+
}
|
52
|
+
|
53
|
+
.animate-item-in {
|
54
|
+
transition-duration: 0.25s;
|
55
|
+
animation: addRow 0.25s ease-in;
|
56
|
+
transform-origin: top;
|
57
|
+
}
|
58
|
+
|
59
|
+
.animate-item-out {
|
60
|
+
transition-duration: 0.25s;
|
61
|
+
animation: removeRow 0.25s ease-in;
|
62
|
+
transform-origin: bottom;
|
63
|
+
}
|
64
|
+
|
65
|
+
@keyframes addRow {
|
66
|
+
0% {
|
67
|
+
transform: scale(1, 0);
|
68
|
+
line-height: 0px;
|
69
|
+
background-color: #fff;
|
70
|
+
visibility: collapse;
|
71
|
+
}
|
72
|
+
50% {
|
73
|
+
transform: scale(1, 1);
|
74
|
+
line-height: 20px;
|
75
|
+
visibility: visible;
|
76
|
+
}
|
77
|
+
100% {
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
@keyframes removeRow {
|
82
|
+
100% {
|
83
|
+
transform: scale(1, 1);
|
84
|
+
line-height: 20px;
|
85
|
+
visibility: visible;
|
86
|
+
}
|
87
|
+
50% {
|
88
|
+
transform: scale(1, 0);
|
89
|
+
line-height: 0px;
|
90
|
+
background-color: #fff;
|
91
|
+
visibility: collapse;
|
92
|
+
}
|
93
|
+
0% {
|
94
|
+
}
|
95
|
+
}
|
96
|
+
.flash {
|
97
|
+
height: 70px;
|
98
|
+
margin-bottom: 2rem;
|
99
|
+
}
|
100
|
+
|
101
|
+
.alert-success {
|
102
|
+
--tw-bg-opacity: 1;
|
103
|
+
background-color: hsl(var(--su)/var(--tw-bg-opacity));
|
104
|
+
--tw-text-opacity: 1;
|
105
|
+
color: hsl(var(--suc,var(--nc))/var(--tw-text-opacity));
|
106
|
+
}
|
107
|
+
|
108
|
+
.text-white {
|
109
|
+
--tw-text-opacity: 1;
|
110
|
+
color: rgb(255 255 255/var(--tw-text-opacity));
|
111
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ApplicationHelper
|
2
|
+
|
3
|
+
def inline_error_for(field, form_obj)
|
4
|
+
html = []
|
5
|
+
|
6
|
+
if form_obj.errors[field].any?
|
7
|
+
html << form_obj.errors[field].map do |msg|
|
8
|
+
tag.div(msg, class: "text-red-400 text-xs m-0 p-0 text-right mb-2")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
html.join.html_safe
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
class Contact < ApplicationRecord
|
2
|
+
validates :name, presence: true
|
3
|
+
validates :age, presence: true, numericality: true, inclusion: { in: 20...100, message: "must be between 20 and 100" }
|
4
|
+
validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }
|
5
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
class ContactsController < ApplicationController
|
2
|
+
include ActionView::RecordIdentifier
|
3
|
+
|
4
|
+
before_action :set_contact, only: %i[show edit update destroy]
|
5
|
+
before_action :all_contacts #, except: [:new, :create, :index]
|
6
|
+
|
7
|
+
# GET /contacts or /contacts.json
|
8
|
+
def index
|
9
|
+
end
|
10
|
+
|
11
|
+
# GET /contacts/1 or /contacts/1.json
|
12
|
+
def show
|
13
|
+
end
|
14
|
+
|
15
|
+
# GET /contacts/new
|
16
|
+
def new
|
17
|
+
@contact = Contact.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# GET /contacts/1/edit
|
21
|
+
def edit
|
22
|
+
end
|
23
|
+
|
24
|
+
# POST /contacts or /contacts.json
|
25
|
+
def create
|
26
|
+
@contact = Contact.new(contact_params)
|
27
|
+
|
28
|
+
if @contact.save
|
29
|
+
flash[:notice] = 'Contact was successfully created.'
|
30
|
+
else
|
31
|
+
render :new, status: :unprocessable_entity
|
32
|
+
end
|
33
|
+
# respond_to do |format|
|
34
|
+
# if @contact.save
|
35
|
+
# format.html { redirect_to contact_url(@contact), notice: "Contact was successfully created." }
|
36
|
+
# format.json { render :show, status: :created, location: @contact }
|
37
|
+
# else
|
38
|
+
# format.html { render :new, status: :unprocessable_entity }
|
39
|
+
# format.json { render json: @contact.errors, status: :unprocessable_entity }
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
|
44
|
+
# PATCH/PUT /contacts/1 or /contacts/1.json
|
45
|
+
def update
|
46
|
+
if @contact.update(contact_params)
|
47
|
+
flash[:notice] = "Contact updated"
|
48
|
+
else
|
49
|
+
render :edit, status: :unprocessable_entity
|
50
|
+
end
|
51
|
+
# respond_to do |format|
|
52
|
+
# if @contact.update(contact_params)
|
53
|
+
# format.html { redirect_to contact_url(@contact), notice: "Contact was successfully updated." }
|
54
|
+
# format.json { render :show, status: :ok, location: @contact }
|
55
|
+
# else
|
56
|
+
# format.html { render :edit, status: :unprocessable_entity }
|
57
|
+
# format.json { render json: @contact.errors, status: :unprocessable_entity }
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
end
|
61
|
+
|
62
|
+
# DELETE /contacts/1 or /contacts/1.json
|
63
|
+
# def destroy
|
64
|
+
# @contact.destroy
|
65
|
+
|
66
|
+
# respond_to do |format|
|
67
|
+
# format.html { redirect_to contacts_url, notice: "Contact was successfully destroyed." }
|
68
|
+
# format.json { head :no_content }
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
def destroy
|
72
|
+
@contact.destroy
|
73
|
+
flash[:notice] = "Contact removed"
|
74
|
+
render turbo_stream: [
|
75
|
+
turbo_stream.update("flash", partial: "shared/flash"),
|
76
|
+
turbo_stream.remove(dom_id(@contact)),
|
77
|
+
turbo_stream.update("contacts-count", partial: "contacts/count", locals: { contacts: @contacts })
|
78
|
+
]
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
# Use callbacks to share common setup or constraints between actions.
|
83
|
+
def set_contact
|
84
|
+
@contact = Contact.find(params.require(:id))
|
85
|
+
end
|
86
|
+
|
87
|
+
def contact_params
|
88
|
+
params.require(:contact).permit(:name, :age, :email)
|
89
|
+
end
|
90
|
+
# def contact_params
|
91
|
+
# params.require(:contact).permit!
|
92
|
+
# end
|
93
|
+
|
94
|
+
def all_contacts
|
95
|
+
@contacts = Contact.all
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<%= turbo_stream.update("flash", partial: "shared/flash") %>
|
2
|
+
<%= turbo_stream.append("contacts-list", partial: "contacts/contact", locals: { contact: @contact }) %>
|
3
|
+
<%= turbo_stream.update("contacts-count", partial: "contacts/count", locals: { contacts: @contacts }) %>
|
4
|
+
<%= turbo_stream.update("contact-form", partial: "contacts/form", locals: { contact: Contact.new }) %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="prose lg:prose-xl">
|
2
|
+
<h1>Edit contact</h1>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div class="grid grid-cols-2 gap-4 mt-8">
|
6
|
+
<div class="bg-gray-100 p-8">
|
7
|
+
<%= render partial: "list", locals: { contacts: @contacts } %>
|
8
|
+
</div>
|
9
|
+
<div class="form-control w-full max-w-xs">
|
10
|
+
<%= render partial: "form", locals: { contact: @contact } %>
|
11
|
+
</div>
|
12
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="prose lg:prose-xl">
|
2
|
+
<h1>New contact</h1>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div class="grid grid-cols-2 gap-4 mt-8">
|
6
|
+
<div class="bg-gray-100 p-8">
|
7
|
+
<%= render partial: "list", locals: { contacts: @contacts } %>
|
8
|
+
</div>
|
9
|
+
<div class="form-control w-full max-w-xs" id="contact-form">
|
10
|
+
<%= render partial: "form", locals: { contact: @contact } %>
|
11
|
+
</div>
|
12
|
+
</div>
|