jekyll-webawesome 0.4.1 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b925e93ad2a43e360c982ac4fbc9c25ee0a0c4573039ecf2c182fa566377d60b
4
- data.tar.gz: 32e0685f36e0c5a3532900ffb964aa15809ba2fb5fbc9d71240dba39d5612427
3
+ metadata.gz: 5f88821b94fa1042ddd81efc46e15e35eb4b0c53f1159ccba1f92f171bf3b498
4
+ data.tar.gz: a10ad10f3477bbbe7da32eab5b9faaab0ef202e94aa6369ee28936ae52017d19
5
5
  SHA512:
6
- metadata.gz: 53d88906164176d32ad025c073d410c8d585f782643e0e3372ae5da51daf1fd5c65519dc77a9dd952aff2870c2c3a6453d454cd858cacefa4f0b19b993466258
7
- data.tar.gz: 9cc2f919be3f5513ca7269f5d9f9c722ab9cd386a78be5f9e1dd968ffd699e7edab43546c4b099d9ebb8fa55f41e5dfa79b30bc39fa9b446f8d0c00806fb18c2
6
+ metadata.gz: 78af1fefc803ab19f6da488775df860d49c0f7855afdec3ed9e2a8794b5e4261914bbd169ad275be7094a8aa10656c36c0ce6a3db88021544ffd6e7b81b2c47f
7
+ data.tar.gz: 9bb145b074f07b779f0fec449d3b24c2c7727a7fd55e9cdeb1697460a8d0214bf6052d84ce0a2686a0b4e2c83264c1a0137cfdb71e20eef204d4d6febfe7cf5d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ - Placeholder
10
+
11
+ ## [0.5.1] - 2025-10-20
12
+
13
+ - Image dialog auto-transformation feature fix: protect comparison components
14
+
15
+ ## [0.5.0] - 2025-10-20
16
+
17
+ - Add support for wa-dialog component
18
+ - Image dialog auto-transformation feature
19
+ - New `image_dialog` configuration option (opt-in, default: false)
20
+ - Automatically transforms markdown images into clickable dialogs
21
+ - Support for custom dialog width via title attribute (e.g., `"50%"`, `"800px"`, `"90vw"`)
22
+ - Opt-out mechanism via `"nodialog"` in title attribute
23
+
9
24
  ## [0.4.1] - 2025-10-02
10
25
 
11
26
  - Code blocks inside custom elements (wa-details, wa-callout, etc.) are now properly protected from markdown processing
data/README.md CHANGED
@@ -19,6 +19,7 @@ This plugin focuses on the most commonly used Web Awesome components for Jekyll
19
19
  | **Comparison** | `\|\|\|` or `\|\|\|25` | `:::wa-comparison` or `:::wa-comparison 25` | `<wa-comparison>` with before/after slots |
20
20
  | **Copy Button** | `<<<` | `:::wa-copy-button` | `<wa-copy-button value="content">content</wa-copy-button>` |
21
21
  | **Details** | `^^^appearance? icon-placement?` | `:::wa-details appearance? icon-placement?` | `<wa-details appearance="..." icon-placement="...">content</wa-details>` |
22
+ | **Dialog** | `???params?` | `:::wa-dialog params?` | `<wa-dialog>` with trigger button and content |
22
23
  | **Tab Group** | `++++++` | `:::wa-tabs` | `<wa-tab-group><wa-tab>content</wa-tab></wa-tab-group>` |
23
24
  | **Tag** | `@@@brand` | `:::wa-tag brand` | `<wa-tag variant="brand">content</wa-tag>` |
24
25
 
@@ -66,6 +67,9 @@ webawesome:
66
67
  # Control which file types to transform (default: both true)
67
68
  transform_pages: true # Transform pages (like index.md, about.md)
68
69
  transform_documents: true # Transform documents (like blog posts in _posts)
