feat: group people by role priority

This commit is contained in:
mohamad
2026-10-29 03:53:39 +08:00
parent 7c186b4230
commit 641f4e6cee
15 changed files with 186 additions and 45 deletions
+25
View File
@@ -0,0 +1,25 @@
from collections import OrderedDict
ROLE_PRIORITY = {"lead": 0, "leader": 0, "organizer": 1, "collaborator": 2}
ROLE_TITLES = {0: "Lead / Leader", 1: "Organizers", 2: "Collaborators"}
def person_sort_key(person):
role = (person.role or "").strip().casefold()
return (ROLE_PRIORITY.get(role, 3), role if role not in ROLE_PRIORITY else "", person.order, person.pk or 0)
def group_people(people):
groups = OrderedDict()
for person in sorted(people, key=person_sort_key):
role = (person.role or "").strip()
priority = ROLE_PRIORITY.get(role.casefold(), 3)
key = priority if priority < 3 else role.casefold()
if key not in groups:
groups[key] = {
"title": ROLE_TITLES[priority] if priority < 3 else role or "Other contributors",
"people": [],
}
groups[key]["people"].append(person)
return list(groups.values())
View File
+10
View File
@@ -0,0 +1,10 @@
from django import template
from apps.core.people import group_people
register = template.Library()
@register.filter
def people_rows(people):
return group_people(people)
@@ -0,0 +1,32 @@
# Generated by Django 5.2.16 on 2026-10-28 19:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pages', '0027_aboutsectionitem_role_and_more'),
]
operations = [
migrations.AlterModelOptions(
name='blogpostpartner',
options={'ordering': [models.Case(models.When(role__iexact='lead', then=models.Value(0)), models.When(role__iexact='leader', then=models.Value(0)), models.When(role__iexact='organizer', then=models.Value(1)), models.When(role__iexact='collaborator', then=models.Value(2)), default=models.Value(3), output_field=models.IntegerField()), 'order', 'pk'], 'verbose_name': 'Article person', 'verbose_name_plural': 'Article people'},
),
migrations.AlterField(
model_name='aboutsectionitem',
name='role',
field=models.CharField(blank=True, help_text='For People sections: Lead, Leader, Organizer, Collaborator, or any custom role name.', max_length=100, verbose_name='Role / group'),
),
migrations.AlterField(
model_name='blogpostpartner',
name='order',
field=models.PositiveIntegerField(default=0, help_text='Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.', verbose_name='Display order'),
),
migrations.AlterField(
model_name='blogpostpartner',
name='role',
field=models.CharField(default='Collaborator', help_text='Type Lead, Leader, Organizer, Collaborator, or any other role name.', max_length=100, verbose_name='Role / group'),
),
]
+12 -14
View File
@@ -4,6 +4,7 @@ from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.text import slugify from django.utils.text import slugify
from apps.core.people import person_sort_key
from apps.core.utils import CONTENT_FORMAT_CHOICES, FORMAT_MARKDOWN, FORMAT_PLAIN, render_content from apps.core.utils import CONTENT_FORMAT_CHOICES, FORMAT_MARKDOWN, FORMAT_PLAIN, render_content
from apps.core.video import VideoBlockMixin from apps.core.video import VideoBlockMixin
from apps.pages.contact_uploads import ( from apps.pages.contact_uploads import (
@@ -157,12 +158,7 @@ class AboutSection(VideoBlockMixin, models.Model):
@property @property
def ordered_people_items(self): def ordered_people_items(self):
def sort_key(item): return sorted(self.items.all(), key=person_sort_key)
role = item.role.strip().casefold()
priority = 0 if role == "organizer" else 1 if role == "collaborator" else 2
return priority, item.order, item.pk or 0
return sorted(self.items.all(), key=sort_key)
def clean(self): def clean(self):
super().clean() super().clean()
@@ -183,7 +179,7 @@ class AboutSectionItem(models.Model):
"Role / group", "Role / group",
max_length=100, max_length=100,
blank=True, blank=True,
help_text="For People sections: Organizer, Collaborator, or any custom role name.", help_text="For People sections: Lead, Leader, Organizer, Collaborator, or any custom role name.",
) )
content = models.TextField(blank=True, help_text="Description text or link label for History links.") content = models.TextField(blank=True, help_text="Description text or link label for History links.")
read_more_content = models.BooleanField(default=False, help_text="Collapse this text with a Read more button.") read_more_content = models.BooleanField(default=False, help_text="Collapse this text with a Read more button.")
@@ -212,7 +208,7 @@ class AboutSectionItem(models.Model):
@property @property
def role_label(self): def role_label(self):
if self.role.casefold() in {"organizer", "collaborator"}: if self.role.casefold() in {"lead", "leader", "organizer", "collaborator"}:
return self.role.title() return self.role.title()
return self.role return self.role
@@ -415,7 +411,7 @@ class BlogPostPartner(models.Model):
"Role / group", "Role / group",
max_length=100, max_length=100,
default="Collaborator", default="Collaborator",
help_text="Type Organizer, Collaborator, or any other role name you want to display.", help_text="Type Lead, Leader, Organizer, Collaborator, or any other role name.",
) )
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
description = models.TextField(blank=True) description = models.TextField(blank=True)
@@ -426,15 +422,17 @@ class BlogPostPartner(models.Model):
order = models.PositiveIntegerField( order = models.PositiveIntegerField(
"Display order", "Display order",
default=0, default=0,
help_text="Smaller numbers appear first. Organizers appear before collaborators, then custom roles.", help_text="Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.",
) )
class Meta: class Meta:
ordering = [ ordering = [
models.Case( models.Case(
models.When(role__iexact="organizer", then=models.Value(0)), models.When(role__iexact="lead", then=models.Value(0)),
models.When(role__iexact="collaborator", then=models.Value(1)), models.When(role__iexact="leader", then=models.Value(0)),
default=models.Value(2), models.When(role__iexact="organizer", then=models.Value(1)),
models.When(role__iexact="collaborator", then=models.Value(2)),
default=models.Value(3),
output_field=models.IntegerField(), output_field=models.IntegerField(),
), ),
"order", "order",
@@ -448,7 +446,7 @@ class BlogPostPartner(models.Model):
@property @property
def role_label(self): def role_label(self):
if self.role.casefold() in {self.ORGANIZER, self.COLLABORATOR}: if self.role.casefold() in {"lead", "leader", self.ORGANIZER, self.COLLABORATOR}:
return self.role.title() return self.role.title()
return self.role return self.role
+14 -6
View File
@@ -44,11 +44,14 @@ class AboutViewTest(TestCase):
AboutSectionItem.objects.create(section=section, title="Advisor", role="Scientific advisor", content="Advisor profile", order=1) AboutSectionItem.objects.create(section=section, title="Advisor", role="Scientific advisor", content="Advisor profile", order=1)
AboutSectionItem.objects.create(section=section, title="Collaborator", role="Collaborator", content="Collaboration profile", read_more_content=True, order=3) AboutSectionItem.objects.create(section=section, title="Collaborator", role="Collaborator", content="Collaboration profile", read_more_content=True, order=3)
AboutSectionItem.objects.create(section=section, title="Organizer", role="Organizer", content="Organizer profile", order=9) AboutSectionItem.objects.create(section=section, title="Organizer", role="Organizer", content="Organizer profile", order=9)
AboutSectionItem.objects.create(section=section, title="Leader", role="Leader", content="Leader profile", order=20)
html = self.client.get(reverse("pages:about")).content.decode() html = self.client.get(reverse("pages:about")).content.decode()
self.assertIn("People behind the work", html) self.assertIn("People behind the work", html)
self.assertIn("Scientific advisor", html) self.assertIn("Scientific advisor", html)
self.assertLess(html.index(">Organizer</h3>"), html.index(">Collaborator</h3>")) self.assertLess(html.index(">Leader</h4>"), html.index(">Organizer</h4>"))
self.assertLess(html.index(">Collaborator</h3>"), html.index(">Advisor</h3>")) self.assertLess(html.index(">Organizer</h4>"), html.index(">Collaborator</h4>"))
self.assertLess(html.index(">Collaborator</h4>"), html.index(">Advisor</h4>"))
self.assertIn("Lead / Leader", html)
self.assertIn('data-readmore="200"', html) self.assertIn('data-readmore="200"', html)
self.assertEqual(html.count('data-readmore="88"'), 1) self.assertEqual(html.count('data-readmore="88"'), 1)
@@ -113,10 +116,15 @@ class BlogViewTest(TestCase):
BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.COLLABORATOR, name="Second collaborator", order=2) BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.COLLABORATOR, name="Second collaborator", order=2)
BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.COLLABORATOR, name="First collaborator", order=1) BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.COLLABORATOR, name="First collaborator", order=1)
BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.ORGANIZER, name="Organizer", order=9) BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.ORGANIZER, name="Organizer", order=9)
BlogPostPartner.objects.create(post=self.post, role="Lead", name="Lead", order=5)
BlogPostPartner.objects.create(post=self.post, role="Leader", name="Leader", order=1)
html = self.client.get(self.post.get_absolute_url()).content.decode() html = self.client.get(self.post.get_absolute_url()).content.decode()
self.assertLess(html.index('class="blog-article rich-content'), html.index('class="blog-partners"')) self.assertLess(html.index('class="blog-article rich-content'), html.index('class="blog-partners"'))
self.assertLess(html.index('>Organizer</h3>'), html.index('>First collaborator</h3>')) self.assertLess(html.index('>Leader</h4>'), html.index('>Lead</h4>'))
self.assertLess(html.index('>First collaborator</h3>'), html.index('>Second collaborator</h3>')) self.assertLess(html.index('>Lead</h4>'), html.index('>Organizer</h4>'))
self.assertLess(html.index('>Organizer</h4>'), html.index('>First collaborator</h4>'))
self.assertLess(html.index('>First collaborator</h4>'), html.index('>Second collaborator</h4>'))
self.assertLess(html.index('Lead / Leader'), html.index('>Organizers</h3>'))
def test_partner_headings_are_shared_and_description_read_more_is_independent(self): def test_partner_headings_are_shared_and_description_read_more_is_independent(self):
branding = SiteBranding.load() branding = SiteBranding.load()
@@ -152,8 +160,8 @@ class BlogViewTest(TestCase):
BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.ORGANIZER, name="Lead", order=9) BlogPostPartner.objects.create(post=self.post, role=BlogPostPartner.ORGANIZER, name="Lead", order=9)
html = self.client.get(self.post.get_absolute_url()).content.decode() html = self.client.get(self.post.get_absolute_url()).content.decode()
self.assertIn("Scientific advisor", html) self.assertIn("Scientific advisor", html)
self.assertLess(html.index(">Lead</h3>"), html.index(">Partner</h3>")) self.assertLess(html.index(">Lead</h4>"), html.index(">Partner</h4>"))
self.assertLess(html.index(">Partner</h3>"), html.index(">Advisor</h3>")) self.assertLess(html.index(">Partner</h4>"), html.index(">Advisor</h4>"))
class ContactViewTest(TestCase): class ContactViewTest(TestCase):
@@ -0,0 +1,55 @@
# Generated by Django 5.2.16 on 2026-10-28 19:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('products', '0025_articleperson_mainproductperson_subproductperson'),
]
operations = [
migrations.AlterModelOptions(
name='articleperson',
options={'ordering': [models.Case(models.When(role__iexact='lead', then=models.Value(0)), models.When(role__iexact='leader', then=models.Value(0)), models.When(role__iexact='organizer', then=models.Value(1)), models.When(role__iexact='collaborator', then=models.Value(2)), default=models.Value(3), output_field=models.IntegerField()), 'order', 'pk'], 'verbose_name': 'Project article person', 'verbose_name_plural': 'Project article people'},
),
migrations.AlterModelOptions(
name='mainproductperson',
options={'ordering': [models.Case(models.When(role__iexact='lead', then=models.Value(0)), models.When(role__iexact='leader', then=models.Value(0)), models.When(role__iexact='organizer', then=models.Value(1)), models.When(role__iexact='collaborator', then=models.Value(2)), default=models.Value(3), output_field=models.IntegerField()), 'order', 'pk'], 'verbose_name': 'Main project person', 'verbose_name_plural': 'Main project people'},
),
migrations.AlterModelOptions(
name='subproductperson',
options={'ordering': [models.Case(models.When(role__iexact='lead', then=models.Value(0)), models.When(role__iexact='leader', then=models.Value(0)), models.When(role__iexact='organizer', then=models.Value(1)), models.When(role__iexact='collaborator', then=models.Value(2)), default=models.Value(3), output_field=models.IntegerField()), 'order', 'pk'], 'verbose_name': 'Sub-project person', 'verbose_name_plural': 'Sub-project people'},
),
migrations.AlterField(
model_name='articleperson',
name='order',
field=models.PositiveIntegerField(default=0, help_text='Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.', verbose_name='Display order'),
),
migrations.AlterField(
model_name='articleperson',
name='role',
field=models.CharField(default='Collaborator', help_text='Type Lead, Leader, Organizer, Collaborator, or any other role name.', max_length=100, verbose_name='Role / group'),
),
migrations.AlterField(
model_name='mainproductperson',
name='order',
field=models.PositiveIntegerField(default=0, help_text='Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.', verbose_name='Display order'),
),
migrations.AlterField(
model_name='mainproductperson',
name='role',
field=models.CharField(default='Collaborator', help_text='Type Lead, Leader, Organizer, Collaborator, or any other role name.', max_length=100, verbose_name='Role / group'),
),
migrations.AlterField(
model_name='subproductperson',
name='order',
field=models.PositiveIntegerField(default=0, help_text='Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.', verbose_name='Display order'),
),
migrations.AlterField(
model_name='subproductperson',
name='role',
field=models.CharField(default='Collaborator', help_text='Type Lead, Leader, Organizer, Collaborator, or any other role name.', max_length=100, verbose_name='Role / group'),
),
]
+8 -6
View File
@@ -227,7 +227,7 @@ class Article(models.Model):
class ProjectPerson(models.Model): class ProjectPerson(models.Model):
role = models.CharField( role = models.CharField(
"Role / group", max_length=100, default="Collaborator", "Role / group", max_length=100, default="Collaborator",
help_text="Type Organizer, Collaborator, or any other role name.", help_text="Type Lead, Leader, Organizer, Collaborator, or any other role name.",
) )
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
description = models.TextField(blank=True) description = models.TextField(blank=True)
@@ -239,23 +239,25 @@ class ProjectPerson(models.Model):
url = models.URLField(blank=True) url = models.URLField(blank=True)
order = models.PositiveIntegerField( order = models.PositiveIntegerField(
"Display order", default=0, "Display order", default=0,
help_text="Smaller numbers appear first. Organizers appear before collaborators, then custom roles.", help_text="Smaller numbers appear first within each role. Leads/Leaders, Organizers, Collaborators, then custom roles.",
) )
class Meta: class Meta:
abstract = True abstract = True
ordering = [ ordering = [
models.Case( models.Case(
models.When(role__iexact="organizer", then=models.Value(0)), models.When(role__iexact="lead", then=models.Value(0)),
models.When(role__iexact="collaborator", then=models.Value(1)), models.When(role__iexact="leader", then=models.Value(0)),
default=models.Value(2), output_field=models.IntegerField(), models.When(role__iexact="organizer", then=models.Value(1)),
models.When(role__iexact="collaborator", then=models.Value(2)),
default=models.Value(3), output_field=models.IntegerField(),
), ),
"order", "pk", "order", "pk",
] ]
@property @property
def role_label(self): def role_label(self):
return self.role.title() if self.role.casefold() in {"organizer", "collaborator"} else self.role return self.role.title() if self.role.casefold() in {"lead", "leader", "organizer", "collaborator"} else self.role
def __str__(self): def __str__(self):
return f"{self.name} ({self.role_label})" return f"{self.name} ({self.role_label})"
+6
View File
@@ -62,11 +62,17 @@ class MainProductDetailViewTest(ProductViewsSetup):
def test_project_and_article_people_are_independent_and_ordered(self): def test_project_and_article_people_are_independent_and_ordered(self):
MainProductPerson.objects.create(main_product=self.main_product, name="Main collaborator", role="Collaborator", order=1) MainProductPerson.objects.create(main_product=self.main_product, name="Main collaborator", role="Collaborator", order=1)
MainProductPerson.objects.create(main_product=self.main_product, name="Main organizer", role="Organizer", order=9) MainProductPerson.objects.create(main_product=self.main_product, name="Main organizer", role="Organizer", order=9)
MainProductPerson.objects.create(main_product=self.main_product, name="Main leader", role="Leader", order=2)
MainProductPerson.objects.create(main_product=self.main_product, name="Main lead", role="Lead", order=1)
main_article = Article.objects.create(main_product=self.main_product, title="Main article", description="Text") main_article = Article.objects.create(main_product=self.main_product, title="Main article", description="Text")
ArticlePerson.objects.create(article=main_article, name="Article advisor", role="Scientific advisor", order=0) ArticlePerson.objects.create(article=main_article, name="Article advisor", role="Scientific advisor", order=0)
response = self.client.get(self.main_product.get_absolute_url()) response = self.client.get(self.main_product.get_absolute_url())
html = response.content.decode() html = response.content.decode()
self.assertLess(html.index("Main lead"), html.index("Main leader"))
self.assertLess(html.index("Main leader"), html.index("Main organizer"))
self.assertLess(html.index("Main organizer"), html.index("Main collaborator")) self.assertLess(html.index("Main organizer"), html.index("Main collaborator"))
self.assertLess(html.index("Lead / Leader"), html.index(">Organizers</h3>"))
self.assertLess(html.index(">Organizers</h3>"), html.index(">Collaborators</h3>"))
self.assertContains(response, "Article advisor") self.assertContains(response, "Article advisor")
self.assertNotContains(response, "Sub collaborator") self.assertNotContains(response, "Sub collaborator")
self.assertContains(response, f'id="article-{main_article.pk}-people"') self.assertContains(response, f'id="article-{main_article.pk}-people"')
+5 -3
View File
@@ -123,15 +123,17 @@ body::before {
.blog-partners-eyebrow { display: block; color: var(--accent-blue-light); font-size: .65rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; } .blog-partners-eyebrow { display: block; color: var(--accent-blue-light); font-size: .65rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }
.blog-partners-heading h2 { margin-top: .45rem; font-size: clamp(1.2rem, 2vw, 1.5rem); line-height: 1.35; } .blog-partners-heading h2 { margin-top: .45rem; font-size: clamp(1.2rem, 2vw, 1.5rem); line-height: 1.35; }
.blog-partners-heading h4 { margin-top: .45rem; font-size: 1.15rem; line-height: 1.35; } .blog-partners-heading h4 { margin-top: .45rem; font-size: 1.15rem; line-height: 1.35; }
.people-role-row + .people-role-row { margin-top: 1.65rem; padding-top: 1.65rem; border-top: 1px solid rgba(255,255,255,.14); }
.people-role-heading { margin: 0 0 .85rem; color: var(--text-secondary); font-size: .78rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.blog-partners-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1rem; } .blog-partners-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1rem; }
.blog-partner-card { display: flex; flex-direction: column; gap: .85rem; padding: .8rem; min-width: 0; } .blog-partner-card { display: flex; flex-direction: column; gap: .85rem; padding: .8rem; min-width: 0; }
.blog-partner-image { width: 100%; aspect-ratio: 1 / 1; border-radius: 12px; background: rgba(255,255,255,.08); overflow: hidden; display: grid; place-items: center; } .blog-partner-image { width: 100%; aspect-ratio: 1 / 1; border-radius: 12px; background: rgba(255,255,255,.08); overflow: hidden; display: grid; place-items: center; }
.blog-partner-image img { width: 100%; height: 100%; object-fit: cover; object-position: center 25%; } .blog-partner-image img { width: 100%; height: 100%; object-fit: cover; object-position: center 25%; }
.blog-partner-info { min-width: 0; } .blog-partner-info { min-width: 0; }
.blog-partner-role { display: block; color: var(--accent-blue-light); font-size: .62rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; margin-bottom: .35rem; } .blog-partner-role { display: block; color: var(--accent-blue-light); font-size: .62rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; margin-bottom: .35rem; }
.blog-partner-info h3, .blog-partner-info h5 { font-size: .9rem; line-height: 1.35; margin: 0 0 .4rem; } .blog-partner-info h3, .blog-partner-info h4, .blog-partner-info h5, .blog-partner-info h6 { font-size: .9rem; line-height: 1.35; margin: 0 0 .4rem; }
.blog-partner-info h3 a, .blog-partner-info h5 a { color: inherit; } .blog-partner-info h3 a, .blog-partner-info h4 a, .blog-partner-info h5 a, .blog-partner-info h6 a { color: inherit; }
.blog-partner-info h3 a:hover, .blog-partner-info h5 a:hover { color: var(--accent-blue-light); } .blog-partner-info h3 a:hover, .blog-partner-info h4 a:hover, .blog-partner-info h5 a:hover, .blog-partner-info h6 a:hover { color: var(--accent-blue-light); }
.blog-partner-info p { color: var(--text-secondary); font-size: .76rem; line-height: 1.55; margin: 0; } .blog-partner-info p { color: var(--text-secondary); font-size: .76rem; line-height: 1.55; margin: 0; }
@media (max-width: 950px) { .blog-partners-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } } @media (max-width: 950px) { .blog-partners-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 620px) { .blog-partners-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (max-width: 620px) { .blog-partners-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+1 -5
View File
@@ -33,11 +33,7 @@
{% if site_branding.article_people_eyebrow %}<span class="blog-partners-eyebrow">{{ site_branding.article_people_eyebrow }}</span>{% endif %} {% if site_branding.article_people_eyebrow %}<span class="blog-partners-eyebrow">{{ site_branding.article_people_eyebrow }}</span>{% endif %}
<h2 id="blog-partners-title">{{ site_branding.article_people_title }}</h2> <h2 id="blog-partners-title">{{ site_branding.article_people_title }}</h2>
</div> </div>
<div class="blog-partners-grid"> {% include "partials/_people_rows.html" with people=partners %}
{% for partner in partners %}
{% include "partials/_person_card.html" with person=partner body=partner.description read_more=partner.read_more_description %}
{% endfor %}
</div>
</section> </section>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
+1 -5
View File
@@ -322,11 +322,7 @@
<h2 id="people-heading-{{ section.pk }}">{{ section.title|default:"People" }}</h2> <h2 id="people-heading-{{ section.pk }}">{{ section.title|default:"People" }}</h2>
{% if section.content %}<div class="rich-content section-desc" {% if section.read_more_content %}data-readmore="200"{% endif %}>{{ section.rendered_content }}</div>{% endif %} {% if section.content %}<div class="rich-content section-desc" {% if section.read_more_content %}data-readmore="200"{% endif %}>{{ section.rendered_content }}</div>{% endif %}
</div> </div>
<div class="blog-partners-grid"> {% include "partials/_people_rows.html" with people=people about=True %}
{% for person in people %}
{% include "partials/_person_card.html" with person=person body=person.content read_more=person.read_more_content %}
{% endfor %}
</div>
</div> </div>
</div> </div>
</section> </section>
+15
View File
@@ -0,0 +1,15 @@
{% load people %}
{% for row in people|people_rows %}
<div class="people-role-row">
{% if embedded %}<h5 class="people-role-heading">{{ row.title }}</h5>{% else %}<h3 class="people-role-heading">{{ row.title }}</h3>{% endif %}
<div class="blog-partners-grid">
{% for person in row.people %}
{% if about %}
{% include "partials/_person_card.html" with person=person body=person.content read_more=person.read_more_content grouped=True %}
{% else %}
{% include "partials/_person_card.html" with person=person body=person.description read_more=person.read_more_description embedded=embedded grouped=True %}
{% endif %}
{% endfor %}
</div>
</div>
{% endfor %}
+1 -5
View File
@@ -4,10 +4,6 @@
{% if eyebrow %}<span class="blog-partners-eyebrow">{{ eyebrow }}</span>{% endif %} {% if eyebrow %}<span class="blog-partners-eyebrow">{{ eyebrow }}</span>{% endif %}
{% if embedded %}<h4 id="{{ heading_id }}">{{ title }}</h4>{% else %}<h2 id="{{ heading_id }}">{{ title }}</h2>{% endif %} {% if embedded %}<h4 id="{{ heading_id }}">{{ title }}</h4>{% else %}<h2 id="{{ heading_id }}">{{ title }}</h2>{% endif %}
</div> </div>
<div class="blog-partners-grid"> {% include "partials/_people_rows.html" with people=people embedded=embedded %}
{% for person in people %}
{% include "partials/_person_card.html" with person=person body=person.description read_more=person.read_more_description embedded=embedded %}
{% endfor %}
</div>
</section> </section>
{% endif %} {% endif %}
+1 -1
View File
@@ -2,7 +2,7 @@
{% if person.image %}<div class="blog-partner-image"><img src="{{ person.image.url }}" alt="{{ person.image_alt|default:person.name }}" loading="lazy"></div>{% endif %} {% if person.image %}<div class="blog-partner-image"><img src="{{ person.image.url }}" alt="{{ person.image_alt|default:person.name }}" loading="lazy"></div>{% endif %}
<div class="blog-partner-info"> <div class="blog-partner-info">
{% if person.role_label %}<span class="blog-partner-role">{{ person.role_label }}</span>{% endif %} {% if person.role_label %}<span class="blog-partner-role">{{ person.role_label }}</span>{% endif %}
{% if embedded %}<h5>{% if person.url %}<a href="{{ person.url }}" target="_blank" rel="noopener noreferrer">{{ person.name }}</a>{% else %}{{ person.name }}{% endif %}</h5>{% else %}<h3>{% if person.url %}<a href="{{ person.url }}" target="_blank" rel="noopener noreferrer">{{ person.name }}</a>{% else %}{{ person.name }}{% endif %}</h3>{% endif %} {% if embedded %}<h6>{% if person.url %}<a href="{{ person.url }}" target="_blank" rel="noopener noreferrer">{{ person.name }}</a>{% else %}{{ person.name }}{% endif %}</h6>{% elif grouped %}<h4>{% if person.url %}<a href="{{ person.url }}" target="_blank" rel="noopener noreferrer">{{ person.name }}</a>{% else %}{{ person.name }}{% endif %}</h4>{% else %}<h3>{% if person.url %}<a href="{{ person.url }}" target="_blank" rel="noopener noreferrer">{{ person.name }}</a>{% else %}{{ person.name }}{% endif %}</h3>{% endif %}
{% if body %}<p {% if read_more %}data-readmore="88"{% endif %}>{{ body }}</p>{% endif %} {% if body %}<p {% if read_more %}data-readmore="88"{% endif %}>{{ body }}</p>{% endif %}
</div> </div>
</div> </div>