
กำลัง rebuild documentation site ด้วย Jekyll เนื่องจาก documentation pages ใหญ่ ต้องมี subnavigation เพิ่มจาก top-level navigation
โพสต์นี้ครอบคลุมทำ Jekyll plugin 簡單 generate subnav links จาก headings ใน posts หรือ pages
Overview
แยก project เป็น tasks:
- สร้าง Jekyll generator รันทุก page บน site
- สอน generator pre-render pages เพื่อ extract heading information
- 用 nokogiri parse HTML หา relevant headings และ content
- Render subnavigation
ในตัวอย่าง subnav links ทั้งหมดเป็น anchor links approach นี้ต้องการ markdown processor สร้าง IDs ให้ headings RedCarpet กับ option with_toc_data ใช้งานดี
Basic Jekyll Generator
มี plugin types หลาย種 สร้าง generator
Generators คือ classes inherit Jekyll::Generator มี method generate
Generators รันหลัง Jekyll load markdown files ทั้งหมด แต่ก่อน convert เป็น HTML object site ส่งเข้า generate method 用 site object เข้าถึง pages, posts, resources ทั้งหมด
ตัวอย่าง generator loop ทุก pages พิมพ์ titles:
class MySubnavGenerator < Jekyll::Generator
def generate(site)
site.pages.each do |page|
puts page.data["title"]
end
end
end
修改 page และ site data ใน generator ได้ data จาก front-matter และ site config
page.data["title"] += " - modified!"
site.data["tagline"]
Pre-Rendering Markdown to HTML
อยาก extract headings จาก markdown documents 简单方式: convert markdown เป็น HTML แล้ว parse HTML 用 nokogiri
Covert มากับ dirty? ใช่ จะช้า? แน่นอน แต่ Jekyll static site generator ไม่ต้องกังวล real-time performance แค่จมูกได้
用 Jekyll built-in markdown wrapper convert markdown pages ทุกตัวเป็น HTML:
class MySubnavGenerator < Jekyll::Generator
def generate(site)
parser = Jekyll::Converters::Markdown.new(site.config)
site.pages.each do |page|
if page.ext == ".md"
html = parser.convert(page['content'])
# Do something with the html here
end
end
end
end
Extracting Headings
Documentation site ใหม่ decide ทุก H2 tag ควรมี subnavigation link 用 nokogiri parse HTML แต่ละ page ดึง H2 tags ทุกตัว
ตอนนี้แค่ print H2 content และ ID หน้าจอ:
require "nokogiri"
class MySubnavGenerator < Jekyll::Generator
def generate(site)
parser = Jekyll::Converters::Markdown.new(site.config)
site.pages.each do |page|
if page.ext == ".md"
doc = Nokogiri::HTML(parser.convert(page['content']))
doc.css('h2').each do |heading|
puts "#{ heading.text }: #{ heading['id'] }"
end
end
end
end
end
Creating the Subnavigation Menu
ตอนมี headings text และ ID สร้าง list subnavigation links
เก็บ list links เป็น data attribute ของ page เอง เข้าถึง links จาก page template ได้
require "nokogiri"
class MySubnavGenerator < Jekyll::Generator
def generate(site)
parser = Jekyll::Converters::Markdown.new(site.config)
site.pages.each do |page|
if page.ext == ".md"
doc = Nokogiri::HTML(parser.convert(page['content']))
page.data["subnav"] = []
doc.css('h2').each do |heading|
page.data["subnav"] << { "title" => heading.text, "url" => [page.url, heading['id']].join("#") }
end
end
end
end
end
ตอนนี้ใน template loop subnav แสดงแต่ละ link:
{% for item in page.subnav %}
{{ item.title }}
{% endfor %}
Troubleshooting
เหมือนกล่าว ขึ้นกับ markdown processor สร้าง unique IDs ให้ headings markdown settings จาก _config.yml:
# Use the redcarpet Markdown renderer
markdown: redcarpet
redcarpet:
extensions: [ 'no_intra_emphasis', 'fenced_code_blocks', 'autolink', 'strikethrough', 'superscript', 'with_toc_data', 'tables', 'hardwrap' ]
Next Up...
Approach ข้างบน work ดีถ้าต้องการ one level subnavigation แตถ้าต้องการมากกว่า? เช่น H3 tags "inside" H2 สร้าง sub-subnavigation links ใน menu?
จะครอบคลุมใน future blog post stay tuned!