70
+
71
+ # Enable automatic image-to-dialog transformation (default: false)
72
+ image_dialog: true # Makes all images clickable and open in dialogs
69
73
  ```
70
74
 
71
75
  And then execute:
@@ -332,6 +336,108 @@ Copy buttons work well for:
332
336
 
333
337
  > **Note**: The `value` attribute contains the raw text (including any markdown) that gets copied to the clipboard. The copy button displays the standard Web Awesome copy icon and handles the clipboard operation automatically.
334
338
 
339
+ ### Dialogs
340
+
341
+ Create interactive dialogs (modals) using the `???` syntax:
342
+
343
+ ```markdown
344
+ ???
345
+ Open Dialog
346
+ >>>
347
+ This is the dialog content with **markdown** support.
348
+ ???
349
+ ```
350
+
351
+ This creates a trigger button and a dialog that opens when clicked:
352
+
353
+ ```html
354
+ <wa-button data-dialog='open dialog-abc123'>Open Dialog</wa-button>
355
+ <wa-dialog id='dialog-abc123' label='Open Dialog'>
356
+ <p>This is the dialog content with <strong>markdown</strong> support.</p>
357
+ <wa-button slot='footer' variant='primary' data-dialog='close'>Close</wa-button>
358
+ </wa-dialog>
359
+ ```
360
+
361
+ #### Dialogs with Headings
362
+
363
+ The first heading (`#`) automatically becomes the dialog's label (title):
364
+
365
+ ```markdown
366
+ ???
367
+ Show Details
368
+ >>>
369
+ # Important Information
370
+ This is the content of the dialog.
371
+ ???
372
+ ```
373
+
374
+ The button displays "Show Details" and the dialog header shows "Important Information".
375
+
376
+ #### Dialog Options
377
+
378
+ You can customize dialog behavior with optional parameters:
379
+
380
+ **Light Dismiss** - Dialog closes when clicking the overlay:
381
+
382
+ ```markdown
383
+ ???light-dismiss
384
+ Open Dialog
385
+ >>>
386
+ Click outside to close this dialog.
387
+ ???
388
+ ```
389
+
390
+ **Without Header** - Remove the dialog header entirely:
391
+
392
+ ```markdown
393
+ ???without-header
394
+ Open Dialog
395
+ >>>
396
+ This dialog has no header.
397
+ ???
398
+ ```
399
+
400
+ **Custom Width** - Set a specific width using CSS units (px, em, rem, vw, vh, %):
401
+
402
+ ```markdown
403
+ ???600px
404
+ Open Dialog
405
+ >>>
406
+ This dialog is 600 pixels wide.
407
+ ???
408
+
409
+ ???50vw
410
+ Open Wide Dialog
411
+ >>>
412
+ This dialog is 50% of the viewport width.
413
+ ???
414
+
415
+ ???40em
416
+ Open Dialog
417
+ >>>
418
+ This dialog is 40em wide.
419
+ ???
420
+ ```
421
+
422
+ **Combining Options** - You can combine multiple options:
423
+
424
+ ```markdown
425
+ ???light-dismiss 700px
426
+ Open Dialog
427
+ >>>
428
+ # Custom Dialog
429
+ This dialog has light dismiss enabled and is 700px wide.
430
+ ???
431
+
432
+ ???without-header light-dismiss 45em
433
+ Open Simple Dialog
434
+ >>>
435
+ This dialog has no header, light dismiss, and is 45em wide.
436
+ ???
437
+ ```
438
+
439
+ > **Note**: The dialog uses Web Awesome's declarative `data-dialog` API, so no custom JavaScript is needed. Each dialog gets a unique ID automatically generated from its content, and a close button is automatically added to the footer.
440
+
335
441
  ### Details/Summary (Collapsible Content)
336
442
 
337
443
  Create collapsible content using the `^^^` syntax:
@@ -510,6 +616,58 @@ Cards automatically parse content into these slots:
510
616
  | `end` (default) | Icon appears on the right side |
511
617
  | `start` | Icon appears on the left side |
512
618
 
