ADD subpaths for pages and create basic index #19
This commit is contained in:
parent
a08a01517d
commit
98ab0ab419
3 changed files with 74 additions and 16 deletions
3
items/projects/2025-10-27_page_another-project.md
Normal file
3
items/projects/2025-10-27_page_another-project.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Another Project
|
||||||
|
|
||||||
|
Just a placeholer.
|
||||||
83
picopaper.py
83
picopaper.py
|
|
@ -41,8 +41,13 @@ class SSGGGenerator:
|
||||||
# Setup markdown with toc extension for header anchors
|
# Setup markdown with toc extension for header anchors
|
||||||
self.md = markdown.Markdown(extensions=['extra', 'toc'])
|
self.md = markdown.Markdown(extensions=['extra', 'toc'])
|
||||||
|
|
||||||
def parse_filename(self, filename):
|
def parse_filename(self, filename, subpath=''):
|
||||||
"""Parse filename format: YYYY-MM-DD_type_name[_feed].md"""
|
"""Parse filename format: YYYY-MM-DD_type_name[_feed].md
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename: The markdown filename
|
||||||
|
subpath: Optional subdirectory path (e.g., 'notes' for items/notes/)
|
||||||
|
"""
|
||||||
pattern = r'(\d{4}-\d{2}-\d{2})_(short|long|page)_(.+?)(?:_([a-z0-9-]+))?\.md'
|
pattern = r'(\d{4}-\d{2}-\d{2})_(short|long|page)_(.+?)(?:_([a-z0-9-]+))?\.md'
|
||||||
match = re.match(pattern, filename)
|
match = re.match(pattern, filename)
|
||||||
|
|
||||||
|
|
@ -58,7 +63,8 @@ class SSGGGenerator:
|
||||||
'type': post_type,
|
'type': post_type,
|
||||||
'name': name,
|
'name': name,
|
||||||
'feed': feed,
|
'feed': feed,
|
||||||
'filename': filename
|
'filename': filename,
|
||||||
|
'subpath': subpath
|
||||||
}
|
}
|
||||||
|
|
||||||
def add_header_anchors(self, html_content):
|
def add_header_anchors(self, html_content):
|
||||||
|
|
@ -97,32 +103,46 @@ class SSGGGenerator:
|
||||||
return title, html_content
|
return title, html_content
|
||||||
|
|
||||||
def collect_posts(self):
|
def collect_posts(self):
|
||||||
"""Collect and parse all posts from items directory"""
|
"""Collect and parse all posts from items directory, including subdirectories"""
|
||||||
posts = []
|
posts = []
|
||||||
|
|
||||||
if not self.items_dir.exists():
|
if not self.items_dir.exists():
|
||||||
print(f"Warning: {self.items_dir} does not exist")
|
print(f"Warning: {self.items_dir} does not exist")
|
||||||
return posts
|
return posts
|
||||||
|
|
||||||
for filepath in self.items_dir.glob('*.md'):
|
# Use rglob to recursively find all .md files
|
||||||
parsed = self.parse_filename(filepath.name)
|
for filepath in self.items_dir.rglob('*.md'):
|
||||||
|
# Calculate subpath relative to items_dir
|
||||||
|
relative_path = filepath.relative_to(self.items_dir)
|
||||||
|
subpath = str(relative_path.parent) if relative_path.parent != Path('.') else ''
|
||||||
|
|
||||||
|
parsed = self.parse_filename(filepath.name, subpath)
|
||||||
|
|
||||||
if not parsed:
|
if not parsed:
|
||||||
print(f"Skipping {filepath.name}: doesn't match naming convention")
|
print(f"Skipping {filepath}: doesn't match naming convention")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
title, content = self.read_post(filepath)
|
title, content = self.read_post(filepath)
|
||||||
|
|
||||||
|
# Build slug and URL with subpath
|
||||||
|
if parsed['subpath']:
|
||||||
|
slug = f"{parsed['subpath']}/{parsed['name']}"
|
||||||
|
url = f"/{parsed['subpath']}/{parsed['name']}/"
|
||||||
|
else:
|
||||||
|
slug = parsed['name']
|
||||||
|
url = f"/{parsed['name']}/"
|
||||||
|
|
||||||
post = {
|
post = {
|
||||||
'date': parsed['date_str'],
|
'date': parsed['date_str'],
|
||||||
'type': parsed['type'],
|
'type': parsed['type'],
|
||||||
'name': parsed['name'],
|
'name': parsed['name'],
|
||||||
'title': title,
|
'title': title,
|
||||||
'content': content,
|
'content': content,
|
||||||
'slug': parsed['name'],
|
'slug': slug,
|
||||||
'url': f"/{parsed['name']}/",
|
'url': url,
|
||||||
'feed': parsed['feed'],
|
'feed': parsed['feed'],
|
||||||
'source': filepath.name
|
'source': str(relative_path),
|
||||||
|
'subpath': parsed['subpath']
|
||||||
}
|
}
|
||||||
|
|
||||||
posts.append(post)
|
posts.append(post)
|
||||||
|
|
@ -199,6 +219,35 @@ class SSGGGenerator:
|
||||||
|
|
||||||
print(f"✓ Generated {output_path}")
|
print(f"✓ Generated {output_path}")
|
||||||
|
|
||||||
|
def generate_subdir_index(self, subpath, posts, all_posts=None):
|
||||||
|
"""Generate index page for a subdirectory (e.g., /projects/)"""
|
||||||
|
template = self.env.get_template('index.tmpl')
|
||||||
|
|
||||||
|
# Use the subpath as the title (capitalize first letter)
|
||||||
|
subpath_title = subpath.replace('/', ' / ').title()
|
||||||
|
title = f"{subpath_title} - {self.blog_title}"
|
||||||
|
output_path = self.output_dir / subpath / 'index.html'
|
||||||
|
|
||||||
|
html = template.render(
|
||||||
|
title=title,
|
||||||
|
blog_title=self.blog_title,
|
||||||
|
blog_description=self.blog_description,
|
||||||
|
navbar_items=self.navbar_items,
|
||||||
|
posts=posts,
|
||||||
|
all_posts=all_posts or posts,
|
||||||
|
hide_logo=self.hide_logo,
|
||||||
|
hide_title=self.hide_title,
|
||||||
|
logo_path=self.logo_path,
|
||||||
|
rss_feed_enabled=ENABLE_RSS_FEED,
|
||||||
|
rss_feed_path=RSS_FEED_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(output_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(html)
|
||||||
|
|
||||||
|
print(f"✓ Generated {output_path}")
|
||||||
|
|
||||||
def generate_post_page(self, post, all_posts=None):
|
def generate_post_page(self, post, all_posts=None):
|
||||||
"""Generate individual post page for 'long' posts"""
|
"""Generate individual post page for 'long' posts"""
|
||||||
template = self.env.get_template('post.tmpl')
|
template = self.env.get_template('post.tmpl')
|
||||||
|
|
@ -217,9 +266,9 @@ class SSGGGenerator:
|
||||||
rss_feed_path=RSS_FEED_PATH
|
rss_feed_path=RSS_FEED_PATH
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create directory for the post slug
|
# Create directory for the post slug (with parents for nested paths)
|
||||||
post_dir = self.output_dir / post['slug']
|
post_dir = self.output_dir / post['slug']
|
||||||
post_dir.mkdir(exist_ok=True)
|
post_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# Generate index.html inside the slug directory
|
# Generate index.html inside the slug directory
|
||||||
output_path = post_dir / 'index.html'
|
output_path = post_dir / 'index.html'
|
||||||
|
|
@ -370,6 +419,16 @@ class SSGGGenerator:
|
||||||
if feeds:
|
if feeds:
|
||||||
self.generate_feeds_overview(feeds, all_posts=feed_posts)
|
self.generate_feeds_overview(feeds, all_posts=feed_posts)
|
||||||
|
|
||||||
|
# Group posts by subdirectory
|
||||||
|
subdirs = {}
|
||||||
|
for post in all_posts:
|
||||||
|
if post['subpath']: # Only posts in subdirectories
|
||||||
|
subdirs.setdefault(post['subpath'], []).append(post)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
# Generate individual pages for long posts, short posts, and pages
|
# Generate individual pages for long posts, short posts, and pages
|
||||||
for post in all_posts:
|
for post in all_posts:
|
||||||
if post['type'] in ['long', 'short', 'page']:
|
if post['type'] in ['long', 'short', 'page']:
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,7 @@
|
||||||
<article class="post">
|
<article class="post">
|
||||||
<div class="post-meta">{{ post.date }}</div>
|
<div class="post-meta">{{ post.date }}</div>
|
||||||
<h2 class="post-title">
|
<h2 class="post-title">
|
||||||
{% if post.type in ['long', 'short'] %}
|
|
||||||
<a href="{{ post.url }}">{{ post.title }}</a>
|
<a href="{{ post.url }}">{{ post.title }}</a>
|
||||||
{% else %}
|
|
||||||
{{ post.title }}
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
</h2>
|
||||||
{% if post.type == 'short' %}
|
{% if post.type == 'short' %}
|
||||||
<div class="post-content">
|
<div class="post-content">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue