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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +161 -0
  3. data/README.md +495 -720
  4. data/_includes/components/cookie-consent.html +2 -2
  5. data/_includes/components/mermaid.html +98 -9
  6. data/_includes/components/post-card.html +2 -2
  7. data/_includes/content/intro.html +13 -1
  8. data/_includes/content/sitemap.html +4 -9
  9. data/_includes/core/header.html +1 -1
  10. data/_includes/stats/stats-categories.html +5 -5
  11. data/_includes/stats/stats-header.html +7 -7
  12. data/_includes/stats/stats-metrics.html +8 -8
  13. data/_includes/stats/stats-no-data.html +9 -9
  14. data/_includes/stats/stats-overview.html +4 -4
  15. data/_includes/stats/stats-tags.html +6 -6
  16. data/_layouts/blog.html +1 -1
  17. data/_layouts/category.html +16 -6
  18. data/_layouts/collection.html +8 -3
  19. data/_layouts/journals.html +8 -3
  20. data/_layouts/landing.html +1 -1
  21. data/_layouts/sitemap-collection.html +3 -26
  22. data/_sass/custom.scss +20 -12
  23. data/assets/images/previews/10-ai-tools-that-will-transform-your-productivity-.png +0 -0
  24. data/assets/images/previews/business.png +0 -0
  25. data/assets/images/previews/css-grid-mastery-build-any-layout-you-can-imagine.png +0 -0
  26. data/assets/images/previews/development.png +0 -0
  27. data/assets/images/previews/github-setup-deployment.png +0 -0
  28. data/assets/images/previews/jekyll-setup.png +0 -0
  29. data/assets/images/previews/machine-setup.png +0 -0
  30. data/assets/images/previews/published-documentation-library.png +0 -0
  31. data/assets/images/previews/quantum-computing-explained-from-qubits-to-quantum.png +0 -0
  32. data/assets/images/previews/science.png +0 -0
  33. data/assets/images/previews/technology.png +0 -0
  34. data/assets/images/previews/the-complete-guide-to-startup-funding-in-2025.png +0 -0
  35. data/assets/images/previews/the-remote-work-revolution-how-global-teams-are-re.png +0 -0
  36. data/assets/images/previews/tutorial.png +0 -0
  37. data/assets/images/previews/world-news.png +0 -0
  38. data/assets/images/previews/zer0-mistakes-news-network-building-dynamic-news-s.png +0 -0
  39. data/assets/images/previews/zer0-mistakes-quick-start-guide.png +0 -0
  40. data/assets/js/auto-hide-nav.js +79 -16
  41. data/scripts/lib/preview_generator.py +37 -22
  42. data/scripts/test-mermaid.sh +51 -11
  43. metadata +18 -1
@@ -1,5 +1,5 @@
1
1
  ---
2
- layout: default
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: default.html
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
- // position: fixed;
182
- top: 0;
183
- width: 100%;
184
- transition: transform 0.3s;
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
- .fixed-navbar {
188
- position: fixed;
189
- top: 0;
190
- width: 100%;
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
- .hide-navbar {
195
- transform: translateY(-100%);
196
- top: 0px;
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
@@ -1,18 +1,81 @@
1
- // Hides the navbar when scrolling down half a page and shows it when scrolling up
2
- window.onload = function() {
3
- let lastScrollTop = 0;
4
- const navbar = document.getElementById('navbar');
5
-
6
- window.addEventListener('scroll', function() {
7
- let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
8
- let halfPageHeight = window.innerHeight / 2;
9
-
10
- if (scrollTop > lastScrollTop && scrollTop > halfPageHeight) {
11
- navbar.classList.add('hide-navbar');
12
- navbar.classList.add('fixed-navbar');
13
- } else {
14
- navbar.classList.remove('hide-navbar');
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 HAS_OPENAI:
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="openai package not installed. Run: pip install openai",
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
- response = client.images.generate(
271
- model="dall-e-3",
272
- prompt=prompt,
273
- size=size,
274
- quality="standard",
275
- n=1,
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
- image_url = response.data[0].url
286
+ data = response.json()
287
+ image_url = data['data'][0]['url']
279
288
 
280
289
  # Download image
281
- if not HAS_REQUESTS:
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,
@@ -13,7 +13,8 @@
13
13
  # --docker Test Docker container
14
14
  ###############################################################################
15
15
 
16
- set -euo pipefail
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
- run_test "$description" "curl -s '$url' | grep -q 'mermaid.min.js'"
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
- run_test "$description" "curl -s '$url' | grep -q 'mermaid.initialize'"
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
- run_test "$description" "curl -s '$url' | grep -q 'class=\"mermaid\"'"
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 "pages/_docs/jekyll/mermaid.md" "Main documentation exists"
169
- test_file_exists "pages/_docs/jekyll/mermaid-test-suite.md" "Test suite exists"
170
- test_file_exists "pages/_docs/jekyll/jekyll-diagram-with-mermaid.md" "Tutorial 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 "pages/_docs/jekyll/mermaid.md" "mermaid: true" "Main docs have front matter"
192
- test_file_content "pages/_docs/jekyll/mermaid-test-suite.md" "mermaid: true" "Test suite has front matter"
193
- test_file_content "pages/_docs/jekyll/mermaid.md" "graph TD" "Main docs have examples"
194
- test_file_content "pages/_docs/jekyll/mermaid-test-suite.md" "graph TD" "Test suite has examples"
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.0
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