ux: CHANGE change 'feeds' to 'sections' - BREAKING - short guide in release notes

This commit is contained in:
Caffeine Fueled 2026-03-22 20:30:05 +01:00
parent 98ab0ab419
commit a99d1db1cb
Signed by: cf7
GPG key ID: CA295D643074C68C
4 changed files with 59 additions and 59 deletions

View file

@ -23,8 +23,8 @@ Show cases:
- long- and short form content
- pages
- static files
- separate feeds (used for categories, tagging, etc) `/feed/{tag}`
- exclusion of feeds from main feed (drafts or system notes)
- separate sections (used for categories, tagging, etc) `/section/{tag}`
- exclusion of sections from main index (drafts or system notes)
- HTML anchors for headers
- list random posts at the bottom
- optional RSS feeds
@ -47,33 +47,33 @@ Put markdown file into `items` dir. **Important naming convention**:
2025-10-05_short_quick-update_draft.md
```
Format: `YYYY-MM-DD_type_slug[_feed].md`
Format: `YYYY-MM-DD_type_slug[_section].md`
- `2025-10-03` - date of the article
- `_long_` - type of content: `long`, `short`, or `page`
- `building-a-static-site-generator` - slug/path for the URL
- `_draft` (optional) - feed tag for categorization
- `_draft` (optional) - section tag for categorization
The first `#` header is the title of the article - no frontmatter needed.
**Types of content**:
- `long` - only title with link to articles will be displayed in feed
- `long` - only title with link to articles will be displayed in the main index
- `short` - title and all content will be displayed
- `page` - won't be displayed in feed at all
- `page` - won't be displayed in the main index at all
### Feeds
### Sections
Posts can be tagged with an optional feed category (e.g., `_python`, `_webdev`). Posts with feed tags:
Posts can be tagged with an optional section (e.g., `_python`, `_webdev`). Posts with section tags:
- Appear on the main page (unless excluded in config)
- Have their own feed page at `/feed/{tag}/`
- Have their own section page at `/section/{tag}/`
**Configuration in `config.py`:**
```python
# Exclude specific feeds from main page (they'll still have /feed/name/ pages)
EXCLUDE_FEEDS_FROM_MAIN = ['draft', 'private']
# Exclude specific sections from main page (they'll still have /section/name/ pages)
EXCLUDE_SECTIONS_FROM_MAIN = ['draft', 'private']
```
This is useful for draft posts or topic-specific content you want separated from the main feed.
This is useful for draft posts or topic-specific content you want separated from the main index.
---

View file

@ -8,13 +8,13 @@ AUTHOR_NAME = "PicoPaper"
AUTHOR_EMAIL = "hello@picopaper.com" # Optional
THEME = "default"
# Exclude specific feeds from the main page (they'll still have their own /feed/name/ pages)
EXCLUDE_FEEDS_FROM_MAIN = ['draft','private'] # e.g., ['python', 'drafts']
# Exclude specific sections from the main page (they'll still have their own /section/name/ pages)
EXCLUDE_SECTIONS_FROM_MAIN = ['draft','private'] # e.g., ['python', 'drafts']
# Navigation bar items - list of dictionaries with 'text' and 'url' keys
NAVBAR_ITEMS = [
{'text': 'Home', 'url': '/'},
{'text': 'Feeds', 'url': '/feed/'},
{'text': 'Sections', 'url': '/section/'},
{'text': 'About', 'url': '/about/'},
{'text': 'RSS', 'url': '/rss.xml'}
]

View file

