diff --git a/.github/workflows/azure-static-web-apps.yml b/.github/workflows/azure-static-web-apps.yml new file mode 100644 index 0000000000..c1c1c80b24 --- /dev/null +++ b/.github/workflows/azure-static-web-apps.yml @@ -0,0 +1,57 @@ +name: Deploy to Azure Static Web Apps + +# Hosts the site on Azure Static Web Apps with the REPO ROOT as the web root, +# so /site/* serves the app and /phases/* serves lesson content (docs/en.md, +# quiz.json) that lesson.html loads at runtime via relative paths — no GitHub +# fetch needed. Requires the repo secret AZURE_STATIC_WEB_APPS_API_TOKEN +# (the deployment token from the Azure Static Web App resource). + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize, reopened, closed] + branches: [main] + +permissions: + contents: read + pull-requests: write + +jobs: + build_and_deploy: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy + steps: + - uses: actions/checkout@v4 + with: + submodules: false + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Generate site/data.js + run: node site/build.js + + - name: Deploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} + repo_token: ${{ secrets.GITHUB_TOKEN }} + action: upload + # Repo root is the web root so /phases/* is served alongside /site/*. + app_location: "/" + output_location: "" + skip_app_build: true + + close_pull_request: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close PR preview + steps: + - name: Close + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} + action: close diff --git a/site/header.js b/site/header.js index 82a7edd2c0..e088920091 100644 --- a/site/header.js +++ b/site/header.js @@ -44,27 +44,12 @@ } function load() { + // No runtime network calls: only paint a previously cached value. + // The live GitHub fetch was removed to keep pages fully self-contained. var cached = readCache(); if (cached != null) { paint(cached); - return; } - fetch('https://api.github.com/repos/' + REPO, { - headers: { Accept: 'application/vnd.github+json' }, - }) - .then(function (r) { - if (!r.ok) throw new Error('gh ' + r.status); - return r.json(); - }) - .then(function (data) { - var n = data.stargazers_count; - if (typeof n !== 'number') return; - writeCache(n); - paint(n); - }) - .catch(function () { - // Leave the placeholder; the link still works. - }); } if (document.readyState === 'loading') { diff --git a/site/lesson.html b/site/lesson.html index b9595a47d8..29b0492192 100644 --- a/site/lesson.html +++ b/site/lesson.html @@ -1838,8 +1838,12 @@ } function fetchLesson(path) { - var rawUrl = 'https://raw.githubusercontent.com/rohitg00/ai-engineering-from-scratch/main/' + path + '/docs/en.md'; - var quizUrl = 'https://raw.githubusercontent.com/rohitg00/ai-engineering-from-scratch/main/' + path + '/quiz.json'; + // Load lesson content from the repo's local files (served relative to + // /site), not from GitHub. Requires serving the repo root over a local + // dev server (e.g. `python3 -m http.server` in the repo root) so the + // page is reached at /site/lesson.html and ../ resolves on disk. + var rawUrl = '../' + path + '/docs/en.md'; + var quizUrl = '../' + path + '/quiz.json'; fetch(rawUrl) .then(function (res) { diff --git a/staticwebapp.config.json b/staticwebapp.config.json new file mode 100644 index 0000000000..77a5349517 --- /dev/null +++ b/staticwebapp.config.json @@ -0,0 +1,24 @@ +{ + "routes": [ + { "route": "/", "rewrite": "/site/index.html" }, + { "route": "/glossary", "rewrite": "/site/glossary.html" }, + { "route": "/catalog", "rewrite": "/site/catalog.html" }, + { "route": "/path", "rewrite": "/site/prereqs.html" }, + { "route": "/roadmap", "rewrite": "/site/prereqs.html" }, + { "route": "/about", "rewrite": "/site/about.html" } + ], + "navigationFallback": { + "rewrite": "/site/index.html", + "exclude": ["/site/*", "/phases/*", "/assets/*", "/*.{js,css,png,jpg,jpeg,svg,webp,woff2,woff,ttf,ico,md,json}"] + }, + "globalHeaders": { + "X-Content-Type-Options": "nosniff" + }, + "mimeTypes": { + ".md": "text/markdown", + ".json": "application/json" + }, + "responseOverrides": { + "404": { "rewrite": "/site/index.html" } + } +}