- my solution to tagcloud
- from Thi
- Useful links
- Using docker to run/deploy jekyll
- Install and run Jekyll on fresh machine
- Make jekyll build faster
- Sitemap
- Loop through posts
- Using markdown syntax inside html tags
- Check version
- Link to posts
- Custom domain & repository with Jekyll sites
- Using custom plugins?
- Using
_data
withinclude
- Create a custom tags/blocks
- Run with draft
- Serve in background
- Using markdown syntax inside a HTML tag/block
- Add search with lunrjs
- tagcloud
my solution to tagcloud
from Thi
This note is used for you who have already had the basic idea about jekyll and how to create a jekyll site. This note is only for quick reference.
Useful links
- Jemoji cheat sheet.
- Link to post / page.
- Jekyll cheat sheet.
- Rouge CSS file theme (Pygment)
- Compress HTML in Jekyll.
- Kramdown quickref.
- Official dependencies / gems supported by Github Pages.
Using docker to run/deploy jekyll
Read this readme. An example is an old version of this site.
Install and run Jekyll on fresh machine
MacOS
This tut is for macOS 11.0 Big Sur.
# install homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
brew --version # check version
# install rbenv to mange ruby versions
brew install rbenv ruby-build
# add rbenv to bash
echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.zshrc
source ~/.zshrc # refresh bash
# install ruby
rbenv install 3.0.0
rbenv global 3.0.0
# reload the terminal / sessions
ruby -v
# go to some jekyll source codes
install bundler
gem install bundler
# install gems
bundle config set --local path 'vendor/bundle'
bundle install
# serve
bundle exec jekyll serve
Ubuntu
::: hsbox Install rvm (ruby version manager) Check this main repo.
sudo apt-get install software-properties-common
sudo apt-add-repository -y ppa:rael-gc/rvm
sudo apt-get update
sudo apt-get install rvm
# add user to group
sudo usermod -a -G rvm thi
# Open terminal setting > tick on "Run command as a login shell"
# Reboot
# Enable local gemsets
rvm user gemsets
# install newest ruby
rvm install ruby
# use system
rvm use system
# use custom rvm
rvm use 3.0.0
# relaunch terminal
:::
::: col-2-equal
# install ruby using rvm
rvm install 3.0.0
rvm --default use 3.0.0
# install bundler
sudo gem install bundler
# clone a jekyll theme
# cd to that theme
# install gems in the theme
bundle install --path vendor/bundle
:::
# serve
bundle exec jekyll serve
# If error "ExecJS and could not find a JavaScript runtime"
sudo apt-get install nodejs
Windows
Follow this guide using WSL2 on Windows.
Make jekyll build faster
- Disable
jekyll-feed
- Run
bundle exec jekyll serve -I
(wuth-I
) to generate the changed file only. If you create a new file, open a new terminal tab and runbundle exec jekyll build
. - Upgrade to Jekyll 4.0.
- Add
gem "liquid-c"
toGemfile
and makebundle update
- Use
jekyll-include-cache
(both inGemfile
and_config.yml
)
Read more in this article.
Disable jekyll-feed
- Comment line
jekyll-feed
inGemfile
- Comment line
jekyll-feed
in_config.yml
- Rebuild.
Sitemap
If in sitemap, there is error like <loc>/reading</loc>
, check your _config.yml
+ make sure there is an url inside url
field.
Loop through posts
{% for post in site.posts %}
{{ post.title }}
{% endfor %}
::: warning
If you using baseurl
,
# in _config.yml
url: ""
baseurl: "/tools"
<ol>
{% for post in site.posts %}
<li>
<a href="{{ site.baseurl }}{{ post.url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ol>
:::
List all posts in each category,
{% for category in site.data.categories %}
{% if site.categories[category.name].size > 0 %}
{% for post in site.categories[category.name] %}
{{ post.title }}
{% endfor %}
{% endif %}
{% endfor %}
{% assign sortedPosts = site.posts | sort: 'title' %}
{% for post in sortedPosts %}
{{ post.title }}
{% endfor %}
List of categories and tags in a single line with commas,
{% for category in site.categories reversed %}{% capture category_name %}{{ category | first }}{% endcapture %}<a href="{{site.url}}{{site.baseurl}}/#{{category_name | replace: " ","_"}}">{{ category_name }}</a>{% if forloop.length > 1 and forloop.last != true %}, {% else %}.{% endif %}{% endfor %}
{% for tag in site.tags %}{% capture test %}{{tag[0] | slice: 0}}{% endcapture %}{% capture testup %}{{tag[0] | slice: 0 | upcase}}{% endcapture %}<a href="#{{tag[0] | slugify}}{% if test == testup %}_cap{% endif %}">{{tag[0]}}</a>{% if forloop.length > 1 and forloop.last != true %}, {% else %}.{% endif %}{% endfor %}
Edit tags for all posts
Read this source code.
Using markdown syntax inside html tags
You can use directly by
<span markdown="span"></span>
<div markdown="1"></div>
of only once,
{::options parse_block_html="true" /}
<!-- other html + markdown inside -->
Or even shorter,
Testing {::nomarkdown}**see**{:/} and test.
Check version
- Local gems:
gem list jekyll
. - Current jekyll version of website: check
Gemfile
. Need to runbundle update
if change any version in this file.
Link to posts
[Name of Link]({% post_url 2010-07-21-name-of-post %})
Edit this post on github (put below link in your post layout),
https://github.com/dinhanhthi/dinhanhthi.com/edit/master/{{path.path}}
Custom domain & repository with Jekyll sites
There are several choices for you to choose, it depends on your need.
You don’t have a custom domain
- Suppose your github account is
<username>
. - Create a repo
<username>.github.io
. - Put your site in branch
master
(default). - Your site is published at
https://<username>.github.io
If you wanna store your site in a custom repo, e.g. mysite
:
- Create a branch
gh-pages
+ set it as default + store your site here. - Remove content at
url:
in_config.yml
. - Your site is live at
https://<username>.github.io/mysite/
You have a custom domain
- Create file
CNAME
at root and put<customdomain>.com
in it. - Create
A
orCNAME
record in DNS provider. Check more. - You can also use netlify to set all things up automatically.
Using custom plugins?
- Build your site locally and get a folder
_site
. - Put it to github and see the results.
You can also use netlify
, it accepts custom plugin as well.
Using _data
with include
You can use,
{% include proud-of.html data=site.data.proudof-notes %}
where there is a data file located in _data/proudof-notes.yml
.
Create a custom tags/blocks
Refs
- Official Jekyll guid.
- How to create customizable Liquid tags in Jekyll by Sverrir Sigmundarson.
- Creating an Accordion Plugin for Jekyll by Mike Lui.
Tag with single parameter
Inside folder _plugins
, create a file thi_single_tag.rb
whose content is,
module Jekyll
class RenderTimeTag < Liquid::Tag
def initialize(tag_name, text, tokens)
super
@text = text
end
def render(context)
"#{@text} #{Time.now}"
end
end
end
Liquid::Template.register_tag('render_time', Jekyll::RenderTimeTag)
Tag with two parameters
Inside folder _plugins
, create a file thi_badge.rb
whose content is,
class Badge < Liquid::Tag
def initialize(tag_name, input, tokens)
super
@input = input
end
def render(context)
# Split the input variable (omitting error checking)
input_split = split_params(@input)
text = input_split[0].strip
color = input_split[1].strip
# Write the output HTML string
output = <<~EOS
<span class="tbadge badge-#{color}">#{text}</span>
EOS
# Render it on the page by returning it
return output;
end
def split_params(params)
params.split("|")
end
end
Liquid::Template.register_tag('badge', Badge)
Block with single parameter
For example, we wanna create a custom block alertbox
using class from Bootstrap.
Content
Inside folder _plugins
, create a file thi_alert.rb
whose content is,
module Jekyll
class Alertbox < Liquid::Block
def initialize(tag_name, input, liquid_options)
super
@input = input.strip
end
def render(context)
content = super
case @input
when "warning"
box_type = 'warning'
when "success"
box_type = 'success'
when "primary"
box_type = 'primary'
when "secondary"
box_type = 'secondary'
when "danger"
box_type = 'danger'
when "info"
box_type = 'info'
when "light"
box_type = 'light'
when "dark"
box_type = 'dark'
end
output = <<~EOS
<div class="alert alert-#{box_type}" markdown="1">
#{content}
</div>
EOS
end
end
end
Liquid::Template.register_tag('alertbox', Jekyll::AlertBox)
Nested blocks with crossed-using variables
A more complicated example, suppose that you wanna create a hide/show box using Bootstrap’s Collapse, you can use below shortcode. Its advantage is that you don’t have to put manually the id
for each box! Wonderful!
Inside folder _plugins
, create a file thi_hideshowbox.rb
whose content is,
module Jekyll
class HideShowBox < Liquid::Block
def initialize(tag_name, contain, tokens)
super
end
def generate_box_id(number)
charset = Array('A'..'Z') + Array('a'..'z')
Array.new(number) { charset.sample }.join
end
def render(context)
context.stack do
context["boxID"] = generate_box_id(20) # create the box's ID
@content = super
end
"<div class=\"hide-show-box\">#{@content}</div>"
end
end
class HSBtitle < Liquid::Tag
def initialize(tag_name, contain, tokens)
super
@title = contain
end
def render(context)
boxID = context["boxID"] # get the box's ID
output = <<~EOS
<button type="button" markdown="1" class="btn collapsed box-button" data-toggle="collapse" data-target="##{boxID}">#{@title}</button>
EOS
end
end
class HSBcontent < Liquid::Block
def initialize(tag_name, contain, tokens)
super
@showBox = contain.strip
end
def render(context)
boxID = context["boxID"] # get the box's ID
if @showBox == 'show'
classShow = 'show'
else
classShow = ''
end
output = <<~EOS
<div id="#{boxID}" markdown="1" class="collapse multi-collapse box-content #{classShow}">
#{super}
</div>
EOS
output
end
end
end
Liquid::Template.register_tag('hsbox', Jekyll::HideShowBox)
Liquid::Template.register_tag('hstitle', Jekyll::HSBtitle)
Liquid::Template.register_tag('hscontent', Jekyll::HSBcontent)
Actually, there is a simpler solution for this task. We can get
by using
module Jekyll
class HideShowBox < Liquid::Block
def initialize(tag_name, contain, tokens)
super
@input = contain
end
def generate_box_id(number)
charset = Array('A'..'Z') + Array('a'..'z')
Array.new(number) { charset.sample }.join
end
def render(context)
# Split the input variable (omitting error checking)
input_split = split_params(@input)
title = input_split[0]
boxid = generate_box_id(20)
if input_split[1] != nil
if input_split[1].strip == 'show'
showbox = "show"
else
showbox = ""
end
else
showbox = ""
end
content = super
output = <<~EOS
<div class="hide-show-box">
<button type="button" markdown="1" class="btn collapsed box-button" data-toggle="collapse" data-target="##{boxid}">
#{title}
</button>
<div id="#{boxid}" markdown="1" class="collapse multi-collapse box-content #{showbox}">
#{content}
</div>
</div>
EOS
end
def split_params(params)
params.split("|")
end
end
end
Liquid::Template.register_tag('hsbox', Jekyll::HideShowBox)
Problem with kramdown
Somtimes, we cannot use markdown="1"
directly in ruby file. For example, below block of code produces a block of codes (<pre>
) instead of a single text,
def initialize(tag_name, input, liquid_options)
super
@title = input
end
def render(context)
content = super
output = <<~EOS
<div class="def-box" id="dn1">
<div class="box-title" markdown="1">
#{@title}
</div>
<div class="box-content" markdown="1">
#{content}
</div>
</div>
EOS
end
Instead, we change a little bit like this,
<div class="box-title">
<span markdown="span">#{@title}</span>
</div>
Run with draft
Inside the root folder, create a folder named _drafts
. You can put your draft posts inside this folder and whenever you wanna show it in your site, use this command,
bundle exec jekyll serve --draft
In the case you have already build your site (all new posts are rendered to _site
), you only changes some small things in some post and you don’t want jekyll to render again all things on your site (just look at your current post), use this,
bundle exec jekyll serve -I
Serve in background
Using markdown syntax inside a HTML tag/block
For a block, we use markdown="1"
,
<div markdown="1">paragraph</div>
For a tag, we use markdown="span"
,
<mark markdown="span">text</span>
Add search with lunrjs
Download lunr.min.js and search.js and put them in root/js/
. The newest version of lunrjs given here but I’m not sur if it works with this technique or not.
Create a file search.html
in the root folder with content:
---
layout: page
title: Search on this page
---
<p class="p-intro">
<span id="search-process">{{re_loading}}</span> {{re_result}} <span id="search-query-container" style="display: none;">{{re_forkey}} "<strong id="search-query"></strong>"</span>
</p>
<ul id="search-results"></ul>
<script type="text/javascript">
window.data = {
{% for post in site.posts %}
{% if post.title %}
{% unless post.excluded_in_search %}
{% if added %},{% endif %}
{% assign added = false %}
"{{ post.url | slugify }}": {
"id": "{{ post.url | slugify }}",
"title": "{{ post.title | xml_escape }}",
"categories": "{{ post.categories | join: ", " | xml_escape }}",
"tags": "{{ post.tags | join: ", " | xml_escape }}",
"url": " {{ post.url | xml_escape }}",
"content": {{ post.content | strip_html | replace_regex: "[\s/\n]+"," " | strip | jsonify }}
}
{% assign added = true %}
{% endunless %}
{% endif %}
{% endfor %}
};
</script>
<script src="{{ site.baseurl }}/js/lunr.min.js"></script>
<script src="{{ site.baseurl }}/js/search.js"></script>
Note that, you can change some personal settings in the files search.js
and search.html
if you like.
Remark: if your site has so many posts, you can remove the last line ("content"....
) to ignore the content from the search. You can even add “keywords” (resplace for “content”) and put that “keywords” in the frontmatter, change also the term “content” in search.js
by “keywords”. That’s what I did on this site.