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 quickly reference.
- Rouge CSS file theme (Pygment)
- Official dependencies / gems supported by Github Pages.
Read this readme. An example is an old version of this site.
This tut is for macOS 11.0 Big Sur.
1# install homebrew
2/bin/bash -c "$(curl -fsSL <https://raw.githubusercontent.com/Homebrew/install/master/install.sh>)"
3brew --version # check version
1# go to some jekyll source codes
2install bundler
3gem install bundler
4
5# install gems
6bundle config set --local path 'vendor/bundle'
7bundle install
8
9# serve
10bundle exec jekyll serve
1# install ruby using rvm
2rvm install 3.0.0
3rvm --default use 3.0.0
4
5# install bundler
6sudo gem install bundler
1# clone a jekyll theme
2# cd to that theme
3
4# install gems in the theme
5bundle install --path vendor/bundle
1# serve
2bundle exec jekyll serve
3
4# If error "ExecJS and could not find a JavaScript runtime"
5sudo apt-get install nodejs
Follow WSL 2 on Windows using WSL2 on Windows.
1# BENCHMARKING your site
2bundle exec jekyll build --profile
1# clean cache
2bundle exec jekyll clean
- Disable
jekyll-feed
- Run
bundle exec jekyll serve -I
(wuthI
) 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.
- Comment line
jekyll-feed
inGemfile
- Comment line
jekyll-feed
in_config.yml
- Rebuild.
If in sitemap, there is error like
<loc>/reading</loc>
, check your _config.yml
+ make sure there is an url inside url
field.1{% for post in site.posts %}
2 {{ post.title }}
3{% endfor %}
Warning
If you using
baseurl
1# in _config.yml
2url: ""
3baseurl: "/tools"
1<ol>
2 {% for post in site.posts %}
3 <li>
4 <a href="{{ site.baseurl }}{{ post.url }}">{{ post.title }}</a>
5 </li>
6 {% endfor %}
7</ol>
List all posts in each category,
1{% for category in site.data.categories %}
2 {% if site.categories[category.name].size > 0 %}
3 {% for post in site.categories[category.name] %}
4 {{ post.title }}
5 {% endfor %}
6 {% endif %}
7{% endfor %}
List all posts in ABC order (ref)
1{% assign sortedPosts = site.posts | sort: 'title' %}
2{% for post in sortedPosts %}
3 {{ post.title }}
4{% endfor %}
List of categories and tags in a single line with commas,
1{% for category in site.categories reversed %}
2 {% capture category_name %}
3 {{ category | first }}
4 {% endcapture %}
5 <a href="{{site.url}}{{site.baseurl}}/#{{category_name | replace: " ","_"}}">
6 {{ category_name }}
7 </a>
8 {% if forloop.length > 1 and forloop.last != true %}, {% else %}.{% endif %}
9{% endfor %}
1{% for tag in site.tags %}
2 {% capture test %}
3 {{tag[0] | slice: 0}}
4 {% endcapture %}
5 {% capture testup %}
6 {{tag[0] | slice: 0 | upcase}}
7 {% endcapture %}
8 <a href="#{{tag[0] | slugify}}{% if test == testup %}_cap{% endif %}">
9 {{tag[0]}}
10 </a>
11 {% if forloop.length > 1 and forloop.last != true %}, {% else %}.{% endif %}
12{% endfor %}
Read this source code.
You can use directly by
1<span markdown="span"></span>
2<div markdown="1"></div>
of only once,
1{::options parse_block_html="true" /}
2<!-- other html + markdown inside -->
Or even shorter,
1Testing {::nomarkdown}**see**{:/} and test.
- Local gems:
gem list jekyll
.
- Current jekyll version of website: check
Gemfile
. Need to runbundle update
if change any version in this file.
1[Name of Link]({% post_url 2010-07-21-name-of-post %})
Edit this post on github (put below link in your post layout),
1<https://github.com/dinhanhthi/dinhanhthi.com/edit/master/{{path.path}>}
There are several choices for you to choose, it depends on your need.
- 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/
- 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.
- 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.You can use,
1{% include proud-of.html data=site.data.proudof-notes %}
where there is a data file located in
_data/proudof-notes.yml
.- How to create customizable Liquid tags in Jekyll by Sverrir Sigmundarson.
- Creating an Accordion Plugin for Jekyll by Mike Lui.
1{% render_time page rendered at: %}
1page rendered at: Tue June 22 23:38:47 –0500 2010
Inside folder
_plugins
, create a file thi_single_tag.rb
whose content is,1module Jekyll
2 class RenderTimeTag < Liquid::Tag
3
4 def initialize(tag_name, text, tokens)
5 super
6 @text = text
7 end
8
9 def render(context)
10 "#{@text} #{Time.now}"
11 end
12 end
13end
14
15Liquid::Template.register_tag('render_time', Jekyll::RenderTimeTag)
1{% badge update | green %}
1<span class="tbadge badge-green">update</span>
Inside folder
_plugins
, create a file thi_badge.rb
whose content is,1class Badge < Liquid::Tag
2 def initialize(tag_name, input, tokens)
3 super
4 @input = input
5 end
6
7 def render(context)
8 # Split the input variable (omitting error checking)
9 input_split = split_params(@input)
10 text = input_split[0].strip
11 color = input_split[1].strip
12
13 # Write the output HTML string
14 output = <<~EOS
15 <span class="tbadge badge-#{color}">#{text}</span>
16 EOS
17
18 # Render it on the page by returning it
19 return output;
20 end
21
22 def split_params(params)
23 params.split("|")
24 end
25end
26Liquid::Template.register_tag('badge', Badge)
For example, we wanna create a custom block
alertbox
using class from Bootstrap.1{% alertbox warning %}
2 Content
3{% endalertbox %}
1<div class="alert alert-warning" role="alert" markdown="1">
2Content
3</div>
Inside folder
_plugins
, create a file thi_alert.rb
whose content is,1module Jekyll
2 class Alertbox < Liquid::Block
3 def initialize(tag_name, input, liquid_options)
4 super
5 @input = input.strip
6 end
7
8 def render(context)
9 content = super
10
11 case @input
12 when "warning"
13 box_type = 'warning'
14 when "success"
15 box_type = 'success'
16 when "primary"
17 box_type = 'primary'
18 when "secondary"
19 box_type = 'secondary'
20 when "danger"
21 box_type = 'danger'
22 when "info"
23 box_type = 'info'
24 when "light"
25 box_type = 'light'
26 when "dark"
27 box_type = 'dark'
28 end
29
30 output = <<~EOS
31 <div class="alert alert-#{box_type}" markdown="1">
32 #{content}
33 </div>
34 EOS
35 end
36 end
37end
38
39Liquid::Template.register_tag('alertbox', Jekyll::AlertBox)
A more complicated example, suppose that you wanna create a hide/show box{:.tbrown} 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!1{% hsbox %}
2 {% hstitle %}
3 Box's title
4 {% endhstitle %}
5
6 {% hscontent %}
7 Box's content.
8 {% endhscontent %}
9{% endhsbox %}
1<div class="hide-show-box">
2<button type="button" markdown="1" class="btn collapsed box-button" data-toggle="collapse" data-target="#box1ct">
3Box's title
4</button>
5<div id="box1ct" markdown="1" class="collapse multi-collapse box-content">
6Box's content.
7</div>
8</div>
Inside folder
_plugins
, create a file thi_hideshowbox.rb
whose content is,1module Jekyll
2 class HideShowBox < Liquid::Block
3
4 def initialize(tag_name, contain, tokens)
5 super
6 end
7
8 def generate_box_id(number)
9 charset = Array('A'..'Z') + Array('a'..'z')
10 Array.new(number) { charset.sample }.join
11 end
12
13 def render(context)
14 context.stack do
15 context["boxID"] = generate_box_id(20) # create the box's ID
16 @content = super
17 end
18 "<div class=\\"hide-show-box\\">#{@content}</div>"
19 end
20 end
21
22 class HSBtitle < Liquid::Tag
23 def initialize(tag_name, contain, tokens)
24 super
25 @title = contain
26 end
27
28 def render(context)
29 boxID = context["boxID"] # get the box's ID
30
31 output = <<~EOS
32 <button type="button" markdown="1" class="btn collapsed box-button" data-toggle="collapse" data-target="##{boxID}">#{@title}</button>
33 EOS
34 end
35 end
36
37 class HSBcontent < Liquid::Block
38 def initialize(tag_name, contain, tokens)
39 super
40 @showBox = contain.strip
41 end
42
43 def render(context)
44 boxID = context["boxID"] # get the box's ID
45 if @showBox == 'show'
46 classShow = 'show'
47 else
48 classShow = ''
49 end
50 output = <<~EOS
51 <div id="#{boxID}" markdown="1" class="collapse multi-collapse box-content #{classShow}">
52 #{super}
53 </div>
54 EOS
55
56 output
57 end
58 end
59end
60
61Liquid::Template.register_tag('hsbox', Jekyll::HideShowBox)
62Liquid::Template.register_tag('hstitle', Jekyll::HSBtitle)
63Liquid::Template.register_tag('hscontent', Jekyll::HSBcontent)
💡 Actually, there is a simpler solution for this task. We can get
1{% hsbox **Box's title** | show %}
2 Box's content.
3{% endhsbox %}
1<div class="hide-show-box">
2<button type="button" markdown="1" class="btn collapsed box-button" data-toggle="collapse" data-target="#something">
3<strong>Box's title</strong>
4</button>
5<div id="something" markdown="1" class="collapse multi-collapse box-content">
6Box's content.
7</div>
8</div>
by using
1module Jekyll
2 class HideShowBox < Liquid::Block
3
4 def initialize(tag_name, contain, tokens)
5 super
6 @input = contain
7 end
8
9 def generate_box_id(number)
10 charset = Array('A'..'Z') + Array('a'..'z')
11 Array.new(number) { charset.sample }.join
12 end
13
14 def render(context)
15 # Split the input variable (omitting error checking)
16 input_split = split_params(@input)
17 title = input_split[0]
18 boxid = generate_box_id(20)
19 if input_split[1] != nil
20 if input_split[1].strip == 'show'
21 showbox = "show"
22 else
23 showbox = ""
24 end
25 else
26 showbox = ""
27 end
28 content = super
29
30 output = <<~EOS
31 <div class="hide-show-box">
32 <button type="button" markdown="1" class="btn collapsed box-button" data-toggle="collapse" data-target="##{boxid}">
33 #{title}
34 </button>
35 <div id="#{boxid}" markdown="1" class="collapse multi-collapse box-content #{showbox}">
36 #{content}
37 </div>
38 </div>
39 EOS
40 end
41
42 def split_params(params)
43 params.split("|")
44 end
45 end
46end
47
48Liquid::Template.register_tag('hsbox', Jekyll::HideShowBox)
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,1def initialize(tag_name, input, liquid_options)
2 super
3 @title = input
4end
5
6def render(context)
7 content = super
8 output = <<~EOS
9 <div class="def-box" id="dn1">
10 <div class="box-title" markdown="1">
11 #{@title}
12 </div>
13 <div class="box-content" markdown="1">
14 #{content}
15 </div>
16 </div>
17 EOS
18end
Instead, we change a little bit like this,
1<div class="box-title">
2 <span markdown="span">#{@title}</span>
3</div>
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,1bundle 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,1bundle exec jekyll serve -I
1# start
2bundle exec jekyll serve 2>&1 &
3bundle exec jekyll serve -I 2>&1 &
1# stop
2# find jekyll server process
3ps -ef | grep jekyll
4# substitute pid# with process id
5kill -9 pid#
For a block, we use
markdown="1"
1<div markdown="1">paragraph</div>
For a tag, we use
markdown="span"
1<mark markdown="span">text</span>
Download [lunr.min.js]({{ site.baseurl }}/js/lunr.min.js) and [search.js]({{ site.baseurl }}/js/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:1---
2layout: page
3title: Search on this page
4---
5
6<p class="p-intro">
7 <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>
8</p>
9<ul id="search-results"></ul>
10
11<script type="text/javascript">
12 window.data = {
13 {% for post in site.posts %}
14 {% if post.title %}
15 {% unless post.excluded_in_search %}
16 {% if added %},{% endif %}
17 {% assign added = false %}
18 "{{ post.url | slugify }}": {
19 "id": "{{ post.url | slugify }}",
20 "title": "{{ post.title | xml_escape }}",
21 "categories": "{{ post.categories | join: ", " | xml_escape }}",
22 "tags": "{{ post.tags | join: ", " | xml_escape }}",
23 "url": " {{ post.url | xml_escape }}",
24 "content": {{ post.content | strip_html | replace_regex: "[\\s/\\n]+"," " | strip | jsonify }}
25 }
26 {% assign added = true %}
27 {% endunless %}
28 {% endif %}
29 {% endfor %}
30 };
31</script>
32<script src="{{ site.baseurl }}/js/lunr.min.js"></script>
33<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.