619
+ ### Dialog Parameters
620
+
621
+ | Option | Description |
622
+ |--------|-------------|
623
+ | `light-dismiss` | Dialog closes when clicking outside/on overlay |
624
+ | `without-header` | Removes the dialog header entirely |
625
+ | Width (e.g., `500px`, `50vw`, `40em`) | Sets custom width using CSS units (px, em, rem, vw, vh, %) |
626
+
627
+ ### Dialog Features
628
+
629
+ - **Automatic ID Generation**: Each dialog gets a unique ID based on MD5 hash of its content
630
+ - **Auto-close Button**: A "Close" button is automatically added to the footer
631
+ - **Declarative API**: Uses Web Awesome's `data-dialog` attributes - no custom JavaScript needed
632
+ - **Label Extraction**: First `#` heading becomes the dialog label, or button text is used as fallback
633
+ - **Markdown Support**: Full markdown formatting in dialog content
634
+
635
+ ### Image Dialogs (Auto-transformation)
636
+
637
+ Enable automatic image-to-dialog transformation in your `_config.yml`:
638
+
639
+ ```yaml
640
+ webawesome:
641
+ image_dialog: true
642
+ ```
643
+
644
+ When enabled, all markdown images automatically become clickable and open in full-size dialogs:
645
+
646
+ ```markdown
647
+ ![Architecture Diagram](diagram.png)
648
+ ```
649
+
650
+ **Control dialog width** by adding a width parameter to the title:
651
+
652
+ ```markdown
653
+ ![Diagram](diagram.png "50%") # Dialog width: 50%
654
+ ![Photo](photo.jpg "800px") # Dialog width: 800px
655
+ ![Wide](image.png "90vw") # Dialog width: 90% viewport
656
+ ```
657
+
658
+ Supported width units: `px`, `em`, `rem`, `vw`, `vh`, `%`, `ch`
659
+
660
+ **Opt-out** by adding `"nodialog"` to the title:
661
+
662
+ ```markdown
663
+ ![Small Icon](icon.svg "nodialog")
664
+ ```
665
+
666
+ **Features:**
667
+
668
+ - Light-dismiss and headerless dialogs for clean UX
669
+ - Thumbnail displays at original size, dialog shows full-size
670
+
513
671
  ### Tab Placements
514
672
 
515
673
  - `top` (default)
@@ -40,6 +40,18 @@ module Jekyll
40
40
  true
41
41
  end
42
42
 
43
+ # Check if image dialog transformation is enabled
44
+ def self.image_dialog_enabled?(site)
45
+ # Check plugin configuration first
46
+ return Jekyll::WebAwesome.configuration.image_dialog if Jekyll::WebAwesome.configuration
47
+
48
+ # Check site config
49
+ return site.config.dig('webawesome', 'image_dialog') if site.config.dig('webawesome', 'image_dialog') != nil
50
+
51
+ # Default to false (opt-in feature)
52
+ false
53
+ end
54
+
43
55
  # Check if a file is a markdown file
44
56
  def self.markdown_file?(filepath)
45
57
  filepath.to_s.match?(/\.md$/i)
@@ -51,7 +63,7 @@ module Jekyll
51
63
  next unless transform_documents_enabled?(document.site)
52
64
 
53
65
  puts "Jekyll::WebAwesome Processing document (pre-render): #{document.relative_path}\n" if debug_enabled?(document.site)
54
- document.content = Transformer.process(document.content)
66
+ document.content = Transformer.process(document.content, document.site)
55
67
  end
56
68
 
57
69
  Jekyll::Hooks.register :pages, :pre_render do |page|
@@ -59,7 +71,7 @@ module Jekyll
59
71
  next unless transform_pages_enabled?(page.site)
60
72
 
61
73
  puts "Jekyll::WebAwesome Processing page (pre-render): #{page.relative_path}\n" if debug_enabled?(page.site)
62
- page.content = Transformer.process(page.content)
74
+ page.content = Transformer.process(page.content, page.site)
63
75
  end
64
76
  end
65
77
  end
@@ -8,7 +8,7 @@ module Jekyll
8
8
  module WebAwesome
9
9
  # Main transformer that orchestrates all component transformers
10
10
  class Transformer
11
- def self.process(content)
11
+ def self.process(content, site = nil)
12
12
  content = BadgeTransformer.transform(content)
13
13
  content = ButtonTransformer.transform(content)
14
14
  content = CalloutTransformer.transform(content)
@@ -16,6 +16,11 @@ module Jekyll
16
16
  content = ComparisonTransformer.transform(content)
17
17
  content = CopyButtonTransformer.transform(content)
18
18
  content = DetailsTransformer.transform(content)
19
+
20
+ # Apply image dialog transformer BEFORE dialog transformer so it can generate dialog syntax
21
+ content = ImageDialogTransformer.transform(content) if site && Plugin.image_dialog_enabled?(site)
22
+
23
+ content = DialogTransformer.transform(content)
19
24
  content = IconTransformer.transform(content)
20
25
  content = TagTransformer.transform(content)
21
26
  TabsTransformer.transform(content)
