As part of the re-write of The Developer Advocacy Handbook I needed to have blockquotes
with different classes.
With GitHub Pages markdown you can do that using the > notation:
> **Fact:** There are no bad students or a bad audience --
only bad workshops and talks. Your mood, dedication and
enthusiasm do become those of the audience --
if you are not happy, they won\'t be happy.
The problem was that I couldn't add CSS classes to the blockquote
elements so I can show them in different styles. I wanted four of them: example, fact, warning and tip.
The good news is that even without any styling using the strong
name should make it obvious. But as there is no text content selector in CSS I couldn't rely on that to change the blockquote
element.
First solution: JavaScript
The first thing I thought was to use JavaScript to apply the classes, which is pretty straight forward:
let bqs = document.querySelectorAll('blockquote');
bqs.forEach(b => {
b.className = b.
querySelector('strong').
innerText.
toLowerCase().
replace(':','');
});
This, however, felt dirty and I wanted to use the system itself to do that task.
Moving to liquid
So I wrote a liquid include to convert the HTML before rendering. In my layout template, this works by replacing the {{ content }}
with {% include blockquotes.html html=content %}
.
In the blockquotes.html
, I thought it'd be easy to do a search and replace. Alas, there is the issue that liquid only does string replacement and doesn't know any regular expressions.
The HTML generated from the markdown has a linebreak in it:
<blockquote>
<p><strong>Fact:</strong> There are no bad students … </p>
</blockquote>
This is where it didn't get fun. The replace filter doesn't allow you to concatenate strings and doesn't know the concept of \n
. So, I tried to use newline_to_br
together with strip_newlines
and then replace the <br />
but it was messy.
Turns out, the main trick was to capture a newline in liquid and assemble the string to replace using that one.
{% capture newline %}
{% endcapture %}
{% capture tip %}<blockquote>{{newline}} <p><strong>Tip:</strong>{% endcapture%}
{% capture example %}<blockquote>{{newline}} <p><strong>Example:</strong>{% endcapture%}
{% capture warning %}<blockquote>{{newline}} <p><strong>Warning:</strong>{% endcapture%}
{% capture fact %}<blockquote>{{newline}} <p><strong>Fact:</strong>{% endcapture%}
{% assign newhtml = include.html |
replace: tip, '<blockquote class="tip"><p><strong>Tip:</strong>' |
replace: example, '<blockquote class="example"><p><strong>Example:</strong>' |
replace: warning, '<blockquote class="warning"><p><strong>Warning:</strong>' |
replace: fact, '<blockquote class="fact"><p><strong>Fact:</strong>'
%}
{{ newhtml }}
This works fine. Seems superfluous, but it is a way. It might be that there is a much simpler way as I am new to this world, having used PHP before the build the old version of the book. Got a better option? Tell me :)