@ -6,7 +6,7 @@ from datetime import datetime
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
import markdown
from config import (BLOG_TITLE, BLOG_DESCRIPTION, THEME, EXCLUDE_FEEDS_FROM_MAIN,
from config import (BLOG_TITLE, BLOG_DESCRIPTION, THEME, EXCLUDE_SECTIONS_FROM_MAIN,
NAVBAR_ITEMS, HIDE_LOGO, HIDE_TITLE, LOGO_PATH,
ENABLE_RSS_FEED, RSS_FEED_PATH,
BASE_URL, AUTHOR_NAME, AUTHOR_EMAIL, FEED_MAX_ITEMS)
@ -21,7 +21,7 @@ class SSGGGenerator:
self.assets_dir = self.theme_dir / 'assets'
self.blog_title = blog_title or BLOG_TITLE
self.blog_description = blog_description or BLOG_DESCRIPTION
self.exclude_feeds = EXCLUDE_FEEDS_FROM_MAIN
self.exclude_sections = EXCLUDE_SECTIONS_FROM_MAIN
self.navbar_items = NAVBAR_ITEMS
self.hide_logo = HIDE_LOGO
self.hide_title = HIDE_TITLE
@ -42,7 +42,7 @@ class SSGGGenerator:
self.md = markdown.Markdown(extensions=['extra', 'toc'])
def parse_filename(self, filename, subpath=''):
"""Parse filename format: YYYY-MM-DD_type_name[_feed].md
"""Parse filename format: YYYY-MM-DD_type_name[_section].md
Args:
filename: The markdown filename
@ -54,7 +54,7 @@ class SSGGGenerator:
if not match:
return None
date_str, post_type, name, feed = match.groups()
date_str, post_type, name, section = match.groups()
date = datetime.strptime(date_str, '%Y-%m-%d')
return {
@ -62,7 +62,7 @@ class SSGGGenerator:
'date_str': date.strftime('%Y-%m-%d'),
'type': post_type,
'name': name,
'feed': feed,
'section': section,
'filename': filename,
'subpath': subpath
}
@ -140,7 +140,7 @@ class SSGGGenerator:
'content': content,
'slug': slug,
'url': url,
'feed': parsed['feed'],
'section': parsed['section'],
'source': str(relative_path),
'subpath': parsed['subpath']
}
@ -152,13 +152,13 @@ class SSGGGenerator:
return posts
def generate_index(self, posts, feed_name=None, all_posts=None):
"""Generate index.html with all posts (or feed-specific index)"""
def generate_index(self, posts, section_name=None, all_posts=None):
"""Generate index.html with all posts (or section-specific index)"""
template = self.env.get_template('index.tmpl')
if feed_name:
title = f"{feed_name} - {self.blog_title}"
output_path = self.output_dir / 'feed' / feed_name / 'index.html'
if section_name:
title = f"{section_name} - {self.blog_title}"
output_path = self.output_dir / 'section' / section_name / 'index.html'
else:
title = self.blog_title
output_path = self.output_dir / 'index.html'
@ -183,28 +183,28 @@ class SSGGGenerator:
print(f"✓ Generated {output_path}")
def generate_feeds_overview(self, feeds, all_posts=None):
"""Generate /feed/index.html with list of all non-excluded feeds"""
template = self.env.get_template('feeds.tmpl')
def generate_sections_overview(self, sections, all_posts=None):
"""Generate /section/index.html with list of all non-excluded sections"""
template = self.env.get_template('sections.tmpl')
# Prepare feed data with counts, excluding feeds in EXCLUDE_FEEDS_FROM_MAIN
feed_list = []
for feed_name, posts in sorted(feeds.items()):
if feed_name not in self.exclude_feeds:
feed_list.append({
'name': feed_name,
# Prepare section data with counts, excluding sections in EXCLUDE_SECTIONS_FROM_MAIN
section_list = []
for section_name, posts in sorted(sections.items()):
if section_name not in self.exclude_sections:
section_list.append({
'name': section_name,
'count': len(posts)
})
title = f"Feeds - {self.blog_title}"
output_path = self.output_dir / 'feed' / 'index.html'
title = f"Sections - {self.blog_title}"
output_path = self.output_dir / 'section' / 'index.html'
html = template.render(
title=title,
blog_title=self.blog_title,
blog_description=self.blog_description,
navbar_items=self.navbar_items,
feeds=feed_list,
sections=section_list,
all_posts=all_posts or [],
hide_logo=self.hide_logo,
hide_title=self.hide_title,
@ -397,27 +397,27 @@ class SSGGGenerator:
all_posts = self.collect_posts()
print(f"Found {len(all_posts)} posts")
# Filter out pages and excluded feeds from main feed
feed_posts = [p for p in all_posts
# Filter out pages and excluded sections from main index
main_posts = [p for p in all_posts
if p['type'] != 'page'
and p['feed'] not in self.exclude_feeds]
and p['section'] not in self.exclude_sections]
# Generate main index with filtered feed posts
self.generate_index(feed_posts, all_posts=feed_posts)
# Generate main index with filtered posts
self.generate_index(main_posts, all_posts=main_posts)
# Group posts by feed (include all posts, not just those in main feed)
feeds = {}
# Group posts by section (include all posts, not just those in main index)
sections = {}
for post in all_posts:
if post['feed'] and post['type'] != 'page':
feeds.setdefault(post['feed'], []).append(post)
if post['section'] and post['type'] != 'page':
sections.setdefault(post['section'], []).append(post)
# Generate feed-specific pages
for feed_name, posts in feeds.items():
self.generate_index(posts, feed_name, all_posts=feed_posts)
# Generate section-specific pages
for section_name, posts in sections.items():
self.generate_index(posts, section_name, all_posts=main_posts)
# Generate feeds overview page
if feeds:
self.generate_feeds_overview(feeds, all_posts=feed_posts)
# Generate sections overview page
if sections:
self.generate_sections_overview(sections, all_posts=main_posts)
# Group posts by subdirectory
subdirs = {}
@ -427,16 +427,16 @@ class SSGGGenerator:
# Generate subdirectory index pages (e.g., /projects/)
for subpath, subdir_posts in subdirs.items():
self.generate_subdir_index(subpath, subdir_posts, all_posts=feed_posts)
self.generate_subdir_index(subpath, subdir_posts, all_posts=main_posts)
# Generate individual pages for long posts, short posts, and pages
for post in all_posts:
if post['type'] in ['long', 'short', 'page']:
self.generate_post_page(post, all_posts=feed_posts)
self.generate_post_page(post, all_posts=main_posts)
# Generate RSS feed
if ENABLE_RSS_FEED:
self.generate_rss_feed(feed_posts)
self.generate_rss_feed(main_posts)
# Copy assets
self.copy_assets()

View file

@ -7,10 +7,10 @@
{% include 'header.tmpl' %}
<main>
<h2>Feeds</h2>
<h2>Sections</h2>
<ul>
{% for feed in feeds %}
<li><a href="/feed/{{ feed.name }}/">{{ feed.name }}</a> ({{ feed.count }} posts)</li>
{% for section in sections %}
<li><a href="/section/{{ section.name }}/">{{ section.name }}</a> ({{ section.count }} posts)</li>
{% endfor %}
</ul>
</main>