Merge pull request #98 from Staninna/hotfix/update-urls #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Pages – aggregate all branches | |
| on: | |
| push: | |
| branches: ["**"] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| concurrency: | |
| group: pages | |
| cancel-in-progress: true | |
| jobs: | |
| aggregate_deploy: | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deploy.outputs.page_url }} | |
| steps: | |
| - name: Checkout (shallow) | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Configure Pages | |
| uses: actions/configure-pages@v5 | |
| - name: Aggregate and build recursive directory pages | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # jq for JSON escaping (present on runners, but ensure) | |
| if ! command -v jq >/dev/null 2>&1; then | |
| sudo apt-get update -y | |
| sudo apt-get install -y jq | |
| fi | |
| REPO="${GITHUB_REPOSITORY#*/}" | |
| SITE_ROOT="/${REPO}/" | |
| mkdir -p public | |
| : > public/.nojekyll | |
| # Tiny favicon assets to avoid 404s | |
| printf "%s" \ | |
| "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><text y='14' font-size='14'>🚀</text></svg>" \ | |
| > public/favicon.svg | |
| # List remote branches | |
| mapfile -t BRANCHES < <( | |
| git ls-remote --heads origin | awk '{print $2}' \ | |
| | sed 's@refs/heads/@@' | |
| ) | |
| # Landing page (no globals except window.__branches) | |
| cat > public/index.html <<'HTML' | |
| <!doctype html> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width,initial-scale=1" /> | |
| <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ctext y='14' font-size='14'%3E🚀%3C/text%3E%3C/svg%3E" /> | |
| <title>Branches</title> | |
| <style> | |
| body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Arial; | |
| margin:24px;background:#0d1117;color:#e6edf3} | |
| a{color:#58a6ff;text-decoration:none} | |
| .card{background:#161b22;padding:16px;border-radius:8px;margin:12px 0} | |
| input{background:#0b0f14;border:1px solid #30363d;color:#e6edf3; | |
| padding:8px 10px;border-radius:6px;width:100%;max-width:420px} | |
| </style> | |
| <h1>Branches</h1> | |
| <input id="q" placeholder="Filter branches..." /> | |
| <div id="list"></div> | |
| <script>window.__branches=window.__branches||[];</script> | |
| HTML | |
| # Emit index.html for a directory | |
| gen_index_dir() { | |
| local DIR="$1" ROOT="$2" BR="$3" | |
| local rel="${DIR#$ROOT}" | |
| local title="Branch: ${BR}${rel:-/}" | |
| { | |
| echo "<!doctype html><meta charset='utf-8'/>" | |
| echo "<meta name='viewport' content='width=device-width,initial-scale=1'/>" | |
| echo "<link rel='icon' href=\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ctext y='14' font-size='14'%3E🚀%3C/text%3E%3C/svg%3E\" />" | |
| echo "<title>${title}</title>" | |
| echo "<style>body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Arial;margin:24px;background:#0d1117;color:#e6edf3}a{color:#58a6ff;text-decoration:none}table{width:100%;border-collapse:collapse}th,td{padding:8px;border-bottom:1px solid #30363d}tr:hover{background:#161b22}</style>" | |
| echo "<h1>${title}</h1>" | |
| if [[ "$DIR" != "$ROOT" ]]; then | |
| echo "<p><a href='../'>⬆ Up</a> • <a href='${SITE_ROOT}'>All branches</a></p>" | |
| else | |
| echo "<p><a href='${SITE_ROOT}'>All branches</a></p>" | |
| fi | |
| echo "<table><thead><tr><th>Name</th><th style='width:120px'>Size</th><th style='width:180px'>Modified</th></tr></thead><tbody>" | |
| # Subdirectories | |
| while IFS= read -r d; do | |
| [[ -n "$d" ]] || continue | |
| printf "<tr><td>📁 <a href='./%s/'>%s/</a></td><td>—</td><td>—</td></tr>\n" "$d" "$d" | |
| done < <(find "$DIR" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | sort) | |
| # Files | |
| while IFS= read -r f; do | |
| [[ -n "$f" ]] || continue | |
| size=$(stat -c %s "$DIR/$f" 2>/dev/null || echo 0) | |
| size_h=$(numfmt --to=iec --suffix=B "$size" 2>/dev/null || echo "$size") | |
| mod=$(date -r "$DIR/$f" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "") | |
| printf "<tr><td>📄 <a href='./%s'>%s</a></td><td>%s</td><td>%s</td></tr>\n" "$f" "$f" "$size_h" "$mod" | |
| done < <(find "$DIR" -mindepth 1 -maxdepth 1 -type f ! -name 'index.html' -printf '%f\n' | sort) | |
| echo "</tbody></table>" | |
| echo "<p style='opacity:.7'>Generated $(date -u '+%Y-%m-%d %H:%M UTC')</p>" | |
| } > "$DIR/index.html" | |
| } | |
| # Build per-branch trees and indexes | |
| for BR in "${BRANCHES[@]}"; do | |
| SAFE="$(echo "$BR" | tr '/:@ ' '----' | sed 's/[^A-Za-z0-9._-]/-/g')" | |
| mkdir -p "public/$SAFE" | |
| git fetch --depth=1 origin "$BR" | |
| git archive --format=tar FETCH_HEAD | tar -x -C "public/$SAFE" | |
| # Keep only static assets; prune empty dirs | |
| rm -rf "public/$SAFE/.git" "public/$SAFE/.github" \ | |
| "public/$SAFE/node_modules" | |
| find "public/$SAFE" -type f ! \ | |
| \( -name '*.html' -o -name '*.js' -o -name '*.css' -o \ | |
| -name '*.json' -o -name '*.png' -o -name '*.jpg' -o \ | |
| -name '*.jpeg' -o -name '*.gif' -o -name '*.svg' \) \ | |
| -delete | |
| find "public/$SAFE" -type d -empty -delete | |
| ROOT_DIR="public/$SAFE" | |
| while IFS= read -r -d '' d; do | |
| gen_index_dir "$d" "$ROOT_DIR" "$BR" | |
| done < <(find "$ROOT_DIR" -type d -print0) | |
| # Append to landing page (JSON-escaped) | |
| SAFE_JSON=$(printf '%s' "$SAFE" | jq -Rr @json) | |
| BR_JSON=$(printf '%s' "$BR" | jq -Rr @json) | |
| echo "<script>window.__branches.push({safe:$SAFE_JSON,name:$BR_JSON});</script>" \ | |
| >> public/index.html | |
| done | |
| # Finish landing page | |
| cat >> public/index.html <<'HTML' | |
| <script> | |
| (() => { | |
| const q = document.getElementById('q'); | |
| const listEl = document.getElementById('list'); | |
| function render(filter = '') { | |
| listEl.innerHTML = ''; | |
| const qv = filter.toLowerCase(); | |
| for (const b of (window.__branches || []).filter(x => | |
| x.name.toLowerCase().includes(qv) | |
| )) { | |
| const div = document.createElement('div'); | |
| div.className = 'card'; | |
| div.innerHTML = `<strong>${b.name}</strong><div> | |
| <a href="./${b.safe}/">Open</a> | |
| </div>`; | |
| listEl.appendChild(div); | |
| } | |
| } | |
| q.addEventListener('input', (e) => render(e.target.value)); | |
| render(); | |
| })(); | |
| </script> | |
| HTML | |
| - name: Upload Pages artifact | |
| uses: actions/upload-pages-artifact@v4 | |
| with: | |
| path: public | |
| - name: Deploy to GitHub Pages | |
| id: deploy | |
| uses: actions/deploy-pages@v4 |