#!/usr/bin/env bash # setup-docsify.sh — Bootstrap a self-hosted Docsify site on Apache 2. # # Run this script from your Apache document root: # cd /path/to/docroot # bash setup-docsify.sh # # Downloads Docsify core, the search plugin, the Vue theme, the copy-to-clipboard # plugin, and extra Prism languages (bash, yaml, python, r) — all # served locally, no external CDN dependencies at runtime. # # Re-running in an existing site is safe: it refreshes the assets and regenerates # index.html, but never overwrites Markdown files (README.md, _sidebar.md, and any # pages you have added) that already exist. set -euo pipefail # ── Configuration ─────────────────────────────────────────────────────────────── # Use "4" for the latest 4.x release, or pin to a specific version e.g. "4.13.1" DOCSIFY_VERSION="4" # ── Argument check ────────────────────────────────────────────────────────────── if [[ $# -gt 0 ]]; then echo "This script takes no options (got: $*)." >&2 echo "Usage: bash setup-docsify.sh" >&2 exit 1 fi # ── Output helpers ────────────────────────────────────────────────────────────── GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[0;33m' RED='\033[0;31m' BOLD='\033[1m' NC='\033[0m' step() { echo -e "\n${BLUE}${BOLD}==> $1${NC}"; } ok() { echo -e " ${GREEN}✓${NC} $1"; } skip() { echo -e " ${YELLOW}•${NC} $1"; } die() { echo -e " ${RED}✗${NC} $1" >&2; exit 1; } # ── Preflight checks ──────────────────────────────────────────────────────────── step "Preflight checks" command -v curl &>/dev/null \ || die "curl is required but not found. Install curl and try again." ok "curl $(curl --version | head -1 | awk '{print $2}')" if [[ -f index.html ]]; then echo -e " ${RED}!${NC} index.html already exists in: $(pwd)" echo -e " This re-downloads assets and regenerates index.html (edits to" echo -e " index.html will be lost). Existing Markdown files are left untouched." read -r -p " Continue? [y/N] " reply [[ "${reply,,}" == "y" ]] || { echo "Aborted."; exit 0; } fi echo -e " Working in: $(pwd)" # ── Step 1: Directories ───────────────────────────────────────────────────────── step "Step 1 — Creating directory structure" mkdir -p assets/js assets/css ok "assets/js/" ok "assets/css/" # ── Step 2: Download Docsify assets ───────────────────────────────────────────── step "Step 2 — Downloading Docsify assets" CDN="https://cdn.jsdelivr.net/npm" fetch() { local url="$1" dest="$2" curl -sL --fail "$url" -o "$dest" || die "Failed to download: $url" ok "$dest" } # Core Docsify, search plugin, and theme fetch "${CDN}/docsify@${DOCSIFY_VERSION}/lib/docsify.min.js" assets/js/docsify.min.js fetch "${CDN}/docsify@${DOCSIFY_VERSION}/lib/plugins/search.min.js" assets/js/search.min.js fetch "${CDN}/docsify@${DOCSIFY_VERSION}/themes/vue.css" assets/css/vue.css # Copy-to-clipboard plugin (injects its own CSS — no separate stylesheet needed) fetch "${CDN}/docsify-copy-code@3/dist/docsify-copy-code.min.js" assets/js/docsify-copy-code.min.js # Extra Prism languages. Docsify already bundles Prism core plus html/css/clike/ # javascript, so we only add the languages it does NOT ship. Never download # prism-core here — a standalone core replaces Docsify's Prism and silently breaks # highlighting for every language loaded after it. fetch "${CDN}/prismjs@1/components/prism-bash.min.js" assets/js/prism-bash.min.js fetch "${CDN}/prismjs@1/components/prism-yaml.min.js" assets/js/prism-yaml.min.js fetch "${CDN}/prismjs@1/components/prism-python.min.js" assets/js/prism-python.min.js fetch "${CDN}/prismjs@1/components/prism-r.min.js" assets/js/prism-r.min.js # ── Step 3: index.html ────────────────────────────────────────────────────────── step "Step 3 — Creating index.html" # The heredoc delimiter is single-quoted ('HTML') so the shell does not expand # $docsify inside the template. cat > index.html << 'HTML'