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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30c46abb1310bf79995534b1fcd52074a67f327d42ea93a933065b46b02d8563
4
- data.tar.gz: 509ac587a90f7be78362d5d92d0506de9528dc3e773d0c20b7bdfa2050eedc30
3
+ metadata.gz: 92a3b3db00be4f62dcf379eac035135cb5161b3bc68e9f1d0c7121e87c88b387
4
+ data.tar.gz: 45d0cb31d2da696369191e60945ba66b25b590e1c321b03df641b4583ba7fcd8
5
5
  SHA512:
6
- metadata.gz: f01fd3115a85191fb41f999662adfda41666f022d54f53e46242987ba5b61fc4459322f41d48f238b1dc2537573a161b2514baf8faee83762fff80e2e7faa11d
7
- data.tar.gz: c58e1ced83b1ad2b8083e0cbc7481476fe06ba8abe26cc95280f4047d1c0174596b129dcfcaf5f1bfa9b5d77c27689649dfb6334743251a6bf9c42607b1c5651
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
  ![Basecoat Login](basecoat-login.png)
10
- Index:
11
- ![Basecoat Index](basecoat-index.png)
12
- Form, mobile dark mode:
13
- ![Basecoat Dark Form](basecoat-dark-form.png)
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
- This is where basecoat-ui comes in. The reason why I love basecoat is because it combines tailwind with clean css classes (like daisy-ui).
8
+ ![Basecoat Form](basecoat-new.png)
21
9
 
22
- 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.
23
-
24
- ## Installation
10
+ ## Usage
25
11
 
26
- Add this line to your application's Gemfile in the development group:
12
+ Try it from scratch:
27
13
 
28
- ```ruby
29
- gem 'basecoat'
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
- And then execute:
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
- ```bash
35
- bundle install
36
- ```
25
+ ## Why?
37
26
 
38
- **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.
27
+ The default scaffolds are ugly. There's no styling, no turbo frames - it's missing the WOW factor.
39
28
 
40
- ## Usage
29
+ Basecoat CSS combines tailwind with clean css classes. It creates the looks of shadcn, which has a massive community.
41
30
 
42
- Run the rake tasks, run a scaffold and observe beauty.
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
- ### Install Application Layout
33
+ ## Rake tasks
45
34
 
46
- Install the Basecoat application layout and partials:
35
+ ### Layout (required)
47
36
 
48
37
  ```bash
49
38
  rake basecoat:install
50
39
  ```
51
- NB: This could overwrite exising files!
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
- * View transitions
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
- ```bash
66
- rails generate scaffold Post title:string body:text published:boolean
67
- ```
54
+ ### Default Rails Authentication
68
55
 
69
- ### Install Devise Views
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
- Install the Basecoat-styled Devise views and layout:
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
- ```bash
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
- ### Install Authentication Views
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:authentication
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
- * The javascript included by basecoat needs some improvement. It's not automatically initialized on turbo:load - included is a hack that I hope is temporary.
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Basecoat
4
- VERSION = "2.0.0"
4
+ VERSION = "2.2.0"
5
5
  end
@@ -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-icon-outline size-8">
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" %>
@@ -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
- FileUtils.cp(theme_controller_source, theme_controller_destination)
86
- puts " Created: app/javascript/controllers/theme_controller.js"
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
- .field_with_errors {
116
- label {
117
- color: var(--color-destructive);
118
- }
119
-
120
- input {
121
- border-color: var(--color-destructive);
122
- }
123
- }
124
-
125
- dl {
126
- font-size: var(--text-sm);
127
- dt {
128
- font-weight: var(--font-weight-bold);
129
- margin-top: calc(var(--spacing)*4);
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
- File.write(head_destination, head_content + "\n")
151
- puts " Created: app/views/layouts/_head.html.erb (extracted from existing application.html.erb)"
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
- FileUtils.cp("#{partials_source}/_head.html.erb", partials_destination.join("_head.html.erb"))
155
- puts " Created: app/views/layouts/_head.html.erb (from template)"
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
- FileUtils.cp("#{partials_source}/_head.html.erb", partials_destination.join("_head.html.erb"))
160
- puts " Created: app/views/layouts/_head.html.erb (from template)"
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
- FileUtils.cp(layout_source, layout_destination)
166
- puts " Created: app/views/layouts/application.html.erb"
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
- FileUtils.cp(file, partials_destination.join(filename))
173
- puts " Created: app/views/layouts/#{filename}"
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
- FileUtils.cp(file, shared_destination.join(filename))
184
- puts " Created: app/views/shared/#{filename}"
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
- FileUtils.cp(initializer_source, initializer_destination)
193
- puts " Created: config/initializers/scaffold_hook.rb"
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
- FileUtils.cp_r("#{devise_source}/.", devise_destination)
209
- puts " Created: app/views/devise/"
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
- FileUtils.cp(layout_source, layout_destination)
217
- puts " Created: app/views/layouts/devise.html.erb"
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-icon-ghost rounded-full size-8">
229
- <img alt="<%= current_user.email %>" src="https://github.com/lafeber.png" class="size-8 shrink-0 rounded-full">
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
- FileUtils.cp(pagy_source, pagy_destination)
264
- puts " Created: app/assets/tailwind/pagy.scss"
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
- FileUtils.cp(pagy_source, pagy_destination)
280
- puts " Created: app/assets/stylesheets/pagy.scss"
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
- FileUtils.cp_r("#{sessions_source}/.", sessions_destination)
295
- puts " Created: app/views/sessions/"
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
- FileUtils.cp_r("#{passwords_source}/.", passwords_destination)
303
- puts " Created: app/views/passwords/"
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
- FileUtils.cp(layout_source, layout_destination)
311
- puts " Created: app/views/layouts/sessions.html.erb"
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-icon-ghost rounded-full size-8">
335
- <img alt="<%= Current.user.email_address %>" src="https://github.com/lafeber.png" class="size-8 shrink-0 rounded-full">
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 attribute.field_type == :datetime_local_field || attribute.field_type == :date_field || attribute.field_type == :time_field -%>
26
+ <% elsif %w[url permalink website].include? attribute.column_name -%>
27
27
  <%%= form.label :<%= attribute.column_name %>, class: "label" %>
28
- <%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, class: "input"<%= ", required: true" if required %> %>
29
- <% elsif attribute.field_type == :number_field -%>
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.<%= attribute.field_type %> :<%= attribute.column_name %>, class: "input"<%= ", required: true" if required %> %>
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.0.0
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
Binary file
data/basecoat-index.png DELETED
Binary file