ResendeTech / Wagtail-test-website

A website built from following the wagtail tutorial on how to build a website using wagtail
MIT License
0 stars 0 forks source link

Feature Request: Add Portfolio App to Wagtail CMS #1

Closed brylie closed 2 months ago

brylie commented 3 months ago

We propose adding a new "Portfolio" app to Wagtail CMS. This feature will allow users to showcase their work or projects in a dedicated section of their website, enhancing the functionality of Wagtail-based sites for personal or professional portfolios.

Proposed Functionality

Data Model

  1. Create a new PortfolioItem model with the following fields:

    • title (CharField): The name of the portfolio item
    • description (RichTextField): A detailed description of the item
    • categories (TaggableManager): Using Wagtail's tagging feature for free-form categorization
    • url (URLField, optional): Link to the online version of the item, if applicable
    • image (ImageField, optional): An image representing the item
  2. Create a PortfolioIndexPage model to serve as the main page for the portfolio section

  3. Add constraints to ensure proper page hierarchy:

    • PortfolioItem instances can only be created under the PortfolioIndexPage
    • PortfolioIndexPage can only have PortfolioItem children
    • PortfolioIndexPage can only have a HomePage (or top-level page model) as its parent

URL Structure

Note: the URL structure will be automatically created by Wagtail when defining instances of the Pages via the Wagtail Admin UI.

Templates

  1. PortfolioIndexPage template:

    • Display a list of all PortfolioItem instances
    • Sort items alphabetically by title
    • Truncate descriptions to 200 characters
    • Link titles to the corresponding PortfolioItem pages
  2. PortfolioItem template:

    • Display all item details: title, categories, image (if any), URL (if any), and full description
    • Use a responsive layout (e.g., Bootstrap classes or custom CSS grid)

Navigation

Future Enhancements

Implementation Details

Models

from django.db import models
from django.core.exceptions import ValidationError
from wagtail.core.models import Page
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel
from wagtail.images.edit_handlers import ImageChooserPanel
from taggit.managers import TaggableManager

class PortfolioIndexPage(Page):
    intro = RichTextField(blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('intro')
    ]

    def get_context(self, request):
        context = super().get_context(request)
        context['portfolio_items'] = PortfolioItem.objects.child_of(self).live().order_by('title')
        return context

    parent_page_types = ['home.HomePage']  # Adjust this if your top-level page has a different name
    subpage_types = ['PortfolioItem']

    def clean(self):
        super().clean()
        # Check if there's already a PortfolioIndexPage
        if PortfolioIndexPage.objects.exists() and not self.pk:
            raise ValidationError("There can only be one PortfolioIndexPage instance.")

class PortfolioItem(Page):
    description = RichTextField()
    categories = TaggableManager(blank=True)
    url = models.URLField(blank=True)
    image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

    content_panels = Page.content_panels + [
        FieldPanel('description'),
        FieldPanel('categories'),
        FieldPanel('url'),
        ImageChooserPanel('image'),
    ]

    parent_page_types = ['PortfolioIndexPage']
    subpage_types = []  # PortfolioItem cannot have children

Templates

portfolio_index_page.html:

{% extends "base.html" %}
{% load wagtailcore_tags %}

{% block content %}
    <h1>{{ page.title }}</h1>
    {{ page.intro|richtext }}

    {% for item in portfolio_items %}
        <div class="portfolio-item">
            <h2><a href="{% pageurl item %}">{{ item.title }}</a></h2>
            <p>{{ item.description|truncatechars_html:200 }}</p>
        </div>
    {% endfor %}
{% endblock %}

portfolio_item.html

% extends "base.html" %}
{% load wagtailcore_tags wagtailimages_tags %}

{% block content %}
    <article class="portfolio-item">
        <h1>{{ page.title }}</h1>
        {% if page.image %}
            {% image page.image fill-300x200 %}
        {% endif %}
        <div class="description">
            {{ page.description|richtext }}
        </div>
        {% if page.categories.all %}
            <div class="categories">
                Categories:
                {% for category in page.categories.all %}
                    <span class="category">{{ category }}</span>
                {% endfor %}
            </div>
        {% endif %}
        {% if page.url %}
            <a href="{{ page.url }}" target="_blank" rel="noopener noreferrer">View Project</a>
        {% endif %}
    </article>
{% endblock %}

CSS (using CSS Grid)

.portfolio-item {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 20px;
    margin-bottom: 30px;
}

.portfolio-item h1 {
    grid-column: 1 / -1;
}

.portfolio-item .image {
    grid-column: 1;
}

.portfolio-item .description {
    grid-column: 2;
}

.portfolio-item .categories,
.portfolio-item .url {
    grid-column: 1 / -1;
}

@media (max-width: 768px) {
    .portfolio-item {
        grid-template-columns: 1fr;
    }

    .portfolio-item .image,
    .portfolio-item .description {
        grid-column: 1;
    }
}

Testing

Documentation

Conclusion

Adding a Portfolio app to Wagtail CMS will significantly enhance its capabilities for users looking to showcase their work. The added constraints ensure a clear and maintainable page structure, aligning well with Wagtail's existing functionality and providing a seamless experience for both developers and end-users.

ResendeTech commented 2 months ago

Added in #2