77from jinja2 import Environment , FileSystemLoader
88import re
99
10+
1011def slugify (text ):
1112 text = text .lower ()
1213 # Replace spaces and underscores with hyphens
13- text = re .sub (r' [\s_]+' , '-' , text )
14+ text = re .sub (r" [\s_]+" , "-" , text )
1415 # Remove all non-alphanumeric characters except hyphens
15- text = re .sub (r' [^a-z0-9-]' , '' , text )
16+ text = re .sub (r" [^a-z0-9-]" , "" , text )
1617 return text
1718
1819
@@ -55,7 +56,7 @@ def markdown_to_html_resume(text):
5556index_template = env .get_template ("index_template.html" )
5657resume_template = env .get_template ("resume_template.html" )
5758blog_template = env .get_template ("blog_template.html" )
58- post_template = env .get_template ("post_template.html" ) # <-- Load the new post template
59+ post_template = env .get_template ("post_template.html" ) # <-- Load the new post template
5960contact_template = env .get_template ("contact_template.html" )
6061projects_template = env .get_template ("projects_template.html" )
6162tech_stack_template = env .get_template ("tech_stack_template.html" )
@@ -68,40 +69,40 @@ def markdown_to_html_resume(text):
6869
6970# 1. First, add a slug to EVERY post object
7071for post in data .get ("blogs" , []):
71- post [' slug' ] = slugify (post [' title' ])
72+ post [" slug" ] = slugify (post [" title" ])
7273
7374# 2. NOW, sort all blog posts by date
7475blog_posts = sorted (
7576 data .get ("blogs" , []),
7677 key = lambda x : datetime .strptime (x ["publish_date" ], "%Y-%m-%d" ),
77- reverse = True
78+ reverse = True ,
7879)
7980
8081# 3. Now that every post has a slug, add previous/next post information and series part resolution
81- slug_to_post = {post [' slug' ]: post for post in blog_posts }
82+ slug_to_post = {post [" slug" ]: post for post in blog_posts }
8283
8384for i , post in enumerate (blog_posts ):
84- post [' next_post' ] = None
85- post [' previous_post' ] = None
85+ post [" next_post" ] = None
86+ post [" previous_post" ] = None
8687 if i + 1 < len (blog_posts ):
87- post [' next_post' ] = blog_posts [i + 1 ]
88+ post [" next_post" ] = blog_posts [i + 1 ]
8889 if i > 0 :
89- post [' previous_post' ] = blog_posts [i - 1 ]
90+ post [" previous_post" ] = blog_posts [i - 1 ]
9091
9192 # Dynamically extract series part number from title, e.g. " (Part 2)" -> "2"
92- part_match = re .search (r' \(Part (\d+)\)' , post [' title' ])
93+ part_match = re .search (r" \(Part (\d+)\)" , post [" title" ])
9394 if part_match :
94- post [' part_num' ] = part_match .group (1 )
95+ post [" part_num" ] = part_match .group (1 )
9596
9697for post in blog_posts :
97- if post .get (' previous_part_slug' ):
98- prev_post = slug_to_post .get (post [' previous_part_slug' ])
99- if prev_post and prev_post .get (' part_num' ):
100- post [' previous_part_num' ] = prev_post [' part_num' ]
101- if post .get (' next_part_slug' ):
102- next_post = slug_to_post .get (post [' next_part_slug' ])
103- if next_post and next_post .get (' part_num' ):
104- post [' next_part_num' ] = next_post [' part_num' ]
98+ if post .get (" previous_part_slug" ):
99+ prev_post = slug_to_post .get (post [" previous_part_slug" ])
100+ if prev_post and prev_post .get (" part_num" ):
101+ post [" previous_part_num" ] = prev_post [" part_num" ]
102+ if post .get (" next_part_slug" ):
103+ next_post = slug_to_post .get (post [" next_part_slug" ])
104+ if next_post and next_post .get (" part_num" ):
105+ post [" next_part_num" ] = next_post [" part_num" ]
105106
106107# 4. Finally, process each post to create its HTML file
107108for post in blog_posts :
@@ -111,7 +112,7 @@ def markdown_to_html_resume(text):
111112 if md_filepath .exists ():
112113 with md_filepath .open ("r" , encoding = "utf-8" ) as f :
113114 markdown_content = f .read ()
114- post [' detailed_content' ] = markdown2 .markdown (
115+ post [" detailed_content" ] = markdown2 .markdown (
115116 markdown_content , extras = ["fenced-code-blocks" , "code-friendly" ]
116117 )
117118
@@ -120,16 +121,12 @@ def markdown_to_html_resume(text):
120121 with output_path .open ("w" , encoding = "utf-8" ) as f :
121122 f .write (post_output )
122123 else :
123- print (f"Warning: Markdown file not found for blog '{ post ['title' ]} ': { md_filepath } " )
124+ print (
125+ f"Warning: Markdown file not found for blog '{ post ['title' ]} ': { md_filepath } "
126+ )
124127
125128# Update the main data dictionary with the sorted and processed posts
126- data ['blogs' ] = blog_posts
127-
128- # Render the template with the data
129- html_output = index_template .render (** data )
130- resume_output = resume_template .render (** data )
131- projects_output = projects_template .render (** data )
132-
129+ data ["blogs" ] = blog_posts
133130
134131# Collect all unique tags from all blog posts
135132all_tags = set ()
@@ -141,6 +138,22 @@ def markdown_to_html_resume(text):
141138# Convert set to a sorted list for consistent order
142139sorted_tags = sorted (list (all_tags ))
143140
141+ # Match featured projects to their starting blog post
142+ for project in data .get ("featured_projects" , []):
143+ github_url = project .get ("github_url" )
144+ if github_url :
145+ # Search backwards so we find earliest dates first (Part 1s)
146+ for post in reversed (blog_posts ):
147+ if post .get ("github_url" ) == github_url and not post .get (
148+ "previous_part_slug"
149+ ):
150+ project ["blog_slug" ] = post ["slug" ]
151+ break
152+
153+ # Render the template with the data
154+ html_output = index_template .render (** data )
155+ resume_output = resume_template .render (** data )
156+ projects_output = projects_template .render (** data )
144157
145158# Find and update the line below to pass the new 'tags' variable
146159blog_output = blog_template .render (tags = sorted_tags , ** data )
0 commit comments