jekyll-theme-zer0 0.22.20 → 0.22.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -4
- data/README.md +325 -40
- data/_data/README.md +1 -0
- data/_data/roadmap.yml +215 -0
- data/scripts/bin/install +717 -0
- data/scripts/bin/test +45 -2
- data/scripts/generate-roadmap.rb +200 -0
- data/scripts/generate-roadmap.sh +21 -0
- data/scripts/lib/install/README.md +63 -0
- data/scripts/lib/install/agents.sh +166 -0
- data/scripts/lib/install/ai/diagnose.sh +199 -0
- data/scripts/lib/install/ai/openai.sh +233 -0
- data/scripts/lib/install/ai/suggest.sh +182 -0
- data/scripts/lib/install/ai/wizard.sh +160 -0
- data/scripts/lib/install/config.sh +56 -0
- data/scripts/lib/install/deploy/README.md +52 -0
- data/scripts/lib/install/deploy/azure-swa.sh +50 -0
- data/scripts/lib/install/deploy/docker-prod.sh +71 -0
- data/scripts/lib/install/deploy/github-pages.sh +44 -0
- data/scripts/lib/install/deploy/registry.sh +190 -0
- data/scripts/lib/install/doctor.sh +301 -0
- data/scripts/lib/install/fs.sh +52 -0
- data/scripts/lib/install/logging.sh +33 -0
- data/scripts/lib/install/pages.sh +255 -0
- data/scripts/lib/install/platform.sh +71 -0
- data/scripts/lib/install/profile.sh +113 -0
- data/scripts/lib/install/template.sh +137 -0
- data/scripts/lib/install/upgrade.sh +184 -0
- data/scripts/lib/install/wizard_interactive.sh +189 -0
- metadata +27 -2
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/lib/install/doctor.sh
|
|
3
|
+
#
|
|
4
|
+
# `install doctor` — environment + site health check.
|
|
5
|
+
#
|
|
6
|
+
# Runs platform-specific prerequisite checks (delegating to
|
|
7
|
+
# scripts/platform/setup-{macos,linux,wsl}.sh in check-only mode), then
|
|
8
|
+
# layers zer0-mistakes-specific checks on top: gh CLI, Docker compose,
|
|
9
|
+
# Bundler/Jekyll versions, agent files, and OpenAI connectivity (opt-in).
|
|
10
|
+
#
|
|
11
|
+
# Output: structured pass/warn/fail report. Exits 0 when no FAIL,
|
|
12
|
+
# 1 when at least one FAIL.
|
|
13
|
+
#
|
|
14
|
+
# Public API:
|
|
15
|
+
# doctor_run <target_dir> <repo_root> [--ai] [--quiet] [--json]
|
|
16
|
+
#
|
|
17
|
+
# Bash 3.2-compatible. Pure shell — no jq required.
|
|
18
|
+
|
|
19
|
+
# shellcheck disable=SC2034
|
|
20
|
+
DOCTOR_LIB_VERSION="1.0.0"
|
|
21
|
+
|
|
22
|
+
# Counters (reset on every doctor_run call)
|
|
23
|
+
DOCTOR_PASS=0
|
|
24
|
+
DOCTOR_WARN=0
|
|
25
|
+
DOCTOR_FAIL=0
|
|
26
|
+
DOCTOR_REPORT=""
|
|
27
|
+
|
|
28
|
+
# Append a structured row.
|
|
29
|
+
# args: status (PASS|WARN|FAIL) name detail [remediation]
|
|
30
|
+
_doctor_row() {
|
|
31
|
+
local status="$1" name="$2" detail="$3" remediation="${4:-}"
|
|
32
|
+
case "$status" in
|
|
33
|
+
PASS) DOCTOR_PASS=$((DOCTOR_PASS+1)); log_success "$name: $detail" ;;
|
|
34
|
+
WARN) DOCTOR_WARN=$((DOCTOR_WARN+1)); log_warning "$name: $detail"; [[ -n "$remediation" ]] && log_info " → $remediation" ;;
|
|
35
|
+
FAIL) DOCTOR_FAIL=$((DOCTOR_FAIL+1)); log_error "$name: $detail"; [[ -n "$remediation" ]] && log_info " → $remediation" ;;
|
|
36
|
+
esac
|
|
37
|
+
DOCTOR_REPORT="${DOCTOR_REPORT}${status}|${name}|${detail}|${remediation}
|
|
38
|
+
"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# ── Platform checks ────────────────────────────────────────────────────────
|
|
42
|
+
_doctor_platform() {
|
|
43
|
+
local repo_root="$1"
|
|
44
|
+
local os
|
|
45
|
+
os="$(uname -s 2>/dev/null || echo unknown)"
|
|
46
|
+
|
|
47
|
+
local script=""
|
|
48
|
+
case "$os" in
|
|
49
|
+
Darwin) script="$repo_root/scripts/platform/setup-macos.sh" ;;
|
|
50
|
+
Linux)
|
|
51
|
+
# Distinguish WSL from native Linux
|
|
52
|
+
if grep -qi microsoft /proc/version 2>/dev/null; then
|
|
53
|
+
script="$repo_root/scripts/platform/setup-wsl.sh"
|
|
54
|
+
else
|
|
55
|
+
script="$repo_root/scripts/platform/setup-linux.sh"
|
|
56
|
+
fi
|
|
57
|
+
;;
|
|
58
|
+
*)
|
|
59
|
+
_doctor_row WARN "Platform" "$os not directly supported" \
|
|
60
|
+
"Doctor will only run zer0-mistakes-specific checks"
|
|
61
|
+
return 0
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
|
|
65
|
+
if [[ ! -f "$script" ]]; then
|
|
66
|
+
_doctor_row WARN "Platform script" "Not found at ${script#$repo_root/}" \
|
|
67
|
+
"Falling back to inline checks"
|
|
68
|
+
_doctor_inline_platform_checks
|
|
69
|
+
return 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
log_info "Running platform checks: $(basename "$script")"
|
|
73
|
+
# Source so we can call individual check functions; suppress its main
|
|
74
|
+
# entrypoint by setting a guard env.
|
|
75
|
+
# shellcheck source=/dev/null
|
|
76
|
+
if ! source "$script" 2>/dev/null; then
|
|
77
|
+
_doctor_row WARN "Platform script" "Failed to source" \
|
|
78
|
+
"Falling back to inline checks"
|
|
79
|
+
_doctor_inline_platform_checks
|
|
80
|
+
return 0
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Each setup script exposes check_* functions. Probe the common set.
|
|
84
|
+
local suffix=""
|
|
85
|
+
case "$os" in
|
|
86
|
+
Darwin) suffix="macos" ;;
|
|
87
|
+
Linux) suffix="linux"; grep -qi microsoft /proc/version 2>/dev/null && suffix="wsl" ;;
|
|
88
|
+
esac
|
|
89
|
+
|
|
90
|
+
if declare -F "check_git_${suffix}" >/dev/null 2>&1; then
|
|
91
|
+
if "check_git_${suffix}"; then
|
|
92
|
+
_doctor_row PASS "Git" "$(git --version 2>/dev/null | head -1)"
|
|
93
|
+
else
|
|
94
|
+
_doctor_row FAIL "Git" "Not installed" "Install via your package manager"
|
|
95
|
+
fi
|
|
96
|
+
fi
|
|
97
|
+
if declare -F "check_docker_${suffix}" >/dev/null 2>&1; then
|
|
98
|
+
if "check_docker_${suffix}"; then
|
|
99
|
+
_doctor_row PASS "Docker" "$(docker --version 2>/dev/null)"
|
|
100
|
+
elif command -v docker >/dev/null 2>&1; then
|
|
101
|
+
_doctor_row WARN "Docker" "Installed but daemon not reachable" \
|
|
102
|
+
"Start Docker Desktop / 'sudo systemctl start docker'"
|
|
103
|
+
else
|
|
104
|
+
_doctor_row WARN "Docker" "Not installed" \
|
|
105
|
+
"Optional — only needed for containerized dev"
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
if declare -F "check_ruby_${suffix}" >/dev/null 2>&1; then
|
|
109
|
+
if "check_ruby_${suffix}"; then
|
|
110
|
+
_doctor_row PASS "Ruby" "$(ruby --version 2>/dev/null)"
|
|
111
|
+
elif command -v ruby >/dev/null 2>&1; then
|
|
112
|
+
_doctor_row WARN "Ruby" "$(ruby --version 2>/dev/null) (3.0+ recommended)" \
|
|
113
|
+
"Upgrade via Homebrew/rbenv for best compatibility"
|
|
114
|
+
else
|
|
115
|
+
_doctor_row WARN "Ruby" "Not installed" \
|
|
116
|
+
"Optional — only needed for native (non-Docker) dev"
|
|
117
|
+
fi
|
|
118
|
+
fi
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Fallback when platform script is missing.
|
|
122
|
+
_doctor_inline_platform_checks() {
|
|
123
|
+
if command -v git >/dev/null 2>&1; then
|
|
124
|
+
_doctor_row PASS "Git" "$(git --version 2>/dev/null | head -1)"
|
|
125
|
+
else
|
|
126
|
+
_doctor_row FAIL "Git" "Not installed" "Required for cloning + version control"
|
|
127
|
+
fi
|
|
128
|
+
if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
|
|
129
|
+
_doctor_row PASS "Docker" "$(docker --version 2>/dev/null)"
|
|
130
|
+
else
|
|
131
|
+
_doctor_row WARN "Docker" "Not running or not installed" \
|
|
132
|
+
"Optional — needed for containerized dev"
|
|
133
|
+
fi
|
|
134
|
+
if command -v ruby >/dev/null 2>&1; then
|
|
135
|
+
_doctor_row PASS "Ruby" "$(ruby --version 2>/dev/null)"
|
|
136
|
+
else
|
|
137
|
+
_doctor_row WARN "Ruby" "Not installed" "Optional — needed for native dev"
|
|
138
|
+
fi
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# ── Tooling checks ─────────────────────────────────────────────────────────
|
|
142
|
+
_doctor_tooling() {
|
|
143
|
+
# gh CLI (used by deploy + agent flows that touch repos)
|
|
144
|
+
if command -v gh >/dev/null 2>&1; then
|
|
145
|
+
_doctor_row PASS "GitHub CLI" "$(gh --version 2>/dev/null | head -1)"
|
|
146
|
+
else
|
|
147
|
+
_doctor_row WARN "GitHub CLI" "Not installed" \
|
|
148
|
+
"Optional — install from https://cli.github.com for repo automation"
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# Docker Compose v2
|
|
152
|
+
if docker compose version >/dev/null 2>&1; then
|
|
153
|
+
_doctor_row PASS "Docker Compose" "$(docker compose version --short 2>/dev/null)"
|
|
154
|
+
elif command -v docker-compose >/dev/null 2>&1; then
|
|
155
|
+
_doctor_row WARN "Docker Compose" "v1 detected ($(docker-compose --version 2>/dev/null))" \
|
|
156
|
+
"Upgrade to v2: docker compose plugin"
|
|
157
|
+
else
|
|
158
|
+
_doctor_row WARN "Docker Compose" "Not available" \
|
|
159
|
+
"Optional — needed for 'docker compose up'"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# Bundler
|
|
163
|
+
if command -v bundle >/dev/null 2>&1; then
|
|
164
|
+
# bundle --version may fail when run inside a dir with a Gemfile.lock
|
|
165
|
+
# pinning a different bundler. Probe in a neutral cwd to avoid noise.
|
|
166
|
+
local bv
|
|
167
|
+
bv="$(cd / && bundle --version 2>/dev/null | head -1)"
|
|
168
|
+
if [[ -n "$bv" ]]; then
|
|
169
|
+
_doctor_row PASS "Bundler" "$bv"
|
|
170
|
+
else
|
|
171
|
+
_doctor_row WARN "Bundler" "Installed but version probe failed" \
|
|
172
|
+
"Likely Gemfile.lock pins an unavailable bundler — run 'bundle update --bundler'"
|
|
173
|
+
fi
|
|
174
|
+
else
|
|
175
|
+
_doctor_row WARN "Bundler" "Not installed" \
|
|
176
|
+
"Install: gem install bundler (only needed for native dev)"
|
|
177
|
+
fi
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# ── Site checks (run inside target_dir) ────────────────────────────────────
|
|
181
|
+
_doctor_site() {
|
|
182
|
+
local target_dir="$1"
|
|
183
|
+
|
|
184
|
+
if [[ ! -d "$target_dir" ]]; then
|
|
185
|
+
_doctor_row FAIL "Target dir" "Does not exist: $target_dir" "Run 'install init' first"
|
|
186
|
+
return
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
if [[ -f "$target_dir/_config.yml" ]]; then
|
|
190
|
+
_doctor_row PASS "_config.yml" "Present"
|
|
191
|
+
else
|
|
192
|
+
_doctor_row WARN "_config.yml" "Missing in $target_dir" \
|
|
193
|
+
"Run 'install init' to scaffold a site"
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
if [[ -f "$target_dir/Gemfile" ]]; then
|
|
197
|
+
_doctor_row PASS "Gemfile" "Present"
|
|
198
|
+
else
|
|
199
|
+
_doctor_row WARN "Gemfile" "Missing" "Run 'install init' or 'install deploy'"
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
if [[ -f "$target_dir/AGENTS.md" ]]; then
|
|
203
|
+
_doctor_row PASS "AI agent files" "AGENTS.md present"
|
|
204
|
+
else
|
|
205
|
+
_doctor_row WARN "AI agent files" "AGENTS.md not installed" \
|
|
206
|
+
"Run 'install agents' to add AI guidance"
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
# Basic _config.yml sanity
|
|
210
|
+
if [[ -f "$target_dir/_config.yml" ]]; then
|
|
211
|
+
if grep -qE "^(remote_theme|theme):" "$target_dir/_config.yml" 2>/dev/null; then
|
|
212
|
+
_doctor_row PASS "Theme config" "remote_theme/theme set in _config.yml"
|
|
213
|
+
else
|
|
214
|
+
_doctor_row WARN "Theme config" "Neither 'theme' nor 'remote_theme' found" \
|
|
215
|
+
"Set 'remote_theme: bamr87/zer0-mistakes' or 'theme: jekyll-theme-zer0'"
|
|
216
|
+
fi
|
|
217
|
+
fi
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
# ── AI connectivity (opt-in) ───────────────────────────────────────────────
|
|
221
|
+
_doctor_ai_connectivity() {
|
|
222
|
+
if [[ "${ZER0_NO_AI:-0}" = "1" ]]; then
|
|
223
|
+
_doctor_row WARN "OpenAI connectivity" "Skipped (ZER0_NO_AI=1)" \
|
|
224
|
+
"Unset ZER0_NO_AI to enable AI checks"
|
|
225
|
+
return
|
|
226
|
+
fi
|
|
227
|
+
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
|
|
228
|
+
_doctor_row WARN "OpenAI API key" "OPENAI_API_KEY not set" \
|
|
229
|
+
"Export OPENAI_API_KEY to enable AI features"
|
|
230
|
+
return
|
|
231
|
+
fi
|
|
232
|
+
# Lightweight ping: check we can reach the API and the key authenticates.
|
|
233
|
+
local http_code
|
|
234
|
+
http_code="$(curl -sS -o /dev/null -w '%{http_code}' \
|
|
235
|
+
--max-time 10 \
|
|
236
|
+
-H "Authorization: Bearer ${OPENAI_API_KEY}" \
|
|
237
|
+
https://api.openai.com/v1/models 2>/dev/null || echo "000")"
|
|
238
|
+
case "$http_code" in
|
|
239
|
+
200) _doctor_row PASS "OpenAI connectivity" "Authenticated (HTTP 200)" ;;
|
|
240
|
+
401) _doctor_row FAIL "OpenAI connectivity" "Authentication failed (HTTP 401)" \
|
|
241
|
+
"Verify OPENAI_API_KEY is valid" ;;
|
|
242
|
+
000) _doctor_row WARN "OpenAI connectivity" "No network response" \
|
|
243
|
+
"Check internet connection / firewall" ;;
|
|
244
|
+
*) _doctor_row WARN "OpenAI connectivity" "Unexpected response (HTTP $http_code)" \
|
|
245
|
+
"Inspect with: curl -v https://api.openai.com/v1/models" ;;
|
|
246
|
+
esac
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# ── Public entrypoint ──────────────────────────────────────────────────────
|
|
250
|
+
doctor_run() {
|
|
251
|
+
local target_dir="$1" repo_root="$2"
|
|
252
|
+
shift 2 || true
|
|
253
|
+
|
|
254
|
+
local check_ai=0 quiet=0 emit_json=0
|
|
255
|
+
while [[ $# -gt 0 ]]; do
|
|
256
|
+
case "$1" in
|
|
257
|
+
--ai) check_ai=1 ;;
|
|
258
|
+
--quiet) quiet=1 ;;
|
|
259
|
+
--json) emit_json=1 ;;
|
|
260
|
+
*) log_warning "doctor_run: ignoring unknown flag: $1" ;;
|
|
261
|
+
esac
|
|
262
|
+
shift
|
|
263
|
+
done
|
|
264
|
+
|
|
265
|
+
DOCTOR_PASS=0; DOCTOR_WARN=0; DOCTOR_FAIL=0; DOCTOR_REPORT=""
|
|
266
|
+
|
|
267
|
+
[[ "$quiet" = "1" ]] || log_info "🩺 Running zer0-mistakes doctor..."
|
|
268
|
+
[[ "$quiet" = "1" ]] || echo
|
|
269
|
+
|
|
270
|
+
[[ "$quiet" = "1" ]] || log_info "── Platform ─────────────────────────────"
|
|
271
|
+
_doctor_platform "$repo_root"
|
|
272
|
+
[[ "$quiet" = "1" ]] || echo
|
|
273
|
+
|
|
274
|
+
[[ "$quiet" = "1" ]] || log_info "── Tooling ──────────────────────────────"
|
|
275
|
+
_doctor_tooling
|
|
276
|
+
[[ "$quiet" = "1" ]] || echo
|
|
277
|
+
|
|
278
|
+
[[ "$quiet" = "1" ]] || log_info "── Site ($target_dir) ───"
|
|
279
|
+
_doctor_site "$target_dir"
|
|
280
|
+
[[ "$quiet" = "1" ]] || echo
|
|
281
|
+
|
|
282
|
+
if [[ "$check_ai" = "1" ]]; then
|
|
283
|
+
[[ "$quiet" = "1" ]] || log_info "── AI ────────────────────────────────────"
|
|
284
|
+
_doctor_ai_connectivity
|
|
285
|
+
[[ "$quiet" = "1" ]] || echo
|
|
286
|
+
fi
|
|
287
|
+
|
|
288
|
+
if [[ "$emit_json" = "1" ]]; then
|
|
289
|
+
# Emit a tiny JSON summary — no jq, just printf.
|
|
290
|
+
printf '{"pass":%d,"warn":%d,"fail":%d}\n' \
|
|
291
|
+
"$DOCTOR_PASS" "$DOCTOR_WARN" "$DOCTOR_FAIL"
|
|
292
|
+
else
|
|
293
|
+
log_info "── Summary ──────────────────────────────"
|
|
294
|
+
log_info " ✅ PASS: $DOCTOR_PASS"
|
|
295
|
+
log_info " ⚠️ WARN: $DOCTOR_WARN"
|
|
296
|
+
log_info " ❌ FAIL: $DOCTOR_FAIL"
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
[[ "$DOCTOR_FAIL" = "0" ]] && return 0
|
|
300
|
+
return 1
|
|
301
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =========================================================================
|
|
3
|
+
# scripts/lib/install/fs.sh
|
|
4
|
+
# =========================================================================
|
|
5
|
+
# Filesystem helpers for install.sh: idempotent file/directory copy with
|
|
6
|
+
# automatic timestamped backups when destination already exists.
|
|
7
|
+
#
|
|
8
|
+
# Required globals (set by install.sh before sourcing/use):
|
|
9
|
+
# $TARGET_DIR — used to compute relative paths in log messages
|
|
10
|
+
#
|
|
11
|
+
# Functions exported:
|
|
12
|
+
# copy_file_with_backup SRC DEST
|
|
13
|
+
# copy_directory_with_backup SRC DEST
|
|
14
|
+
# =========================================================================
|
|
15
|
+
|
|
16
|
+
# Copy a file, backing up the destination if it already exists.
|
|
17
|
+
copy_file_with_backup() {
|
|
18
|
+
local src="$1"
|
|
19
|
+
local dest="$2"
|
|
20
|
+
local relative_path="${dest#${TARGET_DIR:-}/}"
|
|
21
|
+
|
|
22
|
+
# Create destination directory if it doesn't exist
|
|
23
|
+
mkdir -p "$(dirname "$dest")"
|
|
24
|
+
|
|
25
|
+
# Backup existing file if it exists
|
|
26
|
+
if [[ -f "$dest" ]]; then
|
|
27
|
+
local backup_file="${dest}.backup.$(date +%Y%m%d_%H%M%S)"
|
|
28
|
+
log_warning "File exists, creating backup: $relative_path -> ${backup_file##*/}"
|
|
29
|
+
cp "$dest" "$backup_file"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Copy the file
|
|
33
|
+
cp "$src" "$dest"
|
|
34
|
+
log_info "Copied: $relative_path"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Copy a directory, backing up the destination if it already exists.
|
|
38
|
+
copy_directory_with_backup() {
|
|
39
|
+
local src="$1"
|
|
40
|
+
local dest="$2"
|
|
41
|
+
local relative_path="${dest#${TARGET_DIR:-}/}"
|
|
42
|
+
|
|
43
|
+
if [[ -d "$dest" ]]; then
|
|
44
|
+
local backup_dir="${dest}.backup.$(date +%Y%m%d_%H%M%S)"
|
|
45
|
+
log_warning "Directory exists, creating backup: $relative_path -> ${backup_dir##*/}"
|
|
46
|
+
cp -r "$dest" "$backup_dir"
|
|
47
|
+
rm -rf "$dest"
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
cp -r "$src" "$dest"
|
|
51
|
+
log_info "Copied directory: $relative_path"
|
|
52
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =========================================================================
|
|
3
|
+
# scripts/lib/install/logging.sh
|
|
4
|
+
# =========================================================================
|
|
5
|
+
# Logging shim for install.sh. Provides log_info / log_success /
|
|
6
|
+
# log_warning / log_error names used throughout install.sh while
|
|
7
|
+
# delegating to scripts/lib/common.sh primitives where available.
|
|
8
|
+
#
|
|
9
|
+
# WHY a shim instead of a direct sed-rename?
|
|
10
|
+
# - install.sh has ~300+ call sites to log_info/log_success/log_warning/log_error
|
|
11
|
+
# - Common.sh uses different verbs (info/success/warn/error) and `error` exits
|
|
12
|
+
# - A thin shim preserves behavior exactly while letting future code use
|
|
13
|
+
# either vocabulary.
|
|
14
|
+
#
|
|
15
|
+
# Source order requirement:
|
|
16
|
+
# This file must be sourced AFTER scripts/lib/common.sh so the
|
|
17
|
+
# colour variables (RED/GREEN/YELLOW/BLUE/NC) are defined.
|
|
18
|
+
#
|
|
19
|
+
# Compatibility: bash 3.2+ (macOS default)
|
|
20
|
+
# =========================================================================
|
|
21
|
+
|
|
22
|
+
# Define colours if common.sh wasn't sourced (safe defaults).
|
|
23
|
+
RED="${RED:-\033[0;31m}"
|
|
24
|
+
GREEN="${GREEN:-\033[0;32m}"
|
|
25
|
+
YELLOW="${YELLOW:-\033[1;33m}"
|
|
26
|
+
BLUE="${BLUE:-\033[0;34m}"
|
|
27
|
+
NC="${NC:-\033[0m}"
|
|
28
|
+
|
|
29
|
+
# install.sh-style logging — identical output to the original block.
|
|
30
|
+
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
31
|
+
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
|
32
|
+
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
|
33
|
+
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/lib/install/pages.sh
|
|
3
|
+
#
|
|
4
|
+
# Starter-page generator for jekyll-theme-zer0 installations.
|
|
5
|
+
# Replaces 8 near-identical create_*_page heredoc functions with a single
|
|
6
|
+
# manifest-driven renderer.
|
|
7
|
+
#
|
|
8
|
+
# Required env (from install.conf via config.sh):
|
|
9
|
+
# TARGET_DIR, THEME_NAME, THEME_DISPLAY_NAME, DEFAULT_URL, GITHUB_URL
|
|
10
|
+
#
|
|
11
|
+
# Required functions (from template.sh):
|
|
12
|
+
# create_from_template <template_relpath> <dest_abspath> <fallback_content>
|
|
13
|
+
#
|
|
14
|
+
# Public API:
|
|
15
|
+
# render_starter_pages - generate all default pages + admin
|
|
16
|
+
# render_admin_settings_pages - generate just the _about/settings/* pages
|
|
17
|
+
|
|
18
|
+
# ---------- Manifest --------------------------------------------------------
|
|
19
|
+
# Format (pipe-separated, no spaces around |):
|
|
20
|
+
# <template_relpath>|<dest_relpath>|<mkdir_relpath>|<fallback_func>
|
|
21
|
+
# Empty <mkdir_relpath> = no mkdir; empty <fallback_func> = no fallback.
|
|
22
|
+
_starter_pages_manifest() {
|
|
23
|
+
cat <<'MANIFEST'
|
|
24
|
+
pages/quickstart.md.template|pages/quickstart/index.md|pages/quickstart|_fallback_quickstart
|
|
25
|
+
pages/docs-index.md.template|pages/_docs/index.md|pages/_docs|_fallback_docs_index
|
|
26
|
+
pages/configuration.md.template|pages/_docs/configuration/index.md|pages/_docs/configuration|
|
|
27
|
+
pages/troubleshooting.md.template|pages/_docs/troubleshooting.md|pages/_docs|
|
|
28
|
+
pages/about.md.template|pages/_about/index.md|pages/_about|_fallback_about
|
|
29
|
+
pages/blog.md.template|pages/blog.md||_fallback_blog
|
|
30
|
+
MANIFEST
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_admin_settings_pages() {
|
|
34
|
+
echo "theme config navigation collections analytics environment"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# ---------- Fallback content (only used when template missing) --------------
|
|
38
|
+
_fallback_quickstart() {
|
|
39
|
+
cat <<EOF
|
|
40
|
+
---
|
|
41
|
+
layout: default
|
|
42
|
+
title: Quick Start
|
|
43
|
+
permalink: /quickstart/
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Quick Start Guide
|
|
47
|
+
|
|
48
|
+
Get your site up and running in just a few minutes!
|
|
49
|
+
|
|
50
|
+
## Prerequisites
|
|
51
|
+
|
|
52
|
+
Before you begin, make sure you have:
|
|
53
|
+
|
|
54
|
+
- **Docker Desktop** installed ([download](https://www.docker.com/products/docker-desktop))
|
|
55
|
+
- **Git** installed ([download](https://git-scm.com/))
|
|
56
|
+
|
|
57
|
+
## 1. Start Development Server
|
|
58
|
+
|
|
59
|
+
### Using Docker (Recommended)
|
|
60
|
+
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
docker-compose up
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
Your site will be available at **${DEFAULT_URL}**
|
|
66
|
+
|
|
67
|
+
### Using Local Ruby
|
|
68
|
+
|
|
69
|
+
\`\`\`bash
|
|
70
|
+
bundle install
|
|
71
|
+
bundle exec jekyll serve
|
|
72
|
+
\`\`\`
|
|
73
|
+
|
|
74
|
+
## 2. Customize Your Site
|
|
75
|
+
|
|
76
|
+
Edit \`_config.yml\` to personalize your site:
|
|
77
|
+
|
|
78
|
+
\`\`\`yaml
|
|
79
|
+
title: Your Site Title
|
|
80
|
+
description: Your site description
|
|
81
|
+
author: Your Name
|
|
82
|
+
\`\`\`
|
|
83
|
+
|
|
84
|
+
## 3. Add Content
|
|
85
|
+
|
|
86
|
+
- Create posts in \`pages/_posts/\`
|
|
87
|
+
- Create documentation in \`pages/_docs/\`
|
|
88
|
+
- Add static pages in \`pages/\`
|
|
89
|
+
|
|
90
|
+
## Next Steps
|
|
91
|
+
|
|
92
|
+
- [Read the Documentation](/docs/) - Learn about all features
|
|
93
|
+
- [Explore Configuration](/docs/configuration/) - Customize your site
|
|
94
|
+
- [Learn about Layouts](/docs/layouts/) - Understand page layouts
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
Need help? Check the [troubleshooting guide](/docs/troubleshooting/) or [open an issue](${GITHUB_URL}/issues).
|
|
99
|
+
EOF
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
_fallback_docs_index() {
|
|
103
|
+
cat <<EOF
|
|
104
|
+
---
|
|
105
|
+
layout: default
|
|
106
|
+
title: Documentation
|
|
107
|
+
permalink: /docs/
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
# Documentation
|
|
111
|
+
|
|
112
|
+
Welcome to the ${THEME_NAME} theme documentation. Here you'll find everything you need to build and customize your Jekyll site.
|
|
113
|
+
|
|
114
|
+
## Getting Started
|
|
115
|
+
|
|
116
|
+
<div class="row">
|
|
117
|
+
<div class="col-md-6 mb-3">
|
|
118
|
+
|
|
119
|
+
### Installation
|
|
120
|
+
|
|
121
|
+
The theme supports multiple installation methods:
|
|
122
|
+
|
|
123
|
+
- **Docker** (Recommended) - Zero dependencies
|
|
124
|
+
- **Remote Theme** - For GitHub Pages
|
|
125
|
+
- **Gem** - Traditional Ruby installation
|
|
126
|
+
|
|
127
|
+
[View Installation Guide →](/quickstart/)
|
|
128
|
+
|
|
129
|
+
</div>
|
|
130
|
+
<div class="col-md-6 mb-3">
|
|
131
|
+
|
|
132
|
+
### Configuration
|
|
133
|
+
|
|
134
|
+
Customize your site with \`_config.yml\`:
|
|
135
|
+
|
|
136
|
+
- Site title and description
|
|
137
|
+
- Navigation menus
|
|
138
|
+
- Social links
|
|
139
|
+
- Analytics integration
|
|
140
|
+
|
|
141
|
+
[View Configuration Guide →](/docs/configuration/)
|
|
142
|
+
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
## Need Help?
|
|
147
|
+
|
|
148
|
+
- [Troubleshooting Guide](/docs/troubleshooting/)
|
|
149
|
+
- [GitHub Issues](${GITHUB_URL}/issues)
|
|
150
|
+
- [GitHub Discussions](${GITHUB_URL}/discussions)
|
|
151
|
+
EOF
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
_fallback_about() {
|
|
155
|
+
cat <<EOF
|
|
156
|
+
---
|
|
157
|
+
layout: default
|
|
158
|
+
title: About
|
|
159
|
+
permalink: /about/
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
# About This Site
|
|
163
|
+
|
|
164
|
+
This site is built with the **${THEME_DISPLAY_NAME}** - a professional Jekyll theme designed for GitHub Pages with Bootstrap 5.3.
|
|
165
|
+
|
|
166
|
+
## Theme Features
|
|
167
|
+
|
|
168
|
+
- ✅ Bootstrap 5.3 integration
|
|
169
|
+
- ✅ Dark/Light mode toggle
|
|
170
|
+
- ✅ Docker support
|
|
171
|
+
- ✅ GitHub Pages compatible
|
|
172
|
+
- ✅ SEO optimized
|
|
173
|
+
|
|
174
|
+
## Learn More
|
|
175
|
+
|
|
176
|
+
- [Theme Documentation](/docs/)
|
|
177
|
+
- [GitHub Repository](${GITHUB_URL})
|
|
178
|
+
- [Report an Issue](${GITHUB_URL}/issues)
|
|
179
|
+
|
|
180
|
+
## Customizing This Page
|
|
181
|
+
|
|
182
|
+
Edit \`pages/_about/index.md\` to customize this page with your own content.
|
|
183
|
+
EOF
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
_fallback_blog() {
|
|
187
|
+
cat <<'EOF'
|
|
188
|
+
---
|
|
189
|
+
layout: default
|
|
190
|
+
title: Blog
|
|
191
|
+
permalink: /blog/
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
# Blog
|
|
195
|
+
|
|
196
|
+
Welcome to the blog. Create your first post to get started!
|
|
197
|
+
|
|
198
|
+
## Creating Posts
|
|
199
|
+
|
|
200
|
+
Create markdown files in `pages/_posts/` with the format:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
YYYY-MM-DD-your-post-title.md
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Recent Posts
|
|
207
|
+
|
|
208
|
+
{% for post in site.posts limit:5 %}
|
|
209
|
+
- [{{ post.title }}]({{ post.url }}) - {{ post.date | date: "%B %d, %Y" }}
|
|
210
|
+
{% endfor %}
|
|
211
|
+
|
|
212
|
+
{% if site.posts.size == 0 %}
|
|
213
|
+
*No posts yet. Create your first post to see it here!*
|
|
214
|
+
{% endif %}
|
|
215
|
+
EOF
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# ---------- Public renderers ------------------------------------------------
|
|
219
|
+
render_admin_settings_pages() {
|
|
220
|
+
local admin_dir="$TARGET_DIR/pages/_about/settings"
|
|
221
|
+
mkdir -p "$admin_dir"
|
|
222
|
+
|
|
223
|
+
log_info "Creating admin settings pages..."
|
|
224
|
+
local page
|
|
225
|
+
for page in $(_admin_settings_pages); do
|
|
226
|
+
create_from_template "pages/admin/${page}.md.template" "$admin_dir/${page}.md" ""
|
|
227
|
+
done
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
render_starter_pages() {
|
|
231
|
+
log_info "Creating essential starter pages..."
|
|
232
|
+
mkdir -p "$TARGET_DIR/pages"
|
|
233
|
+
|
|
234
|
+
local tmpl dest mkdir_rel fb_func fallback
|
|
235
|
+
while IFS='|' read -r tmpl dest mkdir_rel fb_func; do
|
|
236
|
+
[ -z "$tmpl" ] && continue
|
|
237
|
+
[ -n "$mkdir_rel" ] && mkdir -p "$TARGET_DIR/$mkdir_rel"
|
|
238
|
+
if [ -n "$fb_func" ] && declare -f "$fb_func" >/dev/null 2>&1; then
|
|
239
|
+
fallback="$("$fb_func")"
|
|
240
|
+
else
|
|
241
|
+
fallback=""
|
|
242
|
+
fi
|
|
243
|
+
create_from_template "$tmpl" "$TARGET_DIR/$dest" "$fallback"
|
|
244
|
+
done <<MANIFEST_EOF
|
|
245
|
+
$(_starter_pages_manifest)
|
|
246
|
+
MANIFEST_EOF
|
|
247
|
+
|
|
248
|
+
render_admin_settings_pages
|
|
249
|
+
|
|
250
|
+
log_success "Starter pages created"
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# Backward-compatible aliases (legacy install.sh call sites)
|
|
254
|
+
create_starter_pages() { render_starter_pages "$@"; }
|
|
255
|
+
create_admin_pages() { render_admin_settings_pages "$@"; }
|