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.
@@ -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 "$@"; }