feat: Implement Sprint 8 - Portfolio website expansion (MVP)

New pages:
- Home: Redesigned with hero, impact stats, featured project
- About: 6-section professional narrative
- Projects: Hub with 4 project cards and status badges
- Resume: Inline display with download placeholders
- Contact: Form UI (disabled) with contact info
- Blog: Markdown-based system with frontmatter support

Infrastructure:
- Blog system with markdown loader (python-frontmatter, markdown, pygments)
- Sidebar callback for active state highlighting on navigation
- Separated navigation into main pages and projects/dashboards groups

Closes #36, #37, #38, #39, #40, #41, #42, #43

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-15 15:40:01 -05:00
parent cd7b5ce154
commit 138e6fe497
15 changed files with 1937 additions and 134 deletions

View File

@@ -4,9 +4,18 @@ import dash_mantine_components as dmc
from dash import dcc, html
from dash_iconify import DashIconify
# Navigation items configuration
NAV_ITEMS = [
# Navigation items configuration - main pages
NAV_ITEMS_MAIN = [
{"path": "/", "icon": "tabler:home", "label": "Home"},
{"path": "/about", "icon": "tabler:user", "label": "About"},
{"path": "/blog", "icon": "tabler:article", "label": "Blog"},
{"path": "/resume", "icon": "tabler:file-text", "label": "Resume"},
{"path": "/contact", "icon": "tabler:mail", "label": "Contact"},
]
# Navigation items configuration - projects/dashboards (separated)
NAV_ITEMS_PROJECTS = [
{"path": "/projects", "icon": "tabler:folder", "label": "Projects"},
{"path": "/toronto", "icon": "tabler:map-2", "label": "Toronto Housing"},
]
@@ -135,6 +144,59 @@ def create_sidebar_divider() -> html.Div:
return html.Div(className="sidebar-divider")
def create_sidebar_content(
current_path: str = "/", current_theme: str = "dark"
) -> list[dmc.Tooltip | html.Div]:
"""Create the sidebar content list.
Args:
current_path: Current page path for active state highlighting.
current_theme: Current theme for toggle icon state.
Returns:
List of sidebar components.
"""
return [
# Brand logo
create_brand_logo(),
create_sidebar_divider(),
# Main navigation icons
*[
create_nav_icon(
icon=item["icon"],
label=item["label"],
path=item["path"],
current_path=current_path,
)
for item in NAV_ITEMS_MAIN
],
create_sidebar_divider(),
# Dashboard/Project links
*[
create_nav_icon(
icon=item["icon"],
label=item["label"],
path=item["path"],
current_path=current_path,
)
for item in NAV_ITEMS_PROJECTS
],
create_sidebar_divider(),
# Theme toggle
create_theme_toggle(current_theme),
create_sidebar_divider(),
# External links
*[
create_external_link(
url=link["url"],
icon=link["icon"],
label=link["label"],
)
for link in EXTERNAL_LINKS
],
]
def create_sidebar(current_path: str = "/", current_theme: str = "dark") -> html.Div:
"""Create the floating sidebar navigation.
@@ -146,34 +208,7 @@ def create_sidebar(current_path: str = "/", current_theme: str = "dark") -> html
Complete sidebar component.
"""
return html.Div(
[
# Brand logo
create_brand_logo(),
create_sidebar_divider(),
# Navigation icons
*[
create_nav_icon(
icon=item["icon"],
label=item["label"],
path=item["path"],
current_path=current_path,
)
for item in NAV_ITEMS
],
create_sidebar_divider(),
# Theme toggle
create_theme_toggle(current_theme),
create_sidebar_divider(),
# External links
*[
create_external_link(
url=link["url"],
icon=link["icon"],
label=link["label"],
)
for link in EXTERNAL_LINKS
],
],
className="floating-sidebar",
id="floating-sidebar",
className="floating-sidebar",
children=create_sidebar_content(current_path, current_theme),
)