diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..44e9bc3 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,45 @@ +name: Deploy site to GitHub Pages + +on: + push: + branches: [main] + paths: + - "site/**" + - ".github/workflows/pages.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + name: Build Pages artifact + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Configure Pages + uses: actions/configure-pages@v5 + + - name: Upload site/ as Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: site + + deploy: + name: Deploy to GitHub Pages + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index 6a067eb..05cf4be 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,10 @@ Lessons, an interactive code lab, and an AI mentor — powered by a local LLM Python, write code, get feedback. Your code and your questions never leave the laptop. +> **Start here:** — the +> project's GitHub Pages start page with the three-command install and a +> 30-second visual tour. Source for the page lives in [`site/`](site/). + ``` ┌─────────────────────────────────────────────────────────┐ │ Read a lesson → Run code in the lab → Ask tutor │ @@ -41,12 +45,22 @@ laptop. --- -## Hero website +## Hero website / start page + +The project's **start page** is published on GitHub Pages: + +**** + +It's the link to share with anyone who hasn't cloned the repo yet: dark / +amber aesthetic, the local-first loop in four steps, the three-command +install with copy buttons, and links to the repo, README, and issues. + +Source lives in [`site/`](site/) and is deployed by +[`.github/workflows/pages.yml`](.github/workflows/pages.yml) on every push +to `main` that touches `site/`. The Pages workflow runs independently of +the regular CI workflow. -A small static landing page lives at [`site/`](site/) — dark / amber -aesthetic, the local-first loop in four steps, a simplified product -mockup, and links straight to the two-command install. Useful for -sharing the project without asking people to clone the repo first. +To preview locally (pure static HTML + CSS, no build step): ```bash cd site @@ -54,8 +68,7 @@ python3 -m http.server 8080 # open http://localhost:8080/ ``` -It's pure static HTML + CSS, no build step. See -[`site/README.md`](site/README.md) for what's in it and the asset layout. +See [`site/README.md`](site/README.md) for what's in it and the asset layout. --- diff --git a/scripts/check_site.sh b/scripts/check_site.sh index 380a57e..614fbf3 100755 --- a/scripts/check_site.sh +++ b/scripts/check_site.sh @@ -32,6 +32,27 @@ need 'id="screens"' need 'id="start"' ok "required and section anchors present" +# Start-page install content must be visible — this page is the entry point +# to the repo, so the clone/install/run commands have to be there literally. +need "git clone https://github.com/StewAlexander-com/python-tutor.git" +need "cd python-tutor" +need "./install.sh" +need "./run.sh --open-browser" +ok "clone / install / run commands present in start section" + +# Quick links to repo, README, and issues from the start page. +need 'href="https://github.com/StewAlexander-com/python-tutor"' +need 'href="https://github.com/StewAlexander-com/python-tutor#readme"' +need 'href="https://github.com/StewAlexander-com/python-tutor/issues"' +ok "repo / README / issues links present" + +# Copy-to-clipboard buttons should be wired to the command blocks. +need 'class="copy-btn"' +need 'data-copy-target="cmd-clone"' +need 'data-copy-target="cmd-install"' +need 'data-copy-target="cmd-run"' +ok "copy-to-clipboard buttons wired up" + # Every local href/src under site/ must resolve to a real file. # (We only check ./relative paths — external URLs are skipped.) python3 - "$HTML" "$SITE" <<'PY' @@ -66,4 +87,13 @@ closes=$(grep -c '' "$HTML" || true) [ "$opens" = "$closes" ] || fail "unbalanced
tags ($opens open, $closes close)" ok "
tags balanced" +# GitHub Pages deploy workflow must exist and reference the official actions. +PAGES_WF="$ROOT/.github/workflows/pages.yml" +[ -f "$PAGES_WF" ] || fail ".github/workflows/pages.yml missing (GitHub Pages deploy)" +grep -q "actions/configure-pages" "$PAGES_WF" || fail "pages.yml missing actions/configure-pages" +grep -q "actions/upload-pages-artifact" "$PAGES_WF" || fail "pages.yml missing actions/upload-pages-artifact" +grep -q "actions/deploy-pages" "$PAGES_WF" || fail "pages.yml missing actions/deploy-pages" +grep -q "path: site" "$PAGES_WF" || fail "pages.yml does not upload the site/ folder" +ok "GitHub Pages workflow present and references official actions" + echo "site checks passed" diff --git a/site/README.md b/site/README.md index 46204ca..da6c159 100644 --- a/site/README.md +++ b/site/README.md @@ -1,9 +1,14 @@ -# Hero website +# Hero website / start page A small static landing page for Python Tutor. It mirrors the app's dark / amber aesthetic and explains the local-first loop without needing to launch the backend. +**Published at:** + +Deployed automatically by [`.github/workflows/pages.yml`](../.github/workflows/pages.yml) +on every push to `main` that touches `site/`. + ## Files ``` diff --git a/site/index.html b/site/index.html index c1d0276..110884d 100644 --- a/site/index.html +++ b/site/index.html @@ -4,10 +4,10 @@ Python Tutor — Private Python practice with a local AI tutor - + - + @@ -16,7 +16,7 @@ - + @@ -43,7 +43,7 @@ Why How it works See it - Start + Install @@ -71,8 +71,8 @@

never leave your laptop.

- +
-

Two commands.

-

macOS or Linux. Python 3.10+.

-
-
# 1 — clone
-gh repo clone StewAlexander-com/python-tutor
-cd python-tutor
-
-# 2 — set up & serve (any host step is opt-in y/N)
-./install.sh
-./run.sh             # → http://localhost:8001/
-
-

- install.sh only touches the repo on its own. Installing - Ollama, starting the daemon, pulling the model, or launching the app - are opt-in y/N prompts — press Enter and nothing - changes on your host. +

Clone, install, run.

+

+ This page is the start page for the repo & software. Three short + commands and you're at http://localhost:8001/. + macOS or Linux. Python 3.10+.

-
+ +
    +
  1. +
    + 1 +

    Clone the repo

    +
    +

    HTTPS works without a GitHub login. gh repo clone works too if you use the GitHub CLI.

    +
    +
    git clone https://github.com/StewAlexander-com/python-tutor.git
    +cd python-tutor
    + +
    +
  2. + +
  3. +
    + 2 +

    Install

    +
    +

    + Sets up a Python venv and dependencies. Any host-level step + (Ollama install, daemon start, model pull, app launch) is an + opt-in y/N prompt — press Enter and nothing + changes on your host. +

    +
    +
    ./install.sh
    + +
    +
  4. + +
  5. +
    + 3 +

    Run & open in your browser

    +
    +

    --open-browser pops the tab once /api/health is green.

    +
    +
    ./run.sh --open-browser
    + +
    +

    + Or just ./run.sh and open http://localhost:8001/ yourself. +

    +
  6. +
+ +
+ Common variations +
+
# trusted host: install Ollama, pull model, launch — no prompts
+./install.sh --yes
+
+# CI / air-gapped: never prompt, default everything to "no"
+./install.sh --noninteractive
+
+# Python-only setup (skip every Ollama probe)
+./install.sh --skip-ollama
+
+# pick a different model or port
+./install.sh --model llama3.1:8b
+./run.sh --port 8042
+ +
+
+ +
@@ -290,5 +347,46 @@

Two commands.

MIT-licensed. Frontend adapted from Python Power User.

+ + diff --git a/site/style.css b/site/style.css index 46ac18c..f7dd7a5 100644 --- a/site/style.css +++ b/site/style.css @@ -541,6 +541,111 @@ ul, ol { margin: 0; padding: 0; list-style: none; } display: flex; gap: 12px; flex-wrap: wrap; } +/* numbered step cards */ +.start__steps { + margin-top: 28px; + display: grid; + gap: 18px; +} +.start__step { + background: var(--bg-1); + border: 1px solid var(--line-1); + border-radius: var(--r-lg); + padding: 20px 22px 22px; +} +.start__step-head { + display: flex; align-items: center; gap: 12px; + margin-bottom: 6px; +} +.start__step-num { + width: 28px; height: 28px; + display: grid; place-items: center; + border-radius: 50%; + background: var(--amber); + color: #1a1206; + font-weight: 800; font-size: 13px; + flex-shrink: 0; +} +.start__step-title { + font-size: 1.05rem; + color: var(--ink-0); + font-weight: 700; + letter-spacing: -0.01em; +} +.start__step-sub { + color: var(--ink-2); + font-size: 0.95rem; + margin: 4px 0 12px; +} +.start__step-sub code { + font-family: var(--font-mono); + background: var(--bg-2); + padding: 1px 6px; border-radius: 4px; + color: var(--ink-1); font-size: 0.9em; +} +.start__step-sub strong { color: var(--ink-0); } +.start__step-sub--muted { color: var(--ink-3); margin-top: 10px; margin-bottom: 0; } + +/* code block with copy button */ +.start__code--with-copy { + position: relative; +} +.copy-btn { + position: absolute; + top: 10px; right: 10px; + padding: 6px 12px; + font-size: 12px; + font-family: var(--font-sans); + font-weight: 600; + color: var(--ink-1); + background: var(--bg-1); + border: 1px solid var(--line-2); + border-radius: var(--r-sm); + cursor: pointer; + transition: background 140ms var(--ease), color 140ms var(--ease), border-color 140ms var(--ease); +} +.copy-btn:hover { + background: var(--bg-2); color: var(--ink-0); + border-color: rgba(232,161,59,0.3); +} +.copy-btn.is-copied { + background: var(--amber-wash); + color: var(--amber-soft); + border-color: rgba(232,161,59,0.4); +} + +/* more / details disclosure */ +.start__more { + margin-top: 22px; + border: 1px solid var(--line-1); + border-radius: var(--r-md); + background: var(--bg-1); + padding: 14px 18px; +} +.start__more > summary { + cursor: pointer; + color: var(--ink-0); + font-weight: 600; + font-size: 0.95rem; + list-style: none; +} +.start__more > summary::-webkit-details-marker { display: none; } +.start__more > summary::before { + content: "▸ "; + color: var(--amber); + display: inline-block; + margin-right: 6px; + transition: transform 140ms var(--ease); +} +.start__more[open] > summary::before { content: "▾ "; } +.start__more > .start__code { margin-top: 12px; } + +/* links row beneath the steps */ +.start__links { + margin-top: 24px; + display: flex; gap: 12px; flex-wrap: wrap; +} + /* ============ FOOT ============ */ .foot { border-top: 1px solid var(--line-1);