Compare commits
2 Commits
68cc5bbe66
...
549e1fcbaf
| Author | SHA1 | Date | |
|---|---|---|---|
| 549e1fcbaf | |||
| 3ee4c20f5e |
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user