diff --git a/.github/workflows/bootstrap-pages-branch.yml b/.github/workflows/bootstrap-pages-branch.yml new file mode 100644 index 0000000..bd2150a --- /dev/null +++ b/.github/workflows/bootstrap-pages-branch.yml @@ -0,0 +1,50 @@ +name: Bootstrap gh-pages branch + +on: + workflow_dispatch: + +permissions: + contents: write + +jobs: + bootstrap: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create gh-pages branch if missing + shell: bash + run: | + set -euo pipefail + git fetch --all + + if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then + echo "gh-pages branch already exists; nothing to do." + exit 0 + fi + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git checkout --orphan gh-pages + git rm -rf . >/dev/null 2>&1 || true + + cat > index.html <<'HTML' + + +
+ + +GitHub Pages bootstrap branch created. Deploy workflows will replace this content.
+ + + HTML + + touch .nojekyll + git add index.html .nojekyll + git commit -m "Bootstrap gh-pages branch" + git push origin gh-pages diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..264a3f5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI + +on: + pull_request: + push: + branches: [main, master, dev, work] + +permissions: + contents: read + +jobs: + quality: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Astro + uses: withastro/action@v3 + with: + path: . + node-version: 20 + package-manager: npm + + - name: Type/content check + run: npm run check + + - name: Build site + run: npm run build diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml new file mode 100644 index 0000000..053dcc2 --- /dev/null +++ b/.github/workflows/deploy-dev.yml @@ -0,0 +1,54 @@ +name: Deploy development site + +on: + push: + branches: [dev] + workflow_dispatch: + inputs: + ref: + description: 'Branch/tag/SHA to deploy as preview' + required: false + default: 'dev' + +permissions: + contents: write + +env: + PAGES_BRANCH: gh-pages + +concurrency: + group: deploy-dev + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + env: + DEPLOY_TARGET: dev + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref || 'dev' }} + + - name: Setup Astro + uses: withastro/action@v3 + with: + path: . + node-version: 20 + package-manager: npm + + - name: Build development preview site + run: npm run build + + - name: Add .nojekyll for GitHub Pages + run: touch dist/.nojekyll + + - name: Deploy to pages branch /preview + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: ${{ env.PAGES_BRANCH }} + folder: dist + target-folder: preview + clean: true diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml new file mode 100644 index 0000000..280cfe6 --- /dev/null +++ b/.github/workflows/deploy-prod.yml @@ -0,0 +1,47 @@ +name: Deploy production site + +on: + push: + branches: [main, master] + workflow_dispatch: + +permissions: + contents: write + +env: + PAGES_BRANCH: gh-pages + +concurrency: + group: deploy-prod + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + env: + DEPLOY_TARGET: prod + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Astro + uses: withastro/action@v3 + with: + path: . + node-version: 20 + package-manager: npm + + - name: Build production site + run: npm run build + + - name: Add .nojekyll for GitHub Pages + run: touch dist/.nojekyll + + - name: Deploy to pages branch root + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: ${{ env.PAGES_BRANCH }} + folder: dist + clean: true + clean-exclude: preview diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 0000000..f1da402 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,129 @@ +name: Preview on Pull Request + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: write + pull-requests: write + +concurrency: + group: preview-${{ github.event.pull_request.number }} + cancel-in-progress: true + +env: + PAGES_BRANCH: gh-pages + +jobs: + preview-deploy: + runs-on: ubuntu-latest + env: + DEPLOY_TARGET: pr + DEPLOY_PREVIEW_PATH: pr-${{ github.event.pull_request.number }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Ensure gh-pages branch exists + shell: bash + run: | + set -euo pipefail + git fetch --all + if git ls-remote --exit-code --heads origin "$PAGES_BRANCH" >/dev/null 2>&1; then + echo "Branch $PAGES_BRANCH exists" + exit 0 + fi + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git checkout --orphan "$PAGES_BRANCH" + git rm -rf . >/dev/null 2>&1 || true + printf 'Preview bootstrap.
' > index.html + touch .nojekyll + git add index.html .nojekyll + git commit -m "Bootstrap gh-pages for previews" + git push origin "$PAGES_BRANCH" + + - name: Setup Astro + uses: withastro/action@v3 + with: + path: . + node-version: 20 + package-manager: npm + + - name: Build site + run: npm run build + + - name: Add .nojekyll for GitHub Pages + run: touch dist/.nojekyll + + - name: Deploy PR preview to gh-pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: ${{ env.PAGES_BRANCH }} + folder: dist + target-folder: preview/pr-${{ github.event.pull_request.number }} + clean: true + + - name: Verify preview URL is reachable + shell: bash + env: + PREVIEW_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/preview/pr-${{ github.event.pull_request.number }}/ + run: | + set -euo pipefail + echo "Checking $PREVIEW_URL" + for i in $(seq 1 20); do + code=$(curl -s -o /dev/null -w "%{http_code}" "$PREVIEW_URL" || true) + if [ "$code" = "200" ]; then + echo "Preview is live" + exit 0 + fi + echo "Attempt $i/20: HTTP $code, retrying in 15s..." + sleep 15 + done + echo "Preview did not become reachable in time" + exit 1 + + - name: Comment preview URL on PR + if: success() + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request.number; + const url = `https://${context.repo.owner}.github.io/${context.repo.repo}/preview/pr-${pr}/`; + const body = [ + '🔍 PR preview is ready.', + '', + `**Open preview:** ${url}` + ].join('\n'); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr, + body + }); + + - name: Comment failure help on PR + if: failure() + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request.number; + const body = [ + '❌ PR preview deployment finished but URL was not reachable in time.', + '', + 'Please check **Settings → Pages**:', + '- Source: `Deploy from a branch`', + '- Branch: `gh-pages`', + '- Folder: `/(root)`', + '', + 'Then re-run the `Preview on Pull Request` workflow.' + ].join('\n'); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr, + body + }); diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..953a5b8 --- /dev/null +++ b/.nojekyll @@ -0,0 +1 @@ +# presence of this file disables Jekyll processing on GitHub Pages diff --git a/README.md b/README.md new file mode 100644 index 0000000..b1e3b83 --- /dev/null +++ b/README.md @@ -0,0 +1,168 @@ +# Marcus Astro Theme + +A minimal, editorial Astro theme inspired by calm personal blogs and designed for technical writing. + +## Features + +- Structured front page with sectioned lists (Posts + Micro) +- Content collections with typed frontmatter (`posts`, `micro`) +- Responsive reading width (optimized around `880px` content column) +- Optional sticky left TOC on long-form post pages +- Light/dark mode with persistent preference (`localStorage`) +- Clearly-marked sample content included so the theme works out of the box + +## Quick start + +```bash +npm install +npm run dev +``` + +## Theme structure + +- `src/layouts/BaseLayout.astro` — metadata, shell, and global header +- `src/components/Header.astro` — minimal top navigation +- `src/components/ThemeToggle.astro` — client-side theme switching +- `src/pages/` — homepage, list pages, and dynamic content routes +- `src/content/` — sample posts and micro notes + +## Build checks + +```bash +npm run check +npm run build +``` + + +## Sample content note + +All files under `src/content/` are intentionally demo placeholders so you can safely replace them. + + +## Where to see the sample website + +This repo now supports **two Astro deployments from one repository**: + +- **Production**: `main`/`master` branch → `gh-pages` root +- **Development preview**: `dev` branch → `gh-pages/preview/` + +For a project site, URLs are typically: + +- Prod: `https://sudheer.github.io/marcus-astro/` +- Dev: `https://sudheer.github.io/marcus-astro/preview/` + +## GitHub Pages setup (one-time) + +Yes, this is mostly a one-time setup. + +1. Open **Actions** and run **Bootstrap gh-pages branch** once. + - This creates `gh-pages` so it appears in Pages branch selection. +2. Open **Settings → Pages** in your repository. +3. Under **Build and deployment**, choose: + - **Source**: `Deploy from a branch` + - **Branch**: `gh-pages` + - **Folder**: `/(root)` +4. Save. + +After that: + +- pushing to `main`/`master` runs `.github/workflows/deploy-prod.yml` +- pushing to `dev` runs `.github/workflows/deploy-dev.yml` + +The workflows publish to the same `gh-pages` branch, with prod at root and dev under `/preview/`. + +## Review website before merging (PR previews) + +A pull request preview workflow is included at `.github/workflows/preview.yml`. + +When you open or update a PR: + +1. GitHub Actions builds the site for that PR. +2. It deploys to `gh-pages/preview/pr-+ Minimal Astro theme for technical writing. Structured lists, calm typography, optional TOC, and + dark mode included. +
+{note.data.description}
+