jekyll-theme-zer0 0.22.0 → 0.22.19

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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +236 -0
  3. data/README.md +66 -19
  4. data/_data/navigation/admin.yml +53 -0
  5. data/_data/theme_backgrounds.yml +121 -0
  6. data/_includes/components/admin-tabs.html +59 -0
  7. data/_includes/components/analytics-dashboard.html +232 -0
  8. data/_includes/components/background-customizer.html +159 -0
  9. data/_includes/components/background-settings.html +137 -0
  10. data/_includes/components/collection-manager.html +151 -0
  11. data/_includes/components/component-showcase.html +452 -0
  12. data/_includes/components/config-editor.html +207 -0
  13. data/_includes/components/config-viewer.html +479 -0
  14. data/_includes/components/env-dashboard.html +154 -0
  15. data/_includes/components/feature-card.html +94 -0
  16. data/_includes/components/info-section.html +172 -149
  17. data/_includes/components/js-cdn.html +4 -1
  18. data/_includes/components/nav-editor.html +99 -0
  19. data/_includes/components/setup-banner.html +28 -0
  20. data/_includes/components/setup-check.html +53 -0
  21. data/_includes/components/svg-background.html +42 -0
  22. data/_includes/components/theme-customizer.html +46 -0
  23. data/_includes/content/seo.html +68 -135
  24. data/_includes/core/footer.html +1 -1
  25. data/_includes/core/head.html +3 -2
  26. data/_includes/core/header.html +14 -7
  27. data/_includes/landing/landing-install-cards.html +18 -7
  28. data/_includes/navigation/admin-nav.html +95 -0
  29. data/_includes/navigation/navbar.html +43 -5
  30. data/_includes/navigation/sidebar-left.html +1 -1
  31. data/_includes/setup/wizard.html +330 -0
  32. data/_layouts/admin.html +166 -0
  33. data/_layouts/landing.html +23 -9
  34. data/_layouts/root.html +12 -6
  35. data/_layouts/setup.html +73 -0
  36. data/_plugins/preview_image_generator.rb +26 -12
  37. data/_sass/core/_navbar.scss +2 -2
  38. data/_sass/custom.scss +28 -6
  39. data/_sass/theme/_background-mixins.scss +95 -0
  40. data/_sass/theme/_backgrounds.scss +156 -0
  41. data/_sass/theme/_color-modes.scss +2 -1
  42. data/assets/backgrounds/gradients/air.svg +15 -0
  43. data/assets/backgrounds/gradients/aqua.svg +15 -0
  44. data/assets/backgrounds/gradients/contrast.svg +15 -0
  45. data/assets/backgrounds/gradients/dark.svg +15 -0
  46. data/assets/backgrounds/gradients/dirt.svg +15 -0
  47. data/assets/backgrounds/gradients/mint.svg +15 -0
  48. data/assets/backgrounds/gradients/neon.svg +15 -0
  49. data/assets/backgrounds/gradients/plum.svg +15 -0
  50. data/assets/backgrounds/gradients/sunrise.svg +15 -0
  51. data/assets/backgrounds/noise/air.svg +8 -0
  52. data/assets/backgrounds/noise/aqua.svg +8 -0
  53. data/assets/backgrounds/noise/contrast.svg +8 -0
  54. data/assets/backgrounds/noise/dark.svg +8 -0
  55. data/assets/backgrounds/noise/dirt.svg +8 -0
  56. data/assets/backgrounds/noise/mint.svg +8 -0
  57. data/assets/backgrounds/noise/neon.svg +8 -0
  58. data/assets/backgrounds/noise/plum.svg +8 -0
  59. data/assets/backgrounds/noise/sunrise.svg +8 -0
  60. data/assets/backgrounds/patterns/air.svg +7 -0
  61. data/assets/backgrounds/patterns/aqua.svg +7 -0
  62. data/assets/backgrounds/patterns/contrast.svg +4 -0
  63. data/assets/backgrounds/patterns/dark.svg +5 -0
  64. data/assets/backgrounds/patterns/dirt.svg +5 -0
  65. data/assets/backgrounds/patterns/mint.svg +6 -0
  66. data/assets/backgrounds/patterns/neon.svg +6 -0
  67. data/assets/backgrounds/patterns/plum.svg +6 -0
  68. data/assets/backgrounds/patterns/sunrise.svg +5 -0
  69. data/assets/js/background-customizer.js +73 -0
  70. data/assets/js/code-copy.js +18 -47
  71. data/assets/js/config-utility.js +307 -0
  72. data/assets/js/nav-editor.js +39 -0
  73. data/assets/js/palette-generator.js +415 -0
  74. data/assets/js/search-modal.js +31 -11
  75. data/assets/js/setup-wizard.js +306 -0
  76. data/assets/js/skin-editor.js +645 -0
  77. data/assets/js/theme-customizer.js +102 -0
  78. data/assets/js/ui-enhancements.js +15 -24
  79. data/assets/vendor/bootstrap/css/bootstrap.min.css +1 -0
  80. data/assets/vendor/bootstrap/js/bootstrap.bundle.min.js +1 -0
  81. data/scripts/README.md +45 -0
  82. data/scripts/features/generate-preview-images +297 -7
  83. data/scripts/features/install-preview-generator +51 -33
  84. data/scripts/fork-cleanup.sh +92 -19
  85. data/scripts/github-setup.sh +284 -0
  86. data/scripts/init_setup.sh +0 -1
  87. data/scripts/lib/frontmatter.sh +543 -0
  88. data/scripts/lib/migrate.sh +265 -0
  89. data/scripts/lib/preview_generator.py +607 -32
  90. data/scripts/lint-pages +505 -0
  91. data/scripts/migrate.sh +201 -0
  92. data/scripts/platform/setup-linux.sh +244 -0
  93. data/scripts/platform/setup-macos.sh +187 -0
  94. data/scripts/platform/setup-wsl.sh +196 -0
  95. metadata +71 -6
