Tailwind, the CSS framework, the song…

Tailwind is a CSS framework created by Adam Wathan, and beloved by many. I’ve found it’s really helped me understand CSS grid in particular, and has made building responsive layouts really easy. It sometimes comes in for criticism because it is based on utility classes, meaning you mostly skip the ability to attach styles to elements via CSS selectors (a fundamental feature of CSS). However, when it’s used with a content framework that provides components (like Laravel’s Blade), they can effectively take on that role and prevent repetition. One of the consequences of using Tailwind is that you often end up with lots of classes in HTML class attributes.

Anyway, Tailwind is cool and I like it, so I decided to write a song about it, in the same vein as my previous effort for The Good Ship Laravel.

The arrangement in Logic Pro

It’s all about a hapless, design-challenged developer (could that possibly be me??) having trouble with their styling and layout, and thinking they should give this Tailwind thing a go as a way to help them solve it. They give Tailwind a try, it takes them a while to get to grips with it, but they finally figure it out and all is rosy.

The “I ain’t got no style; I got Tailwind” line was the first line that came to me, followed by “I got classes…”, giving me most of the chorus, but the verses took a while longer. I wrote the music for the chorus first, then worked backwards to make a verse that led into it nicely. There’s a break in the middle that seemed really obvious (“When my mode is getting dark…”), straight out of many other songs – there’s nothing revolutionary going on here!

I played the guitar parts for the chorus (which is a simple C, Am, G), and eventually found a sequence for the verse that worked well (C, F, Dm, G, then Csus2, G at the end). I wrote a very melodic bassline on keyboard. Logic Pro’s Drummer took care of the brush-style drums – I didn’t spend too much time on them. Unfortunately I then found I simply couldn’t play the chord changes in the verse smoothly enough, so I enlisted the help of musicalduo on Fiverr, who did a great job of it. He also played a really smooth version of the bass part, which I hadn’t asked him to do. So my guitar playing only appears in the chorus, and I need to practice more!

I don’t rate my singing (I would love to work with someone that can sing!), but Logic’s Flex Pitch editing works wonders. I also really like using it for vocal harmonies – figuring them out using Flex Pitch, then re-singing them, just as I did for The Good Ship Laravel. I had a cold for a couple of weeks and early versions sounded like I was holding my nose, so I re-recorded them when I was feeling less bunged up! I’ve discovered that you can get away with really bad backing vocals, so long as they are in tune!

I have some other, older songs I’ve not released, one about npm, one about being an open source maintainer, and a half-finished Whitney Houston-style belter about composer… PRs welcome!

Lyrics

[Verse]
I’m trying to build an app that looks good
It’s all taking much more time than it should
Classes and styles going ‘round in my head
turns out it’s not as easy as I originally said.

I’m finding my breakpoints, feeling defeated
and all this old stuff will have to be deleted
One thing is clear from all this confusion
I’ve had to come to an unfortunate conclusion

[Chorus]
No, I ain’t got no style;
I need tailwind
I got problems, maybe more than a few
I need tailwind
Oooooh, I ain’t got style;
I need tailwind
Not sure what I’m gonna do
I need tailwind

[Verse]
You might think I’m crazy, but I’m gonna read some docs
I’ve gotta figure out how to arrange all these blocks
It looks great on my Mac, but explodes on my phone
and judging by Stack Overflow, I’m not alone

I ask, “hey Adam, you got any ideas?”
He says, “yeah, get Tailwind to mop up those tears”
So I’m going with the flow, flexing my grid
trying to figure out what those tutorials did, but still,

[Chorus]
I ain’t got no style;
I’ll try tailwind
I got problems, maybe more than a few
I’ll try tailwind
Oooooh, I ain’t got style;
I’ll try tailwind
Not sure what I’m gonna do
I’ll try tailwind

[Middle]
When my mode is getting dark
and my layouts fall to bits
I keep trying all kinds of things
until suddenly everything clicks

[Verse]
My grid’s all cool unlike my previous wreck
I don’t have to keep my units in check
I love my pretty colours, my text is so clean
I hate to think of what it might have been, but now 

I’m slicing up my blade into little tiny pieces
It’s the moment for components, it’s all utility
I’m loving how it works everywhere, especially on my phone
Tailwind’s really in several classes of its own

[Chorus]
No, I ain’t got no style;
I got tailwind
I got classes, maybe more than a few
I got tailwind
Oooooh, I ain’t got style;
I got tailwind
Maybe you’d like to try it too
We got tailwind

[Outro]
Oooooh, I ain’t got style;
I got tailwind
Oooooh, I ain’t got style;
I got tailwind

Bridging Laravel Scout to Eloquent

Laravel Scout provides an interface to external search engines such as Algolia and Meilisearch. These are typically remote indexes of the same data that you’re storing locally, but with far faster and more powerful searching and ranking capabilities. However, they have some limitations on how you can express the search itself (allowing only a single string value), and what you can do with the search result (because it comes back as a Laravel Collection and not a Query Builder). This makes it difficult to do things like perform a complex search remotely, and then filter the result further via Eloquent operations, perhaps involving different parts of your database. A typical Scout search might be:

use App\Models\Order;
$orders = Order::search('Star Trek')->get();Code language: PHP (php)

This gives us a bunch of Order instances, but we had no opportunity to ask it to do things like load relations or filter the results while it was doing it.

Fortunately it’s not difficult to bridge these two worlds. The resulting Collection contains model instances, so we can extract their IDs and use them to construct an Eloquent search that selects the same records, but locally this time (Scout already did the heavy lifting of figuring out which ones we wanted):

$builder = Order::query()->whereIn('id', $orders->keys());Code language: PHP (php)

This isn’t ideal (because it will fetch those records a second time), but it will be reasonably efficient because the IDs it searches on are exact matches for primary keys in the database.

We now have a builder that will select the same records as the Scout search did, but we can continue adding to it before requesting the final results.

$result = $builder->where('orders.name', 'like', 'a%')
    ->with(['orderItems', 'customer'])
    ->get();Code language: PHP (php)

So that’s how we can get to use Eloquent features on top of a Scout search.


After finding out that this bridging wasn’t built-in, I submitted a PR to add it, but sadly it was rejected. With the PR code in place, the syntax would have looked like this:

use App\Models\Order;
$orders = Order::search('Star Trek')
    ->toEloquent()
    ->where('orders.name', 'like', 'a%')
    ->with(['orderItems', 'customer'])
    ->get();Code language: PHP (php)

To be fair, this isn’t much of a saving in the external syntax, but it is more efficient because it can get the record IDs directly from Scout without having to load the models from the database. I don’t think that efficiency gain can be obtained from outside Scout’s own code.

I hope that helps someone!