jekyll-link-decorator 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jekyll-link-decorator.rb +87 -0
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33285c1668a0edb31f7be980cd4f810232337bd0b627e0b8969349195ebede3e
4
- data.tar.gz: e239a936a02e1d02955e888c043346c703b959c740467c0de768f8928f2882fc
3
+ metadata.gz: 85f578a55d98076ae39a47427c191f790d9f7a804b095849d39897db778a86e7
4
+ data.tar.gz: 023bfd45a25c076a0b7fe8bc632195fc8e85d60d983e63cfb2c50abbd2c9c807
5
5
  SHA512:
6
- metadata.gz: ccb6bf72c6dd271fe95379b9074b7f9d21c19f63dd3f064ae25aa91500789cd9cb14481674bbce08b99d1681139820615265b4f8480eb76a8b2dea26500685aa
7
- data.tar.gz: 47d5e239f7d65ec8bafd8d2d14dea7b2363f5b726f0fd9312f23473e15d167cffa27c2f49bddb6238e13bb12f2e48bf41e275590b8bfceca7d6527a3932b2b2e
6
+ metadata.gz: c32eecd6e74d8ab46a664268c0371f63401ff9c94f40b10984f04fbd0b211e44d6e2f375f3f3cabaceeceda17b4ac4f009666ae472f62e3163a7664caeb6b4b1
7
+ data.tar.gz: b9b1c79b09cb02402fd89740829de88077b59a649936c0e11c4b2034ed0b067e7ae8da6f8bc5e9469af813ac37b2882364e463477e77d46c366869652b15ef4a
@@ -41,6 +41,23 @@
41
41
  # (target="_blank", rel="noopener noreferrer") are still applied.
42
42
  # Example: `external_link_icon_excluded_tags: ["img", "svg"]`
43
43
  #
44
+ # === Heading Anchor Support ===
45
+ #
46
+ # The plugin can inject a Font Awesome link icon inside each heading (h1–h6),
47
+ # giving users a direct, copyable URL to every section. This feature is configured
48
+ # via two top-level keys (separate from `with_link_decorator_data`):
49
+ #
50
+ # * `with_heading_anchor`: Boolean (default: false) that controls whether heading anchors
51
+ # are injected. Set to true to enable.
52
+ #
53
+ # * `with_heading_anchor_data`: A dictionary containing optional configuration keys:
54
+ # - `icon`: Font Awesome icon classes (default: "fa-solid fa-link")
55
+ # - `icon_size`: Font Awesome size modifier appended after icon classes (default: "fa-xs")
56
+ # - `copy_success_message`: Feedback text after copying (consumed by heading-anchor.js,
57
+ # default: "Copied!")
58
+ # - `reset_delay`: Milliseconds before the icon resets (consumed by heading-anchor.js,
59
+ # default: 2000)
60
+ #
44
61
  # If no configuration is provided, the plugin will use default fallback classes
45
62
  # and enable external link icons.
46
63
  #
@@ -55,6 +72,13 @@
55
72
  # external_link_icon_excluded_tags:
56
73
  # - img
57
74
  # - svg
75
+ #
76
+ # with_heading_anchor: true
77
+ # with_heading_anchor_data:
78
+ # icon: "fa-solid fa-link"
79
+ # icon_size: "fa-xs"
80
+ # copy_success_message: "Copied!"
81
+ # reset_delay: 2000
58
82
  # ```
59
83
 
60
84
  require 'nokogiri'
@@ -79,6 +103,9 @@ module Jekyll
79
103
  DEFAULT_ALERT_LINK_CLASSES = 'alert-link'
80
104
  DEFAULT_EXTERNAL_LINK_ICON = true
81
105
  DEFAULT_EXTERNAL_LINK_ICON_EXCLUDED_TAGS = [].freeze
106
+ DEFAULT_HEADING_ANCHOR = false
107
+ DEFAULT_HEADING_ANCHOR_ICON = 'fa-solid fa-link'
108
+ DEFAULT_HEADING_ANCHOR_SIZE = 'fa-xs'
82
109
 
83
110
  def self.name
84
111
  'LinkDecorator'
@@ -196,6 +223,7 @@ module Jekyll
196
223
 
197
224
  apply_link_styles(doc, config)
198
225
  add_external_link_features(doc, config)
226
+ add_heading_anchors(doc)
199
227
 
200
228
  doc.to_html
201
229
  rescue StandardError => e
@@ -262,6 +290,65 @@ module Jekyll
262
290
  extract_domain(site_url)
263
291
  end
264
292
 
293
+ # Inject a Font Awesome anchor link inside each heading (h1–h6).
294
+ # Reads with_heading_anchor and with_heading_anchor_data from @config directly.
295
+ def add_heading_anchors(doc)
296
+ enabled = @config.key?('with_heading_anchor') ? @config['with_heading_anchor'] : DEFAULT_HEADING_ANCHOR
297
+ return unless enabled
298
+
299
+ ha_data = @config['with_heading_anchor_data'] || {}
300
+ icon_class = ha_data.fetch('icon', DEFAULT_HEADING_ANCHOR_ICON)
301
+ icon_size = ha_data.fetch('icon_size', DEFAULT_HEADING_ANCHOR_SIZE)
302
+ full_icon = "#{icon_class} #{icon_size}"
303
+ id_counts = {}
304
+
305
+ doc.css('h1, h2, h3, h4, h5, h6').each do |heading|
306
+ next if heading.css('.heading-anchor').any?
307
+
308
+ id = resolve_heading_id(heading, id_counts)
309
+
310
+ anchor = Nokogiri::XML::Node.new('a', doc)
311
+ anchor['class'] = 'heading-anchor mx-1'
312
+ anchor['href'] = "##{id}"
313
+ anchor['data-copy-anchor'] = "##{id}"
314
+ anchor['aria-label'] = "Link to #{heading.text.strip}"
315
+
316
+ icon = Nokogiri::XML::Node.new('i', doc)
317
+ icon['class'] = full_icon
318
+ icon['aria-hidden'] = 'true'
319
+ anchor.add_child(icon)
320
+
321
+ heading.add_child(anchor)
322
+ end
323
+ end
324
+
325
+ # Return the heading's existing id, or generate and assign one from its text.
326
+ # id_counts tracks generated slugs to produce unique suffixes for duplicates.
327
+ def resolve_heading_id(heading, id_counts)
328
+ existing = heading['id'].to_s.strip
329
+ return existing unless existing.empty?
330
+
331
+ base = slugify(heading.text)
332
+ n = id_counts[base].to_i
333
+ id_counts[base] = n + 1
334
+ final_id = n.zero? ? base : "#{base}-#{n}"
335
+ heading['id'] = final_id
336
+ final_id
337
+ end
338
+
339
+ # Convert heading text to a URL-safe slug matching the link.html.liquid algorithm:
340
+ # strip → downcase → spaces to hyphens → remove ", ', ?, &, #, / → collapse hyphens
341
+ def slugify(text)
342
+ text.strip
343
+ .downcase
344
+ .tr(' ', '-')
345
+ .delete('"\'?&#/')
346
+ .gsub(/-{2,}/, '-')
347
+ .gsub(/\A-|-\z/, '')
348
+ end
349
+
350
+ private :add_heading_anchors, :resolve_heading_id, :slugify
351
+
265
352
  # Add external-link icon to cross-domain external links
266
353
  def add_external_icon(link, site_domain, config, doc)
267
354
  external_link_icon = config.fetch('external_link_icon', DEFAULT_EXTERNAL_LINK_ICON)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-link-decorator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ReleaseBot