jekyll-link-decorator 1.2.2 → 1.3.1

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 +85 -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: 58e0cbaffc8dddaa356b97b7f9523197377c98862ec3398cef26b7436b69d8d1
4
+ data.tar.gz: 5fab208572e92de8982ed60159799b02b729f196a54ba5f0465c86dee212275a
5
5
  SHA512:
6
- metadata.gz: ccb6bf72c6dd271fe95379b9074b7f9d21c19f63dd3f064ae25aa91500789cd9cb14481674bbce08b99d1681139820615265b4f8480eb76a8b2dea26500685aa
7
- data.tar.gz: 47d5e239f7d65ec8bafd8d2d14dea7b2363f5b726f0fd9312f23473e15d167cffa27c2f49bddb6238e13bb12f2e48bf41e275590b8bfceca7d6527a3932b2b2e
6
+ metadata.gz: fa74e76b3aed60bd4be998dd4b227268323aabae2f00ec67d718ec71c2b04f85bb356bdea7ac8622b6d4caabbc778cff534d2796dbd06bd55989611db4760ca7
7
+ data.tar.gz: 233d5cde8f2bfdf617b595a2783633e37d4b3794ba3ccfd8b8e838f8c4906348c4a8cd8979f78ea543861ab648633f004bc81c18aa7b44f6cec3170585d75c4d
@@ -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 (optional)
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,12 @@
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
+ # copy_success_message: "Copied!"
80
+ # reset_delay: 2000
58
81
  # ```
59
82
 
60
83
  require 'nokogiri'
@@ -79,6 +102,8 @@ module Jekyll
79
102
  DEFAULT_ALERT_LINK_CLASSES = 'alert-link'
80
103
  DEFAULT_EXTERNAL_LINK_ICON = true
81
104
  DEFAULT_EXTERNAL_LINK_ICON_EXCLUDED_TAGS = [].freeze
105
+ DEFAULT_HEADING_ANCHOR = false
106
+ DEFAULT_HEADING_ANCHOR_ICON = 'fa-solid fa-link'
82
107
 
83
108
  def self.name
84
109
  'LinkDecorator'
@@ -196,6 +221,7 @@ module Jekyll
196
221
 
197
222
  apply_link_styles(doc, config)
198
223
  add_external_link_features(doc, config)
224
+ add_heading_anchors(doc)
199
225
 
200
226
  doc.to_html
201
227
  rescue StandardError => e
@@ -262,6 +288,65 @@ module Jekyll
262
288
  extract_domain(site_url)
263
289
  end
264
290
 
291
+ # Inject a Font Awesome anchor link inside each heading (h1–h6).
292
+ # Reads with_heading_anchor and with_heading_anchor_data from @config directly.
293
+ def add_heading_anchors(doc)
294
+ enabled = @config.key?('with_heading_anchor') ? @config['with_heading_anchor'] : DEFAULT_HEADING_ANCHOR
295
+ return unless enabled
296
+
297
+ ha_data = @config['with_heading_anchor_data'] || {}
298
+ icon_class = ha_data.fetch('icon', DEFAULT_HEADING_ANCHOR_ICON)
299
+ icon_size = ha_data['icon_size']
300
+ full_icon = [icon_class, icon_size].compact.join(' ')
301
+ id_counts = {}
302
+
303
+ doc.css('h1, h2, h3, h4, h5, h6').each do |heading|
304
+ next if heading.css('.heading-anchor').any?
305
+
306
+ id = resolve_heading_id(heading, id_counts)
307
+
308
+ anchor = Nokogiri::XML::Node.new('a', doc)
309
+ anchor['class'] = 'heading-anchor mx-1'
310
+ anchor['href'] = "##{id}"
311
+ anchor['data-copy-anchor'] = "##{id}"
312
+ anchor['aria-label'] = "Link to #{heading.text.strip}"
313
+
314
+ icon = Nokogiri::XML::Node.new('i', doc)
315
+ icon['class'] = full_icon
316
+ icon['aria-hidden'] = 'true'
317
+ anchor.add_child(icon)
318
+
319
+ heading.add_child(anchor)
320
+ end
321
+ end
322
+
323
+ # Return the heading's existing id, or generate and assign one from its text.
324
+ # id_counts tracks generated slugs to produce unique suffixes for duplicates.
325
+ def resolve_heading_id(heading, id_counts)
326
+ existing = heading['id'].to_s.strip
327
+ return existing unless existing.empty?
328
+
329
+ base = slugify(heading.text)
330
+ n = id_counts[base].to_i
331
+ id_counts[base] = n + 1
332
+ final_id = n.zero? ? base : "#{base}-#{n}"
333
+ heading['id'] = final_id
334
+ final_id
335
+ end
336
+
337
+ # Convert heading text to a URL-safe slug matching the link.html.liquid algorithm:
338
+ # strip → downcase → spaces to hyphens → remove ", ', ?, &, #, / → collapse hyphens
339
+ def slugify(text)
340
+ text.strip
341
+ .downcase
342
+ .tr(' ', '-')
343
+ .delete('"\'?&#/')
344
+ .gsub(/-{2,}/, '-')
345
+ .gsub(/\A-|-\z/, '')
346
+ end
347
+
348
+ private :add_heading_anchors, :resolve_heading_id, :slugify
349
+
265
350
  # Add external-link icon to cross-domain external links
266
351
  def add_external_icon(link, site_domain, config, doc)
267
352
  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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ReleaseBot