forked from fedi/mastodon
Customizing devise views and controllers
This commit is contained in:
parent
7e93da3f8d
commit
6045b6cb18
BIN
app/assets/images/background-photo.jpg
Normal file
BIN
app/assets/images/background-photo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
|
@ -7,15 +7,73 @@ $darker-background-color: #e3dede;
|
||||||
$text-color: #333030;
|
$text-color: #333030;
|
||||||
$lighter-text-color: #8b8687;
|
$lighter-text-color: #8b8687;
|
||||||
|
|
||||||
@import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700,400italic");
|
@import url(https://fonts.googleapis.com/css?family=Roboto:400,500,400italic);
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Roboto+Mono);
|
||||||
@import "font-awesome-sprockets";
|
@import "font-awesome-sprockets";
|
||||||
@import "font-awesome";
|
@import "font-awesome";
|
||||||
|
|
||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Noto Sans', sans-serif;
|
line-height: 1;
|
||||||
background: $background-color image-url('background-pattern.png');
|
}
|
||||||
|
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
background: $background-color image-url('background-photo.jpeg');
|
||||||
|
background-size: cover;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
font-weight: 400;
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,19 +83,143 @@ body {
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.logo-container {
|
||||||
|
width: 400px;
|
||||||
|
margin: 100px auto;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 100px 0;
|
color: #fff;
|
||||||
|
font-size: 48px;
|
||||||
|
line-height: 48px;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
small {
|
||||||
|
display: block;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: $text-color;
|
font-weight: 400;
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mastodon-link {
|
.form-container {
|
||||||
color: $quaternary-color;
|
width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
.field {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text], input[type=email], input[type=password] {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 2px solid #9baec8;
|
||||||
|
padding: 7px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #fff;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
outline: 0;
|
||||||
|
|
||||||
|
&:invalid {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus:invalid {
|
||||||
|
border-bottom-color: #df405a;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:required:valid {
|
||||||
|
border-bottom-color: #79bd9a;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active, &:focus {
|
||||||
|
border-bottom-color: #2b90d9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field_with_error {
|
||||||
|
input[type=text], input[type=email], input[type=password] {
|
||||||
|
border-bottom-color: #df405a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
margin-top: 30px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #2b90d9;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
outline: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten(#2b90d9, 5%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active, &:focus {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
background-color: darken(#2b90d9, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-footer {
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #9baec8;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: bold;
|
|
||||||
|
&:hover {
|
||||||
|
color: #d9e1e8;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#error_explanation {
|
||||||
|
background: #282c37;
|
||||||
|
color: #9baec8;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px 10px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-left: 15px;
|
||||||
|
list-style: circle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-list {
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@import 'home';
|
@import 'home';
|
||||||
@import 'accounts';
|
@import 'accounts';
|
||||||
|
|
34
app/controllers/auth/passwords_controller.rb
Normal file
34
app/controllers/auth/passwords_controller.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
class Auth::PasswordsController < Devise::PasswordsController
|
||||||
|
layout 'auth'
|
||||||
|
|
||||||
|
# GET /resource/password/new
|
||||||
|
# def new
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
|
||||||
|
# POST /resource/password
|
||||||
|
# def create
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
|
||||||
|
# GET /resource/password/edit?reset_password_token=abcdef
|
||||||
|
# def edit
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
|
||||||
|
# PUT /resource/password
|
||||||
|
# def update
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
|
||||||
|
# protected
|
||||||
|
|
||||||
|
# def after_resetting_password_path_for(resource)
|
||||||
|
# super(resource)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# The path used after sending reset password instructions
|
||||||
|
# def after_sending_reset_password_instructions_path_for(resource_name)
|
||||||
|
# super(resource_name)
|
||||||
|
# end
|
||||||
|
end
|
22
app/controllers/auth/registrations_controller.rb
Normal file
22
app/controllers/auth/registrations_controller.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class Auth::RegistrationsController < Devise::RegistrationsController
|
||||||
|
layout 'auth'
|
||||||
|
|
||||||
|
before_filter :configure_sign_up_params, only: [:create]
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def build_resource(hash = nil)
|
||||||
|
super(hash)
|
||||||
|
self.resource.build_account if self.resource.account.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def configure_sign_up_params
|
||||||
|
devise_parameter_sanitizer.for(:sign_up) do |u|
|
||||||
|
u.permit(:email, :password, :password_confirmation, account_attributes: [:username])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_sign_up_path_for(resource)
|
||||||
|
account_path(resource.account)
|
||||||
|
end
|
||||||
|
end
|
27
app/controllers/auth/sessions_controller.rb
Normal file
27
app/controllers/auth/sessions_controller.rb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
class Auth::SessionsController < Devise::SessionsController
|
||||||
|
layout 'auth'
|
||||||
|
|
||||||
|
# before_filter :configure_sign_in_params, only: [:create]
|
||||||
|
|
||||||
|
# GET /resource/sign_in
|
||||||
|
# def new
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
|
||||||
|
# POST /resource/sign_in
|
||||||
|
# def create
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
|
||||||
|
# DELETE /resource/sign_out
|
||||||
|
# def destroy
|
||||||
|
# super
|
||||||
|
# end
|
||||||
|
|
||||||
|
# protected
|
||||||
|
|
||||||
|
# If you have extra params to permit, append them to the sanitizer.
|
||||||
|
# def configure_sign_in_params
|
||||||
|
# devise_parameter_sanitizer.for(:sign_in) << :attribute
|
||||||
|
# end
|
||||||
|
end
|
|
@ -1,6 +1,7 @@
|
||||||
class Account < ActiveRecord::Base
|
class Account < ActiveRecord::Base
|
||||||
# Local users
|
# Local users
|
||||||
has_one :user, inverse_of: :account
|
has_one :user, inverse_of: :account
|
||||||
|
validates :username, uniqueness: { scope: :domain }
|
||||||
|
|
||||||
# Avatar upload
|
# Avatar upload
|
||||||
attr_reader :avatar_remote_url
|
attr_reader :avatar_remote_url
|
||||||
|
|
|
@ -2,6 +2,7 @@ class User < ActiveRecord::Base
|
||||||
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
|
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :user
|
belongs_to :account, inverse_of: :user
|
||||||
|
accepts_nested_attributes_for :account
|
||||||
|
|
||||||
validates :account, presence: true
|
validates :account, presence: true
|
||||||
end
|
end
|
||||||
|
|
3
app/views/auth/mailer/password_change.html.erb
Normal file
3
app/views/auth/mailer/password_change.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<p>Hello <%= @resource.email %>!</p>
|
||||||
|
|
||||||
|
<p>We're contacting you to notify you that your password has been changed.</p>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<p>Hello <%= @resource.email %>!</p>
|
||||||
|
|
||||||
|
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
||||||
|
|
||||||
|
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
||||||
|
|
||||||
|
<p>If you didn't request this, please ignore this email.</p>
|
||||||
|
<p>Your password won't change until you access the link above and create a new one.</p>
|
25
app/views/auth/passwords/edit.html.erb
Normal file
25
app/views/auth/passwords/edit.html.erb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<h2>Change your password</h2>
|
||||||
|
|
||||||
|
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
|
||||||
|
<%= devise_error_messages! %>
|
||||||
|
<%= f.hidden_field :reset_password_token %>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<%= f.label :password, "New password" %><br />
|
||||||
|
<% if @minimum_password_length %>
|
||||||
|
<em>(<%= @minimum_password_length %> characters minimum)</em><br />
|
||||||
|
<% end %>
|
||||||
|
<%= f.password_field :password, autofocus: true, autocomplete: "off" %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<%= f.label :password_confirmation, "Confirm new password" %><br />
|
||||||
|
<%= f.password_field :password_confirmation, autocomplete: "off" %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<%= f.submit "Change my password" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= render "devise/shared/links" %>
|
9
app/views/auth/passwords/new.html.haml
Normal file
9
app/views/auth/passwords/new.html.haml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
|
||||||
|
= devise_error_messages!
|
||||||
|
|
||||||
|
.field
|
||||||
|
= f.email_field :email, autofocus: true, required: true, placeholder: 'E-mail address'
|
||||||
|
.actions
|
||||||
|
= f.button "Reset password", type: 'submit'
|
||||||
|
|
||||||
|
.form-footer= render "auth/shared/links"
|
11
app/views/auth/registrations/edit.html.haml
Normal file
11
app/views/auth/registrations/edit.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f|
|
||||||
|
= devise_error_messages!
|
||||||
|
|
||||||
|
.field
|
||||||
|
= f.password_field :password, autocomplete: "off", placeholder: 'New password'
|
||||||
|
.field
|
||||||
|
= f.password_field :password_confirmation, autocomplete: "off", placeholder: 'Confirm new password'
|
||||||
|
.field
|
||||||
|
= f.password_field :current_password, autocomplete: "off", placeholder: 'Current password'
|
||||||
|
.actions
|
||||||
|
= f.button "Save changes", type: 'submit'
|
17
app/views/auth/registrations/new.html.haml
Normal file
17
app/views/auth/registrations/new.html.haml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
|
||||||
|
= devise_error_messages!
|
||||||
|
|
||||||
|
= f.fields_for :account do |ff|
|
||||||
|
.field
|
||||||
|
= ff.text_field :username, autofocus: true, placeholder: 'Username', required: true
|
||||||
|
|
||||||
|
.field
|
||||||
|
= f.email_field :email, placeholder: 'E-mail address', required: true
|
||||||
|
.field
|
||||||
|
= f.password_field :password, autocomplete: "off", placeholder: 'Password', required: true
|
||||||
|
.field
|
||||||
|
= f.password_field :password_confirmation, autocomplete: "off", placeholder: 'Confirm password', required: true
|
||||||
|
.actions
|
||||||
|
= f.button "Sign up", type: 'submit'
|
||||||
|
|
||||||
|
.form-footer= render "auth/shared/links"
|
9
app/views/auth/sessions/new.html.haml
Normal file
9
app/views/auth/sessions/new.html.haml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
|
||||||
|
.field
|
||||||
|
= f.email_field :email, autofocus: true, placeholder: 'E-mail address', required: true
|
||||||
|
.field
|
||||||
|
= f.password_field :password, autocomplete: "off", placeholder: 'Password', required: true
|
||||||
|
.actions
|
||||||
|
= f.button "Log in", type: 'submit'
|
||||||
|
|
||||||
|
.form-footer= render "auth/shared/links"
|
19
app/views/auth/shared/_links.html.haml
Normal file
19
app/views/auth/shared/_links.html.haml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
%ul.no-list
|
||||||
|
- if controller_name != 'sessions'
|
||||||
|
%li= link_to "Log in", new_session_path(resource_name)
|
||||||
|
|
||||||
|
- if devise_mapping.registerable? && controller_name != 'registrations'
|
||||||
|
%li= link_to "Sign up", new_registration_path(resource_name)
|
||||||
|
|
||||||
|
- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'
|
||||||
|
%li= link_to "Forgot your password?", new_password_path(resource_name)
|
||||||
|
|
||||||
|
- if devise_mapping.confirmable? && controller_name != 'confirmations'
|
||||||
|
%li= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name)
|
||||||
|
|
||||||
|
- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks'
|
||||||
|
%li= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name)
|
||||||
|
|
||||||
|
- if devise_mapping.omniauthable?
|
||||||
|
- resource_class.omniauth_providers.each do |provider|
|
||||||
|
%li= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider)
|
|
@ -1 +1,3 @@
|
||||||
Mastodon
|
Mastodon
|
||||||
|
|
||||||
|
= link_to 'Logout', destroy_user_session_path, method: :delete
|
||||||
|
|
|
@ -9,7 +9,4 @@
|
||||||
= yield :header_tags
|
= yield :header_tags
|
||||||
%body
|
%body
|
||||||
.container
|
.container
|
||||||
= yield
|
= content_for?(:content) ? yield(:content) : yield
|
||||||
.footer
|
|
||||||
Powered by
|
|
||||||
= link_to 'Mastodon', 'https://github.com/Gargron/mastodon', class: 'mastodon-link'
|
|
||||||
|
|
10
app/views/layouts/auth.html.haml
Normal file
10
app/views/layouts/auth.html.haml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
- content_for :content do
|
||||||
|
.logo-container
|
||||||
|
%h1
|
||||||
|
Mastodon
|
||||||
|
%small= Rails.configuration.x.local_domain
|
||||||
|
|
||||||
|
.form-container
|
||||||
|
= yield
|
||||||
|
|
||||||
|
= render template: "layouts/application"
|
|
@ -2,7 +2,11 @@ Rails.application.routes.draw do
|
||||||
get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta
|
get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta
|
||||||
get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger
|
get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger
|
||||||
|
|
||||||
devise_for :users, path: 'auth'
|
devise_for :users, path: 'auth', controllers: {
|
||||||
|
sessions: 'auth/sessions',
|
||||||
|
registrations: 'auth/registrations',
|
||||||
|
passwords: 'auth/passwords'
|
||||||
|
}
|
||||||
|
|
||||||
resources :accounts, path: 'users', only: [:show], param: :username do
|
resources :accounts, path: 'users', only: [:show], param: :username do
|
||||||
resources :stream_entries, path: 'updates', only: [:show]
|
resources :stream_entries, path: 'updates', only: [:show]
|
||||||
|
|
Loading…
Reference in a new issue