Garden-mower is a simple clojure based CSS preprocessor that emulates @apply from PostCSS, as used by tailwindcss. It merges specific selector attributes from a css document, and outputs data that can be digested by https://github.com/noprompt/garden.
Add garden-mower to your dependencies. With tools.deps:
{:deps {com.tristanstraub/garden-mower {:git/url "https://github.com/tristanstraub/garden-mower"
:sha "c8af31358ae1da496c18d3c9d2a35d049611d5f8"}}}
- tailwindcss examples/tailwind
I want to use tailwindcss, but I want to keep my tooling within clojure. I need to be able to create custom class selectors which combine the attributes of specified tailwindcss classes.
I want to run the following, where the keyword arguments passed to garden-mower.core/attributes designate tailwindcss css classes:
(garden.core/css
[[:.card-container (garden-mower.core/attributes css :.flex :.mx-auto :.flex-col :.sm:flex-row)]
[:.card-outer (garden-mower.core/attributes css :.max-w-sm :.w-full :.sm:max-w-full :.lg:flex :.mb-1 :.mx-auto :.sm:mx-1)]])
to produce roughly the following CSS:
.card-container {
display: flex;
margin-left: auto;
margin-right: auto;
flex-direction: column;
}
@media (min-width: 640px) {
.card-container {
flex-direction: row;
}
}
.card-outer {
max-width: 24rem;
width: 100%;
}
@media (min-width: 640px) {
.card-outer {
max-width: 100%;
}
}
@media (min-width: 1024px) {
.card-outer {
display: flex;
}
}
.card-outer {
margin-bottom: 0.25rem;
margin-left: auto;
margin-right: auto;
}
@media (min-width: 640px) {
.card-outer {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
}
garden-mower.core/attributes walks a css document and extracts the attributes that match the selector(s), and converts them into a form that can be digested by https://github.com/noprompt/garden.
Currently, the fetched selectors must be simple single elements, but the result of garden-mower.core/attributes can be embedded within any selector block being delivered to garden.core/css (in my experience!).
Because garden supports nested media queries (so good!), media queries of the selectors are preserved. The following example demonstrates this:
(def css "
@media (min-width: 640px) {
.blue { color: rgba(0,0,255,1); }
}
.bg-red { background-color: rgba(255,0,0,1); }")
(garden.core/css [[:.btn (garden-mower.core/attributes css :.blue :.bg-red)]
[:.btn-red (garden-mower.core/attributes css :.bg-red)]])
which produces:
@media (min-width: 640px) {
.btn {
color: rgba(0, 0, 255, 1);
}
}
.btn {
background-color: rgba(255, 0, 0, 1);
}
.btn-red {
background-color: rgba(255, 0, 0, 1);
}
Some selectors in tailwind contain forward slashes. Since keyword literals in clojure cannot contain backslashes, use a string instead:
(garden.core/css [[:.btn (garden-mower.core/attributes css ".xl:w-1/5")]])
The CSS output is not optimised and sometimes has too much whitespace. There is room for improvement.
Try using https://github.com/tristanstraub/docker-tailwindcss to generate custom tailwindcss css files, which can be fed into garden-mower.
Modify resources/public/index.html to include the newly created css files:
- tailwind-base.css
- tailwind-component.css
and remove:
- tailwind.min.css
Use tailwind-utilities.css with garden-mower to generate your CSS, but don’t include it in index.html.
The tests can be run with:
clj -A:test