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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -0
- data/README.md +0 -15
- data/jekyll-webawesome.gemspec +1 -1
- data/lib/jekyll/webawesome/code_block_transformer.rb +46 -43
- data/lib/jekyll/webawesome/plugin.rb +49 -13
- data/lib/jekyll/webawesome/version.rb +1 -1
- data/lib/jekyll/webawesome.rb +13 -1
- metadata +4 -20
- data/lib/jekyll/webawesome/transformer.rb +0 -31
- data/lib/jekyll/webawesome/transformers/badge_transformer.rb +0 -48
- data/lib/jekyll/webawesome/transformers/base_transformer.rb +0 -65
- data/lib/jekyll/webawesome/transformers/button_transformer.rb +0 -68
- data/lib/jekyll/webawesome/transformers/callout_transformer.rb +0 -72
- data/lib/jekyll/webawesome/transformers/card_transformer.rb +0 -121
- data/lib/jekyll/webawesome/transformers/carousel_transformer.rb +0 -129
- data/lib/jekyll/webawesome/transformers/comparison_transformer.rb +0 -74
- data/lib/jekyll/webawesome/transformers/copy_button_transformer.rb +0 -49
- data/lib/jekyll/webawesome/transformers/details_transformer.rb +0 -85
- data/lib/jekyll/webawesome/transformers/dialog_transformer.rb +0 -175
- data/lib/jekyll/webawesome/transformers/icon_transformer.rb +0 -82
- data/lib/jekyll/webawesome/transformers/image_dialog_transformer.rb +0 -174
- data/lib/jekyll/webawesome/transformers/tabs_transformer.rb +0 -53
- data/lib/jekyll/webawesome/transformers/tag_transformer.rb +0 -58
- data/lib/jekyll/webawesome/transformers.rb +0 -19
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'digest'
|
|
4
|
-
require_relative 'base_transformer'
|
|
5
|
-
|
|
6
|
-
module Jekyll
|
|
7
|
-
module WebAwesome
|
|
8
|
-
# Transforms dialog syntax into wa-dialog elements with trigger buttons
|
|
9
|
-
# Primary syntax: ???params\nbutton text\n>>>\ncontent\n???
|
|
10
|
-
# Alternative syntax: :::wa-dialog params\nbutton text\n>>>\ncontent\n:::
|
|
11
|
-
# Params: light-dismiss and optional width (e.g., 500px, 50vw, 40em)
|
|
12
|
-
# Note: Header with close X button is always enabled for accessibility
|
|
13
|
-
class DialogTransformer < BaseTransformer
|
|
14
|
-
def self.transform(content)
|
|
15
|
-
# Define both regex patterns - capture parameter string, button text, and content
|
|
16
|
-
# Params are on the same line as the opening delimiter
|
|
17
|
-
# Button text is on the next line(s) until >>>
|
|
18
|
-
# Content is everything after >>> until the closing delimiter
|
|
19
|
-
primary_regex = /^\?\?\?([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^\?\?\?$/m
|
|
20
|
-
alternative_regex = /^:::wa-dialog([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^:::$/m
|
|
21
|
-
|
|
22
|
-
# Define shared transformation logic
|
|
23
|
-
transform_proc = proc do |params_string, button_text, dialog_content|
|
|
24
|
-
button_text = button_text.strip
|
|
25
|
-
dialog_content = dialog_content.strip
|
|
26
|
-
|
|
27
|
-
# Parse parameters
|
|
28
|
-
light_dismiss, width = parse_parameters(params_string)
|
|
29
|
-
|
|
30
|
-
# Extract label from first heading or use button text
|
|
31
|
-
label, content_without_label = extract_label(dialog_content, button_text)
|
|
32
|
-
|
|
33
|
-
# Generate unique ID based on content
|
|
34
|
-
dialog_id = generate_dialog_id(button_text, dialog_content)
|
|
35
|
-
|
|
36
|
-
# Convert markdown to HTML
|
|
37
|
-
content_html = markdown_to_html(content_without_label)
|
|
38
|
-
|
|
39
|
-
# Build the dialog HTML
|
|
40
|
-
build_dialog_html(dialog_id, button_text, label, content_html,
|
|
41
|
-
light_dismiss, width)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Apply both patterns
|
|
45
|
-
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
46
|
-
apply_multiple_patterns(content, patterns)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
class << self
|
|
50
|
-
private
|
|
51
|
-
|
|
52
|
-
# Parse parameters from the params string
|
|
53
|
-
def parse_parameters(params_string)
|
|
54
|
-
return [false, nil] if params_string.nil? || params_string.strip.empty?
|
|
55
|
-
|
|
56
|
-
tokens = params_string.strip.split(/\s+/)
|
|
57
|
-
|
|
58
|
-
light_dismiss = tokens.include?('light-dismiss')
|
|
59
|
-
|
|
60
|
-
# Look for width parameter (last token with CSS units)
|
|
61
|
-
width = nil
|
|
62
|
-
tokens.reverse_each do |token|
|
|
63
|
-
if token.match?(/^\d+(\.\d+)?(px|em|rem|vw|vh|%|ch)$/)
|
|
64
|
-
width = token
|
|
65
|
-
break
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
[light_dismiss, width]
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Extract label from first heading in content
|
|
73
|
-
# Always returns a label - uses heading if available, otherwise default_label
|
|
74
|
-
def extract_label(content, default_label)
|
|
75
|
-
# Check if content starts with a heading
|
|
76
|
-
if content.match(/^#\s+(.+?)$/)
|
|
77
|
-
label = Regexp.last_match(1).strip
|
|
78
|
-
# Remove the heading from content
|
|
79
|
-
content_without_label = content.sub(/^#\s+.+?\n/, '').strip
|
|
80
|
-
[label, content_without_label]
|
|
81
|
-
else
|
|
82
|
-
# Use default label (button text) to ensure header is always shown
|
|
83
|
-
[default_label, content]
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Generate a unique ID for the dialog using MD5 hash
|
|
88
|
-
def generate_dialog_id(button_text, content)
|
|
89
|
-
hash_input = "#{button_text}#{content}"
|
|
90
|
-
hash = Digest::MD5.hexdigest(hash_input)
|
|
91
|
-
"dialog-#{hash[0..7]}" # Use first 8 characters of hash
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Build the complete dialog HTML with trigger button
|
|
95
|
-
# Header with X close button is always enabled for accessibility
|
|
96
|
-
def build_dialog_html(dialog_id, button_text, label, content_html,
|
|
97
|
-
light_dismiss, width)
|
|
98
|
-
# Build dialog attributes
|
|
99
|
-
dialog_attrs = ["id='#{dialog_id}'"]
|
|
100
|
-
# Escape both HTML and attribute characters for label
|
|
101
|
-
# Header is always shown to provide the X close button
|
|
102
|
-
dialog_attrs << "label='#{escape_attribute(escape_html(label))}'"
|
|
103
|
-
dialog_attrs << 'light-dismiss' if light_dismiss
|
|
104
|
-
|
|
105
|
-
# Build style attribute for width if specified
|
|
106
|
-
style_attr = width ? " style='--width: #{width}'" : ''
|
|
107
|
-
|
|
108
|
-
# Check if button contains an image (for image dialog support)
|
|
109
|
-
is_image_button = button_text.include?('<img')
|
|
110
|
-
|
|
111
|
-
# Build the HTML
|
|
112
|
-
html = []
|
|
113
|
-
|
|
114
|
-
# Add CSS Parts styling for image buttons to make them invisible
|
|
115
|
-
if is_image_button
|
|
116
|
-
button_id = "#{dialog_id}-btn"
|
|
117
|
-
html << '<style>'
|
|
118
|
-
html << " ##{button_id}::part(base) {"
|
|
119
|
-
html << ' padding: 0;'
|
|
120
|
-
html << ' margin: 0;'
|
|
121
|
-
html << ' border: none;'
|
|
122
|
-
html << ' background: transparent;'
|
|
123
|
-
html << ' box-shadow: none;'
|
|
124
|
-
html << ' color: inherit;'
|
|
125
|
-
html << ' min-width: 0;'
|
|
126
|
-
html << ' height: auto;'
|
|
127
|
-
html << ' }'
|
|
128
|
-
html << " ##{button_id}::part(base):hover {"
|
|
129
|
-
html << ' background: transparent;'
|
|
130
|
-
html << ' border-color: transparent;'
|
|
131
|
-
html << ' }'
|
|
132
|
-
html << " ##{button_id}::part(base):active {"
|
|
133
|
-
html << ' background: transparent;'
|
|
134
|
-
html << ' border-color: transparent;'
|
|
135
|
-
html << ' }'
|
|
136
|
-
html << '</style>'
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# Trigger button
|
|
140
|
-
# Only allow HTML for image tags (for image dialog support), escape everything else for security
|
|
141
|
-
button_content = is_image_button ? button_text : escape_html(button_text)
|
|
142
|
-
button_id_attr = is_image_button ? " id='#{button_id}'" : ''
|
|
143
|
-
button_variant = is_image_button ? " variant='text'" : ''
|
|
144
|
-
html << "<wa-button#{button_id_attr}#{button_variant} data-dialog='open #{dialog_id}'>#{button_content}</wa-button>"
|
|
145
|
-
|
|
146
|
-
# Dialog element
|
|
147
|
-
html << "<wa-dialog #{dialog_attrs.join(' ')}#{style_attr}>"
|
|
148
|
-
html << content_html
|
|
149
|
-
|
|
150
|
-
# Footer with close button
|
|
151
|
-
html << "<wa-button slot='footer' variant='primary' data-dialog='close'>Close</wa-button>"
|
|
152
|
-
|
|
153
|
-
html << '</wa-dialog>'
|
|
154
|
-
|
|
155
|
-
html.join("\n")
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
# Escape HTML entities in text
|
|
159
|
-
def escape_html(text)
|
|
160
|
-
text.gsub('&', '&')
|
|
161
|
-
.gsub('<', '<')
|
|
162
|
-
.gsub('>', '>')
|
|
163
|
-
.gsub('"', '"')
|
|
164
|
-
.gsub("'", ''')
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
# Escape attribute values
|
|
168
|
-
def escape_attribute(text)
|
|
169
|
-
text.gsub("'", ''')
|
|
170
|
-
.gsub('"', '"')
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
end
|
|
@@ -1,82 +0,0 @@
|
|
|
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
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'digest'
|
|
4
|
-
require_relative 'base_transformer'
|
|
5
|
-
|
|
6
|
-
module Jekyll
|
|
7
|
-
module WebAwesome
|
|
8
|
-
# Transforms standalone images into clickable images that open in dialogs
|
|
9
|
-
# Images can opt-out by adding "nodialog" to the title attribute
|
|
10
|
-
# Example: 
|
|
11
|
-
class ImageDialogTransformer < BaseTransformer
|
|
12
|
-
def self.transform(content, site = nil)
|
|
13
|
-
# Get configuration including default width
|
|
14
|
-
config = site ? Plugin.image_dialog_config(site) : {}
|
|
15
|
-
|
|
16
|
-
# First, protect code blocks, inline code, and comparison blocks from transformation
|
|
17
|
-
protected_content, fenced_code_blocks = protect_fenced_code_blocks(content)
|
|
18
|
-
protected_content, inline_code_blocks = protect_inline_code(protected_content)
|
|
19
|
-
protected_content, comparison_blocks = protect_comparisons(protected_content)
|
|
20
|
-
|
|
21
|
-
# Match markdown images:  or 
|
|
22
|
-
# Capture alt text, URL, and optional title
|
|
23
|
-
# URL can contain spaces and special characters
|
|
24
|
-
image_regex = /!\[([^\]]*)\]\(([^)]+?)(?:\s+"([^"]*)")?\)/
|
|
25
|
-
|
|
26
|
-
result = protected_content.gsub(image_regex) do |match|
|
|
27
|
-
alt_text = Regexp.last_match(1)
|
|
28
|
-
image_url = Regexp.last_match(2).strip
|
|
29
|
-
title = Regexp.last_match(3)
|
|
30
|
-
|
|
31
|
-
# Skip transformation if title contains "nodialog"
|
|
32
|
-
if title&.include?('nodialog')
|
|
33
|
-
# Return original image without dialog
|
|
34
|
-
match
|
|
35
|
-
else
|
|
36
|
-
# Transform to clickable image with dialog
|
|
37
|
-
transform_to_dialog(alt_text, image_url, title, config)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Restore protected blocks in reverse order
|
|
42
|
-
result = restore_comparisons(result, comparison_blocks)
|
|
43
|
-
result = restore_inline_code(result, inline_code_blocks)
|
|
44
|
-
restore_fenced_code_blocks(result, fenced_code_blocks)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
class << self
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
# Protect fenced code blocks from transformation
|
|
51
|
-
def protect_fenced_code_blocks(content)
|
|
52
|
-
code_blocks = []
|
|
53
|
-
# Match both ``` and ~~~ style code blocks with optional language
|
|
54
|
-
protected = content.gsub(/^```.*?^```$|^~~~.*?^~~~$/m) do |match|
|
|
55
|
-
placeholder = "<!--IMAGE_DIALOG_FENCED_CODE_#{code_blocks.length}-->"
|
|
56
|
-
code_blocks << match
|
|
57
|
-
placeholder
|
|
58
|
-
end
|
|
59
|
-
[protected, code_blocks]
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# Restore protected fenced code blocks
|
|
63
|
-
def restore_fenced_code_blocks(content, code_blocks)
|
|
64
|
-
code_blocks.each_with_index do |code, index|
|
|
65
|
-
content = content.gsub("<!--IMAGE_DIALOG_FENCED_CODE_#{index}-->", code)
|
|
66
|
-
end
|
|
67
|
-
content
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Protect inline code from transformation
|
|
71
|
-
def protect_inline_code(content)
|
|
72
|
-
code_blocks = []
|
|
73
|
-
protected = content.gsub(/`[^`]+`/) do |match|
|
|
74
|
-
placeholder = "<!--IMAGE_DIALOG_INLINE_CODE_#{code_blocks.length}-->"
|
|
75
|
-
code_blocks << match
|
|
76
|
-
placeholder
|
|
77
|
-
end
|
|
78
|
-
[protected, code_blocks]
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Restore protected inline code
|
|
82
|
-
def restore_inline_code(content, code_blocks)
|
|
83
|
-
code_blocks.each_with_index do |code, index|
|
|
84
|
-
content = content.gsub("<!--IMAGE_DIALOG_INLINE_CODE_#{index}-->", code)
|
|
85
|
-
end
|
|
86
|
-
content
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Protect comparison blocks from image transformation
|
|
90
|
-
# Must protect both markdown syntax (|||...|||) and already-transformed HTML
|
|
91
|
-
def protect_comparisons(content)
|
|
92
|
-
comparison_blocks = []
|
|
93
|
-
|
|
94
|
-
# First protect markdown comparison syntax: |||...|||
|
|
95
|
-
protected = content.gsub(/\|\|\|(\d+)?\n.*?\n\|\|\|/m) do |match|
|
|
96
|
-
placeholder = "<!--IMAGE_DIALOG_COMPARISON_#{comparison_blocks.length}-->"
|
|
97
|
-
comparison_blocks << match
|
|
98
|
-
placeholder
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# Also protect already-transformed HTML comparison blocks: <wa-comparison ...>...</wa-comparison>
|
|
102
|
-
protected = protected.gsub(/<wa-comparison[^>]*>.*?<\/wa-comparison>/m) do |match|
|
|
103
|
-
placeholder = "<!--IMAGE_DIALOG_COMPARISON_#{comparison_blocks.length}-->"
|
|
104
|
-
comparison_blocks << match
|
|
105
|
-
placeholder
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
[protected, comparison_blocks]
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Restore protected comparison blocks
|
|
112
|
-
def restore_comparisons(content, comparison_blocks)
|
|
113
|
-
comparison_blocks.each_with_index do |block, index|
|
|
114
|
-
content = content.gsub("<!--IMAGE_DIALOG_COMPARISON_#{index}-->", block)
|
|
115
|
-
end
|
|
116
|
-
content
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Transform image into our custom dialog syntax
|
|
120
|
-
# This will be processed by DialogTransformer to create the actual wa-dialog
|
|
121
|
-
def transform_to_dialog(alt_text, image_url, title, config = {})
|
|
122
|
-
# Parse width from title if specified (e.g., "50%", "800px", "60vw")
|
|
123
|
-
width = extract_width_from_title(title)
|
|
124
|
-
|
|
125
|
-
# Use default width from config if no width specified in title
|
|
126
|
-
width ||= config[:default_width] if config[:default_width]
|
|
127
|
-
|
|
128
|
-
# Build dialog parameters
|
|
129
|
-
# Always include header with X close button for accessibility
|
|
130
|
-
params = ['light-dismiss']
|
|
131
|
-
params << width if width
|
|
132
|
-
params_string = params.join(' ')
|
|
133
|
-
|
|
134
|
-
# Build the button content - a styled image that acts as the trigger
|
|
135
|
-
# Add title attribute if provided and doesn't contain "nodialog" or width
|
|
136
|
-
title_attr = title && !title.include?('nodialog') && !contains_width?(title) ? " title=\"#{title}\"" : ''
|
|
137
|
-
button_content = "<img src=\"#{image_url}\" alt=\"#{alt_text}\" style=\"cursor: zoom-in; display: block; width: 100%; height: auto;\"#{title_attr} />"
|
|
138
|
-
|
|
139
|
-
# Build the dialog content with alt text as heading for the label
|
|
140
|
-
# Use alt text for the label, or "Image" as fallback if alt is empty
|
|
141
|
-
label_text = alt_text.empty? ? 'Image' : alt_text
|
|
142
|
-
dialog_content = "# #{label_text}\n\n<img src=\"#{image_url}\" alt=\"#{alt_text}\" style=\"max-width: 100%; height: auto; display: block; margin: 0 auto;\" />"
|
|
143
|
-
|
|
144
|
-
# Use our custom dialog syntax that will be processed by DialogTransformer
|
|
145
|
-
# Format: ???params\nbutton_content\n>>>\ndialog_content\n???
|
|
146
|
-
result = []
|
|
147
|
-
result << "???#{params_string}"
|
|
148
|
-
result << button_content
|
|
149
|
-
result << '>>>'
|
|
150
|
-
result << dialog_content
|
|
151
|
-
result << '???'
|
|
152
|
-
|
|
153
|
-
result.join("\n")
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# Extract width parameter from title attribute
|
|
157
|
-
def extract_width_from_title(title)
|
|
158
|
-
return nil unless title
|
|
159
|
-
|
|
160
|
-
# Match CSS width units: px, em, rem, vw, vh, %, ch
|
|
161
|
-
match = title.match(/(\d+(?:\.\d+)?(?:px|em|rem|vw|vh|%|ch))/)
|
|
162
|
-
match ? match[1] : nil
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Check if title contains a width value
|
|
166
|
-
def contains_width?(title)
|
|
167
|
-
return false unless title
|
|
168
|
-
|
|
169
|
-
title.match?(/\d+(?:\.\d+)?(?:px|em|rem|vw|vh|%|ch)/)
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
end
|
|
@@ -1,53 +0,0 @@
|
|
|
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
|
|
@@ -1,58 +0,0 @@
|
|
|
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
|
-
# Inline syntax: @@@ variant? content @@@
|
|
10
|
-
# Alternative syntax: :::wa-tag variant?\ncontent\n:::
|
|
11
|
-
# Variants: brand, success, neutral, warning, danger
|
|
12
|
-
class TagTransformer < BaseTransformer
|
|
13
|
-
def self.transform(content)
|
|
14
|
-
# Define regex patterns
|
|
15
|
-
# Block syntax (multiline with newlines) - supports both LF and CRLF
|
|
16
|
-
primary_regex = /^@@@(brand|success|neutral|warning|danger)?\r?\n(.*?)\r?\n@@@/m
|
|
17
|
-
alternative_regex = /^:::wa-tag\s*(brand|success|neutral|warning|danger)?\r?\n(.*?)\r?\n:::/m
|
|
18
|
-
|
|
19
|
-
# Inline syntax (same line with spaces)
|
|
20
|
-
inline_regex = /@@@\s*(brand|success|neutral|warning|danger)?\s+([^@\r\n]+?)\s+@@@/
|
|
21
|
-
|
|
22
|
-
# Define shared transformation logic
|
|
23
|
-
transform_proc = proc do |variant, tag_content|
|
|
24
|
-
tag_content = tag_content.strip
|
|
25
|
-
|
|
26
|
-
build_tag_html(tag_content, variant)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Apply all patterns (inline first to avoid conflicts)
|
|
30
|
-
patterns = [
|
|
31
|
-
{
|
|
32
|
-
regex: inline_regex,
|
|
33
|
-
block: proc do |_match, matchdata|
|
|
34
|
-
captures = matchdata.captures
|
|
35
|
-
transform_proc.call(*captures)
|
|
36
|
-
end
|
|
37
|
-
},
|
|
38
|
-
*dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
39
|
-
]
|
|
40
|
-
apply_multiple_patterns(content, patterns)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
class << self
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
def build_tag_html(content, variant)
|
|
47
|
-
variant_attr = variant ? " variant=\"#{variant}\"" : ''
|
|
48
|
-
tag_html = markdown_to_html(content).strip
|
|
49
|
-
|
|
50
|
-
# Remove paragraph tags if the content is just text
|
|
51
|
-
tag_html = tag_html.gsub(%r{^<p>(.*)</p>$}m, '\1')
|
|
52
|
-
|
|
53
|
-
"<wa-tag#{variant_attr}>#{tag_html}</wa-tag>"
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
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/carousel_transformer'
|
|
12
|
-
require_relative 'transformers/comparison_transformer'
|
|
13
|
-
require_relative 'transformers/copy_button_transformer'
|
|
14
|
-
require_relative 'transformers/details_transformer'
|
|
15
|
-
require_relative 'transformers/dialog_transformer'
|
|
16
|
-
require_relative 'transformers/icon_transformer'
|
|
17
|
-
require_relative 'transformers/image_dialog_transformer'
|
|
18
|
-
require_relative 'transformers/tabs_transformer'
|
|
19
|
-
require_relative 'transformers/tag_transformer'
|