deploy.sh 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/env bash
  2. # deploy.sh — Deploy a slide deck to Vercel for instant sharing
  3. #
  4. # Usage:
  5. # bash scripts/deploy.sh <path-to-slide-folder-or-html>
  6. #
  7. # Examples:
  8. # bash scripts/deploy.sh ./my-pitch-deck/
  9. # bash scripts/deploy.sh ./presentation.html
  10. #
  11. # What this does:
  12. # 1. Checks if Vercel CLI is installed (installs if not)
  13. # 2. Checks if user is logged in (guides through login if not)
  14. # 3. Deploys the slide deck to a public URL
  15. # 4. Prints the live URL
  16. #
  17. # The deployed URL is permanent and works on any device (mobile, tablet, desktop).
  18. # No server to maintain — Vercel hosts it for free.
  19. set -euo pipefail
  20. # ─── Colors ────────────────────────────────────────────────
  21. RED='\033[0;31m'
  22. GREEN='\033[0;32m'
  23. CYAN='\033[0;36m'
  24. YELLOW='\033[1;33m'
  25. BOLD='\033[1m'
  26. NC='\033[0m'
  27. info() { echo -e "${CYAN}ℹ${NC} $*"; }
  28. ok() { echo -e "${GREEN}✓${NC} $*"; }
  29. warn() { echo -e "${YELLOW}⚠${NC} $*"; }
  30. err() { echo -e "${RED}✗${NC} $*" >&2; }
  31. # ─── Input validation ─────────────────────────────────────
  32. if [[ $# -lt 1 ]]; then
  33. err "Usage: bash scripts/deploy.sh <path-to-slide-folder-or-html>"
  34. err ""
  35. err "Examples:"
  36. err " bash scripts/deploy.sh ./my-pitch-deck/"
  37. err " bash scripts/deploy.sh ./presentation.html"
  38. exit 1
  39. fi
  40. INPUT="$1"
  41. # If input is a single HTML file, create a temp directory with it as index.html
  42. if [[ -f "$INPUT" && "$INPUT" == *.html ]]; then
  43. DEPLOY_DIR=$(mktemp -d)
  44. cp "$INPUT" "$DEPLOY_DIR/index.html"
  45. PARENT_DIR=$(dirname "$INPUT")
  46. # Parse the HTML for local file references (src="...", url('...'), href="...")
  47. # and copy any referenced local files into the deploy directory
  48. grep -oE '(src|href|url\()["'"'"']?[^"'"'"'>)]+' "$INPUT" 2>/dev/null | \
  49. sed "s/^src=//; s/^href=//; s/^url(//; s/[\"']//g" | \
  50. grep -v '^http' | grep -v '^data:' | grep -v '^#' | grep -v '^/' | \
  51. sort -u | while read -r ref; do
  52. # Resolve the reference relative to the HTML file's directory
  53. SOURCE_FILE="$PARENT_DIR/$ref"
  54. if [[ -e "$SOURCE_FILE" ]]; then
  55. # Preserve directory structure for nested paths (e.g., assets/img.png)
  56. TARGET_DIR="$DEPLOY_DIR/$(dirname "$ref")"
  57. mkdir -p "$TARGET_DIR"
  58. cp -r "$SOURCE_FILE" "$TARGET_DIR/"
  59. fi
  60. done
  61. # Also copy any assets/ folder if it exists (common convention)
  62. if [[ -d "$PARENT_DIR/assets" ]]; then
  63. cp -r "$PARENT_DIR/assets" "$DEPLOY_DIR/assets" 2>/dev/null || true
  64. fi
  65. CLEANUP_TEMP=true
  66. info "Single HTML file detected — preparing for deployment..."
  67. elif [[ -d "$INPUT" ]]; then
  68. # Verify the folder has an index.html
  69. if [[ ! -f "$INPUT/index.html" ]]; then
  70. err "Folder '$INPUT' does not contain an index.html file."
  71. err "Make sure your presentation folder has an index.html."
  72. exit 1
  73. fi
  74. DEPLOY_DIR="$INPUT"
  75. CLEANUP_TEMP=false
  76. else
  77. err "'$INPUT' is not a valid HTML file or directory."
  78. exit 1
  79. fi
  80. # ─── Step 1: Check for Vercel CLI ─────────────────────────
  81. echo ""
  82. echo -e "${BOLD}╔══════════════════════════════════════╗${NC}"
  83. echo -e "${BOLD}║ Deploy Slides to Vercel ║${NC}"
  84. echo -e "${BOLD}╚══════════════════════════════════════╝${NC}"
  85. echo ""
  86. if ! command -v npx &>/dev/null; then
  87. err "Node.js is required but not installed."
  88. err ""
  89. err "Install Node.js:"
  90. err " macOS: brew install node"
  91. err " or visit https://nodejs.org and download the installer"
  92. exit 1
  93. fi
  94. info "Checking Vercel CLI..."
  95. # Check if vercel is available (either globally or via npx)
  96. if command -v vercel &>/dev/null; then
  97. VERCEL_CMD="vercel"
  98. ok "Vercel CLI found"
  99. elif npx --yes vercel --version &>/dev/null 2>&1; then
  100. VERCEL_CMD="npx --yes vercel"
  101. ok "Vercel CLI available via npx"
  102. else
  103. info "Installing Vercel CLI..."
  104. npm install -g vercel
  105. VERCEL_CMD="vercel"
  106. ok "Vercel CLI installed"
  107. fi
  108. # ─── Step 2: Check login status ───────────────────────────
  109. echo ""
  110. info "Checking Vercel login status..."
  111. # Try to check if logged in by running whoami
  112. if ! $VERCEL_CMD whoami &>/dev/null 2>&1; then
  113. echo ""
  114. warn "You're not logged in to Vercel yet."
  115. echo ""
  116. echo -e "${BOLD}To log in, run this command and follow the prompts:${NC}"
  117. echo ""
  118. echo " vercel login"
  119. echo ""
  120. echo "If you don't have a Vercel account yet:"
  121. echo " 1. Go to https://vercel.com/signup"
  122. echo " 2. Sign up with GitHub, GitLab, email, or any method"
  123. echo " 3. Come back here and run: vercel login"
  124. echo " 4. Then re-run this deploy script"
  125. echo ""
  126. # Try interactive login
  127. echo -e "${YELLOW}Attempting interactive login now...${NC}"
  128. echo ""
  129. $VERCEL_CMD login || {
  130. err "Login failed. Please run 'vercel login' manually and try again."
  131. [[ "$CLEANUP_TEMP" == "true" ]] && rm -rf "$DEPLOY_DIR"
  132. exit 1
  133. }
  134. echo ""
  135. ok "Logged in to Vercel!"
  136. fi
  137. VERCEL_USER=$($VERCEL_CMD whoami 2>/dev/null || echo "unknown")
  138. ok "Logged in as: $VERCEL_USER"
  139. # ─── Step 3: Deploy ───────────────────────────────────────
  140. echo ""
  141. info "Deploying slides..."
  142. echo ""
  143. # Deploy with sensible defaults:
  144. # --yes: skip confirmation prompts
  145. # --prod: deploy to production URL (not preview)
  146. # --name: use the folder name as the project name
  147. DECK_NAME=$(basename "$DEPLOY_DIR")
  148. # If we used a temp dir, use the original filename without .html
  149. if [[ "$CLEANUP_TEMP" == "true" ]]; then
  150. DECK_NAME=$(basename "$INPUT" .html)
  151. fi
  152. # Sanitize project name for Vercel:
  153. # - lowercase, replace spaces/special chars with hyphens
  154. # - collapse multiple hyphens, trim to 100 chars
  155. DECK_NAME=$(echo "$DECK_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9._-]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-100)
  156. # Vercel uses the directory name as the project name, so rename the deploy
  157. # directory to the sanitized deck name (avoids deprecated --name flag)
  158. if [[ "$CLEANUP_TEMP" == "true" ]]; then
  159. RENAMED_DIR="$(dirname "$DEPLOY_DIR")/$DECK_NAME"
  160. mv "$DEPLOY_DIR" "$RENAMED_DIR"
  161. DEPLOY_DIR="$RENAMED_DIR"
  162. fi
  163. DEPLOY_OUTPUT=$($VERCEL_CMD deploy "$DEPLOY_DIR" --yes --prod 2>&1) || {
  164. err "Deployment failed:"
  165. echo "$DEPLOY_OUTPUT"
  166. [[ "$CLEANUP_TEMP" == "true" ]] && rm -rf "$DEPLOY_DIR"
  167. exit 1
  168. }
  169. # Extract the URL from output
  170. DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -o 'https://[^ ]*' | tail -1)
  171. # ─── Step 4: Success ──────────────────────────────────────
  172. echo ""
  173. echo -e "${BOLD}════════════════════════════════════════${NC}"
  174. ok "Slides deployed successfully!"
  175. echo ""
  176. echo -e " ${BOLD}Live URL:${NC} $DEPLOY_URL"
  177. echo ""
  178. echo " This URL works on any device — phones, tablets, laptops."
  179. echo " Share it via Slack, email, text, or anywhere."
  180. echo ""
  181. echo -e " ${CYAN}Tip:${NC} To take it down later, visit https://vercel.com/dashboard"
  182. echo -e " and delete the project '${DECK_NAME}'."
  183. echo -e "${BOLD}════════════════════════════════════════${NC}"
  184. echo ""
  185. # ─── Cleanup ──────────────────────────────────────────────
  186. if [[ "$CLEANUP_TEMP" == "true" ]]; then
  187. rm -rf "$DEPLOY_DIR"
  188. fi