@@ -0,0 +1,306 @@
1
+ /**
2
+ * ===================================================================
3
+ * Setup Wizard — _config.yml Generator
4
+ * ===================================================================
5
+ *
6
+ * Reads form inputs from the wizard include, builds a YAML string,
7
+ * and offers Download / Copy actions. Pure vanilla JS, no deps
8
+ * beyond Bootstrap 5 (already on the page).
9
+ *
10
+ * ===================================================================
11
+ */
12
+
13
+ (function () {
14
+ 'use strict';
15
+
16
+ // ── helpers ────────────────────────────────────────────────────────
17
+
18
+ /**
19
+ * Escape a YAML scalar string value (wrap in quotes if needed).
20
+ * Multi-line input (e.g., textarea newlines) is intentionally collapsed to
21
+ * a single line with spaces so the generated _config.yml remains valid YAML.
22
+ * All form fields in this wizard expect single-line values.
23
+ */
24
+ function yamlValue(val) {
25
+ if (val === '' || val === null || val === undefined) return '""';
26
+
27
+ // Normalize newlines and collapse whitespace to keep scalar values single-line
28
+ var normalized = String(val)
29
+ .replace(/\r\n|\r|\n/g, ' ')
30
+ .replace(/\s{2,}/g, ' ')
31
+ .trim();
32
+
33
+ if (normalized === '') return '""';
34
+ if (normalized === 'true' || normalized === 'false') return normalized;
35
+ if (/^[0-9]+$/.test(normalized)) return normalized;
36
+ // Wrap in quotes if it contains special chars
37
+ if (/[:#{}[\],&*?|>!%@`]/.test(normalized) || normalized.includes("'") || normalized.includes('"')) {
38
+ return '"' + normalized.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
39
+ }
40
+ return '"' + normalized + '"';
41
+ }
42
+
43
+ /** Pad a YAML key to 25 chars for alignment. */
44
+ function pad(key, width) {
45
+ width = width || 25;
46
+ return (key + ' '.repeat(width)).slice(0, width);
47
+ }
48
+
49
+ /** Return the permalink pattern for a given collection name. */
50
+ function collectionPermalink(col) {
51
+ switch (col) {
52
+ case 'posts': return '/posts/:title/';
53
+ case 'docs': return '/docs/:path/';
54
+ case 'about': return '/about/:path/';
55
+ default: return '/' + col + '/:path/';
56
+ }
57
+ }
58
+
59
+ // ── YAML builder ──────────────────────────────────────────────────
60
+
61
+ function buildYAML() {
62
+ var fields = {};
63
+
64
+ // Read simple fields
65
+ document.querySelectorAll('.cfg-field').forEach(function (el) {
66
+ var key = el.getAttribute('data-key');
67
+ if (!key) return;
68
+ var val = (el.tagName === 'TEXTAREA' || el.tagName === 'SELECT')
69
+ ? el.value.trim()
70
+ : el.value.trim();
71
+ if (val) fields[key] = val;
72
+ });
73
+
74
+ // Read collection toggles
75
+ var collections = [];
76
+ document.querySelectorAll('.cfg-collection').forEach(function (el) {
77
+ if (el.checked) {
78
+ collections.push(el.getAttribute('data-col'));
79
+ }
80
+ });
81
+
82
+ // Read PostHog toggle
83
+ var posthogEnabled = document.getElementById('cfg-posthog-enabled');
84
+ var posthogOn = posthogEnabled && posthogEnabled.checked;
85
+
86
+ // Build YAML
87
+ var lines = [];
88
+ lines.push('# =============================================================================');
89
+ lines.push('# Site Configuration — generated by Setup Wizard');
90
+ lines.push('# Docs: https://jekyllrb.com/docs/configuration/');
91
+ lines.push('# =============================================================================');
92
+ lines.push('');
93
+
94
+ // Site Identity
95
+ lines.push('# ── Site Identity ──────────────────────────────────────────────────');
96
+ lines.push(pad('title') + ': ' + yamlValue(fields.title || 'My Site'));
97
+ if (fields.subtitle) {
98
+ lines.push(pad('subtitle') + ': ' + yamlValue(fields.subtitle));
99
+ }
100
+ lines.push(pad('description') + ': ' + yamlValue(fields.description || ''));
101
+ lines.push(pad('founder') + ': ' + yamlValue(fields.founder || ''));
102
+ if (fields.email) {
103
+ lines.push(pad('email') + ': ' + yamlValue(fields.email));
104
+ }
105
+ lines.push('');
106
+
107
+ // GitHub
108
+ lines.push('# ── GitHub ─────────────────────────────────────────────────────────');
109
+ var ghUser = fields.github_user || 'your-username';
110
+ var repoName = fields.repository_name || (ghUser !== 'your-username' ? ghUser + '-site' : 'my-site');
111
+ lines.push(pad('github_user') + ': &github_user ' + yamlValue(ghUser));
112
+ lines.push(pad('repository_name') + ': &github_repository ' + yamlValue(repoName));
113
+ lines.push('');
114
+
115
+ // URLs
116
+ lines.push('# ── URLs & Deployment ──────────────────────────────────────────────');
117
+ lines.push(pad('url') + ': ' + yamlValue(fields.url || 'https://' + ghUser + '.github.io'));
118
+ lines.push(pad('baseurl') + ': ' + yamlValue(fields.baseurl || ''));
119
+ lines.push(pad('remote_theme') + ': ' + yamlValue(fields.remote_theme || 'bamr87/zer0-mistakes'));
120
+ lines.push(pad('permalink') + ': ' + (fields.permalink || '/:categories/:title/'));
121
+ lines.push(pad('port') + ': 4000');
122
+ lines.push('');
123
+
124
+ // Collections
125
+ lines.push('# ── Collections ────────────────────────────────────────────────────');
126
+ lines.push('collections:');
127
+ collections.forEach(function (col) {
128
+ lines.push(' ' + col + ':');
129
+ lines.push(' output: true');
130
+ lines.push(' permalink: ' + collectionPermalink(col));
131
+ });
132
+ lines.push('');
133
+
134
+ // Defaults
135
+ lines.push('# ── Default Front Matter ───────────────────────────────────────────');
136
+ lines.push('defaults:');
137
+ if (collections.indexOf('posts') !== -1) {
138
+ lines.push(' - scope:');
139
+ lines.push(' path: ""');
140
+ lines.push(' type: "posts"');
141
+ lines.push(' values:');
142
+ lines.push(' layout: "article"');
143
+ lines.push(' author: "default"');
144
+ }
145
+ if (collections.indexOf('docs') !== -1) {
146
+ lines.push(' - scope:');
147
+ lines.push(' path: ""');
148
+ lines.push(' type: "docs"');
149
+ lines.push(' values:');
150
+ lines.push(' layout: "default"');
151
+ }
152
+ if (collections.indexOf('about') !== -1) {
153
+ lines.push(' - scope:');
154
+ lines.push(' path: ""');
155
+ lines.push(' type: "about"');
156
+ lines.push(' values:');
157
+ lines.push(' layout: "default"');
158
+ }
159
+ lines.push(' - scope:');
160
+ lines.push(' path: ""');
161
+ lines.push(' type: "pages"');
162
+ lines.push(' values:');
163
+ lines.push(' layout: "default"');
164
+ lines.push('');
165
+
166
+ // Build settings
167
+ lines.push('# ── Build ──────────────────────────────────────────────────────────');
168
+ lines.push(pad('markdown') + ': kramdown');
169
+ lines.push(pad('highlighter') + ': rouge');
170
+ lines.push(pad('public_folder') + ': assets');
171
+ lines.push('');
172
+
173
+ // Plugins
174
+ lines.push('# ── Plugins ────────────────────────────────────────────────────────');
175
+ lines.push('plugins:');
176
+ lines.push(' - jekyll-feed');
177
+ lines.push(' - jekyll-sitemap');
178
+ lines.push(' - jekyll-seo-tag');
179
+ lines.push(' - jekyll-remote-theme');
180
+ lines.push('');
181
+
182
+ // Analytics
183
+ lines.push('# ── Analytics ──────────────────────────────────────────────────────');
184
+ if (fields.google_analytics) {
185
+ lines.push(pad('google_analytics') + ': ' + yamlValue(fields.google_analytics));
186
+ } else {
187
+ lines.push(pad('google_analytics') + ': ""');
188
+ }
189
+ lines.push('posthog:');
190
+ lines.push(' enabled: ' + (posthogOn ? 'true' : 'false'));
191
+ lines.push(' api_key: ' + yamlValue(fields['posthog.api_key'] || ''));
192
+ lines.push('');
193
+
194
+ // Social
195
+ if (fields.twitter_username || fields.linkedin_username) {
196
+ lines.push('# ── Social ─────────────────────────────────────────────────────────');
197
+ if (fields.twitter_username) {
198
+ lines.push(pad('twitter_username') + ': ' + yamlValue(fields.twitter_username));
199
+ }
200
+ if (fields.linkedin_username) {
201
+ lines.push(pad('linkedin_username') + ': ' + yamlValue(fields.linkedin_username));
202
+ }
203
+ lines.push('');
204
+ }
205
+
206
+ // Exclude
207
+ lines.push('# ── Exclude from build ─────────────────────────────────────────────');
208
+ lines.push('exclude:');
209
+ lines.push(' - .sass-cache/');
210
+ lines.push(' - .jekyll-cache/');
211
+ lines.push(' - node_modules/');
212
+ lines.push(' - vendor/');
213
+ lines.push(' - Gemfile.lock');
214
+ lines.push(' - scripts/');
215
+ lines.push(' - test/');
216
+ lines.push(' - templates/');
217
+ lines.push(' - "*.log"');
218
+
219
+ return lines.join('\n');
220
+ }
221
+
222
+ // ── actions ────────────────────────────────────────────────────────
223
+
224
+ function updatePreview() {
225
+ var preview = document.getElementById('yaml-preview');
226
+ if (preview) {
227
+ preview.textContent = buildYAML();
228
+ }
229
+ }
230
+
231
+ function downloadYAML() {
232
+ var yaml = buildYAML();
233
+ var blob = new Blob([yaml], { type: 'text/yaml;charset=utf-8' });
234
+ var url = URL.createObjectURL(blob);
235
+ var a = document.createElement('a');
236
+ a.href = url;
237
+ a.download = '_config.yml';
238
+ document.body.appendChild(a);
239
+ a.click();
240
+ document.body.removeChild(a);
241
+ URL.revokeObjectURL(url);
242
+ }
243
+
244
+ function copyYAML() {
245
+ var yaml = buildYAML();
246
+ navigator.clipboard.writeText(yaml).then(function () {
247
+ var btn = document.getElementById('btn-copy-full') || document.getElementById('btn-copy');
248
+ if (btn) {
249
+ var orig = btn.innerHTML;
250
+ btn.innerHTML = '<i class="bi bi-check-lg"></i> Copied!';
251
+ setTimeout(function () { btn.innerHTML = orig; }, 2000);
252
+ }
253
+ });
254
+ }
255
+
256
+ // ── wiring ─────────────────────────────────────────────────────────
257
+
258
+ document.addEventListener('DOMContentLoaded', function () {
259
+ // Next / Prev buttons
260
+ document.querySelectorAll('.btn-next').forEach(function (btn) {
261
+ btn.addEventListener('click', function () {
262
+ var target = btn.getAttribute('data-next');
263
+ var tab = document.getElementById(target);
264
+ if (tab) new bootstrap.Tab(tab).show();
265
+ updatePreview();
266
+ });
267
+ });
268
+
269
+ document.querySelectorAll('.btn-prev').forEach(function (btn) {
270
+ btn.addEventListener('click', function () {
271
+ var target = btn.getAttribute('data-prev');
272
+ var tab = document.getElementById(target);
273
+ if (tab) new bootstrap.Tab(tab).show();
274
+ });
275
+ });
276
+
277
+ // Live update on review tab activation
278
+ var reviewTab = document.getElementById('tab-review');
279
+ if (reviewTab) {
280
+ reviewTab.addEventListener('shown.bs.tab', updatePreview);
281
+ }
282
+
283
+ // Description char count
284
+ var descField = document.getElementById('cfg-description');
285
+ var descCount = document.getElementById('desc-count');
286
+ if (descField && descCount) {
287
+ descField.addEventListener('input', function () {
288
+ descCount.textContent = descField.value.length;
289
+ });
290
+ }
291
+
292
+ // Download / Copy
293
+ var dlBtn = document.getElementById('btn-download');
294
+ if (dlBtn) dlBtn.addEventListener('click', downloadYAML);
295
+
296
+ var copyBtn = document.getElementById('btn-copy');
297
+ if (copyBtn) copyBtn.addEventListener('click', copyYAML);
298
+
299
+ var copyFullBtn = document.getElementById('btn-copy-full');
300
+ if (copyFullBtn) copyFullBtn.addEventListener('click', copyYAML);
301
+
302
+ // Initial preview
303
+ updatePreview();
304
+ });
305
+
306
+ })();