basecoat 2.0.0 → 2.2.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 +4 -4
- data/README.md +36 -57
- data/basecoat-new.png +0 -0
- data/lib/basecoat/version.rb +1 -1
- data/lib/generators/basecoat/templates/layouts/_theme_toggle.html.erb +1 -1
- data/lib/generators/basecoat/templates/sessions/new.html.erb +1 -1
- data/lib/tasks/basecoat.rake +159 -51
- data/lib/templates/erb/scaffold/_form.html.erb.tt +7 -4
- metadata +2 -3
- data/basecoat-dark-form.png +0 -0
- data/basecoat-index.png +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 92a3b3db00be4f62dcf379eac035135cb5161b3bc68e9f1d0c7121e87c88b387
|
|
4
|
+
data.tar.gz: 45d0cb31d2da696369191e60945ba66b25b590e1c321b03df641b4583ba7fcd8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ef24e7f5c6dd6588cb64fc0a79efd8830e86a80bce99b6f621dbde384c218cc69e2ac25c6119d8986327789313c25a0269adbe065ca4cbf7c224099cb2640767
|
|
7
|
+
data.tar.gz: 86047f8393f17eb1aa5407bc5f19ea578c3522b053dd06c7d156c57ade2e8c3c989233a62da9ab5038ee5a7e6b498dd7a06b97856c81744a799d2a993941c044
|
data/README.md
CHANGED
|
@@ -3,86 +3,75 @@
|
|
|
3
3
|
This gem provides you with amazing layouts, scaffolds, views and partials based on [Basecoat UI](https://basecoatui.com).
|
|
4
4
|
It is especially powerful for admin applications with a lot of CRUD actions.
|
|
5
5
|
|
|
6
|
-
Beautiful responsive, dark & light mode Rails scaffolds, pages for authentication and Devise, and pagy styling.
|
|
7
|
-
|
|
8
|
-
Login:
|
|
9
6
|

|
|
10
|
-
Index:
|
|
11
|
-

|
|
12
|
-
Form, mobile dark mode:
|
|
13
|
-

|
|
14
|
-
|
|
15
|
-
## Why?
|
|
16
|
-
|
|
17
|
-
Shadcn has quickly become the default ui for the web. However, sometimes we don't _really_ need all the React components.
|
|
18
|
-
Especially with backend applications - where Rails shines as full stack solution.
|
|
19
7
|
|
|
20
|
-
|
|
8
|
+

|
|
21
9
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## Installation
|
|
10
|
+
## Usage
|
|
25
11
|
|
|
26
|
-
|
|
12
|
+
Try it from scratch:
|
|
27
13
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
rails new myproject -c tailwind
|
|
15
|
+
cd myproject
|
|
16
|
+
bundle add basecoat
|
|
17
|
+
rails basecoat:install
|
|
18
|
+
rails g scaffold Post title:string! description:text posted_at:datetime active:boolean rating:integer
|
|
19
|
+
rails db:migrate
|
|
20
|
+
./bin/dev
|
|
21
|
+
# open http://localhost:3000/posts
|
|
31
22
|
|
|
32
|
-
|
|
23
|
+
**Note:** Basecoat requires Tailwind CSS. If you haven't installed it yet, follow the instructions at [https://github.com/rails/tailwindcss-rails](https://github.com/rails/tailwindcss-rails) to set up Tailwind CSS in your Rails application.
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
bundle install
|
|
36
|
-
```
|
|
25
|
+
## Why?
|
|
37
26
|
|
|
38
|
-
|
|
27
|
+
The default scaffolds are ugly. There's no styling, no turbo frames - it's missing the WOW factor.
|
|
39
28
|
|
|
40
|
-
|
|
29
|
+
Basecoat CSS combines tailwind with clean css classes. It creates the looks of shadcn, which has a massive community.
|
|
41
30
|
|
|
42
|
-
|
|
31
|
+
If you need more complex components; enrich the views with https://railsblocks.com/ or https://shadcn.rails-components.com/ or just the shadcn React components themselves.
|
|
43
32
|
|
|
44
|
-
|
|
33
|
+
## Rake tasks
|
|
45
34
|
|
|
46
|
-
|
|
35
|
+
### Layout (required)
|
|
47
36
|
|
|
48
37
|
```bash
|
|
49
38
|
rake basecoat:install
|
|
50
39
|
```
|
|
51
|
-
NB:
|
|
40
|
+
NB: Only run this once.
|
|
52
41
|
|
|
53
42
|
The generated views will include:
|
|
54
43
|
* Basecoat CSS styling
|
|
55
44
|
* Turbo Frame support for SPA-like navigation
|
|
56
|
-
*
|
|
45
|
+
* A tiny bit of javascript for awesome view transitions
|
|
57
46
|
* Responsive design
|
|
58
47
|
* Dark mode support
|
|
59
48
|
* Form validation with required fields
|
|
60
49
|
* Boolean fields styled as switches
|
|
61
50
|
* Automatic sidebar navigation links
|
|
62
51
|
|
|
63
|
-
The scaffold templates are automatically available from the gem, so you can immediately generate scaffolds
|
|
52
|
+
The scaffold templates are automatically available from the gem, so you can immediately generate scaffolds.
|
|
64
53
|
|
|
65
|
-
|
|
66
|
-
rails generate scaffold Post title:string body:text published:boolean
|
|
67
|
-
```
|
|
54
|
+
### Default Rails Authentication
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
Install the Basecoat-styled authentication views (for Rails built-in authentication):
|
|
57
|
+
|
|
58
|
+
rails generate:authentication
|
|
59
|
+
rails db:migrate
|
|
60
|
+
rake basecoat:install:authentication
|
|
70
61
|
|
|
71
|
-
|
|
62
|
+
NB: To create a user, go to your console:
|
|
63
|
+
|
|
64
|
+
rails console
|
|
65
|
+
User.create(email_address: "email@example.com", password: "basecoat")
|
|
66
|
+
exit
|
|
72
67
|
|
|
73
|
-
|
|
74
|
-
rake basecoat:install:devise
|
|
75
|
-
```
|
|
76
|
-
NB: This will overwrite exising files!
|
|
68
|
+
### Install the Basecoat-styled Devise views and layout:
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Install the Basecoat-styled authentication views (for Rails built-in authentication):
|
|
70
|
+
First install devise, follow the instructions at https://github.com/heartcombo/devise. Then:
|
|
81
71
|
|
|
82
72
|
```bash
|
|
83
|
-
rake basecoat:install:
|
|
73
|
+
rake basecoat:install:devise
|
|
84
74
|
```
|
|
85
|
-
NB: This will overwrite exising files!
|
|
86
75
|
|
|
87
76
|
### Install Pagy Pagination Styles
|
|
88
77
|
|
|
@@ -99,19 +88,9 @@ rake basecoat:install:pagy
|
|
|
99
88
|
- Basecoat CSS
|
|
100
89
|
- Stimulus (for the theme toggle, can be moved to something else if you desire...)
|
|
101
90
|
|
|
102
|
-
## Discussion
|
|
103
|
-
|
|
104
|
-
The scaffolds are more opinionated than the default - it includes a main turbo frame.
|
|
105
|
-
I also strongly feel that the index should not reuse the partial used in show - it defeats the purpose of the show page.
|
|
106
|
-
A responsive table was the best I could come up with - closer to the OG scaffolds before Hotwire.
|
|
107
|
-
|
|
108
|
-
Also, the (arguably) most messy part of the views are the svg tags which contain the lovely lucide icons.
|
|
109
|
-
Since these icons are the default for shadcn I'm considering including https://github.com/heyvito/lucide-rails to clean up the views.
|
|
110
|
-
|
|
111
91
|
## Issues
|
|
112
92
|
|
|
113
|
-
*
|
|
114
|
-
* We include extra css for the definition list. Hopefully this will be part of basecoat-css someday.
|
|
93
|
+
* We include extra css for the definition list. Ideally I would pick an existing component.
|
|
115
94
|
* Rails adds class="field_with_errors", so we need extra css for this. I hope Rails will at some point have aria-invalid="true" on the input, basecoat will apply the correct styling.
|
|
116
95
|
* Can the views even be prettier? Probably! I'm more than happy to discuss improvements:
|
|
117
96
|
|
data/basecoat-new.png
ADDED
|
Binary file
|
data/lib/basecoat/version.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<button type="button" aria-label="Toggle dark mode" data-tooltip="Toggle dark mode" data-side="left" data-action="click->theme#toggle" class="btn-
|
|
1
|
+
<button type="button" aria-label="Toggle dark mode" data-tooltip="Toggle dark mode" data-side="left" data-action="click->theme#toggle" class="btn-ghost size-8">
|
|
2
2
|
<span class="hidden dark:block"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"></circle><path d="M12 2v2"></path><path d="M12 20v2"></path><path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path><path d="M2 12h2"></path><path d="M20 12h2"></path><path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path></svg></span>
|
|
3
3
|
<span class="block dark:hidden"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg></span>
|
|
4
4
|
</button>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<p>Sign in to your account to continue.</p>
|
|
7
7
|
</header>
|
|
8
8
|
<section class="space-y-4">
|
|
9
|
-
<%= form_with url: session_url, html: { class: "grid gap-6" } do |form| %>
|
|
9
|
+
<%= form_with url: session_url, html: { data: { turbo: false }, class: "grid gap-6" } do |form| %>
|
|
10
10
|
<div class="grid gap-3">
|
|
11
11
|
<%= form.label :email_address, "Email", class: "label" %>
|
|
12
12
|
<%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", value: params[:email_address], class: "input" %>
|
data/lib/tasks/basecoat.rake
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
require 'fileutils'
|
|
2
2
|
|
|
3
3
|
namespace :basecoat do
|
|
4
|
+
# Helper method to prompt for overwrite confirmation
|
|
5
|
+
def prompt_overwrite(file_path, overwrite_all)
|
|
6
|
+
return true if overwrite_all[:value]
|
|
7
|
+
return true unless File.exist?(file_path)
|
|
8
|
+
|
|
9
|
+
print " Overwrite #{file_path.relative_path_from(Rails.root)}? [y/n/a] "
|
|
10
|
+
response = STDIN.gets.chomp.downcase
|
|
11
|
+
|
|
12
|
+
if response == 'a'
|
|
13
|
+
overwrite_all[:value] = true
|
|
14
|
+
true
|
|
15
|
+
elsif response == 'y'
|
|
16
|
+
true
|
|
17
|
+
else
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
4
22
|
desc "Install Basecoat application layout and partials"
|
|
5
23
|
task :install do
|
|
24
|
+
overwrite_all = { value: false }
|
|
6
25
|
# Install basecoat-css (detect package manager)
|
|
7
26
|
puts "\n📦 Installing basecoat-css..."
|
|
8
27
|
|
|
@@ -82,8 +101,12 @@ namespace :basecoat do
|
|
|
82
101
|
theme_controller_destination = Rails.root.join("app/javascript/controllers/theme_controller.js")
|
|
83
102
|
|
|
84
103
|
FileUtils.mkdir_p(File.dirname(theme_controller_destination))
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
if prompt_overwrite(theme_controller_destination, overwrite_all)
|
|
105
|
+
FileUtils.cp(theme_controller_source, theme_controller_destination)
|
|
106
|
+
puts " Created: app/javascript/controllers/theme_controller.js"
|
|
107
|
+
else
|
|
108
|
+
puts " Skipped: app/javascript/controllers/theme_controller.js"
|
|
109
|
+
end
|
|
87
110
|
end
|
|
88
111
|
|
|
89
112
|
# Add CSS imports and styles
|
|
@@ -112,23 +135,25 @@ namespace :basecoat do
|
|
|
112
135
|
css_content = File.read(css_path)
|
|
113
136
|
|
|
114
137
|
css_code = <<~CSS
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
dl {
|
|
139
|
+
font-size: var(--text-sm);
|
|
140
|
+
dt {
|
|
141
|
+
font-weight: var(--font-weight-bold);
|
|
142
|
+
margin-top: calc(var(--spacing)*4);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
label:has(+ input:required):after {
|
|
147
|
+
content: " *"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
input:user-invalid, .field_with_errors input {
|
|
151
|
+
border-color: var(--color-destructive);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
label:has(+ input:user-invalid), .field_with_errors label {
|
|
155
|
+
color: var(--color-destructive);
|
|
156
|
+
}
|
|
132
157
|
CSS
|
|
133
158
|
File.open(css_path, "a") { |f| f.write(css_code) }
|
|
134
159
|
puts " Added: basic styles to #{css_path.relative_path_from(Rails.root)}"
|
|
@@ -147,30 +172,53 @@ namespace :basecoat do
|
|
|
147
172
|
if content =~ /(<head>.*?<\/head>)/m
|
|
148
173
|
head_content = $1
|
|
149
174
|
head_destination = partials_destination.join("_head.html.erb")
|
|
150
|
-
|
|
151
|
-
|
|
175
|
+
if prompt_overwrite(head_destination, overwrite_all)
|
|
176
|
+
File.write(head_destination, head_content + "\n")
|
|
177
|
+
puts " Created: app/views/layouts/_head.html.erb (extracted from existing application.html.erb)"
|
|
178
|
+
else
|
|
179
|
+
puts " Skipped: app/views/layouts/_head.html.erb"
|
|
180
|
+
end
|
|
152
181
|
else
|
|
153
182
|
# Fallback: copy the template if no <head> found in existing layout
|
|
154
|
-
|
|
155
|
-
|
|
183
|
+
head_destination = partials_destination.join("_head.html.erb")
|
|
184
|
+
if prompt_overwrite(head_destination, overwrite_all)
|
|
185
|
+
FileUtils.cp("#{partials_source}/_head.html.erb", head_destination)
|
|
186
|
+
puts " Created: app/views/layouts/_head.html.erb (from template)"
|
|
187
|
+
else
|
|
188
|
+
puts " Skipped: app/views/layouts/_head.html.erb"
|
|
189
|
+
end
|
|
156
190
|
end
|
|
157
191
|
else
|
|
158
192
|
# No existing layout, use template
|
|
159
|
-
|
|
160
|
-
|
|
193
|
+
head_destination = partials_destination.join("_head.html.erb")
|
|
194
|
+
if prompt_overwrite(head_destination, overwrite_all)
|
|
195
|
+
FileUtils.cp("#{partials_source}/_head.html.erb", head_destination)
|
|
196
|
+
puts " Created: app/views/layouts/_head.html.erb (from template)"
|
|
197
|
+
else
|
|
198
|
+
puts " Skipped: app/views/layouts/_head.html.erb"
|
|
199
|
+
end
|
|
161
200
|
end
|
|
162
201
|
|
|
163
202
|
# Copy application layout
|
|
164
203
|
layout_source = File.expand_path("../generators/basecoat/templates/application.html.erb", __dir__)
|
|
165
|
-
|
|
166
|
-
|
|
204
|
+
if prompt_overwrite(layout_destination, overwrite_all)
|
|
205
|
+
FileUtils.cp(layout_source, layout_destination)
|
|
206
|
+
puts " Created: app/views/layouts/application.html.erb"
|
|
207
|
+
else
|
|
208
|
+
puts " Skipped: app/views/layouts/application.html.erb"
|
|
209
|
+
end
|
|
167
210
|
|
|
168
211
|
# Copy layout partials (except _head.html.erb which we already handled)
|
|
169
212
|
Dir.glob("#{partials_source}/*").each do |file|
|
|
170
213
|
filename = File.basename(file)
|
|
171
214
|
next if filename == "_head.html.erb" # Skip _head.html.erb, we already created it
|
|
172
|
-
|
|
173
|
-
|
|
215
|
+
destination = partials_destination.join(filename)
|
|
216
|
+
if prompt_overwrite(destination, overwrite_all)
|
|
217
|
+
FileUtils.cp(file, destination)
|
|
218
|
+
puts " Created: app/views/layouts/#{filename}"
|
|
219
|
+
else
|
|
220
|
+
puts " Skipped: app/views/layouts/#{filename}"
|
|
221
|
+
end
|
|
174
222
|
end
|
|
175
223
|
|
|
176
224
|
# Copy shared partials
|
|
@@ -180,8 +228,13 @@ namespace :basecoat do
|
|
|
180
228
|
FileUtils.mkdir_p(shared_destination)
|
|
181
229
|
Dir.glob("#{shared_source}/*").each do |file|
|
|
182
230
|
filename = File.basename(file)
|
|
183
|
-
|
|
184
|
-
|
|
231
|
+
destination = shared_destination.join(filename)
|
|
232
|
+
if prompt_overwrite(destination, overwrite_all)
|
|
233
|
+
FileUtils.cp(file, destination)
|
|
234
|
+
puts " Created: app/views/shared/#{filename}"
|
|
235
|
+
else
|
|
236
|
+
puts " Skipped: app/views/shared/#{filename}"
|
|
237
|
+
end
|
|
185
238
|
end
|
|
186
239
|
|
|
187
240
|
# Copy scaffold hook initializer
|
|
@@ -189,8 +242,12 @@ namespace :basecoat do
|
|
|
189
242
|
initializer_destination = Rails.root.join("config/initializers/scaffold_hook.rb")
|
|
190
243
|
|
|
191
244
|
FileUtils.mkdir_p(File.dirname(initializer_destination))
|
|
192
|
-
|
|
193
|
-
|
|
245
|
+
if prompt_overwrite(initializer_destination, overwrite_all)
|
|
246
|
+
FileUtils.cp(initializer_source, initializer_destination)
|
|
247
|
+
puts " Created: config/initializers/scaffold_hook.rb"
|
|
248
|
+
else
|
|
249
|
+
puts " Skipped: config/initializers/scaffold_hook.rb"
|
|
250
|
+
end
|
|
194
251
|
|
|
195
252
|
puts "\n✓ Basecoat installed successfully!"
|
|
196
253
|
puts " Scaffold templates are automatically available from the gem."
|
|
@@ -200,21 +257,37 @@ namespace :basecoat do
|
|
|
200
257
|
namespace :install do
|
|
201
258
|
desc "Install Basecoat Devise views and layout"
|
|
202
259
|
task :devise do
|
|
260
|
+
overwrite_all = { value: false }
|
|
261
|
+
|
|
203
262
|
# Copy devise views
|
|
204
263
|
devise_source = File.expand_path("../generators/basecoat/templates/devise", __dir__)
|
|
205
264
|
devise_destination = Rails.root.join("app/views/devise")
|
|
206
265
|
|
|
207
266
|
FileUtils.mkdir_p(devise_destination)
|
|
208
|
-
|
|
209
|
-
|
|
267
|
+
Dir.glob("#{devise_source}/**/*").each do |file|
|
|
268
|
+
next if File.directory?(file)
|
|
269
|
+
relative_path = Pathname.new(file).relative_path_from(Pathname.new(devise_source))
|
|
270
|
+
destination = devise_destination.join(relative_path)
|
|
271
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
272
|
+
if prompt_overwrite(destination, overwrite_all)
|
|
273
|
+
FileUtils.cp(file, destination)
|
|
274
|
+
puts " Created: app/views/devise/#{relative_path}"
|
|
275
|
+
else
|
|
276
|
+
puts " Skipped: app/views/devise/#{relative_path}"
|
|
277
|
+
end
|
|
278
|
+
end
|
|
210
279
|
|
|
211
280
|
# Copy devise layout
|
|
212
281
|
layout_source = File.expand_path("../generators/basecoat/templates/devise.html.erb", __dir__)
|
|
213
282
|
layout_destination = Rails.root.join("app/views/layouts/devise.html.erb")
|
|
214
283
|
|
|
215
284
|
FileUtils.mkdir_p(File.dirname(layout_destination))
|
|
216
|
-
|
|
217
|
-
|
|
285
|
+
if prompt_overwrite(layout_destination, overwrite_all)
|
|
286
|
+
FileUtils.cp(layout_source, layout_destination)
|
|
287
|
+
puts " Created: app/views/layouts/devise.html.erb"
|
|
288
|
+
else
|
|
289
|
+
puts " Skipped: app/views/layouts/devise.html.erb"
|
|
290
|
+
end
|
|
218
291
|
|
|
219
292
|
# Add user dropdown to header partial
|
|
220
293
|
header_path = Rails.root.join("app/views/layouts/_header.html.erb")
|
|
@@ -225,8 +298,8 @@ namespace :basecoat do
|
|
|
225
298
|
|
|
226
299
|
<% if defined?(user_signed_in?) && user_signed_in? %>
|
|
227
300
|
<div id="dropdown-user" class="dropdown-menu">
|
|
228
|
-
<button type="button" id="dropdown-user-trigger" aria-haspopup="menu" aria-controls="dropdown-user-menu" aria-expanded="false" class="btn-
|
|
229
|
-
<
|
|
301
|
+
<button type="button" id="dropdown-user-trigger" aria-haspopup="menu" aria-controls="dropdown-user-menu" aria-expanded="false" class="btn-ghost size-8">
|
|
302
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-user-icon lucide-circle-user"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="10" r="3"/><path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662"/></svg>
|
|
230
303
|
</button>
|
|
231
304
|
<div id="dropdown-user-popover" data-popover="" aria-hidden="true" data-align="end">
|
|
232
305
|
<div role="menu" id="dropdown-user-menu" aria-labelledby="dropdown-user-trigger">
|
|
@@ -253,6 +326,7 @@ namespace :basecoat do
|
|
|
253
326
|
|
|
254
327
|
desc "Install Basecoat Pagy pagination styles"
|
|
255
328
|
task :pagy do
|
|
329
|
+
overwrite_all = { value: false }
|
|
256
330
|
pagy_source = File.expand_path("../generators/basecoat/templates/pagy.scss", __dir__)
|
|
257
331
|
|
|
258
332
|
# Check if using Tailwind v4 setup (app/assets/tailwind)
|
|
@@ -260,8 +334,12 @@ namespace :basecoat do
|
|
|
260
334
|
# Copy pagy styles to tailwind directory
|
|
261
335
|
pagy_destination = Rails.root.join("app/assets/tailwind/pagy.scss")
|
|
262
336
|
FileUtils.mkdir_p(File.dirname(pagy_destination))
|
|
263
|
-
|
|
264
|
-
|
|
337
|
+
if prompt_overwrite(pagy_destination, overwrite_all)
|
|
338
|
+
FileUtils.cp(pagy_source, pagy_destination)
|
|
339
|
+
puts " Created: app/assets/tailwind/pagy.scss"
|
|
340
|
+
else
|
|
341
|
+
puts " Skipped: app/assets/tailwind/pagy.scss"
|
|
342
|
+
end
|
|
265
343
|
|
|
266
344
|
# Add import to tailwind application.css
|
|
267
345
|
tailwind_css = Rails.root.join("app/assets/tailwind/application.css")
|
|
@@ -276,8 +354,12 @@ namespace :basecoat do
|
|
|
276
354
|
# Copy pagy styles to stylesheets directory
|
|
277
355
|
pagy_destination = Rails.root.join("app/assets/stylesheets/pagy.scss")
|
|
278
356
|
FileUtils.mkdir_p(File.dirname(pagy_destination))
|
|
279
|
-
|
|
280
|
-
|
|
357
|
+
if prompt_overwrite(pagy_destination, overwrite_all)
|
|
358
|
+
FileUtils.cp(pagy_source, pagy_destination)
|
|
359
|
+
puts " Created: app/assets/stylesheets/pagy.scss"
|
|
360
|
+
else
|
|
361
|
+
puts " Skipped: app/assets/stylesheets/pagy.scss"
|
|
362
|
+
end
|
|
281
363
|
end
|
|
282
364
|
|
|
283
365
|
puts "\n✓ Basecoat Pagy styles installed successfully!"
|
|
@@ -286,29 +368,55 @@ namespace :basecoat do
|
|
|
286
368
|
|
|
287
369
|
desc "Install Basecoat authentication views and layout"
|
|
288
370
|
task :authentication do
|
|
371
|
+
overwrite_all = { value: false }
|
|
372
|
+
|
|
289
373
|
# Copy sessions views
|
|
290
374
|
sessions_source = File.expand_path("../generators/basecoat/templates/sessions", __dir__)
|
|
291
375
|
sessions_destination = Rails.root.join("app/views/sessions")
|
|
292
376
|
|
|
293
377
|
FileUtils.mkdir_p(sessions_destination)
|
|
294
|
-
|
|
295
|
-
|
|
378
|
+
Dir.glob("#{sessions_source}/**/*").each do |file|
|
|
379
|
+
next if File.directory?(file)
|
|
380
|
+
relative_path = Pathname.new(file).relative_path_from(Pathname.new(sessions_source))
|
|
381
|
+
destination = sessions_destination.join(relative_path)
|
|
382
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
383
|
+
if prompt_overwrite(destination, overwrite_all)
|
|
384
|
+
FileUtils.cp(file, destination)
|
|
385
|
+
puts " Created: app/views/sessions/#{relative_path}"
|
|
386
|
+
else
|
|
387
|
+
puts " Skipped: app/views/sessions/#{relative_path}"
|
|
388
|
+
end
|
|
389
|
+
end
|
|
296
390
|
|
|
297
391
|
# Copy passwords views
|
|
298
392
|
passwords_source = File.expand_path("../generators/basecoat/templates/passwords", __dir__)
|
|
299
393
|
passwords_destination = Rails.root.join("app/views/passwords")
|
|
300
394
|
|
|
301
395
|
FileUtils.mkdir_p(passwords_destination)
|
|
302
|
-
|
|
303
|
-
|
|
396
|
+
Dir.glob("#{passwords_source}/**/*").each do |file|
|
|
397
|
+
next if File.directory?(file)
|
|
398
|
+
relative_path = Pathname.new(file).relative_path_from(Pathname.new(passwords_source))
|
|
399
|
+
destination = passwords_destination.join(relative_path)
|
|
400
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
401
|
+
if prompt_overwrite(destination, overwrite_all)
|
|
402
|
+
FileUtils.cp(file, destination)
|
|
403
|
+
puts " Created: app/views/passwords/#{relative_path}"
|
|
404
|
+
else
|
|
405
|
+
puts " Skipped: app/views/passwords/#{relative_path}"
|
|
406
|
+
end
|
|
407
|
+
end
|
|
304
408
|
|
|
305
409
|
# Copy sessions layout
|
|
306
410
|
layout_source = File.expand_path("../generators/basecoat/templates/sessions.html.erb", __dir__)
|
|
307
411
|
layout_destination = Rails.root.join("app/views/layouts/sessions.html.erb")
|
|
308
412
|
|
|
309
413
|
FileUtils.mkdir_p(File.dirname(layout_destination))
|
|
310
|
-
|
|
311
|
-
|
|
414
|
+
if prompt_overwrite(layout_destination, overwrite_all)
|
|
415
|
+
FileUtils.cp(layout_source, layout_destination)
|
|
416
|
+
puts " Created: app/views/layouts/sessions.html.erb"
|
|
417
|
+
else
|
|
418
|
+
puts " Skipped: app/views/layouts/sessions.html.erb"
|
|
419
|
+
end
|
|
312
420
|
|
|
313
421
|
# Add layout to passwords_controller
|
|
314
422
|
passwords_controller = Rails.root.join("app/controllers/passwords_controller.rb")
|
|
@@ -331,8 +439,8 @@ namespace :basecoat do
|
|
|
331
439
|
|
|
332
440
|
<% if defined?(Current) && defined?(Current.user) && Current.user %>
|
|
333
441
|
<div id="dropdown-user" class="dropdown-menu">
|
|
334
|
-
<button type="button" id="dropdown-user-trigger" aria-haspopup="menu" aria-controls="dropdown-user-menu" aria-expanded="false" class="btn-
|
|
335
|
-
<
|
|
442
|
+
<button type="button" id="dropdown-user-trigger" aria-haspopup="menu" aria-controls="dropdown-user-menu" aria-expanded="false" class="btn-ghost size-8">
|
|
443
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-user-icon lucide-circle-user"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="10" r="3"/><path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662"/></svg>
|
|
336
444
|
</button>
|
|
337
445
|
<div id="dropdown-user-popover" data-popover="" aria-hidden="true" data-align="end">
|
|
338
446
|
<div role="menu" id="dropdown-user-menu" aria-labelledby="dropdown-user-trigger">
|
|
@@ -23,12 +23,15 @@
|
|
|
23
23
|
<%%= form.check_box :<%= attribute.column_name %>, class: "input", role: "switch" %>
|
|
24
24
|
<%= attribute.human_name %>
|
|
25
25
|
<%% end %>
|
|
26
|
-
<% elsif
|
|
26
|
+
<% elsif %w[url permalink website].include? attribute.column_name -%>
|
|
27
27
|
<%%= form.label :<%= attribute.column_name %>, class: "label" %>
|
|
28
|
-
|
|
29
|
-
<% elsif attribute.
|
|
28
|
+
<%%= form.url_field :<%= attribute.column_name %>, class: "input"<%= ", required: true" if required %> %>
|
|
29
|
+
<% elsif %w[email email_address].include? attribute.column_name -%>
|
|
30
30
|
<%%= form.label :<%= attribute.column_name %>, class: "label" %>
|
|
31
|
-
<%%= form
|
|
31
|
+
<%%= form.email_field :<%= attribute.column_name %>, class: "input"<%= ", required: true" if required %> %>
|
|
32
|
+
<% elsif %w[phone phone_number].include? attribute.column_name -%>
|
|
33
|
+
<%%= form.label :<%= attribute.column_name %>, class: "label" %>
|
|
34
|
+
<%%= form.phone_field :<%= attribute.column_name %>, maxLength: 16, pattern: "[0-9\+\\-\\(\\)\s]*", class: "input"<%= ", required: true" if required %> %>
|
|
32
35
|
<% else -%>
|
|
33
36
|
<%%= form.label :<%= attribute.column_name %>, class: "label" %>
|
|
34
37
|
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, class: "input"<%= ", required: true" if required %> %>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: basecoat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Martijn Lafeber
|
|
@@ -40,9 +40,8 @@ files:
|
|
|
40
40
|
- LICENSE.txt
|
|
41
41
|
- README.md
|
|
42
42
|
- Rakefile
|
|
43
|
-
- basecoat-dark-form.png
|
|
44
|
-
- basecoat-index.png
|
|
45
43
|
- basecoat-login.png
|
|
44
|
+
- basecoat-new.png
|
|
46
45
|
- lib/basecoat.rb
|
|
47
46
|
- lib/basecoat/railtie.rb
|
|
48
47
|
- lib/basecoat/version.rb
|
data/basecoat-dark-form.png
DELETED
|
Binary file
|
data/basecoat-index.png
DELETED
|
Binary file
|