Skip to content

Commit

Permalink
Fixes #39
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertoPrevato committed Jul 18, 2023
1 parent cb94a30 commit 6503a83
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file.
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).

## [1.0.3] - 2023-07-18 :cat:

- Adds support for icons in cards (by @Andy2003).
- Adds support for anchors with target="_blank" in cards.

## [1.0.2] - 2023-04-25

- Fixes detail in the `contribs` plugin: when the name is specified for a
contributor by email address, it is used.
- Improves `pyproject.toml`.
Expand Down
2 changes: 1 addition & 1 deletion neoteroi/mkdocs/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.0.2"
__version__ = "1.0.3"
25 changes: 20 additions & 5 deletions neoteroi/mkdocs/cards/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ def build_html(self, parent, obj, props) -> None:
if not isinstance(obj, list):
raise TypeError("Expected a list of items describing cards.")

if self.root_config:
new_props = dict(**self.root_config)
new_props.update(props)
props = new_props

self.norm_obj(obj)
builder = CardsHTMLBuilder(create_instance(CardsViewOptions, props))
builder.build_html(parent, Cards(create_instances(CardItem, obj)))
Expand All @@ -55,18 +60,28 @@ class CardsSourceProcessor(BaseCardsProcessor, SourceBlockProcessor):
class CardsExtension(Extension):
"""Extension that includes cards."""

config = {
"priority": [12, "The priority to be configured for the extension."],
}
def __init__(self, *args, **kwargs):
self.config = {
"priority": [12, "The priority to be configured for the extension."],
"blank_target": [False, 'Whether to generate links with target="_blank"'],
}
super().__init__(*args, **kwargs)

def extendMarkdown(self, md):
md.registerExtension(self)
priority = self.getConfig("priority")

configs = self.getConfigs()
del configs["priority"]

md.parser.blockprocessors.register(
CardsEmbeddedProcessor(md.parser), "cards", priority + 0.1
CardsEmbeddedProcessor(md.parser).with_root_config(configs),
"cards",
priority + 0.1,
)

md.parser.blockprocessors.register(
CardsSourceProcessor(md.parser), "cards-from-source", priority
CardsSourceProcessor(md.parser).with_root_config(configs),
"cards-from-source",
priority,
)
23 changes: 17 additions & 6 deletions neoteroi/mkdocs/cards/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import xml.etree.ElementTree as etree
from dataclasses import dataclass

from neoteroi.mkdocs.markdown.images import build_icon_html
from neoteroi.mkdocs.markdown.images import build_image_html
from neoteroi.mkdocs.markdown.images import build_icon_html, build_image_html

from .domain import CardItem, Cards

Expand All @@ -16,6 +15,7 @@ class CardsViewOptions:
class_name: str = ""
cols: int = 3
image_bg: bool = False
blank_target: bool = False

def __post_init__(self):
if isinstance(self.cols, str):
Expand Down Expand Up @@ -45,6 +45,14 @@ def _get_root_class(self):
return base_class + " " + self.options.class_name
return base_class

def _get_link_properties(self, item: CardItem):
assert item.url is not None
props = {"href": item.url}

if self.options.blank_target:
props.update(target="_blank", rel="noopener")
return props

