jekyll-theme-zer0 1.28.0 → 1.30.0
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 +1143 -13
- data/_data/README.md +2 -0
- data/_data/ai.yml +5 -3
- data/_data/ai_pricing.yml +36 -0
- data/_data/backlog.yml +507 -2
- data/_data/consumers.yml +157 -9
- data/_data/features.yml +303 -20
- data/_data/feedback_types.yml +17 -12
- data/_data/i18n/fr.yml +12 -7
- data/_data/i18n/manifest.yml +39 -12
- data/_data/ingredient_densities.yml +122 -0
- data/_data/landing.yml +5 -2
- data/_data/navigation/main.yml +16 -0
- data/_data/navigation/quickstart.yml +4 -0
- data/_data/recipe_courses.yml +64 -0
- data/_data/site_builder.yml +874 -0
- data/_data/theme-manifest.yml +160 -124
- data/_data/ui-text.yml +26 -0
- data/_includes/README.md +26 -2
- data/_includes/analytics/posthog.html +2 -2
- data/_includes/components/admin-links.html +2 -2
- data/_includes/components/admin-tabs.html +2 -2
- data/_includes/components/ai-chat.html +14 -11
- data/_includes/components/analytics-dashboard.html +8 -8
- data/_includes/components/author-bio.html +1 -1
- data/_includes/components/author-card.html +10 -2
- data/_includes/components/author-eeat.html +4 -4
- data/_includes/components/background-customizer.html +10 -10
- data/_includes/components/background-image.html +114 -0
- data/_includes/components/background-settings.html +28 -15
- data/_includes/components/collection-manager.html +5 -5
- data/_includes/components/component-showcase.html +13 -13
- data/_includes/components/config-editor.html +12 -12
- data/_includes/components/config-viewer.html +8 -8
- data/_includes/components/cookie-consent.html +15 -15
- data/_includes/components/cta-button.html +7 -2
- data/_includes/components/dev-shortcuts.html +7 -7
- data/_includes/components/env-dashboard.html +8 -8
- data/_includes/components/env-switcher.html +9 -9
- data/_includes/components/feature-card.html +2 -2
- data/_includes/components/halfmoon.html +2 -2
- data/_includes/components/info-section.html +42 -37
- data/_includes/components/js-cdn.html +15 -15
- data/_includes/components/language-toggle.html +168 -21
- data/_includes/components/mermaid.html +72 -435
- data/_includes/components/nanobar.html +5 -5
- data/_includes/components/nav-editor.html +2 -2
- data/_includes/components/nav-export.html +2 -2
- data/_includes/components/nav-overview.html +2 -2
- data/_includes/components/page-feedback.html +45 -30
- data/_includes/components/page-views-init.html +55 -0
- data/_includes/components/page-views.html +33 -0
- data/_includes/components/post-card.html +22 -22
- data/_includes/components/post-type-badge.html +2 -2
- data/_includes/components/powered-by.html +2 -2
- data/_includes/components/preview-image.html +6 -0
- data/_includes/components/quick-index.html +2 -2
- data/_includes/components/recipe-card.html +67 -0
- data/_includes/components/recipe-duration.html +50 -0
- data/_includes/components/recipe-grams.html +58 -0
- data/_includes/components/recipe-index.html +96 -0
- data/_includes/components/recipe-ingredients.html +90 -0
- data/_includes/components/recipe-meta.html +96 -0
- data/_includes/components/recipe-nutrition.html +57 -0
- data/_includes/components/recipe-qty.html +73 -0
- data/_includes/components/recipe-ratio.html +151 -0
- data/_includes/components/recipe-scaler.html +73 -0
- data/_includes/components/recipe-steps.html +86 -0
- data/_includes/components/recipe-temp.html +45 -0
- data/_includes/components/search-modal.html +29 -4
- data/_includes/components/searchbar.html +2 -2
- data/_includes/components/shortcuts-modal.html +3 -0
- data/_includes/components/svg-background.html +2 -2
- data/_includes/components/theme-customizer.html +2 -2
- data/_includes/components/theme-info.html +14 -7
- data/_includes/components/theme-preview-gallery.html +22 -22
- data/_includes/content/giscus.html +2 -2
- data/_includes/content/intro.html +8 -8
- data/_includes/content/jsonld-faq.html +2 -2
- data/_includes/content/jsonld-software.html +24 -5
- data/_includes/content/seo.html +4 -4
- data/_includes/content/sitemap.html +27 -27
- data/_includes/content/toc.html +183 -183
- data/_includes/core/branding.html +6 -6
- data/_includes/core/console-capture.html +32 -74
- data/_includes/core/favicon.html +49 -7
- data/_includes/core/footer-fabs.html +17 -3
- data/_includes/core/footer.html +49 -34
- data/_includes/core/head.html +110 -86
- data/_includes/core/header.html +76 -54
- data/_includes/docs/bootstrap-docs.html +8 -8
- data/_includes/landing/landing-install-cards.html +2 -2
- data/_includes/landing/landing-quick-links.html +1 -1
- data/_includes/navigation/admin-nav.html +2 -2
- data/_includes/navigation/nav-tree.html +8 -8
- data/_includes/navigation/navbar.html +12 -12
- data/_includes/navigation/section-sidebar.html +109 -27
- data/_includes/navigation/sidebar-config.html +36 -2
- data/_includes/navigation/sidebar-left.html +17 -16
- data/_includes/navigation/sidebar-right.html +8 -7
- data/_includes/obsidian/full-graph.html +2 -2
- data/_includes/setup/claude-session.html +72 -0
- data/_includes/setup/prereq-checklist.html +90 -0
- data/_includes/setup/wizard.html +924 -222
- data/_includes/stats/stats-categories.html +8 -8
- data/_includes/stats/stats-header.html +14 -14
- data/_includes/stats/stats-metrics.html +14 -14
- data/_includes/stats/stats-no-data.html +12 -12
- data/_includes/stats/stats-overview.html +6 -6
- data/_includes/stats/stats-tags.html +8 -8
- data/_layouts/404.html +38 -24
- data/_layouts/README.md +2 -0
- data/_layouts/admin.html +24 -24
- data/_layouts/article.html +43 -33
- data/_layouts/author.html +20 -20
- data/_layouts/authors.html +2 -2
- data/_layouts/book-abc.html +12 -12
- data/_layouts/book-story.html +15 -15
- data/_layouts/book.html +12 -12
- data/_layouts/collection.html +33 -33
- data/_layouts/cookbook.html +88 -0
- data/_layouts/default.html +31 -28
- data/_layouts/home.html +23 -23
- data/_layouts/index.html +10 -10
- data/_layouts/landing.html +17 -17
- data/_layouts/news.html +44 -44
- data/_layouts/note.html +38 -38
- data/_layouts/notebook.html +34 -34
- data/_layouts/recipe.html +274 -0
- data/_layouts/root.html +92 -55
- data/_layouts/section.html +62 -33
- data/_layouts/setup.html +3 -3
- data/_layouts/sitemap-collection.html +49 -49
- data/_layouts/stats.html +40 -40
- data/_layouts/tag.html +12 -12
- data/_layouts/welcome.html +21 -21
- data/_sass/components/_callout.scss +1 -1
- data/_sass/components/_footer.scss +37 -1
- data/_sass/components/_mermaid.scss +375 -0
- data/_sass/components/_page-views.scss +36 -0
- data/_sass/components/_recipe.scss +506 -0
- data/_sass/components/_setup-wizard.scss +764 -0
- data/_sass/components/_ui-enhancements.scss +6 -6
- data/_sass/core/_navbar.scss +261 -46
- data/_sass/layouts/_landing.scss +2 -2
- data/_sass/layouts/_navbar-extras.scss +14 -4
- data/_sass/tokens/_color.scss +6 -0
- data/_sass/tokens/_index.scss +2 -0
- data/_sass/tokens/_radius.scss +21 -0
- data/_sass/tokens/_typography.scss +4 -0
- data/_sass/utilities/_focus.scss +14 -0
- data/assets/css/main.scss +4 -0
- data/assets/js/ai-chat.js +47 -5
- data/assets/js/fleet-feedback-capture.js +124 -0
- data/assets/js/fleet-feedback.js +853 -0
- data/assets/js/mermaid-diagrams.js +1267 -0
- data/assets/js/modules/navigation/config.js +9 -6
- data/assets/js/modules/navigation/navbar.js +55 -0
- data/assets/js/modules/navigation/scroll-spy.js +315 -80
- data/assets/js/modules/theme/appearance.js +8 -2
- data/assets/js/obsidian-wiki-links.js +8 -3
- data/assets/js/page-feedback.js +125 -192
- data/assets/js/page-views.js +372 -0
- data/assets/js/recipe-scaler.js +501 -0
- data/assets/js/search-modal.js +36 -0
- data/assets/js/setup-wizard.js +2279 -226
- data/assets/js/site-builder.js +1834 -0
- data/assets/js/ui-enhancements.js +11 -3
- data/scripts/README.md +44 -0
- data/scripts/ai/README.md +38 -0
- data/scripts/ai/api_call.rb +124 -0
- data/scripts/ai/usage.rb +314 -0
- data/scripts/ai/usage_report.rb +225 -0
- data/scripts/bin/audit-consumer +39 -7
- data/scripts/bin/giscus-discussions +213 -14
- data/scripts/bin/manifest +35 -12
- data/scripts/ci/agent_review_result.py +164 -0
- data/scripts/ci/test_agent_review_result.py +172 -0
- data/scripts/ci/test_visual_evidence_autogen.py +341 -0
- data/scripts/ci/visual_evidence_autogen.py +1060 -0
- data/scripts/content-review.rb +20 -1
- data/scripts/design-system-check.rb +170 -0
- data/scripts/lib/audit.sh +42 -2
- data/scripts/lint-liquid-raw.rb +137 -0
- data/scripts/test/integration/mermaid +22 -8
- data/scripts/test/lib/run_tests.sh +3 -1
- data/scripts/test/lib/test_agent_review_result.sh +27 -0
- data/scripts/test/lib/test_visual_evidence_autogen.sh +24 -0
- data/scripts/translate.rb +94 -16
- metadata +48 -2
data/_includes/setup/wizard.html
CHANGED
|
@@ -1,331 +1,1033 @@
|
|
|
1
|
-
{% comment %} Feature: ZER0-067 {% endcomment %}
|
|
2
|
-
|
|
1
|
+
{% comment %} Feature: ZER0-067, ZER0-086, ZER0-087 {% endcomment %}
|
|
2
|
+
{% comment %}
|
|
3
3
|
===================================================================
|
|
4
|
-
|
|
4
|
+
SITE BUILDER — guided, Claude-assisted site setup wizard
|
|
5
5
|
===================================================================
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Path:
|
|
9
|
-
Purpose:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
Component: setup/wizard
|
|
8
|
+
Path: _includes/setup/wizard.html
|
|
9
|
+
Purpose: Nine-step wizard that takes a reader from "nothing installed"
|
|
10
|
+
to a complete, personalised zer0-mistakes site: prerequisites,
|
|
11
|
+
identity, URLs, structure, appearance, voice, integrations and
|
|
12
|
+
a Build step that writes the project and starts Docker — with
|
|
13
|
+
an embedded AI session (Claude or Grok, the user's own token)
|
|
14
|
+
that can read the form, fill it in, read the theme's real
|
|
15
|
+
source, drive the build, and — in an open session — modify an
|
|
16
|
+
existing site file by file and generate images for it.
|
|
17
|
+
Params: none — configured via site.site_builder + site.ai_chat, data
|
|
18
|
+
from _data/site_builder.yml
|
|
19
|
+
Depends on: Bootstrap 5.3, Bootstrap Icons, assets/js/setup-wizard.js
|
|
20
|
+
(form, generators, drafts), assets/js/site-builder.js (Claude
|
|
21
|
+
session + dev-proxy tools), _sass/components/_setup-wizard.scss,
|
|
22
|
+
setup/prereq-checklist.html, setup/claude-session.html
|
|
23
|
+
Notes:
|
|
24
|
+
- Works with NO proxy at all: the form, every generated file, per-file
|
|
25
|
+
download and the self-extracting bundle are pure client-side, so a
|
|
26
|
+
GitHub Pages consumer on the welcome layout still gets a full wizard.
|
|
27
|
+
Live prerequisite checks, "Write project" and the Docker actions
|
|
28
|
+
light up when the local dev proxy answers GET
|
|
29
|
+
{site_builder.endpoint}/status; the AI panel lights up once the
|
|
30
|
+
chosen provider has a credential — from .env, or pasted on the
|
|
31
|
+
Connect step (sent once to the localhost proxy, never stored in the
|
|
32
|
+
page). See templates/deploy/chat-proxy/.
|
|
33
|
+
- Layout at lg+: stepper (2) · steps (6) · side column (4) holding the
|
|
34
|
+
Claude session on top and the live file preview underneath, so every
|
|
35
|
+
answer and every generated file stays in view on every step.
|
|
36
|
+
- Stable-height contract (T-040 / #408): `.wizard-panes` is a CSS grid
|
|
37
|
+
with every pane in one cell; `.wizard-nav` is pinned with mt-auto. Do
|
|
38
|
+
not put inactive panes back on display:none — see _setup-wizard.scss.
|
|
39
|
+
- Draft persistence: every field, switch and check is mirrored to
|
|
40
|
+
localStorage under `zer0-setup-draft` (debounced) and restored on load.
|
|
41
|
+
"Start over" clears it; a successful project write clears it too.
|
|
42
|
+
- Accessibility: the stepper is a vertical tablist; each pane is a
|
|
43
|
+
tabpanel; status regions use aria-live; icons are aria-hidden; every
|
|
44
|
+
control has a label; touch targets are ≥ 44px.
|
|
14
45
|
===================================================================
|
|
15
|
-
|
|
46
|
+
{% endcomment %}
|
|
47
|
+
|
|
48
|
+
{% assign sb = site.data.site_builder %}
|
|
49
|
+
{% assign sb_cfg = site.site_builder %}
|
|
50
|
+
{% assign sb_port = sb_cfg.default_port | default: 4000 %}
|
|
16
51
|
|
|
17
|
-
<div class="container py-4" id="setup-wizard">
|
|
18
|
-
<div class="row justify-content-center">
|
|
19
|
-
<div class="col-lg-10">
|
|
52
|
+
<div class="container-xl py-4" id="setup-wizard" data-default-port="{{ sb_port }}">
|
|
20
53
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
54
|
+
<header class="wizard-header d-flex flex-wrap align-items-end justify-content-between gap-3 mb-4">
|
|
55
|
+
<div>
|
|
56
|
+
<p class="text-uppercase small fw-semibold text-body-secondary mb-1">
|
|
57
|
+
<i class="bi bi-magic" aria-hidden="true"></i> zer0-mistakes
|
|
25
58
|
</p>
|
|
59
|
+
<h1 class="mb-1">Site Builder</h1>
|
|
60
|
+
<p class="lead text-body-secondary mb-0">
|
|
61
|
+
Answer a few questions — or just talk to Claude or Grok — and leave with a running site.
|
|
62
|
+
</p>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="d-flex align-items-center gap-2">
|
|
65
|
+
<span id="wizard-draft-chip" class="wizard-draft-chip" hidden aria-live="polite">
|
|
66
|
+
<i class="bi bi-cloud-check" aria-hidden="true"></i> Draft saved
|
|
67
|
+
</span>
|
|
68
|
+
<button class="btn btn-outline-secondary btn-sm" type="button" id="btn-reset"
|
|
69
|
+
title="Clear every answer and start again">
|
|
70
|
+
<i class="bi bi-arrow-counterclockwise" aria-hidden="true"></i> Start over
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</header>
|
|
26
74
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
type="button" role="tab">
|
|
49
|
-
<i class="bi bi-collection"></i> Collections
|
|
50
|
-
</button>
|
|
51
|
-
</li>
|
|
52
|
-
<li class="nav-item" role="presentation">
|
|
53
|
-
<button class="nav-link" id="tab-analytics"
|
|
54
|
-
data-bs-toggle="pill" data-bs-target="#step-analytics"
|
|
55
|
-
type="button" role="tab">
|
|
56
|
-
<i class="bi bi-graph-up"></i> Analytics
|
|
57
|
-
</button>
|
|
58
|
-
</li>
|
|
59
|
-
<li class="nav-item" role="presentation">
|
|
60
|
-
<button class="nav-link" id="tab-review"
|
|
61
|
-
data-bs-toggle="pill" data-bs-target="#step-review"
|
|
62
|
-
type="button" role="tab">
|
|
63
|
-
<i class="bi bi-file-earmark-code"></i> Review
|
|
75
|
+
<div class="row g-4 wizard-grid">
|
|
76
|
+
|
|
77
|
+
{% comment %} ============================================================ {% endcomment %}
|
|
78
|
+
{% comment %} 1. Vertical stepper (generated from _data/site_builder.yml) {% endcomment %}
|
|
79
|
+
{% comment %} ============================================================ {% endcomment %}
|
|
80
|
+
<div class="col-lg-2">
|
|
81
|
+
<div class="wizard-stepper-wrap sticky-lg-top">
|
|
82
|
+
<div class="nav flex-column wizard-stepper" id="wizardTabs" role="tablist"
|
|
83
|
+
aria-orientation="vertical" aria-label="Site Builder steps">
|
|
84
|
+
{% for step in sb.steps %}
|
|
85
|
+
<button class="wizard-step{% if forloop.first %} is-active{% endif %}" id="tab-{{ step.id }}"
|
|
86
|
+
data-bs-toggle="pill" data-bs-target="#step-{{ step.id }}"
|
|
87
|
+
type="button" role="tab" aria-controls="step-{{ step.id }}"
|
|
88
|
+
aria-selected="{% if forloop.first %}true{% else %}false{% endif %}"
|
|
89
|
+
data-step="{{ forloop.index }}" data-step-id="{{ step.id }}"
|
|
90
|
+
title="{{ step.summary | escape }}">
|
|
91
|
+
<span class="wizard-step-marker" aria-hidden="true"><i class="bi {{ step.icon }}"></i></span>
|
|
92
|
+
<span class="wizard-step-text">
|
|
93
|
+
<span class="wizard-step-label">{{ step.label }}</span>
|
|
94
|
+
<span class="wizard-step-state visually-hidden">{% if forloop.first %}current step{% endif %}</span>
|
|
95
|
+
</span>
|
|
64
96
|
</button>
|
|
65
|
-
|
|
66
|
-
|
|
97
|
+
{% endfor %}
|
|
98
|
+
</div>
|
|
99
|
+
<div class="wizard-progress mt-3" aria-hidden="true">
|
|
100
|
+
<div class="progress" style="height: 4px;">
|
|
101
|
+
<div class="progress-bar" id="wizard-progress-bar" role="progressbar" style="width: 0%"></div>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="small text-body-secondary mt-1" id="wizard-progress-text">Step 1 of {{ sb.steps | size }}</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
67
107
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
108
|
+
{% comment %} ============================================================ {% endcomment %}
|
|
109
|
+
{% comment %} 2. Step panes {% endcomment %}
|
|
110
|
+
{% comment %} ============================================================ {% endcomment %}
|
|
111
|
+
<div class="col-lg-6">
|
|
112
|
+
<div class="tab-content wizard-panes" id="wizardTabContent">
|
|
72
113
|
|
|
73
|
-
|
|
74
|
-
<div class="tab-pane fade show active" id="step-
|
|
114
|
+
{% comment %} ───── Step 1: Connect ───── {% endcomment %}
|
|
115
|
+
<div class="tab-pane fade show active" id="step-connect" role="tabpanel" aria-labelledby="tab-connect">
|
|
75
116
|
<div class="card">
|
|
76
117
|
<div class="card-body">
|
|
77
|
-
<
|
|
118
|
+
<h2 class="h4 card-title mb-1">Connect your AI</h2>
|
|
119
|
+
<p class="text-body-secondary">
|
|
120
|
+
The builder runs entirely in your browser. Connect <strong>Claude</strong> or <strong>Grok</strong> through the
|
|
121
|
+
<strong>local dev proxy</strong> with your own token and it can fill in these forms, check your machine, read the
|
|
122
|
+
theme's source, write <em>or modify</em> your project, generate images and start Docker — in the order you choose.
|
|
123
|
+
</p>
|
|
78
124
|
|
|
79
|
-
<div class="mb-3"
|
|
80
|
-
|
|
81
|
-
<
|
|
82
|
-
|
|
125
|
+
<div class="sb-connect-status alert d-flex align-items-start gap-3 mb-3" id="connect-status"
|
|
126
|
+
role="status" aria-live="polite" data-state="checking">
|
|
127
|
+
<span class="sb-status-dot mt-1" aria-hidden="true"></span>
|
|
128
|
+
<div class="flex-grow-1">
|
|
129
|
+
<div class="fw-semibold sb-status-title">Looking for the dev proxy…</div>
|
|
130
|
+
<div class="small sb-status-detail">Checking <code class="sb-endpoint"></code></div>
|
|
131
|
+
</div>
|
|
132
|
+
<button class="btn btn-sm btn-outline-primary" type="button" id="btn-connect-retry">
|
|
133
|
+
<i class="bi bi-arrow-repeat" aria-hidden="true"></i> Retry
|
|
134
|
+
</button>
|
|
83
135
|
</div>
|
|
84
136
|
|
|
85
|
-
<
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
137
|
+
<fieldset class="mb-3" id="sb-providers">
|
|
138
|
+
<legend class="form-label fs-6 mb-2">AI provider</legend>
|
|
139
|
+
<div class="row g-2">
|
|
140
|
+
{% for p in sb.providers %}
|
|
141
|
+
<div class="col-sm-6">
|
|
142
|
+
<input type="radio" class="btn-check" name="sb_provider" id="sb-provider-{{ p.id }}"
|
|
143
|
+
value="{{ p.id }}" autocomplete="off" {% if forloop.first %}checked{% endif %}>
|
|
144
|
+
<label class="btn btn-outline-primary w-100 text-start wizard-choice sb-provider-card" for="sb-provider-{{ p.id }}">
|
|
145
|
+
<span class="d-flex justify-content-between align-items-center gap-2">
|
|
146
|
+
<span class="fw-semibold"><i class="bi {{ p.icon }}" aria-hidden="true"></i> {{ p.label }} <small class="fw-normal">{{ p.vendor }}</small></span>
|
|
147
|
+
<span class="badge rounded-pill text-bg-secondary sb-provider-state" data-provider="{{ p.id }}">proxy offline</span>
|
|
148
|
+
</span>
|
|
149
|
+
<span class="small d-block">{{ p.description }}</span>
|
|
150
|
+
</label>
|
|
151
|
+
</div>
|
|
152
|
+
{% endfor %}
|
|
153
|
+
</div>
|
|
154
|
+
</fieldset>
|
|
90
155
|
|
|
91
|
-
<
|
|
92
|
-
<label for="
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
156
|
+
<form class="sb-credential mb-3" id="sb-credential-form" autocomplete="off">
|
|
157
|
+
<label for="sb-token" class="form-label fw-semibold">Token for <span class="sb-provider-name">Claude</span></label>
|
|
158
|
+
<div class="input-group">
|
|
159
|
+
<input type="password" class="form-control" id="sb-token" placeholder="sk-ant-oat01-…"
|
|
160
|
+
autocomplete="off" autocapitalize="off" spellcheck="false" disabled>
|
|
161
|
+
<button class="btn btn-primary" type="submit" id="sb-token-use" disabled>
|
|
162
|
+
<i class="bi bi-plug" aria-hidden="true"></i> Use for this session
|
|
163
|
+
</button>
|
|
164
|
+
</div>
|
|
165
|
+
<div class="form-text" id="sb-token-hint">Mint one with <code>claude setup-token</code>. The token goes once to the local proxy and stays in its memory — never in this page or your browser storage.</div>
|
|
166
|
+
<div class="form-check form-switch mt-2">
|
|
167
|
+
<input class="form-check-input" type="checkbox" id="sb-token-persist" disabled>
|
|
168
|
+
<label class="form-check-label small" for="sb-token-persist">Also save it to <code>.env</code> (mode 600) so the proxy remembers it next time</label>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="small mt-2" id="sb-credential-status" aria-live="polite"></div>
|
|
171
|
+
</form>
|
|
98
172
|
|
|
99
|
-
<div class="row">
|
|
100
|
-
<div class="col-md-6
|
|
101
|
-
<label for="
|
|
102
|
-
<
|
|
103
|
-
|
|
173
|
+
<div class="row g-3 mb-3">
|
|
174
|
+
<div class="col-md-6">
|
|
175
|
+
<label for="sb-model" class="form-label">Model</label>
|
|
176
|
+
<select class="form-select form-select-sm" id="sb-model" disabled>
|
|
177
|
+
<option value="{{ sb_cfg.model | default: site.ai_chat.model | default: 'claude-opus-4-8' }}">{{ sb_cfg.model | default: site.ai_chat.model | default: 'claude-opus-4-8' }}</option>
|
|
178
|
+
</select>
|
|
179
|
+
<div class="form-text" id="sb-model-note">Sent with every request; the proxy can pin one with <code>CHAT_MODEL</code> / <code>XAI_CHAT_MODEL</code>.</div>
|
|
104
180
|
</div>
|
|
105
|
-
<div class="col-md-6
|
|
106
|
-
<label for="
|
|
107
|
-
<
|
|
108
|
-
|
|
181
|
+
<div class="col-md-6">
|
|
182
|
+
<label for="sb-image-provider" class="form-label">Image generation</label>
|
|
183
|
+
<select class="form-select form-select-sm" id="sb-image-provider" disabled>
|
|
184
|
+
<option value="">Off</option>
|
|
185
|
+
{% for ip in sb.image_providers %}<option value="{{ ip.id }}" data-label="{{ ip.label }} ({{ ip.vendor }})">{{ ip.label }} ({{ ip.vendor }})</option>{% endfor %}
|
|
186
|
+
</select>
|
|
187
|
+
<div class="form-text" id="sb-image-note">Renders hero, logo and post images straight into the project's <code>assets/</code>.</div>
|
|
109
188
|
</div>
|
|
110
189
|
</div>
|
|
111
190
|
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
<
|
|
115
|
-
|
|
191
|
+
<fieldset class="mb-3" id="sb-mode">
|
|
192
|
+
<legend class="form-label fs-6 mb-2">How do you want to work?</legend>
|
|
193
|
+
<div class="row g-2">
|
|
194
|
+
{% for m in sb.session_modes %}
|
|
195
|
+
<div class="col-sm-6">
|
|
196
|
+
<input type="radio" class="btn-check" name="sb_mode" id="sb-mode-{{ m.id }}" value="{{ m.id }}"
|
|
197
|
+
autocomplete="off" {% if m.id == sb_cfg.mode %}checked{% elsif sb_cfg.mode == nil and forloop.first %}checked{% endif %}>
|
|
198
|
+
<label class="btn btn-outline-secondary w-100 text-start wizard-choice" for="sb-mode-{{ m.id }}">
|
|
199
|
+
<span class="fw-semibold d-block"><i class="bi {{ m.icon }}" aria-hidden="true"></i> {{ m.label }}</span>
|
|
200
|
+
<span class="small d-block">{{ m.description }}</span>
|
|
201
|
+
</label>
|
|
202
|
+
</div>
|
|
203
|
+
{% endfor %}
|
|
204
|
+
</div>
|
|
205
|
+
</fieldset>
|
|
206
|
+
|
|
207
|
+
<div class="sb-connect-howto" id="connect-howto">
|
|
208
|
+
<h3 class="h6 text-uppercase text-body-secondary">How to connect (once, on your machine)</h3>
|
|
209
|
+
<ol class="sb-steps list-unstyled mb-3">
|
|
210
|
+
<li>
|
|
211
|
+
<span class="sb-step-num" aria-hidden="true">1</span>
|
|
212
|
+
<div>
|
|
213
|
+
<div class="fw-semibold">Start the dev proxy next to the site</div>
|
|
214
|
+
<p class="small text-body-secondary mb-1">Node 20.6+. It starts without any key and waits for the token you paste above; <code>--env-file=.env</code> loads keys you saved earlier.</p>
|
|
215
|
+
<div class="wizard-cmd"><code>node --env-file=.env templates/deploy/chat-proxy/dev-proxy.mjs</code><button class="btn btn-sm btn-link" type="button" data-copy="node --env-file=.env templates/deploy/chat-proxy/dev-proxy.mjs" aria-label="Copy command"><i class="bi bi-clipboard" aria-hidden="true"></i></button></div>
|
|
216
|
+
</div>
|
|
217
|
+
</li>
|
|
218
|
+
<li>
|
|
219
|
+
<span class="sb-step-num" aria-hidden="true">2</span>
|
|
220
|
+
<div>
|
|
221
|
+
<div class="fw-semibold">Get a token from the provider you picked</div>
|
|
222
|
+
<p class="small text-body-secondary mb-1">Claude: a personal OAuth token from the Claude Code CLI (Pro/Max) or an API key from console.anthropic.com. Grok: an API key from <a href="https://console.x.ai/" target="_blank" rel="noopener">console.x.ai</a>.</p>
|
|
223
|
+
<div class="wizard-cmd"><code>claude setup-token</code><button class="btn btn-sm btn-link" type="button" data-copy="claude setup-token" aria-label="Copy command"><i class="bi bi-clipboard" aria-hidden="true"></i></button></div>
|
|
224
|
+
</div>
|
|
225
|
+
</li>
|
|
226
|
+
<li>
|
|
227
|
+
<span class="sb-step-num" aria-hidden="true">3</span>
|
|
228
|
+
<div>
|
|
229
|
+
<div class="fw-semibold">Paste it above — or keep it in <code>.env</code></div>
|
|
230
|
+
<p class="small text-body-secondary mb-1">Pasting keeps the token in the proxy's memory for this run (tick the switch to save it). Or put it in the git-ignored <code>.env</code> yourself and restart the proxy.</p>
|
|
231
|
+
<div class="wizard-cmd"><code>CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-… # or XAI_API_KEY=xai-…</code></div>
|
|
232
|
+
</div>
|
|
233
|
+
</li>
|
|
234
|
+
</ol>
|
|
235
|
+
<details class="small">
|
|
236
|
+
<summary class="text-body-secondary">What the proxy is allowed to do</summary>
|
|
237
|
+
<ul class="mt-2 mb-0">
|
|
238
|
+
<li>Hold the token you paste in memory only; write it to <code>.env</code> (mode 600) only when you tick the switch; report it masked.</li>
|
|
239
|
+
<li>Run a fixed list of read-only version checks (Docker, Git, gh, VS Code, Node, Claude CLI).</li>
|
|
240
|
+
<li>Read text source files inside the theme checkout — never <code>.env</code>, keys or build output.</li>
|
|
241
|
+
<li>Write generated files into a folder beside the theme (never inside it), and read, edit, add or delete text files inside a site you open there — each change behind a confirmation card.</li>
|
|
242
|
+
<li>Save generated images (PNG/JPEG/WebP only) under that site's <code>assets/</code>.</li>
|
|
243
|
+
<li>Run <code>docker compose</code> up / ps / logs / down / build and <code>git status</code> / diff / log / init in that folder — nothing else.</li>
|
|
244
|
+
</ul>
|
|
245
|
+
</details>
|
|
116
246
|
</div>
|
|
117
247
|
|
|
118
|
-
<div class="mb-
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
placeholder="my-site" data-key="repository_name">
|
|
122
|
-
<div class="form-text">The GitHub repository name for this site (e.g. <code>my-site</code>).</div>
|
|
248
|
+
<div class="alert alert-light border small mt-3 mb-0">
|
|
249
|
+
<i class="bi bi-info-circle" aria-hidden="true"></i>
|
|
250
|
+
No proxy? Continue anyway. Every step still works and the Build step gives you the files and the commands to run yourself.
|
|
123
251
|
</div>
|
|
124
252
|
|
|
125
|
-
<div class="
|
|
126
|
-
<button class="btn btn-primary btn-next" data-next="tab-
|
|
127
|
-
Next:
|
|
253
|
+
<div class="wizard-nav">
|
|
254
|
+
<button class="btn btn-primary btn-next" data-next="tab-prereqs">
|
|
255
|
+
Next: Prerequisites <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
128
256
|
</button>
|
|
129
257
|
</div>
|
|
130
258
|
</div>
|
|
131
259
|
</div>
|
|
132
260
|
</div>
|
|
133
261
|
|
|
134
|
-
|
|
135
|
-
<div class="tab-pane fade" id="step-
|
|
262
|
+
{% comment %} ───── Step 2: Prerequisites ───── {% endcomment %}
|
|
263
|
+
<div class="tab-pane fade" id="step-prereqs" role="tabpanel" aria-labelledby="tab-prereqs">
|
|
136
264
|
<div class="card">
|
|
137
265
|
<div class="card-body">
|
|
138
|
-
<
|
|
266
|
+
<h2 class="h4 card-title mb-1">Prerequisites</h2>
|
|
267
|
+
<p class="text-body-secondary">
|
|
268
|
+
Docker runs Jekyll for you, Git and the GitHub CLI publish it. Connected? Press
|
|
269
|
+
<strong>Run checks</strong>. Otherwise tick each item as you install it.
|
|
270
|
+
</p>
|
|
271
|
+
{% include setup/prereq-checklist.html %}
|
|
272
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
273
|
+
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-connect">
|
|
274
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
275
|
+
</button>
|
|
276
|
+
<button class="btn btn-primary btn-next" data-next="tab-identity">
|
|
277
|
+
Next: Identity <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
278
|
+
</button>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
{% comment %} ───── Step 3: Identity ───── {% endcomment %}
|
|
285
|
+
<div class="tab-pane fade" id="step-identity" role="tabpanel" aria-labelledby="tab-identity">
|
|
286
|
+
<div class="card">
|
|
287
|
+
<div class="card-body">
|
|
288
|
+
<h2 class="h4 card-title mb-1">Site identity</h2>
|
|
289
|
+
<p class="text-body-secondary">Describe the site in your own words first — the assistant uses that brief to draft everything else.</p>
|
|
139
290
|
|
|
140
291
|
<div class="mb-3">
|
|
141
|
-
<label for="cfg-
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
<div class="form-text
|
|
292
|
+
<label for="cfg-brief" class="form-label fw-semibold">What is this site about, and who is it for?</label>
|
|
293
|
+
<textarea class="form-control cfg-field" id="cfg-brief" rows="3" data-key="brief"
|
|
294
|
+
placeholder="e.g. A blog about running Postgres in production, written for backend engineers who are new to operations."></textarea>
|
|
295
|
+
<div class="form-text d-flex justify-content-between">
|
|
296
|
+
<span>The brief is not published; it steers the drafts.</span>
|
|
297
|
+
<button class="btn btn-link btn-sm p-0 sb-ask" type="button"
|
|
298
|
+
data-ask="Here is my brief: {brief}. Draft a title, subtitle, tagline and a 120–160 character description for the site, then apply them.">
|
|
299
|
+
<i class="bi bi-stars" aria-hidden="true"></i> Draft with <span class="sb-provider-name">Claude</span>
|
|
300
|
+
</button>
|
|
301
|
+
</div>
|
|
145
302
|
</div>
|
|
146
303
|
|
|
147
|
-
<div class="
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
304
|
+
<div class="row g-3">
|
|
305
|
+
<div class="col-md-7">
|
|
306
|
+
<label for="cfg-title" class="form-label">Site title <span class="text-danger" aria-hidden="true">*</span></label>
|
|
307
|
+
<input type="text" class="form-control cfg-field" id="cfg-title" placeholder="My Awesome Site"
|
|
308
|
+
data-key="title" data-recommended="Site Title" maxlength="60" autocomplete="off">
|
|
309
|
+
<div class="form-text">Shown in the navbar, browser tab and feed.</div>
|
|
310
|
+
</div>
|
|
311
|
+
<div class="col-md-5">
|
|
312
|
+
<label for="cfg-subtitle" class="form-label">Subtitle <small class="text-body-secondary">(optional)</small></label>
|
|
313
|
+
<input type="text" class="form-control cfg-field" id="cfg-subtitle" placeholder="Notes from the field"
|
|
314
|
+
data-key="subtitle" maxlength="80" autocomplete="off">
|
|
315
|
+
</div>
|
|
316
|
+
<div class="col-12">
|
|
317
|
+
<label for="cfg-tagline" class="form-label">Tagline <small class="text-body-secondary">(optional)</small></label>
|
|
318
|
+
<input type="text" class="form-control cfg-field" id="cfg-tagline" placeholder="One line for the home hero"
|
|
319
|
+
data-key="tagline" maxlength="120" autocomplete="off">
|
|
320
|
+
</div>
|
|
321
|
+
<div class="col-12">
|
|
322
|
+
<label for="cfg-description" class="form-label">Description</label>
|
|
323
|
+
<textarea class="form-control cfg-field" id="cfg-description" rows="2" data-key="description"
|
|
324
|
+
data-recommended="Description" maxlength="240"
|
|
325
|
+
placeholder="A search-friendly sentence about the site."></textarea>
|
|
326
|
+
<div class="form-text d-flex justify-content-between">
|
|
327
|
+
<span>Meta description for search and social cards. Aim for 120–160 characters.</span>
|
|
328
|
+
<span><span id="desc-count">0</span>/160</span>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
<div class="col-md-6">
|
|
332
|
+
<label for="cfg-author" class="form-label">Author / owner</label>
|
|
333
|
+
<input type="text" class="form-control cfg-field" id="cfg-author" placeholder="Your name"
|
|
334
|
+
data-key="founder" data-recommended="Author / Owner" autocomplete="name">
|
|
335
|
+
</div>
|
|
336
|
+
<div class="col-md-6">
|
|
337
|
+
<label for="cfg-email" class="form-label">Contact email</label>
|
|
338
|
+
<input type="email" class="form-control cfg-field" id="cfg-email" placeholder="you@example.com"
|
|
339
|
+
data-key="email" data-recommended="Email" autocomplete="email" aria-describedby="cfg-email-feedback">
|
|
340
|
+
<div class="invalid-feedback" id="cfg-email-feedback"></div>
|
|
341
|
+
</div>
|
|
152
342
|
</div>
|
|
153
343
|
|
|
154
|
-
<div class="
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
<
|
|
344
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
345
|
+
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-prereqs">
|
|
346
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
347
|
+
</button>
|
|
348
|
+
<button class="btn btn-primary btn-next" data-next="tab-urls">
|
|
349
|
+
Next: URLs <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
350
|
+
</button>
|
|
159
351
|
</div>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
160
355
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
356
|
+
{% comment %} ───── Step 4: URLs ───── {% endcomment %}
|
|
357
|
+
<div class="tab-pane fade" id="step-urls" role="tabpanel" aria-labelledby="tab-urls">
|
|
358
|
+
<div class="card">
|
|
359
|
+
<div class="card-body">
|
|
360
|
+
<h2 class="h4 card-title mb-1">GitHub & URLs</h2>
|
|
361
|
+
<p class="text-body-secondary">Where the code lives and where the site is served from.</p>
|
|
362
|
+
|
|
363
|
+
<div class="row g-3">
|
|
364
|
+
<div class="col-md-6">
|
|
365
|
+
<label for="cfg-github-user" class="form-label">GitHub username</label>
|
|
366
|
+
<div class="input-group">
|
|
367
|
+
<span class="input-group-text"><i class="bi bi-github" aria-hidden="true"></i></span>
|
|
368
|
+
<input type="text" class="form-control cfg-field" id="cfg-github-user" placeholder="octocat"
|
|
369
|
+
data-key="github_user" data-recommended="GitHub Username" autocomplete="username">
|
|
370
|
+
</div>
|
|
371
|
+
</div>
|
|
372
|
+
<div class="col-md-6">
|
|
373
|
+
<label for="cfg-repo-name" class="form-label">Repository name</label>
|
|
374
|
+
<input type="text" class="form-control cfg-field" id="cfg-repo-name" placeholder="my-site"
|
|
375
|
+
data-key="repository_name" data-recommended="Repository Name" autocomplete="off">
|
|
376
|
+
<div class="form-text">Also the project folder name in the Build step.</div>
|
|
377
|
+
</div>
|
|
378
|
+
|
|
379
|
+
<div class="col-12">
|
|
380
|
+
<fieldset>
|
|
381
|
+
<legend class="form-label fs-6 mb-2">How will the theme be loaded?</legend>
|
|
382
|
+
<div class="row g-2">
|
|
383
|
+
{% for t in sb.deploy_targets %}
|
|
384
|
+
<div class="col-md-6">
|
|
385
|
+
<input type="radio" class="btn-check cfg-radio" name="deploy_target" id="deploy-{{ t.id }}"
|
|
386
|
+
value="{{ t.id }}" data-key="deploy_target" autocomplete="off"
|
|
387
|
+
{% if forloop.first %}checked{% endif %}>
|
|
388
|
+
<label class="btn btn-outline-primary w-100 text-start wizard-choice" for="deploy-{{ t.id }}">
|
|
389
|
+
<span class="fw-semibold d-block">{{ t.label }}</span>
|
|
390
|
+
<span class="small d-block">{{ t.description }}</span>
|
|
391
|
+
</label>
|
|
392
|
+
</div>
|
|
393
|
+
{% endfor %}
|
|
394
|
+
</div>
|
|
395
|
+
</fieldset>
|
|
396
|
+
</div>
|
|
397
|
+
|
|
398
|
+
<div class="col-md-8">
|
|
399
|
+
<label for="cfg-url" class="form-label">Site URL</label>
|
|
400
|
+
<div class="input-group">
|
|
401
|
+
<input type="url" class="form-control cfg-field" id="cfg-url" placeholder="https://octocat.github.io"
|
|
402
|
+
data-key="url" data-recommended="Site URL" aria-describedby="cfg-url-feedback" autocomplete="url">
|
|
403
|
+
<button class="btn btn-outline-secondary" type="button" id="btn-suggest-urls" title="Fill url and baseurl from the GitHub fields">
|
|
404
|
+
<i class="bi bi-lightning-charge" aria-hidden="true"></i> Suggest
|
|
405
|
+
</button>
|
|
406
|
+
<div class="invalid-feedback" id="cfg-url-feedback"></div>
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
<div class="col-md-4">
|
|
410
|
+
<label for="cfg-baseurl" class="form-label">Base path</label>
|
|
411
|
+
<input type="text" class="form-control cfg-field" id="cfg-baseurl" placeholder="/my-site"
|
|
412
|
+
data-key="baseurl" autocomplete="off">
|
|
413
|
+
<div class="form-text">Empty for <code>user.github.io</code>; <code>/repo</code> for project sites.</div>
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
<div class="col-md-6">
|
|
417
|
+
<label for="cfg-permalink" class="form-label">Permalink style</label>
|
|
418
|
+
<select class="form-select cfg-field" id="cfg-permalink" data-key="permalink">
|
|
419
|
+
<option value="/:categories/:title/">/:categories/:title/</option>
|
|
420
|
+
<option value="/:title/">/:title/</option>
|
|
421
|
+
<option value="/:year/:month/:title/">/:year/:month/:title/</option>
|
|
422
|
+
<option value="pretty">pretty</option>
|
|
423
|
+
</select>
|
|
424
|
+
</div>
|
|
425
|
+
<div class="col-md-3">
|
|
426
|
+
<label for="cfg-port" class="form-label">Dev port</label>
|
|
427
|
+
<input type="number" class="form-control cfg-field" id="cfg-port" min="1024" max="65535"
|
|
428
|
+
value="{{ sb_port }}" data-key="port">
|
|
429
|
+
</div>
|
|
430
|
+
<div class="col-md-3">
|
|
431
|
+
<label for="cfg-remote-theme" class="form-label">Remote theme</label>
|
|
432
|
+
<input type="text" class="form-control cfg-field" id="cfg-remote-theme" value="bamr87/zer0-mistakes"
|
|
433
|
+
data-key="remote_theme" autocomplete="off">
|
|
434
|
+
</div>
|
|
169
435
|
</div>
|
|
170
436
|
|
|
171
|
-
<div class="d-flex justify-content-between">
|
|
437
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
172
438
|
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-identity">
|
|
173
|
-
<i class="bi bi-arrow-left"></i> Back
|
|
439
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
174
440
|
</button>
|
|
175
|
-
<button class="btn btn-primary btn-next" data-next="tab-
|
|
176
|
-
Next:
|
|
441
|
+
<button class="btn btn-primary btn-next" data-next="tab-structure">
|
|
442
|
+
Next: Structure <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
177
443
|
</button>
|
|
178
444
|
</div>
|
|
179
445
|
</div>
|
|
180
446
|
</div>
|
|
181
447
|
</div>
|
|
182
448
|
|
|
183
|
-
|
|
184
|
-
<div class="tab-pane fade" id="step-
|
|
449
|
+
{% comment %} ───── Step 5: Structure ───── {% endcomment %}
|
|
450
|
+
<div class="tab-pane fade" id="step-structure" role="tabpanel" aria-labelledby="tab-structure">
|
|
185
451
|
<div class="card">
|
|
186
452
|
<div class="card-body">
|
|
187
|
-
<
|
|
188
|
-
<p class="text-
|
|
453
|
+
<h2 class="h4 card-title mb-1">Structure</h2>
|
|
454
|
+
<p class="text-body-secondary">Pick a starting shape, then fine-tune the collections and the top navigation.</p>
|
|
189
455
|
|
|
190
|
-
<
|
|
191
|
-
<
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
456
|
+
<fieldset class="mb-3">
|
|
457
|
+
<legend class="form-label fs-6 mb-2">Kind of site</legend>
|
|
458
|
+
<div class="d-flex flex-wrap gap-2">
|
|
459
|
+
{% for st in sb.site_types %}
|
|
460
|
+
<input type="radio" class="btn-check cfg-radio" name="site_type" id="site-type-{{ st.id }}"
|
|
461
|
+
value="{{ st.id }}" data-key="site_type" data-collections="{{ st.collections | join: ',' }}" autocomplete="off">
|
|
462
|
+
<label class="btn btn-outline-secondary btn-sm rounded-pill" for="site-type-{{ st.id }}">{{ st.label }}</label>
|
|
463
|
+
{% endfor %}
|
|
464
|
+
</div>
|
|
465
|
+
</fieldset>
|
|
196
466
|
|
|
197
|
-
<
|
|
198
|
-
<
|
|
199
|
-
<
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
467
|
+
<fieldset class="mb-3">
|
|
468
|
+
<legend class="form-label fs-6 mb-2">Collections</legend>
|
|
469
|
+
<div class="row g-2">
|
|
470
|
+
{% for c in sb.collections %}
|
|
471
|
+
<div class="col-sm-6">
|
|
472
|
+
<div class="form-check wizard-check">
|
|
473
|
+
<input class="form-check-input cfg-collection" type="checkbox" id="col-{{ c.id }}"
|
|
474
|
+
data-col="{{ c.id }}" data-layout="{{ c.layout }}" data-permalink="{{ c.permalink }}"
|
|
475
|
+
{% if c.default %}checked{% endif %}>
|
|
476
|
+
<label class="form-check-label" for="col-{{ c.id }}">
|
|
477
|
+
<i class="bi {{ c.icon }} me-1" aria-hidden="true"></i><strong>{{ c.label }}</strong>
|
|
478
|
+
<span class="d-block small text-body-secondary">{{ c.description }}</span>
|
|
479
|
+
</label>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
{% endfor %}
|
|
483
|
+
</div>
|
|
484
|
+
</fieldset>
|
|
203
485
|
|
|
204
|
-
<div class="
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
486
|
+
<div class="row g-3 mb-3">
|
|
487
|
+
<div class="col-md-6">
|
|
488
|
+
<fieldset>
|
|
489
|
+
<legend class="form-label fs-6 mb-2">Navigation style</legend>
|
|
490
|
+
<div class="d-flex flex-wrap gap-2">
|
|
491
|
+
{% for n in sb.navigation_styles %}
|
|
492
|
+
<input type="radio" class="btn-check cfg-radio" name="nav_style" id="nav-style-{{ n.id }}" value="{{ n.id }}"
|
|
493
|
+
data-key="plan.navigation.style" autocomplete="off" {% if forloop.first %}checked{% endif %}>
|
|
494
|
+
<label class="btn btn-outline-secondary btn-sm rounded-pill" for="nav-style-{{ n.id }}" title="{{ n.description | escape }}">{{ n.label }}</label>
|
|
495
|
+
{% endfor %}
|
|
496
|
+
</div>
|
|
497
|
+
</fieldset>
|
|
498
|
+
</div>
|
|
499
|
+
<div class="col-md-6">
|
|
500
|
+
<label for="cfg-sidebar-mode" class="form-label fs-6 mb-2">Sidebar</label>
|
|
501
|
+
<select class="form-select form-select-sm cfg-field" id="cfg-sidebar-mode" data-key="plan.navigation.sidebar">
|
|
502
|
+
{% for m in sb.sidebar_modes %}<option value="{{ m.id }}" title="{{ m.description | escape }}">{{ m.label }} — {{ m.description }}</option>{% endfor %}
|
|
503
|
+
</select>
|
|
504
|
+
</div>
|
|
209
505
|
</div>
|
|
210
506
|
|
|
211
|
-
<
|
|
212
|
-
<
|
|
213
|
-
|
|
214
|
-
<
|
|
215
|
-
|
|
216
|
-
|
|
507
|
+
<fieldset class="mb-3">
|
|
508
|
+
<legend class="form-label fs-6 mb-2 d-flex justify-content-between align-items-center">
|
|
509
|
+
<span>Landing page</span>
|
|
510
|
+
<button class="btn btn-link btn-sm p-0 sb-ask" type="button"
|
|
511
|
+
data-ask="Design the landing page for my site: pick the template, write the hero (eyebrow, headline, subheadline, up to three CTAs) and fill every section with real copy from my brief — then apply it with set_site_plan.">
|
|
512
|
+
<i class="bi bi-stars" aria-hidden="true"></i> Design with <span class="sb-provider-name">Claude</span>
|
|
513
|
+
</button>
|
|
514
|
+
</legend>
|
|
515
|
+
<div class="row g-2">
|
|
516
|
+
{% for t in sb.landing_templates %}
|
|
517
|
+
<div class="col-sm-6 col-lg-4">
|
|
518
|
+
<input type="radio" class="btn-check cfg-radio" name="landing_template" id="landing-{{ t.id }}" value="{{ t.id }}"
|
|
519
|
+
data-key="plan.landing.template" autocomplete="off" {% if t.id == 'hero' %}checked{% endif %}>
|
|
520
|
+
<label class="btn btn-outline-primary w-100 text-start wizard-choice" for="landing-{{ t.id }}">
|
|
521
|
+
<span class="fw-semibold d-block">{{ t.label }}</span>
|
|
522
|
+
<span class="small d-block">{{ t.description }}</span>
|
|
523
|
+
</label>
|
|
524
|
+
</div>
|
|
525
|
+
{% endfor %}
|
|
526
|
+
</div>
|
|
527
|
+
<div class="form-text" id="landing-summary" aria-live="polite"></div>
|
|
528
|
+
</fieldset>
|
|
217
529
|
|
|
218
|
-
<
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
<
|
|
222
|
-
|
|
223
|
-
|
|
530
|
+
<fieldset class="mb-3">
|
|
531
|
+
<legend class="form-label fs-6 mb-2 d-flex justify-content-between align-items-center">
|
|
532
|
+
<span>Example pages <span class="badge text-bg-secondary rounded-pill" id="pages-count">0</span></span>
|
|
533
|
+
<span>
|
|
534
|
+
<button class="btn btn-link btn-sm p-0 me-2 sb-ask" type="button"
|
|
535
|
+
data-ask="Plan five or six example pages for my site across the enabled collections — each with a slug, title, description and a 150–300 word Markdown body in the {tone} tone for {audience} — then apply them with set_site_plan.">
|
|
536
|
+
<i class="bi bi-stars" aria-hidden="true"></i> Plan with <span class="sb-provider-name">Claude</span>
|
|
537
|
+
</button>
|
|
538
|
+
<button class="btn btn-link btn-sm p-0" type="button" id="btn-page-add">
|
|
539
|
+
<i class="bi bi-plus-circle" aria-hidden="true"></i> Add page
|
|
540
|
+
</button>
|
|
541
|
+
</span>
|
|
542
|
+
</legend>
|
|
543
|
+
<div id="pages-planner" class="pages-planner" aria-live="polite"></div>
|
|
544
|
+
<div class="form-text">Each row becomes a real file with front matter. Bodies come from the assistant, or are drafted from the title.</div>
|
|
545
|
+
</fieldset>
|
|
224
546
|
|
|
225
|
-
<
|
|
547
|
+
<fieldset>
|
|
548
|
+
<legend class="form-label fs-6 mb-2 d-flex justify-content-between align-items-center">
|
|
549
|
+
<span>Main navigation</span>
|
|
550
|
+
<span>
|
|
551
|
+
<button class="btn btn-link btn-sm p-0 me-2" type="button" id="btn-nav-regenerate" title="Rebuild the menu from the selected collections">
|
|
552
|
+
<i class="bi bi-arrow-repeat" aria-hidden="true"></i> From collections
|
|
553
|
+
</button>
|
|
554
|
+
<button class="btn btn-link btn-sm p-0" type="button" id="btn-nav-add">
|
|
555
|
+
<i class="bi bi-plus-circle" aria-hidden="true"></i> Add item
|
|
556
|
+
</button>
|
|
557
|
+
</span>
|
|
558
|
+
</legend>
|
|
559
|
+
<div id="nav-editor" class="nav-editor" aria-live="polite"></div>
|
|
560
|
+
</fieldset>
|
|
561
|
+
|
|
562
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
226
563
|
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-urls">
|
|
227
|
-
<i class="bi bi-arrow-left"></i> Back
|
|
564
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
228
565
|
</button>
|
|
229
|
-
<button class="btn btn-primary btn-next" data-next="tab-
|
|
230
|
-
Next:
|
|
566
|
+
<button class="btn btn-primary btn-next" data-next="tab-appearance">
|
|
567
|
+
Next: Appearance <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
231
568
|
</button>
|
|
232
569
|
</div>
|
|
233
570
|
</div>
|
|
234
571
|
</div>
|
|
235
572
|
</div>
|
|
236
573
|
|
|
237
|
-
|
|
238
|
-
<div class="tab-pane fade" id="step-
|
|
574
|
+
{% comment %} ───── Step 6: Appearance ───── {% endcomment %}
|
|
575
|
+
<div class="tab-pane fade" id="step-appearance" role="tabpanel" aria-labelledby="tab-appearance">
|
|
239
576
|
<div class="card">
|
|
240
577
|
<div class="card-body">
|
|
241
|
-
<
|
|
578
|
+
<h2 class="h4 card-title mb-1">Appearance</h2>
|
|
579
|
+
<p class="text-body-secondary">Seven skins re-colour every component and background layer. Preview any of them on this page.</p>
|
|
242
580
|
|
|
243
|
-
<
|
|
244
|
-
<
|
|
245
|
-
<
|
|
246
|
-
|
|
581
|
+
<fieldset class="mb-3">
|
|
582
|
+
<legend class="form-label fs-6 mb-2">Skin</legend>
|
|
583
|
+
<div class="row g-2 skin-grid">
|
|
584
|
+
{% for s in sb.skins %}
|
|
585
|
+
<div class="col-6 col-md-4">
|
|
586
|
+
<input type="radio" class="btn-check cfg-radio" name="theme_skin" id="skin-{{ s.id }}"
|
|
587
|
+
value="{{ s.id }}" data-key="theme_skin" autocomplete="off" {% if forloop.first %}checked{% endif %}>
|
|
588
|
+
<label class="skin-card" for="skin-{{ s.id }}">
|
|
589
|
+
<span class="skin-swatch" aria-hidden="true"
|
|
590
|
+
style="--sw-a: {{ s.primary }}; --sw-b: {{ s.accent }};"></span>
|
|
591
|
+
<span class="skin-name">{{ s.label }}</span>
|
|
592
|
+
<span class="skin-mood">{{ s.mood }}</span>
|
|
593
|
+
</label>
|
|
594
|
+
</div>
|
|
595
|
+
{% endfor %}
|
|
596
|
+
</div>
|
|
597
|
+
<div class="form-text d-flex justify-content-between align-items-center flex-wrap gap-2">
|
|
598
|
+
<span>Applies <code>theme_skin</code> in <code>_config.yml</code>.</span>
|
|
599
|
+
<span class="d-flex gap-2">
|
|
600
|
+
<button class="btn btn-link btn-sm p-0 sb-ask" type="button"
|
|
601
|
+
data-ask="Generate a hero image for the landing page that fits my brief, the {theme_skin} skin and the chosen palette (no text in the image), save it as assets/images/hero.png in my project, and set landing.hero.image to /assets/images/hero.png.">
|
|
602
|
+
<i class="bi bi-image" aria-hidden="true"></i> Hero image with <span class="sb-provider-name">Claude</span>
|
|
603
|
+
</button>
|
|
604
|
+
<button class="btn btn-outline-secondary btn-sm" type="button" id="btn-skin-preview" aria-pressed="false">
|
|
605
|
+
<i class="bi bi-eye" aria-hidden="true"></i> Preview on this page
|
|
606
|
+
</button>
|
|
607
|
+
</span>
|
|
608
|
+
</div>
|
|
609
|
+
</fieldset>
|
|
610
|
+
|
|
611
|
+
<div class="row g-3">
|
|
612
|
+
<div class="col-md-6">
|
|
613
|
+
<label for="cfg-color-mode" class="form-label">Colour mode</label>
|
|
614
|
+
<select class="form-select cfg-field" id="cfg-color-mode" data-key="color_mode_default">
|
|
615
|
+
{% for m in sb.color_modes %}<option value="{{ m.id }}">{{ m.label }}</option>{% endfor %}
|
|
616
|
+
</select>
|
|
617
|
+
</div>
|
|
618
|
+
<div class="col-md-6 d-flex flex-column justify-content-end gap-2">
|
|
619
|
+
<div class="form-check form-switch">
|
|
620
|
+
<input class="form-check-input cfg-switch" type="checkbox" id="cfg-color-lock" data-key="color_mode_lock">
|
|
621
|
+
<label class="form-check-label" for="cfg-color-lock">Lock the colour mode (hide the toggle)</label>
|
|
622
|
+
</div>
|
|
623
|
+
<div class="form-check form-switch">
|
|
624
|
+
<input class="form-check-input cfg-switch" type="checkbox" id="cfg-backgrounds" data-key="theme_background" checked>
|
|
625
|
+
<label class="form-check-label" for="cfg-backgrounds">SVG background layers (gradient, pattern, noise)</label>
|
|
626
|
+
</div>
|
|
627
|
+
</div>
|
|
628
|
+
<div class="col-12">
|
|
629
|
+
<fieldset>
|
|
630
|
+
<legend class="form-label fs-6 mb-2">Palette <small class="text-body-secondary">layered over the skin</small></legend>
|
|
631
|
+
<div class="d-flex flex-wrap gap-2 palette-grid">
|
|
632
|
+
{% for p in sb.palettes %}
|
|
633
|
+
<input type="radio" class="btn-check cfg-radio" name="palette" id="palette-{{ p.id }}" value="{{ p.id }}"
|
|
634
|
+
data-key="plan.theme.palette.preset" autocomplete="off" {% if forloop.first %}checked{% endif %}>
|
|
635
|
+
<label class="palette-card" for="palette-{{ p.id }}" title="{{ p.description | default: p.label | escape }}">
|
|
636
|
+
<span class="palette-swatches" aria-hidden="true">
|
|
637
|
+
{% if p.primary %}
|
|
638
|
+
<span style="background: {{ p.primary }}"></span><span style="background: {{ p.secondary }}"></span><span style="background: {{ p.accent }}"></span>
|
|
639
|
+
{% else %}
|
|
640
|
+
<span class="palette-swatch-skin"></span>
|
|
641
|
+
{% endif %}
|
|
642
|
+
</span>
|
|
643
|
+
<span class="palette-name">{{ p.label }}</span>
|
|
644
|
+
</label>
|
|
645
|
+
{% endfor %}
|
|
646
|
+
<input type="radio" class="btn-check cfg-radio" name="palette" id="palette-custom" value="custom" data-key="plan.theme.palette.preset" autocomplete="off">
|
|
647
|
+
<label class="palette-card" for="palette-custom" title="Pick your own three colours">
|
|
648
|
+
<span class="palette-swatches palette-swatches--custom" aria-hidden="true"><i class="bi bi-eyedropper"></i></span>
|
|
649
|
+
<span class="palette-name">Custom</span>
|
|
650
|
+
</label>
|
|
651
|
+
</div>
|
|
652
|
+
<div class="row g-2 mt-2 wizard-subfields" data-for="palette-custom" hidden>
|
|
653
|
+
<div class="col-4"><label for="cfg-color-primary" class="form-label small mb-1">Primary</label><input type="color" class="form-control form-control-color cfg-field" id="cfg-color-primary" data-key="plan.theme.palette.primary" value="#0d6efd"></div>
|
|
654
|
+
<div class="col-4"><label for="cfg-color-secondary" class="form-label small mb-1">Secondary</label><input type="color" class="form-control form-control-color cfg-field" id="cfg-color-secondary" data-key="plan.theme.palette.secondary" value="#6c757d"></div>
|
|
655
|
+
<div class="col-4"><label for="cfg-color-accent" class="form-label small mb-1">Accent</label><input type="color" class="form-control form-control-color cfg-field" id="cfg-color-accent" data-key="plan.theme.palette.accent" value="#20c997"></div>
|
|
656
|
+
</div>
|
|
657
|
+
</fieldset>
|
|
658
|
+
</div>
|
|
659
|
+
<div class="col-md-7">
|
|
660
|
+
<label for="cfg-fonts" class="form-label">Fonts</label>
|
|
661
|
+
<select class="form-select cfg-field" id="cfg-fonts" data-key="plan.theme.fonts">
|
|
662
|
+
{% for fp in sb.font_pairings %}<option value="{{ fp.id }}">{{ fp.label }} — {{ fp.description }}</option>{% endfor %}
|
|
663
|
+
</select>
|
|
664
|
+
<div class="form-text font-preview" id="font-preview">The quick brown fox jumps over the lazy dog. <strong>Headline weight</strong>.</div>
|
|
665
|
+
</div>
|
|
666
|
+
<div class="col-md-5">
|
|
667
|
+
<fieldset>
|
|
668
|
+
<legend class="form-label fs-6 mb-2">Corners</legend>
|
|
669
|
+
<div class="btn-group w-100" role="group" aria-label="Corner radius">
|
|
670
|
+
{% for r in sb.radius_options %}
|
|
671
|
+
<input type="radio" class="btn-check cfg-radio" name="radius" id="radius-{{ r.id }}" value="{{ r.id }}" data-key="plan.theme.radius" autocomplete="off" {% if r.id == 'soft' %}checked{% endif %}>
|
|
672
|
+
<label class="btn btn-outline-secondary" for="radius-{{ r.id }}">{{ r.label }}</label>
|
|
673
|
+
{% endfor %}
|
|
674
|
+
</div>
|
|
675
|
+
</fieldset>
|
|
676
|
+
</div>
|
|
677
|
+
<div class="col-md-6">
|
|
678
|
+
<label for="cfg-title-icon" class="form-label">Navbar icon <small class="text-body-secondary">(Bootstrap icon name)</small></label>
|
|
679
|
+
<div class="input-group">
|
|
680
|
+
<span class="input-group-text"><i class="bi bi-robot" id="cfg-title-icon-preview" aria-hidden="true"></i></span>
|
|
681
|
+
<input type="text" class="form-control cfg-field" id="cfg-title-icon" value="robot" data-key="title_icon" autocomplete="off">
|
|
682
|
+
</div>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
|
|
686
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
687
|
+
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-structure">
|
|
688
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
689
|
+
</button>
|
|
690
|
+
<button class="btn btn-primary btn-next" data-next="tab-voice">
|
|
691
|
+
Next: Voice <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
692
|
+
</button>
|
|
247
693
|
</div>
|
|
694
|
+
</div>
|
|
695
|
+
</div>
|
|
696
|
+
</div>
|
|
248
697
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
698
|
+
{% comment %} ───── Step 7: Voice ───── {% endcomment %}
|
|
699
|
+
<div class="tab-pane fade" id="step-voice" role="tabpanel" aria-labelledby="tab-voice">
|
|
700
|
+
<div class="card">
|
|
701
|
+
<div class="card-body">
|
|
702
|
+
<h2 class="h4 card-title mb-1">Voice & first content</h2>
|
|
703
|
+
<p class="text-body-secondary">Set the tone, then let the assistant draft the welcome post and about page — or write them yourself.</p>
|
|
704
|
+
|
|
705
|
+
<div class="row g-3 mb-3">
|
|
706
|
+
<div class="col-md-7">
|
|
707
|
+
<fieldset>
|
|
708
|
+
<legend class="form-label fs-6 mb-2">Tone</legend>
|
|
709
|
+
<div class="d-flex flex-wrap gap-2">
|
|
710
|
+
{% for t in sb.tones %}
|
|
711
|
+
<input type="radio" class="btn-check cfg-radio" name="tone" id="tone-{{ t.id }}" value="{{ t.id }}"
|
|
712
|
+
data-key="tone" autocomplete="off" {% if forloop.first %}checked{% endif %}>
|
|
713
|
+
<label class="btn btn-outline-secondary btn-sm rounded-pill" for="tone-{{ t.id }}" title="{{ t.description | escape }}">{{ t.label }}</label>
|
|
714
|
+
{% endfor %}
|
|
715
|
+
</div>
|
|
716
|
+
</fieldset>
|
|
717
|
+
</div>
|
|
718
|
+
<div class="col-md-5">
|
|
719
|
+
<label for="cfg-audience" class="form-label">Audience</label>
|
|
720
|
+
<select class="form-select cfg-field" id="cfg-audience" data-key="audience">
|
|
721
|
+
{% for a in sb.audiences %}<option value="{{ a.id }}">{{ a.label }}</option>{% endfor %}
|
|
722
|
+
</select>
|
|
254
723
|
</div>
|
|
255
|
-
<input type="text" class="form-control cfg-field" id="cfg-posthog-key"
|
|
256
|
-
placeholder="phc_your_key_here" data-key="posthog.api_key">
|
|
257
724
|
</div>
|
|
258
725
|
|
|
259
726
|
<div class="mb-3">
|
|
260
|
-
<label
|
|
261
|
-
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
727
|
+
<label for="cfg-welcome-title" class="form-label d-flex justify-content-between">
|
|
728
|
+
<span>Welcome post title</span>
|
|
729
|
+
<button class="btn btn-link btn-sm p-0 sb-ask" type="button"
|
|
730
|
+
data-ask="Using my brief and the {tone} tone for {audience}, write the welcome post (title + 150–250 words of Markdown body) and the about page (100–200 words), then apply both.">
|
|
731
|
+
<i class="bi bi-stars" aria-hidden="true"></i> Draft both with <span class="sb-provider-name">Claude</span>
|
|
732
|
+
</button>
|
|
733
|
+
</label>
|
|
734
|
+
<input type="text" class="form-control cfg-field" id="cfg-welcome-title" data-key="welcome_title"
|
|
735
|
+
placeholder="Hello, world" autocomplete="off">
|
|
736
|
+
</div>
|
|
737
|
+
<div class="mb-3">
|
|
738
|
+
<label for="cfg-welcome-body" class="form-label">Welcome post body <small class="text-body-secondary">(Markdown)</small></label>
|
|
739
|
+
<textarea class="form-control cfg-field font-monospace small" id="cfg-welcome-body" rows="5" data-key="welcome_body"
|
|
740
|
+
placeholder="Why this site exists, what readers will find, what is coming next."></textarea>
|
|
741
|
+
</div>
|
|
742
|
+
<div>
|
|
743
|
+
<label for="cfg-about-body" class="form-label">About page <small class="text-body-secondary">(Markdown)</small></label>
|
|
744
|
+
<textarea class="form-control cfg-field font-monospace small" id="cfg-about-body" rows="4" data-key="about_body"
|
|
745
|
+
placeholder="Who you are, what you do, how to reach you."></textarea>
|
|
746
|
+
</div>
|
|
747
|
+
|
|
748
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
749
|
+
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-appearance">
|
|
750
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
751
|
+
</button>
|
|
752
|
+
<button class="btn btn-primary btn-next" data-next="tab-integrations">
|
|
753
|
+
Next: Integrations <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
754
|
+
</button>
|
|
755
|
+
</div>
|
|
756
|
+
</div>
|
|
757
|
+
</div>
|
|
758
|
+
</div>
|
|
759
|
+
|
|
760
|
+
{% comment %} ───── Step 8: Integrations ───── {% endcomment %}
|
|
761
|
+
<div class="tab-pane fade" id="step-integrations" role="tabpanel" aria-labelledby="tab-integrations">
|
|
762
|
+
<div class="card">
|
|
763
|
+
<div class="card-body">
|
|
764
|
+
<h2 class="h4 card-title mb-1">Integrations</h2>
|
|
765
|
+
<p class="text-body-secondary">Everything here is off-by-default safe: nothing sends data until you add a key, and keys never go in <code>_config.yml</code>.</p>
|
|
766
|
+
|
|
767
|
+
<div class="list-group wizard-integrations mb-3">
|
|
768
|
+
{% for i in sb.integrations %}
|
|
769
|
+
<div class="list-group-item">
|
|
770
|
+
<div class="form-check form-switch d-flex align-items-start gap-3 ps-0">
|
|
771
|
+
<input class="form-check-input cfg-switch ms-0 mt-1 flex-shrink-0" type="checkbox" id="int-{{ i.id }}"
|
|
772
|
+
data-key="integration.{{ i.id }}" {% if i.default %}checked{% endif %}>
|
|
773
|
+
<label class="form-check-label flex-grow-1" for="int-{{ i.id }}">
|
|
774
|
+
<i class="bi {{ i.icon }} me-1" aria-hidden="true"></i><strong>{{ i.label }}</strong>
|
|
775
|
+
<span class="d-block small text-body-secondary">{{ i.description }}</span>
|
|
776
|
+
</label>
|
|
777
|
+
</div>
|
|
778
|
+
{% if i.id == 'giscus' %}
|
|
779
|
+
<div class="row g-2 mt-2 wizard-subfields" data-for="int-giscus">
|
|
780
|
+
<div class="col-md-6">
|
|
781
|
+
<label for="cfg-giscus-repo-id" class="form-label small mb-1">Repo ID</label>
|
|
782
|
+
<input type="text" class="form-control form-control-sm cfg-field" id="cfg-giscus-repo-id" data-key="giscus.repo_id" placeholder="R_kgDO…" autocomplete="off">
|
|
783
|
+
</div>
|
|
784
|
+
<div class="col-md-6">
|
|
785
|
+
<label for="cfg-giscus-category-id" class="form-label small mb-1">Category ID</label>
|
|
786
|
+
<input type="text" class="form-control form-control-sm cfg-field" id="cfg-giscus-category-id" data-key="giscus.category_id" placeholder="DIC_kwDO…" autocomplete="off">
|
|
787
|
+
</div>
|
|
788
|
+
<div class="col-12 form-text">Get both from <a href="https://giscus.app" target="_blank" rel="noopener">giscus.app</a> after enabling Discussions on the repo.</div>
|
|
789
|
+
</div>
|
|
790
|
+
{% endif %}
|
|
791
|
+
{% if i.id == 'posthog' %}
|
|
792
|
+
<div class="row g-2 mt-2 wizard-subfields" data-for="int-posthog">
|
|
793
|
+
<div class="col-12">
|
|
794
|
+
<label for="cfg-posthog-key" class="form-label small mb-1">PostHog project key</label>
|
|
795
|
+
<input type="text" class="form-control form-control-sm cfg-field" id="cfg-posthog-key" data-key="posthog.api_key" placeholder="phc_…" autocomplete="off">
|
|
266
796
|
</div>
|
|
267
797
|
</div>
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
798
|
+
{% endif %}
|
|
799
|
+
{% if i.id == 'ai_chat' %}
|
|
800
|
+
<div class="row g-2 mt-2 wizard-subfields" data-for="int-ai_chat">
|
|
801
|
+
<div class="col-md-6">
|
|
802
|
+
<label for="cfg-ai-provider" class="form-label small mb-1">Chat provider</label>
|
|
803
|
+
<select class="form-select form-select-sm cfg-field" id="cfg-ai-provider" data-key="ai_provider">
|
|
804
|
+
{% for p in sb.providers %}<option value="{{ p.id }}">{{ p.label }} ({{ p.vendor }})</option>{% endfor %}
|
|
805
|
+
</select>
|
|
272
806
|
</div>
|
|
807
|
+
<div class="col-12 form-text">Written as <code>ai_chat.provider</code>; the site's chat proxy needs the matching key (<code>.env.example</code> lists it).</div>
|
|
273
808
|
</div>
|
|
809
|
+
{% endif %}
|
|
274
810
|
</div>
|
|
811
|
+
{% endfor %}
|
|
275
812
|
</div>
|
|
276
813
|
|
|
277
|
-
<div class="
|
|
278
|
-
<
|
|
279
|
-
<
|
|
814
|
+
<div class="row g-3">
|
|
815
|
+
<div class="col-md-6">
|
|
816
|
+
<label for="cfg-ga" class="form-label">Google Analytics 4 ID <small class="text-body-secondary">(optional)</small></label>
|
|
817
|
+
<input type="text" class="form-control cfg-field" id="cfg-ga" placeholder="G-XXXXXXXXXX" data-key="google_analytics" autocomplete="off">
|
|
818
|
+
</div>
|
|
819
|
+
<div class="col-md-3">
|
|
820
|
+
<label for="cfg-twitter" class="form-label">X / Twitter</label>
|
|
821
|
+
<div class="input-group">
|
|
822
|
+
<span class="input-group-text"><i class="bi bi-twitter-x" aria-hidden="true"></i></span>
|
|
823
|
+
<input type="text" class="form-control cfg-field" id="cfg-twitter" placeholder="handle" data-key="twitter_username" autocomplete="off">
|
|
824
|
+
</div>
|
|
825
|
+
</div>
|
|
826
|
+
<div class="col-md-3">
|
|
827
|
+
<label for="cfg-linkedin" class="form-label">LinkedIn</label>
|
|
828
|
+
<div class="input-group">
|
|
829
|
+
<span class="input-group-text"><i class="bi bi-linkedin" aria-hidden="true"></i></span>
|
|
830
|
+
<input type="text" class="form-control cfg-field" id="cfg-linkedin" placeholder="handle" data-key="linkedin_username" autocomplete="off">
|
|
831
|
+
</div>
|
|
832
|
+
</div>
|
|
833
|
+
<div class="col-md-6">
|
|
834
|
+
<label for="cfg-image-provider" class="form-label">Preview-image renderer <small class="text-body-secondary">(optional)</small></label>
|
|
835
|
+
<select class="form-select cfg-field" id="cfg-image-provider" data-key="image_provider">
|
|
836
|
+
<option value="">None</option>
|
|
837
|
+
{% for ip in sb.image_providers %}<option value="{{ ip.id }}">{{ ip.label }} ({{ ip.vendor }}) — {{ ip.model }}</option>{% endfor %}
|
|
838
|
+
</select>
|
|
839
|
+
<div class="form-text">Pre-configures <code>preview_images</code> in <code>_config.yml</code> for the theme's preview-image generator; the key goes in <code>.env</code>.</div>
|
|
840
|
+
</div>
|
|
841
|
+
</div>
|
|
842
|
+
|
|
843
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
844
|
+
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-voice">
|
|
845
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
280
846
|
</button>
|
|
281
|
-
<button class="btn btn-primary btn-next" data-next="tab-
|
|
282
|
-
|
|
847
|
+
<button class="btn btn-primary btn-next" data-next="tab-build">
|
|
848
|
+
Next: Build <i class="bi bi-arrow-right" aria-hidden="true"></i>
|
|
283
849
|
</button>
|
|
284
850
|
</div>
|
|
285
851
|
</div>
|
|
286
852
|
</div>
|
|
287
853
|
</div>
|
|
288
854
|
|
|
289
|
-
|
|
290
|
-
<div class="tab-pane fade" id="step-
|
|
855
|
+
{% comment %} ───── Step 9: Build ───── {% endcomment %}
|
|
856
|
+
<div class="tab-pane fade" id="step-build" role="tabpanel" aria-labelledby="tab-build">
|
|
291
857
|
<div class="card">
|
|
292
858
|
<div class="card-body">
|
|
293
|
-
<
|
|
294
|
-
<p class="text-
|
|
295
|
-
|
|
296
|
-
<div class="position-relative">
|
|
297
|
-
<pre class="bg-dark text-light p-3 rounded" style="max-height:450px;overflow:auto"><code id="yaml-preview">Loading…</code></pre>
|
|
298
|
-
<button class="btn btn-sm btn-outline-light position-absolute top-0 end-0 m-2" id="btn-copy"
|
|
299
|
-
title="Copy to clipboard">
|
|
300
|
-
<i class="bi bi-clipboard"></i>
|
|
301
|
-
</button>
|
|
302
|
-
</div>
|
|
859
|
+
<h2 class="h4 card-title mb-1">Build & launch</h2>
|
|
860
|
+
<p class="text-body-secondary">Every file is in the preview on the right. Write the project and start Docker from here, or take the files and run the commands yourself.</p>
|
|
303
861
|
|
|
304
|
-
<div
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
</
|
|
308
|
-
<div>
|
|
309
|
-
<
|
|
310
|
-
<
|
|
862
|
+
<div id="wizard-review-warnings" role="status" aria-live="polite" class="mb-3"></div>
|
|
863
|
+
|
|
864
|
+
<div class="mb-3" id="sb-project-picker">
|
|
865
|
+
<label for="sb-project-select" class="form-label fw-semibold">Modify an existing site</label>
|
|
866
|
+
<div class="input-group">
|
|
867
|
+
<select class="form-select" id="sb-project-select" disabled>
|
|
868
|
+
<option value="">Connect the dev proxy to list sites</option>
|
|
869
|
+
</select>
|
|
870
|
+
<button class="btn btn-outline-secondary sb-needs-proxy" type="button" id="btn-project-open" disabled>
|
|
871
|
+
<i class="bi bi-folder2-open" aria-hidden="true"></i> Open
|
|
311
872
|
</button>
|
|
312
|
-
|
|
313
|
-
|
|
873
|
+
</div>
|
|
874
|
+
<div class="form-text">Any site under the target root — one this builder wrote, or one you copied there. The assistant can then read, edit and add files, generate images and rebuild it.</div>
|
|
875
|
+
</div>
|
|
876
|
+
|
|
877
|
+
<div class="mb-3">
|
|
878
|
+
<label for="cfg-target" class="form-label fw-semibold">Project folder</label>
|
|
879
|
+
<div class="input-group">
|
|
880
|
+
<span class="input-group-text sb-target-root" id="target-root" title="New sites are created under this folder">…/</span>
|
|
881
|
+
<input type="text" class="form-control cfg-field" id="cfg-target" data-key="target" placeholder="my-site" autocomplete="off" aria-describedby="target-resolved">
|
|
882
|
+
<button class="btn btn-outline-secondary" type="button" id="btn-target-check">
|
|
883
|
+
<i class="bi bi-folder2-open" aria-hidden="true"></i> Check
|
|
314
884
|
</button>
|
|
315
885
|
</div>
|
|
886
|
+
<div class="form-text" id="target-resolved">Created beside the theme checkout. Must be new or empty unless you allow overwriting.</div>
|
|
887
|
+
<div class="form-check form-switch mt-2">
|
|
888
|
+
<input class="form-check-input cfg-switch" type="checkbox" id="cfg-overwrite" data-key="overwrite">
|
|
889
|
+
<label class="form-check-label" for="cfg-overwrite">Allow replacing files that already exist there</label>
|
|
890
|
+
</div>
|
|
316
891
|
</div>
|
|
317
892
|
|
|
318
|
-
<div class="
|
|
319
|
-
<
|
|
320
|
-
|
|
893
|
+
<div class="sb-build-actions d-grid gap-2 d-sm-flex flex-wrap mb-3">
|
|
894
|
+
<button class="btn btn-primary sb-needs-proxy" type="button" id="btn-write-project" disabled>
|
|
895
|
+
<i class="bi bi-hdd" aria-hidden="true"></i> Write project
|
|
896
|
+
</button>
|
|
897
|
+
<button class="btn btn-success sb-needs-proxy" type="button" id="btn-compose-up" disabled>
|
|
898
|
+
<i class="bi bi-play-fill" aria-hidden="true"></i> docker compose up
|
|
899
|
+
</button>
|
|
900
|
+
<button class="btn btn-outline-secondary sb-needs-proxy" type="button" id="btn-compose-build" disabled
|
|
901
|
+
title="Runs jekyll build inside the running container to validate the site">
|
|
902
|
+
<i class="bi bi-hammer" aria-hidden="true"></i> jekyll build
|
|
903
|
+
</button>
|
|
904
|
+
<button class="btn btn-outline-secondary sb-needs-proxy" type="button" id="btn-compose-logs" disabled>
|
|
905
|
+
<i class="bi bi-terminal" aria-hidden="true"></i> Logs
|
|
906
|
+
</button>
|
|
907
|
+
<button class="btn btn-outline-danger sb-needs-proxy" type="button" id="btn-compose-down" disabled>
|
|
908
|
+
<i class="bi bi-stop-fill" aria-hidden="true"></i> Stop
|
|
909
|
+
</button>
|
|
910
|
+
<a class="btn btn-outline-primary" id="btn-open-site" href="http://localhost:{{ sb_port }}/" target="_blank" rel="noopener">
|
|
911
|
+
<i class="bi bi-box-arrow-up-right" aria-hidden="true"></i> Open site
|
|
912
|
+
</a>
|
|
913
|
+
<button class="btn btn-outline-secondary" type="button" id="btn-check-live">
|
|
914
|
+
<i class="bi bi-activity" aria-hidden="true"></i> Is it live?
|
|
915
|
+
</button>
|
|
916
|
+
</div>
|
|
917
|
+
<p class="small text-body-secondary sb-proxy-hint" id="build-proxy-hint">
|
|
918
|
+
<i class="bi bi-plug" aria-hidden="true"></i> Connect the dev proxy (step 1) to write and run from here. Without it, download the bundle and run the commands below.
|
|
919
|
+
</p>
|
|
920
|
+
|
|
921
|
+
<pre class="wizard-terminal" id="wizard-terminal" aria-live="polite" aria-label="Build output" tabindex="0" hidden></pre>
|
|
922
|
+
|
|
923
|
+
<details class="mt-3" id="manual-run">
|
|
924
|
+
<summary class="fw-semibold">Run it yourself</summary>
|
|
925
|
+
<ol class="small mt-2 mb-0 sb-manual-steps">
|
|
926
|
+
<li>Download <strong>Bundle</strong> from the preview panel and run it: <span class="wizard-cmd d-inline-flex"><code id="cmd-bundle">bash zer0-site-bundle.sh my-site</code><button class="btn btn-sm btn-link" type="button" data-copy-target="#cmd-bundle" aria-label="Copy command"><i class="bi bi-clipboard" aria-hidden="true"></i></button></span></li>
|
|
927
|
+
<li>Start the dev server: <span class="wizard-cmd d-inline-flex"><code id="cmd-up">cd my-site && docker compose up</code><button class="btn btn-sm btn-link" type="button" data-copy-target="#cmd-up" aria-label="Copy command"><i class="bi bi-clipboard" aria-hidden="true"></i></button></span></li>
|
|
928
|
+
<li>Open <a id="link-local" href="http://localhost:{{ sb_port }}/" target="_blank" rel="noopener">http://localhost:{{ sb_port }}/</a>. Edit a file — the page reloads by itself.</li>
|
|
929
|
+
<li>Publish: <span class="wizard-cmd d-inline-flex"><code id="cmd-publish">gh repo create my-site --public --source=. --push</code><button class="btn btn-sm btn-link" type="button" data-copy-target="#cmd-publish" aria-label="Copy command"><i class="bi bi-clipboard" aria-hidden="true"></i></button></span> then enable Pages in the repository settings.</li>
|
|
930
|
+
</ol>
|
|
931
|
+
</details>
|
|
932
|
+
|
|
933
|
+
<div class="wizard-nav d-flex justify-content-between">
|
|
934
|
+
<button class="btn btn-outline-secondary btn-prev" data-prev="tab-integrations">
|
|
935
|
+
<i class="bi bi-arrow-left" aria-hidden="true"></i> Back
|
|
936
|
+
</button>
|
|
937
|
+
<button class="btn btn-outline-primary" type="button" id="btn-download-all">
|
|
938
|
+
<i class="bi bi-file-earmark-zip" aria-hidden="true"></i> Download bundle
|
|
939
|
+
</button>
|
|
321
940
|
</div>
|
|
322
941
|
</div>
|
|
323
942
|
</div>
|
|
324
943
|
</div>
|
|
325
944
|
|
|
326
|
-
</div
|
|
945
|
+
</div>{% comment %} /tab-content {% endcomment %}
|
|
946
|
+
</div>
|
|
947
|
+
|
|
948
|
+
{% comment %} ============================================================ {% endcomment %}
|
|
949
|
+
{% comment %} 3. Side column — Claude session + live multi-file preview {% endcomment %}
|
|
950
|
+
{% comment %} ============================================================ {% endcomment %}
|
|
951
|
+
<div class="col-lg-4">
|
|
952
|
+
<aside class="wizard-side sticky-lg-top" aria-label="AI session and generated files">
|
|
953
|
+
|
|
954
|
+
{% include setup/claude-session.html %}
|
|
955
|
+
|
|
956
|
+
<section class="wizard-preview mt-3" aria-labelledby="wizard-preview-heading">
|
|
957
|
+
<div class="d-flex align-items-center justify-content-between mb-2">
|
|
958
|
+
<h2 class="h6 mb-0" id="wizard-preview-heading">
|
|
959
|
+
<i class="bi bi-files" aria-hidden="true"></i> Generated files
|
|
960
|
+
</h2>
|
|
961
|
+
<span class="badge text-bg-secondary wizard-preview-live">live</span>
|
|
962
|
+
</div>
|
|
963
|
+
|
|
964
|
+
<div class="wizard-file-tabs nav nav-pills flex-nowrap overflow-auto mb-2" id="wizard-file-tabs" role="tablist" aria-label="Generated files">
|
|
965
|
+
{% for f in sb.generated_files %}
|
|
966
|
+
<button class="nav-link wizard-file-tab{% if forloop.first %} active{% endif %}" type="button" role="tab"
|
|
967
|
+
data-file="{{ f.path }}" title="{{ f.description | escape }}"
|
|
968
|
+
aria-selected="{% if forloop.first %}true{% else %}false{% endif %}">{{ f.label }}</button>
|
|
969
|
+
{% endfor %}
|
|
970
|
+
</div>
|
|
971
|
+
|
|
972
|
+
<div class="position-relative">
|
|
973
|
+
<pre class="wizard-preview-code bg-dark text-light p-3 rounded" data-file="_config.yml"><code id="yaml-preview">Loading…</code></pre>
|
|
974
|
+
<button class="btn btn-sm btn-outline-light position-absolute top-0 end-0 m-2" id="btn-copy"
|
|
975
|
+
type="button" title="Copy this file" aria-label="Copy this file to clipboard">
|
|
976
|
+
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
|
977
|
+
</button>
|
|
978
|
+
</div>
|
|
979
|
+
<div class="small text-body-secondary mt-1" id="wizard-file-description"></div>
|
|
980
|
+
|
|
981
|
+
<div class="d-grid gap-2 d-sm-flex mt-3">
|
|
982
|
+
<button class="btn btn-outline-primary flex-sm-fill" id="btn-copy-full" type="button">
|
|
983
|
+
<i class="bi bi-clipboard" aria-hidden="true"></i> Copy file
|
|
984
|
+
</button>
|
|
985
|
+
<button class="btn btn-primary flex-sm-fill" id="btn-download" type="button">
|
|
986
|
+
<i class="bi bi-download" aria-hidden="true"></i> Download file
|
|
987
|
+
</button>
|
|
988
|
+
</div>
|
|
989
|
+
</section>
|
|
990
|
+
</aside>
|
|
991
|
+
</div>
|
|
992
|
+
|
|
993
|
+
</div>{% comment %} /row {% endcomment %}
|
|
994
|
+
|
|
995
|
+
<div class="toast-container position-fixed bottom-0 start-50 translate-middle-x p-3">
|
|
996
|
+
<div class="toast align-items-center text-bg-dark border-0" id="wizard-toast" role="status" aria-live="polite" aria-atomic="true">
|
|
997
|
+
<div class="d-flex">
|
|
998
|
+
<div class="toast-body" id="wizard-toast-body">Copied</div>
|
|
999
|
+
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
1000
|
+
</div>
|
|
327
1001
|
</div>
|
|
328
1002
|
</div>
|
|
329
1003
|
</div>
|
|
330
1004
|
|
|
331
|
-
|
|
1005
|
+
{% comment %} Catalogs + framework brief shared by both scripts (from _data/site_builder.yml). {% endcomment %}
|
|
1006
|
+
<script id="siteBuilderData" type="application/json">{{ sb | jsonify }}</script>
|
|
1007
|
+
|
|
1008
|
+
{% comment %}
|
|
1009
|
+
Runtime configuration. The AI session is proxy-only: the endpoint below is
|
|
1010
|
+
the dev proxy's /api/wizard base; chat goes to ai_chat.endpoint (or an explicit
|
|
1011
|
+
site_builder.chat_endpoint). No credential is ever present in this JSON —
|
|
1012
|
+
a token pasted on the Connect step goes straight to the localhost proxy.
|
|
1013
|
+
{% endcomment %}
|
|
1014
|
+
<script id="siteBuilderConfig" type="application/json">
|
|
1015
|
+
{
|
|
1016
|
+
"enabled": {% if sb_cfg.enabled == false %}false{% else %}true{% endif %},
|
|
1017
|
+
"endpoint": {{ sb_cfg.endpoint | default: "/api/wizard" | jsonify }},
|
|
1018
|
+
"chatEndpoint": {{ sb_cfg.chat_endpoint | default: site.ai_chat.endpoint | default: "/api/chat" | jsonify }},
|
|
1019
|
+
"provider": {{ sb_cfg.provider | default: "auto" | jsonify }},
|
|
1020
|
+
"model": {{ sb_cfg.model | default: site.ai_chat.model | default: "claude-opus-4-8" | jsonify }},
|
|
1021
|
+
"mode": {{ sb_cfg.mode | default: "guided" | jsonify }},
|
|
1022
|
+
"imageProvider": {{ sb_cfg.image_provider | default: "" | jsonify }},
|
|
1023
|
+
"maxTokens": {{ sb_cfg.max_tokens | default: 8192 }},
|
|
1024
|
+
"defaultPort": {{ sb_port }},
|
|
1025
|
+
"searchIndex": {{ "/search.json" | relative_url | jsonify }},
|
|
1026
|
+
"docsBase": {{ "/docs/" | relative_url | jsonify }},
|
|
1027
|
+
"themeVersion": {{ site.theme_version | default: site.data.theme-manifest.version | default: "" | jsonify }},
|
|
1028
|
+
"themeRepository": "bamr87/zer0-mistakes"
|
|
1029
|
+
}
|
|
1030
|
+
</script>
|
|
1031
|
+
|
|
1032
|
+
<script defer src="{{ '/assets/js/setup-wizard.js' | relative_url }}"></script>
|
|
1033
|
+
<script defer src="{{ '/assets/js/site-builder.js' | relative_url }}"></script>
|