jekyll-webawesome 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.
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+ require 'jekyll'
5
+ require 'kramdown'
6
+
7
+ module Jekyll
8
+ module WebAwesome
9
+ # Base class for all Web Awesome component transformers
10
+ # Each transformer should implement the transform method
11
+ class BaseTransformer
12
+ def self.transform(content)
13
+ raise NotImplementedError, 'Subclasses must implement the transform method'
14
+ end
15
+
16
+ class << self
17
+ protected
18
+
19
+ # Helper method to convert markdown content to HTML
20
+ def markdown_to_html(content)
21
+ Kramdown::Document.new(content).to_html
22
+ end
23
+
24
+ # Helper method to apply multiple regex patterns with the same transformation logic
25
+ # @param content [String] The content to transform
26
+ # @param patterns [Array<Hash>] Array of pattern hashes with :regex and :block
27
+ # @return [String] The transformed content
28
+ def apply_multiple_patterns(content, patterns)
29
+ patterns.each do |pattern|
30
+ content = content.gsub(pattern[:regex]) do |match|
31
+ pattern[:block].call(match, $LAST_MATCH_INFO)
32
+ end
33
+ end
34
+ content
35
+ end
36
+
37
+ # Helper method to create both primary and alternative syntax patterns
38
+ # @param primary_regex [Regexp] The primary syntax regex
39
+ # @param alternative_regex [Regexp] The alternative syntax regex
40
+ # @param transform_proc [Proc] The proc that takes captured groups and returns HTML
41
+ # @return [Array<Hash>] Array of pattern hashes
42
+ def dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
43
+ [
44
+ {
45
+ regex: primary_regex,
46
+ block: proc do |_match, matchdata|
47
+ # Get all captured groups from the matchdata
48
+ captures = matchdata.captures
49
+ transform_proc.call(*captures)
50
+ end
51
+ },
52
+ {
53
+ regex: alternative_regex,
54
+ block: proc do |_match, matchdata|
55
+ # Get all captured groups from the matchdata
56
+ captures = matchdata.captures
57
+ transform_proc.call(*captures)
58
+ end
59
+ }
60
+ ]
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+
5
+ module Jekyll
6
+ module WebAwesome
7
+ # Transforms button syntax into wa-button elements
8
+ # Primary syntax: %%%variant?\ncontent\n%%%
9
+ # Alternative syntax: :::wa-button variant?\ncontent\n:::
10
+ # Variants: brand, success, neutral, warning, danger
11
+ #
12
+ # Link buttons: %%%brand\n[Text](url)\n%%%
13
+ # Regular buttons: %%%brand\nText\n%%%
14
+ class ButtonTransformer < BaseTransformer
15
+ def self.transform(content)
16
+ # Define both regex patterns
17
+ primary_regex = /^%%%(brand|success|neutral|warning|danger)?\n(.*?)\n%%%/m
18
+ alternative_regex = /^:::wa-button\s*(brand|success|neutral|warning|danger)?\n(.*?)\n:::/m
19
+
20
+ # Define shared transformation logic
21
+ transform_proc = proc do |variant, button_content|
22
+ button_content = button_content.strip
23
+
24
+ build_button_html(button_content, variant)
25
+ end
26
+
27
+ # Apply both patterns
28
+ patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
29
+ apply_multiple_patterns(content, patterns)
30
+ end
31
+
32
+ class << self
33
+ private
34
+
35
+ def build_button_html(content, variant)
36
+ variant_attr = variant ? " variant=\"#{variant}\"" : ''
37
+
38
+ # Check if content contains a markdown link
39
+ link_match = content.match(/^\[([^\]]+)\]\(([^)]+)\)$/)
40
+
41
+ if link_match
42
+ # It's a link button
43
+ link_text = link_match[1]
44
+ link_url = link_match[2]
45
+
46
+ # Process any markdown in the link text (bold, italic, etc.)
47
+ button_html = markdown_to_html(link_text).strip
48
+ button_html = button_html.gsub(%r{^<p>(.*)</p>$}m, '\1')
49
+
50
+ # Fix whitespace issues like in badges
51
+ button_html = button_html.gsub(%r{(</\w+>)\s+}, '\1&nbsp;')
52
+
53
+ "<wa-button#{variant_attr} href=\"#{link_url}\">#{button_html}</wa-button>"
54
+ else
55
+ # It's a regular button
56
+ button_html = markdown_to_html(content).strip
57
+ button_html = button_html.gsub(%r{^<p>(.*)</p>$}m, '\1')
58
+
59
+ # Fix whitespace issues like in badges
60
+ button_html = button_html.gsub(%r{(</\w+>)\s+}, '\1&nbsp;')
61
+
62
+ "<wa-button#{variant_attr}>#{button_html}</wa-button>"
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+
5
+ module Jekyll
6
+ module WebAwesome
7
+ # Transforms callout syntax into wa-callout elements
8
+ # Primary syntax: :::variant\ncontent\n:::
9
+ # Alternative syntax: :::wa-callout variant\ncontent\n:::
10
+ # Variants: info, success, neutral, warning, danger
11
+ class CalloutTransformer < BaseTransformer
12
+ def self.transform(content)
13
+ # Define both regex patterns
14
+ primary_regex = /^:::(info|success|neutral|warning|danger)\n(.*?)\n:::/m
15
+ alternative_regex = /^:::wa-callout\s+(info|success|neutral|warning|danger)\n(.*?)\n:::/m
16
+
17
+ # Define shared transformation logic
18
+ transform_proc = proc do |variant, inner_content|
19
+ attrs = callout_attributes(variant)
20
+
21
+ element_tag = "wa-callout#{attrs[:additional_params]}"
22
+ html_content = "#{attrs[:inner_prepend]}#{markdown_to_html(inner_content)}"
23
+
24
+ "<#{element_tag}>#{html_content}</wa-callout>"
25
+ end
26
+
27
+ # Apply both patterns
28
+ patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
29
+ apply_multiple_patterns(content, patterns)
30
+ end
31
+
32
+ class << self
33
+ private
34
+
35
+ def callout_attributes(variant)
36
+ case variant
37
+ when 'info'
38
+ {
39
+ additional_params: ' variant="brand"',
40
+ inner_prepend: '<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>'
41
+ }
42
+ when 'success'
43
+ {
44
+ additional_params: ' variant="success"',
45
+ inner_prepend: '<wa-icon slot="icon" name="circle-check" variant="regular"></wa-icon>'
46
+ }
47
+ when 'neutral'
48
+ {
49
+ additional_params: ' variant="neutral"',
50
+ inner_prepend: '<wa-icon slot="icon" name="gear" variant="regular"></wa-icon>'
51
+ }
52
+ when 'warning'
53
+ {
54
+ additional_params: ' variant="warning"',
55
+ inner_prepend: '<wa-icon slot="icon" name="triangle-exclamation" variant="regular"></wa-icon>'
56
+ }
57
+ when 'danger'
58
+ {
59
+ additional_params: ' variant="danger"',
60
+ inner_prepend: '<wa-icon slot="icon" name="circle-exclamation" variant="regular"></wa-icon>'
61
+ }
62
+ else
63
+ {
64
+ additional_params: '',
65
+ inner_prepend: ''
66
+ }
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+
5
+ module Jekyll
6
+ module WebAwesome
7
+ # Transforms card syntax into wa-card elements
8
+ # Primary syntax: ===appearance?\ncontent\n===
9
+ # Alternative syntax: :::wa-card appearance?\ncontent\n:::
10
+ # Appearances: outlined (default), filled, filled-outlined, plain, accent
11
+ class CardTransformer < BaseTransformer
12
+ def self.transform(content)
13
+ # Define both regex patterns
14
+ primary_regex = /^===(outlined|filled|filled-outlined|plain|accent)?\n(.*?)\n===/m
15
+ alternative_regex = /^:::wa-card\s*(outlined|filled|filled-outlined|plain|accent)?\n(.*?)\n:::/m
16
+
17
+ # Define shared transformation logic
18
+ transform_proc = proc do |appearance_param, card_content|
19
+ card_content = card_content.strip
20
+
21
+ appearance = normalize_appearance(appearance_param)
22
+ card_parts = parse_card_content(card_content)
23
+
24
+ build_card_html(card_parts, appearance)
25
+ end
26
+
27
+ # Apply both patterns
28
+ patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
29
+ apply_multiple_patterns(content, patterns)
30
+ end
31
+
32
+ class << self
33
+ private
34
+
35
+ def normalize_appearance(appearance_param)
36
+ case appearance_param
37
+ when 'filled', 'filled-outlined', 'plain', 'accent'
38
+ appearance_param
39
+ else
40
+ 'outlined' # default
41
+ end
42
+ end
43
+
44
+ def parse_card_content(content)
45
+ parts = {
46
+ media: nil,
47
+ header: nil,
48
+ content: content,
49
+ footer: nil
50
+ }
51
+
52
+ # Extract first image as media
53
+ if content.match(/^!\[([^\]]*)\]\(([^)]+)\)/)
54
+ parts[:media] = {
55
+ alt: ::Regexp.last_match(1),
56
+ src: ::Regexp.last_match(2)
57
+ }
58
+ # Remove the image from content
59
+ content = content.sub(/^!\[([^\]]*)\]\(([^)]+)\)\n?/, '')
60
+ end
61
+
62
+ # Extract first heading as header
63
+ if content.match(/^# (.+)$/)
64
+ parts[:header] = ::Regexp.last_match(1).strip
65
+ # Remove the heading from content
66
+ content = content.sub(/^# .+\n?/, '')
67
+ end
68
+
69
+ # Extract trailing buttons/links as footer
70
+ # Look for links or buttons at the end of the content
71
+ if content.match(/\n\[([^\]]+)\]\(([^)]+)\)\s*$/)
72
+ parts[:footer] = {
73
+ text: ::Regexp.last_match(1),
74
+ href: ::Regexp.last_match(2)
75
+ }
76
+ # Remove the footer link from content
77
+ content = content.sub(/\n\[([^\]]+)\]\(([^)]+)\)\s*$/, '')
78
+ end
79
+
80
+ # Update the main content after extractions
81
+ parts[:content] = content.strip
82
+ parts
83
+ end
84
+
85
+ def build_card_html(parts, appearance)
86
+ attributes = []
87
+ attributes << "appearance=\"#{appearance}\"" if appearance != 'outlined'
88
+
89
+ # Add SSR attributes if slots are present
90
+ attributes << 'with-media' if parts[:media]
91
+ attributes << 'with-header' if parts[:header]
92
+ attributes << 'with-footer' if parts[:footer]
93
+
94
+ attr_string = attributes.empty? ? '' : " #{attributes.join(' ')}"
95
+
96
+ html_parts = []
97
+
98
+ # Media slot
99
+ html_parts << "<img slot=\"media\" src=\"#{parts[:media][:src]}\" alt=\"#{parts[:media][:alt]}\">" if parts[:media]
100
+
101
+ # Header slot
102
+ if parts[:header]
103
+ header_html = markdown_to_html(parts[:header])
104
+ html_parts << "<div slot=\"header\">#{header_html}</div>"
105
+ end
106
+
107
+ # Main content
108
+ if parts[:content] && !parts[:content].empty?
109
+ content_html = markdown_to_html(parts[:content])
110
+ html_parts << content_html
111
+ end
112
+
113
+ # Footer slot
114
+ html_parts << "<div slot=\"footer\"><wa-button href=\"#{parts[:footer][:href]}\">#{parts[:footer][:text]}</wa-button></div>" if parts[:footer]
115
+
116
+ "<wa-card#{attr_string}>#{html_parts.join}</wa-card>"
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+
5
+ module Jekyll
6
+ module WebAwesome
7
+ # Transforms summary/details syntax into wa-details elements
8
+ # Primary syntax: ^^^appearance?\nsummary\n>>>\ndetails\n^^^
9
+ # Alternative syntax: :::wa-details appearance?\nsummary\n>>>\ndetails\n:::
10
+ # Appearances: outlined (default), filled, filled-outlined, plain
11
+ class DetailsTransformer < BaseTransformer
12
+ def self.transform(content)
13
+ # Define both regex patterns
14
+ primary_regex = /^\^\^\^?(outlined|filled|filled-outlined|plain)?\n(.*?)\n^>>>\n(.*?)\n^\^\^\^?/m
15
+ alternative_regex = /^:::wa-details\s*(outlined|filled|filled-outlined|plain)?\n(.*?)\n^>>>\n(.*?)\n:::/m
16
+
17
+ # Define shared transformation logic
18
+ transform_proc = proc do |appearance_param, summary_content, details_content|
19
+ summary_content = summary_content.strip
20
+ details_content = details_content.strip
21
+
22
+ appearance_class = normalize_appearance(appearance_param)
23
+ summary_html = markdown_to_html(summary_content)
24
+ details_html = markdown_to_html(details_content)
25
+
26
+ "<wa-details appearance='#{appearance_class}'>" \
27
+ "<span slot='summary'>#{summary_html}</span>" \
28
+ "#{details_html}</wa-details>"
29
+ end
30
+
31
+ # Apply both patterns
32
+ patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
33
+ apply_multiple_patterns(content, patterns)
34
+ end
35
+
36
+ class << self
37
+ private
38
+
39
+ def normalize_appearance(appearance_param)
40
+ case appearance_param
41
+ when 'filled'
42
+ 'filled'
43
+ when 'filled-outlined'
44
+ 'filled outlined'
45
+ when 'plain'
46
+ 'plain'
47
+ else
48
+ 'outlined'
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+
5
+ module Jekyll
6
+ module WebAwesome
7
+ # Transforms icon syntax into wa-icon elements
8
+ # Primary syntax: $$$icon-name
9
+ # Alternative syntax: :::wa-icon icon-name
10
+ #
11
+ # Examples:
12
+ # $$$settings -> <wa-icon name="settings"></wa-icon>
13
+ # $$$home -> <wa-icon name="home"></wa-icon>
14
+ # $$$user-circle -> <wa-icon name="user-circle"></wa-icon>
15
+ class IconTransformer < BaseTransformer
16
+ def self.transform(content)
17
+ # Protect code blocks first
18
+ protected_content, code_blocks = protect_code_blocks(content)
19
+
20
+ # Apply primary syntax transformation
21
+ # Only block patterns that look like incomplete icon names:
22
+ # $$$icon name (where 'icon name' could be intended as one identifier)
23
+ result = protected_content.gsub(/\$\$\$([a-zA-Z0-9\-_]+)(?![a-zA-Z0-9\-_]|\s+name\b)/) do
24
+ icon_name = ::Regexp.last_match(1)
25
+ build_icon_html(icon_name)
26
+ end
27
+
28
+ # Apply alternative syntax transformation
29
+ result = result.gsub(/:::wa-icon\s+([a-zA-Z0-9\-_]+)\s*\n:::/m) do
30
+ icon_name = ::Regexp.last_match(1)
31
+ build_icon_html(icon_name)
32
+ end
33
+
34
+ # Restore code blocks
35
+ restore_code_blocks(result, code_blocks)
36
+ end
37
+
38
+ class << self
39
+ private
40
+
41
+ def build_icon_html(icon_name)
42
+ # Clean and validate icon name
43
+ clean_name = icon_name.strip
44
+
45
+ # Return the wa-icon element
46
+ "<wa-icon name=\"#{clean_name}\"></wa-icon>"
47
+ end
48
+
49
+ def protect_code_blocks(content)
50
+ code_blocks = {}
51
+ counter = 0
52
+
53
+ # Protect fenced code blocks
54
+ protected = content.gsub(/```.*?```/m) do |match|
55
+ placeholder = "ICON_PROTECTED_CODE_BLOCK_#{counter}"
56
+ code_blocks[placeholder] = match
57
+ counter += 1
58
+ placeholder
59
+ end
60
+
61
+ # Protect inline code
62
+ protected = protected.gsub(/`[^`]+`/) do |match|
63
+ placeholder = "ICON_PROTECTED_INLINE_CODE_#{counter}"
64
+ code_blocks[placeholder] = match
65
+ counter += 1
66
+ placeholder
67
+ end
68
+
69
+ [protected, code_blocks]
70
+ end
71
+
72
+ def restore_code_blocks(content, code_blocks)
73
+ result = content
74
+ code_blocks.each do |placeholder, original|
75
+ result = result.gsub(placeholder, original)
76
+ end
77
+ result
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+
5
+ module Jekyll
6
+ module WebAwesome
7
+ # Transforms tabs syntax into wa-tab-group elements
8
+ # Primary syntax: ++++++placement?\n+++tab1\ncontent\n+++\n+++tab2\ncontent\n+++\n++++++
9
+ # Alternative syntax: :::wa-tabs placement?\n+++tab1\ncontent\n+++\n+++tab2\ncontent\n+++\n:::
10
+ # Placements: top (default), bottom, start, end
11
+ class TabsTransformer < BaseTransformer
12
+ def self.transform(content)
13
+ # Define both regex patterns
14
+ primary_regex = /^\+{6}(top|bottom|start|end)?\n((\+\+\+ [^\n]+\n.*?\n\+\+\+\n?)+)\+{6}/m
15
+ alternative_regex = /^:::wa-tabs\s*(top|bottom|start|end)?\n((\+\+\+ [^\n]+\n.*?\n\+\+\+\n?)+):::/m
16
+
17
+ # Define shared transformation logic
18
+ transform_proc = proc do |placement, tabs_block, _third_capture|
19
+ placement ||= 'top'
20
+
21
+ tabs, tab_panels = extract_tabs_and_panels(tabs_block)
22
+
23
+ "<wa-tab-group placement=\"#{placement}\">#{tabs.join}#{tab_panels.join}</wa-tab-group>"
24
+ end
25
+
26
+ # Apply both patterns
27
+ patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
28
+ apply_multiple_patterns(content, patterns)
29
+ end
30
+
31
+ class << self
32
+ private
33
+
34
+ def extract_tabs_and_panels(tabs_block)
35
+ # Extract individual tabs
36
+ tab_contents = tabs_block.scan(/^\+\+\+ ([^\n]+)\n(.*?)\n\+\+\+/m)
37
+ tabs = []
38
+ tab_panels = []
39
+
40
+ tab_contents.each_with_index do |(title, panel_content), index|
41
+ tab_id = "tab-#{index + 1}"
42
+ tabs << "<wa-tab panel=\"#{tab_id}\">#{title.strip}</wa-tab>"
43
+
44
+ panel_html = markdown_to_html(panel_content.strip)
45
+ tab_panels << "<wa-tab-panel name=\"#{tab_id}\">#{panel_html}</wa-tab-panel>"
46
+ end
47
+
48
+ [tabs, tab_panels]
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_transformer'
4
+
5
+ module Jekyll
6
+ module WebAwesome
7
+ # Transforms tag syntax into wa-tag elements
8
+ # Primary syntax: @@@variant?\ncontent\n@@@
9
+ # Alternative syntax: :::wa-tag variant?\ncontent\n:::
10
+ # Variants: brand, success, neutral, warning, danger
11
+ class TagTransformer < BaseTransformer
12
+ def self.transform(content)
13
+ # Define both regex patterns
14
+ primary_regex = /^@@@(brand|success|neutral|warning|danger)?\n(.*?)\n@@@/m
15
+ alternative_regex = /^:::wa-tag\s*(brand|success|neutral|warning|danger)?\n(.*?)\n:::/m
16
+
17
+ # Define shared transformation logic
18
+ transform_proc = proc do |variant, tag_content|
19
+ tag_content = tag_content.strip
20
+
21
+ build_tag_html(tag_content, variant)
22
+ end
23
+
24
+ # Apply both patterns
25
+ patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
26
+ apply_multiple_patterns(content, patterns)
27
+ end
28
+
29
+ class << self
30
+ private
31
+
32
+ def build_tag_html(content, variant)
33
+ variant_attr = variant ? " variant=\"#{variant}\"" : ''
34
+ tag_html = markdown_to_html(content).strip
35
+
36
+ # Remove paragraph tags if the content is just text
37
+ tag_html = tag_html.gsub(%r{^<p>(.*)</p>$}m, '\1')
38
+
39
+ "<wa-tag#{variant_attr}>#{tag_html}</wa-tag>"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Index file for all Web Awesome transformers
4
+ # This file makes it easy to require all transformers at once
5
+
6
+ require_relative 'transformers/base_transformer'
7
+ require_relative 'transformers/badge_transformer'
8
+ require_relative 'transformers/button_transformer'
9
+ require_relative 'transformers/callout_transformer'
10
+ require_relative 'transformers/card_transformer'
11
+ require_relative 'transformers/details_transformer'
12
+ require_relative 'transformers/icon_transformer'
13
+ require_relative 'transformers/tabs_transformer'
14
+ require_relative 'transformers/tag_transformer'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module WebAwesome
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'webawesome/version'
4
+ require_relative 'webawesome/transformer'
5
+ require_relative 'webawesome/code_block_transformer'
6
+ require_relative 'webawesome/plugin'
7
+
8
+ module Jekyll
9
+ # Main module for Jekyll WebAwesome plugin
10
+ module WebAwesome
11
+ class Error < StandardError; end
12
+
13
+ # Configuration options
14
+ class << self
15
+ attr_accessor :configuration
16
+
17
+ def configure
18
+ self.configuration ||= Configuration.new
19
+ yield(configuration) if block_given?
20
+ configuration
21
+ end
22
+ end
23
+
24
+ # Configuration class for future extensibility
25
+ class Configuration
26
+ attr_accessor :debug_mode, :callout_icons, :custom_components
27
+
28
+ def initialize
29
+ @debug_mode = false
30
+ @callout_icons = default_callout_icons
31
+ @custom_components = {}
32
+ end
33
+
34
+ private
35
+
36
+ def default_callout_icons
37
+ {
38
+ info: 'circle-info',
39
+ success: 'circle-check',
40
+ neutral: 'gear',
41
+ warning: 'triangle-exclamation',
42
+ danger: 'circle-exclamation'
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'jekyll_webawesome'
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'jekyll/webawesome'