diff --git a/apps/core/management/commands/seed_content.py b/apps/core/management/commands/seed_content.py index e9e36b3..3ec612d 100644 --- a/apps/core/management/commands/seed_content.py +++ b/apps/core/management/commands/seed_content.py @@ -21,6 +21,8 @@ MAIN_PRODUCTS = [ "(IBSI 1.0), and implements image filters standardized against IBSI 2.0." ), "order": 1, + "show_on_homepage": True, + "homepage_order": 1, "sub_products": [ { "name": "Image Processing", @@ -34,8 +36,6 @@ MAIN_PRODUCTS = [ "for consistent, reproducible research outcomes." ), "order": 1, - "show_on_homepage": True, - "homepage_order": 1, "articles": [ { "title": "Image Filtering Techniques", @@ -408,10 +408,6 @@ class Command(BaseCommand): self.stdout.write(self.style.SUCCESS("Content seeded successfully.")) def _seed_products(self): - SubProduct.objects.filter(show_on_homepage=False, homepage_order=0).update( - show_on_homepage=True, - ) - for product_data in MAIN_PRODUCTS: sub_products_data = product_data.pop("sub_products") main_product, created = MainProduct.objects.get_or_create( diff --git a/apps/pages/admin.py b/apps/pages/admin.py index 9af651f..41b636a 100644 --- a/apps/pages/admin.py +++ b/apps/pages/admin.py @@ -46,13 +46,13 @@ class HeroSectionAdmin(admin.ModelAdmin): class HomepageSectionItemInline(admin.TabularInline): model = HomepageSectionItem extra = 1 - fields = ("icon", "title", "content", "image", "order") + fields = ("icon", "title", "content", "url", "image", "order") ordering = ("order",) @admin.register(HomepageSection) class HomepageSectionAdmin(admin.ModelAdmin): - list_display = ("section_type", "badge", "title", "order", "is_active") + list_display = ("section_type", "title", "badge", "order", "is_active") list_filter = ("section_type", "is_active") list_editable = ("order", "is_active") inlines = [HomepageSectionItemInline] @@ -147,22 +147,33 @@ class CustomPageSectionInline(admin.StackedInline): show_change_link = True -@admin.register(CustomPage) -class CustomPageAdmin(admin.ModelAdmin): - list_display = ("title", "slug", "show_in_nav", "menu_order", "is_published", "updated_at") - list_filter = ("show_in_nav", "is_published") - search_fields = ("title", "slug", "menu_label") - list_editable = ("show_in_nav", "menu_order", "is_published") - prepopulated_fields = {"slug": ("title",)} - inlines = [CustomPageSectionInline] - fieldsets = ( - (None, {"fields": ("title", "slug", "menu_label", "meta_description")}), - ("Navigation", {"fields": ("show_in_nav", "menu_order")}), - ("Publishing", {"fields": ("is_published",)}), +class CustomPageSectionItemOnPageInline(admin.TabularInline): + model = CustomPageSectionItem + fk_name = "page" + extra = 1 + verbose_name = "Section item" + verbose_name_plural = "Section items (subsections)" + fields = ( + "section", + "icon", + "badge", + "title", + "content_format", + "content", + "url", + "image", + "order", ) + ordering = ("section", "order") + + def formfield_for_foreignkey(self, db_field, request, **kwargs): + if db_field.name == "section": + page_id = request.resolver_match.kwargs.get("object_id") if request.resolver_match else None + if page_id: + kwargs["queryset"] = CustomPageSection.objects.filter(page_id=page_id).order_by("order") + return super().formfield_for_foreignkey(db_field, request, **kwargs) -@admin.register(CustomPageSection) class CustomPageSectionAdmin(admin.ModelAdmin): list_display = ("page", "section_type", "title", "order", "is_active") list_filter = ("section_type", "is_active", "page") @@ -175,6 +186,44 @@ class CustomPageSectionAdmin(admin.ModelAdmin): ("Settings", {"fields": ("order", "is_active")}), ) + def save_formset(self, request, form, formset, change): + instances = formset.save(commit=False) + for instance in instances: + if isinstance(instance, CustomPageSectionItem): + instance.page = form.instance.page + instance.save() + for obj in formset.deleted_objects: + obj.delete() + formset.save_m2m() + + +@admin.register(CustomPage) +class CustomPageAdmin(admin.ModelAdmin): + list_display = ("title", "slug", "show_in_nav", "menu_order", "is_published", "updated_at") + list_filter = ("show_in_nav", "is_published") + search_fields = ("title", "slug", "menu_label") + list_editable = ("show_in_nav", "menu_order", "is_published") + prepopulated_fields = {"slug": ("title",)} + inlines = [CustomPageSectionInline, CustomPageSectionItemOnPageInline] + fieldsets = ( + (None, {"fields": ("title", "slug", "menu_label", "meta_description")}), + ("Navigation", {"fields": ("show_in_nav", "menu_order")}), + ("Publishing", {"fields": ("is_published",)}), + ) + + def save_formset(self, request, form, formset, change): + instances = formset.save(commit=False) + for instance in instances: + if isinstance(instance, CustomPageSectionItem): + instance.page = form.instance + instance.save() + for obj in formset.deleted_objects: + obj.delete() + formset.save_m2m() + + +admin.site.register(CustomPageSection, CustomPageSectionAdmin) + @admin.register(DownloadItem) class DownloadItemAdmin(admin.ModelAdmin): diff --git a/apps/pages/migrations/0009_alter_homepagesection_section_type.py b/apps/pages/migrations/0009_alter_homepagesection_section_type.py new file mode 100644 index 0000000..3eb8b52 --- /dev/null +++ b/apps/pages/migrations/0009_alter_homepagesection_section_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2026-05-26 12:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pages', '0008_custom_pages'), + ] + + operations = [ + migrations.AlterField( + model_name='homepagesection', + name='section_type', + field=models.CharField(choices=[('features', 'Features'), ('screenshots', 'Screenshots Gallery'), ('products', 'Products'), ('problems', 'Problems / Value Proposition'), ('about_strip', 'About Strip'), ('supporters', 'Supporters')], max_length=30), + ), + ] diff --git a/apps/pages/migrations/0010_homepagesectionitem_url_and_more.py b/apps/pages/migrations/0010_homepagesectionitem_url_and_more.py new file mode 100644 index 0000000..6e08b29 --- /dev/null +++ b/apps/pages/migrations/0010_homepagesectionitem_url_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.0.2 on 2026-05-26 12:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pages', '0009_alter_homepagesection_section_type'), + ] + + operations = [ + migrations.AddField( + model_name='homepagesectionitem', + name='url', + field=models.CharField(blank=True, help_text='Optional link; makes this item clickable.', max_length=300), + ), + migrations.AlterField( + model_name='custompagesection', + name='section_type', + field=models.CharField(choices=[('hero', 'Hero'), ('intro', 'Intro Card'), ('grid', 'Grid Cards'), ('history', 'History Block'), ('custom', 'Custom Content'), ('features', 'Features Grid'), ('screenshots', 'Screenshots Gallery'), ('products', 'Products Grid'), ('products_catalog', 'Products with Sub-products'), ('problems', 'Problems / Value Proposition'), ('supporters', 'Supporters'), ('about_strip', 'About Strip'), ('faq', 'FAQ Accordion')], default='custom', max_length=30), + ), + migrations.AlterField( + model_name='custompagesectionitem', + name='url', + field=models.CharField(blank=True, help_text='Optional link; makes this item clickable.', max_length=300), + ), + migrations.AlterField( + model_name='homepagesection', + name='section_type', + field=models.CharField(choices=[('features', 'Features'), ('screenshots', 'Screenshots Gallery'), ('products', 'Products'), ('products_catalog', 'Products with Sub-products'), ('problems', 'Problems / Value Proposition'), ('about_strip', 'About Strip'), ('supporters', 'Supporters')], max_length=30), + ), + ] diff --git a/apps/pages/migrations/0011_custompagesectionitem_page_aboutsectionitem_url.py b/apps/pages/migrations/0011_custompagesectionitem_page_aboutsectionitem_url.py new file mode 100644 index 0000000..62dad68 --- /dev/null +++ b/apps/pages/migrations/0011_custompagesectionitem_page_aboutsectionitem_url.py @@ -0,0 +1,48 @@ +from django.db import migrations, models +import django.db.models.deletion + + +def set_custom_page_section_item_page(apps, schema_editor): + CustomPageSectionItem = apps.get_model("pages", "CustomPageSectionItem") + for item in CustomPageSectionItem.objects.select_related("section").iterator(): + item.page_id = item.section.page_id + item.save(update_fields=["page_id"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ("pages", "0010_homepagesectionitem_url_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="aboutsectionitem", + name="url", + field=models.CharField( + blank=True, + help_text="Optional link; makes this item clickable.", + max_length=300, + ), + ), + migrations.AddField( + model_name="custompagesectionitem", + name="page", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="section_items", + to="pages.custompage", + ), + ), + migrations.RunPython(set_custom_page_section_item_page, migrations.RunPython.noop), + migrations.AlterField( + model_name="custompagesectionitem", + name="page", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="section_items", + to="pages.custompage", + ), + ), + ] diff --git a/apps/pages/models.py b/apps/pages/models.py index 8091c69..37ba61c 100644 --- a/apps/pages/models.py +++ b/apps/pages/models.py @@ -41,6 +41,7 @@ class HomepageSection(models.Model): TYPE_FEATURES = "features" TYPE_SCREENSHOTS = "screenshots" TYPE_PRODUCTS = "products" + TYPE_PRODUCTS_CATALOG = "products_catalog" TYPE_PROBLEMS = "problems" TYPE_ABOUT_STRIP = "about_strip" TYPE_SUPPORTERS = "supporters" @@ -49,12 +50,13 @@ class HomepageSection(models.Model): (TYPE_FEATURES, "Features"), (TYPE_SCREENSHOTS, "Screenshots Gallery"), (TYPE_PRODUCTS, "Products"), + (TYPE_PRODUCTS_CATALOG, "Products with Sub-products"), (TYPE_PROBLEMS, "Problems / Value Proposition"), (TYPE_ABOUT_STRIP, "About Strip"), (TYPE_SUPPORTERS, "Supporters"), ] - section_type = models.CharField(max_length=30, choices=TYPE_CHOICES, unique=True) + section_type = models.CharField(max_length=30, choices=TYPE_CHOICES) badge = models.CharField(max_length=100, blank=True) title = models.CharField(max_length=300, blank=True) description = models.TextField(blank=True) @@ -77,6 +79,7 @@ class HomepageSectionItem(models.Model): icon = models.CharField(max_length=20, blank=True, help_text="Emoji or short symbol (e.g. ⚗️).") title = models.CharField(max_length=300, blank=True) content = models.TextField(blank=True) + url = models.CharField(max_length=300, blank=True, help_text="Optional link; makes this item clickable.") image = models.ImageField(upload_to="homepage/items/", blank=True, null=True, help_text="Logo or image (used for Supporters cards).") order = models.PositiveIntegerField(default=0) @@ -134,7 +137,7 @@ class AboutSectionItem(models.Model): badge = models.CharField(max_length=100, blank=True) title = models.CharField(max_length=300, blank=True) content = models.TextField(blank=True, help_text="Description text or link label for History links.") - url = models.URLField(blank=True, help_text="Used for History block links.") + url = models.CharField(max_length=300, blank=True, help_text="Optional link; makes this item clickable.") image = models.ImageField(upload_to="about/", blank=True, null=True) image_alt = models.CharField(max_length=200, blank=True) is_featured = models.BooleanField(default=False, help_text="Mark as featured item (e.g. large screenshot).") @@ -267,6 +270,7 @@ class CustomPageSection(models.Model): TYPE_FEATURES = "features" TYPE_SCREENSHOTS = "screenshots" TYPE_PRODUCTS = "products" + TYPE_PRODUCTS_CATALOG = "products_catalog" TYPE_PROBLEMS = "problems" TYPE_SUPPORTERS = "supporters" TYPE_ABOUT_STRIP = "about_strip" @@ -281,6 +285,7 @@ class CustomPageSection(models.Model): (TYPE_FEATURES, "Features Grid"), (TYPE_SCREENSHOTS, "Screenshots Gallery"), (TYPE_PRODUCTS, "Products Grid"), + (TYPE_PRODUCTS_CATALOG, "Products with Sub-products"), (TYPE_PROBLEMS, "Problems / Value Proposition"), (TYPE_SUPPORTERS, "Supporters"), (TYPE_ABOUT_STRIP, "About Strip"), @@ -315,13 +320,18 @@ class CustomPageSection(models.Model): class CustomPageSectionItem(models.Model): + page = models.ForeignKey( + CustomPage, + on_delete=models.CASCADE, + related_name="section_items", + ) section = models.ForeignKey(CustomPageSection, on_delete=models.CASCADE, related_name="items") icon = models.CharField(max_length=20, blank=True) badge = models.CharField(max_length=100, blank=True) title = models.CharField(max_length=300, blank=True) content = models.TextField(blank=True) content_format = models.CharField(max_length=20, choices=CONTENT_FORMAT_CHOICES, default=FORMAT_PLAIN) - url = models.URLField(blank=True) + url = models.CharField(max_length=300, blank=True, help_text="Optional link; makes this item clickable.") image = models.ImageField(upload_to="pages/custom/", blank=True, null=True) image_alt = models.CharField(max_length=200, blank=True) is_featured = models.BooleanField(default=False) @@ -336,5 +346,10 @@ class CustomPageSectionItem(models.Model): def rendered_content(self): return render_content(self.content, self.content_format) + def save(self, *args, **kwargs): + if self.section_id: + self.page_id = self.section.page_id + super().save(*args, **kwargs) + def __str__(self): return f"{self.section} › {self.title or self.icon or '(item)'}" diff --git a/apps/pages/tests/test_custom_pages.py b/apps/pages/tests/test_custom_pages.py index f4bdd54..b7f6792 100644 --- a/apps/pages/tests/test_custom_pages.py +++ b/apps/pages/tests/test_custom_pages.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.urls import reverse -from apps.pages.models import CustomPage, CustomPageSection +from apps.pages.models import CustomPage, CustomPageSection, CustomPageSectionItem class CustomPageViewTest(TestCase): @@ -40,6 +40,26 @@ class CustomPageViewTest(TestCase): response = self.client.get(reverse("pages:custom_page", kwargs={"slug": "missing"})) self.assertEqual(response.status_code, 404) + def test_section_item_with_url_renders_as_link(self): + section = CustomPageSection.objects.create( + page=self.page, + section_type=CustomPageSection.TYPE_FEATURES, + title="Highlights", + is_active=True, + ) + CustomPageSectionItem.objects.create( + page=self.page, + section=section, + title="Documentation", + content="Read the docs.", + url="/about/", + order=1, + ) + response = self.client.get(reverse("pages:custom_page", kwargs={"slug": "resources"})) + self.assertContains(response, 'href="/about/"') + self.assertContains(response, "section-item-link") + self.assertContains(response, "Documentation") + class CustomPageNavTest(TestCase): def test_nav_custom_pages_in_context(self): diff --git a/apps/pages/views.py b/apps/pages/views.py index b8fff2c..2a0836a 100644 --- a/apps/pages/views.py +++ b/apps/pages/views.py @@ -1,11 +1,12 @@ import random +from django.db.models import Prefetch from django.http import JsonResponse from django.shortcuts import render from django.views import View from django.views.generic import DetailView, ListView, TemplateView -from apps.products.models import SubProduct +from apps.products.models import MainProduct, SubProduct from .forms import ContactForm from .models import ( @@ -18,6 +19,19 @@ from .models import ( ) +def _homepage_products_catalog_queryset(): + return ( + MainProduct.objects.filter(is_active=True) + .prefetch_related( + Prefetch( + "sub_products", + queryset=SubProduct.objects.filter(is_active=True).order_by("order", "name"), + ) + ) + .order_by("order", "name") + ) + + class HomeView(TemplateView): template_name = "pages/home.html" @@ -29,11 +43,11 @@ class HomeView(TemplateView): .prefetch_related("items") .order_by("order") ) - ctx["sub_products"] = ( - SubProduct.objects.filter(is_active=True, show_on_homepage=True) - .select_related("main_product") + ctx["homepage_products"] = ( + MainProduct.objects.filter(is_active=True, show_on_homepage=True) .order_by("homepage_order", "order") ) + ctx["homepage_products_catalog"] = _homepage_products_catalog_queryset() return ctx @@ -115,9 +129,9 @@ class CustomPageView(DetailView): .prefetch_related("items") .order_by("order") ) - ctx["sub_products"] = ( - SubProduct.objects.filter(is_active=True, show_on_homepage=True) - .select_related("main_product") + ctx["homepage_products"] = ( + MainProduct.objects.filter(is_active=True, show_on_homepage=True) .order_by("homepage_order", "order") ) + ctx["homepage_products_catalog"] = _homepage_products_catalog_queryset() return ctx diff --git a/apps/products/admin.py b/apps/products/admin.py index 5a887fe..38f720c 100644 --- a/apps/products/admin.py +++ b/apps/products/admin.py @@ -76,16 +76,17 @@ class SubProductInline(admin.StackedInline): @admin.register(MainProduct) class MainProductAdmin(admin.ModelAdmin): - list_display = ("name", "order", "is_active", "created_at") - list_filter = ("is_active",) + list_display = ("name", "show_on_homepage", "homepage_order", "order", "is_active", "created_at") + list_filter = ("is_active", "show_on_homepage") search_fields = ("name", "description") prepopulated_fields = {"slug": ("name",)} - list_editable = ("order", "is_active") + list_editable = ("order", "is_active", "show_on_homepage", "homepage_order") inlines = [MainProductArticleInline, MainProductVersionInline, SubProductInline] fieldsets = ( (None, {"fields": ("name", "slug", "short_description", "distribution")}), ("Description", {"fields": ("description_format", "description")}), ("Media", {"fields": ("image",)}), + ("Homepage", {"fields": ("show_on_homepage", "homepage_order")}), ("Settings", {"fields": ("order", "is_active")}), ) diff --git a/apps/products/migrations/0011_mainproduct_homepage_order_and_more.py b/apps/products/migrations/0011_mainproduct_homepage_order_and_more.py new file mode 100644 index 0000000..74ae5cb --- /dev/null +++ b/apps/products/migrations/0011_mainproduct_homepage_order_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.2 on 2026-05-26 12:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('products', '0010_release_version_main_product'), + ] + + operations = [ + migrations.AddField( + model_name='mainproduct', + name='homepage_order', + field=models.PositiveIntegerField(default=0, help_text='Order within the homepage Products section.'), + ), + migrations.AddField( + model_name='mainproduct', + name='show_on_homepage', + field=models.BooleanField(default=False, help_text='Display this product in the homepage Products section.'), + ), + ] diff --git a/apps/products/migrations/0012_migrate_homepage_visibility_to_mainproduct.py b/apps/products/migrations/0012_migrate_homepage_visibility_to_mainproduct.py new file mode 100644 index 0000000..ef974c3 --- /dev/null +++ b/apps/products/migrations/0012_migrate_homepage_visibility_to_mainproduct.py @@ -0,0 +1,26 @@ +from django.db import migrations + + +def copy_subproduct_homepage_flags(apps, schema_editor): + SubProduct = apps.get_model("products", "SubProduct") + for sub in ( + SubProduct.objects.filter(show_on_homepage=True) + .select_related("main_product") + .order_by("homepage_order", "order") + ): + main = sub.main_product + if not main.show_on_homepage: + main.show_on_homepage = True + main.homepage_order = sub.homepage_order + main.save(update_fields=["show_on_homepage", "homepage_order"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ("products", "0011_mainproduct_homepage_order_and_more"), + ] + + operations = [ + migrations.RunPython(copy_subproduct_homepage_flags, migrations.RunPython.noop), + ] diff --git a/apps/products/models.py b/apps/products/models.py index 810007e..220f6f2 100644 --- a/apps/products/models.py +++ b/apps/products/models.py @@ -38,6 +38,8 @@ class MainProduct(models.Model): ) order = models.PositiveIntegerField(default=0) is_active = models.BooleanField(default=True) + show_on_homepage = models.BooleanField(default=False, help_text="Display this product in the homepage Products section.") + homepage_order = models.PositiveIntegerField(default=0, help_text="Order within the homepage Products section.") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) diff --git a/static/css/main.css b/static/css/main.css index 1dff5c3..c13627c 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -853,6 +853,44 @@ h1, h2, h3, h4, h5, h6 { line-height: 1.65; } +a.section-item-link { + text-decoration: none; + color: inherit; + transition: var(--transition-fast); +} + +a.section-item-link:hover { + border-color: rgba(79, 142, 247, 0.35); +} + +a.supporter-card.section-item-link { + display: flex; +} + +a.screenshot-item.section-item-link { + display: block; +} + +a.faq-item--link.section-item-link { + display: block; + padding: 1.25rem 1.5rem; +} + +a.faq-item--link .faq-question { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 1rem; + font-weight: 600; + margin: 0; +} + +a.faq-item--link .faq-link-preview { + margin-top: 0.75rem; + font-size: 0.88rem; + color: var(--text-secondary); +} + /* ============================================================ Products Grid (Home) ============================================================ */ diff --git a/templates/pages/home.html b/templates/pages/home.html index 70d1000..3ab8566 100644 --- a/templates/pages/home.html +++ b/templates/pages/home.html @@ -48,157 +48,6 @@ -{% for section in homepage_sections %} - - {% if section.section_type == "features" %} -
-
-
- {% if section.badge %}
{{ section.badge }}
{% endif %} -

{{ section.title }}

- {% if section.description %}

{{ section.description }}

{% endif %} -
-
- {% for item in section.items.all %} -
- {% if item.icon %}{% endif %} -

{{ item.title }}

-

{{ item.content }}

-
- {% endfor %} -
-
-
- - {% elif section.section_type == "screenshots" %} -
-
-
- {% if section.badge %}
{{ section.badge }}
{% endif %} -

{{ section.title }}

- {% if section.description %}

{{ section.description }}

{% endif %} -
-
-
- Radiuma full workflow interface -
-
- Radiuma panel view -
-
- Radiuma segmentation view -
-
- Radiuma radiomics results -
-
-
-
- - {% elif section.section_type == "products" %} - {% if sub_products %} -
-
-
- {% if section.badge %}
{{ section.badge }}
{% endif %} -

{{ section.title }}

- {% if section.description %}

{{ section.description }}

{% endif %} -
- -
-
- {% endif %} - - {% elif section.section_type == "problems" %} -
-
-
- {% if section.badge %}
{{ section.badge }}
{% endif %} -

{{ section.title }}

- {% if section.description %}

{{ section.description }}

{% endif %} -
-
- {% for item in section.items.all %} -
- {% if item.icon %}{% endif %} -

{{ item.title }}

-

{{ item.content }}

-
- {% endfor %} -
-
-
- - {% elif section.section_type == "supporters" %} -
-
-
- {% if section.badge %}
{{ section.badge }}
{% endif %} -

{{ section.title }}

- {% if section.description %}

{{ section.description }}

{% endif %} -
-
- {% for item in section.items.all %} -
- {% if item.image %} - - {% endif %} -
-

{{ item.title }}

- {% if item.content %}

{{ item.content }}

{% endif %} -
-
- {% endfor %} -
-
-
- - {% elif section.section_type == "about_strip" %} -
-
-
-
- {% if section.badge %}
{{ section.badge }}
{% endif %} -

{{ section.title }}

- {% if section.description %}

{{ section.description }}

{% endif %} - {% if section.link_text and section.link_url %} - {{ section.link_text }} - {% endif %} -
- -
-
-
- - {% endif %} -{% endfor %} +{% include "partials/_page_sections.html" with sections=homepage_sections %} {% endblock %} diff --git a/templates/partials/_linked_card_close.html b/templates/partials/_linked_card_close.html new file mode 100644 index 0000000..add2fb6 --- /dev/null +++ b/templates/partials/_linked_card_close.html @@ -0,0 +1,5 @@ +{% if url %} + +{% else %} + +{% endif %} diff --git a/templates/partials/_linked_card_open.html b/templates/partials/_linked_card_open.html new file mode 100644 index 0000000..f660851 --- /dev/null +++ b/templates/partials/_linked_card_open.html @@ -0,0 +1,5 @@ +{% if url %} + +{% else %} +
+{% endif %} diff --git a/templates/partials/_page_sections.html b/templates/partials/_page_sections.html index c7b6e95..d52c3d1 100644 --- a/templates/partials/_page_sections.html +++ b/templates/partials/_page_sections.html @@ -48,11 +48,11 @@ {% if items %}
{% for item in items %} -
+ {% include "partials/_linked_card_open.html" with url=item.url card_class="standard-card" %} {% if item.badge %}
{{ item.badge }}
{% endif %} {% if item.title %}

{{ item.title }}

{% endif %} {% if item.content %}

{{ item.content }}

{% endif %} -
+ {% include "partials/_linked_card_close.html" with url=item.url %} {% endfor %}
{% endif %} @@ -107,12 +107,11 @@ {% if items %}
{% for item in items %} - + {% include "partials/_linked_card_close.html" with url=item.url %} {% endfor %}
{% endif %} @@ -130,11 +129,11 @@
{% for item in section.items.all %} -
+ {% include "partials/_linked_card_open.html" with url=item.url card_class="feature-card" %} {% if item.icon %}{% endif %}

{{ item.title }}

{{ item.content }}

-
+ {% include "partials/_linked_card_close.html" with url=item.url %} {% endfor %}
@@ -151,9 +150,9 @@
{% for item in section.items.all %} {% if item.image %} -
+ {% include "partials/_linked_card_open.html" with url=item.url card_class="screenshot-item" %} {{ item.image_alt|default:item.title }} -
+ {% include "partials/_linked_card_close.html" with url=item.url %} {% endif %} {% empty %}
@@ -174,7 +173,7 @@ {% elif section.section_type == "products" %} -{% if sub_products %} +{% if homepage_products %}
@@ -183,7 +182,7 @@ {% if section.description %}

{{ section.description }}

{% endif %}
{% endif %} +{% elif section.section_type == "products_catalog" %} +{% if homepage_products_catalog %} +
+ +
+{% endif %} + {% elif section.section_type == "problems" %}
@@ -220,11 +263,11 @@
{% for item in section.items.all %} -
+ {% include "partials/_linked_card_open.html" with url=item.url card_class="problem-item" %} {% if item.icon %}{% endif %}

{{ item.title }}

{{ item.content }}

-
+ {% include "partials/_linked_card_close.html" with url=item.url %} {% endfor %}
@@ -240,7 +283,7 @@
{% for item in section.items.all %} -
+ {% include "partials/_linked_card_open.html" with url=item.url card_class="supporter-card" %} {% if item.image %} -
+ {% include "partials/_linked_card_close.html" with url=item.url %} {% endfor %}
@@ -289,6 +332,17 @@ {% if items %}
{% for item in items %} + {% if item.url %} + {% include "partials/_linked_card_open.html" with url=item.url card_class="faq-item faq-item--link" %} +
+ {{ item.title }} + +
+ {% if item.content %}{% endif %} + {% include "partials/_linked_card_close.html" with url=item.url %} + {% else %}
+ {% endif %} {% endfor %} {% endif %}