basecoat 0.1.1
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 +7 -0
- data/.idea/.gitignore +8 -0
- data/.idea/basecoat.iml +17 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/vcs.xml +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +194 -0
- data/Rakefile +4 -0
- data/lib/basecoat/railtie.rb +11 -0
- data/lib/basecoat/version.rb +5 -0
- data/lib/basecoat.rb +8 -0
- data/lib/generators/basecoat/templates/application.html.erb +16 -0
- data/lib/generators/basecoat/templates/devise/confirmations/new.html.erb +27 -0
- data/lib/generators/basecoat/templates/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/lib/generators/basecoat/templates/devise/mailer/email_changed.html.erb +7 -0
- data/lib/generators/basecoat/templates/devise/mailer/password_change.html.erb +3 -0
- data/lib/generators/basecoat/templates/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/lib/generators/basecoat/templates/devise/mailer/unlock_instructions.html.erb +7 -0
- data/lib/generators/basecoat/templates/devise/passwords/edit.html.erb +40 -0
- data/lib/generators/basecoat/templates/devise/passwords/new.html.erb +31 -0
- data/lib/generators/basecoat/templates/devise/registrations/edit.html.erb +63 -0
- data/lib/generators/basecoat/templates/devise/registrations/new.html.erb +40 -0
- data/lib/generators/basecoat/templates/devise/sessions/new.html.erb +38 -0
- data/lib/generators/basecoat/templates/devise/shared/_error_messages.html.erb +15 -0
- data/lib/generators/basecoat/templates/devise/shared/_links.html.erb +27 -0
- data/lib/generators/basecoat/templates/devise/unlocks/new.html.erb +29 -0
- data/lib/generators/basecoat/templates/devise.html.erb +36 -0
- data/lib/generators/basecoat/templates/layouts/_alert.html.erb +6 -0
- data/lib/generators/basecoat/templates/layouts/_aside.html.erb +21 -0
- data/lib/generators/basecoat/templates/layouts/_form_errors.html.erb +13 -0
- data/lib/generators/basecoat/templates/layouts/_head.html.erb +21 -0
- data/lib/generators/basecoat/templates/layouts/_header.html.erb +12 -0
- data/lib/generators/basecoat/templates/layouts/_notice.html.erb +18 -0
- data/lib/generators/basecoat/templates/pagy.scss +31 -0
- data/lib/generators/basecoat/templates/passwords/edit.html.erb +30 -0
- data/lib/generators/basecoat/templates/passwords/new.html.erb +25 -0
- data/lib/generators/basecoat/templates/scaffold_hook.rb +36 -0
- data/lib/generators/basecoat/templates/sessions/new.html.erb +30 -0
- data/lib/generators/basecoat/templates/sessions.html.erb +36 -0
- data/lib/tasks/basecoat.rake +281 -0
- data/lib/templates/erb/scaffold/_form.html.erb.tt +43 -0
- data/lib/templates/erb/scaffold/edit.html.erb.tt +21 -0
- data/lib/templates/erb/scaffold/index.html.erb.tt +35 -0
- data/lib/templates/erb/scaffold/new.html.erb.tt +20 -0
- data/lib/templates/erb/scaffold/partial.html.erb.tt +20 -0
- data/lib/templates/erb/scaffold/show.html.erb.tt +23 -0
- data/sig/basecoat.rbs +4 -0
- metadata +104 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8f01bc1f26666e2b22f7dce37ac14410959de6e6b59b8a6dcce926a810337c3c
|
|
4
|
+
data.tar.gz: d6c89871d8c7786c7919c2f2cb3ce42535590db0ca058febfe6f8a709f12207f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 143506fdec46f25c4ac200bd81c5c8aa74363ec4cd3bc99c63921613a830e0a8f971579bcc766d57ce42ce3d7818792830a881cf05a50dab70b6c8f13fbdfd05
|
|
7
|
+
data.tar.gz: be5d2db1f6b559a1937e257e07cf8cb2ce98a138be26e99b145c7090fd476f363684ff19993288feae77858c2a79a86b51951c7ed217b596e36c5ac1ec0c3958
|
data/.idea/.gitignore
ADDED
data/.idea/basecoat.iml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="RUBY_MODULE" version="4">
|
|
3
|
+
<component name="ModuleRunConfigurationManager">
|
|
4
|
+
<shared />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="NewModuleRootManager">
|
|
7
|
+
<content url="file://$MODULE_DIR$">
|
|
8
|
+
<sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
|
|
9
|
+
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
|
10
|
+
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
11
|
+
</content>
|
|
12
|
+
<orderEntry type="inheritedJdk" />
|
|
13
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
14
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v1.17.2, ruby-2.6.10-p210) [gem]" level="application" />
|
|
15
|
+
<orderEntry type="library" scope="PROVIDED" name="irb (v1.0.0, ruby-2.6.10-p210) [gem]" level="application" />
|
|
16
|
+
</component>
|
|
17
|
+
</module>
|
data/.idea/misc.xml
ADDED
data/.idea/modules.xml
ADDED
data/.idea/vcs.xml
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Martijn Lafeber
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# All of the shadcn/ui styling, all of the Rails power, no React
|
|
2
|
+
|
|
3
|
+
This gem provides you with amazing frontend based on [Basecoat CSS](https://basecoatui.com).
|
|
4
|
+
It is especially powerful for admin applications with a lot of CRUD actions.
|
|
5
|
+
|
|
6
|
+
Experience beautiful Rails scaffolds, pages for authentication and Devise, and pagy styling.
|
|
7
|
+
All responsive, all dark & light mode. See all the features below.
|
|
8
|
+
|
|
9
|
+
## Why?
|
|
10
|
+
|
|
11
|
+
There is a new default component library for the web; it's called shadcn.
|
|
12
|
+
As a developer you are standing on the shoulders of a giant with every component they provide.
|
|
13
|
+
However... in many (most?) applications you don't need complicated components -
|
|
14
|
+
e.g. an input field can just be a html tag, not a separate component with its own shadow DOM.
|
|
15
|
+
|
|
16
|
+
This is where basecoat-css comes in.
|
|
17
|
+
|
|
18
|
+
You can still include complicated shadcn React components if you need them,
|
|
19
|
+
but most of your application is just the simple rails views, leveraging the power of Rails.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Add this line to your application's Gemfile:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
gem 'basecoat'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
And then execute:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bundle install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**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.
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
Run the rake tasks, run a scaffold and observe beauty.
|
|
40
|
+
|
|
41
|
+
### Install Application Layout
|
|
42
|
+
|
|
43
|
+
Install the Basecoat application layout and partials:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
rake basecoat:install
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This will:
|
|
50
|
+
- Install `basecoat-css` via yarn/npm (if package.json exists) or importmap
|
|
51
|
+
- Add basecoat-css import to `app/javascript/application.js`
|
|
52
|
+
- Add view transition JavaScript for turbo frames
|
|
53
|
+
- Add dark mode toggle functionality
|
|
54
|
+
- Add view transition CSS animations and form validation styles
|
|
55
|
+
- Copy application layout to `app/views/layouts/application.html.erb`
|
|
56
|
+
- Copy layout partials (`_head.html.erb`, `_header.html.erb`, `_aside.html.erb`, `_notice.html.erb`, `_alert.html.erb`, `_form_errors.html.erb`)
|
|
57
|
+
- Copy scaffold hook initializer to `config/initializers/scaffold_hook.rb`
|
|
58
|
+
|
|
59
|
+
The scaffold templates are automatically available from the gem, so you can immediately generate scaffolds:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
rails generate scaffold Post title:string body:text published:boolean
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The generated views will include:
|
|
66
|
+
* Basecoat CSS styling
|
|
67
|
+
* Turbo Frame support for SPA-like navigation
|
|
68
|
+
* View transitions
|
|
69
|
+
* Responsive design
|
|
70
|
+
* Dark mode support
|
|
71
|
+
* Form validation with required fields
|
|
72
|
+
* Boolean fields styled as switches
|
|
73
|
+
* Automatic sidebar navigation links
|
|
74
|
+
|
|
75
|
+
### Install Devise Views
|
|
76
|
+
|
|
77
|
+
Install the Basecoat-styled Devise views and layout:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
rake basecoat:install:devise
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This will copy:
|
|
84
|
+
- All Devise views to `app/views/devise/`
|
|
85
|
+
- Devise layout to `app/views/layouts/devise.html.erb`
|
|
86
|
+
|
|
87
|
+
The Devise views include:
|
|
88
|
+
- Beautiful login/signup forms
|
|
89
|
+
* Two-column layout with image placeholder
|
|
90
|
+
* Dark mode toggle
|
|
91
|
+
* Responsive design
|
|
92
|
+
* Password reset flows
|
|
93
|
+
* Email confirmation views
|
|
94
|
+
|
|
95
|
+
### Install Pagy Pagination Styles
|
|
96
|
+
|
|
97
|
+
Install the Basecoat-styled Pagy pagination:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
rake basecoat:install:pagy
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This will copy:
|
|
104
|
+
- Pagy styles to `app/assets/stylesheets/pagy.scss`
|
|
105
|
+
|
|
106
|
+
The Pagy styles include:
|
|
107
|
+
|
|
108
|
+
* Basecoat CSS button styling using `@apply`
|
|
109
|
+
* Proper spacing and layout
|
|
110
|
+
* Active page highlighting
|
|
111
|
+
* Disabled state styling
|
|
112
|
+
|
|
113
|
+
### Install Authentication Views
|
|
114
|
+
|
|
115
|
+
Install the Basecoat-styled authentication views (for Rails built-in authentication):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
rake basecoat:install:authentication
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This will copy:
|
|
122
|
+
- Sessions views to `app/views/sessions/`
|
|
123
|
+
- Passwords views to `app/views/passwords/`
|
|
124
|
+
- Sessions layout to `app/views/layouts/sessions.html.erb`
|
|
125
|
+
- Adds `layout "sessions"` to `app/controllers/passwords_controller.rb`
|
|
126
|
+
|
|
127
|
+
The authentication views include:
|
|
128
|
+
|
|
129
|
+
* Beautiful sign in form
|
|
130
|
+
* Password reset flows
|
|
131
|
+
* Two-column layout with image placeholder
|
|
132
|
+
* Dark mode toggle
|
|
133
|
+
* Responsive design
|
|
134
|
+
* Consistent styling with Devise views
|
|
135
|
+
|
|
136
|
+
## Features
|
|
137
|
+
|
|
138
|
+
### Application Layout
|
|
139
|
+
|
|
140
|
+
- **Sidebar Navigation**: Collapsible sidebar with automatic active state detection
|
|
141
|
+
- **Header**: User dropdown with sign out functionality
|
|
142
|
+
- **Alerts & Notices**: Beautiful toast notifications for flash messages
|
|
143
|
+
- **Form Errors**: Consistent error message styling
|
|
144
|
+
- **Dark Mode**: Built-in theme toggle
|
|
145
|
+
|
|
146
|
+
### Scaffold Templates
|
|
147
|
+
|
|
148
|
+
- **Modern UI**: Clean, professional design using Basecoat CSS
|
|
149
|
+
- **Turbo Frames**: SPA-like navigation without full page reloads
|
|
150
|
+
- **View Transitions**: Smooth slide animations between pages
|
|
151
|
+
- **Smart Forms**: Automatic required field detection based on database schema
|
|
152
|
+
- **Auto Sidebar Links**: New scaffolds automatically add navigation links to sidebar
|
|
153
|
+
- **Dark Mode**: Built-in dark mode support
|
|
154
|
+
- **Responsive**: Mobile-first responsive design
|
|
155
|
+
|
|
156
|
+
### Devise Views
|
|
157
|
+
|
|
158
|
+
- **Professional Design**: Matches modern authentication UI patterns
|
|
159
|
+
- **Two-Column Layout**: Image placeholder with form on desktop
|
|
160
|
+
- **Complete Views**: All Devise views including confirmations, passwords, registrations
|
|
161
|
+
- **Dark Mode**: Toggle between light and dark themes
|
|
162
|
+
- **Accessible**: ARIA labels and semantic HTML
|
|
163
|
+
|
|
164
|
+
## Requirements
|
|
165
|
+
|
|
166
|
+
- Rails 8.0+
|
|
167
|
+
- Tailwind CSS ([installation instructions](https://github.com/rails/tailwindcss-rails))
|
|
168
|
+
- Basecoat CSS
|
|
169
|
+
- Turbo Rails (for scaffold templates)
|
|
170
|
+
|
|
171
|
+
## How It Works
|
|
172
|
+
|
|
173
|
+
The gem uses Rails' template resolution system to provide scaffold templates automatically. When you run `rails generate scaffold`, Rails will use the templates from the Basecoat gem instead of the default ones.
|
|
174
|
+
|
|
175
|
+
The application layout and partials are copied to your application so you can customize them as needed.
|
|
176
|
+
|
|
177
|
+
## Discussion
|
|
178
|
+
|
|
179
|
+
I tried not to be too opinionated with my scaffolds - they're very close to the original ones. With the exception of
|
|
180
|
+
using a turbo frame main_content. I love this too much not to include it.
|
|
181
|
+
|
|
182
|
+
However, I have my doubts with the index page reusing the show partial. Especially in admin applications you might want
|
|
183
|
+
to have a (responsive) table in the index.
|
|
184
|
+
|
|
185
|
+
Also, the arguably ugliest part of the views are the svg tags which contains the lovely lucide icons.
|
|
186
|
+
Since these icons are the default for shadcn I'm considering including https://github.com/heyvito/lucide-rails to clean up the views.
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
Bug reports and pull requests are welcome on GitHub.
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/lib/basecoat.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<%= render "layouts/head" %>
|
|
4
|
+
<body>
|
|
5
|
+
<%= render 'layouts/alert', alert: alert if alert %>
|
|
6
|
+
<%= render "layouts/aside" %>
|
|
7
|
+
<main>
|
|
8
|
+
<%= render "layouts/header" %>
|
|
9
|
+
<div class="py-8">
|
|
10
|
+
<%= turbo_frame_tag "main_content" do %>
|
|
11
|
+
<%= yield %>
|
|
12
|
+
<% end %>
|
|
13
|
+
</div>
|
|
14
|
+
</main>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<div class="container mx-auto px-4 py-8">
|
|
2
|
+
<div class="max-w-2xl mx-auto">
|
|
3
|
+
<div class="card">
|
|
4
|
+
<header>
|
|
5
|
+
<h2>Resend confirmation instructions</h2>
|
|
6
|
+
<p>Enter your email address to receive confirmation instructions.</p>
|
|
7
|
+
</header>
|
|
8
|
+
<section class="space-y-4">
|
|
9
|
+
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: "grid gap-6" }) do |f| %>
|
|
10
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
11
|
+
|
|
12
|
+
<div class="grid gap-3">
|
|
13
|
+
<%= f.label :email, class: "label" %>
|
|
14
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), class: "input" %>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="grid gap-3">
|
|
18
|
+
<%= f.submit "Resend confirmation instructions", class: "btn" %>
|
|
19
|
+
</div>
|
|
20
|
+
<% end %>
|
|
21
|
+
</section>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="mt-6">
|
|
24
|
+
<%= render "devise/shared/links" %>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<p>Hello <%= @email %>!</p>
|
|
2
|
+
|
|
3
|
+
<% if @resource.try(:unconfirmed_email?) %>
|
|
4
|
+
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
|
|
5
|
+
<% else %>
|
|
6
|
+
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
|
|
7
|
+
<% end %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<p>Hello <%= @resource.email %>!</p>
|
|
2
|
+
|
|
3
|
+
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
|
4
|
+
|
|
5
|
+
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
|
6
|
+
|
|
7
|
+
<p>If you didn't request this, please ignore this email.</p>
|
|
8
|
+
<p>Your password won't change until you access the link above and create a new one.</p>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<p>Hello <%= @resource.email %>!</p>
|
|
2
|
+
|
|
3
|
+
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
|
4
|
+
|
|
5
|
+
<p>Click the link below to unlock your account:</p>
|
|
6
|
+
|
|
7
|
+
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
<div class="container mx-auto px-4 py-8">
|
|
6
|
+
<div class="max-w-2xl mx-auto">
|
|
7
|
+
<div class="card">
|
|
8
|
+
<header>
|
|
9
|
+
<h2>Change your password</h2>
|
|
10
|
+
<p>Enter your new password below.</p>
|
|
11
|
+
</header>
|
|
12
|
+
<section class="space-y-4">
|
|
13
|
+
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put, class: "grid gap-6" }) do |f| %>
|
|
14
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
15
|
+
<%= f.hidden_field :reset_password_token %>
|
|
16
|
+
|
|
17
|
+
<div class="grid gap-3">
|
|
18
|
+
<%= f.label :password, "New password", class: "label" %>
|
|
19
|
+
<% if @minimum_password_length %>
|
|
20
|
+
<span class="text-sm text-muted-foreground">(<%= @minimum_password_length %> characters minimum)</span>
|
|
21
|
+
<% end %>
|
|
22
|
+
<%= f.password_field :password, autofocus: true, autocomplete: "new-password", class: "input" %>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="grid gap-3">
|
|
26
|
+
<%= f.label :password_confirmation, "Confirm new password", class: "label" %>
|
|
27
|
+
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: "input" %>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="grid gap-3">
|
|
31
|
+
<%= f.submit "Change my password", class: "btn" %>
|
|
32
|
+
</div>
|
|
33
|
+
<% end %>
|
|
34
|
+
</section>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="mt-6">
|
|
37
|
+
<%= render "devise/shared/links" %>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
<div class="container mx-auto px-4 py-8">
|
|
6
|
+
<div class="max-w-2xl mx-auto">
|
|
7
|
+
<div class="card">
|
|
8
|
+
<header>
|
|
9
|
+
<h2>Forgot your password?</h2>
|
|
10
|
+
<p>Enter your email address and we'll send you instructions to reset your password.</p>
|
|
11
|
+
</header>
|
|
12
|
+
<section class="space-y-4">
|
|
13
|
+
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post, class: "grid gap-6" }) do |f| %>
|
|
14
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
15
|
+
|
|
16
|
+
<div class="grid gap-3">
|
|
17
|
+
<%= f.label :email, class: "label" %>
|
|
18
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: "input" %>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="grid gap-3">
|
|
22
|
+
<%= f.submit "Send reset link", class: "btn" %>
|
|
23
|
+
</div>
|
|
24
|
+
<% end %>
|
|
25
|
+
</section>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="mt-6">
|
|
28
|
+
<%= render "devise/shared/links" %>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<div class="container mx-auto px-4 py-8">
|
|
2
|
+
<div class="max-w-2xl mx-auto">
|
|
3
|
+
<div class="card">
|
|
4
|
+
<header>
|
|
5
|
+
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
|
6
|
+
<p>Update your account settings.</p>
|
|
7
|
+
</header>
|
|
8
|
+
|
|
9
|
+
<section class="space-y-4">
|
|
10
|
+
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: "grid gap-6" }) do |f| %>
|
|
11
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
12
|
+
|
|
13
|
+
<div class="grid gap-3">
|
|
14
|
+
<%= f.label :email, class: "label" %>
|
|
15
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: "input" %>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
|
19
|
+
<div class="text-sm text-muted-foreground">Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
|
|
20
|
+
<% end %>
|
|
21
|
+
|
|
22
|
+
<div class="grid gap-3">
|
|
23
|
+
<%= f.label :password, class: "label" %>
|
|
24
|
+
<span class="text-sm text-muted-foreground">(leave blank if you don't want to change it)</span>
|
|
25
|
+
<%= f.password_field :password, autocomplete: "new-password", class: "input" %>
|
|
26
|
+
<% if @minimum_password_length %>
|
|
27
|
+
<span class="text-sm text-muted-foreground"><%= @minimum_password_length %> characters minimum</span>
|
|
28
|
+
<% end %>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="grid gap-3">
|
|
32
|
+
<%= f.label :password_confirmation, class: "label" %>
|
|
33
|
+
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: "input" %>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="grid gap-3">
|
|
37
|
+
<%= f.label :current_password, class: "label" %>
|
|
38
|
+
<span class="text-sm text-muted-foreground">(we need your current password to confirm your changes)</span>
|
|
39
|
+
<%= f.password_field :current_password, autocomplete: "current-password", class: "input" %>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="grid gap-3">
|
|
43
|
+
<%= f.submit "Update", class: "btn" %>
|
|
44
|
+
</div>
|
|
45
|
+
<% end %>
|
|
46
|
+
</section>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="card mt-6">
|
|
50
|
+
<header>
|
|
51
|
+
<h3>Cancel my account</h3>
|
|
52
|
+
<p>Unhappy? You can delete your account below.</p>
|
|
53
|
+
</header>
|
|
54
|
+
<footer>
|
|
55
|
+
<%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete, class: "btn-outline" %>
|
|
56
|
+
</footer>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="mt-6">
|
|
60
|
+
<%= link_to "Back", :back, class: "btn-ghost" %>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
|
2
|
+
|
|
3
|
+
<div class="container mx-auto px-4 py-8">
|
|
4
|
+
<div class="max-w-2xl mx-auto">
|
|
5
|
+
<div class="card">
|
|
6
|
+
<header>
|
|
7
|
+
<h2>Sign up</h2>
|
|
8
|
+
<p>Create a new account to get started.</p>
|
|
9
|
+
</header>
|
|
10
|
+
<section class="space-y-4">
|
|
11
|
+
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: "grid gap-6" }) do |f| %>
|
|
12
|
+
<div class="grid gap-2">
|
|
13
|
+
<%= f.label :email, class: "label" %>
|
|
14
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: "input" %>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="grid gap-2">
|
|
18
|
+
<%= f.label :password, class: "label" %>
|
|
19
|
+
<% if @minimum_password_length %>
|
|
20
|
+
<span class="text-sm text-muted-foreground">(<%= @minimum_password_length %> characters minimum)</span>
|
|
21
|
+
<% end %>
|
|
22
|
+
<%= f.password_field :password, autocomplete: "new-password", class: "input" %>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="grid gap-2">
|
|
26
|
+
<%= f.label :password_confirmation, class: "label" %>
|
|
27
|
+
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: "input" %>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="grid gap-3">
|
|
31
|
+
<%= f.submit "Sign up", class: "btn" %>
|
|
32
|
+
</div>
|
|
33
|
+
<% end %>
|
|
34
|
+
</section>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="mt-6">
|
|
37
|
+
<%= render "devise/shared/links" %>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<div class="container mx-auto px-4 py-8">
|
|
2
|
+
<div class="max-w-2xl mx-auto">
|
|
3
|
+
<div class="card">
|
|
4
|
+
<header>
|
|
5
|
+
<h2>Log in</h2>
|
|
6
|
+
<p>Sign in to your account to continue.</p>
|
|
7
|
+
</header>
|
|
8
|
+
<section class="space-y-4">
|
|
9
|
+
<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "grid gap-6" }) do |f| %>
|
|
10
|
+
<div class="grid gap-3">
|
|
11
|
+
<%= f.label :email, class: "label" %>
|
|
12
|
+
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: "input" %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="grid gap-2">
|
|
16
|
+
<%= f.label :password, class: "label" %>
|
|
17
|
+
<%= f.password_field :password, autocomplete: "current-password", class: "input" %>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<% if devise_mapping.rememberable? %>
|
|
21
|
+
<div class="grid gap-2">
|
|
22
|
+
<%= f.label :remember_me, class: "label" do |builder| %>
|
|
23
|
+
<%= f.check_box :remember_me, class: "input", role: "switch" %>
|
|
24
|
+
<%= builder.translation %>
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
28
|
+
<div class="grid gap-2">
|
|
29
|
+
<%= f.submit "Log in", class: "btn" %>
|
|
30
|
+
</div>
|
|
31
|
+
<% end %>
|
|
32
|
+
</section>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="mt-6">
|
|
35
|
+
<%= render "devise/shared/links" %>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<% if resource.errors.any? %>
|
|
2
|
+
<div class="alert-destructive max-w-2xl mx-auto" data-turbo-cache="false">
|
|
3
|
+
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
4
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
|
|
5
|
+
</svg>
|
|
6
|
+
<h2><%= pluralize(resource.errors.count, "error") %> prohibited this <%= resource.class.model_name.human.downcase %> from being saved</h2>
|
|
7
|
+
<section>
|
|
8
|
+
<ul>
|
|
9
|
+
<% resource.errors.full_messages.each do |message| %>
|
|
10
|
+
<li><%= message %></li>
|
|
11
|
+
<% end %>
|
|
12
|
+
</ul>
|
|
13
|
+
</section>
|
|
14
|
+
</div>
|
|
15
|
+
<% end %>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<div class="flex flex-col gap-2 text-sm">
|
|
2
|
+
<%- if controller_name != 'sessions' %>
|
|
3
|
+
<%= link_to "Log in", new_session_path(resource_name), class: "btn-ghost" %>
|
|
4
|
+
<% end %>
|
|
5
|
+
|
|
6
|
+
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
|
7
|
+
<%= link_to "Sign up", new_registration_path(resource_name), class: "btn-ghost" %>
|
|
8
|
+
<% end %>
|
|
9
|
+
|
|
10
|
+
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
|
|
11
|
+
<%= link_to "Forgot your password?", new_password_path(resource_name), class: "btn-ghost" %>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
|
15
|
+
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: "btn-ghost" %>
|
|
16
|
+
<% end %>
|
|
17
|
+
|
|
18
|
+
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
|
19
|
+
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: "btn-ghost" %>
|
|
20
|
+
<% end %>
|
|
21
|
+
|
|
22
|
+
<%- if devise_mapping.omniauthable? %>
|
|
23
|
+
<%- resource_class.omniauth_providers.each do |provider| %>
|
|
24
|
+
<%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: "btn-outline" %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|