staging #96

Merged
lmiranda merged 90 commits from staging into main 2026-02-01 21:33:13 +00:00
4 changed files with 213 additions and 16 deletions
Showing only changes of commit 549e1fcbaf - Show all commits

View File

@@ -1,26 +1,28 @@
"""Dash application factory with Pages routing.""" """Dash application factory with Pages routing."""
import dash import dash
from dash import html import dash_mantine_components as dmc
from .config import get_settings from .config import get_settings
def create_app() -> dash.Dash: def create_app() -> dash.Dash:
"""Create and configure the Dash application.""" """Create and configure the Dash application."""
settings = get_settings()
app = dash.Dash( app = dash.Dash(
__name__, __name__,
use_pages=True, use_pages=True,
suppress_callback_exceptions=True, suppress_callback_exceptions=True,
title="Analytics Portfolio", title="Analytics Portfolio",
external_stylesheets=dmc.styles.ALL,
) )
app.layout = html.Div( app.layout = dmc.MantineProvider(
[ dash.page_container,
dash.page_container, theme={
] "primaryColor": "blue",
"fontFamily": "'Inter', sans-serif",
},
forceColorScheme="light",
) )
return app return app

View File

@@ -5,7 +5,7 @@ from functools import lru_cache
from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings): class Settings(BaseSettings): # type: ignore[misc]
"""Application settings loaded from environment variables.""" """Application settings loaded from environment variables."""
model_config = SettingsConfigDict( model_config = SettingsConfigDict(

View File

@@ -1,14 +1,205 @@
"""Bio landing page.""" """Bio landing page."""
import dash import dash
from dash import html import dash_mantine_components as dmc
from dash_iconify import DashIconify
dash.register_page(__name__, path="/", name="Home") dash.register_page(__name__, path="/", name="Home")
layout = html.Div( # Content from bio_content_v2.md
[ HEADLINE = "Leo | Data Engineer & Analytics Developer"
html.H1("Analytics Portfolio"), TAGLINE = "I build data infrastructure that actually gets used."
html.P("Welcome to Leo's analytics portfolio."),
html.P("Dashboard coming soon."), SUMMARY = """Over the past 5 years, I've designed and evolved an enterprise analytics platform
] from scratch—now processing 1B+ rows across 21 tables with Python-based ETL pipelines and
dbt-style SQL transformations. The result: 40% efficiency gains, 30% reduction in call
abandon rates, and dashboards that executives actually open.
My approach: dimensional modeling (star schema), layered transformations
(staging → intermediate → marts), and automation that eliminates manual work.
I've built everything from self-service analytics portals to OCR-powered receipt processing systems.
Currently at Summitt Energy supporting multi-market operations across Canada and 8 US states.
Previously cut my teeth on IT infrastructure projects at Petrobras (Fortune 500) and the
Project Management Institute."""
TECH_STACK = [
"Python",
"Pandas",
"SQLAlchemy",
"FastAPI",
"SQL",
"PostgreSQL",
"MSSQL",
"Power BI",
"Plotly/Dash",
"dbt patterns",
"Genesys Cloud",
]
PROJECTS = [
{
"title": "Toronto Housing Dashboard",
"description": "Choropleth visualization of GTA real estate trends with TRREB and CMHC data.",
"status": "In Development",
"link": "/toronto",
},
{
"title": "Energy Pricing Analysis",
"description": "Time series analysis and ML prediction for utility market pricing.",
"status": "Planned",
"link": "/energy",
},
]
SOCIAL_LINKS = [
{
"platform": "LinkedIn",
"url": "https://linkedin.com/in/leobmiranda",
"icon": "mdi:linkedin",
},
{
"platform": "GitHub",
"url": "https://github.com/leomiranda",
"icon": "mdi:github",
},
]
AVAILABILITY = "Open to Senior Data Analyst, Analytics Engineer, and BI Developer opportunities in Toronto or remote."
def create_hero_section() -> dmc.Stack:
"""Create the hero section with name and tagline."""
return dmc.Stack(
[
dmc.Title(HEADLINE, order=1, ta="center"),
dmc.Text(TAGLINE, size="xl", c="dimmed", ta="center"),
],
gap="xs",
py="xl",
)
def create_summary_section() -> dmc.Paper:
"""Create the professional summary section."""
paragraphs = SUMMARY.strip().split("\n\n")
return dmc.Paper(
dmc.Stack(
[
dmc.Title("About", order=2, size="h3"),
*[dmc.Text(p.replace("\n", " "), size="md") for p in paragraphs],
],
gap="md",
),
p="xl",
radius="md",
withBorder=True,
)
def create_tech_stack_section() -> dmc.Paper:
"""Create the tech stack section with badges."""
return dmc.Paper(
dmc.Stack(
[
dmc.Title("Tech Stack", order=2, size="h3"),
dmc.Group(
[
dmc.Badge(tech, size="lg", variant="light", radius="sm")
for tech in TECH_STACK
],
gap="sm",
),
],
gap="md",
),
p="xl",
radius="md",
withBorder=True,
)
def create_project_card(project: dict[str, str]) -> dmc.Card:
"""Create a project card."""
status_color = "blue" if project["status"] == "In Development" else "gray"
return dmc.Card(
[
dmc.Group(
[
dmc.Text(project["title"], fw=500, size="lg"),
dmc.Badge(project["status"], color=status_color, variant="light"),
],
justify="space-between",
align="center",
),
dmc.Text(project["description"], size="sm", c="dimmed", mt="sm"),
],
withBorder=True,
radius="md",
p="lg",
)
def create_projects_section() -> dmc.Paper:
"""Create the portfolio projects section."""
return dmc.Paper(
dmc.Stack(
[
dmc.Title("Portfolio Projects", order=2, size="h3"),
dmc.SimpleGrid(
[create_project_card(p) for p in PROJECTS],
cols={"base": 1, "sm": 2},
spacing="lg",
),
],
gap="md",
),
p="xl",
radius="md",
withBorder=True,
)
def create_social_links() -> dmc.Group:
"""Create social media links."""
return dmc.Group(
[
dmc.Anchor(
dmc.Button(
link["platform"],
leftSection=DashIconify(icon=link["icon"], width=20),
variant="outline",
size="md",
),
href=link["url"],
target="_blank",
)
for link in SOCIAL_LINKS
],
justify="center",
gap="md",
)
def create_availability_section() -> dmc.Text:
"""Create the availability statement."""
return dmc.Text(AVAILABILITY, size="sm", c="dimmed", ta="center", fs="italic")
layout = dmc.Container(
dmc.Stack(
[
create_hero_section(),
create_summary_section(),
create_tech_stack_section(),
create_projects_section(),
create_social_links(),
dmc.Divider(my="lg"),
create_availability_section(),
dmc.Space(h=40),
],
gap="xl",
),
size="md",
py="xl",
) )

View File

@@ -39,6 +39,7 @@ dependencies = [
"dash>=3.3", "dash>=3.3",
"plotly>=6.5", "plotly>=6.5",
"dash-mantine-components>=2.4", "dash-mantine-components>=2.4",
"dash-iconify>=0.1",
# PDF Parsing # PDF Parsing
"pdfplumber>=0.11", "pdfplumber>=0.11",
@@ -132,17 +133,20 @@ skip-magic-trailing-comma = false
python_version = "3.11" python_version = "3.11"
strict = true strict = true
warn_return_any = true warn_return_any = true
warn_unused_ignores = true warn_unused_ignores = false
disallow_untyped_defs = true disallow_untyped_defs = true
plugins = ["pydantic.mypy"] plugins = ["pydantic.mypy"]
[[tool.mypy.overrides]] [[tool.mypy.overrides]]
module = [ module = [
"dash.*", "dash.*",
"dash_mantine_components.*",
"dash_iconify.*",
"plotly.*", "plotly.*",
"geopandas.*", "geopandas.*",
"shapely.*", "shapely.*",
"pdfplumber.*", "pdfplumber.*",
"tabula.*", "tabula.*",
"pydantic_settings.*",
] ]
ignore_missing_imports = true ignore_missing_imports = true