diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7c5b934..4b2c4ff 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,8 @@ "ghcr.io/devcontainers/features/git-lfs:1": {}, "ghcr.io/devcontainers/features/node:1": { "version": "20" - } + }, + "ghcr.io/devcontainers/features/azure-cli:1": {} }, "customizations": { "vscode": { @@ -14,12 +15,13 @@ "GitHub.copilot-chat", "ms-dotnettools.csharp", "ms-dotnettools.vscode-dotnet-runtime", - "ms-azuretools.vscode-azure-mcp-server" + "ms-azuretools.vscode-azure-mcp-server", + "ms-azuretools.vscode-bicep" ] } }, - "postCreateCommand": "dotnet tool install -g docfx", + "postCreateCommand": "dotnet tool install -g docfx && az bicep install", "remoteEnv": { "PATH": "${containerEnv:PATH}:${containerEnv:HOME}/.dotnet/tools" } -} +} \ No newline at end of file diff --git a/.github/workflows/azure-swa-deploy.yml b/.github/workflows/azure-swa-deploy.yml new file mode 100644 index 0000000..0ae060b --- /dev/null +++ b/.github/workflows/azure-swa-deploy.yml @@ -0,0 +1,72 @@ +# name: Deploy to Azure Static Web Apps + +# on: +# push: +# branches: +# - main +# paths: +# - 'docs/**' +# pull_request: +# types: [opened, synchronize, reopened, closed] +# branches: +# - main +# paths: +# - 'docs/**' +# workflow_dispatch: + +# # Sets permissions for GITHUB_TOKEN +# permissions: +# contents: read +# pull-requests: write + +# # Allow only one concurrent deployment +# concurrency: +# group: "azure-swa" +# cancel-in-progress: false + +# jobs: +# build_and_deploy: +# # Only run on push or if PR is not closed +# if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.action != 'closed') +# runs-on: ubuntu-latest +# name: Build and Deploy +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 1 + +# - name: Setup .NET +# uses: actions/setup-dotnet@v4 +# with: +# dotnet-version: 8.x + +# - name: Install DocFX +# run: dotnet tool update -g docfx + +# - name: Build documentation +# run: docfx docs/docfx.json + +# - name: Deploy to Azure Static Web Apps +# id: 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 +# app_location: "docs/_site" +# api_location: "" +# output_location: "" +# skip_app_build: true + +# close_pull_request: +# # Only run when PR is closed +# if: github.event_name == 'pull_request' && github.event.action == 'closed' +# runs-on: ubuntu-latest +# name: Close Pull Request +# steps: +# - name: Close Pull Request +# 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/.gitignore b/.gitignore index 31873c8..87d7fe4 100644 --- a/.gitignore +++ b/.gitignore @@ -53,4 +53,12 @@ CodeCoverage/ TestResult.xml nunit-*.xml -_site/ \ No newline at end of file +_site/ + +# Azure Static Web Apps +.azure/ +swa-cli.config.json + +# Bicep build artifacts +infra/*.json +!infra/bicep.parameters.json \ No newline at end of file diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..6ff75ab --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,171 @@ +# Azure Static Web Apps Deployment - Quick Start + +This guide walks you through deploying your DocFX wiki to Azure Static Web Apps in minutes. + +## Prerequisites + +- Azure subscription ([free trial available](https://azure.microsoft.com/free/)) +- Azure CLI installed ([install guide](https://learn.microsoft.com/cli/azure/install-azure-cli)) +- GitHub repository access (for setting secrets) + +## Step-by-Step Deployment + +### 1. Clone and Customize + +```bash +# Clone the repository +git clone https://github.com/YOUR-USERNAME/docfx-wiki.git +cd docfx-wiki + +# Edit the parameters file +cd infra +nano bicep.parameters.json # or use your preferred editor +``` + +**Edit these values in `bicep.parameters.json`:** + +```json +{ + "parameters": { + "staticWebAppName": { + "value": "my-unique-wiki-name" // ⚠️ Must be globally unique + }, + "location": { + "value": "eastus2" // Choose your preferred region + }, + "sku": { + "value": "Free" // Free or Standard + } + } +} +``` + +### 2. Login to Azure + +```bash +az login +``` + +### 3. Deploy Infrastructure (One Command!) + +```bash +# Create resource group and deploy in one go +RESOURCE_GROUP="rg-docfx-wiki" +LOCATION="eastus2" + +az group create --name $RESOURCE_GROUP --location $LOCATION && \ +az deployment group create \ + --resource-group $RESOURCE_GROUP \ + --template-file main.bicep \ + --parameters bicep.parameters.json +``` + +✅ **Success!** Your Azure Static Web App is now created. + +### 4. Get Your Deployment Token + +```bash +DEPLOYMENT_TOKEN=$(az deployment group show \ + --resource-group $RESOURCE_GROUP \ + --name main \ + --query properties.outputs.deploymentToken.value \ + --output tsv) + +echo "Your deployment token: $DEPLOYMENT_TOKEN" +``` + +⚠️ **Important:** Copy this token - you'll need it in the next step. + +### 5. Add Secret to GitHub + +1. Go to your GitHub repository +2. Click **Settings** → **Secrets and variables** → **Actions** +3. Click **New repository secret** +4. Set: + - **Name:** `AZURE_STATIC_WEB_APPS_API_TOKEN` + - **Value:** Paste the deployment token from step 4 +5. Click **Add secret** + +### 6. Trigger Deployment + +Option A: Push to main branch +```bash +git add . +git commit -m "Update documentation" +git push origin main +``` + +Option B: Manual trigger +1. Go to **Actions** tab in GitHub +2. Select **Deploy to Azure Static Web Apps** +3. Click **Run workflow** + +### 7. View Your Site + +Get your site URL: +```bash +az staticwebapp show \ + --name $(jq -r '.parameters.staticWebAppName.value' bicep.parameters.json) \ + --resource-group $RESOURCE_GROUP \ + --query defaultHostname \ + --output tsv +``` + +Or find it in the Azure Portal: +- Go to [portal.azure.com](https://portal.azure.com) +- Navigate to your resource group +- Click on your Static Web App +- Copy the URL from the Overview page + +## What Happens Next? + +✨ **Automatic Deployments:** Every time you push changes to the `docs/**` folder on the `main` branch, GitHub Actions will: +1. Build your DocFX site +2. Deploy it to Azure Static Web Apps +3. Make it available at your custom URL + +## Troubleshooting + +### "Static Web App name already exists" +- Change `staticWebAppName` in `bicep.parameters.json` to a unique value +- Re-run the deployment command + +### "Deployment token not working" +- Regenerate the token: + ```bash + az staticwebapp secrets list \ + --name YOUR_APP_NAME \ + --resource-group $RESOURCE_GROUP + ``` +- Update the GitHub secret with the new token + +### "Workflow not triggering" +- Check that the workflow file exists: `.github/workflows/azure-swa-deploy.yml` +- Verify the secret name is exactly: `AZURE_STATIC_WEB_APPS_API_TOKEN` +- Check workflow runs under the **Actions** tab + +### "Site shows 404 or not found" +- Wait 2-3 minutes after first deployment +- Clear your browser cache +- Check the deployment status in GitHub Actions + +## Cleanup + +To delete all resources and stop charges: + +```bash +az group delete --name $RESOURCE_GROUP --yes --no-wait +``` + +## Next Steps + +- 📝 [Edit your wiki content](../docs/content/) +- 🎨 [Customize DocFX templates](../docs/docfx.json) +- 🔧 [Configure routing](../staticwebapp.config.json) +- 📊 [Monitor with Application Insights](https://learn.microsoft.com/azure/static-web-apps/monitor) + +## Support + +- 📖 [Azure Static Web Apps Documentation](https://learn.microsoft.com/azure/static-web-apps/) +- 💬 [GitHub Discussions](https://github.com/YOUR-USERNAME/docfx-wiki/discussions) +- 🐛 [Report Issues](https://github.com/YOUR-USERNAME/docfx-wiki/issues) diff --git a/README.md b/README.md index 9466436..84cae24 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,50 @@ -# docfx-wiki +# DocFX Wiki -Lightweight wiki-style documentation site built with [DocFX](https://github.com/dotnet/docfx). Author content in Markdown, build a static site, and (optionally) publish to GitHub Pages. +A proof of concept (PoC) wiki-style documentation site built with [DocFX](https://github.com/dotnet/docfx). It demonstrates a simple, yet feature-rich wiki experience (navigation, search, static hosting) while keeping authoring lightweight with Markdown. -## Quick start +The focus of this repo is to provide a reusable template so others can quickly start a wiki in their own environment and deploy it with minimal setup. + +## Publish + +Click the green `Use this template` button in the top right of this page and choose `create a new repository`, then pick one of the following deployment options: + +### Option 1: GitHub Pages + +- Workflow: `.github/workflows/publish-site.yml` + +Enable GitHub Pages for the new repo created from this template: + +1. In the repo, go to **Settings** → **Pages**. +2. Under **Build and deployment**, set **Source** to **GitHub Actions**. +3. Deploy to GitHub Pages by pushing a change under `docs/` to `main` or run the workflow via **Actions**. + +### Option 2: Azure Static Web Apps + +- Workflow: `.github/workflows/azure-swa-deploy.yml` +- Requires a repo secret named `AZURE_STATIC_WEB_APPS_API_TOKEN` + +Quick deploy (Codespaces recommended): + +1. Edit the `infra/bicep.parameters.json` as desired. +2. Authenticate to Azure using `az login` and select the desired subscription +3. Run the deployment script: +```bash +./deploy-azure.sh +``` +4. Copy the deployment token from the Azure Static Web App in the Azure Portal. +5. Create a repo secret in this repository named `AZURE_STATIC_WEB_APPS_API_TOKEN` with the deployment token as the value. +6. Uncomment `.github/workflows/azure-swa-deploy.yml` and run the workflow via **Actions**. + +or + +Manual setup: see `DEPLOYMENT.md`. + +## Local Development ### Option A: GitHub Codespaces (recommended) 1. Create a Codespace from this repo. -2. Wait for the dev container to finish provisioning (it installs DocFX). +2. Wait for the dev container to finish provisioning. 3. Start the local site server: ```bash @@ -58,10 +95,7 @@ docfx docs/docfx.json Output goes to `docs/_site/`. -## Publish - -This repo includes a GitHub Actions workflow that builds the site and deploys `docs/_site` to GitHub Pages on pushes to `main`. - ## Learn more -- DocFX project: https://github.com/dotnet/docfx \ No newline at end of file +- DocFX project: https://github.com/dotnet/docfx +- Azure Static Web Apps: https://learn.microsoft.com/azure/static-web-apps/ \ No newline at end of file diff --git a/deploy-azure.sh b/deploy-azure.sh new file mode 100755 index 0000000..3fd4bb8 --- /dev/null +++ b/deploy-azure.sh @@ -0,0 +1,166 @@ +#!/bin/bash + +# Azure Static Web Apps Deployment Script +# This script automates the deployment of the DocFX wiki to Azure Static Web Apps + +set -e # Exit on any error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored messages +print_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +print_step() { + echo -e "\n${GREEN}==>${NC} $1" +} + +# Check prerequisites +print_step "Checking prerequisites..." + +if ! command -v az &> /dev/null; then + print_error "Azure CLI is not installed. Please install it from: https://learn.microsoft.com/cli/azure/install-azure-cli" + exit 1 +fi + +if ! command -v jq &> /dev/null; then + print_warning "jq is not installed. Some features may not work. Install with: apt-get install jq" +fi + +# Check if logged in to Azure +print_step "Checking Azure login status..." +if ! az account show &> /dev/null; then + print_info "Not logged in to Azure. Logging in..." + az login +else + ACCOUNT=$(az account show --query name -o tsv) + print_info "Already logged in to Azure account: $ACCOUNT" +fi + +# Change to infra directory +cd "$(dirname "$0")/infra" + +# Read parameters from bicep.parameters.json +if [ -f "bicep.parameters.json" ]; then + if command -v jq &> /dev/null; then + APP_NAME=$(jq -r '.parameters.staticWebAppName.value' bicep.parameters.json) + LOCATION=$(jq -r '.parameters.location.value' bicep.parameters.json) + print_info "Using Static Web App name: $APP_NAME" + print_info "Using location: $LOCATION" + else + print_warning "Cannot read parameters without jq. Using defaults." + APP_NAME="docfx-wiki-swa" + LOCATION="eastus2" + fi +else + print_error "bicep.parameters.json not found!" + exit 1 +fi + +# Set resource group name +RESOURCE_GROUP="rg-docfx-wiki" + +# Confirm deployment +print_step "Deployment Summary" +echo "Resource Group: $RESOURCE_GROUP" +echo "Static Web App Name: $APP_NAME" +echo "Location: $LOCATION" +echo "" +read -p "Do you want to proceed with deployment? (y/n) " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Deployment cancelled." + exit 0 +fi + +# Create resource group +print_step "Creating resource group..." +if az group create --name "$RESOURCE_GROUP" --location "$LOCATION" --output none; then + print_info "Resource group created or already exists: $RESOURCE_GROUP" +else + print_error "Failed to create resource group" + exit 1 +fi + +# Deploy Bicep template +print_step "Deploying Azure Static Web App..." +if az deployment group create \ + --resource-group "$RESOURCE_GROUP" \ + --template-file main.bicep \ + --parameters bicep.parameters.json \ + --output none; then + print_info "Deployment successful!" +else + print_error "Deployment failed" + exit 1 +fi + +# Get deployment token +print_step "Retrieving deployment token..." +DEPLOYMENT_TOKEN=$(az deployment group show \ + --resource-group "$RESOURCE_GROUP" \ + --name main \ + --query properties.outputs.deploymentToken.value \ + --output tsv) + +if [ -z "$DEPLOYMENT_TOKEN" ]; then + print_error "Failed to retrieve deployment token" + exit 1 +fi + +# Get site URL +SITE_URL=$(az deployment group show \ + --resource-group "$RESOURCE_GROUP" \ + --name main \ + --query properties.outputs.defaultHostname.value \ + --output tsv) + +# Print success message +print_step "Deployment Complete! 🎉" +echo "" +echo "┌────────────────────────────────────────────────────────────────┐" +echo "│ DEPLOYMENT SUCCESSFUL │" +echo "└────────────────────────────────────────────────────────────────┘" +echo "" +echo "Your site will be available at: https://$SITE_URL" +echo "" +echo "Next steps:" +echo "" +echo "1. Add the deployment token to GitHub:" +echo " - Go to: https://github.com/YOUR-USERNAME/YOUR-REPO/settings/secrets/actions" +echo " - Create new secret: AZURE_STATIC_WEB_APPS_API_TOKEN" +echo " - Value (copy this): " +echo "" +echo " $DEPLOYMENT_TOKEN" +echo "" +echo "2. Push changes to trigger deployment:" +echo " git add ." +echo " git commit -m 'Update documentation'" +echo " git push origin main" +echo "" +echo "3. Monitor deployment:" +echo " - GitHub Actions: https://github.com/YOUR-USERNAME/YOUR-REPO/actions" +echo " - Azure Portal: https://portal.azure.com" +echo "" + +# Optionally copy token to clipboard if available +if command -v xclip &> /dev/null; then + echo "$DEPLOYMENT_TOKEN" | xclip -selection clipboard + print_info "Deployment token copied to clipboard!" +elif command -v pbcopy &> /dev/null; then + echo "$DEPLOYMENT_TOKEN" | pbcopy + print_info "Deployment token copied to clipboard!" +fi diff --git a/docs/content/introduction.md b/docs/content/introduction.md index e329fe8..317e896 100644 --- a/docs/content/introduction.md +++ b/docs/content/introduction.md @@ -6,8 +6,8 @@ Adventure racing is a thrilling multidisciplinary endurance sport that combines Unlike traditional running or biking races where you follow a marked route, adventure racing requires you to plan your own path. Teams make strategic decisions about which checkpoints to visit and how to connect them, navigating through forests, across rivers, and over mountains while managing limited time and energy. -> [!NOTE] -> Most races allow only map-and-compass navigation, so practicing those skills early makes every other discipline smoother. +> [!WARNING] +> Adventure racing can be intense fun.
diff --git a/docs/content/race-formats.md b/docs/content/race-formats.md index aa93042..e602b78 100644 --- a/docs/content/race-formats.md +++ b/docs/content/race-formats.md @@ -8,6 +8,7 @@ Adventure races are categorized primarily by time, not distance. This page summa Here's what to expect: +# [Sprint](#tab/Sprint) ### Sprint Races (2-8 hours) - **Ideal for**: First-timers and those new to adventure racing - **Format**: Usually completed during daylight hours @@ -16,6 +17,7 @@ Here's what to expect: - **Gear**: Minimal mandatory gear list - **What to expect**: A fun, manageable introduction to the sport with forgiving navigation and moderate physical demands +# [12-Hour](#tab/12-Hour) ### 12-Hour Races - **Ideal for**: Those ready for a bigger challenge after sprint races - **Format**: May extend into nighttime @@ -23,6 +25,7 @@ Here's what to expect: - **Gear**: More comprehensive gear list, including headlamps - **What to expect**: Sustained physical effort, night navigation skills, and better time management needed +# [24-Hour](#tab/24-Hour) ### 24-Hour Races - **Ideal for**: Experienced racers comfortable with extended endurance - **Format**: Racing through both day and night @@ -30,12 +33,13 @@ Here's what to expect: - **Gear**: Full equipment kit for all conditions - **What to expect**: Sleep management decisions, cold-weather preparedness, and advanced navigation strategies +# [Expedition](#tab/expedition) ### Expedition Races (Multi-day) - **Ideal for**: Elite-level teams - **Format**: Can last several days and cover hundreds of miles - **What to expect**: Ultimate test of endurance, navigation, and team dynamics -
+--- ## Checkpoint Navigation Styles diff --git a/infra/README.md b/infra/README.md new file mode 100644 index 0000000..e35469a --- /dev/null +++ b/infra/README.md @@ -0,0 +1,96 @@ +# Azure Infrastructure + +This directory contains Bicep templates for deploying the DocFX wiki to Azure Static Web Apps. + +## Prerequisites + +- Azure CLI installed and authenticated +- Azure subscription +- Appropriate permissions to create resources + +## Quick Deployment + +### 1. Edit Parameters + +Edit `bicep.parameters.json` to customize: +- `staticWebAppName`: Globally unique name for your Static Web App +- `location`: Azure region (default: eastus2) +- `sku`: Free or Standard tier +- `tags`: Resource tags for organization + +### 2. Create Resource Group + +```bash +az group create --name rg-docfx-wiki --location eastus2 +``` + +### 3. Deploy Bicep Template + +```bash +az deployment group create \ + --resource-group rg-docfx-wiki \ + --template-file main.bicep \ + --parameters bicep.parameters.json +``` + +### 4. Get Deployment Token + +After deployment, retrieve the deployment token: + +```bash +az deployment group show \ + --resource-group rg-docfx-wiki \ + --name main \ + --query properties.outputs.deploymentToken.value \ + --output tsv +``` + +### 5. Add Secret to GitHub + +Add the deployment token as a repository secret: + +1. Go to your GitHub repository +2. Navigate to Settings → Secrets and variables → Actions +3. Click "New repository secret" +4. Name: `AZURE_STATIC_WEB_APPS_API_TOKEN` +5. Value: Paste the deployment token from step 4 +6. Click "Add secret" + +## Available Outputs + +The deployment provides these outputs: + +- `deploymentToken`: Use this for CI/CD authentication +- `defaultHostname`: Your site's URL +- `resourceId`: Azure resource ID for the Static Web App + +## One-Line Deployment Script + +For convenience, you can use this one-liner to deploy and capture outputs: + +```bash +az deployment group create \ + --resource-group rg-docfx-wiki \ + --template-file main.bicep \ + --parameters bicep.parameters.json \ + --query properties.outputs +``` + +## Updating the Deployment + +To update the deployment with new parameters: + +```bash +az deployment group create \ + --resource-group rg-docfx-wiki \ + --template-file main.bicep \ + --parameters bicep.parameters.json +``` + +## Cleanup + +To delete all resources: + +```bash +az group delete --name rg-docfx-wiki --yes --no-wait +``` diff --git a/infra/bicep.parameters.json b/infra/bicep.parameters.json new file mode 100644 index 0000000..3f125ec --- /dev/null +++ b/infra/bicep.parameters.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "staticWebAppName": { + "value": "docfx-wiki-swa" + }, + "location": { + "value": "eastus2" + }, + "sku": { + "value": "Free" + }, + "tags": { + "value": { + "Environment": "Dev", + "Project": "DocFX Wiki" + } + } + } +} diff --git a/infra/main.bicep b/infra/main.bicep new file mode 100644 index 0000000..cbc5cd9 --- /dev/null +++ b/infra/main.bicep @@ -0,0 +1,40 @@ +@description('Name of the Azure Static Web App') +param staticWebAppName string + +@description('Location for the Static Web App') +param location string = resourceGroup().location + +@description('SKU for the Static Web App') +@allowed([ + 'Free' + 'Standard' +]) +param sku string = 'Free' + +@description('Tags to apply to resources') +param tags object = {} + +resource staticWebApp 'Microsoft.Web/staticSites@2023-12-01' = { + name: staticWebAppName + location: location + tags: tags + sku: { + name: sku + tier: sku + } + properties: { + repositoryUrl: '' + branch: '' + buildProperties: { + appLocation: '/' + apiLocation: '' + outputLocation: 'docs/_site' + } + } +} + +@description('Static Web App default hostname') +output defaultHostname string = staticWebApp.properties.defaultHostname + +@description('Static Web App resource ID') +output resourceId string = staticWebApp.id diff --git a/staticwebapp.config.json b/staticwebapp.config.json new file mode 100644 index 0000000..3620e0a --- /dev/null +++ b/staticwebapp.config.json @@ -0,0 +1,27 @@ +{ + "navigationFallback": { + "rewrite": "/index.html", + "exclude": [ + "/images/*", + "/content/*", + "/styles/*", + "/fonts/*", + "/*.{css,scss,js,png,jpg,jpeg,gif,svg,ico,woff,woff2,ttf,eot}" + ] + }, + "routes": [], + "globalHeaders": { + "Cache-Control": "public, max-age=600, must-revalidate" + }, + "mimeTypes": { + ".json": "application/json", + ".yml": "text/yaml", + ".yaml": "text/yaml" + }, + "responseOverrides": { + "404": { + "rewrite": "/index.html", + "statusCode": 404 + } + } +}