markawesome 0.3.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/lib/markawesome/icon_slot_parser.rb +63 -0
- data/lib/markawesome/transformer.rb +1 -0
- data/lib/markawesome/transformers/button_transformer.rb +11 -6
- data/lib/markawesome/transformers/callout_transformer.rb +12 -2
- data/lib/markawesome/transformers/details_transformer.rb +14 -4
- data/lib/markawesome/transformers/layout_transformer.rb +121 -0
- data/lib/markawesome/transformers/tag_transformer.rb +14 -5
- data/lib/markawesome/transformers.rb +1 -0
- data/lib/markawesome/version.rb +1 -1
- data/lib/markawesome.rb +1 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c1a813451ca32ebe286489c510fd9ebc0f161877d6e20bdc50c390c8e54669c8
|
|
4
|
+
data.tar.gz: fe1f091910a15ebf1f825769266fdaa1ff776e1ceace7a041e0fe71370b42817
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ddf1bc53111ca053bd5fe82040ee9387783dd95f0892658697a2f38f0b7a11ebd8fa1517df4e990fbda8aaa90f465f27bb1a6f46d673b8f6fc31a24acab5070
|
|
7
|
+
data.tar.gz: 83ac02b6ca5cb7744579661c068511c53666bf4ec8b550a6170050ab04f8911c053db46f1b87122b91aec2024b3a564f4e21d1a34e49189fdbb0e5152df99e49
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.5.0] - 2026-02-10
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **LayoutTransformer**: New `::::` (quadruple colon) syntax for wrapping content in Web Awesome CSS layout containers
|
|
12
|
+
- Supports 6 layout types: `grid`, `stack`, `cluster`, `split`, `flank`, `frame`
|
|
13
|
+
- Common attributes: `gap:SIZE`, `align:VALUE`, `justify:VALUE` for all layouts
|
|
14
|
+
- Grid-specific: `min:CSS_VALUE` for custom minimum column size (`--min-column-size`)
|
|
15
|
+
- Split-specific: `row` and `column` direction modifiers
|
|
16
|
+
- Flank-specific: `start`/`end` position modifiers, `size:CSS_VALUE`, `content:PCT`
|
|
17
|
+
- Frame-specific: `landscape`/`portrait`/`square` aspect ratios, `radius:SIZE`
|
|
18
|
+
- Dual syntax: both `::::grid` and `::::wa-grid` work identically
|
|
19
|
+
- CSS value sanitization for user-provided values (strips quotes, angle brackets, semicolons)
|
|
20
|
+
- Inner content is not markdown-converted, allowing component `:::` syntax to be processed by subsequent transformers
|
|
21
|
+
- Runs first in the pipeline so layout containers wrap around component output
|
|
22
|
+
|
|
23
|
+
## [0.4.0] - 2026-02-09
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **IconSlotParser**: New reusable parser for `icon:name` and `icon:slot:name` syntax across components
|
|
28
|
+
- **ButtonTransformer**: Icon support with `icon:name` (start slot) and `icon:end:name` for start/end icon slots
|
|
29
|
+
- **CalloutTransformer**: Custom icon override with `icon:name` to replace default variant icons
|
|
30
|
+
- **DetailsTransformer**: Custom expand/collapse icons with `icon:expand:name` and `icon:collapse:name`
|
|
31
|
+
- **TagTransformer**: Inline content icons with `icon:name` for both block and inline tag syntax
|
|
32
|
+
|
|
33
|
+
### Design
|
|
34
|
+
|
|
35
|
+
- IconSlotParser composes with AttributeParser — strips icon tokens first, passes remaining params for attribute parsing
|
|
36
|
+
- Supports slot name mapping (e.g. `expand` → `expand-icon`) for Web Awesome's HTML slot conventions
|
|
37
|
+
- Rightmost-wins semantics consistent with AttributeParser
|
|
38
|
+
- Content slot mode omits `slot=` attribute for inline icon usage (tags)
|
|
39
|
+
|
|
7
40
|
## [0.3.0] - 2026-02-08
|
|
8
41
|
|
|
9
42
|
### Added
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Markawesome
|
|
4
|
+
# Parses icon:... tokens from parameter strings for Web Awesome component icon slots
|
|
5
|
+
# Supports default slot mapping, explicit slot names, and slot name remapping
|
|
6
|
+
#
|
|
7
|
+
# Examples:
|
|
8
|
+
# "icon:gear" → default slot gets "gear"
|
|
9
|
+
# "icon:end:arrow-right" → "end" slot gets "arrow-right"
|
|
10
|
+
# "success icon:gear large" → icons: { 'start' => 'gear' }, remaining: "success large"
|
|
11
|
+
class IconSlotParser
|
|
12
|
+
# Parse icon tokens from a parameter string
|
|
13
|
+
# @param params_string [String] Space-separated parameter string potentially containing icon:... tokens
|
|
14
|
+
# @param slot_config [Hash] Configuration for icon slots
|
|
15
|
+
# :default [String, nil] Default slot name for icon:name tokens (nil = no default)
|
|
16
|
+
# :slots [Array<String>] Allowed slot names
|
|
17
|
+
# :slot_map [Hash] Optional mapping from short slot names to HTML slot attributes
|
|
18
|
+
# @return [Hash] { icons: Hash, remaining: String }
|
|
19
|
+
def self.parse(params_string, slot_config)
|
|
20
|
+
return { icons: {}, remaining: '' } if params_string.nil? || params_string.strip.empty?
|
|
21
|
+
|
|
22
|
+
icons = {}
|
|
23
|
+
remaining_tokens = []
|
|
24
|
+
tokens = params_string.strip.split(/\s+/)
|
|
25
|
+
|
|
26
|
+
tokens.each do |token|
|
|
27
|
+
if token.start_with?('icon:')
|
|
28
|
+
parts = token.split(':', 3) # ["icon", slot_or_name, maybe_name]
|
|
29
|
+
|
|
30
|
+
if parts.length == 3
|
|
31
|
+
# Explicit slot: icon:slot:name
|
|
32
|
+
slot = parts[1]
|
|
33
|
+
name = parts[2]
|
|
34
|
+
icons[slot] = name if slot_config[:slots]&.include?(slot)
|
|
35
|
+
elsif parts.length == 2 && slot_config[:default]
|
|
36
|
+
# Default slot: icon:name
|
|
37
|
+
name = parts[1]
|
|
38
|
+
icons[slot_config[:default]] = name unless name.empty?
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
remaining_tokens << token
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
{ icons: icons, remaining: remaining_tokens.join(' ') }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Generate <wa-icon> HTML elements for parsed icons
|
|
49
|
+
# @param icons_hash [Hash] Slot name => icon name pairs
|
|
50
|
+
# @param slot_map [Hash, nil] Optional mapping from parsed slot names to HTML slot attributes
|
|
51
|
+
# @return [String] HTML string with <wa-icon> elements
|
|
52
|
+
def self.to_html(icons_hash, slot_map = nil)
|
|
53
|
+
icons_hash.map do |slot, name|
|
|
54
|
+
html_slot = slot_map ? (slot_map[slot] || slot) : slot
|
|
55
|
+
if html_slot == 'content'
|
|
56
|
+
"<wa-icon name=\"#{name}\"></wa-icon>"
|
|
57
|
+
else
|
|
58
|
+
"<wa-icon slot=\"#{html_slot}\" name=\"#{name}\"></wa-icon>"
|
|
59
|
+
end
|
|
60
|
+
end.join
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -7,6 +7,7 @@ module Markawesome
|
|
|
7
7
|
# Main transformer that orchestrates all component transformers
|
|
8
8
|
class Transformer
|
|
9
9
|
def self.process(content, options = {})
|
|
10
|
+
content = LayoutTransformer.transform(content)
|
|
10
11
|
content = BadgeTransformer.transform(content)
|
|
11
12
|
content = ButtonTransformer.transform(content)
|
|
12
13
|
content = CalloutTransformer.transform(content)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'base_transformer'
|
|
4
4
|
require_relative '../attribute_parser'
|
|
5
|
+
require_relative '../icon_slot_parser'
|
|
5
6
|
|
|
6
7
|
module Markawesome
|
|
7
8
|
# Transforms button syntax into wa-button elements
|
|
@@ -31,6 +32,8 @@ module Markawesome
|
|
|
31
32
|
disabled: %w[disabled]
|
|
32
33
|
}.freeze
|
|
33
34
|
|
|
35
|
+
ICON_SLOTS = { default: 'start', slots: %w[start end] }.freeze
|
|
36
|
+
|
|
34
37
|
def self.transform(content)
|
|
35
38
|
# Define both regex patterns - capture all space-separated parameters
|
|
36
39
|
primary_regex = /^%%%([^\n]*)\n(.*?)\n%%%/m
|
|
@@ -40,10 +43,11 @@ module Markawesome
|
|
|
40
43
|
transform_proc = proc do |params_string, button_content|
|
|
41
44
|
button_content = button_content.strip
|
|
42
45
|
|
|
43
|
-
# Parse
|
|
44
|
-
|
|
46
|
+
# Parse icon tokens first, then pass remaining to AttributeParser
|
|
47
|
+
icon_result = IconSlotParser.parse(params_string, ICON_SLOTS)
|
|
48
|
+
attributes = AttributeParser.parse(icon_result[:remaining], BUTTON_ATTRIBUTES)
|
|
45
49
|
|
|
46
|
-
build_button_html(button_content, attributes)
|
|
50
|
+
build_button_html(button_content, attributes, icon_result[:icons])
|
|
47
51
|
end
|
|
48
52
|
|
|
49
53
|
# Apply both patterns
|
|
@@ -54,7 +58,7 @@ module Markawesome
|
|
|
54
58
|
class << self
|
|
55
59
|
private
|
|
56
60
|
|
|
57
|
-
def build_button_html(content, attributes)
|
|
61
|
+
def build_button_html(content, attributes, icons = {})
|
|
58
62
|
# Build HTML attributes from parsed attributes
|
|
59
63
|
html_attrs = []
|
|
60
64
|
|
|
@@ -67,6 +71,7 @@ module Markawesome
|
|
|
67
71
|
html_attrs << 'disabled' if attributes[:disabled]
|
|
68
72
|
|
|
69
73
|
attrs_string = html_attrs.empty? ? '' : " #{html_attrs.join(' ')}"
|
|
74
|
+
icon_html = IconSlotParser.to_html(icons)
|
|
70
75
|
|
|
71
76
|
# Check if content contains a markdown link
|
|
72
77
|
link_match = content.match(/^\[([^\]]+)\]\(([^)]+)\)$/)
|
|
@@ -83,7 +88,7 @@ module Markawesome
|
|
|
83
88
|
# Fix whitespace issues like in badges
|
|
84
89
|
button_html = button_html.gsub(%r{(</\w+>)\s+}, '\1 ')
|
|
85
90
|
|
|
86
|
-
"<wa-button#{attrs_string} href=\"#{link_url}\">#{button_html}</wa-button>"
|
|
91
|
+
"<wa-button#{attrs_string} href=\"#{link_url}\">#{icon_html}#{button_html}</wa-button>"
|
|
87
92
|
else
|
|
88
93
|
# It's a regular button
|
|
89
94
|
button_html = markdown_to_html(content).strip
|
|
@@ -92,7 +97,7 @@ module Markawesome
|
|
|
92
97
|
# Fix whitespace issues like in badges
|
|
93
98
|
button_html = button_html.gsub(%r{(</\w+>)\s+}, '\1 ')
|
|
94
99
|
|
|
95
|
-
"<wa-button#{attrs_string}>#{button_html}</wa-button>"
|
|
100
|
+
"<wa-button#{attrs_string}>#{icon_html}#{button_html}</wa-button>"
|
|
96
101
|
end
|
|
97
102
|
end
|
|
98
103
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'base_transformer'
|
|
4
4
|
require_relative '../attribute_parser'
|
|
5
|
+
require_relative '../icon_slot_parser'
|
|
5
6
|
|
|
6
7
|
module Markawesome
|
|
7
8
|
# Transforms callout syntax into wa-callout elements
|
|
@@ -17,6 +18,7 @@ module Markawesome
|
|
|
17
18
|
appearance: %w[accent filled outlined plain filled-outlined]
|
|
18
19
|
}.freeze
|
|
19
20
|
VARIANT_ALIASES = { 'info' => 'brand' }.freeze
|
|
21
|
+
ICON_SLOTS = { default: 'icon', slots: %w[icon] }.freeze
|
|
20
22
|
|
|
21
23
|
def self.transform(content)
|
|
22
24
|
variant_pattern = VARIANTS.join('|')
|
|
@@ -25,13 +27,21 @@ module Markawesome
|
|
|
25
27
|
|
|
26
28
|
transform_proc = proc do |variant, extra_params, inner_content|
|
|
27
29
|
actual_variant = VARIANT_ALIASES.fetch(variant, variant)
|
|
28
|
-
|
|
30
|
+
|
|
31
|
+
# Parse icon tokens first, then pass remaining to AttributeParser
|
|
32
|
+
icon_result = IconSlotParser.parse(extra_params, ICON_SLOTS)
|
|
33
|
+
extra_attrs = AttributeParser.parse(icon_result[:remaining], CALLOUT_ATTRIBUTES)
|
|
29
34
|
|
|
30
35
|
attr_parts = ["variant=\"#{actual_variant}\""]
|
|
31
36
|
attr_parts << "appearance=\"#{extra_attrs[:appearance]}\"" if extra_attrs[:appearance]
|
|
32
37
|
attr_parts << "size=\"#{extra_attrs[:size]}\"" if extra_attrs[:size]
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
# Use custom icon if provided, otherwise use default variant icon
|
|
40
|
+
icon_html = if icon_result[:icons]['icon']
|
|
41
|
+
"<wa-icon slot=\"icon\" name=\"#{icon_result[:icons]['icon']}\" variant=\"solid\"></wa-icon>"
|
|
42
|
+
else
|
|
43
|
+
icon_for(actual_variant)
|
|
44
|
+
end
|
|
35
45
|
html_content = "#{icon_html}#{markdown_to_html(inner_content)}"
|
|
36
46
|
|
|
37
47
|
"<wa-callout #{attr_parts.join(' ')}>#{html_content}</wa-callout>"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'base_transformer'
|
|
4
4
|
require_relative '../attribute_parser'
|
|
5
|
+
require_relative '../icon_slot_parser'
|
|
5
6
|
|
|
6
7
|
module Markawesome
|
|
7
8
|
# Transforms summary/details syntax into wa-details elements
|
|
@@ -19,6 +20,12 @@ module Markawesome
|
|
|
19
20
|
open: %w[open]
|
|
20
21
|
}.freeze
|
|
21
22
|
|
|
23
|
+
ICON_SLOTS = {
|
|
24
|
+
default: nil,
|
|
25
|
+
slots: %w[expand collapse],
|
|
26
|
+
slot_map: { 'expand' => 'expand-icon', 'collapse' => 'collapse-icon' }
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
22
29
|
def self.transform(content)
|
|
23
30
|
# Define both regex patterns - capture parameter string
|
|
24
31
|
primary_regex = /^\^\^\^?(.*?)\n(.*?)\n^>>>\n(.*?)\n^\^\^\^?/m
|
|
@@ -29,11 +36,12 @@ module Markawesome
|
|
|
29
36
|
summary_content = summary_content.strip
|
|
30
37
|
details_content = details_content.strip
|
|
31
38
|
|
|
32
|
-
# Parse
|
|
33
|
-
|
|
39
|
+
# Parse icon tokens first, then pass remaining to AttributeParser and name extraction
|
|
40
|
+
icon_result = IconSlotParser.parse(params_string, ICON_SLOTS)
|
|
41
|
+
attributes = AttributeParser.parse(icon_result[:remaining], COMPONENT_ATTRIBUTES)
|
|
34
42
|
|
|
35
43
|
# Extract name parameter (format: name:value) - special handling
|
|
36
|
-
name_value = extract_name_value(
|
|
44
|
+
name_value = extract_name_value(icon_result[:remaining])
|
|
37
45
|
|
|
38
46
|
appearance_class = normalize_appearance(attributes[:appearance])
|
|
39
47
|
icon_placement = attributes[:icon_placement] || 'end'
|
|
@@ -46,9 +54,11 @@ module Markawesome
|
|
|
46
54
|
attr_parts << 'open' if attributes[:open]
|
|
47
55
|
attr_parts << "name='#{name_value}'" if name_value
|
|
48
56
|
|
|
57
|
+
icon_html = IconSlotParser.to_html(icon_result[:icons], ICON_SLOTS[:slot_map])
|
|
58
|
+
|
|
49
59
|
"<wa-details #{attr_parts.join(' ')}>" \
|
|
50
60
|
"<span slot='summary'>#{summary_html}</span>" \
|
|
51
|
-
"#{details_html}</wa-details>"
|
|
61
|
+
"#{icon_html}#{details_html}</wa-details>"
|
|
52
62
|
end
|
|
53
63
|
|
|
54
64
|
# Apply both patterns
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_transformer'
|
|
4
|
+
|
|
5
|
+
module Markawesome
|
|
6
|
+
# Transforms layout syntax into CSS layout utility containers
|
|
7
|
+
# Primary syntax: ::::type params?\ncontent\n::::
|
|
8
|
+
# Alternative syntax: ::::wa-type params?\ncontent\n::::
|
|
9
|
+
# Supported types: grid, stack, cluster, split, flank, frame
|
|
10
|
+
#
|
|
11
|
+
# Common attributes (all layouts):
|
|
12
|
+
# gap:SIZE - wa-gap-{SIZE} class (0, 3xs, 2xs, xs, s, m, l, xl, 2xl, 3xl)
|
|
13
|
+
# align:VALUE - wa-align-items-{VALUE} class (start, end, center, stretch, baseline)
|
|
14
|
+
# justify:VALUE - wa-justify-content-{VALUE} class (start, end, center, space-between, space-around, space-evenly)
|
|
15
|
+
#
|
|
16
|
+
# Grid-specific: min:CSS_VALUE - sets --min-column-size style
|
|
17
|
+
# Split-specific: row, column modifiers
|
|
18
|
+
# Flank-specific: start, end modifiers; size:CSS_VALUE, content:PCT
|
|
19
|
+
# Frame-specific: landscape, portrait, square modifiers; radius:SIZE
|
|
20
|
+
class LayoutTransformer < BaseTransformer
|
|
21
|
+
VALID_GAPS = %w[0 3xs 2xs xs s m l xl 2xl 3xl].freeze
|
|
22
|
+
VALID_ALIGNS = %w[start end center stretch baseline].freeze
|
|
23
|
+
VALID_JUSTIFIES = %w[start end center space-between space-around space-evenly].freeze
|
|
24
|
+
VALID_RADII = %w[s m l pill circle square].freeze
|
|
25
|
+
|
|
26
|
+
KEYWORD_MODIFIERS = {
|
|
27
|
+
split: %w[row column],
|
|
28
|
+
flank: %w[start end],
|
|
29
|
+
frame: %w[landscape portrait square]
|
|
30
|
+
}.freeze
|
|
31
|
+
|
|
32
|
+
COMMON_KEY_CLASS_MAP = {
|
|
33
|
+
'gap' => ->(v) { "wa-gap-#{v}" if VALID_GAPS.include?(v) },
|
|
34
|
+
'align' => ->(v) { "wa-align-items-#{v}" if VALID_ALIGNS.include?(v) },
|
|
35
|
+
'justify' => ->(v) { "wa-justify-content-#{v}" if VALID_JUSTIFIES.include?(v) }
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
def self.transform(content)
|
|
39
|
+
primary_regex = /^::::(grid|stack|cluster|split|flank|frame)[ \t]*([^\n]*)\n(.*?)\n::::/m
|
|
40
|
+
alternative_regex = /^::::wa-(grid|stack|cluster|split|flank|frame)[ \t]*([^\n]*)\n(.*?)\n::::/m
|
|
41
|
+
|
|
42
|
+
transform_proc = proc do |type, params_string, inner_content|
|
|
43
|
+
classes, styles = build_attributes(type, params_string)
|
|
44
|
+
build_html(classes, styles, inner_content)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
patterns = dual_syntax_patterns(primary_regex, alternative_regex, transform_proc)
|
|
48
|
+
apply_multiple_patterns(content, patterns)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class << self
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def build_attributes(type, params_string)
|
|
55
|
+
classes = ["wa-#{type}"]
|
|
56
|
+
styles = []
|
|
57
|
+
|
|
58
|
+
return [classes, styles] if params_string.nil? || params_string.strip.empty?
|
|
59
|
+
|
|
60
|
+
tokens = params_string.strip.split(/\s+/)
|
|
61
|
+
|
|
62
|
+
tokens.each do |token|
|
|
63
|
+
process_token(type, token, classes, styles)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
[classes, styles]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def process_token(type, token, classes, styles)
|
|
70
|
+
if token.include?(':')
|
|
71
|
+
process_key_value(type, token, classes, styles)
|
|
72
|
+
else
|
|
73
|
+
process_keyword(type, token, classes)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def process_key_value(type, token, classes, styles)
|
|
78
|
+
key, value = token.split(':', 2)
|
|
79
|
+
return if value.nil? || value.empty?
|
|
80
|
+
|
|
81
|
+
if COMMON_KEY_CLASS_MAP.key?(key)
|
|
82
|
+
css_class = COMMON_KEY_CLASS_MAP[key].call(value)
|
|
83
|
+
classes << css_class if css_class
|
|
84
|
+
else
|
|
85
|
+
process_type_specific_key_value(type, key, value, classes, styles)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def process_type_specific_key_value(type, key, value, classes, styles)
|
|
90
|
+
case key
|
|
91
|
+
when 'min'
|
|
92
|
+
styles << "--min-column-size: #{sanitize_css(value)}" if type == 'grid'
|
|
93
|
+
when 'size'
|
|
94
|
+
styles << "--flank-size: #{sanitize_css(value)}" if type == 'flank'
|
|
95
|
+
when 'content'
|
|
96
|
+
styles << "--content-percentage: #{sanitize_css(value)}" if type == 'flank'
|
|
97
|
+
when 'radius'
|
|
98
|
+
classes << "wa-border-radius-#{value}" if type == 'frame' && VALID_RADII.include?(value)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def process_keyword(type, token, classes)
|
|
103
|
+
modifiers = KEYWORD_MODIFIERS[type.to_sym]
|
|
104
|
+
return unless modifiers&.include?(token)
|
|
105
|
+
|
|
106
|
+
classes[0] = "wa-#{type}:#{token}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def sanitize_css(value)
|
|
110
|
+
value.gsub(/["'<>;]/, '')
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def build_html(classes, styles, inner_content)
|
|
114
|
+
attr_parts = ["class=\"#{classes.join(' ')}\""]
|
|
115
|
+
attr_parts << "style=\"#{styles.join('; ')}\"" unless styles.empty?
|
|
116
|
+
|
|
117
|
+
"<div #{attr_parts.join(' ')}>\n#{inner_content}\n</div>"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'base_transformer'
|
|
4
4
|
require_relative '../attribute_parser'
|
|
5
|
+
require_relative '../icon_slot_parser'
|
|
5
6
|
|
|
6
7
|
module Markawesome
|
|
7
8
|
# Transforms tag syntax into wa-tag elements
|
|
@@ -25,6 +26,8 @@ module Markawesome
|
|
|
25
26
|
'with-remove': %w[with-remove]
|
|
26
27
|
}.freeze
|
|
27
28
|
|
|
29
|
+
ICON_SLOTS = { default: 'content', slots: %w[content] }.freeze
|
|
30
|
+
|
|
28
31
|
def self.transform(content)
|
|
29
32
|
# Define regex patterns
|
|
30
33
|
# Block syntax (multiline with newlines) - supports both LF and CRLF
|
|
@@ -51,10 +54,14 @@ module Markawesome
|
|
|
51
54
|
params_tokens = []
|
|
52
55
|
content_tokens = []
|
|
53
56
|
|
|
54
|
-
# Separate attribute tokens from content tokens
|
|
57
|
+
# Separate attribute and icon tokens from content tokens
|
|
55
58
|
tokens.each do |token|
|
|
56
59
|
matched = COMPONENT_ATTRIBUTES.any? { |_attr, values| values.include?(token) }
|
|
57
|
-
matched
|
|
60
|
+
if matched || token.start_with?('icon:')
|
|
61
|
+
params_tokens << token
|
|
62
|
+
else
|
|
63
|
+
content_tokens << token
|
|
64
|
+
end
|
|
58
65
|
end
|
|
59
66
|
|
|
60
67
|
# Build params and content strings
|
|
@@ -81,8 +88,9 @@ module Markawesome
|
|
|
81
88
|
private
|
|
82
89
|
|
|
83
90
|
def build_tag_html(content, params)
|
|
84
|
-
# Parse
|
|
85
|
-
|
|
91
|
+
# Parse icon tokens first, then pass remaining to AttributeParser
|
|
92
|
+
icon_result = IconSlotParser.parse(params, ICON_SLOTS)
|
|
93
|
+
attributes = AttributeParser.parse(icon_result[:remaining], COMPONENT_ATTRIBUTES)
|
|
86
94
|
|
|
87
95
|
# Build HTML attributes
|
|
88
96
|
html_attrs = []
|
|
@@ -93,13 +101,14 @@ module Markawesome
|
|
|
93
101
|
html_attrs << 'with-remove' if attributes[:'with-remove']
|
|
94
102
|
|
|
95
103
|
attrs_string = html_attrs.empty? ? '' : " #{html_attrs.join(' ')}"
|
|
104
|
+
icon_html = IconSlotParser.to_html(icon_result[:icons])
|
|
96
105
|
|
|
97
106
|
tag_html = markdown_to_html(content).strip
|
|
98
107
|
|
|
99
108
|
# Remove paragraph tags if the content is just text
|
|
100
109
|
tag_html = tag_html.gsub(%r{^<p>(.*)</p>$}m, '\1')
|
|
101
110
|
|
|
102
|
-
"<wa-tag#{attrs_string}>#{tag_html}</wa-tag>"
|
|
111
|
+
"<wa-tag#{attrs_string}>#{icon_html}#{tag_html}</wa-tag>"
|
|
103
112
|
end
|
|
104
113
|
end
|
|
105
114
|
end
|
|
@@ -15,5 +15,6 @@ require_relative 'transformers/details_transformer'
|
|
|
15
15
|
require_relative 'transformers/dialog_transformer'
|
|
16
16
|
require_relative 'transformers/icon_transformer'
|
|
17
17
|
require_relative 'transformers/image_dialog_transformer'
|
|
18
|
+
require_relative 'transformers/layout_transformer'
|
|
18
19
|
require_relative 'transformers/tabs_transformer'
|
|
19
20
|
require_relative 'transformers/tag_transformer'
|
data/lib/markawesome/version.rb
CHANGED
data/lib/markawesome.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'markawesome/version'
|
|
4
|
+
require_relative 'markawesome/icon_slot_parser'
|
|
4
5
|
require_relative 'markawesome/transformer'
|
|
5
6
|
|
|
6
7
|
# Main module for Markawesome - framework-agnostic Markdown to Web Awesome component transformer
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: markawesome
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janne Waren
|
|
@@ -92,6 +92,7 @@ files:
|
|
|
92
92
|
- README.md
|
|
93
93
|
- lib/markawesome.rb
|
|
94
94
|
- lib/markawesome/attribute_parser.rb
|
|
95
|
+
- lib/markawesome/icon_slot_parser.rb
|
|
95
96
|
- lib/markawesome/transformer.rb
|
|
96
97
|
- lib/markawesome/transformers.rb
|
|
97
98
|
- lib/markawesome/transformers/badge_transformer.rb
|
|
@@ -106,6 +107,7 @@ files:
|
|
|
106
107
|
- lib/markawesome/transformers/dialog_transformer.rb
|
|
107
108
|
- lib/markawesome/transformers/icon_transformer.rb
|
|
108
109
|
- lib/markawesome/transformers/image_dialog_transformer.rb
|
|
110
|
+
- lib/markawesome/transformers/layout_transformer.rb
|
|
109
111
|
- lib/markawesome/transformers/tabs_transformer.rb
|
|
110
112
|
- lib/markawesome/transformers/tag_transformer.rb
|
|
111
113
|
- lib/markawesome/version.rb
|