#3 Style your Hanami App with Bulma using Hanami Assets

I have this simple Hanami web application here, listing sample blog articles with cat's images on top. Honestly, It is horrible. Really. And my goal for this episode is to make it prettier with the least effort possible.

Unstyled articles listUnstyled articles list

To achieve this, I'll make use of Bulma CSS framework Which is a great, simple to use CSS-only framework, which means, it works with any JS engine you would like to use in your app. No matter if you use your custom scripts, jQuery, React, Angular or Vue, Bulma will allways work as you may expect and this is the main reason I've chosen it for this showcase.

Install Bulma in Hanami application

Let's integrate Bulma with our project first

Due to Hanami::Assets being fully configured in the new Hanami application, it's pretty easy to install any npm package and use it in our web apps.

In the getting started guide, You can see several ways to install it, and just for now we'll use the option to import the css directly from the CDN's official URL.

I just need to copy the source code and paste it in the slices/main/assets/public/index.css Index.css file for my main slice.

Then going back to the installation, I can see that in the code requirements section of the Bulma's documentation I also need to add viewport information into my applicaiton layout html file. Let me copy that very quickly.

# slices/main/assets/public/index.css

@import "https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css";

Also, as I'm already in the main application layout file, I'll add the section and container wrapper, as mentioned in the installation guide.

// slices/main/web/templates/layouts/application.html.slim

body
 section.section
  .container
    == yield

Then run npm start to run my assets server and when I check the browser, you can already see that my application looks a little bit better. You can notice it mainly by the font being changed together with its color.

Disclaimer: If you're using the Hanami 2 Template before the Hanami 2.0 is released, you may encounter a little configuration issue and assets can not be loaded due to the Headers misconfiguration. Here is a fix for that. Add the code below to the config/application.rb file.

# config/application.rb

config.actions.default_headers = {
  "X-Frame-Options" => "DENY",
  "X-Content-Type-Options" => "nosniff",
  "X-XSS-Protection" => "1; mode=block",
  "Content-Security-Policy" => \
    "base-uri 'self'; " \
    "child-src 'self'; " \
    "connect-src 'self'; " \
    "default-src 'none'; " \
    "font-src 'self'; " \
    "form-action 'self'; " \
    "frame-ancestors 'self'; " \
    "frame-src 'self'; " \
    "img-src 'self' https: data:; " \
    "media-src 'self'; " \
    "object-src 'none'; " \
    "script-src 'localhost'; " \
    "style-src * 'unsafe-inline'"
  }

Article's gridArticle's grid

Install Bulma with Hanami via NPM

Bulma is also shipped as an NPM package, so If you don't want to use CDN, thanks to Hanami::View you can easily install any NPM package into your hanami application using the standard package installation instructions.

In he terminal let me just install the bulma package

npm install bulma

and then in the index.css file just replace the CDN download link with the package path. In my case it's bulma/css/bulma

@import 'bulma/css/bulma'

When you'll visit the browser, you should not notice any changes in the rendered content.

Add Bulma grid to Hanami template

The margins had been changed too, however, this is still pretty bad. Let's update it by adding some grid. I want articles to be shown in rows of three elements. To achieve this, I'll iterate through my array of articles, using each_slice method, passing the expected number of columns as an argument.

Then at the beginning of an each slice I'll add a .columns wrapper, and then for each column in a row I'll add a .column class

// slices/main/web/templates/templates/articles/index.html.slim

h1.title Blog articles

- articles.each_slice(3) do |row|
  .columns
    - row.each do |article|
      .column
        == render :item, article: article

This finally gives a nice change to the rendered result. All articles are grouped in columns, and I did not write a single CSS line, everything being working out of the box. Awesome!

Bulma installedBulma installed

Adding Breadcrumbs

Bulma has a lot of predefined components ready to be used. I'll just add some breadcrumbs on top of my articles list just to demonstrate how to use them.

// slices/main/web/templates/blog/articles/index.html.slim

nav.breadcrumb aria-label="breadcrumbs"
  ul
    li
      a href="/" Home
    li.is-active
      a href='/articles' aria-current='page' articles

I'll need a navigation tag with breadcrumb class, with a list of items to be displayed. The last one I mark as active by adding a proper class to the list element and now let's see the result.

Breadcrumbs componentBreadcrumbs component

Now let's update the single article's item. For this, I'll use Bulma's card component and simliar to breadcrumbs, I just need to copy the HTML structure to my template file. To speed things up I'll just paste the content I've prepared before. This is a card component, translated to slim - as this is what I'm working with, and instead of static strings, I show the appropriate article's attributes.

// slices/main/web/templates/blog/articles/_item_.html.slim

.card
  .card-image
    figure.image.is-16by9
      img src=(article.thumbnail)
  .card-content
    .media
      .media-content
        h4.title.is-4 = article.title
        h6.subtitle.is-6
          == article.by
          time datetime==article.published_on
            = article.published_on
    .content
      = article.excerpt
      .buttons.is-right
        a.button.is-primary.mt-4.is-right href=("/articles/#{article.id}")
          | Read...

Cards componentCards component

With similar tweaks you can easily prettify the single article's page or anything you want in your application.

// slices/main/web/templates/blog/articles/show.html.slim

nav.breadcrumb aria-label="breadcrumbs"
  ul
    li
      a href="/" Home
    li
      a href='/articles' articles
    li.is-active
      a href='/articles/#{article.id}' aria-current='page' = article.id

article.container
  figure class="image is-16by9"
    img src=(article.thumbnail) alt="Placeholder image"

  div class="media"
    div class="media-content"
      p class="title is-4" = article.title
      p class="subtitle is-6"
        == article.by
        time datetime==article.published_on
          = article.published_on
  .content
    = article.content

Summary

Hanami-Assets is an amazing gem that allows to manage assets in any Ruby application. In Hanami 2,, with zero-configuration integration, it's just a pleasure to work with.

You can use it with Bulma, Fundation, React, Vue, or any other asset framework, as it's extremely flexible.

Special Thanks