Skip to content

Commit a4cfabb

Browse files
committed
Auto nav generation added for just-the-docs
1 parent 677a425 commit a4cfabb

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

docs/_plugins/auto_nav.rb

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# _plugins/auto_nav.rb
2+
# ------------------------------------------------------------------
3+
# Just‑the‑Docs auto‑navigation generator
4+
#
5+
# Scans the site’s root (excluding _site, _config.yml, _data, _posts, etc.)
6+
# and builds a `navigation.yml` file in `_data/` that matches the folder
7+
# structure and uses the file title (first H1) or the filename as fallback.
8+
# ------------------------------------------------------------------
9+
module AutoNav
10+
class Generator < Jekyll::Generator
11+
safe true
12+
priority :low
13+
14+
# Called by Jekyll
15+
def generate(site)
16+
nav = []
17+
18+
Dir.glob('**/*', File::FNM_DOTMATCH).each do |path|
19+
next if skip_path?(path)
20+
21+
# Convert Windows backslashes to forward slashes
22+
path = path.tr('\\', '/')
23+
next unless File.extname(path) == '.md'
24+
25+
# Build a relative URL
26+
url = File.basename(path, '.md')
27+
url = '/' if url == 'index'
28+
url = File.join('/', File.dirname(path), url, '.html')
29+
url = url.gsub('//', '/')
30+
31+
# Grab the first H1 or fallback to filename
32+
title = extract_title(path) || File.basename(path, '.md').capitalize
33+
34+
# Build a hierarchical structure
35+
add_to_nav(nav, path, title, url)
36+
end
37+
38+
# Write the navigation file
39+
File.open('_data/navigation.yml', 'w') { |f| f.write(nav.to_yaml) }
40+
41+
Jekyll.logger.info "AutoNav:", "Generated navigation.yml with #{nav.size} top‑level items."
42+
end
43+
44+
private
45+
46+
def skip_path?(path)
47+
# Skip hidden files, Jekyll defaults, and directories that start with _
48+
File.directory?(path) || path.start_with?('_') || path =~ /\A\.{1,2}\z/
49+
end
50+
51+
# Return the first <h1> text from the markdown file
52+
def extract_title(md_path)
53+
content = File.read(md_path)
54+
# simple regex: line starting with # followed by space
55+
line = content.lines.find { |l| l.start_with?('# ') }
56+
line ? line.sub(/^# /, '').strip : nil
57+
end
58+
59+
# Insert item into the nav hierarchy
60+
def add_to_nav(nav, path, title, url)
61+
parts = path.split('/').reject { |p| p.start_with?('_') }
62+
parts.pop # drop .md extension
63+
parts.map! { |p| p.sub(/\.md$/, '') }
64+
current = nav
65+
66+
parts.each_with_index do |part, idx|
67+
item = current.find { |i| i['title'] == part }
68+
if item.nil?
69+
# new node
70+
item = { 'title' => part }
71+
item['sub_navigation'] = [] if idx < parts.size - 1
72+
current << item
73+
end
74+
current = item['sub_navigation'] if idx < parts.size - 1
75+
end
76+
77+
# Final leaf
78+
leaf = { 'title' => title, 'url' => url }
79+
current << leaf
80+
end
81+
end
82+
end

0 commit comments

Comments
 (0)