playframework - Styling the login
Bulma
I want to use Bulma for styling for now. This is simply because I’m lazy to do all the CSS. Why Bulma? - I didn’t put a lot of thought into this, I just needed something that can do the CSS for me.
Adding bulma classes
From the Bulma docs, I wanted to reproduce this form:
<div class="field">
<p class="control has-icons-left has-icons-right">
<input class="input" type="email" placeholder="Email">
<span class="icon is-small is-left">
<i class="fas fa-envelope"></i>
</span>
<span class="icon is-small is-right">
<i class="fas fa-check"></i>
</span>
</p>
</div>
<div class="field">
<p class="control has-icons-left">
<input class="input" type="password" placeholder="Password">
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
</p>
</div>
<div class="field">
<p class="control">
<button class="button is-success">
Login</button>
</p>
</div>
This needed a few things:
- Add Bulma
- Add fontawesome icons
- Add the required wrappers and classed to the playframework form fields
The first 2 items were each, I just downloaded the CSS files for Bulma and
fontawesome and just added them to the public/stylesheets
directory.
❯ exa -RTL 2 public
public
├── images
│ ├── favicon.png
│ └── website-bg.jpg
├── javascripts
│ └── main.js
└── stylesheets
├── fontawesome
├── bulma.min.css
├── main.css
└── website
I then link these in the website base template:
<!DOCTYPE html>
<html lang="en">
<head>
...<link rel="stylesheet" type="text/css" media="all" href="@routes.Assets.versioned("stylesheets/bulma.min.css")"/>
<link rel="stylesheet" type="text/css" media="all" href="@routes.Assets.versioned("stylesheets/fontawesome/css/fontawesome.css")"/>
<link rel="stylesheet" type="text/css" media="all" href="@routes.Assets.versioned("stylesheets/fontawesome/css/brands.css")"/>
<link rel="stylesheet" type="text/css" media="all" href="@routes.Assets.versioned("stylesheets/fontawesome/css/solid.css")"/>
...<style>
...
Now on to the last thing.
Custom field constructor
I followed the playframework docs on custom field constructors for this.
Firstly, needed to add an template (authentication/templates/fields.scala.html
)
for the fields
@(elements: helper.FieldElements)
<div class="field @if(elements.hasErrors) {error}">
<label for="@elements.id" class="label">@elements.label</label>
<div class="control">
@elements.input</div>
<span class="errors">@elements.errors.mkString(", ")</span>
<span class="help">@elements.infos.mkString(", ")</span>
</div>
This just adds the label.class
(a label with a class=“label”) on the label tag and wraps the input with a
div.control
(a div with class=“control”, should find where I got this syntax from).
It seems playframework doesn’t allow changing the input here to add the rest of
the Bulma classes.
I then added an object that
package authentication
object Fields {
import views.html.helper.FieldConstructor
implicit val myFields: FieldConstructor = FieldConstructor(
.templates.html.fields.f
authentication)
}
I also needed to change the folder that contains the authentication views from
views
to templates
because metals kept warning that html.helper.FieldConstructor
is not part of “authentication.views.html”.
This is probably because I changed the layout playframework expects.
I then add an import of the template to the authentication/templates/loginForm.
:
@import authentication.Fields._
and the file looks like:
@import authentication.Fields._
@(form: Form[authentication.models.User], postUrl: Call)(implicit request: MessagesRequestHeader)
@request.flash.data.map{ case (name, value) =><div>@name: @value</div>
}
@* Global errors are not tied to any particular form field *@
@if(form.hasGlobalErrors) {
@form.globalErrors.map { (error: FormError) =><div>
Error: @error.key: @error.message</div>
}
}
@helper.form(postUrl, Symbol("id") -> "user-login-form") {
@helper.CSRF.formField
@helper.input(
form("username"),
Symbol("_label") -> "Username",
Symbol("placeholder") -> "username",
Symbol("id") -> "username",
Symbol("size") -> 60
) { (id, name, value, args) =><p class="control has-icons-left has-icons-right">
<input class="input" type="text" name="@name" id="@id" @toHtmlArgs(args)>
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>
<span class="icon is-small is-right">
<i class="fas fa-check"></i>
</span>
</p>
}
@helper.input(
form("password"),
Symbol("_label") -> "Password",
Symbol("placeholder") -> "password",
Symbol("id") -> "password",
Symbol("size") -> 60
) { (id, name, value, args) =><p class="control has-icons-left">
<input class="input" type="password" name="@name" id="@id" @toHtmlArgs(args)>
<span class="icon is-small is-left">
<i class="fas fa-lock"></i>
</span>
</p>
}
<div class="field">
<p class="control">
<button class="button is-success">
Login</button>
</p>
</div>
}
Here, instead of using the playframework helpers @helper.inputText
and
@helper.inputPassword
, I use the @helper.input
and set the input types
myself. This allows me to add the rest of the classes I need for Bulma.
This now gives me a loginForm template which I can now use in the website
login.scala.html
as follows:
@import authentication.templates.html._
@(form: Form[authentication.models.User], postUrl: Call)(implicit request: MessagesRequestHeader)
@base("- login") {<div id="content">
<div id="user-login-form">
@loginForm(form, postUrl)(request)</div>
</div>
}
and now I have a styled login page. Need to polish but looks good enough so far.
Next
Mandla