def build_html(self, parent, cards: Cards):
root_element = etree.SubElement(
parent, "div", {"class": self._get_root_class()}
Expand All @@ -57,7 +65,9 @@ def build_item_html(self, parent, item: CardItem):
item_element = etree.SubElement(parent, "div", self.get_item_props(item))

if item.url:
first_child = etree.SubElement(item_element, "a", {"href": item.url})
first_child = etree.SubElement(
item_element, "a", self._get_link_properties(item)
)
else:
first_child = etree.SubElement(
item_element, "div", {"class": "nt-card-wrap"}
Expand All @@ -68,9 +78,10 @@ def build_item_html(self, parent, item: CardItem):
if item.image:
self.build_image_html(wrapper_element, item)
elif item.icon:
build_icon_html(etree.SubElement(
wrapper_element, "div", {"class": "nt-card-icon"}
), item.icon)
build_icon_html(
etree.SubElement(wrapper_element, "div", {"class": "nt-card-icon"}),
item.icon,
)

text_wrapper = etree.SubElement(
wrapper_element, "div", {"class": "nt-card-content"}
Expand Down
5 changes: 5 additions & 0 deletions neoteroi/mkdocs/markdown/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def pop_to_index(items, index):


class BaseProcessor(ABC):
root_config: dict = {}
parsers: Iterable[TextParser] = (YAMLParser(), JSONParser(), CSVParser())

@property
Expand Down Expand Up @@ -143,6 +144,10 @@ def get_match(self, pattern, blocks) -> Optional[re.Match]:

return match

def with_root_config(self, props):
self.__dict__["root_config"] = props
return self


class SourceBlockProcessor(BlockProcessor, BaseProcessor):
"""
Expand Down
77 changes: 77 additions & 0 deletions tests/test_cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
</div>
"""

EXAMPLE_1_b = """
<div class="nt-cards nt-grid cols-3">
<div class="nt-card"><a href="/some-path/a" rel="noopener" target="_blank"><div><div class="nt-card-image tags"><img src="/img/icons/lorem-ipsum-1.png" /></div><div class="nt-card-content"><p class="nt-card-title">Title A</p><p class="nt-card-text">Lorem ipsum dolor sit amet 1.</p></div></div></a></div>
<div class="nt-card"><a href="/some-path/b" rel="noopener" target="_blank"><div><div class="nt-card-image tags"><img src="/img/icons/lorem-ipsum-2.png" /></div><div class="nt-card-content"><p class="nt-card-title">Title B</p><p class="nt-card-text">Lorem ipsum dolor sit amet 2.</p></div></div></a></div>
<div class="nt-card"><a href="/some-path/c" rel="noopener" target="_blank"><div><div class="nt-card-image tags"><img src="/img/icons/lorem-ipsum-3.png" /></div><div class="nt-card-content"><p class="nt-card-title">Title C</p><p class="nt-card-text">Lorem ipsum dolor sit amet 3.</p></div></div></a></div>
<div class="nt-card"><a href="/some-path/d" rel="noopener" target="_blank"><div><div class="nt-card-image tags"><img src="/img/icons/lorem-ipsum-4.png" /></div><div class="nt-card-content"><p class="nt-card-title">Title D</p><p class="nt-card-text">Lorem ipsum dolor sit amet 4.</p></div></div></a></div>
</div>
"""

EXAMPLE_2 = """
<div class="nt-cards nt-grid cols-3">
<div class="nt-card"><a href="/some-path/a"><div><div class="nt-card-image tags"><img src="/img/icons/lorem-ipsum-1.png" /></div><div class="nt-card-content"><p class="nt-card-title">Title A</p><p class="nt-card-text">Lorem ipsum dolor sit amet 1.</p></div></div></a></div>
Expand Down Expand Up @@ -114,13 +123,81 @@ def test_base_cards_processor_raises_for_not_list_input():
""",
EXAMPLE_1,
],
[
"""
::cards:: flex=25 image-tags blank_target
- title: Title A
url: /some-path/a
content: Lorem ipsum dolor sit amet 1.
image: /img/icons/lorem-ipsum-1.png
- title: Title B
url: /some-path/b
content: Lorem ipsum dolor sit amet 2.
image: /img/icons/lorem-ipsum-2.png
- title: Title C
url: /some-path/c
content: Lorem ipsum dolor sit amet 3.
image: /img/icons/lorem-ipsum-3.png
- title: Title D
url: /some-path/d
content: Lorem ipsum dolor sit amet 4.
image: /img/icons/lorem-ipsum-4.png
::/cards::
""",
EXAMPLE_1_b,
],
],
)
def test_cards_extension_image_tags(example, expected_result):
html = markdown.markdown(example, extensions=[CardsExtension(priority=100)])
assert html.strip() == expected_result.strip()


@pytest.mark.parametrize(
"example,expected_result",
[
[
"""
::cards:: flex=25 image-tags
- title: Title A
url: /some-path/a
content: Lorem ipsum dolor sit amet 1.
image: /img/icons/lorem-ipsum-1.png
- title: Title B
url: /some-path/b
content: Lorem ipsum dolor sit amet 2.
image: /img/icons/lorem-ipsum-2.png
- title: Title C
url: /some-path/c
content: Lorem ipsum dolor sit amet 3.
image: /img/icons/lorem-ipsum-3.png
- title: Title D
url: /some-path/d
content: Lorem ipsum dolor sit amet 4.
image: /img/icons/lorem-ipsum-4.png
::/cards::
""",
EXAMPLE_1_b,
],
],
)
def test_cards_extension_target_blank_config(example, expected_result):
html = markdown.markdown(
example, extensions=[CardsExtension(priority=100, blank_target=True)]
)
assert html.strip() == expected_result.strip()


@pytest.mark.parametrize(
"example,expected_result",
[
Expand Down

0 comments on commit 6503a83

Please sign in to comment.