jekyll-social-share 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 24ac5ee5e3a6b80333f4997ffdea6c2d14721fbd4ffd8434cbdac2e575e429c9
4
+ data.tar.gz: 6ce2d84654fcd7edb050be02c5e0dcfe59c5bc9cc8ee77055a6c0aa5159975be
5
+ SHA512:
6
+ metadata.gz: b65879cfa35c2adcf2f7e7b6ab6e5b099791bdd871d1a02f328ac10b677c470ab15f5f653edbce70c3824620c23b8530d451c7d58fc83207b1e4c66095dcaf23
7
+ data.tar.gz: 0d8152c3726d88d0a5eade4e65eaaea9c07f8e3959d4672fb9f51c56a5bac8a81adea4982b7c38f58f50089ee16ab5521bfda03356cd0266e5cf7f7de17d9e18
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "jekyll-social-share/icons"
5
+
6
+ module Jekyll
7
+ class SocialShareTag < Liquid::Tag
8
+ DEFAULT_SERVICES = %w[bluesky mastodon facebook reddit linkedin x threads email copy].freeze
9
+
10
+ SERVICE_CONFIG = {
11
+ "bluesky" => { label: "Bluesky", url_template: "https://bsky.app/intent/compose?text=%<title>s%%20%<url>s" },
12
+ "mastodon" => { label: "Mastodon", url_template: :mastodon },
13
+ "facebook" => { label: "Facebook", url_template: "https://www.facebook.com/sharer/sharer.php?u=%<url>s" },
14
+ "reddit" => { label: "Reddit", url_template: "https://www.reddit.com/submit?url=%<url>s&title=%<title>s" },
15
+ "linkedin" => { label: "LinkedIn", url_template: "https://www.linkedin.com/sharing/share-offsite/?url=%<url>s" },
16
+ "x" => { label: "X", url_template: "https://twitter.com/intent/tweet?url=%<url>s&text=%<title>s" },
17
+ "threads" => { label: "Threads", url_template: "https://www.threads.net/intent/post?text=%<title>s%%20%<url>s" },
18
+ "email" => { label: "Email", url_template: :email },
19
+ "copy" => { label: "Copy link", url_template: :copy },
20
+ }.freeze
21
+
22
+ def initialize(tag_name, markup, tokens)
23
+ super
24
+ @params = parse_params(markup.strip)
25
+ end
26
+
27
+ def render(context)
28
+ site = context.registers[:site]
29
+ page = context.registers[:page]
30
+ config = site.config["social_share"] || {}
31
+
32
+ return "" if page["share"] == false
33
+
34
+ services = resolve_services(@params["services"] || config["services"] || DEFAULT_SERVICES)
35
+ icon_only = bool_param(@params, config, "icon_only", false)
36
+ text_only = bool_param(@params, config, "text_only", false)
37
+ label = @params["label"] || config["label"] || "Share"
38
+ show_label = label != false && label != "false"
39
+ mastodon_relay = config["mastodon_instance"] || "https://toot.kytta.dev"
40
+
41
+ page_url = absolute_url(page["url"] || "", site)
42
+ page_title = URI.encode_www_form_component(@params["title"] || page["title"] || site.config["title"] || "")
43
+
44
+ items = services.map do |svc|
45
+ cfg = SERVICE_CONFIG[svc]
46
+ next nil unless cfg
47
+
48
+ href = build_url(svc, cfg[:url_template], page_url, page_title, mastodon_relay)
49
+ icon = SocialShare::ICONS[svc] || ""
50
+ render_item(svc, cfg[:label], href, icon, icon_only, text_only)
51
+ end.compact
52
+
53
+ render_wrapper(label, show_label, items)
54
+ end
55
+
56
+ private
57
+
58
+ def parse_params(markup)
59
+ params = {}
60
+ markup.scan(/(\w+)\s*=\s*"([^"]*)"/) { |k, v| params[k] = v }
61
+ params
62
+ end
63
+
64
+ def resolve_services(raw)
65
+ case raw
66
+ when Array then raw.map(&:to_s).map(&:strip)
67
+ when String then raw.split(",").map(&:strip)
68
+ else DEFAULT_SERVICES
69
+ end
70
+ end
71
+
72
+ def bool_param(params, config, key, default)
73
+ return params[key] == "true" if params.key?(key)
74
+ return config[key] if config.key?(key)
75
+ default
76
+ end
77
+
78
+ def absolute_url(path, site)
79
+ base = site.config["url"].to_s.chomp("/")
80
+ base_path = site.config["baseurl"].to_s.chomp("/")
81
+ URI.encode_www_form_component("#{base}#{base_path}#{path}")
82
+ end
83
+
84
+ def build_url(svc, template, page_url, page_title, mastodon_relay)
85
+ case template
86
+ when :mastodon
87
+ text = URI.encode_www_form_component("#{URI.decode_www_form_component(page_title)} #{URI.decode_www_form_component(page_url)}")
88
+ "#{mastodon_relay.chomp("/")}/?text=#{text}"
89
+ when :email
90
+ subject = URI.encode_www_form_component(URI.decode_www_form_component(page_title))
91
+ body = URI.encode_www_form_component(URI.decode_www_form_component(page_url))
92
+ "mailto:?subject=#{subject}&body=#{body}"
93
+ when :copy
94
+ "#copy-link"
95
+ else
96
+ format(template, url: page_url, title: page_title)
97
+ end
98
+ end
99
+
100
+ def render_item(svc, label, href, icon, icon_only, text_only)
101
+ if svc == "copy"
102
+ render_copy_item(icon, label, icon_only, text_only)
103
+ else
104
+ target = %(target="_blank" rel="noopener noreferrer")
105
+ icon_html = text_only ? "" : %(<span class="social-share__icon">#{icon}</span>)
106
+ label_html = icon_only ? %(<span class="social-share__text sr-only">#{label}</span>) : %(<span class="social-share__text">#{label}</span>)
107
+ %(<li class="social-share__item social-share__item--#{svc}"><a href="#{href}" #{target} class="social-share__link" aria-label="Share on #{label}">#{icon_html}#{label_html}</a></li>)
108
+ end
109
+ end
110
+
111
+ def render_copy_item(icon, label, icon_only, text_only)
112
+ icon_html = text_only ? "" : %(<span class="social-share__icon">#{icon}</span>)
113
+ label_html = icon_only ? %(<span class="social-share__text sr-only">#{label}</span>) : %(<span class="social-share__text">#{label}</span>)
114
+ script = <<~JS.strip
115
+ <script>
116
+ (function(){
117
+ var btn=document.getElementById('social-share-copy');
118
+ if(!btn)return;
119
+ btn.addEventListener('click',function(e){
120
+ e.preventDefault();
121
+ navigator.clipboard.writeText(window.location.href).then(function(){
122
+ btn.classList.add('social-share__copy--copied');
123
+ var t=btn.querySelector('.social-share__text');
124
+ if(t){var orig=t.textContent;t.textContent='Copied!';setTimeout(function(){t.textContent=orig;btn.classList.remove('social-share__copy--copied');},2000);}
125
+ });
126
+ });
127
+ })();
128
+ </script>
129
+ JS
130
+ %(<li class="social-share__item social-share__item--copy"><button id="social-share-copy" class="social-share__link social-share__copy" aria-label="Copy link">#{icon_html}#{label_html}</button></li>#{script})
131
+ end
132
+
133
+ def render_wrapper(label, show_label, items)
134
+ label_html = show_label ? %(<span class="social-share__label">#{label}</span>) : ""
135
+ <<~HTML
136
+ <div class="social-share">
137
+ #{label_html}
138
+ <ul class="social-share__list">
139
+ #{items.join("\n ")}
140
+ </ul>
141
+ </div>
142
+ HTML
143
+ end
144
+ end
145
+ end
146
+
147
+ Liquid::Template.register_tag("social_share", Jekyll::SocialShareTag)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # Inline SVGs sourced from Simple Icons (https://simpleicons.org) — CC0 licensed
3
+
4
+ module Jekyll
5
+ module SocialShare
6
+ ICONS = {
7
+ "bluesky" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M5.202 2.857C7.954 4.922 10.913 9.11 12 11.358c1.087-2.247 4.046-6.436 6.798-8.501C20.783 1.366 24 .213 24 3.883c0 .732-.42 6.156-.667 7.037-.856 3.061-3.978 3.842-6.755 3.37 4.854.826 6.089 3.562 3.422 6.299-5.065 5.196-7.28-1.304-7.847-2.97-.104-.305-.152-.448-.153-.327 0-.121-.05.022-.153.327-.568 1.666-2.782 8.166-7.847 2.97-2.667-2.737-1.432-5.473 3.422-6.3-2.777.473-5.899-.308-6.755-3.369C.42 10.04 0 4.615 0 3.883c0-3.67 3.217-2.517 5.202-1.026"/></svg>',
8
+ "mastodon" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg>',
9
+ "facebook" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"/></svg>',
10
+ "reddit" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M12 0C5.373 0 0 5.373 0 12c0 3.314 1.343 6.314 3.515 8.485l-2.286 2.286C.775 23.225 1.097 24 1.738 24H12c6.627 0 12-5.373 12-12S18.627 0 12 0Zm4.388 3.199c1.104 0 1.999.895 1.999 1.999 0 1.105-.895 2-1.999 2-.946 0-1.739-.657-1.947-1.539v.002c-1.147.162-2.032 1.15-2.032 2.341v.007c1.776.067 3.4.567 4.686 1.363.473-.363 1.064-.58 1.707-.58 1.547 0 2.802 1.254 2.802 2.802 0 1.117-.655 2.081-1.601 2.531-.088 3.256-3.637 5.876-7.997 5.876-4.361 0-7.905-2.617-7.998-5.87-.954-.447-1.614-1.415-1.614-2.538 0-1.548 1.255-2.802 2.803-2.802.645 0 1.239.218 1.712.585 1.275-.79 2.881-1.291 4.64-1.365v-.01c0-1.663 1.263-3.034 2.88-3.207.188-.911.993-1.595 1.959-1.595Zm-8.085 8.376c-.784 0-1.459.78-1.506 1.797-.047 1.016.64 1.429 1.426 1.429.786 0 1.371-.369 1.418-1.385.047-1.017-.553-1.841-1.338-1.841Zm7.406 0c-.786 0-1.385.824-1.338 1.841.047 1.017.634 1.385 1.418 1.385.785 0 1.473-.413 1.426-1.429-.046-1.017-.721-1.797-1.506-1.797Zm-3.703 4.013c-.974 0-1.907.048-2.77.135-.147.015-.241.168-.183.305.483 1.154 1.622 1.964 2.953 1.964 1.33 0 2.47-.81 2.953-1.964.057-.137-.037-.29-.184-.305-.863-.087-1.795-.135-2.769-.135Z"/></svg>',
11
+ "linkedin" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>',
12
+ "x" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"/></svg>',
13
+ "threads" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M18.263 11.097c-.03-3.486-1.92-5.586-5.111-5.586-2.13 0-3.922.963-4.863 2.499l2.062 1.438c.535-.843 1.272-1.543 2.628-1.543 1.528 0 2.318.85 2.544 2.431a15 15 0 0 0-2.236-.173c-4.125 0-6.068 1.867-6.068 4.336s1.943 3.99 4.804 3.99c3.139 0 5.013-2.115 5.781-4.735.798.361 1.348 1.204 1.348 2.47 0 3.387-3.907 5.232-7.22 5.232-4.885 0-8.077-3.207-8.077-8.424 0-6.392 4.223-10.487 9.9-10.487 3.808 0 5.69 1.671 6.97 3.914l2.108-1.475C21.44 2.078 18.331 0 13.663 0 6.227 0 1.168 5.277 1.168 12.934c0 7 4.953 11.066 10.856 11.066 4.878 0 9.809-2.846 9.809-7.716 0-2.545-1.46-4.231-3.569-5.187m-6.33 4.855c-1.077 0-2.026-.512-2.026-1.453 0-1.483 1.822-1.934 3.606-1.934.678 0 1.34.045 1.927.173-.422 1.927-1.671 3.215-3.508 3.214Z"/></svg>',
14
+ "email" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4-8 5-8-5V6l8 5 8-5v2z"/></svg>',
15
+ "copy" => '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>',
16
+ }.freeze
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module SocialShare
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll-social-share/version"
4
+ require "jekyll-social-share/icons"
5
+ require "jekyll/social_share_tag"
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-social-share
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jason Chance
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-08-21 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: jekyll
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '4.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '4.0'
26
+ description: Adds a {% social_share %} Liquid tag that renders share buttons for Bluesky,
27
+ Mastodon, Facebook, Reddit, LinkedIn, X, Threads, email, and copy-link. Icons are
28
+ inline SVGs from Simple Icons (CC0). Fully configurable via _config.yml.
29
+ email:
30
+ - jason@jasonchance.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/jekyll-social-share.rb
36
+ - lib/jekyll-social-share/icons.rb
37
+ - lib/jekyll-social-share/version.rb
38
+ - lib/jekyll/social_share_tag.rb
39
+ homepage: https://github.com/jchance/jekyll-social-share
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '2.7'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.6.2
58
+ specification_version: 4
59
+ summary: Social sharing buttons for Jekyll — inline SVG icons, no external dependencies.
60
+ test_files: []