Redesign the News page around D8's list + preview split view

Replaces the flat news list with a D8-style two-pane layout: a filterable
list on the left (All/Drafts/Scheduled/Published chips with counts) and a
preview of whichever item is selected on the right, reusing the same
article/photos/publish markup news_detail.html already had (now factored
into _news_preview.html so both pages share it). Adds an NL/EN language
toggle to the article preview -- the club's two content languages are now
switchable in place, with a fallback note when a translation is missing,
instead of a separate "English" card that only appeared once translated.
The standalone news_detail.html permalink page is unchanged behaviourally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
2026-08-20 08:30:24 +02:00
parent 2b4cc7d527
commit 331b0b8227
9 changed files with 379 additions and 158 deletions

View File

@@ -86,6 +86,14 @@ class News(ClubScopedModel):
needs a cron job to "flip" it at the scheduled moment."""
return self.status == self.Status.PUBLISHED and self.published_at is not None and self.published_at > timezone.now()
@property
def main_photo(self):
"""The cover photo for the article preview, if one's been marked as
such. Filters ``self.photos.all()`` in Python rather than a fresh
``.filter(is_main=True)`` query, so a prefetch_related("photos") on
the calling queryset is actually honoured instead of bypassed."""
return next((photo for photo in self.photos.all() if photo.is_main), None)
class NewsPhoto(UUIDModel):
news_item = models.ForeignKey(News, on_delete=models.CASCADE, related_name="photos", verbose_name=_("news item"))