j-curran.com / work / Personal Website ↗ code
project_02 · 2024 · 3 months · Solo

Personal Website

This portfolio site — a Flask-based notebook aesthetic with live interactive data widgets and dynamic weather theming.

3 months Stack: Python · Flask · HTML · CSS · JavaScript
the idea

A portfolio site that IS the portfolio, not just a listing.

Most portfolios are static resumes in pretty clothes. This one is built to be an interactive notebook: each project is a case study with live filtering, interactive widgets, and design that matches the content. The site itself is a project, which means I get to ship things I actually care about building.

notebook aesthetic

Numbered cells, monospace gutters, ruled lines.

The design is inspired by computational notebooks (Jupyter, Observable) but applied to a static site. Each section is a numbered cell [01], [02], etc. Content flows through a grid with a monospace left gutter for cell numbers and metadata. All colors, spacing, and typography are driven by CSS custom properties that swap between light and dark themes.

No frameworks, no build step, no npm. Pure HTML/CSS/vanilla JS. Fonts are Geist (sans) and JetBrains Mono (monospace) from Google Fonts. Design tokens live in one CSS file. Everything else is component-scoped inline styles.

what's built

Live filtering, interactive widgets, dark mode, custom themes.

Project Filter

Year slider and tag/stack multi-select chips that sync a scatter plot and archive table. All client-side, no server calls.

Interactive Widgets

SVG-based threshold sliders and scatter plots embedded in project pages. Real data, real interactivity, no charting libraries.

Theme Tweaks

Accent palette (terracotta, slate, forest, plum, mono), density toggle (airy/compact), dark mode. Persisted to localStorage.

Markdown Content

Project details live as markdown files. Flask renders them to HTML at runtime. One source of truth.

technologies

Backend: Flask 3.1, Python 3.13 with Jinja2 templating.

Frontend: HTML5, CSS custom properties, vanilla JavaScript. No React, no Vue, no build step.

Fonts: Geist (sans) and JetBrains Mono (monospace) from Google Fonts.

Content: Markdown files stored in /projects/, project metadata in app.py.

Hosting: Render.com with Gunicorn. Site lives at j-curran.com.

what I learned

Constraints are clarifying. No build step meant every CSS decision had to be simple and reusable. No charting libraries meant learning to hand-craft SVG and think about coordinate systems. No framework meant I had to get comfortable with vanilla DOM manipulation and event delegation — skills that transfer everywhere.

The hardest part wasn't the code. It was deciding what to include and what to cut. A portfolio can easily become a kitchen sink. This one tries to be a genuine reflection of how I think about work: focused, measured, with just enough craft to be interesting.

← previous
Wage Distribution Analysis
next →
Global Temperatures Analysis
© 2026 · case study updated 2026-05-25 ↑ view source on github