Skip to content

feat: multi-volume, navbar redesign, PyRunner v1#1

Merged
marcofarina merged 15 commits into
mainfrom
fix/pyrunner-security
May 28, 2026
Merged

feat: multi-volume, navbar redesign, PyRunner v1#1
marcofarina merged 15 commits into
mainfrom
fix/pyrunner-security

Conversation

@marcofarina
Copy link
Copy Markdown
Owner

Summary

Bundle ampio che chiude tre filoni di lavoro paralleli sviluppati sullo stesso branch. Sono separati nei commit (ben distinti per topic) ma condivisi in un unico merge per evitare cherry-pick complessi tra branch che si toccano.

1. Infrastruttura multi-volume

Quattro istanze plugin-content-docs (Programmatore, Artefice, Archivista, Apprendista) con contenuti in volumes/<volume>/, sidebar dedicata per percorso (IT / Liceo / ITS), PathContext persistente in localStorage, runtime sidebar swap via swizzle DocRoot, banner inline per lezioni fuori-percorso, dropdown "Libri" in navbar, 2x2 grid in home.

Commit chiave: 2fb5cb6, 7e3a4a0, c0403bf, f725e0d, 8667e68, 1bf2800.

2. Redesign navbar

Refactoring dei link icon-only (GitHub, coffee) in componente NavbarIconButton condiviso con ColorModeToggle. Tooltip neon con caret, due varianti accent (cyan / amber). Titolo two-tone "Python doesn't byte" via swizzle Navbar/Logo. Iconografia Star Wars per il color mode toggle (Sith / Starfighter) con hover color per-button.

Commit chiave: 30cb06e, 6de090e, 9847b67, 24de645.

3. PyRunner v1 (sostituisce docusaurus-live-brython)

