feat(web): add global footer and button-style nav #77
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
| # .github/workflows/guardian.yml | |
| # | |
| # Sidecoin Monorepo CI Suite | |
| # Runs on every push/PR to master across all packages. | |
| # | |
| # IMPORTANT: All cargo commands use --locked to ensure deterministic | |
| # builds from the committed Cargo.lock. Without --locked, Cargo may | |
| # resolve newer transitive dependencies (e.g. tauri-runtime) that | |
| # introduce breaking trait changes and fail compilation. | |
| name: Sidecoin CI Suite | |
| on: | |
| push: | |
| branches: ["master"] | |
| pull_request: | |
| branches: ["master"] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Force any remaining JavaScript actions onto the Node.js 24 runtime. | |
| # After replacing pnpm/action-setup (corepack) and wrangler-action | |
| # (npx wrangler) below, the only Node-20 action left is the transitive | |
| # actions/github-script pulled in by codecov-action — which we cannot | |
| # version-pin directly. This flag keeps it running on Node 24 so it does | |
| # not break after the Sept 16 2026 Node-20 removal. Drop once codecov | |
| # ships a Node 24 release. | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| jobs: | |
| guardian: | |
| name: desktop-client (${{ matrix.platform }}) | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| platform: [ubuntu-latest, macos-latest, windows-latest] | |
| runs-on: ${{ matrix.platform }} | |
| env: | |
| WEBVIEW2_LINK_STATIC: "1" | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy, rustfmt, llvm-tools-preview | |
| - name: Install cargo-llvm-cov | |
| uses: taiki-e/install-action@cargo-llvm-cov | |
| - name: Rust Cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ runner.os }}-v2 | |
| workspaces: "./packages/desktop/src-tauri -> target" | |
| - name: Install Linux dependencies | |
| if: matrix.platform == 'ubuntu-latest' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libwebkit2gtk-4.1-dev \ | |
| libappindicator3-dev \ | |
| librsvg2-dev \ | |
| patchelf \ | |
| xvfb \ | |
| webkit2gtk-driver | |
| cargo install tauri-driver | |
| - name: Install Frontend dependencies | |
| run: pnpm install --frozen-lockfile | |
| # ── Shared ────────────────────────────────────────────── | |
| - name: Type-check Shared | |
| run: pnpm --filter @sidecoin/shared build | |
| # ── Desktop — Placeholder Dist ────────────────────────── | |
| # | |
| # Tauri's generate_context!() proc macro validates that | |
| # frontendDist ("../dist") exists at compile time. This | |
| # placeholder must exist BEFORE any cargo command that | |
| # compiles the Tauri app (clippy, build, llvm-cov, etc.). | |
| # It is replaced by the real frontend build later. | |
| # ──────────────────────────────────────────────────────── | |
| - name: Create Placeholder Dist | |
| shell: bash | |
| run: mkdir -p packages/desktop/dist && touch packages/desktop/dist/index.html | |
| # ── Desktop — Rust Quality Gates ──────────────────────── | |
| - name: Check Rust Formatting | |
| working-directory: packages/desktop/src-tauri | |
| run: cargo fmt --all -- --check | |
| - name: Clippy Lint | |
| working-directory: packages/desktop/src-tauri | |
| run: cargo clippy --locked --all-features --lib -- -D warnings | |
| # ── Desktop — Build ───────────────────────────────────── | |
| - name: Generate Types (Specta) | |
| shell: bash | |
| working-directory: packages/desktop/src-tauri | |
| run: | | |
| cargo run --locked --bin export_types | |
| node -e " | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const f = path.join('..', 'src', 'bindings.ts'); | |
| if (fs.existsSync(f)) { | |
| const content = fs.readFileSync(f, 'utf8'); | |
| if (!content.startsWith('//@ts-nocheck')) { | |
| fs.writeFileSync(f, '//@ts-nocheck\n' + content); | |
| } | |
| } | |
| " | |
| - name: Build Desktop Frontend | |
| run: pnpm --filter @sidecoin/desktop exec vite build | |
| - name: Build Tauri App | |
| working-directory: packages/desktop/src-tauri | |
| run: cargo build --locked | |
| # ── Desktop — Tests ───────────────────────────────────── | |
| - name: Run Rust Unit Tests (with coverage) | |
| if: matrix.platform != 'windows-latest' | |
| working-directory: packages/desktop/src-tauri | |
| shell: bash | |
| run: cargo llvm-cov --locked --all-features --lib --lcov --output-path lcov-rust.info | |
| - name: Run Desktop Frontend Tests | |
| run: pnpm --filter @sidecoin/desktop test | |
| - name: Run Desktop Type Check | |
| run: pnpm --filter @sidecoin/desktop exec vue-tsc --noEmit --skipLibCheck | |
| # ── Desktop — E2E ─────────────────────────────────────── | |
| - name: Run E2E Tests | |
| if: matrix.platform == 'ubuntu-latest' | |
| continue-on-error: true | |
| env: | |
| CI: true | |
| GDK_BACKEND: x11 | |
| WEBKIT_DISABLE_COMPOSITING_MODE: "1" | |
| shell: bash | |
| run: xvfb-run --auto-servernum pnpm --filter @sidecoin/desktop test:e2e | |
| # ── Coverage Upload ───────────────────────────────────── | |
| - name: Verify coverage file exists | |
| if: matrix.platform == 'ubuntu-latest' | |
| working-directory: packages/desktop/src-tauri | |
| shell: bash | |
| run: | | |
| if [ -f lcov-rust.info ]; then | |
| echo "✅ Coverage file found ($(wc -l < lcov-rust.info) lines)" | |
| head -5 lcov-rust.info | |
| else | |
| echo "❌ Coverage file NOT found" | |
| ls -la | |
| exit 1 | |
| fi | |
| - name: Upload Rust Coverage | |
| if: matrix.platform == 'ubuntu-latest' | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: packages/desktop/src-tauri/lcov-rust.info | |
| flags: rust | |
| fail_ci_if_error: false | |
| verbose: true | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Upload Desktop Frontend Coverage | |
| if: matrix.platform == 'ubuntu-latest' | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: packages/desktop/coverage/lcov.info | |
| flags: desktop-frontend | |
| fail_ci_if_error: false | |
| verbose: true | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| # ── Wallet (standalone, labeled job) ───────────────────── | |
| # | |
| # Pure TS/Vite — runs once on ubuntu (no Rust/matrix needed). | |
| # Appears as its own "wallet" entry in the Actions sidebar so | |
| # a failure here is immediately distinguishable from the | |
| # desktop/web/mobile/api legs. Builds @sidecoin/shared first | |
| # (wallet depends on it). deploy-wallet gates on this job. | |
| # | |
| # Test runs with --coverage.reporter=lcov so the v8 provider | |
| # emits coverage/lcov.info for the Codecov upload below. lcov | |
| # is NOT a default vitest reporter, so it must be requested | |
| # explicitly on the CLI (keeps local `pnpm test` coverage-free). | |
| # The `--` separator forwards the flags to vitest rather than | |
| # letting pnpm try to parse them as its own options. | |
| # ───────────────────────────────────────────────────────── | |
| wallet: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build Shared | |
| run: pnpm --filter @sidecoin/shared build | |
| - name: Build Wallet | |
| run: pnpm --filter @sidecoin/wallet build | |
| - name: Test Wallet | |
| run: pnpm --filter @sidecoin/wallet test -- --coverage --coverage.reporter=lcov | |
| - name: Type-check Wallet | |
| run: pnpm --filter @sidecoin/wallet type-check | |
| - name: Upload Wallet Coverage | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: packages/wallet/coverage/lcov.info | |
| flags: wallet | |
| fail_ci_if_error: false | |
| verbose: true | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| # ── Mobile (standalone, labeled job) ───────────────────── | |
| # | |
| # React Native / Jest — runs once on ubuntu (no Rust/matrix | |
| # needed). Appears as its own "mobile" entry in the Actions | |
| # sidebar so a failure here is immediately distinguishable | |
| # from the desktop/web/api legs. | |
| # | |
| # Builds @sidecoin/shared first: the App test imports | |
| # @sidecoin/shared/chain and @sidecoin/shared/sidechains. | |
| # ───────────────────────────────────────────────────────── | |
| mobile: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build Shared | |
| run: pnpm --filter @sidecoin/shared build | |
| - name: Test Mobile | |
| run: pnpm --filter @sidecoin/mobile test | |
| # ── Web — Landing Site (standalone, labeled job) ───────── | |
| # | |
| # Pure TS/Vite — runs once on ubuntu. Appears as its own | |
| # "web" entry in the Actions sidebar. Builds @sidecoin/shared | |
| # first (web depends on it), then builds + tests the site. | |
| # deploy-web gates on this job. | |
| # ───────────────────────────────────────────────────────── | |
| web: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build Shared | |
| run: pnpm --filter @sidecoin/shared build | |
| - name: Build Web | |
| run: pnpm --filter @sidecoin/web build | |
| - name: Test Web | |
| run: pnpm --filter @sidecoin/web test | |
| # ── API adapter + client (standalone, labeled job) ─────── | |
| # | |
| # Pure TS — runs once on ubuntu (no Rust/matrix needed). | |
| # Appears as its own "api" entry in the Actions sidebar so | |
| # a failure here is immediately distinguishable from the | |
| # desktop/web/wallet legs. Each named step (Test/Type-check) | |
| # pinpoints exactly which check broke. | |
| # ───────────────────────────────────────────────────────── | |
| api: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Test API client | |
| run: pnpm --filter @sidecoin/api-client test | |
| - name: Type-check API client | |
| run: pnpm --filter @sidecoin/api-client typecheck | |
| - name: Test API adapter | |
| run: pnpm --filter @sidecoin/api test | |
| - name: Type-check API adapter | |
| run: pnpm --filter @sidecoin/api typecheck | |
| # ── Cloudflare Pages — Landing Site ────────────────────── | |
| # | |
| # Deploys on every push to master after all CI jobs pass. | |
| # PRs do NOT deploy — only merged commits to master. | |
| # ───────────────────────────────────────────────────────── | |
| deploy-web: | |
| needs: web | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build Shared | |
| run: pnpm --filter @sidecoin/shared build | |
| - name: Build Web | |
| run: pnpm --filter @sidecoin/web build | |
| - name: Deploy to Cloudflare Pages | |
| run: npx wrangler pages deploy packages/web/dist --project-name=sidecoin --commit-dirty=true | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # ── Cloudflare Pages — Wallet App ──────────────────────── | |
| deploy-wallet: | |
| needs: wallet | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build Shared | |
| run: pnpm --filter @sidecoin/shared build | |
| - name: Build Wallet | |
| run: pnpm --filter @sidecoin/wallet build | |
| - name: Deploy to Cloudflare Pages | |
| run: npx wrangler pages deploy packages/wallet/dist --project-name=sidecoin-wallet --commit-dirty=true | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # ── Cloudflare Workers — API Adapter (GATED) ───────────── | |
| # | |
| # Worker deploy (wrangler deploy), NOT Pages. Gated behind a | |
| # GitHub Environment ("production-api") with required reviewers: | |
| # this job pauses for manual approval before the adapter ships. | |
| # Deploys only on push to master, after the api job passes. | |
| # ───────────────────────────────────────────────────────── | |
| deploy-api: | |
| needs: api | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: production-api | |
| url: https://sidecoin.app | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: "22" | |
| cache: "pnpm" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build Shared | |
| run: pnpm --filter @sidecoin/shared build | |
| - name: Deploy Worker | |
| run: npx wrangler deploy | |
| working-directory: packages/api | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} |