jekyll-theme-zer0 0.10.0 → 0.10.4
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 +161 -0
- data/README.md +495 -720
- data/_includes/components/cookie-consent.html +2 -2
- data/_includes/components/mermaid.html +98 -9
- data/_includes/components/post-card.html +2 -2
- data/_includes/content/intro.html +13 -1
- data/_includes/content/sitemap.html +4 -9
- data/_includes/core/header.html +1 -1
- data/_includes/stats/stats-categories.html +5 -5
- data/_includes/stats/stats-header.html +7 -7
- data/_includes/stats/stats-metrics.html +8 -8
- data/_includes/stats/stats-no-data.html +9 -9
- data/_includes/stats/stats-overview.html +4 -4
- data/_includes/stats/stats-tags.html +6 -6
- data/_layouts/blog.html +1 -1
- data/_layouts/category.html +16 -6
- data/_layouts/collection.html +8 -3
- data/_layouts/journals.html +8 -3
- data/_layouts/landing.html +1 -1
- data/_layouts/sitemap-collection.html +3 -26
- data/_sass/custom.scss +20 -12
- data/assets/images/previews/10-ai-tools-that-will-transform-your-productivity-.png +0 -0
- data/assets/images/previews/business.png +0 -0
- data/assets/images/previews/css-grid-mastery-build-any-layout-you-can-imagine.png +0 -0
- data/assets/images/previews/development.png +0 -0
- data/assets/images/previews/github-setup-deployment.png +0 -0
- data/assets/images/previews/jekyll-setup.png +0 -0
- data/assets/images/previews/machine-setup.png +0 -0
- data/assets/images/previews/published-documentation-library.png +0 -0
- data/assets/images/previews/quantum-computing-explained-from-qubits-to-quantum.png +0 -0
- data/assets/images/previews/science.png +0 -0
- data/assets/images/previews/technology.png +0 -0
- data/assets/images/previews/the-complete-guide-to-startup-funding-in-2025.png +0 -0
- data/assets/images/previews/the-remote-work-revolution-how-global-teams-are-re.png +0 -0
- data/assets/images/previews/tutorial.png +0 -0
- data/assets/images/previews/world-news.png +0 -0
- data/assets/images/previews/zer0-mistakes-news-network-building-dynamic-news-s.png +0 -0
- data/assets/images/previews/zer0-mistakes-quick-start-guide.png +0 -0
- data/assets/js/auto-hide-nav.js +79 -16
- data/scripts/lib/preview_generator.py +37 -22
- data/scripts/test-mermaid.sh +51 -11
- metadata +18 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
layout:
|
|
2
|
+
layout: root
|
|
3
3
|
---
|
|
4
4
|
<!--
|
|
5
5
|
===================================================================
|
|
@@ -8,9 +8,9 @@ layout: default
|
|
|
8
8
|
|
|
9
9
|
File: sitemap-collection.html
|
|
10
10
|
Path: _layouts/sitemap-collection.html
|
|
11
|
-
Inherits:
|
|
11
|
+
Inherits: root.html
|
|
12
12
|
Purpose: Unified layout combining collection display with site statistics
|
|
13
|
-
and comprehensive site structure overview
|
|
13
|
+
and comprehensive site structure overview (full-width, no sidebars)
|
|
14
14
|
|
|
15
15
|
Features:
|
|
16
16
|
- Complete site overview with statistics
|
|
@@ -419,29 +419,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
419
419
|
});
|
|
420
420
|
});
|
|
421
421
|
|
|
422
|
-
// Add fade-in animation to cards
|
|
423
|
-
const observerOptions = {
|
|
424
|
-
threshold: 0.1,
|
|
425
|
-
rootMargin: '0px 0px -50px 0px'
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
const observer = new IntersectionObserver(function(entries) {
|
|
429
|
-
entries.forEach(entry => {
|
|
430
|
-
if (entry.isIntersecting) {
|
|
431
|
-
entry.target.style.opacity = '1';
|
|
432
|
-
entry.target.style.transform = 'translateY(0)';
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
}, observerOptions);
|
|
436
|
-
|
|
437
|
-
// Observe all cards for animation
|
|
438
|
-
document.querySelectorAll('.card').forEach(card => {
|
|
439
|
-
card.style.opacity = '0';
|
|
440
|
-
card.style.transform = 'translateY(20px)';
|
|
441
|
-
card.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
|
442
|
-
observer.observe(card);
|
|
443
|
-
});
|
|
444
|
-
|
|
445
422
|
// Add click tracking for analytics (optional)
|
|
446
423
|
document.querySelectorAll('a[href]').forEach(link => {
|
|
447
424
|
link.addEventListener('click', function() {
|
data/_sass/custom.scss
CHANGED
|
@@ -177,23 +177,31 @@ img {
|
|
|
177
177
|
height: auto;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
// ============================================
|
|
181
|
+
// NAVBAR - Fixed positioning with auto-hide
|
|
182
|
+
// ============================================
|
|
183
|
+
// Uses Bootstrap's fixed-top class for positioning (z-index: 1030)
|
|
184
|
+
// JavaScript adds/removes .navbar-hidden class on scroll
|
|
185
|
+
|
|
180
186
|
#navbar {
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
187
|
+
// Transition for smooth hide/show animation
|
|
188
|
+
transition: transform 0.3s ease-in-out !important;
|
|
189
|
+
|
|
190
|
+
// Ensure navbar background is opaque
|
|
191
|
+
background-color: var(--bs-body-bg);
|
|
185
192
|
}
|
|
186
193
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
transition: transform 0.3s;
|
|
194
|
+
// Hidden state - slides up out of view
|
|
195
|
+
// Using higher specificity to override Bootstrap's fixed-top
|
|
196
|
+
#navbar.navbar-hidden {
|
|
197
|
+
transform: translateY(-100%) !important;
|
|
192
198
|
}
|
|
193
199
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
// Respect user's motion preferences
|
|
201
|
+
@media (prefers-reduced-motion: reduce) {
|
|
202
|
+
#navbar {
|
|
203
|
+
transition: none !important;
|
|
204
|
+
}
|
|
197
205
|
}
|
|
198
206
|
|
|
199
207
|
$enable-cssgrid: true;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/assets/js/auto-hide-nav.js
CHANGED
|
@@ -1,18 +1,81 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Auto-hide navbar on scroll
|
|
3
|
+
*
|
|
4
|
+
* Behavior:
|
|
5
|
+
* - Navbar is fixed at top and visible by default
|
|
6
|
+
* - Hides when scrolling DOWN past a threshold (100px)
|
|
7
|
+
* - Reappears when scrolling UP
|
|
8
|
+
* - Respects prefers-reduced-motion accessibility setting
|
|
9
|
+
* - Adds body padding to prevent content jump
|
|
10
|
+
*/
|
|
11
|
+
(function() {
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
// Configuration
|
|
15
|
+
const SCROLL_THRESHOLD = 100; // Pixels before hide/show triggers
|
|
16
|
+
const SCROLL_DELTA = 5; // Minimum scroll distance to trigger change
|
|
17
|
+
|
|
18
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
19
|
+
const navbar = document.getElementById('navbar');
|
|
20
|
+
if (!navbar) return;
|
|
21
|
+
|
|
22
|
+
let lastScrollTop = 0;
|
|
23
|
+
let ticking = false;
|
|
24
|
+
|
|
25
|
+
// Check for reduced motion preference
|
|
26
|
+
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
27
|
+
|
|
28
|
+
// Calculate and set body padding to prevent content jump
|
|
29
|
+
function updateBodyPadding() {
|
|
30
|
+
const navbarHeight = navbar.offsetHeight;
|
|
31
|
+
document.body.style.paddingTop = navbarHeight + 'px';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Initial padding setup
|
|
35
|
+
updateBodyPadding();
|
|
36
|
+
|
|
37
|
+
// Update padding on window resize
|
|
38
|
+
window.addEventListener('resize', updateBodyPadding, { passive: true });
|
|
39
|
+
|
|
40
|
+
// Scroll handler
|
|
41
|
+
function handleScroll() {
|
|
42
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
43
|
+
const scrollDelta = scrollTop - lastScrollTop;
|
|
44
|
+
|
|
45
|
+
// Only trigger if scroll delta exceeds minimum threshold
|
|
46
|
+
if (Math.abs(scrollDelta) < SCROLL_DELTA) {
|
|
47
|
+
ticking = false;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (scrollDelta > 0 && scrollTop > SCROLL_THRESHOLD) {
|
|
52
|
+
// Scrolling DOWN past threshold - hide navbar
|
|
53
|
+
navbar.classList.add('navbar-hidden');
|
|
54
|
+
} else if (scrollDelta < 0) {
|
|
55
|
+
// Scrolling UP - show navbar
|
|
56
|
+
navbar.classList.remove('navbar-hidden');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Always show navbar when at top of page
|
|
60
|
+
if (scrollTop <= 0) {
|
|
61
|
+
navbar.classList.remove('navbar-hidden');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
lastScrollTop = Math.max(0, scrollTop);
|
|
65
|
+
ticking = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Optimized scroll listener using requestAnimationFrame
|
|
69
|
+
window.addEventListener('scroll', function() {
|
|
70
|
+
if (!ticking) {
|
|
71
|
+
window.requestAnimationFrame(handleScroll);
|
|
72
|
+
ticking = true;
|
|
73
|
+
}
|
|
74
|
+
}, { passive: true });
|
|
75
|
+
|
|
76
|
+
// Disable animations if user prefers reduced motion
|
|
77
|
+
if (prefersReducedMotion) {
|
|
78
|
+
navbar.style.transition = 'none';
|
|
15
79
|
}
|
|
16
|
-
lastScrollTop = scrollTop;
|
|
17
80
|
});
|
|
18
|
-
}
|
|
81
|
+
})();
|
|
@@ -234,13 +234,13 @@ class PreviewGenerator:
|
|
|
234
234
|
return safe_name[:50] # Limit length
|
|
235
235
|
|
|
236
236
|
def generate_image_openai(self, prompt: str, output_path: Path) -> GenerationResult:
|
|
237
|
-
"""Generate image using OpenAI DALL-E."""
|
|
238
|
-
if not
|
|
237
|
+
"""Generate image using OpenAI DALL-E via HTTP API (no SDK required)."""
|
|
238
|
+
if not HAS_REQUESTS:
|
|
239
239
|
return GenerationResult(
|
|
240
240
|
success=False,
|
|
241
241
|
image_path=None,
|
|
242
242
|
preview_url=None,
|
|
243
|
-
error="
|
|
243
|
+
error="requests package not installed. Run: pip install requests",
|
|
244
244
|
prompt_used=prompt,
|
|
245
245
|
)
|
|
246
246
|
|
|
@@ -255,8 +255,6 @@ class PreviewGenerator:
|
|
|
255
255
|
)
|
|
256
256
|
|
|
257
257
|
try:
|
|
258
|
-
client = OpenAI(api_key=api_key)
|
|
259
|
-
|
|
260
258
|
self.debug(f"Generating with prompt: {prompt[:200]}...")
|
|
261
259
|
|
|
262
260
|
# Parse size
|
|
@@ -267,27 +265,29 @@ class PreviewGenerator:
|
|
|
267
265
|
}
|
|
268
266
|
size = size_map.get(self.image_size, "1024x1024")
|
|
269
267
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
268
|
+
# Use HTTP API directly instead of SDK
|
|
269
|
+
response = requests.post(
|
|
270
|
+
"https://api.openai.com/v1/images/generations",
|
|
271
|
+
headers={
|
|
272
|
+
"Authorization": f"Bearer {api_key}",
|
|
273
|
+
"Content-Type": "application/json",
|
|
274
|
+
},
|
|
275
|
+
json={
|
|
276
|
+
"model": "dall-e-3",
|
|
277
|
+
"prompt": prompt,
|
|
278
|
+
"size": size,
|
|
279
|
+
"quality": "standard",
|
|
280
|
+
"n": 1,
|
|
281
|
+
},
|
|
282
|
+
timeout=120, # 2 minute timeout for image generation
|
|
276
283
|
)
|
|
284
|
+
response.raise_for_status()
|
|
277
285
|
|
|
278
|
-
|
|
286
|
+
data = response.json()
|
|
287
|
+
image_url = data['data'][0]['url']
|
|
279
288
|
|
|
280
289
|
# Download image
|
|
281
|
-
|
|
282
|
-
return GenerationResult(
|
|
283
|
-
success=False,
|
|
284
|
-
image_path=None,
|
|
285
|
-
preview_url=image_url,
|
|
286
|
-
error="requests package not installed. Run: pip install requests",
|
|
287
|
-
prompt_used=prompt,
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
img_response = requests.get(image_url)
|
|
290
|
+
img_response = requests.get(image_url, timeout=60)
|
|
291
291
|
img_response.raise_for_status()
|
|
292
292
|
|
|
293
293
|
output_path.write_bytes(img_response.content)
|
|
@@ -300,6 +300,21 @@ class PreviewGenerator:
|
|
|
300
300
|
prompt_used=prompt,
|
|
301
301
|
)
|
|
302
302
|
|
|
303
|
+
except requests.exceptions.HTTPError as e:
|
|
304
|
+
error_msg = str(e)
|
|
305
|
+
try:
|
|
306
|
+
error_data = e.response.json()
|
|
307
|
+
if 'error' in error_data:
|
|
308
|
+
error_msg = error_data['error'].get('message', str(e))
|
|
309
|
+
except:
|
|
310
|
+
pass
|
|
311
|
+
return GenerationResult(
|
|
312
|
+
success=False,
|
|
313
|
+
image_path=None,
|
|
314
|
+
preview_url=None,
|
|
315
|
+
error=error_msg,
|
|
316
|
+
prompt_used=prompt,
|
|
317
|
+
)
|
|
303
318
|
except Exception as e:
|
|
304
319
|
return GenerationResult(
|
|
305
320
|
success=False,
|
data/scripts/test-mermaid.sh
CHANGED
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
# --docker Test Docker container
|
|
14
14
|
###############################################################################
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
# Note: Removed -e flag to avoid SIGPIPE issues with pipelines (curl | grep)
|
|
17
|
+
set -uo pipefail
|
|
17
18
|
|
|
18
19
|
# Colors for output
|
|
19
20
|
RED='\033[0;31m'
|
|
@@ -132,24 +133,63 @@ test_url() {
|
|
|
132
133
|
test_mermaid_script() {
|
|
133
134
|
local url="$1"
|
|
134
135
|
local description="$2"
|
|
136
|
+
local response
|
|
137
|
+
local count
|
|
135
138
|
|
|
136
|
-
|
|
139
|
+
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
|
140
|
+
response=$(curl -s "$url" 2>/dev/null) || true
|
|
141
|
+
count=$(echo "$response" | grep -c 'mermaid.min.js' || true)
|
|
142
|
+
if [ "$count" -gt 0 ]; then
|
|
143
|
+
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
144
|
+
log_success "$description"
|
|
145
|
+
return 0
|
|
146
|
+
else
|
|
147
|
+
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
148
|
+
log_error "$description"
|
|
149
|
+
return 1
|
|
150
|
+
fi
|
|
137
151
|
}
|
|
138
152
|
|
|
139
153
|
# Test Mermaid initialization
|
|
140
154
|
test_mermaid_init() {
|
|
141
155
|
local url="$1"
|
|
142
156
|
local description="$2"
|
|
157
|
+
local response
|
|
158
|
+
local count
|
|
143
159
|
|
|
144
|
-
|
|
160
|
+
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
|
161
|
+
response=$(curl -s "$url" 2>/dev/null) || true
|
|
162
|
+
count=$(echo "$response" | grep -c 'mermaid.initialize' || true)
|
|
163
|
+
if [ "$count" -gt 0 ]; then
|
|
164
|
+
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
165
|
+
log_success "$description"
|
|
166
|
+
return 0
|
|
167
|
+
else
|
|
168
|
+
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
169
|
+
log_error "$description"
|
|
170
|
+
return 1
|
|
171
|
+
fi
|
|
145
172
|
}
|
|
146
173
|
|
|
147
174
|
# Test diagram rendering
|
|
148
175
|
test_diagram_rendering() {
|
|
149
176
|
local url="$1"
|
|
150
177
|
local description="$2"
|
|
178
|
+
local response
|
|
179
|
+
local count
|
|
151
180
|
|
|
152
|
-
|
|
181
|
+
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
|
182
|
+
response=$(curl -s "$url" 2>/dev/null) || true
|
|
183
|
+
count=$(echo "$response" | grep -c 'class="mermaid"' || true)
|
|
184
|
+
if [ "$count" -gt 0 ]; then
|
|
185
|
+
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
186
|
+
log_success "$description"
|
|
187
|
+
return 0
|
|
188
|
+
else
|
|
189
|
+
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
190
|
+
log_error "$description"
|
|
191
|
+
return 1
|
|
192
|
+
fi
|
|
153
193
|
}
|
|
154
194
|
|
|
155
195
|
# Main test execution
|
|
@@ -165,9 +205,9 @@ main() {
|
|
|
165
205
|
log_info "Testing core files..."
|
|
166
206
|
|
|
167
207
|
test_file_exists "_includes/components/mermaid.html" "Mermaid include file exists"
|
|
168
|
-
test_file_exists "
|
|
169
|
-
test_file_exists "
|
|
170
|
-
test_file_exists "
|
|
208
|
+
test_file_exists "docs/jekyll/mermaid.md" "Main documentation exists"
|
|
209
|
+
test_file_exists "docs/jekyll/mermaid-test-suite.md" "Test suite exists"
|
|
210
|
+
test_file_exists "docs/jekyll/jekyll-diagram-with-mermaid.md" "Tutorial exists"
|
|
171
211
|
|
|
172
212
|
# Configuration tests
|
|
173
213
|
log_info "Testing configuration..."
|
|
@@ -188,10 +228,10 @@ main() {
|
|
|
188
228
|
# Documentation tests
|
|
189
229
|
log_info "Testing documentation..."
|
|
190
230
|
|
|
191
|
-
test_file_content "
|
|
192
|
-
test_file_content "
|
|
193
|
-
test_file_content "
|
|
194
|
-
test_file_content "
|
|
231
|
+
test_file_content "docs/jekyll/mermaid.md" "mermaid: true" "Main docs have front matter"
|
|
232
|
+
test_file_content "docs/jekyll/mermaid-test-suite.md" "mermaid: true" "Test suite has front matter"
|
|
233
|
+
test_file_content "docs/jekyll/mermaid.md" "graph TD" "Main docs have examples"
|
|
234
|
+
test_file_content "docs/jekyll/mermaid-test-suite.md" "graph TD" "Test suite has examples"
|
|
195
235
|
|
|
196
236
|
# Server tests (if not quick mode)
|
|
197
237
|
if [ "$QUICK" = false ]; then
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-theme-zer0
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.10.
|
|
4
|
+
version: 0.10.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Amr Abdel
|
|
@@ -161,7 +161,24 @@ files:
|
|
|
161
161
|
- assets/images/gravatar-small.png
|
|
162
162
|
- assets/images/gravatar.png
|
|
163
163
|
- assets/images/info-banner-mountain-wizard.png
|
|
164
|
+
- assets/images/previews/10-ai-tools-that-will-transform-your-productivity-.png
|
|
165
|
+
- assets/images/previews/business.png
|
|
166
|
+
- assets/images/previews/css-grid-mastery-build-any-layout-you-can-imagine.png
|
|
167
|
+
- assets/images/previews/development.png
|
|
164
168
|
- assets/images/previews/git-workflow-best-practices-for-modern-teams.png
|
|
169
|
+
- assets/images/previews/github-setup-deployment.png
|
|
170
|
+
- assets/images/previews/jekyll-setup.png
|
|
171
|
+
- assets/images/previews/machine-setup.png
|
|
172
|
+
- assets/images/previews/published-documentation-library.png
|
|
173
|
+
- assets/images/previews/quantum-computing-explained-from-qubits-to-quantum.png
|
|
174
|
+
- assets/images/previews/science.png
|
|
175
|
+
- assets/images/previews/technology.png
|
|
176
|
+
- assets/images/previews/the-complete-guide-to-startup-funding-in-2025.png
|
|
177
|
+
- assets/images/previews/the-remote-work-revolution-how-global-teams-are-re.png
|
|
178
|
+
- assets/images/previews/tutorial.png
|
|
179
|
+
- assets/images/previews/world-news.png
|
|
180
|
+
- assets/images/previews/zer0-mistakes-news-network-building-dynamic-news-s.png
|
|
181
|
+
- assets/images/previews/zer0-mistakes-quick-start-guide.png
|
|
165
182
|
- assets/images/wizard-on-journey.png
|
|
166
183
|
- assets/images/zer0-checkpoint-1.png
|
|
167
184
|
- assets/images/zer0-checkpoint-2.png
|