Module: Jekyll::VitePressTheme::Sidebar
- Defined in:
- lib/jekyll/vitepress_theme/hooks.rb
Overview
rubocop:disable Metrics/ModuleLength
Constant Summary collapse
- DATA_KEY =
'jekyll_vitepress_sidebar'.freeze
- MAX_ITEM_LEVEL =
5
Class Method Summary collapse
- .ancestor_titles(doc, docs) ⇒ Object
- .apply(site) ⇒ Object
- .attach_nodes(collection_name, docs, nodes) ⇒ Object
- .attaching_creates_cycle?(doc, parent_doc, docs) ⇒ Boolean
- .build_collection(collection_name, docs) ⇒ Object
- .collection_data(group) ⇒ Object
- .collection_docs(site, collection_name) ⇒ Object
- .data_value(doc, key) ⇒ Object
- .doc_url(doc) ⇒ Object
- .finalize_children(node, level) ⇒ Object
- .finalize_nodes(nodes, level) ⇒ Object
- .flatten_docs(nodes) ⇒ Object
- .generate(site) ⇒ Object
- .generated_group(site, group) ⇒ Object
- .group_hash(group) ⇒ Object
- .group_value(group, key) ⇒ Object
- .node_for(doc) ⇒ Object
- .normalized_string(value) ⇒ Object
- .numeric?(value) ⇒ Boolean
- .parent_doc_for(doc, docs) ⇒ Object
- .parent_title(doc) ⇒ Object
- .sort_docs(docs) ⇒ Object
- .sort_key(doc) ⇒ Object
- .title(doc) ⇒ Object
- .truthy?(value) ⇒ Boolean
- .valid_parent?(doc, parent_doc, docs) ⇒ Boolean
- .warn_depth_limit(node) ⇒ Object
- .warn_missing_parent(collection_name, doc) ⇒ Object
-
.warn_missing_sidebar_data(site) ⇒ Object
A site with collection documents and no _data/sidebar.yml builds a page with an empty sidebar and no other complaint, which is a slow thing to notice.
Class Method Details
.ancestor_titles(doc, docs) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 168 def ancestor_titles(doc, docs) titles = [] current = parent_doc_for(doc, docs) seen = [] while current && !seen.include?(current) seen << current titles << title(current) current = parent_doc_for(current, docs) end titles end |
.apply(site) ⇒ Object
13 14 15 16 17 18 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 13 def apply(site) = generate(site) site.data[DATA_KEY] = if rescue StandardError => e Jekyll.logger.warn('jekyll-vitepress-theme', "Sidebar hierarchy generation failed: #{e.}") end |
.attach_nodes(collection_name, docs, nodes) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 79 def attach_nodes(collection_name, docs, nodes) docs.each_with_object([]) do |doc, roots| parent_doc = parent_doc_for(doc, docs) if valid_parent?(doc, parent_doc, docs) nodes[parent_doc]['children'] << nodes[doc] else warn_missing_parent(collection_name, doc) if parent_title(doc) roots << nodes[doc] end end end |
.attaching_creates_cycle?(doc, parent_doc, docs) ⇒ Boolean
154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 154 def attaching_creates_cycle?(doc, parent_doc, docs) current = parent_doc seen = [] while current return true if current == doc || seen.include?(current) seen << current current = parent_doc_for(current, docs) end false end |
.build_collection(collection_name, docs) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 64 def build_collection(collection_name, docs) ordered_docs = sort_docs(docs) nodes = ordered_docs.to_h { |doc| [doc, node_for(doc)] } roots = attach_nodes(collection_name, ordered_docs, nodes) finalize_nodes(roots, 1) flat_docs = flatten_docs(roots) { 'collection' => collection_name.to_s, 'items' => roots, 'docs' => flat_docs, 'active_urls' => flat_docs.filter_map { |doc| doc_url(doc) } } end |
.collection_data(group) ⇒ Object
60 61 62 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 60 def collection_data(group) group.slice('collection', 'items', 'docs', 'active_urls') end |
.collection_docs(site, collection_name) ⇒ Object
95 96 97 98 99 100 101 102 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 95 def collection_docs(site, collection_name) return [] unless collection_name collection = site.collections[collection_name.to_s] return [] unless collection collection.docs end |
.data_value(doc, key) ⇒ Object
206 207 208 209 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 206 def data_value(doc, key) data = doc.respond_to?(:data) ? doc.data : {} data[key] || data[key.to_sym] end |
.doc_url(doc) ⇒ Object
219 220 221 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 219 def doc_url(doc) doc.url if doc.respond_to?(:url) end |
.finalize_children(node, level) ⇒ Object
191 192 193 194 195 196 197 198 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 191 def finalize_children(node, level) if level >= MAX_ITEM_LEVEL warn_depth_limit(node) unless node['children'].empty? node['children'] = [] else finalize_nodes(node['children'], level + 1) end end |
.finalize_nodes(nodes, level) ⇒ Object
182 183 184 185 186 187 188 189 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 182 def finalize_nodes(nodes, level) nodes.sort_by! { |node| sort_key(node['doc']) } nodes.each do |node| finalize_children(node, level) node['active_urls'] = [node['url'], *node['children'].flat_map { |child| child['active_urls'] }].compact end end |
.flatten_docs(nodes) ⇒ Object
200 201 202 203 204 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 200 def flatten_docs(nodes) nodes.flat_map do |node| [node['doc'], *flatten_docs(node['children'])] end end |
.generate(site) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 34 def generate(site) = site.data['sidebar'] unless .respond_to?(:each) (site) return nil end groups = .filter_map { |group| generated_group(site, group) } { 'groups' => groups, 'collections' => groups.to_h { |group| [group['collection'], collection_data(group)] } } end |
.generated_group(site, group) ⇒ Object
49 50 51 52 53 54 55 56 57 58 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 49 def generated_group(site, group) collection_name = group_value(group, 'collection') docs = collection_docs(site, collection_name) return nil if docs.empty? collection_data = build_collection(collection_name, docs) return nil if collection_data['docs'].empty? group_hash(group).merge(collection_data) end |
.group_hash(group) ⇒ Object
104 105 106 107 108 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 104 def group_hash(group) return group if group.is_a?(Hash) group.respond_to?(:to_h) ? group.to_h : {} end |
.group_value(group, key) ⇒ Object
110 111 112 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 110 def group_value(group, key) group_hash(group)[key] || group_hash(group)[key.to_sym] end |
.node_for(doc) ⇒ Object
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 132 def node_for(doc) { 'doc' => doc, 'title' => title(doc), 'url' => doc_url(doc), 'collapsed' => truthy?(data_value(doc, 'collapsed')), 'children' => [], 'active_urls' => [] } end |
.normalized_string(value) ⇒ Object
223 224 225 226 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 223 def normalized_string(value) string = value.to_s.strip string.empty? ? nil : string end |
.numeric?(value) ⇒ Boolean
128 129 130 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 128 def numeric?(value) value.is_a?(Numeric) || value.to_s.match?(/\A-?\d+(?:\.\d+)?\z/) end |
.parent_doc_for(doc, docs) ⇒ Object
143 144 145 146 147 148 149 150 151 152 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 143 def parent_doc_for(doc, docs) direct_parent = parent_title(doc) return nil unless direct_parent candidates = docs.select { |candidate| candidate != doc && title(candidate) == direct_parent } grand_parent = normalized_string(data_value(doc, 'grand_parent')) return candidates.first unless grand_parent candidates.find { |candidate| ancestor_titles(candidate, docs).include?(grand_parent) } end |
.parent_title(doc) ⇒ Object
215 216 217 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 215 def parent_title(doc) normalized_string(data_value(doc, 'parent')) end |
.sort_docs(docs) ⇒ Object
114 115 116 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 114 def sort_docs(docs) docs.sort_by { |doc| sort_key(doc) } end |
.sort_key(doc) ⇒ Object
118 119 120 121 122 123 124 125 126 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 118 def sort_key(doc) nav_order = data_value(doc, 'nav_order') order_bucket = nav_order.nil? ? 1 : 0 numeric_order = numeric?(nav_order) order_type = numeric_order ? 0 : 1 order_value = numeric_order ? nav_order.to_f : nav_order.to_s [order_bucket, order_type, order_value, title(doc).downcase, doc_url(doc).to_s] end |
.title(doc) ⇒ Object
211 212 213 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 211 def title(doc) normalized_string(data_value(doc, 'title')) || '' end |
.truthy?(value) ⇒ Boolean
228 229 230 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 228 def truthy?(value) value == true || value.to_s.casecmp('true').zero? end |
.valid_parent?(doc, parent_doc, docs) ⇒ Boolean
91 92 93 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 91 def valid_parent?(doc, parent_doc, docs) parent_doc && !attaching_creates_cycle?(doc, parent_doc, docs) end |
.warn_depth_limit(node) ⇒ Object
239 240 241 242 243 244 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 239 def warn_depth_limit(node) Jekyll.logger.warn( 'jekyll-vitepress-theme', "Sidebar item '#{node['title']}' is deeper than #{MAX_ITEM_LEVEL} item levels; nested children were not rendered." ) end |
.warn_missing_parent(collection_name, doc) ⇒ Object
232 233 234 235 236 237 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 232 def warn_missing_parent(collection_name, doc) Jekyll.logger.warn( 'jekyll-vitepress-theme', "Missing sidebar parent '#{parent_title(doc)}' for '#{title(doc)}' in #{collection_name}; rendering it at the collection root." ) end |
.warn_missing_sidebar_data(site) ⇒ Object
A site with collection documents and no _data/sidebar.yml builds a page
with an empty sidebar and no other complaint, which is a slow thing to
notice. Overriding data_dir without carrying the file over is the
usual cause.
24 25 26 27 28 29 30 31 32 |
# File 'lib/jekyll/vitepress_theme/hooks.rb', line 24 def (site) return if site.collections.values.all? { |collection| collection.docs.empty? } Jekyll.logger.warn( 'jekyll-vitepress-theme', 'No _data/sidebar.yml found, so the sidebar will be empty. ' \ 'If you set a custom data_dir, copy the theme data files into it.' ) end |