@@ -0,0 +1,172 @@
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, without-header, and optional width (e.g., 500px, 50vw, 40em)
12
+ class DialogTransformer < BaseTransformer
13
+ def self.transform(content)
14
+ # Define both regex patterns - capture parameter string, button text, and content
15
+ # Params are on the same line as the opening delimiter
16
+ # Button text is on the next line(s) until >>>
17
+ # Content is everything after >>> until the closing delimiter
18
+ primary_regex = /^\?\?\?([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^\?\?\?$/m
19
+ alternative_regex = /^:::wa-dialog([^\n]*)$\n(.*?)\n^>>>$\n(.*?)\n^:::$/m
20
+
21
+ # Define shared transformation logic
22
+ transform_proc = proc do |params_string, button_text, dialog_content|
23
+ button_text = button_text.strip
24
+ dialog_content = dialog_content.strip
25
+
26
+ # Parse parameters
27
+ light_dismiss, without_header, width = parse_parameters(params_string)
28
+
29
+ # Extract label from first heading or use button text
30
+ label, content_without_label = extract_label(dialog_content, button_text)
31
+
32
+ # Generate unique ID based on content
33
+ dialog_id = generate_dialog_id(button_text, dialog_content)
34
+
35
+ # Convert markdown to HTML
36
+ content_html = markdown_to_html(content_without_label)
37
+
38
+ # Build the dialog HTML
39
+ build_dialog_html(dialog_id, button_text, label, content_html,
40
+ light_dismiss, without_header, width)
41
+ end
42
+
43
+ # Apply both patterns
44
+ patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
45
+ apply_multiple_patterns(content, patterns)
46
+ end
47
+
48
+ class << self
49
+ private
50
+
51
+ # Parse parameters from the params string
52
+ def parse_parameters(params_string)
53
+ return [false, false, nil] if params_string.nil? || params_string.strip.empty?
54
+
55
+ tokens = params_string.strip.split(/\s+/)
56
+
57
+ light_dismiss = tokens.include?('light-dismiss')
58
+ without_header = tokens.include?('without-header')
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, without_header, width]
70
+ end
71
+
72
+ # Extract label from first heading in content
73
+ def extract_label(content, default_label)
74
+ # Check if content starts with a heading
75
+ if content.match(/^#\s+(.+?)$/)
76
+ label = Regexp.last_match(1).strip
77
+ # Remove the heading from content
78
+ content_without_label = content.sub(/^#\s+.+?\n/, '').strip
79
+ [label, content_without_label]
80
+ else
81
+ [default_label, content]
82
+ end
83
+ end
84
+
85
+ # Generate a unique ID for the dialog using MD5 hash
86
+ def generate_dialog_id(button_text, content)
87
+ hash_input = "#{button_text}#{content}"
88
+ hash = Digest::MD5.hexdigest(hash_input)
89
+ "dialog-#{hash[0..7]}" # Use first 8 characters of hash
90
+ end
91
+
92
+ # Build the complete dialog HTML with trigger button
93
+ def build_dialog_html(dialog_id, button_text, label, content_html,
94
+ light_dismiss, without_header, width)
95
+ # Build dialog attributes
96
+ dialog_attrs = ["id='#{dialog_id}'"]
97
+ # Escape both HTML and attribute characters for label
98
+ dialog_attrs << "label='#{escape_attribute(escape_html(label))}'" unless without_header
99
+ dialog_attrs << 'without-header' if without_header
100
+ dialog_attrs << 'light-dismiss' if light_dismiss
101
+
102
+ # Build style attribute for width if specified
103
+ style_attr = width ? " style='--width: #{width}'" : ''
104
+
105
+ # Check if button contains an image (for image dialog support)
106
+ is_image_button = button_text.include?('<img')
107
+
108
+ # Build the HTML
109
+ html = []
110
+
111
+ # Add CSS Parts styling for image buttons to make them invisible
112
+ if is_image_button
113
+ button_id = "#{dialog_id}-btn"
114
+ html << '<style>'
115
+ html << " ##{button_id}::part(base) {"
116
+ html << ' padding: 0;'
117
+ html << ' margin: 0;'
118
+ html << ' border: none;'
119
+ html << ' background: transparent;'
120
+ html << ' box-shadow: none;'
121
+ html << ' color: inherit;'
122
+ html << ' min-width: 0;'
123
+ html << ' height: auto;'
124
+ html << ' }'
125
+ html << " ##{button_id}::part(base):hover {"
126
+ html << ' background: transparent;'
127
+ html << ' border-color: transparent;'
128
+ html << ' }'
129
+ html << " ##{button_id}::part(base):active {"
130
+ html << ' background: transparent;'
131
+ html << ' border-color: transparent;'
132
+ html << ' }'
133
+ html << '</style>'
134
+ end
135
+
136
+ # Trigger button
137
+ # Only allow HTML for image tags (for image dialog support), escape everything else for security
138
+ button_content = is_image_button ? button_text : escape_html(button_text)
139
+ button_id_attr = is_image_button ? " id='#{button_id}'" : ''
140
+ button_variant = is_image_button ? " variant='text'" : ''
141
+ html << "<wa-button#{button_id_attr}#{button_variant} data-dialog='open #{dialog_id}'>#{button_content}</wa-button>"
142
+
143
+ # Dialog element
144
+ html << "<wa-dialog #{dialog_attrs.join(' ')}#{style_attr}>"
145
+ html << content_html
146
+
147
+ # Footer with close button
148
+ html << "<wa-button slot='footer' variant='primary' data-dialog='close'>Close</wa-button>"
149
+
150
+ html << '</wa-dialog>'
151
+
152
+ html.join("\n")
153
+ end
154
+
155
+ # Escape HTML entities in text
156
+ def escape_html(text)
157
+ text.gsub('&', '&amp;')
158
+ .gsub('<', '&lt;')
159
+ .gsub('>', '&gt;')
160
+ .gsub('"', '&quot;')
161
+ .gsub("'", '&#39;')
162
+ end
163
+
164
+ # Escape attribute values
165
+ def escape_attribute(text)
166
+ text.gsub("'", '&apos;')
167
+ .gsub('"', '&quot;')
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,133 @@
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: ![Alt text](image.png "nodialog")
11
+ class ImageDialogTransformer < BaseTransformer
12
+ def self.transform(content)
13
+ # First, protect inline code blocks and comparison blocks from transformation
14
+ protected_content, code_blocks = protect_inline_code(content)
15
+ protected_content, comparison_blocks = protect_comparisons(protected_content)
16
+
17
+ # Match markdown images: ![alt](url) or ![alt](url "title")
18
+ # Capture alt text, URL, and optional title
19
+ # URL can contain spaces and special characters
20
+ image_regex = /!\[([^\]]*)\]\(([^)]+?)(?:\s+"([^"]*)")?\)/
21
+
22
+ result = protected_content.gsub(image_regex) do |match|
23
+ alt_text = Regexp.last_match(1)
24
+ image_url = Regexp.last_match(2).strip
25
+ title = Regexp.last_match(3)
26
+
27
+ # Skip transformation if title contains "nodialog"
28
+ if title&.include?('nodialog')
29
+ # Return original image without dialog
30
+ match
31
+ else
32
+ # Transform to clickable image with dialog
33
+ transform_to_dialog(alt_text, image_url, title)
34
+ end
35
+ end
36
+
37
+ # Restore protected comparison blocks first, then inline code
38
+ result = restore_comparisons(result, comparison_blocks)
39
+ restore_inline_code(result, code_blocks)
40
+ end
41
+
42
+ class << self
43
+ private
44
+
45
+ # Protect inline code from transformation
46
+ def protect_inline_code(content)
47
+ code_blocks = []
48
+ protected = content.gsub(/`[^`]+`/) do |match|
49
+ placeholder = "INLINE_CODE_#{code_blocks.length}"
50
+ code_blocks << match
51
+ placeholder
52
+ end
53
+ [protected, code_blocks]
54
+ end
55
+
56
+ # Restore protected inline code
57
+ def restore_inline_code(content, code_blocks)
58
+ code_blocks.each_with_index do |code, index|
59
+ content = content.gsub("INLINE_CODE_#{index}", code)
60
+ end
61
+ content
62
+ end
63
+
64
+ # Protect comparison blocks from image transformation
65
+ def protect_comparisons(content)
66
+ comparison_blocks = []
67
+ # Match comparison blocks: <wa-comparison ...>...</wa-comparison>
68
+ protected = content.gsub(/<wa-comparison[^>]*>.*?<\/wa-comparison>/m) do |match|
69
+ placeholder = "COMPARISON_BLOCK_#{comparison_blocks.length}"
70
+ comparison_blocks << match
71
+ placeholder
72
+ end
73
+ [protected, comparison_blocks]
74
+ end
75
+
76
+ # Restore protected comparison blocks
77
+ def restore_comparisons(content, comparison_blocks)
78
+ comparison_blocks.each_with_index do |block, index|
79
+ content = content.gsub("COMPARISON_BLOCK_#{index}", block)
80
+ end
81
+ content
82
+ end
83
+
84
+ # Transform image into our custom dialog syntax
85
+ # This will be processed by DialogTransformer to create the actual wa-dialog
86
+ def transform_to_dialog(alt_text, image_url, title)
87
+ # Parse width from title if specified (e.g., "50%", "800px", "60vw")
88
+ width = extract_width_from_title(title)
89
+
90
+ # Build dialog parameters
91
+ params = %w[light-dismiss without-header]
92
+ params << width if width
93
+ params_string = params.join(' ')
94
+
95
+ # Build the button content - a styled image that acts as the trigger
96
+ # Add title attribute if provided and doesn't contain "nodialog" or width
97
+ title_attr = title && !title.include?('nodialog') && !contains_width?(title) ? " title=\"#{title}\"" : ''
98
+ button_content = "<img src=\"#{image_url}\" alt=\"#{alt_text}\" style=\"cursor: zoom-in; display: block; width: 100%; height: auto;\"#{title_attr} />"
99
+
100
+ # Build the dialog content - full-size image
101
+ dialog_content = "<img src=\"#{image_url}\" alt=\"#{alt_text}\" style=\"max-width: 100%; height: auto; display: block; margin: 0 auto;\" />"
102
+
103
+ # Use our custom dialog syntax that will be processed by DialogTransformer
104
+ # Format: ???params\nbutton_content\n>>>\ndialog_content\n???
105
+ result = []
106
+ result << "???#{params_string}"
107
+ result << button_content
108
+ result << '>>>'
109
+ result << dialog_content
110
+ result << '???'
111
+
112
+ result.join("\n")
113
+ end
114
+
115
+ # Extract width parameter from title attribute
116
+ def extract_width_from_title(title)
117
+ return nil unless title
118
+
119
+ # Match CSS width units: px, em, rem, vw, vh, %, ch
120
+ match = title.match(/(\d+(?:\.\d+)?(?:px|em|rem|vw|vh|%|ch))/)
121
+ match ? match[1] : nil
122
+ end
123
+
124
+ # Check if title contains a width value
125
+ def contains_width?(title)
126
+ return false unless title
127
+
128
+ title.match?(/\d+(?:\.\d+)?(?:px|em|rem|vw|vh|%|ch)/)
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -11,6 +11,8 @@ require_relative 'transformers/card_transformer'
11
11
  require_relative 'transformers/comparison_transformer'
12
12
  require_relative 'transformers/copy_button_transformer'
13
13
  require_relative 'transformers/details_transformer'
14
+ require_relative 'transformers/dialog_transformer'
14
15
  require_relative 'transformers/icon_transformer'
16
+ require_relative 'transformers/image_dialog_transformer'
15
17
  require_relative 'transformers/tabs_transformer'
16
18
  require_relative 'transformers/tag_transformer'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module WebAwesome
5
- VERSION = '0.4.1'
5
+ VERSION = '0.5.1'
6
6
  end
7
7
  end
@@ -23,7 +23,7 @@ module Jekyll
23
23
 
24
24
  # Configuration class for future extensibility
25
25
  class Configuration
26
- attr_accessor :debug_mode, :callout_icons, :custom_components, :transform_pages, :transform_documents
26
+ attr_accessor :debug_mode, :callout_icons, :custom_components, :transform_pages, :transform_documents, :image_dialog
27
27
 
28
28
  def initialize
29
29
  @debug_mode = false
@@ -31,6 +31,7 @@ module Jekyll
31
31
  @custom_components = {}
32
32
  @transform_pages = true
33
33
  @transform_documents = true
34
+ @image_dialog = false # Opt-in by default for safety
34
35
  end
35
36
 
36
37
  private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-webawesome
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janne Waren
@@ -125,7 +125,9 @@ files:
125
125
  - lib/jekyll/webawesome/transformers/comparison_transformer.rb
126
126
  - lib/jekyll/webawesome/transformers/copy_button_transformer.rb
127
127
  - lib/jekyll/webawesome/transformers/details_transformer.rb
128
+ - lib/jekyll/webawesome/transformers/dialog_transformer.rb
128
129
  - lib/jekyll/webawesome/transformers/icon_transformer.rb
130
+ - lib/jekyll/webawesome/transformers/image_dialog_transformer.rb
129
131
  - lib/jekyll/webawesome/transformers/tabs_transformer.rb
130
132
  - lib/jekyll/webawesome/transformers/tag_transformer.rb
131
133
  - lib/jekyll/webawesome/version.rb