From 13fdc074e8dd03d48809502345669bf2dfc06903 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 16:38:28 +0000 Subject: [PATCH 1/3] feat: add JupyterLite in-browser demo sub-site (spec 049, closes #21) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Publishes a self-contained JupyterLite site at /jupyterlite/ alongside the frozen playground. One example notebook (demo.ipynb) loads a light sample CSV of European capital city data and renders three matplotlib figures inline — entirely in the browser via Pyodide, no server or account needed. Changes: - jupyterlite/: new demo source directory with pinned requirements.txt (jupyterlite-core==0.8.0, jupyterlite-pyodide-kernel==0.8.1), build and runtime configs, sample dataset, and example notebook - .github/workflows/deploy.yml: additive JupyterLite build step after the existing IDE copy; publishes to _site/jupyterlite/ - .github/workflows/pr-preview.yml: same additive step with PR-scoped base URL; preview comment now lists /jupyterlite/ URL - web/index.html: visible "JupyterLite demo" card link added - .specify/memory/constitution.md: amendment v2.2.0 — JupyterLite demo bullet added to Technology Constraints (new infrastructural dependency) - README.md: demo pin rows added to Pinned versions table - docs/limitations.md: online-only, cold-load, and separate-pin entries Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_011jxCebZyA1CpyG5KL3eh5j --- .github/workflows/deploy.yml | 28 +++- .github/workflows/pr-preview.yml | 25 ++- .gitignore | 1 + .specify/memory/constitution.md | 42 ++++- README.md | 3 + docs/limitations.md | 35 ++++ jupyterlite/.gitignore | 4 + jupyterlite/README.md | 82 +++++++++ jupyterlite/files/data/sample.csv | 31 ++++ jupyterlite/files/demo.ipynb | 237 +++++++++++++++++++++++++++ jupyterlite/jupyter-lite.json | 11 ++ jupyterlite/jupyter_lite_config.json | 5 + jupyterlite/requirements.txt | 2 + specs/049-jupyterlite-demo/tasks.md | 40 ++--- web/index.html | 9 + 15 files changed, 531 insertions(+), 24 deletions(-) create mode 100644 jupyterlite/.gitignore create mode 100644 jupyterlite/README.md create mode 100644 jupyterlite/files/data/sample.csv create mode 100644 jupyterlite/files/demo.ipynb create mode 100644 jupyterlite/jupyter-lite.json create mode 100644 jupyterlite/jupyter_lite_config.json create mode 100644 jupyterlite/requirements.txt diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8c73855..7cd30d3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,6 +9,7 @@ on: # / → static welcome page (web/index.html) # /slides/ → reveal.js findings deck (web/slides/) # /playground/ → the Vite IDE app (built with a matching base path) +# /jupyterlite/ → JupyterLite in-browser demo (jupyter lite build) # /sample-package/ → lesson 8's self-hosted Data Package (kept at root # so the URL hard-coded in lesson 8 stays valid) # PR previews (see pr-preview.yml) live under `/pr-preview/pr-N/` of the @@ -59,7 +60,29 @@ jobs: VITE_BASE_PATH: /tabular-data-playground/playground/ run: pnpm run build - - name: Assemble published site (welcome + slides + IDE + sample-package) + - name: Set up Python for JupyterLite build + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install JupyterLite build dependencies + working-directory: ${{ github.workspace }} + run: pip install -r jupyterlite/requirements.txt + + - name: Build JupyterLite demo (served under /jupyterlite/) + working-directory: ${{ github.workspace }} + run: | + jupyter lite build \ + --config jupyterlite/jupyter_lite_config.json \ + --output-dir jupyterlite/_output \ + --base-url /tabular-data-playground/jupyterlite/ + + - name: Verify JupyterLite build produced output + working-directory: ${{ github.workspace }} + run: | + test -d jupyterlite/_output && test -n "$(ls -A jupyterlite/_output)" + + - name: Assemble published site (welcome + slides + IDE + jupyterlite + sample-package) working-directory: ${{ github.workspace }} run: | set -e @@ -70,6 +93,9 @@ jobs: # IDE under /playground/ mkdir -p _site/playground cp -r app/dist/. _site/playground/ + # JupyterLite demo under /jupyterlite/ + mkdir -p _site/jupyterlite + cp -r jupyterlite/_output/. _site/jupyterlite/ # Keep the lesson-8 sample package at the gh-pages root if [ -d _site/playground/sample-package ]; then rm -rf _site/sample-package diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index ebc0b88..6729925 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -6,6 +6,7 @@ name: PR Preview to GitHub Pages # /pr-preview/pr-/ → welcome page (web/index.html) # /pr-preview/pr-/slides/ → reveal.js findings deck # /pr-preview/pr-/playground/ → the Vite IDE (PR-scoped base path) +# /pr-preview/pr-/jupyterlite/ → JupyterLite demo (PR-scoped base path) # /pr-preview/pr-/sample-package/ → lesson 8's package, kept at the # preview root to mirror production # A single sticky comment (idempotent via the marker below) links to @@ -62,7 +63,26 @@ jobs: VITE_BASE_PATH: /tabular-data-playground/pr-preview/pr-${{ github.event.pull_request.number }}/playground/ run: pnpm run build - - name: Assemble preview site (welcome + slides + IDE + sample-package) + - name: Set up Python for JupyterLite build + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install JupyterLite build dependencies + run: pip install -r jupyterlite/requirements.txt + + - name: Build JupyterLite demo with PR-scoped base path + run: | + jupyter lite build \ + --config jupyterlite/jupyter_lite_config.json \ + --output-dir jupyterlite/_output \ + --base-url /tabular-data-playground/pr-preview/pr-${{ github.event.pull_request.number }}/jupyterlite/ + + - name: Verify JupyterLite build produced output + run: | + test -d jupyterlite/_output && test -n "$(ls -A jupyterlite/_output)" + + - name: Assemble preview site (welcome + slides + IDE + jupyterlite + sample-package) run: | set -e rm -rf _site @@ -70,6 +90,8 @@ jobs: cp -r web/. _site/ mkdir -p _site/playground cp -r app/dist/. _site/playground/ + mkdir -p _site/jupyterlite + cp -r jupyterlite/_output/. _site/jupyterlite/ if [ -d _site/playground/sample-package ]; then rm -rf _site/sample-package mv _site/playground/sample-package _site/sample-package @@ -103,6 +125,7 @@ jobs: `- Welcome page: ${base}`, `- Findings slides: ${base}slides/`, `- IDE: ${base}playground/`, + `- JupyterLite demo: ${base}jupyterlite/`, '', `Built from \`${sha}\`. Updates on every push to this PR; removed when the PR closes.`, ].join('\n'); diff --git a/.gitignore b/.gitignore index 5c50aa9..eb9fe29 100644 --- a/.gitignore +++ b/.gitignore @@ -145,3 +145,4 @@ vite.config.ts.timestamp-* # Claude Code local/user-specific artifacts (skills under .claude/skills/ are tracked) .claude/settings.local.json .claude/.credentials.json +.jupyterlite.doit.db diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index cc8d44b..bb61eb9 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,6 +1,37 @@ + +