This is Andrea Leopardi's personal website (https://andrealeopardi.com), built with Zola v0.22.1, a static site generator written in Rust. The site features blog posts about Elixir, system architecture, teaching materials, and personal information.
Key characteristics:
- Static site generator: Zola
- Content: Markdown files with YAML frontmatter
- Styling: SCSS (compiled by Zola)
- Templates: Tera template engine (Zola's default)
- Deployment: Static HTML output to
/publicdirectory
Zola is installed, don't check.
# Serve the site locally with live reload (default: http://127.0.0.1:1111)
zola serve
# Build the site (outputs to /public directory)
zola build
# Check the site without rendering (validates links)
zola check# Check all markdown links using Docker
make check-all-linksNote: This runs markdown-link-check via Docker on all .md files in the repository.
The project uses markdownlint for markdown files. Configuration is in .markdownlint.json.
.
βββ config.toml # Zola configuration
βββ content/ # Markdown content
β βββ _index.md # Homepage
β βββ about.md # About page
β βββ blog.md # Blog index
β βββ books.md # Books page
β βββ teaching.md # Teaching resources
β βββ travels.md # Travel page
β βββ uses.md # Tech stack page
β βββ posts/ # Blog posts
β βββ _index.md # Posts configuration
β βββ YYYY-MM-DD-slug/
β βββ index.md # Individual posts
βββ templates/ # Tera templates
β βββ base.html # Master template (header, body, content blocks)
β βββ base_sidebar.html # Sidebar layout (extends base, adds sidebar)
β βββ index.html # Landing page (own top bar + sidebar + posts)
β βββ post.html # Blog post (full-width, no sidebar)
β βββ posts.html # Blog listing (with sidebar)
β βββ extra_page.html # Generic page (with sidebar)
β βββ books.html # Books page (with sidebar)
β βββ travels.html # Travels page (with sidebar)
β βββ section.html # Section template (with sidebar)
β βββ shortcodes/ # Custom shortcodes
β β βββ callout.html
β β βββ unsplash_credit.html
β β βββ youtube.html
β β βββ ...
β βββ snippets/ # Reusable template snippets
β βββ sidebar.html # Shared sidebar (portrait, identity, roles, nav)
β βββ header.html # Top bar (~ site + /now link)
β βββ footer.html # Terminal footer (social + pid)
β βββ meta.html
β βββ ...
βββ sass/ # SCSS stylesheets
β βββ style.scss # Main stylesheet
β βββ _variables.scss # Colors, fonts, sizes
β βββ _mixins.scss # Reusable SCSS mixins
β βββ _reset.scss # CSS reset
β βββ _books.scss # Books page styles
β βββ _travels.scss # Travels page styles
β βββ components/ # Component-specific styles
β βββ _landing_page.scss
β βββ _header.scss
β βββ _footer.scss
βββ static/ # Static assets (copied as-is)
β βββ assets/
β β βββ fonts/
β β βββ geo/ # Geography/map assets
β β βββ icons/
β β βββ js/
β β βββ media/
β βββ favicons/
β βββ CNAME # GitHub Pages custom domain
β βββ favicon.ico
β βββ llms.txt # LLM context file
β βββ manifest.webmanifest
βββ data/ # Data files (YAML)
β βββ travels.yaml # Travel data for /travels page
βββ .agents/ # Agent skills
βββ skills/
βββ frontend-design/ # Frontend design skill definition
Location: content/posts/YYYY-MM-DD-title-slug/index.md
Frontmatter format:
---
title: Post Title
description: |
Multi-line description
can span multiple lines
extra:
cover_image: cover-image.jpg # Optional, relative to post directory
---Content features:
- Posts use
<!-- more -->comment to mark excerpt cutoff - Dates in filenames:
YYYY-MM-DD-slugformat - Images stored alongside post in same directory
- Shortcodes available (see below)
Posts configuration: content/posts/_index.md sets:
page_template: "post.html"generate_feeds: trueinsert_anchor_links: "heading"
Use in markdown with {{ shortcode_name(param="value") }} syntax:
-
unsplash_credit - Photo attribution
{{ unsplash_credit(name="Photographer Name", link="https://unsplash.com/...") }} -
callout - Info/warning boxes
{% callout(type="info", title="Title") %} Content here (supports markdown) {% end %}Types:
info,warning -
youtube - Embed YouTube videos
-
youtube_playlist_url - YouTube playlist links
-
summary_tag - Summary/details tags
Regular pages (about, blog, etc.) are markdown files in content/ root with frontmatter:
---
title: Page Title
template: template_name.html # Optional
---The site was redesigned in March 2026 around a terminal/hacker aesthetic. The guiding metaphor is a personal computer terminal β monospace typography, green accents, command-line structural patterns β applied as a personal website rather than an actual terminal emulator.
- Terminal structure, human content. The chrome (header, sidebar, footer, nav, meta elements) is fully terminal-styled. Blog post body text uses sans-serif for comfortable long-form reading.
- One accent color. Green (
#3FB950dark /#4A6B56light) is the single accent, used for$prompts,>cursors, status dot, active links. No other accent colors. - Monospace as the primary voice. IBM Plex Mono is the personality of the site. IBM Plex Sans is used only where readability demands it (blog post body text, book descriptions).
- Persistent sidebar. The sidebar (portrait, identity,
$-prefixed roles,/slashnav) persists across all section pages (essays, books, travels, uses, teaching, now). Blog post reading pages go full-width (no sidebar) to give content room. - Earned decorative elements. Every visual element serves a purpose. The green status dot links to
/now. The$prompts echo the terminal metaphor. Thepid 1 Β· uptime 99.9%footer is playful but restrained.
The site supports two modes via prefers-color-scheme, both expressing the same terminal personality through different physical metaphors:
Dark mode (default) β CRT Terminal:
- Background:
#0D1117(void black) - Text:
#E6EDF3(phosphor white) - Green:
#3FB950(neon terminal green) - Borders:
#21262D(dark steel) - Background effects: phosphor glows, scanlines (1px lines at 3% opacity), dot grid, corner vignettes
- Status dot has a green box-shadow glow
Light mode β E-Ink Paper:
- Background:
#F4F1EB(warm paper) - Text:
#1C1917(warm ink) - Green:
#4A6B56(forest ink, desaturated) - Borders:
#D8D3CB(pencil line) - Background effects: all disabled (transparent) β e-ink doesn't emit light
- Status dot has no glow β just a solid ink circle
- No vignette, no scanlines, no glows
The color swap is purely CSS variables in _variables.scss. Zero structural/layout changes between modes.
- Mono (primary):
IBM Plex Monoβ used for all UI chrome, headings, nav, sidebar, post titles, meta elements - Sans (reading):
IBM Plex Sansβ used for blog post body text (.entry), book descriptions, page intro text - Handwritten:
Andrea(custom@font-face) β available but rarely used
All colors are CSS custom properties in :root (dark) with @media (prefers-color-scheme: light) overrides. Key semantic tokens:
--color-text/--color-text-dimmer/--color-text-faint/--color-text-faintestβ four-level text hierarchy--color-links/--color-links-hoverβ green accent--color-box-borders/--color-post-borderβ structural borders (two weights)--color-entry-textβ blog post body text (slightly dimmer than--color-textfor reading comfort)--color-roles-surface/--color-footer-surfaceβ semi-transparent surface fills--color-status-glowβ box-shadow for the status dot (value ornone)--portrait-filterβ CSS filter for the portrait image (nonein both modes currently)
Available in sass/_mixins.scss:
@include mediumScreen { ... }β min-width: 760px (sidebar becomes vertical)@include wideScreen { ... }β min-width: 1280px@include darkMode { ... }βprefers-color-scheme: dark@include lightMode { ... }βprefers-color-scheme: light
- Landing page (
index.html): top bar + sidebar + post list. Extendsbase.htmldirectly, overrides the header block (uses its own top bar instead). - Section pages (books, travels, uses, teaching, now, essays index): extend
base_sidebar.htmlwhich wraps content inshell-layoutwith the shared sidebar. The sidebar is insnippets/sidebar.html. - Blog posts (
post.html): extendbase.htmldirectly. Full-width, no sidebar. Just header bar + content + footer. - Responsive behavior: on mobile (<760px), the sidebar stacks above content. Nav links wrap horizontally. Portrait shrinks to 72px avatar.
These patterns recur throughout and define the aesthetic:
$β role/credential prompt prefix (sidebar roles, post date sigil)>β content item cursor (post entries on landing page)/slashβ nav link prefix (/essays,/books,/now)ββ LABEL βββ section dividers with rule linespid 1 Β· uptime 99.9%β footer status line~β tilde home symbol in header- Dashed borders β role boxes, used sparingly for "form field" feel
- Right-aligned dates in
YYYY-MMformat on post entries
Applied via ::before and ::after pseudo-elements on .wrapper-masthead:
- Phosphor glows β two subtle radial gradients (top-right, bottom-left) at ~6% opacity
- Scanlines β horizontal 1px green lines repeating every 4px at 3% opacity
- Dot grid β 24px grid of 0.6px dots at 12% opacity
- Corner vignettes β radial gradients darkening the four corners
All effects use z-index: -1 so they sit behind content. In light mode, all are set to transparent.
- Max content width:
800px($maxContentWidth) - Base font size: 18px, line-height: 1.6
- Blog post entry text: 18px, line-height: 1.7
- Code blocks:
14pxmono, background--color-site-background-accented, border--color-box-borders - Inline code: dark chip with border, 4px radius
- Blockquotes: green left border + subtle green-tinted background
- Syntax highlighting: dark theme (
ayu-dark) in dark mode, light theme (github-light) in light mode
Zola uses Tera, similar to Jinja2/Liquid.
Common patterns:
{# Comments #}
{{ variable }}
{{ variable | filter }}
{% if condition %}...{% endif %}
{% for item in items %}...{% endfor %}
{% block name %}...{% endblock %}
{% extends "base.html" %}
{% include "snippets/file.html" %}- base.html β Master template with
<head>, analytics, schema.org metadata. Hasheader,body, andcontentblocks. - base_sidebar.html β Extends base. Wraps content in
shell-layoutwith the shared sidebar (snippets/sidebar.html). Used by all section/index pages. - index.html β Landing page. Extends base directly (overrides header with its own top bar). Uses
snippets/sidebar.htmlfor the sidebar. - post.html β Individual blog post. Extends base directly (no sidebar, full-width).
- extra_page.html β Generic content page. Extends base_sidebar. Used by uses, teaching, now.
- books.html / travels.html β Specific page templates. Extend base_sidebar.
- posts.html / section.html β Post listing. Extend base_sidebar.
- snippets/sidebar.html β The shared sidebar (portrait, identity, roles, nav). Single source of truth, used by both
index.htmlandbase_sidebar.html. Nav items auto-highlight based oncurrent_path. - snippets/header.html β Top bar for inner pages (
~ andrealeopardi.com+/nowlink). Not used on landing page (which has its own top bar inindex.html). - snippets/footer.html β Terminal footer (
github email bluesky rss+pid 1 Β· uptime 99.9%).
Common Zola variables:
config.title,config.base_url,config.extra.*page.title,page.content,page.date,page.extra.*section.pages- List of pages in a section
Key settings:
base_url = "https://andrealeopardi.com/"
compile_sass = true
build_search_index = false
title = "Andrea Leopardi"
generate_feeds = true
feed_filenames = ["feed.xml"]
feed_limit = 20
[extra]
# Custom variables accessible via config.extra.*
full_name = "Andrea Leopardi"
username = "whatyouhide"
email = "hi@andrealeopardi.com"
twitter_username = "whatyouhide"
github_username = "whatyouhide"
analytics_umami_website_id = "2516c3bf-d125-4dcb-b2b9-2c086e715e81"Tags are enabled:
taxonomies = [{ name = "tags", feed = true }]Posts can include tags = ["tag1", "tag2"] in frontmatter.
Umami analytics integrated in base.html:
<script defer
src="https://analytics.andrealeopardi.com/script.js"
data-website-id="{{ config.extra.analytics_umami_website_id }}">
</script>Configured in config.toml:
[markdown.highlighting]
style = "inline"
light_theme = "github-light"
dark_theme = "ayu-dark"Themes auto-generated to /static/syntax-theme-*.css (gitignored).
Structured data in base.html for person/author information. Blog posts have additional JSON-LD via snippets/json_ld_blog_post.html.
Giscus (GitHub Discussions) enabled for blog posts via snippets/giscus.html.
JavaScript in base.html creates decorative snowflakes animation (lines 64-110).
Structured data for the /travels page:
countries:
ITA:
name: "Italy"
visited: true
home: true
USA:
name: "United States"
visited: trueISO 3166-1 alpha-3 country codes used as keys.
Configuration in .markdownlint.json:
Enforced rules:
- MD001: Header levels increment by one
- MD003: Consistent header style
- MD004: Unordered lists use asterisks
- MD009: No trailing spaces
- MD010: No hard tabs
- MD018: No space after hash in headers
- MD033: Limited HTML tags allowed (img, details, summary, div, svg, etc.)
- MD046: Fenced code blocks (not indented)
- MD048: Backtick code fences
Disabled rules:
- MD007: Unordered list indentation (disabled)
- MD012: Multiple blank lines (disabled)
- MD013: Line length (disabled)
- MD022: Blank lines around headers (disabled)
- MD024: Multiple headers with same content (disabled)
Configuration in link_check_config.json:
Ignored patterns:
- Twitter/Reddit links (often rate-limited)
- OpenAI
- Medium
These sites frequently block automated checkers.
.gitignore includes:
/public # Build output
/static/syntax-theme-dark.css # Generated
/static/syntax-theme-light.css # Generated
- Branch:
main - Recent work: Terminal hacker redesign (March 2026) β new visual direction, persistent sidebar, dual color scheme (dark CRT + light e-ink paper), /now page
- Edit markdown files in
content/orcontent/posts/ - Run
zola serveto preview changes locally - Check that links work with
zola check - Build with
zola buildto generate/public
- Edit SCSS files in
sass/ - Zola automatically compiles to
/style.css - Use CSS variables from
_variables.scssfor consistency - Follow existing patterns for dark mode support
- Test responsiveness with
mediumScreenandwideScreenmixins
- Create
.htmlfile intemplates/ - Use Tera syntax
- Extend
base.htmlfor consistent layout - Include snippets from
templates/snippets/for reusable components
- Create
.htmlfile intemplates/shortcodes/ - Access parameters via
{{ param_name }} - Use
{{ body }}for content between{% shortcode %}...{% end %} - Use
| markdown | safefilter to render markdown in shortcode body
- Base URL:
https://andrealeopardi.com/ - No trailing slashes in feed URLs:
get_url(path="feed.xml", trailing_slash=false) - Internal links: Use Zola's
get_url(path="...")or relative paths - External links: Always use HTTPS
- Post images: Store alongside post in
content/posts/YYYY-MM-DD-slug/ - Static images: Place in
static/assets/ - Favicons:
static/favicons/ - Always provide alt text
- Use
unsplash_creditshortcode for Unsplash photos
- Templates: 4-space indentation
- SCSS: 2-space indentation
- Markdown: Follow
.markdownlint.jsonrules - Naming: kebab-case for files and directories
-
Build output directory:
/publicis gitignored. This is the deployment target. -
Syntax highlighting themes: Auto-generated CSS files are gitignored. Don't edit them directly.
-
Zola serve vs build:
serveuses different base URL (localhost). Usebuildto test production URLs. -
SCSS compilation: Automatic via Zola. No separate build step needed.
-
Template changes: Require server restart with
zola serve(unlike content changes which auto-reload). -
Post dates: Must be in filename AND can be in frontmatter. Filename format:
YYYY-MM-DD-slug. -
Excerpt marker: Use
<!-- more -->in post content, not frontmatter. -
Color scheme: Dark (CRT) is the
:rootdefault. Light (e-ink paper) applied viaprefers-color-scheme: light. No manual toggle β follows OS preference. -
Custom fonts: "Andrea" font loaded via
@font-facefromstatic/assets/fonts/. -
Analytics: Umami self-hosted at
analytics.andrealeopardi.com. Website ID in config. -
Section configuration:
_index.mdfiles configure how Zola processes a directory of pages. -
Shortcode syntax: Two types:
- Inline:
{{ shortcode(param="value") }} - Block:
{% shortcode(param="value") %}content{% end %}
- Inline:
A frontend-design skill is available in .agents/skills/. This skill provides guidance for creating distinctive, production-grade frontend interfaces. Key principles:
- Avoid generic AI aesthetics (Inter, Roboto, purple gradients)
- Choose bold, intentional design directions
- Use distinctive typography (avoid system fonts)
- Implement cohesive color schemes with CSS variables
- Add motion and micro-interactions thoughtfully
- Match implementation complexity to aesthetic vision
See .agents/skills/frontend-design/SKILL.md for full details.
- Zola documentation: https://www.getzola.org/documentation/
- Tera template syntax: https://keats.github.io/tera/docs/
- Site content context: See
static/llms.txtfor LLM-friendly site overview - Live site: https://andrealeopardi.com
| Task | Command |
|---|---|
| Start dev server | zola serve |
| Build site | zola build |
| Check links | zola check |
| Check markdown links | make check-all-links |
| View output | Open /public/index.html |
Last updated: 2026-03-16