jekyll-webawesome 0.6.1 → 0.7.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.
@@ -1,72 +0,0 @@
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="solid"></wa-icon>'
41
- }
42
- when 'success'
43
- {
44
- additional_params: ' variant="success"',
45
- inner_prepend: '<wa-icon slot="icon" name="circle-check" variant="solid"></wa-icon>'
46
- }
47
- when 'neutral'
48
- {
49
- additional_params: ' variant="neutral"',
50
- inner_prepend: '<wa-icon slot="icon" name="gear" variant="solid"></wa-icon>'
51
- }
52
- when 'warning'
53
- {
54
- additional_params: ' variant="warning"',
55
- inner_prepend: '<wa-icon slot="icon" name="triangle-exclamation" variant="solid"></wa-icon>'
56
- }
57
- when 'danger'
58
- {
59
- additional_params: ' variant="danger"',
60
- inner_prepend: '<wa-icon slot="icon" name="circle-exclamation" variant="solid"></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
@@ -1,121 +0,0 @@
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
@@ -1,129 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_transformer'
4
-
5
- module Jekyll
6
- module WebAwesome
7
- # Transforms carousel syntax into wa-carousel elements
8
- # Primary syntax: ~~~~~~params\n~~~ slide1\ncontent\n~~~\n~~~ slide2\ncontent\n~~~\n~~~~~~
9
- # Alternative syntax: :::wa-carousel params\n~~~ slide1\ncontent\n~~~\n~~~ slide2\ncontent\n~~~\n:::
10
- # Params can include: numbers (slides-per-page, slides-per-move), keywords (loop, navigation, pagination,
11
- # autoplay, mouse-dragging, vertical), and CSS properties (scroll-hint:value, aspect-ratio:value, slide-gap:value)
12
- class CarouselTransformer < BaseTransformer
13
- def self.transform(content)
14
- # Define both regex patterns
15
- # Match: ~~~~~~params (optional)
16
- # ~~~
17
- # content (can be empty)
18
- # ~~~
19
- # (repeat slides)
20
- # ~~~~~~
21
- primary_regex = /^~{6}([^\n]*)\n((?:~~~\n(?:.*?\n)?~~~\n?)+)~{6}/m
22
- alternative_regex = /^:::wa-carousel\s*([^\n]*)\n((?:~~~\n(?:.*?\n)?~~~\n?)+):::/m
23
-
24
- # Define shared transformation logic
25
- transform_proc = proc do |params, slides_block, _third_capture|
26
- parsed_params = parse_params(params)
27
- slides = extract_slides(slides_block)
28
-
29
- build_carousel_html(slides, parsed_params)
30
- end
31
-
32
- # Apply both patterns
33
- patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
34
- apply_multiple_patterns(content, patterns)
35
- end
36
-
37
- class << self
38
- private
39
-
40
- def parse_params(params)
41
- return {} if params.nil? || params.strip.empty?
42
-
43
- result = {
44
- attributes: {},
45
- css_vars: {}
46
- }
47
-
48
- tokens = params.strip.split(/\s+/)
49
- numeric_count = 0
50
-
51
- tokens.each do |token|
52
- # Check for CSS custom properties (key:value)
53
- if token.include?(':')
54
- key, value = token.split(':', 2)
55
- case key
56
- when 'scroll-hint'
57
- result[:css_vars]['--scroll-hint'] = value
58
- when 'aspect-ratio'
59
- # Support 'auto', 'none', or 'unset' to remove the default aspect ratio
60
- # This is useful for text content or variable-height slides
61
- result[:css_vars]['--aspect-ratio'] = value
62
- when 'slide-gap'
63
- result[:css_vars]['--slide-gap'] = value
64
- end
65
- # Check for numeric values
66
- elsif token.match?(/^\d+$/)
67
- numeric_count += 1
68
- if numeric_count == 1
69
- result[:attributes]['slides-per-page'] = token
70
- elsif numeric_count == 2
71
- result[:attributes]['slides-per-move'] = token
72
- end
73
- # Check for boolean flags
74
- elsif %w[loop navigation pagination autoplay mouse-dragging vertical].include?(token)
75
- # For orientation, we need to handle it specially
76
- if token == 'vertical'
77
- result[:attributes]['orientation'] = 'vertical'
78
- else
79
- result[:attributes][token] = true
80
- end
81
- end
82
- end
83
-
84
- result
85
- end
86
-
87
- def extract_slides(slides_block)
88
- # Extract individual slides using ~~~ markers
89
- # Handle both content and empty slides
90
- slide_contents = slides_block.scan(/~~~\n(.*?)~~~(?:\n|$)/m)
91
- slide_contents.map { |match| match[0].strip }
92
- end
93
-
94
- def build_carousel_html(slides, parsed_params)
95
- attributes = build_attributes(parsed_params[:attributes] || {})
96
- style = build_style(parsed_params[:css_vars] || {})
97
-
98
- attr_string = attributes.empty? ? '' : " #{attributes.join(' ')}"
99
- style_string = style.empty? ? '' : " style=\"#{style}\""
100
-
101
- slide_items = slides.map do |slide_content|
102
- slide_html = markdown_to_html(slide_content)
103
- "<wa-carousel-item>#{slide_html}</wa-carousel-item>"
104
- end
105
-
106
- "<wa-carousel#{attr_string}#{style_string}>#{slide_items.join}</wa-carousel>"
107
- end
108
-
109
- def build_attributes(attrs)
110
- return [] if attrs.nil? || attrs.empty?
111
-
112
- attrs.map do |key, value|
113
- if value == true
114
- key
115
- else
116
- "#{key}=\"#{value}\""
117
- end
118
- end
119
- end
120
-
121
- def build_style(css_vars)
122
- return '' if css_vars.nil? || css_vars.empty?
123
-
124
- css_vars.map { |key, value| "#{key}: #{value}" }.join('; ')
125
- end
126
- end
127
- end
128
- end
129
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_transformer'
4
-
5
- module Jekyll
6
- module WebAwesome
7
- # Transforms comparison syntax into wa-comparison elements
8
- # Primary syntax: |||\n![before](before.jpg)\n![after](after.jpg)\n|||
9
- # Primary syntax with position: |||50\n![before](before.jpg)\n![after](after.jpg)\n|||
10
- # Alternative syntax: :::wa-comparison\n![before](before.jpg)\n![after](after.jpg)\n:::
11
- # Alternative syntax with position: :::wa-comparison 50\n![before](before.jpg)\n![after](after.jpg)\n:::
12
- # Expects exactly two image elements inside the wrapper
13
- class ComparisonTransformer < BaseTransformer
14
- def self.transform(content)
15
- # Process primary syntax
16
- content = content.gsub(/^\|\|\|(\d+)?\n(.*?)\n\|\|\|/m) do |match|
17
- position = Regexp.last_match(1)
18
- inner_content = Regexp.last_match(2).strip
19
- images = extract_images(inner_content)
20
-
21
- if images.length == 2
22
- build_comparison_html(inner_content, position)
23
- else
24
- match # Return original match if not exactly 2 images
25
- end
26
- end
27
-
28
- # Process alternative syntax
29
- content.gsub(/^:::wa-comparison\s*(\d+)?\n(.*?)\n:::/m) do |match|
30
- position = Regexp.last_match(1)
31
- inner_content = Regexp.last_match(2).strip
32
- images = extract_images(inner_content)
33
-
34
- if images.length == 2
35
- build_comparison_html(inner_content, position)
36
- else
37
- match # Return original match if not exactly 2 images
38
- end
39
- end
40
- end
41
-
42
- class << self
43
- private
44
-
45
- def build_comparison_html(content, position = nil)
46
- images = extract_images(content)
47
-
48
- before_image = build_image_html(images[0], 'before')
49
- after_image = build_image_html(images[1], 'after')
50
-
51
- position_attr = position ? " position=\"#{position}\"" : ''
52
-
53
- "<wa-comparison#{position_attr}>#{before_image}#{after_image}</wa-comparison>"
54
- end
55
-
56
- def extract_images(content)
57
- # Extract markdown image syntax: ![alt](url)
58
- image_regex = /!\[([^\]]*)\]\(([^)]+)\)/
59
- content.scan(image_regex)
60
- end
61
-
62
- def build_image_html(image_match, slot)
63
- alt_text = image_match[0]
64
- src = image_match[1]
65
-
66
- # Escape HTML characters in alt text
67
- escaped_alt = alt_text.gsub('&', '&amp;').gsub('"', '&quot;').gsub('<', '&lt;').gsub('>', '&gt;')
68
-
69
- "<img slot=\"#{slot}\" src=\"#{src}\" alt=\"#{escaped_alt}\" />"
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base_transformer'
4
-
5
- module Jekyll
6
- module WebAwesome
7
- # Transforms copy button syntax into wa-copy-button elements
8
- # Primary syntax: <<<\ncontent\n<<<
9
- # Alternative syntax: :::wa-copy-button\ncontent\n:::
10
- #
11
- # Usage:
12
- # <<<
13
- # This text will be copied to clipboard
14
- # <<<
15
- #
16
- # :::wa-copy-button
17
- # Copy this text
18
- # :::
19
- class CopyButtonTransformer < BaseTransformer
20
- def self.transform(content)
21
- # Define both regex patterns
22
- primary_regex = /^<<<\n(.*?)\n<<</m
23
- alternative_regex = /^:::wa-copy-button\n(.*?)\n:::/m
24
-
25
- # Define shared transformation logic
26
- transform_proc = proc do |copy_content|
27
- copy_content = copy_content.strip
28
-
29
- build_copy_button_html(copy_content)
30
- end
31
-
32
- # Apply both patterns
33
- patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
34
- apply_multiple_patterns(content, patterns)
35
- end
36
-
37
- class << self
38
- private
39
-
40
- def build_copy_button_html(content)
41
- # Escape the content for the value attribute
42
- escaped_content = content.gsub('"', '&quot;').gsub("'", '&#39;')
43
-
44
- "<wa-copy-button value=\"#{escaped_content}\"></wa-copy-button>"
45
- end
46
- end
47
- end
48
- end
49
- end
@@ -1,85 +0,0 @@
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? icon-placement?\nsummary\n>>>\ndetails\n^^^
9
- # Alternative syntax: :::wa-details appearance? icon-placement?\nsummary\n>>>\ndetails\n:::
10
- # Appearances: outlined (default), filled, filled-outlined, plain
11
- # Icon placement: start, end (default)
12
- class DetailsTransformer < BaseTransformer
13
- def self.transform(content)
14
- # Define both regex patterns - capture parameter string
15
- primary_regex = /^\^\^\^?(.*?)\n(.*?)\n^>>>\n(.*?)\n^\^\^\^?/m
16
- alternative_regex = /^:::wa-details\s*(.*?)\n(.*?)\n^>>>\n(.*?)\n:::/m
17
-
18
- # Define shared transformation logic
19
- transform_proc = proc do |params_string, summary_content, details_content|
20
- summary_content = summary_content.strip
21
- details_content = details_content.strip
22
-
23
- # Parse parameters from the params string
24
- appearance_param, icon_placement_param = parse_parameters(params_string)
25
-
26
- appearance_class = normalize_appearance(appearance_param)
27
- icon_placement = normalize_icon_placement(icon_placement_param)
28
- summary_html = markdown_to_html(summary_content)
29
- details_html = markdown_to_html(details_content)
30
-
31
- "<wa-details appearance='#{appearance_class}' icon-placement='#{icon_placement}'>" \
32
- "<span slot='summary'>#{summary_html}</span>" \
33
- "#{details_html}</wa-details>"
34
- end
35
-
36
- # Apply both patterns
37
- patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
38
- apply_multiple_patterns(content, patterns)
39
- end
40
-
41
- class << self
42
- private
43
-
44
- def parse_parameters(params_string)
45
- return [nil, nil] if params_string.nil? || params_string.strip.empty?
46
-
47
- # Split by whitespace and extract known parameters
48
- tokens = params_string.strip.split(/\s+/)
49
-
50
- appearance_options = %w[outlined filled filled-outlined plain]
51
- placement_options = %w[start end]
52
-
53
- appearance_param = tokens.find { |token| appearance_options.include?(token) }
54
- icon_placement_param = tokens.find { |token| placement_options.include?(token) }
55
-
56
- [appearance_param, icon_placement_param]
57
- end
58
-
59
- def normalize_appearance(appearance_param)
60
- case appearance_param
61
- when 'filled'
62
- 'filled'
63
- when 'filled-outlined'
64
- 'filled outlined'
65
- when 'plain'
66
- 'plain'
67
- else
68
- 'outlined'
69
- end
70
- end
71
-
72
- def normalize_icon_placement(icon_placement_param)
73
- case icon_placement_param
74
- when 'start'
75
- 'start'
76
- when 'end'
77
- 'end'
78
- else
79
- 'end'
80
- end
81
- end
82
- end
83
- end
84
- end
85
- end