Styling + The Final Day

Jul 26, 2020


What I did today

I started off by trying to figure out how to deploy Pomato to Vercel. Adrien had done something similar with his ”Hail the Wheel” app so I asked him how he’d deployed it.

It turned out to be pretty easy. All I had to do was use the vercel CLI to deploy the resources/public folder of the app after building the production bundle.

Here’s the basic structure of a re-frame app built using the lein re-frame template.

├── README.md
├── dev
│   └── cljs
│       └── user.cljs
├── karma.conf.js
├── package-lock.json
├── package.json
├── project.clj
├── resources
│   └── public
│       ├── index.html
│       └── js
├── shadow-cljs.edn
├── src
│   ├── clj
│   └── cljs
│       ├── deps.cljs
│       └── pomato
└── target
    ├── classes
    │   └── META-INF
    └── stale
        └── leiningen.core.classpath.extract-native-dependencies

The src folder holds the source of the project and the resources/public has the production build for the project. When we create a new project using the vercel CLI, we can mention this folder as the output folder to serve and Vercel will serve it.

You can now check out this app here - https://pomato.vercel.app

It’s honestly very cool how easy Vercel has made this process. I’ve used them before back when they were Zeit for some personal projects and the experience has only gotten better over time.

Using Stylefy

Since Athens uses Stylefy internally, I wanted to use it too for building my app. So what is it -

stylefy makes it possible to define CSS styles as Clojure data and attach them into HTML elements easily without writing selectors. Styles are converted to CSS on-demand and scoped locally. This makes writing style code easy and maintainable.

Building some styles and using them are incredibly easy. I created a new file called styles.cljs to hold all the styles. I also called stylefy/init with the use-caching? option set to false since we want our styles to be refreshed on every change (we will change this when the app is finalized). An Example style for our main div would be -

(def app-style {:display "flex"
                :flex-direction "column"
                :align-items "center"})

We can then call it in our views.cljs file -

(defn main-panel []
  [:div (use-style styles/app-style)
   [:h1 "Pomato Timer"]

And boom, Pomato now uses Flex styling! Stylefy lets you declare your CSS styles per-component or per-hierarchy as a Clojure variable and call it in your Hiccup component. There’s definitely a very “Styled Components” vibe to Stylefy which is a good thing. Since the style is just a Clojure map, we can also do fun Clojure map things to it, like merging. This is an easy way to combine style map together.


I wanted to finish today off strong by completing a couple of 4Clojure problems -

  1. Intro to Trampoline

The trampoline function takes a function f and a variable number of parameters. Trampoline calls f with any parameters that were supplied. If f returns a function, trampoline calls that function with no arguments. This is repeated, until the return value is not a function, and then trampoline returns that non-function value. This is useful for implementing mutually recursive algorithms in a way that won’t consume the stack.

  [(foo [x y] #(bar (conj x y) y))
     [x y]
     (if (> (last x) 10)
       #(foo x (+ 2 y))))]
  (trampoline foo [] 1))
;; => [1 3 5 7 9 11]
  1. intoCamelCase

When working with java, you often need to create an object with fieldsLikeThis, but you’d rather work with a hashmap that has :keys-like-this until it’s time to convert. Write a function which takes lower-case hyphen-separated strings and converts them to camel-case strings.

(defn intoCamelCase
  (let [spl (clojure.string/split s #"-")]
    (clojure.string/join (cons (first spl) (map clojure.string/capitalize (rest spl))))))


I still can’t believe ClojureFam is coming to an end. I feel like I’ve grown close with my fellow Team Seneca members, Adrien and nthd3gr33. We’ve come together to work on a lot of Athens issues and Clojure problems. Having some people who are also going through the same experience was definitely quite helpful on my own journey.

Although the 5 weeks of ClojureFam are at an end, I don’t think this is going to be the end of my Learn In Public journey. I think I have a lot more intrinsic motivation to keep working on Clojure and open source projects in general and document my journey in public. It’s both a form of holding myself accountable and of broadcasting what I’m doing to the world.

I still have to spend some time putting together a comprehensive account of my experience over the past month. It will probably be a mini-essay (no one can accuse me of brevity) and I do have some thoughts on what I would have done differently, and improvements that can be made to the ClojureFam program itself.

All said and done, I really want to thank the Athens team for bringing this ClojureFam program out into the world and for helping new Clojure programmers like myself find a welcoming community to join and learn with. This really has been quite fun.

The Final Tally of what I’ve done with ClojureFam -