Update en.json #55
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: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build production files (main branch only) | |
| if: github.ref == 'refs/heads/main' | |
| run: | | |
| echo "🔨 Building production files..." | |
| if ! npm run build:all; then | |
| echo "❌ Production build failed" >&2 | |
| exit 1 | |
| fi | |
| mkdir -p public/production | |
| if ! cp -r dist/* public/production/; then | |
| echo "❌ Failed to copy production files" >&2 | |
| exit 1 | |
| fi | |
| echo "✅ Production build completed successfully" | |
| - 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" | |
| # Build files for this branch with proper error handling | |
| if [[ -f "public/$SAFE/package.json" ]]; then | |
| cd "public/$SAFE" | |
| echo "🔨 Building files for branch $BR..." | |
| # Install dependencies with error handling | |
| if ! npm ci; then | |
| echo "❌ Failed to install dependencies for branch $BR" >&2 | |
| cd ../.. | |
| continue | |
| fi | |
| # Build with error handling | |
| if npm run build:all; then | |
| echo "✅ Successfully built files for branch $BR" | |
| # Validate build outputs exist and have reasonable size | |
| build_success=true | |
| if [[ -d "dist" ]]; then | |
| for file in dist/auto-image.*.js dist/auto-image.*.txt; do | |
| if [[ -f "$file" ]]; then | |
| size=$(stat -c%s "$file" 2>/dev/null || echo 0) | |
| if [[ $size -lt 100 ]]; then | |
| echo "⚠️ Build output $file is suspiciously small ($size bytes)" >&2 | |
| build_success=false | |
| fi | |
| fi | |
| done | |
| if [[ "$build_success" == "true" ]]; then | |
| # Copy built files to root of branch directory for direct access | |
| if cp dist/auto-image.*.js . && cp dist/auto-image.*.txt .; then | |
| echo "✅ Build artifacts copied successfully for branch $BR" | |
| else | |
| echo "⚠️ Failed to copy some build artifacts for branch $BR" >&2 | |
| fi | |
| else | |
| echo "⚠️ Build validation failed for branch $BR, serving source files only" >&2 | |
| fi | |
| else | |
| echo "⚠️ No dist directory found for branch $BR, serving source files only" >&2 | |
| fi | |
| else | |
| echo "❌ Build failed for branch $BR, serving source files only" >&2 | |
| fi | |
| cd ../.. | |
| else | |
| echo "ℹ️ No package.json found for branch $BR, serving source files only" | |
| fi | |
| # 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' -o \ | |
| -name '*.txt' \) \ | |
| -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 |