jekyll-uj-powertools 1.6.0 → 1.6.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.
- checksums.yaml +4 -4
- data/README.md +94 -0
- data/jekyll-uj-powertools.gemspec +2 -1
- data/lib/filters/main.rb +36 -18
- data/lib/generators/inject-properties.rb +23 -1
- data/lib/hooks/inject-properties.rb +10 -0
- data/lib/hooks/markdown-images.rb +40 -0
- data/lib/jekyll-uj-powertools.rb +10 -0
- data/lib/tags/fake_comments.rb +72 -0
- data/lib/tags/icon.rb +262 -0
- data/lib/tags/image.rb +208 -0
- data/lib/tags/language.rb +301 -0
- data/lib/tags/member.rb +204 -0
- data/lib/tags/post.rb +258 -0
- data/lib/tags/readtime.rb +73 -0
- data/lib/tags/social.rb +84 -0
- data/lib/tags/translation_url.rb +154 -0
- metadata +26 -2
data/lib/tags/member.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJMemberTag < Liquid::Tag
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
super
|
8
|
+
@markup = markup.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
# Parse arguments preserving quotes
|
13
|
+
args = parse_arguments_with_quotes(@markup)
|
14
|
+
member_input = args[0]
|
15
|
+
property_input = args[1] || "'name'" # Default to name if no property specified
|
16
|
+
|
17
|
+
# Strip quotes from property if present
|
18
|
+
property = property_input.gsub(/^['"]|['"]$/, '')
|
19
|
+
|
20
|
+
# Check if the member input was originally quoted
|
21
|
+
is_quoted = member_input && member_input.match(/^['"]/)
|
22
|
+
|
23
|
+
# Resolve member ID
|
24
|
+
if is_quoted
|
25
|
+
# If quoted, strip quotes and use as literal
|
26
|
+
member_id = member_input.gsub(/^['"]|['"]$/, '')
|
27
|
+
else
|
28
|
+
# Otherwise resolve as variable
|
29
|
+
member_id = resolve_member_id(context, member_input)
|
30
|
+
end
|
31
|
+
return '' unless member_id
|
32
|
+
|
33
|
+
# Find member in site.team collection
|
34
|
+
site = context.registers[:site]
|
35
|
+
member = find_member(site, member_id)
|
36
|
+
return '' unless member
|
37
|
+
|
38
|
+
# Return the requested property
|
39
|
+
case property
|
40
|
+
when 'name'
|
41
|
+
(member.data['member'] && member.data['member']['name']) || ''
|
42
|
+
when 'url'
|
43
|
+
site_url = site.config['url'] || ''
|
44
|
+
site_url + member.url
|
45
|
+
when 'path'
|
46
|
+
member.url
|
47
|
+
when 'image'
|
48
|
+
member_id_clean = member.id.gsub('/team/', '')
|
49
|
+
"/assets/images/team/#{member_id_clean}/profile.jpg"
|
50
|
+
when 'image-tag'
|
51
|
+
# Generate image path
|
52
|
+
member_id_clean = member.id.gsub('/team/', '')
|
53
|
+
image_path = "/assets/images/team/#{member_id_clean}/profile.jpg"
|
54
|
+
|
55
|
+
# Parse additional options for the image tag
|
56
|
+
image_options = parse_image_options(args[2..-1])
|
57
|
+
|
58
|
+
# Set default alt text if not provided
|
59
|
+
if !image_options['alt'] && member.data['member'] && member.data['member']['name']
|
60
|
+
image_options['alt'] = member.data['member']['name']
|
61
|
+
end
|
62
|
+
|
63
|
+
# Build the markup string for uj_image tag
|
64
|
+
image_markup = build_image_markup(image_path, image_options)
|
65
|
+
|
66
|
+
# Parse and render the uj_image tag using Liquid template
|
67
|
+
template_content = "{% uj_image #{image_markup} %}"
|
68
|
+
template = Liquid::Template.parse(template_content)
|
69
|
+
template.render!(context)
|
70
|
+
else
|
71
|
+
# Try to access any other property dynamically
|
72
|
+
(member.data['member'] && member.data['member'][property]) || member.data[property] || ''
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def parse_arguments_with_quotes(markup)
|
79
|
+
# Parse arguments preserving quotes for detection
|
80
|
+
args = []
|
81
|
+
current_arg = ''
|
82
|
+
in_quotes = false
|
83
|
+
quote_char = nil
|
84
|
+
|
85
|
+
markup.each_char.with_index do |char, i|
|
86
|
+
if !in_quotes && (char == '"' || char == "'")
|
87
|
+
in_quotes = true
|
88
|
+
quote_char = char
|
89
|
+
current_arg += char
|
90
|
+
elsif in_quotes && char == quote_char
|
91
|
+
in_quotes = false
|
92
|
+
current_arg += char
|
93
|
+
quote_char = nil
|
94
|
+
elsif !in_quotes && char == ','
|
95
|
+
args << current_arg.strip
|
96
|
+
current_arg = ''
|
97
|
+
else
|
98
|
+
current_arg += char
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
args << current_arg.strip if current_arg.strip.length > 0
|
103
|
+
args
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse_arguments(markup)
|
107
|
+
# Parse arguments that can be quoted or unquoted
|
108
|
+
args = []
|
109
|
+
current_arg = ''
|
110
|
+
in_quotes = false
|
111
|
+
quote_char = nil
|
112
|
+
|
113
|
+
markup.each_char.with_index do |char, i|
|
114
|
+
if !in_quotes && (char == '"' || char == "'")
|
115
|
+
in_quotes = true
|
116
|
+
quote_char = char
|
117
|
+
elsif in_quotes && char == quote_char
|
118
|
+
in_quotes = false
|
119
|
+
quote_char = nil
|
120
|
+
elsif !in_quotes && char == ','
|
121
|
+
args << current_arg.strip
|
122
|
+
current_arg = ''
|
123
|
+
else
|
124
|
+
current_arg += char
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
args << current_arg.strip if current_arg.strip.length > 0
|
129
|
+
args
|
130
|
+
end
|
131
|
+
|
132
|
+
def resolve_member_id(context, member_input)
|
133
|
+
if member_input.nil? || member_input.empty?
|
134
|
+
# No input, try default sources
|
135
|
+
page = context['page']
|
136
|
+
return nil unless page
|
137
|
+
|
138
|
+
if page['post'] && page['post']['member']
|
139
|
+
page['post']['member']
|
140
|
+
elsif page['member'] && page['member']['name']
|
141
|
+
page['id']
|
142
|
+
else
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
else
|
146
|
+
# Resolve the variable
|
147
|
+
resolve_variable(context, member_input)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def resolve_variable(context, variable_name)
|
152
|
+
# Handle nested variable access
|
153
|
+
parts = variable_name.split('.')
|
154
|
+
current = context
|
155
|
+
|
156
|
+
parts.each do |part|
|
157
|
+
return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
|
158
|
+
current = current[part]
|
159
|
+
return nil if current.nil?
|
160
|
+
end
|
161
|
+
|
162
|
+
current
|
163
|
+
end
|
164
|
+
|
165
|
+
def find_member(site, member_id)
|
166
|
+
return nil unless site.collections['team']
|
167
|
+
|
168
|
+
site.collections['team'].docs.find do |member|
|
169
|
+
member.id.include?(member_id.to_s)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def parse_image_options(option_args)
|
174
|
+
options = {}
|
175
|
+
|
176
|
+
option_args.each do |arg|
|
177
|
+
# Strip quotes if present
|
178
|
+
arg_clean = arg.gsub(/^['"]|['"]$/, '')
|
179
|
+
|
180
|
+
if arg_clean.include?('=')
|
181
|
+
key, value = arg_clean.split('=', 2)
|
182
|
+
key = key.strip
|
183
|
+
value = value.strip.gsub(/^['"]|['"]$/, '')
|
184
|
+
options[key] = value
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
options
|
189
|
+
end
|
190
|
+
|
191
|
+
def build_image_markup(image_path, options)
|
192
|
+
# Build markup string in the format expected by uj_image tag
|
193
|
+
markup_parts = ["\"#{image_path}\""]
|
194
|
+
|
195
|
+
options.each do |key, value|
|
196
|
+
markup_parts << "#{key}=\"#{value}\""
|
197
|
+
end
|
198
|
+
|
199
|
+
markup_parts.join(', ')
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
Liquid::Template.register_tag('uj_member', Jekyll::UJMemberTag)
|
data/lib/tags/post.rb
ADDED
@@ -0,0 +1,258 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJPostTag < Liquid::Tag
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
super
|
8
|
+
@markup = markup.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
# Parse arguments
|
13
|
+
args = parse_arguments_with_quotes(@markup)
|
14
|
+
post_input = args[0]
|
15
|
+
property_input = args[1] || "'title'" # Default to title if no property specified
|
16
|
+
|
17
|
+
# Strip quotes from property if present
|
18
|
+
property = property_input.gsub(/^['"]|['"]$/, '')
|
19
|
+
|
20
|
+
# Check if the post input was originally quoted
|
21
|
+
is_quoted = post_input && post_input.match(/^['"]/)
|
22
|
+
|
23
|
+
# Resolve post ID
|
24
|
+
if is_quoted
|
25
|
+
# If quoted, strip quotes and use as literal
|
26
|
+
post_id = post_input.gsub(/^['"]|['"]$/, '')
|
27
|
+
else
|
28
|
+
# Otherwise resolve as variable
|
29
|
+
post_id = resolve_post_id(context, post_input)
|
30
|
+
end
|
31
|
+
return '' unless post_id
|
32
|
+
|
33
|
+
# Find post in site collections
|
34
|
+
site = context.registers[:site]
|
35
|
+
post = find_post(site, post_id)
|
36
|
+
return '' unless post
|
37
|
+
|
38
|
+
# Return the requested property
|
39
|
+
case property
|
40
|
+
when 'title'
|
41
|
+
post.data['title'] || ''
|
42
|
+
when 'description'
|
43
|
+
post.data['description'] || post.data['excerpt'] || ''
|
44
|
+
when 'url'
|
45
|
+
site_url = site.config['url'] || ''
|
46
|
+
site_url + post.url
|
47
|
+
when 'path'
|
48
|
+
post.url
|
49
|
+
when 'image'
|
50
|
+
# Use the custom post.post.id if available, otherwise fall back to extracting from post.id
|
51
|
+
custom_id = (post.data['post'] && post.data['post']['id']) || post.id.gsub(/^\/(\w+)\//, '')
|
52
|
+
# Extract the slug from the Jekyll post ID
|
53
|
+
post_id_clean = post.id.gsub(/^\/(\w+)\//, '')
|
54
|
+
slug = post_id_clean.gsub(/^\d{4}-\d{2}-\d{2}-/, '')
|
55
|
+
"/assets/images/blog/post-#{custom_id}/#{slug}.jpg"
|
56
|
+
when 'date'
|
57
|
+
post.data['date'] ? post.data['date'].strftime('%Y-%m-%d') : ''
|
58
|
+
when 'author'
|
59
|
+
(post.data['post'] && post.data['post']['author']) || post.data['author'] || ''
|
60
|
+
when 'category'
|
61
|
+
post.data['category'] || post.data['categories']&.first || ''
|
62
|
+
when 'categories'
|
63
|
+
Array(post.data['categories']).join(', ')
|
64
|
+
when 'tags'
|
65
|
+
Array(post.data['tags']).join(', ')
|
66
|
+
when 'id'
|
67
|
+
post.id
|
68
|
+
when 'image-tag'
|
69
|
+
# Generate image path
|
70
|
+
# Use the custom post.post.id if available, otherwise fall back to extracting from post.id
|
71
|
+
custom_id = (post.data['post'] && post.data['post']['id']) || post.id.gsub(/^\/(\w+)\//, '')
|
72
|
+
# Extract the slug from the Jekyll post ID
|
73
|
+
post_id_clean = post.id.gsub(/^\/(\w+)\//, '')
|
74
|
+
slug = post_id_clean.gsub(/^\d{4}-\d{2}-\d{2}-/, '')
|
75
|
+
image_path = "/assets/images/blog/post-#{custom_id}/#{slug}.jpg"
|
76
|
+
|
77
|
+
# Parse additional options for the image tag
|
78
|
+
image_options = parse_image_options(args[2..-1], context)
|
79
|
+
|
80
|
+
# Set default alt text if not provided
|
81
|
+
if !image_options['alt']
|
82
|
+
# Try to get the title from post.post.title first, then fall back to post.title
|
83
|
+
default_alt = (post.data['post'] && post.data['post']['title']) || post.data['title']
|
84
|
+
image_options['alt'] = default_alt if default_alt
|
85
|
+
end
|
86
|
+
|
87
|
+
# Build the markup string for uj_image tag
|
88
|
+
image_markup = build_image_markup(image_path, image_options)
|
89
|
+
|
90
|
+
# Parse and render the uj_image tag using Liquid template
|
91
|
+
template_content = "{% uj_image #{image_markup} %}"
|
92
|
+
template = Liquid::Template.parse(template_content)
|
93
|
+
template.render!(context)
|
94
|
+
else
|
95
|
+
# Try to access any other property dynamically
|
96
|
+
(post.data['post'] && post.data['post'][property]) || post.data[property] || ''
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def parse_arguments_with_quotes(markup)
|
103
|
+
# Parse arguments preserving quotes for detection
|
104
|
+
args = []
|
105
|
+
current_arg = ''
|
106
|
+
in_quotes = false
|
107
|
+
quote_char = nil
|
108
|
+
|
109
|
+
markup.each_char.with_index do |char, i|
|
110
|
+
if !in_quotes && (char == '"' || char == "'")
|
111
|
+
in_quotes = true
|
112
|
+
quote_char = char
|
113
|
+
current_arg += char
|
114
|
+
elsif in_quotes && char == quote_char
|
115
|
+
in_quotes = false
|
116
|
+
current_arg += char
|
117
|
+
quote_char = nil
|
118
|
+
elsif !in_quotes && char == ','
|
119
|
+
args << current_arg.strip
|
120
|
+
current_arg = ''
|
121
|
+
else
|
122
|
+
current_arg += char
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
args << current_arg.strip if current_arg.strip.length > 0
|
127
|
+
args
|
128
|
+
end
|
129
|
+
|
130
|
+
def parse_arguments(markup)
|
131
|
+
# Parse arguments that can be quoted or unquoted
|
132
|
+
args = []
|
133
|
+
current_arg = ''
|
134
|
+
in_quotes = false
|
135
|
+
quote_char = nil
|
136
|
+
|
137
|
+
markup.each_char.with_index do |char, i|
|
138
|
+
if !in_quotes && (char == '"' || char == "'")
|
139
|
+
in_quotes = true
|
140
|
+
quote_char = char
|
141
|
+
elsif in_quotes && char == quote_char
|
142
|
+
in_quotes = false
|
143
|
+
quote_char = nil
|
144
|
+
elsif !in_quotes && char == ','
|
145
|
+
args << current_arg.strip
|
146
|
+
current_arg = ''
|
147
|
+
else
|
148
|
+
current_arg += char
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
args << current_arg.strip if current_arg.strip.length > 0
|
153
|
+
args
|
154
|
+
end
|
155
|
+
|
156
|
+
def resolve_post_id(context, post_input)
|
157
|
+
if post_input.nil? || post_input.empty?
|
158
|
+
# No input, use current page if it's a post
|
159
|
+
page = context['page']
|
160
|
+
return nil unless page
|
161
|
+
|
162
|
+
# Check if current page is a post
|
163
|
+
if page['post'] || page['collection'] == 'posts'
|
164
|
+
page['id']
|
165
|
+
else
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
else
|
169
|
+
# Resolve the variable
|
170
|
+
resolve_variable(context, post_input)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def resolve_variable(context, variable_name)
|
175
|
+
# Handle nested variable access
|
176
|
+
parts = variable_name.split('.')
|
177
|
+
current = context
|
178
|
+
|
179
|
+
parts.each do |part|
|
180
|
+
return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
|
181
|
+
current = current[part]
|
182
|
+
return nil if current.nil?
|
183
|
+
end
|
184
|
+
|
185
|
+
current
|
186
|
+
end
|
187
|
+
|
188
|
+
def find_post(site, post_id)
|
189
|
+
post_id_clean = post_id.to_s.strip
|
190
|
+
|
191
|
+
# Search in posts collection first
|
192
|
+
if site.collections['posts']
|
193
|
+
post = site.collections['posts'].docs.find do |doc|
|
194
|
+
# Check standard ID match
|
195
|
+
doc.id == post_id_clean ||
|
196
|
+
doc.id.include?(post_id_clean) ||
|
197
|
+
# Also check if the post has a custom post.id field that matches
|
198
|
+
(doc.data['post'] && doc.data['post']['id'] == post_id_clean)
|
199
|
+
end
|
200
|
+
return post if post
|
201
|
+
end
|
202
|
+
|
203
|
+
# Search in other collections that might contain posts
|
204
|
+
site.collections.each do |name, collection|
|
205
|
+
next if name == 'posts' # Already checked
|
206
|
+
|
207
|
+
post = collection.docs.find do |doc|
|
208
|
+
(doc.id == post_id_clean ||
|
209
|
+
doc.id.include?(post_id_clean) ||
|
210
|
+
# Check custom post.id field
|
211
|
+
(doc.data['post'] && doc.data['post']['id'] == post_id_clean)) &&
|
212
|
+
doc.data['post']
|
213
|
+
end
|
214
|
+
return post if post
|
215
|
+
end
|
216
|
+
|
217
|
+
nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def parse_image_options(option_args, context)
|
221
|
+
options = {}
|
222
|
+
|
223
|
+
option_args.each do |arg|
|
224
|
+
if arg.include?('=')
|
225
|
+
key, value = arg.split('=', 2)
|
226
|
+
key = key.strip
|
227
|
+
|
228
|
+
# Check if the value is quoted (literal) or unquoted (variable)
|
229
|
+
if value.strip.match(/^['"].*['"]$/)
|
230
|
+
# It's a literal string, strip quotes
|
231
|
+
value = value.strip.gsub(/^['"]|['"]$/, '')
|
232
|
+
else
|
233
|
+
# It's a variable, resolve it
|
234
|
+
resolved_value = resolve_variable(context, value.strip)
|
235
|
+
value = resolved_value || value.strip
|
236
|
+
end
|
237
|
+
|
238
|
+
options[key] = value
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
options
|
243
|
+
end
|
244
|
+
|
245
|
+
def build_image_markup(image_path, options)
|
246
|
+
# Build markup string in the format expected by uj_image tag
|
247
|
+
markup_parts = ["\"#{image_path}\""]
|
248
|
+
|
249
|
+
options.each do |key, value|
|
250
|
+
markup_parts << "#{key}=\"#{value}\""
|
251
|
+
end
|
252
|
+
|
253
|
+
markup_parts.join(', ')
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
Liquid::Template.register_tag('uj_post', Jekyll::UJPostTag)
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJReadtimeTag < Liquid::Tag
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
super
|
8
|
+
@markup = markup.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
# Get the content to analyze
|
13
|
+
content = resolve_content(context)
|
14
|
+
return '1' unless content
|
15
|
+
|
16
|
+
# Strip HTML tags
|
17
|
+
stripped_content = strip_html(content)
|
18
|
+
|
19
|
+
# Count words
|
20
|
+
words = count_words(stripped_content)
|
21
|
+
|
22
|
+
# Calculate readtime (200 words per minute, minimum 1 minute)
|
23
|
+
readtime = (words / 200.0).ceil
|
24
|
+
readtime = 1 if readtime < 1
|
25
|
+
|
26
|
+
readtime.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def resolve_content(context)
|
32
|
+
if @markup.empty?
|
33
|
+
# No argument, use page content
|
34
|
+
page = context['page']
|
35
|
+
return nil unless page
|
36
|
+
page['content']
|
37
|
+
else
|
38
|
+
# Resolve the variable name
|
39
|
+
resolve_variable(context, @markup)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def resolve_variable(context, variable_name)
|
44
|
+
# Handle nested variable access like page.content or include.content
|
45
|
+
parts = variable_name.split('.')
|
46
|
+
current = context
|
47
|
+
|
48
|
+
parts.each do |part|
|
49
|
+
return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
|
50
|
+
current = current[part]
|
51
|
+
return nil if current.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
current
|
55
|
+
end
|
56
|
+
|
57
|
+
def strip_html(content)
|
58
|
+
# Remove HTML tags
|
59
|
+
content = content.to_s.gsub(/<script.*?<\/script>/m, '')
|
60
|
+
content = content.gsub(/<style.*?<\/style>/m, '')
|
61
|
+
content = content.gsub(/<[^>]+>/, ' ')
|
62
|
+
content = content.gsub(/\s+/, ' ')
|
63
|
+
content.strip
|
64
|
+
end
|
65
|
+
|
66
|
+
def count_words(text)
|
67
|
+
# Count words (split by whitespace)
|
68
|
+
text.split(/\s+/).length
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Liquid::Template.register_tag('uj_readtime', Jekyll::UJReadtimeTag)
|
data/lib/tags/social.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJSocialTag < Liquid::Tag
|
6
|
+
# Social platform URL patterns
|
7
|
+
SOCIAL_URLS = {
|
8
|
+
'facebook' => 'https://facebook.com/%s',
|
9
|
+
'twitter' => 'https://twitter.com/%s',
|
10
|
+
'linkedin' => 'https://linkedin.com/in/%s',
|
11
|
+
'youtube' => 'https://youtube.com/@%s',
|
12
|
+
'instagram' => 'https://instagram.com/%s',
|
13
|
+
'tumblr' => 'https://%s.tumblr.com',
|
14
|
+
'slack' => 'https://%s.slack.com',
|
15
|
+
'discord' => 'https://discord.gg/%s',
|
16
|
+
'github' => 'https://github.com/%s',
|
17
|
+
'dev' => 'https://dev.to/%s',
|
18
|
+
'tiktok' => 'https://tiktok.com/@%s',
|
19
|
+
'twitch' => 'https://twitch.tv/%s',
|
20
|
+
'soundcloud' => 'https://soundcloud.com/%s',
|
21
|
+
'spotify' => 'https://open.spotify.com/user/%s',
|
22
|
+
'mixcloud' => 'https://mixcloud.com/%s'
|
23
|
+
}
|
24
|
+
|
25
|
+
def initialize(tag_name, markup, tokens)
|
26
|
+
super
|
27
|
+
@markup = markup.strip
|
28
|
+
end
|
29
|
+
|
30
|
+
def render(context)
|
31
|
+
# Parse the platform name (can be quoted or unquoted)
|
32
|
+
platform_input = parse_argument(@markup)
|
33
|
+
|
34
|
+
# Resolve the platform name (could be a variable or literal string)
|
35
|
+
platform = resolve_variable(context, platform_input)
|
36
|
+
|
37
|
+
# If it didn't resolve to anything, use the input as a literal string
|
38
|
+
platform = platform_input if platform.nil? || platform.empty?
|
39
|
+
|
40
|
+
# Get the social handle from page.resolved.socials.{platform}
|
41
|
+
page = context['page']
|
42
|
+
return '' unless page
|
43
|
+
|
44
|
+
social_handle = page['resolved'] && page['resolved']['socials'] && page['resolved']['socials'][platform]
|
45
|
+
return '' unless social_handle && !social_handle.empty?
|
46
|
+
|
47
|
+
# Get the URL pattern for this platform
|
48
|
+
url_pattern = SOCIAL_URLS[platform]
|
49
|
+
return '' unless url_pattern
|
50
|
+
|
51
|
+
# Build the URL
|
52
|
+
url_pattern % social_handle
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def parse_argument(markup)
|
58
|
+
# Remove quotes if present
|
59
|
+
cleaned = markup.strip
|
60
|
+
if (cleaned.start_with?('"') && cleaned.end_with?('"')) ||
|
61
|
+
(cleaned.start_with?("'") && cleaned.end_with?("'"))
|
62
|
+
cleaned[1..-2]
|
63
|
+
else
|
64
|
+
cleaned
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def resolve_variable(context, variable_name)
|
69
|
+
# Handle nested variable access like page.social
|
70
|
+
parts = variable_name.split('.')
|
71
|
+
current = context
|
72
|
+
|
73
|
+
parts.each do |part|
|
74
|
+
return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
|
75
|
+
current = current[part]
|
76
|
+
return nil if current.nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
current
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Liquid::Template.register_tag('uj_social', Jekyll::UJSocialTag)
|