The bmannconsulting.com website
1# frozen_string_literal: true
2class BidirectionalLinksGenerator < Jekyll::Generator
3 def generate(site)
4 graph_nodes = []
5 graph_edges = []
6
7 all_notes = site.collections['notes'].docs
8 all_posts = site.posts.docs
9 all_pages = site.pages
10 all_journals = site.collections['journals'].docs
11
12 all_docs = all_notes + all_pages + all_journals + all_posts
13
14 link_extension = !!site.config["use_html_extension"] ? '.html' : ''
15
16 # Convert all Wiki/Roam-style double-bracket link syntax to plain HTML
17 # anchor tag elements (<a>) with "internal-link" CSS class
18 all_docs.each do |current_note|
19 all_docs.each do |note_potentially_linked_to|
20 note_title_regexp_pattern = Regexp.escape(
21 File.basename(
22 note_potentially_linked_to.basename,
23 File.extname(note_potentially_linked_to.basename)
24 )
25 ).gsub('\_', '[ _]').gsub('\-', '[ -]').capitalize
26
27 title_from_data = note_potentially_linked_to.data['title']
28 if title_from_data
29 title_from_data = Regexp.escape(title_from_data)
30 end
31
32 new_href = "#{site.baseurl}#{note_potentially_linked_to.url}#{link_extension}"
33 # new_href = "#{site.tags_url}#{title_from_data}" #TODO is this how we can get a link over to my notes site?
34
35 anchor_tag = "<a class='internal-link' href='#{new_href}'>\\1</a>"
36
37 # Replace double-bracketed links with label using note title
38 # [[A note about cats|this is a link to the note about cats]]
39 current_note.content.gsub!(
40 /\[\[#{note_title_regexp_pattern}\|(.+?)(?=\])\]\]/i,
41 anchor_tag
42 )
43
44 # Replace double-bracketed links with label using note filename
45 # [[cats|this is a link to the note about cats]]
46 current_note.content.gsub!(
47 /\[\[#{title_from_data}\|(.+?)(?=\])\]\]/i,
48 anchor_tag
49 )
50
51 # Replace double-bracketed links using note title
52 # [[a note about cats]]
53 current_note.content.gsub!(
54 /\[\[(#{title_from_data})\]\]/i,
55 anchor_tag
56 # "<a class='internal-link' href='https://notes.bmannconsulting.com/#page/#{title_from_data}'>\\1</a>" # this only works if there is a local note with the right title
57 )
58
59 # Replace double-bracketed links using note filename
60 # [[cats]]
61 current_note.content.gsub!(
62 /\[\[(#{note_title_regexp_pattern})\]\]/i,
63 anchor_tag
64 )
65 end
66
67 # At this point, all remaining double-bracket-wrapped words are
68 # pointing to non-existing pages, so let's turn them into disabled
69 # links by greying them out and changing the cursor
70 current_note.content = current_note.content.gsub(
71 /\[\[([^\]]+)\]\]/i, # match on the remaining double-bracket links
72 #<<~HTML.delete("\n") # replace with this HTML (\\1 is what was inside the brackets)
73 # <span title='There is no note that matches this link.' class='invalid-link'>
74 # <span class='invalid-link-brackets'>[[</span>
75 # \\1
76 # <span class='invalid-link-brackets'>]]</span></span>
77 #HTML
78
79 # This doesn't handle lots of cases, need a URI.escape
80 <<~HTML.delete("\n") # replace with this HTML (\\1 is what was inside the brackets)
81 <a href='https://notes.bmannconsulting.com/#/page/\\1' class='noteslink' target='_notes'>\\1</a>
82 HTML
83 )
84 end
85
86 # Identify note backlinks and add them to each note
87 all_notes.each do |current_note|
88 # Nodes: Jekyll
89 notes_linking_to_current_note = all_notes.filter do |e|
90 e.content.include?(current_note.url)
91 end
92
93 # Nodes: Graph
94 graph_nodes << {
95 id: note_id_from_note(current_note),
96 path: "#{site.baseurl}#{current_note.url}#{link_extension}",
97 label: current_note.data['title'],
98 } unless current_note.path.include?('_notes/index.html')
99
100 # Edges: Jekyll
101 current_note.data['backlinks'] = notes_linking_to_current_note
102
103 # Edges: Graph
104 notes_linking_to_current_note.each do |n|
105 graph_edges << {
106 source: note_id_from_note(n),
107 target: note_id_from_note(current_note),
108 }
109 end
110 end
111
112 File.write('_includes/notes_graph.json', JSON.dump({
113 edges: graph_edges,
114 nodes: graph_nodes,
115 }))
116 end
117
118 def note_id_from_note(note)
119 note.data['title'].bytes.join
120 end
121end