Markdown to HTML Presentation Converter
Uno script Python per convertire file Markdown in presentazioni HTML con navigazione laterale.
Requisiti
- Python 3.9+
uv(gestore pacchetti Python)
Per installare uv:
curl -LsSf https://astral.sh/uv/install.sh | sh
Installazione
Veloce (Script)
Per installare tutto automaticamente (dipendenze incluse) e rendere disponibile il comando md2 globalmente, esegui:
chmod +x install.sh
./install.sh
Lo script installerà uv (se non presente) e il tool md2 globalmente tramite uv tool install.
Nota importante: Se dopo l'installazione il comando md2 non viene trovato, potresti dover aggiungere ~/.local/bin al tuo PATH eseguendo:
export PATH="$HOME/.local/bin:$PATH"
Manuale (Globale)
Se preferisci usare uv direttamente:
uv tool install .
Sviluppo (Locale)
Per configurare l'ambiente di lavoro in modo isolato e pulito:
make install
Questo creerà un ambiente virtuale .venv e installerà le dipendenze con uv sync.
Come usarlo
Globale
Se hai installato lo script globalmente, puoi generare la presentazione HTML direttamente:
md2 nomefile.md
Opzioni
md2 nomefile.md --lang en --dark --template corporate
| Flag | Default | Descrizione |
|---|---|---|
--lang |
it |
Attributo lang dell'HTML generato |
--dark |
off | Usa il tema scuro come default |
--template NOME |
— | Usa un template da ~/.md2/templates/NOME/ |
--init-templates |
— | (Re)copia il template default in ~/.md2/templates/ |
Sviluppo (Locale)
In alternativa, usa il target run di make specificando il file Markdown:
make run FILE=nomefile.md
Il comando genererà un file nomefile.html nella stessa directory.
Navigazione da tastiera
L'HTML generato supporta le seguenti scorciatoie:
| Tasto | Azione |
|---|---|
↓ / → / PgDn |
Slide successiva |
↑ / ← / PgUp |
Slide precedente |
Home |
Torna alla cover |
End |
Vai all'ultima slide |
S |
Toggle sidebar |
D |
Toggle dark/light mode |
Test
I test usano pytest e sono divisi in unit (funzioni pure, senza I/O) e live (end-to-end con file su disco).
tests/
├── unit/
│ ├── test_sanitize_html.py # sanitizzazione HTML e prevenzione XSS
│ ├── test_generate_css.py # generazione CSS, temi, dark mode, responsive
│ ├── test_render_presentation.py # parsing markdown, slide, sidebar, struttura HTML
│ ├── test_main_cli.py # parsing argomenti CLI
│ ├── test_template_system.py # sistema template, --template, --init-templates
│ ├── test_frontmatter.py # parsing frontmatter TOML
│ ├── test_palettes.py # sistema palette colori
│ ├── test_charts.py # direttiva :::chart e Charts.css
│ ├── test_chart_sizing.py # dimensioni default per tipo di chart
│ ├── test_columns.py # direttiva :::columns layout
│ └── test_print_css.py # CSS stampa ottimizzato per chart
└── live/
├── test_conversion_e2e.py # conversione completa file → HTML
├── test_edge_cases_e2e.py # file vuoti, unicode, XSS, casi limite
└── test_ui_improvements_e2e.py # verifica migliorie grafiche nell'output
Tutti i test
make test
oppure direttamente:
uv run pytest
Solo unit test
make test-unit
Solo live test (end-to-end)
make test-live
Test con output verboso
uv run pytest -v
Singolo file di test
uv run pytest tests/unit/test_sanitize_html.py
Singolo test per nome
uv run pytest -k "test_strips_script_tags"
Pulizia
Per rimuovere l'ambiente virtuale e i file generati:
make clean
Frontmatter
md2 supporta un blocco frontmatter TOML all'inizio del file markdown, delimitato da +++:
+++
title = "Report Trimestrale"
palette = "warm"
lang = "en"
dark = true
+++
# Report Trimestrale
Contenuto della presentazione...
| Campo | Tipo | Default | Descrizione |
|---|---|---|---|
title |
string | da # H1 |
Titolo della presentazione (override) |
palette |
string | "default" |
Nome palette colori |
colors |
array di string | — | Override colori della palette |
lang |
string | "it" |
Lingua del documento |
dark |
bool | false |
Dark mode come default |
I flag CLI (--lang, --dark) hanno priorità sul frontmatter quando specificati esplicitamente.
Palette colori
md2 include 6 palette predefinite: default, warm, cool, mono, vivid, pastel.
Le palette sono file TOML con questa struttura:
name = "warm"
colors = [
"#d45d00",
"#e8910c",
"#f5c542",
"#e15759",
]
[dark]
colors = [
"#f0a050",
"#f5b84c",
"#fce08a",
"#f28e8e",
]
Palette custom
Crea un file .toml in ~/.md2/palettes/:
# Nuova palette
~/.md2/palettes/corporate.toml
# Override di una builtin
~/.md2/palettes/warm.toml
Le palette utente hanno priorità sulle builtin.
Cascata colori
Palette builtin → Palette utente → Frontmatter (palette=) → Frontmatter (colors=)
Se nel frontmatter sono presenti sia palette che colors, i colori nel frontmatter sovrascrivono i primi N colori della palette selezionata.
Se la sezione [dark] è assente nel file palette, le varianti dark vengono calcolate automaticamente.
Struttura del file Markdown
md2 converte un singolo file .md in una presentazione HTML. Il file è diviso in sezioni separate da ---.
Copertina
La prima sezione (prima del primo ---) è la copertina. Il primo # H1 diventa il titolo della presentazione e della pagina HTML. Il testo sotto appare centrato nella slide di copertina. Se non c'è un # H1, il titolo di default è "Presentation".
Separatore slide
Usa --- su una riga separata, con righe vuote sopra e sotto, per separare le slide:
Contenuto slide 1
---
Contenuto slide 2
Titolo slide
Il primo ## H2 di ogni sezione diventa il titolo della slide e la voce corrispondente nella sidebar di navigazione. Se una sezione non ha ## H2, viene chiamata "Slide N".
Sotto-sezioni
All'interno di ogni slide puoi usare ### H3 e #### H4 per creare sotto-sezioni.
Esempio completo
# Titolo della Presentazione
Questo testo appare sulla copertina.
**Data:** 14 marzo 2026
---
## Introduzione
Contenuto della prima slide con **bold** e *italic*.
- Punto uno
- Punto due
- Sotto-punto
> Una citazione importante.
---
## Dati e Codice
### Tabella risultati
| Metrica | Valore | Trend |
|---------|--------|-------|
| CPL | €29 | +15% |
| CAC | €514 | -2% |
### Esempio di codice
```python
def hello():
print("Hello, world!")
Un link automatico: https://example.com
Una nota a piè di pagina1.
## Markdown supportato
### Testo
| Sintassi | Risultato |
|-------------------------|--------------------|
| `**bold**` | **bold** |
| `*italic*` | *italic* |
| `` `inline code` `` | `inline code` |
| `[testo](url)` | link cliccabile |
| `` | immagine centrata |
### Heading
| Livello | Uso |
|------------|--------------------------------------------------|
| `# H1` | Titolo della presentazione (solo nella copertina) |
| `## H2` | Titolo della slide (uno per slide) |
| `### H3` | Sotto-sezione dentro una slide |
| `#### H4` | Sotto-sezione di livello inferiore |
### Liste
Liste puntate (`-` o `*`) e numerate (`1.`), anche annidate con indentazione.
### Tabelle
Sintassi standard con `|` e `---`. L'allineamento colonne è supportato (`:---`, `:---:`, `---:`).
### Grafici (Charts)
Usa la direttiva `:::chart` per trasformare una tabella markdown in un grafico visuale. La sintassi è:
:::chart TIPO [--opzioni...]
| Intestazione | Colonna Dati |
|---|---|
| Etichetta | Valore |
| ::: |
La prima colonna è sempre l'etichetta (asse delle categorie). Le colonne successive sono i dati. Se ci sono più colonne dati, il grafico diventa automaticamente multi-dataset.
#### Tipi di grafico
| Tipo | Descrizione |
|----------|------------------------------------------------------|
| `bar` | Barre orizzontali — ideale per confronti |
| `column` | Barre verticali — ideale per serie temporali |
| `line` | Grafico a linea — trend e andamenti |
| `line filled` | Linea con riempimento sotto la curva (era `area`) |
| `pie` | Grafico a torta — proporzioni (solo singola serie) |
> `:::chart area` resta supportato come alias di `:::chart line filled` per retro-compatibilità.
#### Opzioni
| Opzione | Effetto |
|---------------|-------------------------------------------------------|
| `--labels` | Mostra le etichette (prima colonna) sugli assi |
| `--legend` | Mostra legenda sotto il grafico (per multi-dataset) |
| `--stacked` | Barre/colonne impilate anziché affiancate |
| `--show-data` | Mostra i valori numerici al passaggio del mouse |
| `--title "…"` | Aggiunge un titolo/caption sopra il grafico |
#### Esempio: singola serie
:::chart bar --labels --title "Vendite per prodotto"
| Prodotto | Vendite |
|---|---|
| Widget A | 50 |
| Widget B | 80 |
| Widget C | 65 |
| ::: |
#### Esempio: multi-dataset con legenda
:::chart column --labels --legend
| Trimestre | Entrate | Uscite |
|---|---|---|
| Q1 | 100 | 80 |
| Q2 | 150 | 90 |
| Q3 | 130 | 110 |
| ::: |
#### Dimensioni
Ogni tipo di grafico ha dimensioni di default sensate:
| Tipo | Altezza | Larghezza |
|------|---------|-----------|
| `bar` | automatica (cresce con le righe) | 100% |
| `column`, `line`, `area` | `min(300px, 40vh)` | 100% |
| `pie` | proporzionale al viewport | `min(50vh, 50vw)` centrato |
#### Note
- I valori nelle colonne dati devono essere **numerici**. Valori non numerici vengono trattati come 0.
- I grafici usano automaticamente i colori della **palette** del documento (vedi sezione Palette colori).
- **Charts.css** viene incluso nell'HTML solo quando il documento contiene almeno un grafico — le presentazioni senza grafici non hanno overhead aggiuntivo.
- Basato su [Charts.css](https://chartscss.org/), una libreria CSS pura senza JavaScript.
- In **stampa**, i colori dei grafici vengono preservati (`print-color-adjust: exact`). I grafici non vengono spezzati tra pagine.
### Layout a colonne
Usa `:::columns` con `:::col` per affiancare contenuti in due colonne:
:::columns
:::col Testo nella colonna sinistra.
- Punto uno
- Punto due
:::col :::chart bar --labels
| A | B |
|---|---|
| x | 50 |
| ::: |
:::
Ogni `:::col` delimita l'inizio di una colonna (massimo 2). Su mobile (< 768px) le colonne si impilano verticalmente. In stampa restano affiancate.
### Blocchi di codice
Fenced code blocks con ` ```linguaggio ``` `. Il linguaggio viene usato come attributo class per eventuale syntax highlighting.
### Blockquote
`>` produce un blocco citazione con bordino laterale blu.
### Footnotes
`[^1]` nel testo e `[^1]: testo della nota` in fondo alla slide. Le note vengono renderizzate in fondo alla slide con stile ridotto.
### Autolink
URL nudi (`https://...`) vengono automaticamente convertiti in link cliccabili con `target="_blank"`.
### Newline
Un singolo invio nel markdown produce un `<br>` nell'HTML (estensione `nl2br`). Non serve il doppio spazio a fine riga.
### HTML inline
Tag HTML sicuri vengono preservati: `<iframe>` per embed video/mappe, `<img>` con attributi `src`, `alt`, `width`, `height`. Tag pericolosi (`<script>`, `onclick`, `javascript:`) vengono rimossi automaticamente.
## Interfaccia generata
- **Sidebar navigabile** — link a ogni slide, indicatore slide attiva, lista scrollabile con shortcut fissi in fondo
- **Sidebar collassabile** — bottone `«`/`»` o tasto `S`
- **Dark mode** — toggle sole/luna in alto a destra o tasto `D`
- **Indicatore slide** — mostra "2 / 5" in basso a destra
- **Barra di progresso** — linea blu in cima alla pagina
- **Scroll-snap** — ogni slide occupa l'intero viewport
- **Fade-in** — il contenuto delle slide appare con animazione
- **Print** — `Ctrl+P` produce un layout pulito senza UI, una slide per pagina, con margini uniformi (15mm) tra browser. I grafici mantengono i colori e non vengono spezzati tra pagine; le tabelle conservano l'header colorato
- **Meta tag Open Graph** — titolo e descrizione per la condivisione
- **Favicon inline** — nessun 404 nel browser
- **Responsive** — breakpoint a 1024px (tablet) e 768px (mobile) con menu hamburger
## Template personalizzati
md2 usa un sistema di template basato su [Jinja2](https://jinja.palletsprojects.com/). Al primo avvio, il template default viene copiato in `~/.md2/templates/default/` — puoi modificarlo o crearne di nuovi.
### Struttura di un template
~/.md2/templates/ ├── default/ ← template default (copiato automaticamente) │ ├── base.html ← template principale con {% block %} │ ├── style.css ← CSS completo │ └── components/ │ ├── head.html ← con meta, OG, favicon, <style> │ ├── sidebar.html ← sidebar con lista slide e shortcut │ ├── cover.html ← slide di copertina │ ├── slide.html ← singola slide (usata nel for loop) │ ├── controls.html ← progress bar, indicator, theme toggle │ └── scripts.html ← JavaScript └── mio-template/ ← template custom └── base.html
### Creare un template custom
**Metodo 1 — Copia e modifica:**
```bash
cp -r ~/.md2/templates/default ~/.md2/templates/mio-template
# Modifica i file a piacere
md2 presentazione.md --template mio-template
Metodo 2 — Ereditarietà (solo override):
Crea ~/.md2/templates/mio-template/base.html:
{% extends "default/base.html" %}
{% block sidebar %}{% endblock %}
{% block controls %}{% endblock %}
Questo template eredita tutto dal default e rimuove sidebar e controlli. Puoi sovrascrivere qualsiasi blocco.
Blocchi disponibili
| Blocco | Contenuto |
|---|---|
head |
Contenuto di <head> (meta, title, CSS) |
css |
Solo il CSS (dentro <style>) |
controls |
Progress bar, hamburger, indicator, theme toggle |
sidebar |
Sidebar completa con lista slide e shortcut |
main |
Container principale con cover e slide |
cover |
Slide di copertina |
slides |
Loop delle slide |
scripts |
Blocco <script> con tutto il JS |
Variabili di contesto
Queste variabili sono disponibili in tutti i template:
| Variabile | Tipo | Descrizione |
|---|---|---|
title |
string | Titolo della presentazione (HTML-escaped) |
og_description |
string | Meta description per Open Graph |
lang |
string | Attributo lang (it, en, ...) |
dark_mode |
bool | true se --dark è attivo |
cover.title |
string | Titolo della copertina |
cover.content |
string | HTML del contenuto della copertina |
slides |
list | Lista delle slide |
slides[].id |
string | ID HTML della slide (slide-0, slide-1) |
slides[].title |
string | Titolo della slide |
slides[].content |
string | HTML del contenuto della slide |
palette_css |
string | CSS con variabili --md2-color-N |
has_charts |
bool | true se il documento contiene grafici |
Aggiornare il template default
Dopo un aggiornamento di md2, puoi rigenerare il template default con:
md2 --init-templates
Questo sovrascrive ~/.md2/templates/default/ con la versione bundled aggiornata. I template custom non vengono toccati.
-
Questa è la nota. ↩
Release files for md2-presenter 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| md2_presenter-0.2.1.tar.gz | 169.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| md2_presenter-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 212.9 kB
Release files / md2_presenter-0.2.1.tar.gz
| Download URL | md2_presenter-0.2.1.tar.gz |
|---|---|
| Size | 169.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d1d4f36052229b969e9afd8dfffcbac9b24c858c6d1a4d4955ea44db33cbec8e
|
|
BLAKE2b-256 checksum How to use checksums |
cd293c733eeecb85c4ee71cabc48c085a5fed9c907ce4d0380aace841d23bf30
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.12
|
Release files / md2_presenter-0.2.1-py3-none-any.whl
| Download URL | md2_presenter-0.2.1-py3-none-any.whl |
|---|---|
| Size | 43.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e0921d78c89208a90b8626b92f2b98e044c86d2617dbf9791221bbe627d45744
|
|
BLAKE2b-256 checksum How to use checksums |
4a9e28ea217b1ef6d44a46ebe33654aa5baeb5ab3b6ec6cf8b9890f709eb983d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.12
|