Skip to content

Commit 0f736a6

Browse files
authored
feat: add instance.get_classes for template components (#268)
1 parent 15aecbb commit 0f736a6

File tree

8 files changed

+95
-5
lines changed

8 files changed

+95
-5
lines changed

djangocms_frontend/component_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def _get_mixin_classes(mixins: list, suffix: str = "") -> list[type]:
2121
(mixin.rsplit(".")[0], f"{mixin.rsplit('.')[-1]}{suffix}Mixin")
2222
if "." in mixin
2323
else ("djangocms_frontend.common", f"{mixin}{suffix}Mixin")
24-
for mixin in mixins
24+
for mixin in reversed(mixins)
2525
]
2626

2727
return [_import_or_empty(module, name) for module, name in mixins]

djangocms_frontend/models.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,8 @@ def add_attribute(self, attr, value=None):
7676

7777
def get_attributes(self):
7878
attributes = self.config.get("attributes", {})
79-
classes = set(attributes.get("class", "").split()) # classes added in attriutes
80-
classes.update(self._additional_classes) # add additional classes
81-
classes = (f'class="{conditional_escape(" ".join(classes))}"') if classes else "" # to string
79+
classes = self.get_classes() # get classes
80+
classes = (f'class="{classes}"') if classes else "" # to string
8281
parts = (
8382
f'{item}="{conditional_escape(value)}"' if value else f"{item}"
8483
for item, value in attributes.items()
@@ -87,6 +86,12 @@ def get_attributes(self):
8786
attributes_string = (classes + " ".join(parts)).strip()
8887
return mark_safe(" " + attributes_string) if attributes_string else ""
8988

89+
def get_classes(self):
90+
attributes = self.config.get("attributes", {})
91+
classes = set(attributes.get("class", "").split()) # classes added in attriutes
92+
classes.update(self._additional_classes) # add additional classes
93+
return conditional_escape(" ".join(classes))
94+
9095
def save(self, *args, **kwargs):
9196
self.ui_item = self.__class__.__name__
9297
return super().save(*args, **kwargs)

docs/source/tutorial/template_components.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,9 @@ The fields declared earlier (``title``, ``slogan``, and ``hero_image``) are now
196196
<img src="{{ hero_image.url }}">
197197

198198
The ``{% childplugins %}`` block allows additional CMS plugins (like buttons) to be added inside the component
199-
in the structure editor.
199+
in the structure editor. Anything in between ``{% childplugins %}`` and ``{% endchildplugins %}`` will only be
200+
rendered if the component has no children.
201+
200202

201203
Make the component available in django CMS
202204
-------------------------------------------

examples/__init__.py

Whitespace-only changes.

examples/migrations/__init__.py

Whitespace-only changes.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{% load frontend cms_component djangocms_link_tags sekizai_tags icon_tags %}
2+
3+
{% cms_component "FeatureHanging" name=_("Feature hanging") module=_("Examples") mixins="Background|Spacing|Attributes"|split %}
4+
{% field "icon" IconPickerField required=True label=_("Icon") initial="chevron-right" %}
5+
{% field "title" forms.CharField required=True label=_("Title") initial=_("Featured title") %}
6+
{% field "description" HTMLFormField required=True label=_("Description") initial=_("<p>Paragraph of text beneath the heading to explain the heading. We'll add onto it with another sentence and probably just keep going until we run out of words.</p>") %}
7+
{% field "call_to_action" forms.CharField required=True label=_("Call to action") initial=_("Call to action") %}
8+
{% field "link" LinkFormField required=True label=_("Link") initial="#"|to_link %}
9+
10+
{% add_css_for_icon icon %}
11+
<div class="d-flex align-items-start {{ instance.get_classes }}">
12+
<div class="icon-square text-body-emphasis bg-body-secondary d-inline-flex align-items-center justify-content-center fs-4 flex-shrink-0 me-3">
13+
{% icon icon %}
14+
</div>
15+
<div>
16+
<h3 class="fs-2 text-body-emphasis">{% inline_field "title" %}</h3>
17+
{% inline_field instance "description" "" "safe" %}
18+
<a href="{{ link|to_url }}" class="btn btn-primary">
19+
{{ call_to_action }}
20+
</a>
21+
</div>
22+
</div>
23+
24+
{% addtoblock "css" %}
25+
<style>
26+
.icon-square {
27+
width: 3rem;
28+
height: 3rem;
29+
border-radius: .75rem;
30+
}
31+
</style>
32+
{% endaddtoblock %}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{% load frontend cms_component djangocms_link_tags sekizai_tags icon_tags %}
2+
3+
{% cms_component "FeatureIcon" name=_("Feature with icon") module=_("Examples") mixins="Background|Spacing|Attributes"|split %}
4+
{% field "icon" IconPickerField required=True label=_("Icon") initial="chevron-right" %}
5+
{% field "title" forms.CharField required=True label=_("Title") initial=_("Featured title") %}
6+
{% field "description" HTMLFormField required=True label=_("Description") initial=_("<p>Paragraph of text beneath the heading to explain the heading. We'll add onto it with another sentence and probably just keep going until we run out of words.</p>") %}
7+
{% field "call_to_action" forms.CharField required=True label=_("Call to action") initial=_("Call to action") %}
8+
{% field "link" LinkFormField required=True label=_("Link") initial="#"|to_link %}
9+
10+
{% add_css_for_icon icon %}
11+
<div class="feature {{ instance.get_classes }}">
12+
<div class="feature-icon d-inline-flex align-items-center justify-content-center text-bg-primary bg-gradient fs-2 mb-3">
13+
{% icon icon %}
14+
</div>
15+
<h3 class="fs-2 text-body-emphasis">{% inline_field "title" %}</h3>
16+
{% inline_field instance "description" "" "safe" %}
17+
<a href="{{ link|to_url }}" class="icon-link">
18+
{{ call_to_action }}
19+
<svg class="bi"><use xlink:href="#chevron-right"/></svg>
20+
</a>
21+
</div>
22+
23+
{% addtoblock "css" %}
24+
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
25+
<symbol id="chevron-right" viewBox="0 0 16 16">
26+
<path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708"/>
27+
</symbol>
28+
</svg>
29+
<style>
30+
.feature-icon {
31+
width: 4rem;
32+
height: 4rem;
33+
border-radius: .75rem;
34+
}
35+
</style>
36+
{% endaddtoblock %}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{% load frontend cms_component djangocms_link_tags sekizai_tags icon_tags %}
2+
3+
{% cms_component "IconGrid" name=_("Icon grid") module=_("Examples") mixins="Background|Spacing|Attributes"|split %}
4+
{% field "icon" IconPickerField required=True label=_("Icon") %}
5+
{% field "title" forms.CharField required=True label=_("Title") initial=_("Featured title") %}
6+
{% field "description" HTMLFormField required=True label=_("Description") initial=_("<p>Paragraph of text beneath the heading to explain the heading. We'll add onto it with another sentence and probably just keep going until we run out of words.</p>") %}
7+
8+
{% add_css_for_icon icon %}
9+
<div class="col d-flex align-items-start {{ instance.get_classes }}">
10+
<span class="fs-4 me-3">{% icon icon %}</span>
11+
<div>
12+
<h3 class="fw-bold mb-0 fs-4 text-body-emphasis">{% inline_field "title" %}</h3>
13+
{% inline_field instance "description" "" "safe" %}
14+
</div>
15+
</div>

0 commit comments

Comments
 (0)