Componente custom Brython 3.12 + CodeMirror 6 per esecuzione Python in-pagina. Plugin Docusaurus locale (plugins/pyrunner/) con walk di static/py-examples/, remark che converte ```py live in <PyRunner code=...>, injection script Brython via injectHtmlTags. Toolbar con traffic lights stile macOS, fullscreen condizionale (visibile solo su overflow), pagina /playground, feature "Spiegamelo facile" che copia un prompt LLM in clipboard. Mitigazioni di sicurezza post-audit: SRI sui bundle CDN, cap output (1000 righe / 256 KB), banner warning su /playground?code=, rimozione ?p= per evitare clipboard-poisoning.

Cut-over completo: docusaurus-live-brython rimosso, 14 fence migrati da py live_py a py live ```. -60+ deps transitive, pulizia del dedupe @docusaurus/* 3.4.x nested.

Commit chiave: 80d57fe (PR1 scaffold), bfd87ab (PR2 fullscreen/playground/explain), 5440941 (PR3 cut-over), 749d284 (style polish), 3f57aab (security).

Test plan

  • CI verde (test-deploy.yml)
  • Smoke test post-deploy su rainbowbits.cloud/python-doesnt-byte/:
    • Home: 2x2 grid dei 4 volumi
    • Navbar: dropdown "Libri" + icon buttons (GitHub / coffee / Lumos-Nox) con tooltip neon
    • PathSelector visibile in un volume, sidebar swap funzionante
    • Off-path banner appare su /programmatore/variabili con percorso ITS attivo
    • Una lezione con py live ```` (es. basi-del-linguaggio/le-stringhe): tutti i PyRunner si caricano, esecuzione OK
    • Pulsante "Spiegamelo facile" copia il prompt corretto
    • /playground accessibile da fullscreen di un PyRunner overflowing

marcofarina and others added 15 commits May 24, 2026 19:18
Adds three new plugin-content-docs instances (Manuale del
Programmatore, dell'Artefice, dell'Archivista) alongside the
existing default docs, each with its own content folder under
docs/<volume>/, its own routeBasePath, and a sidebars/<volume>.ts
that exports one sidebar per "percorso" (IT / Liceo / ITS).
Sidebars currently reference only the placeholder intro.mdx for
each volume — real chapters come once we have UI to switch
percorso.

PathContext (src/contexts/PathContext.tsx) persists per-volume
the user's chosen path in localStorage under
pdb:path:<volumeId>, with cross-tab sync via the storage event.
The provider is wired through a Root swizzle so any component
(future navbar selector, sidebar resolver, off-path banner) can
read or update it.

Each volume has the same three placeholder paths for now; per-
volume customization happens when we wire the navbar selector.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PathSelector (src/components/PathSelector) reads the active
plugin-content-docs instance via useActivePlugin, fetches that
instance's full sidebar set via useAllDocsData (each sidebar key
= a percorso: it/liceo/its by current convention), and renders a
pill-shaped segmented control in the navbar center. Clicking
writes to PathContext + localStorage; the component hides itself
on non-volume routes (so the navbar center stays empty on the
homepage and elsewhere).

To slot it into the navbar I swizzled Navbar/Content (otherwise
the only public extension point is themeConfig.navbar.items,
which can't render arbitrary React). The original layout had
left/right slots; I added a center slot between them.

The actual sidebar swap happens in a DocRoot swizzle:
useResolvedSidebar reads useDocsVersion().docsSidebars (the full
set for the current volume) and replaces sidebarName/sidebarItems
in DocsSidebarProvider with the user's pick when one exists and
is valid. Falls back to the default Docusaurus selection for any
volume not in the registered set and for users who haven't picked
a path yet.

Verified end-to-end with a second placeholder doc
(volumes/programmatore/variabili.mdx) listed under it+liceo but
not under its: switching the selector now visibly adds/removes
the lesson from the sidebar without a reload, and the choice
persists across refreshes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When the user opens a lesson whose docId isn't present in their
chosen path's sidebar (e.g. lands on /programmatore/variabili
while on ITS, but variabili lives only in IT+Liceo), an inline
banner appears above the chapter kicker.

The banner lists the *other* paths in the same volume that DO
contain the lesson; each is rendered as an inline button that
calls setPath(volumeId, otherPath). Switching is in-place — no
navigation — so the URL stays the same, the sidebar reshuffles
to include the lesson, and the banner self-removes.

Detection lives in useOffPathInfo (src/components/OffPathBanner)
which walks each sidebar's items recursively for a docId match
(categories included). Returns null when:
- the active plugin isn't one of the three volumes
- the user has never picked a path (we don't surprise them)
- the lesson IS in the active path's sidebar

Path labels (Istituto Tecnico / Liceo / ITS) extracted to
src/contexts/pathLabels.ts and reused by both PathSelector
(short labels for the navbar pill) and the banner (full labels
for prose).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…nment fix

Banner collapsed from a two-paragraph stack (~120px tall, lots
of empty space) into a single horizontal line (~46px). Title
and detail are now one continuous sentence:

  ⓘ  Lezione fuori dal percorso [ITS] · Disponibile in [IT] · [Liceo]

- Replaced the inline SVG with FontAwesome circle-info
  (consistent with our `<FAIcon>`/`<FontAwesomeIcon>` convention)
- "passa a X" prefix dropped — under "Disponibile in:" the bare
  path name is enough and reads better
- Capitalized "Disponibile" and "Non inclusa" for sentence-case
  consistency after the · separator
- align-items: center on the flex container, but the message
  <p> wasn't centering because .theme-doc-markdown p
  (specificity 0,1,1) was adding margin-bottom 1.15em that
  inflated the banner content area and anchored the <p> to the
  top of the line. Bumped specificity with .banner > .message
  (0,2,0) to wipe the margin. Now icon-cy = msg-cy = banner-cy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the single "Libro" entry with a dropdown listing the
three volumes (Programmatore, Artefice, Archivista) plus a
"Versione precedente" entry pointing at the legacy /docs/intro
content until we migrate it into Programmatore.

Each volume entry uses type: 'doc' with docsPluginId so
Docusaurus highlights the right item when the user is inside
that plugin instance.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… grid

Adds a fourth plugin-content-docs instance (apprendista) for
exercises and lab projects, alongside the three theory volumes.
Bookkeeping spread across: VolumeId union in PathContext, the
three VOLUMES sets in PathSelector / OffPathBanner / DocRoot,
sidebars/apprendista.ts placeholder, navbar "Libri" dropdown.

Homepage hero cards go from 2 to 4 in a natural 2x2 grid
(existing CSS already used grid-template-columns: 1fr 1fr):
Programmatore (blue), Artefice (pink), Archivista (amber),
Apprendista (green). Added two new VolumeCard accent palettes
(amber + green) plus two inline SVG icons (database, flask).
Card targets switch from legacy /docs/ URLs to the new volume
roots.

Naming note: "Biblioteca" not "Manuale" because the fourth
volume is a curated collection of practice material, not a
linear didactic narrative like the other three.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Title: "Python doesn't byte" rendered as two spans via a
Navbar/Logo swizzle. "Python" is fg-strong, "doesn't byte" is
muted italic in Crimson Pro, matching the design's navbar
treatment (which inspired the homepage hero word split).

Icons: both .github-link and .sponsorship-link now use a
mask-image + background-color: currentColor pattern instead of
hardcoded SVG fills. This means the icon color follows the link
color (and any :hover/light/dark variant) without needing a
separate SVG per state. GitHub previously turned green on hover
because the hover SVG had a baked-in #25c2a0 fill; now both
icons fade to var(--at-accent) on hover via a plain CSS color
transition.

Replaced the heart icon (Support sponsorship link) with a
coffee-mug glyph (Lucide style) and renamed the navbar entry
"Support" → "Offrimi un caffè".

Removed the Rainbow Bits navbar entry and the unused
.rainbowbits-link + .designedBy/.heart CSS leftovers from the
Docusaurus template.

Removed the "Versione precedente" entry from the Libri dropdown
— the legacy /docs/ content stays reachable by direct URL and
via the footer until we migrate it into Programmatore.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GitHub and "Offrimi un caffè" navbar links rebuilt to match the
ColorModeToggle visually: 2rem round buttons with just the icon
glyph, label collapsed via font-size: 0 (kept in DOM + aria-label
for SR). Hover paints a soft bg and tints the icon accent.

On hover/focus the link's ::after expands into a neon popup
tooltip with the human label — the same Lumos/Nox treatment:

  GitHub          → cyan (matches our default accent)
  Offrimi un caffè → warm amber/brown (#c8845c border,
                     #f0b072 text, brown box-shadow)

Specificity quirk: .navbar__link sits later in the file and was
overriding .github-link's font-size: 0. Bumped to
.navbar__link.github-link (0,2,0) so the icon-only collapse
actually wins.

Added aria-label to the sponsorship navbar item too (GitHub
already had one) so screen readers still announce both even with
visible text hidden.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GitHub and "Offrimi un caffè" rebuilt as a shared React component
(NavbarIconButton) instead of CSS-only ::before/::after on
config-driven navbar items. This gives them the same DOM shape
as ColorModeToggle — round 2rem button + FontAwesomeIcon + a
proper tooltip <span> with two pseudo-element carets (border
color + bg color stacked) pointing at the icon.

Tooltips now have the same upward caret as Lumos/Nox; the
previous CSS-only ::after approach couldn't draw an arrow
outside its own box without ugly tricks. Two accent variants:
cyan (`--at-accent` family) for GitHub, amber/brown for the
coffee button (#c8845c border, #f0b072 text, warm box-shadow).

ColorModeToggle switched from Docusaurus' IconLightMode /
IconDarkMode / IconSystemColorMode to FontAwesome sun / moon /
circle-half-stroke at 18px — same family + sizing as the new
buttons, so all four icons in the navbar right rail look
unified. mug-hot is rendered at 20px because the steam puffs
push it visually smaller otherwise.

FontAwesome library.add(fab, fas) moved from MDXComponents.tsx
(which is only loaded on MDX-rendered routes) to Root.tsx so
non-MDX pages like the homepage get the icons registered.

GitHub and sponsorship links removed from
themeConfig.navbar.items — they're rendered directly by the
Navbar/Content swizzle now. Old per-class CSS in custom.css
(mask SVGs + ::after tooltips) deleted.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three SVGs (starfighter, user-sith, mug-saucer) copied from
static/img/icons/ into src/icons/ so Docusaurus' @svgr/webpack
imports them as React components with currentColor support.
Static copies stay in place for any future <img src=...> use.

ColorModeToggle: FA sun/moon swapped for Sith (shown in light
mode, click → dark) / Starfighter (shown in dark mode, click →
light). The icon represents the *destination* of the click, not
the current state — same affordance as the tooltip text. Lumos
→ "Light side" (cyan), Nox → "Dark side" (red lightsaber palette
replaces the old magenta).

Hover color on the toggle now follows data-next-mode: cyan when
next is light, red when next is dark, matching the tooltip
palette.

NavbarIconButton: `icon` prop relaxed from FA IconProp to
ReactNode so callers can pass either a FontAwesomeIcon or an
imported SVG component. Coffee button switched to mug-saucer
(Pro SVG); GitHub keeps the FA brand glyph. Dropped the
iconSize prop — all icons rendered at a uniform 20×20 via CSS
on .icon and .icon > svg. Added a 'red' accent variant.

Default icon color is var(--at-muted) on all four buttons;
hover paints it with the variant's accent (cyan / amber / red).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sostituisce gradualmente docusaurus-live-brython con un PyRunner custom basato
su Brython + CodeMirror 6, integrato nei 4 plugin docs (default + 3 volumi) via
remark che converte i fence ```py live``` in <PyRunner code=...>.

Componenti principali:
- plugins/pyrunner: walk dei .py in static/py-examples/, setGlobalData, watch,
  hook injectHtmlTags gated da skipScriptInjection (true in PR1 per convivere
  con docusaurus-live-brython, da rimuovere in PR2).
- plugins/pyrunner/remark.js: trasforma py live in JSX, parsing meta booleani
  e key=value (readonly, title, maxLines).
- src/pyBoot.ts: client module idempotente che inizializza __BRYTHON__.
- src/theme/PyRunner: Editor (CodeMirror 6, theme Atmospheric), Output con
  stdout/stderr separati, Toolbar con run/reset/copy/traffic lights stile macOS,
  bridge eventi bry_notify ↔ React.
- docs/pyrunner-test.mdx (unlisted): sandbox con 7 casi di test.

Pol di UX al primo passaggio:
- copy button con animazione check (replica del CodeBlock Docusaurus, riusa
  @theme/Icon/Copy + @theme/Icon/Success per coerenza visiva).
- font code ridotto a 0.85rem (assoluto) → più piccolo del testo normale.
- font output alzato a 0.92rem per leggibilità.
- placeholder "Esegui" sostituito con chip che riprende i token del pulsante run.

Bug fix scoperti testando in browser:
- bryBridge: id del div di output allineato a Config.OUTPUT_DIV
  (${codeId}_brython_result, non ${codeId}_output) — sbloccava ogni esecuzione.
- bryBridge: \n di sicurezza prima della chiusura del triple-quote del wrapper,
  altrimenti codice che termina con `"` produceva SyntaxError.
- Editor: per il flag readonly servono EditorState.readOnly + EditorView.editable
  insieme — il primo da solo non disabilita contenteditable.
- Output: setStatus('error') al primo stderr (in Brython lo stderr è proxy
  affidabile dell'eccezione).
- styles: .outputBody non più flex column per evitare doppia spaziatura dopo
  i \n di print, header allineato con line-height: 1 + align-self center.

Codemirror 6 aggiunto come dipendenza diretta (commands, lang-python, language,
state, view). docusaurus-live-brython resta in themes finché non parte PR2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tre nuove feature del PyRunner (step 10-11 della roadmap §13 + nuova pagina
playground), tutte sotto BrowserOnly e senza dipendenze extra runtime.

Fullscreen condizionale
- ResizeObserver sul wrapper editor (+ .cm-scroller interno) → state
  `overflowing` aggiornato a ogni resize/cambio codice.
- Bottone faExpand in toolbar visibile solo se overflowing (rispetta la
  decisione §14 punto 7: no opt-in esplicito, solo quando serve).
- onClick apre /playground in nuovo tab. Se l'utente non ha editato e c'è
  un `src`, l'URL usa `?src=` (corto, riusa globalData del plugin);
  altrimenti `?code=<base64url>` con encoding UTF-8-safe via TextEncoder
  (gestisce accentate italiane). `?title=` + `?p=` (prompt) opzionali.

Pagina /playground
- src/pages/playground.tsx + .module.css: PyRunner embedded a
  calc(100vh - navbar), noFooter.
- Lazy useState init che decodifica i query params (sotto BrowserOnly,
  quindi window è disponibile). Empty state per visita diretta senza
  parametri.
- Nuova prop `embedded` del PyRunner: rimuove margin/border-radius,
  flex column full-height, max-height dell'output spostato a 38vh.
  In embedded mode il bottone fullscreen è sempre nascosto.

"Spiegamelo facile"
- Nuovo modulo share.ts con encode/decode base64url + DEFAULT_EXPLAIN_PROMPT
  + buildExplainText (placeholder `{code}`, `{contextTitle}`).
- Bottone faWandMagicSparkles in toolbar (accent-colored), visibile per
  default, nascosto con prop `noExplain`.
- Click → copia in clipboard via navigator.clipboard con fallback
  copy-text-to-clipboard. Toast non-bloccante (2s, animazione pyrToast)
  in alto a destra del runner.
- `{contextTitle}` da document.title strippato del suffisso "| <siteTitle>"
  che Docusaurus aggiunge automaticamente.
- Prop `explainPrompt` per template custom per-lezione (es. cicli for,
  list comprehension): override completo con stessi placeholder.

Sanitizzazione hooks
- PR1 aveva 17 occorrenze di hooks-after-conditional-return
  (react-hooks/rules-of-hooks): spostata l'early return su !data sotto
  tutti gli hook, accessi via `data?.libUrl ?? ''` ecc. Niente comportamento
  cambiato, lint pulito sui file toccati.

Sandbox
- docs/pyrunner-test.mdx: 4 nuovi casi (§8-11): default explain, custom
  explainPrompt, noExplain, fullscreen forzato con maxLines=3.

Verifica in Chrome
- /playground apre, decodifica `?code=`, esegue codice live, rende empty
  state senza params.
- Fullscreen visibile solo dove c'è overflow (§7, §11); assente altrove.
- Clipboard intercettata con writeText hook: contiene il template con
  `{code}` e `{contextTitle}` risolti. Override custom (§9) funzionante.
- `noExplain` (§10) nasconde il bottone wand come atteso.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…(PR3)

Cut-over completo dal plugin upstream al PyRunner custom. Chiude la roadmap
§13 step 12-14 del piano in .claude/PLAN-pyrunner.md.

Migrazione fence
- 14 occorrenze ```py live_py``` → ```py live``` in:
  docs/basi-del-linguaggio/{le-variabili, le-stringhe, input, output}.mdx
  (sed in-place, allineato al meta nuovo che il remark di pyrunner riconosce).

Rimozione docusaurus-live-brython
- docusaurus.config.ts: rimosso `themes: ['docusaurus-live-brython']`. Il
  plugin pyrunner ora inietta da solo gli script Brython (`brython.min.js`
  + `brython_stdlib.js` da jsdelivr CDN) tramite il suo `injectHtmlTags`.
- Rimossa l'opzione `skipScriptInjection: true` dal config: era un
  workaround di convivenza per PR1, ora il default (false) è quello giusto.
  Aggiornato il commento in plugins/pyrunner/index.js per riflettere il
  nuovo ruolo generale (passare a true solo se un altro plugin inietta
  già gli script, niente più riferimenti a PR2/upstream).
- `npm uninstall docusaurus-live-brython` → -2 deps dirette + 60+ deps
  transitive (incluso il bundle nested di @docusaurus/* 3.4.0 che era il
  motivo principale dietro la decisione di sostituire — ora il dedupe è
  pulito).

Verifica
- npm run build: OK (server 4.6s, client 8.7s).
- /docs/basi-del-linguaggio/le-stringhe (7 fence migrati): tutti i 7
  PyRunner renderizzano, Brython scripts iniettati una sola volta,
  esecuzione del primo runner "Completato in 650 ms" output corretto.

CLAUDE.md + ROADMAP
- CLAUDE.md: aggiornata sezione dipendenze (PyRunner custom + CodeMirror 6
  + copy-text-to-clipboard al posto di docusaurus-live-brython), directory
  structure (plugins/pyrunner/, src/pages/playground.tsx, src/pyBoot.ts,
  static/py-examples/), config highlights (plugin pyrunner + 4 docs-content),
  conventions MDX (sintassi ```py live``` con i nuovi meta), security audit
  rivista 2026-05-27 (41→41 advisories, ma niente più copie nested di
  @docusaurus/* da fork upstream).
- .claude/ROADMAP.md: PR1/PR2/PR3 marcate completate con ref commit
  (80d57fe, bfd87ab, current); cancellato il TODO "verificare
  compatibilità con docusaurus-live-brython" (N/A ora).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- statusDot allineato al centro ottico delle uppercase (top: -1px)
- font-size editor 0.85rem → 1.05rem; --ifm-code-font-size 95% → 80%
  (entrambi convergono a ~16.8px)
- palette --py-* spostata in custom.css come globale, allineata a
  Prism Github (light) e Dracula (dark); rimossi gli override locali
  su .runner
- commenti in CodeMirror ora in Monaspace Radon (come nei code-block)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- SRI sha384 sui bundle Brython da jsdelivr (CDN compromise/MITM backstop)
- Banner di warning su /playground?code= per codice da link non fidati
- Cap su output (1000 righe / 256 KB) contro DoS lato client da loop infiniti
- Rimosso ?p= da /playground per evitare clipboard-poisoning del prompt
  "Spiegamelo facile" via URL condivisa
- Assert difensivo sul formato di codeId prima dell'interpolazione nel
  template Python eseguito via __BRYTHON__.runPythonSource
- Rename sanitizePyScript → escapeForTripleQuote con commento che chiarisce
  che non è un security boundary (l'exec è by design)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Large bundle that merges three parallel workstreams onto a single branch: a multi-volume docs infrastructure (4 plugin-content-docs instances with per-path sidebars and a persisted PathContext), a navbar redesign (shared NavbarIconButton, two-tone logo via Navbar/Logo swizzle, Star Wars-themed color mode toggle), and a custom PyRunner v1 component (Brython 3.12 + CodeMirror 6) that replaces docusaurus-live-brython, plus a local Docusaurus plugin, a /playground page, and migrations of existing py live_py fences to py live.

Changes:

  • New multi-volume docs (volumes/<vol>/, sidebars/<vol>.ts), PathContext + PathSelector + OffPathBanner + DocRoot swizzle.
  • Navbar redesign: NavbarIconButton, swizzles for Navbar/Logo, Navbar/Content, ColorModeToggle; new SVG icons; large CSS cleanup in custom.css.
  • PyRunner stack: plugins/pyrunner/ (loader + remark + script injection with SRI), src/theme/PyRunner/ (Editor, Toolbar, Output, bryBridge, share), src/pyBoot.ts, /playground page; cut-over of 14 live_pylive fences and removal of docusaurus-live-brython dep.

Reviewed changes

Copilot reviewed 53 out of 61 changed files in this pull request and generated no comments.

Show a summary per file
File Description
volumes/{programmatore,artefice,archivista,apprendista}/*.mdx Placeholder intro/lessons for new volumes
sidebars/{programmatore,artefice,archivista,apprendista}.ts Per-path sidebars (it/liceo/its) per volume
src/contexts/PathContext.tsx, pathLabels.ts localStorage-backed selected-path state, cross-tab sync
src/components/PathSelector/* Segmented control shown only inside a volume
src/components/OffPathBanner/* Notice when current doc is not in the selected path
src/components/VolumeCard/index.tsx Added amber/green accents for new volume cards
src/components/NavbarIconButton/* Shared icon button with neon tooltip (cyan/amber/red)
src/theme/Root.tsx Registers FA library + injects PathProvider
src/theme/Navbar/Logo/, Navbar/Content/, ColorModeToggle/* Swizzles for two-tone title, PathSelector slot, icon buttons, Sith/Starfighter icons
src/theme/DocRoot/index.tsx Swaps sidebar at render time based on PathContext
src/theme/DocItem/Content/index.tsx Renders <OffPathBanner/> at top of doc content
src/theme/MDXComponents.tsx Registers PyRunner as MDX global
src/theme/PyRunner/* Custom Brython + CodeMirror 6 runner (Editor, Toolbar, Output, bryBridge, share, types, styles)
src/pyBoot.ts One-shot Brython bootstrap (idempotent, timeout)
src/pages/playground.tsx + .module.css Fullscreen playground page with untrusted-URL warning
src/pages/index.tsx Home now has 2x2 volume grid
src/css/custom.css Removed legacy header-icon CSS; added Prism-matched --py-* palette
src/icons/.svg, static/img/icons/.svg New Sith/Starfighter/mug-saucer/code-branch/github icons
static/py-examples/_test/{hello,somma}.py Test fixtures for PyRunner src= and ### PRE/POST
plugins/pyrunner/{index.js,remark.js,package.json} Local Docusaurus plugin: walks .py examples, injects Brython scripts with SRI, transforms ```py live into <PyRunner>
docusaurus.config.ts Registers 4 docs plugin instances + pyrunner; navbar dropdown for "Libri"; drops themes: ['docusaurus-live-brython']
package.json Adds CodeMirror 6 deps; removes docusaurus-live-brython
docs/pyrunner-test.mdx Unlisted sandbox page for PyRunner verification
docs/basi-del-linguaggio/{output,le-variabili,le-stringhe,input}.mdx Migrate py live_pypy live fences

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@marcofarina marcofarina merged commit f8b6e51 into main May 28, 2026
2 checks passed
@marcofarina marcofarina deleted the fix/pyrunner-security branch May 28, 2026 03:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants