Temi
In questa pagina
- Integrati
- Installare un tema pubblicato
- Siti air-gapped/offline
- Il contratto ThemeProvider
- Più layout per pagina
- Quale layout/corpo è attivo
- Personalizzare i colori senza sovrascrivere un tema
- Banner hero della homepage
- Sovrascrivere un tema
- Sovrascritture del progetto
- Slot
- Manifesto del tema ( theme.json )
- Layout impliciti
- Scrivere un tema da zero
Temi
I temi sono template nativi BoxLang .bxm - non c'è alcun motore di
template separato o passaggio di build coinvolto.
Integrati
| Tema | Base | Note |
|---|---|---|
bootstrap (predefinito) | Bootstrap 5, incluso localmente | Font Poppins, navbar con gradiente del brand |
material | CSS in stile Material scritto a mano | Layout a card, ombre di elevazione, font Roboto |
tailwind | Tailwind Play CDN | Guidato da classi utility, nessun passaggio di build |
docsy | CSS scritto a mano, derivato da material | Look ispirato a Read the Docs/Docsy, blu navy da manuale di riferimento |
slate | CSS scritto a mano, derivato da material | Ispirato a Stripe/Slate - una sidebar permanentemente scura indipendentemente dalla modalità chiara/scura |
docusaurus | CSS scritto a mano, derivato da material | Ispirato a Docusaurus - navbar colorata a larghezza intera e in grassetto, card arrotondate |
justthedocs | CSS scritto a mano, derivato da material | Minimalismo ispirato a Just the Docs - il box di ricerca vive in cima alla sidebar |
vuepress | CSS scritto a mano, derivato da material | Accento verde ispirato a VuePress, angoli morbidi e arrotondati |
gitbook | CSS scritto a mano, derivato da material | Colonna di lettura centrata ispirata a GitBook, intestazioni serif |
notion | CSS scritto a mano, derivato da material | Sidebar senza bordi ispirata a Notion, UI quasi in scala di grigi, spazio bianco generoso |
I sette temi derivati da material sopra riutilizzano gli identici
template BoxLang di material (layout.bxm/page.bxm/search.bxm) invariati,
tranne per una rinomina con prefisso di classe CSS con ambito limitato -
solo assets/style.css (e, per justthedocs, una riga <bx:include>
riposizionata per spostare il box di ricerca nella sidebar) differisce,
quindi ereditano lo stesso set completo di funzionalità e lo stesso
comportamento air-gapped-capable che material ha già.
Il CSS/JS proprio di ogni tema integrato (il pacchetto CSS/JS di Bootstrap,
highlight.js, Alpine.js, lunr.js per il provider di ricerca local
predefinito, e Mermaid quando mermaid è attivato) viene incluso con
questo modulo e copiato direttamente in ogni site/ compilato - nessuna
CDN, nessun accesso a internet necessario per visualizzare un sito
compilato. Il motore di utility proprio del tema tailwind (un
compilatore JIT lato client, non un foglio di stile statico) e altre
funzionalità opzionali che attivi tu stesso (math, ricerca Algolia,
Google Analytics) continuano a caricarsi da una CDN o da un'API ospitata -
vedi Siti air-gapped/offline più sotto.
bootstrap, material e tailwind applicano la stessa palette del
brand BoxLang (un gradiente #00FF78 -> #00DBFF e un accento #FFF500);
i sette temi della galleria sotto di essi usano ciascuno la propria
palette distinta, ispirata alla piattaforma da cui prendono il proprio
look - vedi la tabella sopra. Ognuno dei dieci include lo stesso insieme
di funzionalità di pagina indipendentemente dalla palette:
- Un sommario "In questa pagina" in pagina, generato dalle intestazioni
h2/h3proprie di ogni pagina. - Breadcrumb, che mostrano la catena di antenati di una pagina quando è annidata più di un livello sotto un antenato collegato.
- Link pagina precedente/successiva in fondo all'articolo, seguendo l'ordine di lettura della nav stessa.
- Blocchi di codice con evidenziazione della sintassi, tramite
highlight.js più una grammatica BoxLang
propria (
```bx/```boxlang/```cfscript), ciascuno con un pulsante di copia - mostrato al passaggio del mouse sui dispositivi che lo supportano, sempre visibile sui dispositivi touch (dove non c'è hover per rivelarlo). Vedi Estensioni Markdown. - Webfont autoospitati - nessuna richiesta a
fonts.googleapis.comal momento della visualizzazione. - Un interruttore modalità scura/chiara, alimentato da
Alpine.js per la reattività. La scelta del
visitatore viene ricordata in
localStorage(ricadendo sulla preferenza del suo sistema operativo), e applicata prima del primo rendering per evitare un lampo del tema sbagliato. - Un header responsivo che resta su una sola riga a qualsiasi larghezza - un viewport stretto restringe il box di ricerca invece di farlo andare a capo - più una nav laterale comprimibile (un interruttore a hamburger in tutti e dieci i temi).
- Scorciatoie da tastiera nel box di ricerca:
/porta il focus sulla ricerca da qualsiasi punto della pagina, eEscapechiude i risultati. Vedi Ricerca. - Un link al repository e una riga "Modifica questa pagina"/"Ultimo
aggiornamento", quando le opzioni
repo/lastUpdateddibxsites.yamlsono impostate. Vedi Configurazione. - Un link "Scarica Markdown", accanto a "Modifica questa pagina" - il
sorgente
.mdgrezzo di ogni pagina viene pubblicato accanto al proprio HTML compilato (guides/themes.mdsi trova accanto aguides/themes/index.html), così una persona (o un LLM) può leggere la pagina come Markdown puro direttamente invece di analizzare l'HTML renderizzato. Sempre attivo, nessuna configurazione necessaria. Vedi Per iniziare. - Un footer opzionale (copyright, link
social, un credito "Built with BxSites") quandofooterdibxsites.yamlètrue. Vedi Configurazione. - Un selettore di versione, che appare automaticamente non appena un
progetto ha una cartella
docs/versions/con più di una versione al suo interno. Vedi Configurazione. - Un
404.htmlcon tema applicato, servito automaticamente dalla maggior parte degli host statici (incluso GitHub Pages) per qualsiasi percorso non corrispondente. Aggiungi un404.mdalla radice didocs/(osrc/) per sostituirne titolo e contenuto con i tuoi - non viene mai compilato come una pagina normale (nessuna voce nel nav, nessun URL insitemap.xml), ma renderizzato al suo posto insite/404.html. - Un logo e una favicon personalizzati, quando
theme.logo/theme.favicondibxsites.yamlsono impostati. Vedi Configurazione. - Una nav laterale comprimibile, opzionale tramite
theme.options.navCollapsible. Vedi Configurazione. - Google Analytics, quando
analyticsdibxsites.yamlè configurato. Vedi Configurazione. - Social share card (meta tag Open Graph + Twitter Card), ricavate
dal frontmatter
descriptiondi ogni pagina (o dalladescriptiona livello di sito) e dal suoogImage(o da quello a livello di sito) - generate automaticamente per pagina in modo opzionale tramitegenerateOgImagesdibxsites.yaml. Vedi Configurazione. - Tag di pagina, un'icona e una riga di riepilogo, tutti opzionali
tramite il frontmatter di una pagina - i tag vengono renderizzati come
badge che collegano a un indice
/tags/a livello di sito. Vedi Per iniziare. - Una nav esplicita in sostituzione, in
bxsites.yamlo nel propriodocs/nav.json, che sostituisce la deduzione dalle cartelle per siti di grandi dimensioni. Vedi Configurazione. - CSS/JS extra, iniettati tramite
extraCss/extraJsdibxsites.yaml. Vedi Configurazione. - Box di richiamo per ammonizioni (nota/avviso/suggerimento/...), attivi di default nel markdown di qualsiasi pagina, incluse le varianti comprimibili - nessuna configurazione necessaria. Vedi Estensioni Markdown.
- Note a piè di pagina e liste di definizioni, opzionali tramite
markdowndibxsites.yaml. Vedi Estensioni Markdown. - Schede di contenuto, numeri di riga/righe evidenziate/titoli del codice e indicatori di diff/cornici terminale per i blocchi di codice, nessuna configurazione necessaria. Vedi Estensioni Markdown.
- Immagini responsive - varianti ridimensionate + WebP e una
riscrittura
<picture>per ogni immagine idonea indocs/assets/**, attiva di default. Vedi Immagini Responsive. - Diagrammi Mermaid, opzionali tramite
mermaiddibxsites.yaml. Vedi Estensioni Markdown. - Matematica (KaTeX), opzionale tramite
mathdibxsites.yaml. Vedi Estensioni Markdown.
Imposta quale tema usa un progetto in bxsites.yaml:
theme: { name: material }
{ "theme": { "name": "material" } }
[theme]
name = "material"
Installare un tema pubblicato
Un tema pubblicato su ForgeBox si installa con nient'altro che il
binario bxSites stesso - non serve box/CommandBox. Sfoglia i pacchetti
già pubblicati nella categoria
bxsites-themes su
ForgeBox:
bxSites install:theme --name=bx-sites-theme-blog1 [--version=1.0.0]
Questo scarica lo zip del pacchetto e lo estrae in
.themes/bx-sites-theme-blog1/ dentro la content root del progetto (vedi
Content Source),
verificando che soddisfi il contratto ThemeProvider sotto prima di
terminare. Un progetto può portare con sé più temi installati fianco a
fianco in questo modo e passare dall'uno all'altro semplicemente per
nome:
theme: { name: bx-sites-theme-blog1 }
{ "theme": { "name": "bx-sites-theme-blog1" } }
[theme]
name = "bx-sites-theme-blog1"
Un tema non necessita di alcun coinvolgimento del modulo BoxLang/
class-loader (a differenza di un plugin) - sono puri file, quindi non
c'è un passaggio di attivazione separato come per install:plugin;
impostare theme.name è l'unico collegamento necessario. Vedi
install:theme nel riferimento CLI.
Parti da un tema costruito per un altro generatore di siti statici
invece? Vedi Importare un tema - theme:import
converte meccanicamente, con il massimo impegno possibile, i file
template propri di un tema mkdocs/jekyll/hugo in uno scheletro
.themes/<name>/.
Siti air-gapped/offline
Un sito compilato funziona senza alcun accesso a internet per
impostazione predefinita, per bootstrap, material e i sette temi
derivati da material (docsy, slate, docusaurus, justthedocs,
vuepress, gitbook, notion) con il provider di ricerca local
predefinito: il CSS/JS proprio di Bootstrap, highlight.js, Alpine.js e
lunr.js sono tutti inclusi con questo modulo
(resources/assets/vendor/) e copiati direttamente in
site/assets/vendor/ al momento del build - nessun tag <script>/
<link> verso una CDN in nessun punto dell'HTML generato per nessuno di
questi. Attivare la chiave mermaid di bxsites.yaml include Mermaid
nello stesso modo - il suo pacchetto mermaid.min.js viene copiato in
site/assets/vendor/mermaid/ e ogni tema integrato lo carica da lì, così
i diagrammi continuano a essere renderizzati con zero richieste in
uscita.
Alcune cose comunicano ancora con la rete, solo quando le attivi tu stesso:
- Il motore di utility proprio del tema
tailwindè un compilatore JIT lato client caricato dacdn.tailwindcss.com- non è un foglio di stile statico che questo modulo può includere allo stesso modo, quindi questo tema non è ancora predisposto per l'uso air-gapped. - Il motore di layout proprio di Mermaid carica in modo differito un
chunk aggiuntivo,
elk-api.js, da jsDelivr - ma solo per i tipi di diagramma che optano per l'algoritmo di layoutelk; il pacchetto inclusomermaid.min.jsrenderizza da solo ogni altro tipo di diagramma. - L'opzione
mathdibxsites.yamlcarica KaTeX (sia il suo JS sia i propri file font) da una CDN quando è attivata. searchProvider.provider: "algolia"eanalytics.provider: "google"comunicano intrinsecamente con un'API ospitata/un endpoint di tracciamento - includere il file JS localmente non eliminerebbe questa dipendenza.
Se il tuo ambiente di distribuzione non ha davvero alcun accesso a
internet, limitati a bootstrap/material/uno dei sette temi derivati
da material, al provider di ricerca local predefinito, evita i
diagrammi Mermaid con layout elk se mermaid è attivo, e lascia
disattivati math/Algolia/analytics.
Vedi Icone per come il frontmatter icon proprio di una
pagina (o l'icon proprio di una voce di nav.json) viene risolto in
un'emoji, un'icona con nome da una delle otto librerie incluse, oppure
un SVG del tuo progetto.
Il contratto ThemeProvider
Un tema è semplicemente una cartella con:
layout.bxm(obbligatorio) - il guscio HTML esterno + la nav. Ricevevariables.page,variables.nav,variables.siteConfig,variables.themeDirevariables.basePathnello scope, e include il template del corpo risolto tramite#variables.themeDir#/#variables.bodyFile#(page.bxm, a meno che una pagina/un tipo di contenuto non risolva a qualcos'altro - vedi Più layout per pagina sotto).variables.basePathè sempre un percorso relativo alla radice che termina con/(/di default,/my-docs/quandobaseURLdibxsites.yamllo sovrascrive) - anteponilo a ognihref/srcinterno, invece di codificare un/iniziale fisso, così il tema continua a funzionare quando il sito viene servito da un sotto-percorso.page.bxm(obbligatorio) - il corpo dell'articolo. Renderizzavariables.page.contentHtml- il markdown già convertito.search.bxm(opzionale) - il markup del box di ricerca, incluso dalayout.bxmsolo quandosearchdibxsites.yamlètrue. Vedi Ricerca.blog.bxm(opzionale) - un guscio esterno alternativo per le pagine di elenco/categoria/archivio/autore/statistiche del blog. Ricade sulayout.bxmquando un tema non lo ha. Vedi Più layout per pagina.blog-page.bxm(opzionale) - un corpo alternativo per un singolo articolo del blog, comunque renderizzato sotto il normalelayout.bxmdel tema. Ricade supage.bxmquando un tema non lo ha.assets/(opzionale) - CSS/JS del tema, copiati insite/assets/theme/al momento del build.slots/<name>.bxm(opzionale) - il contenuto predefinito del tema per uno slot, incluso ovunque il suolayout.bxmchiamirenderSlot( "<name>" ).theme.json(opzionale) - il manifesto del tema: il suo slug e gli slot che espone.
variables.page.editUrl/.lastUpdated (stringhe vuote quando non
configurati) e variables.siteConfig.repo/.social/.footer sono
sempre disponibili anch'essi, a supporto delle funzionalità di link al
repository/link di modifica/ultimo aggiornamento/footer sopra descritte -
un tema personalizzato decide da sé se e come renderizzarli, come
tutto il resto. variables.versions ([ { label, url, kind } ], con
"Latest" per primo) e variables.currentVersion (l'etichetta label in
fase di rendering in questo momento) sono a supporto del selettore di
versione - vuoti/"Latest" per un progetto non versionato, quindi un
tema deve renderizzare un selettore solo quando
variables.versions.len() gt 1. Il kind di ogni voce è "current" (la
versione su cui atterra un visitatore alla radice del sito), "released"
(qualsiasi altro snapshot già creato), oppure "next" (il semplice
albero docs/, una volta impostato versions.default - vedi
Versionamento).
Invece di scorrere variables.versions a mano, chiama
renderVersionSwitcher( variables.versions, variables.currentVersion ) -
collegata allo scope di rendering di ogni tema nello stesso modo in cui lo
sono themeAssetUrl()/moduleAssetUrl() (sopra) - e questa costruisce
l'intero <select>, raggruppa "next" dietro un separatore dopo ogni
versione rilasciata, ed etichetta la voce "current" con "(Current)",
tutto guidato da kind invece che un tema debba reimplementare da sé
questa logica. Un secondo argomento opzionale aggiunge classi CSS extra
al <select> (renderVersionSwitcher( variables.versions, variables.currentVersion, "my-extra-class" )) per un tema che vuole uno
stile proprio senza reimplementare il markup. Ogni tema integrato ottiene
le proprie icone repository/social da una
piccola tabella SVG condivisa,
<bx:include template="#variables.moduleAssetsDir#/icons.bxm">
(definisce bxsitesIcon( name ), uno tra github, twitter/x, rss,
youtube, linkedin, facebook, bluesky, threads, slack,
patreon, email, edit, clock, con un glifo di link generico come
ripiego) - un tema personalizzato può includerla nello stesso modo,
oppure fornire le proprie icone del tutto.
Una cartella tema a cui manca uno dei due file obbligatori fallisce
subito con un chiaro errore BxSites.InvalidTheme al momento del build,
invece di un confuso errore di template nel profondo del rendering.
blog.bxm/blog-page.bxm non sono mai obbligatori - la stessa forma
"opzionale, con ripiego" che ha già search.bxm.
Più layout per pagina
Un tema può offrire più di un guscio esterno e più di un template del corpo, permettendo a un blog (o a qualsiasi altro tipo di contenuto) di avere un aspetto diverso dal resto del sito riutilizzando comunque il chrome e gli asset dello stesso tema. Due catene di risoluzione indipendenti:
- Guscio esterno -
layout.bxmdi default. Le pagine di elenco/categoria/archivio/autore/statistiche del blog usanoblog.bxmquando il tema attivo lo ha. Una pagina che impostalayout:nel proprio frontmatter (o che corrisponde a una regola di layout implicito) viene invece renderizzata tramite<name>.bxm, quando il tema attivo o le sovrascritture del progetto ne hanno uno. - Corpo -
page.bxmdi default. Un articolo del blog usablog-page.bxmquando il tema attivo lo ha. Un guscio include il corpo coninclude "#variables.themeDir#/#variables.bodyFile#".
---
title: We raised a Series A
layout: press-release
---
layout: press-release renderizza questa singola pagina tramite
.overrides/<theme>/press-release.bxm (o il press-release.bxm proprio
del tema attivo, se ne ha uno) al posto di layout.bxm. Quel file è una
pagina completa: copia layout.bxm per partire dal chrome proprio del
tema (bxSites layout:new press-release fa esattamente questo), oppure
scrivine uno minimale e usa include per il corpo dove serve. Un
layout: che nomina un file che nessuno fornisce ricade su
layout.bxm/page.bxm invece di far fallire il build, così cambiare
tema non rompe mai una pagina che nominava il layout personalizzato di
un altro tema.
bootstrap fornisce blog.bxm/blog-page.bxm come esempio funzionante
da copiare; gli altri temi integrati non ancora, e ricadono su
layout.bxm/page.bxm per i contenuti del blog nello stesso modo in
cui lo farebbe qualsiasi override .theme/ incompleto.
Quale layout/corpo è attivo
Ogni .bxm attraverso cui viene renderizzata una pagina - layout.bxm,
page.bxm, blog.bxm, blog-page.bxm, o uno personalizzato di un
progetto - può leggere quali file sono stati effettivamente risolti,
nello stesso modo diretto in cui già legge variables.page/
variables.data:
variables.layoutFile- il guscio esterno in uso, es."layout.bxm"o"blog.bxm"variables.bodyFile- il corpo in uso, es."page.bxm","blog-page.bxm", o uno nominato via frontmattervariables.page.layout- il valore grezzo del frontmatterlayout:proprio della pagina, se ne ha impostato uno;""altrimenti
Utile come aggancio per una classe del body, o per ramificare senza un template separato:
<body class="layout-#reReplace( variables.bodyFile, '\.bxm$', '' )#">
<bx:if variables.bodyFile == "blog-page.bxm">
<!-- chrome esclusivo degli articoli del blog -->
</bx:if>
Personalizzare i colori senza sovrascrivere un tema
Per una piccola modifica di colore/font, forkare un intero tema è
eccessivo - ogni tema integrato legge la propria palette da una manciata
di proprietà CSS personalizzate su :root, ridichiarate sotto
[data-theme="dark"] per la modalità scura. L'
extraCss di bxsites.yaml si
carica dopo il foglio di stile proprio del tema, quindi una
ridichiarazione con la stessa specificità al suo interno vince senza
toccare affatto resources/themes/:
extraCss: [ assets/brand.css ]
{ "extraCss": ["assets/brand.css"] }
extraCss = [ "assets/brand.css" ]
/* docs/assets/brand.css - copiato in site/assets/brand.css al momento del build */
:root {
--bxsites-gradient-start: #7C3AED;
--bxsites-gradient-end: #DB2777;
--bxsites-accent: #FBBF24;
--bxsites-link: #7C3AED;
--bxsites-link-hover: #9F5AF0;
}
[data-theme="dark"] {
--bxsites-link: #C4B5FD;
--bxsites-link-hover: #DDD6FE;
}
L'insieme proprio del tema bootstrap
(resources/themes/bootstrap/assets/style.css) è composto da
--bxsites-gradient-start/-end, --bxsites-accent, --bxsites-bg,
--bxsites-text, --bxsites-sidebar-bg, --bxsites-sidebar-text,
--bxsites-border, --bxsites-link, --bxsites-link-hover,
--bxsites-code-bg, --bxsites-step-marker-bg, --bxsites-step-marker-text,
--bxsites-step-line, --bxsites-step-success-bg/-text,
--bxsites-step-warning-bg/-text, --bxsites-step-danger-bg/-text e
l'insieme --bxsites-table-*, che disegna la card, la
fascia di intestazione, i separatori e le tinte zebra/hover di una tabella
renderizzata.
Ogni tema integrato garantisce --bxsites-gradient-start/-end,
--bxsites-accent e gli insiemi --bxsites-step-* e --bxsites-table-*
con questi nomi esatti,
quindi extraCss può sempre ridefinire il colore del brand/gli accenti
dello stepper indipendentemente dal tema - ma solo bootstrap, slate e
notion espongono anche --bxsites-bg/-text/-sidebar-bg/-sidebar-text/-border/-link/-link-hover/-code-bg
con questi nomi (justthedocs alias tutti tranne i due -sidebar-* allo
stesso modo). Ogni altro tema integrato (material, tailwind,
docsy, docusaurus, vuepress, gitbook) usa invece i propri nomi di
proprietà personalizzata interni per quel secondo gruppo (ad es. il
proprio assets/style.css di material usa --md-bg/--md-ink/--md-link/...)
- apri il proprio
assets/style.cssdi quel tema per trovare i suoi nomi reali prima di sovrascriverne uno tramiteextraCss. Qualsiasi cosa oltre a colore/font (layout, aggiungere/rimuovere elementi di contorno) richiede una vera sovrascrittura o un tema personalizzato - vedi sotto.
Il resto supporta il blocco di direttive
::: stepper/::: step -
--bxsites-step-marker-bg/-text sono lo sfondo/colore testo del
cerchio numerato predefinito (bootstrap/material lo impostano di
default sull'--bxsites-accent proprio del tema; tailwind usa una
coppia dedicata verde acqua/menta dato che non ha un unico token di
accento condiviso), --bxsites-step-line è la linea di collegamento tra
i passi, e le coppie -success/-warning/-danger supportano
l'attributo opzionale color="..." di un passo - a differenza del
marcatore predefinito, queste tre sono la stessa coppia fissa di
sfondo/testo sia in modalità chiara sia scura (un badge autonomo, non
legato all'accento del brand del tema), quindi non c'è alcuna
sovrascrittura [data-theme="dark"] da ridichiarare:
:root {
--bxsites-step-marker-bg: #7C3AED;
--bxsites-step-marker-text: #fff;
--bxsites-step-success-bg: #059669;
--bxsites-step-success-text: #fff;
}
[data-theme="dark"] {
--bxsites-step-marker-bg: #C4B5FD;
--bxsites-step-marker-text: #1b1f21;
}
Banner hero della homepage
Ogni tema integrato include CSS per un banner homepage a larghezza
intera con un'immagine principale e pulsanti di call-to-action - il
proprio docs/index.md di questo stesso sito lo usa. Non c'è alcun
blocco di direttiva o configurazione per questo, solo puro HTML che
qualsiasi pagina può inserire (una homepage è solo una pagina normale,
order: 1 o comunque la prima nella nav):
<div class="bxsites-hero">
<img class="bxsites-hero__banner" src="assets/home-banner.jpg" alt="...">
<div class="bxsites-hero__actions">
<a class="bxsites-hero__btn bxsites-hero__btn--primary" href="getting-started.md">Get Started</a>
<a class="bxsites-hero__btn bxsites-hero__btn--secondary" href="https://github.com/your/repo">View on GitHub</a>
</div>
</div>
bxsites-hero__btn--primary/--secondary sono gli stessi due stili di
accento che ogni tema usa già altrove - scambia, rimuovi o aggiungi
pulsanti liberamente, e ridimensiona/sostituisci l'immagine propria di
bxsites-hero__banner tramite un src relativo a docs/assets/ nello
stesso modo in cui si risolve qualsiasi altra immagine.
Sovrascrivere un tema
Metti il tuo layout.bxm + page.bxm (e opzionalmente search.bxm /
assets/) in una cartella .theme/ dentro la content root del tuo
progetto - docs/.theme/, src/.theme/, oppure <contentRoot>/.theme/
per qualunque cosa risolva source (vedi
Origine del contenuto), non alla radice nuda del
progetto. BxSites preferisce una sovrascrittura .theme/ a livello di
content root sia rispetto a un tema .themes/<name>/ installato sia
rispetto a qualsiasi tema integrato, purché soddisfi il contratto sopra
descritto - i temi integrati sotto resources/themes/ proprio di questo
modulo sono un buon punto di partenza da copiare e adattare. Ordine di
risoluzione completo: .theme/ (questa sezione) ->
.themes/theme.name/ (un tema installato,
se theme.name corrisponde a uno) -> un tema integrato chiamato
theme.name.
Un esempio pratico - parti da bootstrap e sostituisci la sua palette del
brand e il font delle intestazioni con i tuoi, mantenendo tutto il resto
(nav, ricerca, modalità scura, evidenziazione del codice, ...) esattamente
come già funziona:
my-project/
├── bxsites.yaml
└── docs/
├── index.md
└── .theme/ ← sovrascrittura a livello di content root, verificata prima di qualsiasi tema integrato
├── layout.bxm ← copiato da resources/themes/bootstrap/layout.bxm
├── page.bxm ← copiato da resources/themes/bootstrap/page.bxm, invariato
├── search.bxm ← copiato invariato
└── assets/
└── style.css ← copiato da assets/style.css di bootstrap, poi modificato
- Copia i tre file
.bxmeassets/style.cssdaresources/themes/bootstrap/di questo modulo neldocs/.theme/del tuo progetto (oppuresrc/.theme/, oppure<contentRoot>/.theme/, a seconda di dove si trova davvero la tua content root). - Modifica solo ciò che serve cambiare. Per sostituire la palette del
brand e il font, basta agire sulla parte iniziale di
.theme/assets/style.css:
:root {
--bxsites-gradient-start: #7C3AED; /* era #00FF78 */
--bxsites-gradient-end: #DB2777; /* era #00DBFF */
--bxsites-accent: #FBBF24; /* era #FFF500 */
}
body {
font-family: "Inter", system-ui, sans-serif; /* era "Poppins" */
}
- Esegui
bxSites build(oservementre iteri) - BX Sites recepisce.theme/automaticamente, nessuna modifica abxsites.yamlnecessaria (una cartella.theme/a livello di content root ha sempre la precedenza sul tema integrato nominato intheme.name). Tutto ciò che non hai toccato - rendering della nav, ricerca, interruttore modalità scura, annotazioni del codice - continua a funzionare esattamente come nel temabootstraporiginale, dato che è sempre lo stesso identico markuplayout.bxm/page.bxmsottostante.
Una cartella .theme/ di progetto è comunque tutto-o-niente - una volta
che BxSites ne trova una, viene usata al posto del tema integrato per
intero, quindi necessita comunque del proprio layout.bxm + page.bxm
anche se l'unica cosa cambiata è assets/style.css (una cartella priva
di uno dei due file fallisce subito con BxSites.InvalidTheme invece di
ricadere silenziosamente su un altro tema). Per una modifica solo CSS
senza .bxm, usa
extraCss come
sopra invece - si sovrappone a qualunque tema bxsites.yaml nomini,
senza alcuna cartella .theme/ coinvolta. .theme/ serve per quando
devi anche cambiare il markup stesso, argomento trattato di seguito.
Sovrascritture del progetto
Una cartella .theme/ sostituisce un tema per intero. Per cambiare solo
poche cose e mantenere tutto il resto, inclusi i futuri aggiornamenti del
tema, metti invece le modifiche in .overrides/<theme>/ dentro la content
root. <theme> è lo slug del tema, il valore di theme.name:
docs/
└── .overrides/
└── bootstrap/ ← si applica solo mentre theme.name è bootstrap
├── home.bxm ← un layout, usato da `layout: home`
├── page.bxm ← sostituisce il page.bxm del tema
├── assets/
│ └── logo.svg ← sostituisce (o aggiunge) un asset del tema
└── slots/
└── footer.bxm ← riempie lo slot `footer` del tema
Ogni file in .overrides/<theme>/ viene sovrapposto al tema: un file con lo
stesso nome sostituisce quello del tema, qualsiasi altro viene aggiunto. Il
tema non viene mai modificato. Al momento del build il risultato viene unito
in .cache/theme/<theme>/ (rimossa da bxSites clean), ed è quella cartella
unita a essere renderizzata, quindi themeAssetUrl(), gli include e il
fingerprinting funzionano come per un tema semplice.
- Cambiare tema cambia anche le sovrascritture. Un build con
materialignora.overrides/bootstrap/; dagli il suo.overrides/material/. - Il nome di un tema deve essere uno slug: lettere minuscole, cifre e
trattini, il valore che
slugify()di BoxLang restituisce per esso (altrimentibxSitesfallisce con un suggerimento). Dà il nome alla cartella del tema, alla sua installazione.themes/<slug>/e alla sua cartella.overrides/<slug>/. - Ordine di risoluzione per qualsiasi file: un
.theme/piatto completo (se il progetto ne ha uno vince in modo assoluto), poi.overrides/<theme>/, poi un.themes/<theme>/installato, poi il tema integrato. .overrides/è una cartella con il punto, quindi non viene mai pubblicata come pagine.
bxSites layout:new <name> genera un layout in questa cartella.
Slot
Uno slot è un buco con nome nel layout.bxm di un tema che un progetto può
riempire senza copiare il layout. Crea slots/<name>.bxm nella cartella
delle sovrascritture:
<bx:output>
<div class="alert alert-info text-center mb-0">
v1.0 is out. <a href="#variables.basePath#releases/1.0.md">Read the notes</a>
</div>
</bx:output>
Ogni tema integrato espone gli stessi cinque slot:
| Slot | Dove viene renderizzato | Predefinito del tema |
|---|---|---|
head-extra | Subito prima di </head>: <meta>, <link> e script extra | vuoto |
announcement-bar | Subito dopo <body>, sopra l'header | vuoto |
header | La barra di navigazione in alto | l'header proprio del tema |
footer | Il footer della pagina | il footer proprio del tema (quando footer: true) |
sidebar-bottom | Sotto l'albero di navigazione nella barra laterale | vuoto |
- Una sovrascrittura sostituisce il predefinito. Per
headerefootersignifica sostituire il markup del tema; per gli altri riempie uno slot vuoto. Elimina il file per riavere il predefinito. - Un file di slot è un template. Vede le stesse variabili di un layout
(
page,nav,siteConfig,basePath,data, ...) e, comelayout.bxm, racchiude il suo markup in<bx:output>così che le#expressions#vengano renderizzate. - Un tema può esporre più slot dei cinque; il suo manifesto li elenca.
- Un nome di slot che il tema non espone stampa un avviso di build e viene ignorato. Non fa mai fallire il build, quindi cambiare tema è sicuro.
Renderizzare uno slot dal tuo layout:
#renderSlot( "footer" )#
Manifesto del tema (theme.json)
Un file opzionale alla radice della cartella di un tema. Tutti e 10 i temi integrati ne includono uno.
{
"slug": "bootstrap",
"name": "Bootstrap",
"slots": ["head-extra", "announcement-bar", "header", "footer", "sidebar-bottom"]
}
slugdeve essere uguale al nome della cartella del tema; una discrepanza fa fallire il build conBxSites.InvalidTheme.slotselenca i nomi degli slot che il layout del tema renderizza, ognuno con lettere minuscole, cifre e trattini. Con un manifesto, una chiamata arenderSlot()per un nome non elencato e un file di slot di sovrascrittura che il tema non espone stampano entrambi un avviso.- Senza un manifesto un tema funziona come prima; i nomi degli slot non vengono controllati.
Layout impliciti
Invece di ripetere layout: landing nel frontmatter di ogni pagina,
assegna un layout a un insieme di pagine per percorso in bxsites.yaml.
Funziona come i layout impliciti di ColdBox.
layouts:
- layout: landing
match: ["marketing/**", "pricing.md"]
- layout: post
match: "blog/posts/**"
layoutè un nome di template semplice, risolto come unlayout:del frontmatter (.overrides/<theme>/<name>.bxm, poi quello del tema, poi il predefinito).matchè un glob o una lista. Le regole vengono provate in ordine e vince la prima corrispondenza.- Il frontmatter
layout:proprio di una pagina vince sempre su una regola. - I glob vengono confrontati con il percorso della pagina relativo alla
content root, con barre normali e distinguendo maiuscole e minuscole:
*è qualsiasi carattere dentro un segmento,**attraversa i segmenti (**/corrisponde anche a zero cartelle),?è un carattere, e una/finale significa tutto ciò che sta sotto quella cartella.marketing/**corrisponde amarketing/a.mdemarketing/deep/b.md, non amarketing.md. - Le regole si applicano alle pagine della documentazione e agli articoli
del blog (il percorso di un articolo è
blog/posts/<file>). Le pagine generate (elenchi del blog, tag, ricerca, 404) mantengono i propri template. - Le stesse regole si applicano negli alberi versionati e tradotti, confrontate con il percorso all'interno di quell'albero.
Scrivere un tema da zero
Un tema necessita solo dei due file obbligatori, quindi ecco un esempio
davvero minimale - niente Bootstrap/Tailwind, niente modalità scura,
niente UI di ricerca - per mostrare esattamente cosa è richiesto rispetto
a cosa aggiungono in più i temi integrati. Salva entrambi come
docs/.theme/layout.bxm e docs/.theme/page.bxm nel tuo progetto
(oppure sotto qualunque content root risolva il tuo source) - una
cartella .theme/ a livello di content root viene recepita
automaticamente (come sopra), nessuna modifica a bxsites.yaml
necessaria:
<!-- docs/.theme/layout.bxm -->
<bx:script>
function renderNav( required array nodes ) {
var html = "<ul>"
for ( var node in arguments.nodes ) {
html &= "<li>"
html &= len( node.url )
? '<a href="' & variables.basePath & node.url & '">' & encodeForHTML( node.title ) & '</a>'
: encodeForHTML( node.title )
if ( node.children.len() ) {
html &= renderNav( node.children )
}
html &= "</li>"
}
return html & "</ul>"
}
</bx:script>
<bx:output>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>#encodeForHTML( variables.page.title )# - #encodeForHTML( variables.siteConfig.name )#</title>
<link rel="stylesheet" href="#themeAssetUrl( 'style.css' )#">
</head>
<body>
<header><a href="#variables.basePath#">#encodeForHTML( variables.siteConfig.name )#</a></header>
<nav>#renderNav( variables.nav )#</nav>
<main>
</bx:output>
<bx:include template="#variables.themeDir#/#variables.bodyFile#">
<bx:output>
</main>
</body>
</html>
</bx:output>
<!-- docs/.theme/page.bxm -->
<bx:output>
<article>
<h1>#encodeForHTML( variables.page.title )#</h1>
#variables.page.contentHtml#
</article>
</bx:output>
Questo è un tema completo e funzionante -
variables.page.contentHtml è il markdown già convertito (evidenziazione
della sintassi, ammonizioni, schede, matematica e tutto il resto), quindi
non c'è più nulla da analizzare, solo da impaginare. Da qui, aggiungi
qualsiasi cosa dei temi integrati che vuoi davvero: search.bxm (incluso
solo quando search di bxsites.yaml è true - vedi Ricerca),
un interruttore modalità scura (copia la coppia x-data/x-init di
Alpine.js dal tag <body> di resources/themes/bootstrap/layout.bxm e il
blocco CSS [data-theme="dark"] corrispondente), breadcrumb/tag/link
pagina precedente-successiva (page.bxm in qualsiasi tema integrato
mostra lo schema - ognuno è solo un if intorno a una piccola funzione di
rendering, tutti guidati da campi già presenti su variables.page),
oppure una cartella assets/ per il tuo CSS/JS, copiata automaticamente
in site/assets/theme/ al momento del build.
themeAssetUrl( "style.css" ) (usato sopra, invece di un
assets/theme/style.css fisso) è ciò che fa sì che il CSS proprio del
tuo tema adotti l'
impronta digitale basata sull'hash del contenuto -
assets.fingerprint (attivo per impostazione predefinita) significa che
ogni modifica che apporti a quel file ottiene un nuovo nome al build
successivo, così i browser dei visitatori non servono mai una copia
obsoleta dalla cache. Funziona allo stesso modo per qualsiasi file CSS o
JS di primo livello nella cartella assets/ propria del tuo tema, non
solo per style.css - un tema con un proprio assets/main.js lo
collega allo stesso modo:
<script src="themeAssetUrl( 'main.js' )"></script>.
moduleAssetUrl( "copy-code.js" ) è lo stesso helper per gli script
condivisi e indipendenti dal tema propri di questo modulo (quelli che il
layout.bxm proprio di ogni tema integrato collega tramite
variables.moduleAssetsDir) - usalo al posto di un
assets/copy-code.js fisso se il tuo tema ne collega uno direttamente.
Entrambi gli helper assegnano l'impronta digitale solo a un file che si
trova direttamente dentro quella cartella - mai a uno annidato in una
sottocartella (una tua assets/fonts/ o assets/vendor/, ad esempio).
È una scelta deliberata: un file referenziato indirettamente da uno
dei tuoi file di primo livello (un @font-face url(...), un @import
CSS) si romperebbe se rinominato senza riscrivere anche ogni punto che
vi fa riferimento con il vecchio nome, quindi questo non tocca mai quei
file. Chiamare uno dei due helper su un file che non esiste ancora,
oppure con assets.fingerprint disattivato, ricade esattamente
sull'attuale percorso fisso - mai su un errore.
Qualsiasi .bxm (integrato o personalizzato) che fissa un percorso
semplice invece di chiamare uno di questi due helper non si romperà, ma
non invaliderà automaticamente la cache - e un build ora stampa un
avviso non fatale di una riga che nomina il file quando rileva esattamente
questo, così un tema come questo non diventa obsoleto in silenzio.