jekyll-theme-zer0 0.16.0 → 0.17.2

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +115 -10
  3. data/README.md +7 -7
  4. data/_data/authors.yml +2 -2
  5. data/_data/features.yml +676 -0
  6. data/_data/navigation/README.md +54 -0
  7. data/_data/navigation/about.yml +7 -5
  8. data/_data/navigation/docs.yml +77 -31
  9. data/_data/navigation/home.yml +4 -3
  10. data/_data/navigation/main.yml +16 -7
  11. data/_data/navigation/quickstart.yml +4 -2
  12. data/_includes/components/cookie-consent.html +81 -9
  13. data/_includes/components/js-cdn.html +2 -2
  14. data/_includes/components/mermaid.html +260 -14
  15. data/_includes/core/head.html +1 -0
  16. data/_includes/landing/landing-install-cards.html +8 -8
  17. data/_includes/landing/landing-quick-links.html +4 -4
  18. data/_includes/navigation/breadcrumbs.html +29 -6
  19. data/_includes/navigation/nav-tree.html +181 -0
  20. data/_includes/navigation/navbar.html +262 -9
  21. data/_includes/navigation/sidebar-left.html +22 -23
  22. data/_layouts/default.html +1 -1
  23. data/_layouts/landing.html +21 -21
  24. data/_layouts/notebook.html +4 -4
  25. data/_layouts/root.html +2 -2
  26. data/_sass/core/_nav-tree.scss +145 -0
  27. data/_sass/core/code-copy.scss +45 -6
  28. data/_sass/custom.scss +541 -1
  29. data/assets/js/code-copy.js +79 -13
  30. data/assets/js/modules/navigation/config.js +149 -0
  31. data/assets/js/modules/navigation/focus.js +189 -0
  32. data/assets/js/modules/navigation/gestures.js +179 -0
  33. data/assets/js/modules/navigation/index.js +227 -0
  34. data/assets/js/modules/navigation/keyboard.js +237 -0
  35. data/assets/js/modules/navigation/scroll-spy.js +219 -0
  36. data/assets/js/modules/navigation/sidebar-state.js +267 -0
  37. data/assets/js/modules/navigation/smooth-scroll.js +153 -0
  38. data/assets/js/ui-enhancements.js +194 -0
  39. data/scripts/migrate-nav-modes.sh +146 -0
  40. metadata +20 -7
  41. data/assets/js/sidebar.js +0 -511
data/_sass/custom.scss CHANGED
@@ -5,6 +5,9 @@
5
5
  // Import notebook-specific styles
6
6
  @import "notebooks";
7
7
 
8
+ // Import navigation tree styles
9
+ @import "core/nav-tree";
10
+
8
11
  html, body {
9
12
  max-width: 100%;
10
13
  // overflow-x: hidden;
@@ -373,4 +376,541 @@ $enable-grid-classes: false;
373
376
  }
374
377
  .folder {
375
378
  cursor: pointer;
376
- }
379
+ }
380
+
381
+ // ==============================================================================
382
+ // UI/UX ENHANCEMENTS - Modern, polished interactions
383
+ // ==============================================================================
384
+
385
+ // Hero Section Enhancements
386
+ .bg-primary {
387
+ position: relative;
388
+ overflow: hidden;
389
+
390
+ &::before {
391
+ content: '';
392
+ position: absolute;
393
+ top: 0;
394
+ left: 0;
395
+ right: 0;
396
+ bottom: 0;
397
+ background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 100%);
398
+ pointer-events: none;
399
+ }
400
+ }
401
+
402
+ // Hero content animations
403
+ .bg-primary .container-xl {
404
+ animation: fadeInUp 0.8s ease-out;
405
+ }
406
+
407
+ @keyframes fadeInUp {
408
+ from {
409
+ opacity: 0;
410
+ transform: translateY(30px);
411
+ }
412
+ to {
413
+ opacity: 1;
414
+ transform: translateY(0);
415
+ }
416
+ }
417
+
418
+ // Enhanced Button Styles
419
+ .btn {
420
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
421
+ position: relative;
422
+ overflow: hidden;
423
+
424
+ &::before {
425
+ content: '';
426
+ position: absolute;
427
+ top: 50%;
428
+ left: 50%;
429
+ width: 0;
430
+ height: 0;
431
+ border-radius: 50%;
432
+ background: rgba(255, 255, 255, 0.2);
433
+ transform: translate(-50%, -50%);
434
+ transition: width 0.6s, height 0.6s;
435
+ }
436
+
437
+ &:hover::before {
438
+ width: 300px;
439
+ height: 300px;
440
+ }
441
+
442
+ &:hover {
443
+ transform: translateY(-2px);
444
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
445
+ }
446
+
447
+ &:active {
448
+ transform: translateY(0);
449
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
450
+ }
451
+
452
+ &.btn-lg {
453
+ padding: 0.75rem 1.5rem;
454
+ font-size: 1.125rem;
455
+ }
456
+ }
457
+
458
+ .btn-outline-light:hover {
459
+ background-color: rgba(255, 255, 255, 0.95);
460
+ color: var(--bs-primary);
461
+ border-color: rgba(255, 255, 255, 0.95);
462
+ }
463
+
464
+ .btn-light:hover {
465
+ background-color: rgba(255, 255, 255, 0.9);
466
+ transform: translateY(-2px);
467
+ }
468
+
469
+ // Enhanced Card Styles
470
+ .card {
471
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
472
+ border: 1px solid rgba(0, 0, 0, 0.08);
473
+
474
+ &:hover {
475
+ transform: translateY(-8px);
476
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
477
+ border-color: rgba(var(--bs-primary-rgb), 0.2);
478
+ }
479
+
480
+ .card-header {
481
+ transition: all 0.3s ease;
482
+ }
483
+
484
+ &:hover .card-header {
485
+ background-color: rgba(255, 255, 255, 0.1);
486
+ }
487
+ }
488
+
489
+ // Feature Cards - Icon Animation
490
+ .card-body {
491
+ .rounded-circle {
492
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
493
+ }
494
+
495
+ i {
496
+ transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
497
+ }
498
+ }
499
+
500
+ .card:hover .rounded-circle {
501
+ transform: scale(1.1) rotate(5deg);
502
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
503
+ }
504
+
505
+ .card:hover .rounded-circle i {
506
+ transform: scale(1.2);
507
+ }
508
+
509
+ // Code Block Enhancements
510
+ pre {
511
+ position: relative;
512
+ transition: all 0.3s ease;
513
+ border: 1px solid rgba(0, 0, 0, 0.1);
514
+
515
+ &:hover {
516
+ border-color: rgba(var(--bs-primary-rgb), 0.3);
517
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
518
+ }
519
+
520
+ code {
521
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
522
+ font-size: 0.875rem;
523
+ line-height: 1.6;
524
+ }
525
+ }
526
+
527
+ // Quick Links Bar Enhancements
528
+ .bg-dark {
529
+ .btn-outline-light {
530
+ transition: all 0.3s ease;
531
+ border-width: 2px;
532
+
533
+ &:hover {
534
+ background-color: rgba(255, 255, 255, 0.95);
535
+ color: var(--bs-dark);
536
+ transform: translateY(-2px);
537
+ box-shadow: 0 4px 8px rgba(255, 255, 255, 0.2);
538
+ }
539
+ }
540
+ }
541
+
542
+ // Smooth Scroll Enhancement
543
+ html {
544
+ scroll-behavior: smooth;
545
+ scroll-padding-top: 80px; // Account for fixed navbar
546
+ }
547
+
548
+ // Section Spacing Improvements
549
+ section,
550
+ .py-5 {
551
+ scroll-margin-top: 80px;
552
+ }
553
+
554
+ // Landing Page Quick Links Animation
555
+ .bg-dark {
556
+ animation: slideDown 0.6s ease-out;
557
+ }
558
+
559
+ @keyframes slideDown {
560
+ from {
561
+ opacity: 0;
562
+ transform: translateY(-20px);
563
+ }
564
+ to {
565
+ opacity: 1;
566
+ transform: translateY(0);
567
+ }
568
+ }
569
+
570
+ // Feature Section Cards Stagger Animation
571
+ .bg-body-tertiary .row.g-4 > * {
572
+ animation: fadeInUp 0.6s ease-out backwards;
573
+
574
+ &:nth-child(1) { animation-delay: 0.1s; }
575
+ &:nth-child(2) { animation-delay: 0.2s; }
576
+ &:nth-child(3) { animation-delay: 0.3s; }
577
+ }
578
+
579
+ // Installation Cards Enhancement
580
+ #get-started .card {
581
+ border-top: 3px solid transparent;
582
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
583
+
584
+ &:hover {
585
+ border-top-color: var(--bs-primary);
586
+ }
587
+
588
+ &.card-header.bg-primary ~ .card-body {
589
+ border-top-color: var(--bs-primary);
590
+ }
591
+
592
+ &.card-header.bg-info ~ .card-body {
593
+ border-top-color: var(--bs-info);
594
+ }
595
+
596
+ &.card-header.bg-secondary ~ .card-body {
597
+ border-top-color: var(--bs-secondary);
598
+ }
599
+ }
600
+
601
+ // Mobile Responsiveness Improvements
602
+ @media (max-width: 768px) {
603
+ .bg-primary .display-4 {
604
+ font-size: 2rem;
605
+ }
606
+
607
+ .bg-primary .lead {
608
+ font-size: 1rem;
609
+ }
610
+
611
+ .btn-lg {
612
+ padding: 0.625rem 1.25rem;
613
+ font-size: 1rem;
614
+ }
615
+
616
+ .card {
617
+ margin-bottom: 1rem;
618
+ }
619
+
620
+ // Reduce hover effects on mobile for better performance
621
+ .card:hover {
622
+ transform: translateY(-4px);
623
+ }
624
+
625
+ .btn:hover {
626
+ transform: none;
627
+ }
628
+ }
629
+
630
+ // Loading State for Images
631
+ img {
632
+ transition: opacity 0.3s ease;
633
+
634
+ &[loading="lazy"] {
635
+ opacity: 0;
636
+
637
+ &.loaded {
638
+ opacity: 1;
639
+ }
640
+ }
641
+ }
642
+
643
+ // Focus States for Accessibility
644
+ .btn:focus-visible,
645
+ .card:focus-visible,
646
+ a:focus-visible {
647
+ outline: 3px solid rgba(var(--bs-primary-rgb), 0.5);
648
+ outline-offset: 2px;
649
+ }
650
+
651
+ // Reduce Motion for Users Who Prefer It
652
+ @media (prefers-reduced-motion: reduce) {
653
+ *,
654
+ *::before,
655
+ *::after {
656
+ animation-duration: 0.01ms !important;
657
+ animation-iteration-count: 1 !important;
658
+ transition-duration: 0.01ms !important;
659
+ scroll-behavior: auto !important;
660
+ }
661
+ }
662
+
663
+ // Table Enhancements
664
+ .table {
665
+ transition: all 0.3s ease;
666
+
667
+ tbody tr {
668
+ transition: background-color 0.2s ease;
669
+
670
+ &:hover {
671
+ background-color: rgba(var(--bs-primary-rgb), 0.05);
672
+ }
673
+ }
674
+ }
675
+
676
+ // Badge Enhancements
677
+ .badge {
678
+ transition: all 0.3s ease;
679
+
680
+ &:hover {
681
+ transform: scale(1.05);
682
+ }
683
+ }
684
+
685
+ // Link Enhancements
686
+ a:not(.btn) {
687
+ transition: color 0.2s ease;
688
+ text-decoration: none;
689
+
690
+ &:hover {
691
+ text-decoration: underline;
692
+ text-underline-offset: 3px;
693
+ }
694
+ }
695
+
696
+ // Container Enhancements
697
+ .container-xl {
698
+ position: relative;
699
+ }
700
+
701
+ // Hero Image Animation
702
+ .bg-primary img {
703
+ animation: fadeInRight 1s ease-out 0.3s backwards;
704
+ filter: drop-shadow(0 10px 30px rgba(0, 0, 0, 0.3));
705
+ transition: transform 0.3s ease;
706
+
707
+ &:hover {
708
+ transform: scale(1.02);
709
+ }
710
+ }
711
+
712
+ @keyframes fadeInRight {
713
+ from {
714
+ opacity: 0;
715
+ transform: translateX(30px);
716
+ }
717
+ to {
718
+ opacity: 1;
719
+ transform: translateX(0);
720
+ }
721
+ }
722
+
723
+ // Improved Shadow Utilities
724
+ .shadow-sm {
725
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08) !important;
726
+ }
727
+
728
+ .shadow {
729
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12) !important;
730
+ }
731
+
732
+ .shadow-lg {
733
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15) !important;
734
+ }
735
+
736
+ // Button Ripple Effect
737
+ .btn {
738
+ position: relative;
739
+ overflow: hidden;
740
+
741
+ .ripple {
742
+ position: absolute;
743
+ border-radius: 50%;
744
+ background: rgba(255, 255, 255, 0.6);
745
+ transform: scale(0);
746
+ animation: ripple-animation 0.6s ease-out;
747
+ pointer-events: none;
748
+ }
749
+ }
750
+
751
+ @keyframes ripple-animation {
752
+ to {
753
+ transform: scale(4);
754
+ opacity: 0;
755
+ }
756
+ }
757
+
758
+ // Mobile Navigation Enhancements
759
+ @media (max-width: 991.98px) {
760
+ .navbar-collapse {
761
+ background-color: var(--bs-body-bg);
762
+ border-radius: 0.5rem;
763
+ margin-top: 1rem;
764
+ padding: 1rem;
765
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
766
+ }
767
+
768
+ .navbar-nav .nav-link {
769
+ padding: 0.75rem 1rem;
770
+ border-radius: 0.375rem;
771
+ transition: all 0.2s ease;
772
+
773
+ &:hover {
774
+ background-color: rgba(var(--bs-primary-rgb), 0.1);
775
+ }
776
+ }
777
+ }
778
+
779
+ // Improved Mobile Hero Section
780
+ @media (max-width: 768px) {
781
+ .bg-primary {
782
+ padding: 2rem 0 !important;
783
+
784
+ .display-4 {
785
+ font-size: 1.75rem;
786
+ line-height: 1.3;
787
+ }
788
+
789
+ .lead {
790
+ font-size: 0.95rem;
791
+ }
792
+
793
+ .btn-lg {
794
+ width: 100%;
795
+ margin-bottom: 0.5rem;
796
+ }
797
+ }
798
+
799
+ // Better card spacing on mobile
800
+ .row.g-4 > * {
801
+ margin-bottom: 1rem;
802
+ }
803
+
804
+ // Improved code block readability on mobile
805
+ pre {
806
+ font-size: 0.8rem;
807
+ padding: 0.75rem;
808
+ overflow-x: auto;
809
+ -webkit-overflow-scrolling: touch;
810
+ }
811
+ }
812
+
813
+ // Touch-friendly tap targets
814
+ @media (hover: none) and (pointer: coarse) {
815
+ .btn,
816
+ .card,
817
+ a {
818
+ min-height: 44px; // iOS HIG recommendation
819
+ min-width: 44px;
820
+ }
821
+
822
+ // Disable hover effects on touch devices
823
+ .card:hover {
824
+ transform: none;
825
+ }
826
+
827
+ .btn:hover {
828
+ transform: none;
829
+ }
830
+ }
831
+
832
+ // Improved focus visibility for keyboard navigation
833
+ *:focus-visible {
834
+ outline: 2px solid var(--bs-primary);
835
+ outline-offset: 2px;
836
+ border-radius: 0.25rem;
837
+ }
838
+
839
+ // Enhanced active link states
840
+ .nav-link.active,
841
+ .btn.active {
842
+ position: relative;
843
+
844
+ &::after {
845
+ content: '';
846
+ position: absolute;
847
+ bottom: 0;
848
+ left: 50%;
849
+ transform: translateX(-50%);
850
+ width: 80%;
851
+ height: 2px;
852
+ background-color: currentColor;
853
+ border-radius: 2px;
854
+ }
855
+ }
856
+
857
+ // Better table responsiveness
858
+ @media (max-width: 768px) {
859
+ .table-responsive {
860
+ border-radius: 0.5rem;
861
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
862
+ }
863
+
864
+ .table {
865
+ font-size: 0.875rem;
866
+
867
+ th, td {
868
+ padding: 0.5rem;
869
+ }
870
+ }
871
+ }
872
+
873
+ // Improved badge styling
874
+ .badge {
875
+ font-weight: 500;
876
+ letter-spacing: 0.025em;
877
+ padding: 0.35em 0.65em;
878
+ }
879
+
880
+ // Enhanced form controls
881
+ .form-control:focus,
882
+ .form-select:focus {
883
+ border-color: var(--bs-primary);
884
+ box-shadow: 0 0 0 0.25rem rgba(var(--bs-primary-rgb), 0.25);
885
+ transform: translateY(-1px);
886
+ transition: all 0.2s ease;
887
+ }
888
+
889
+ // Loading skeleton for better perceived performance
890
+ .skeleton {
891
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
892
+ background-size: 200% 100%;
893
+ animation: loading 1.5s ease-in-out infinite;
894
+ }
895
+
896
+ @keyframes loading {
897
+ 0% { background-position: 200% 0; }
898
+ 100% { background-position: -200% 0; }
899
+ }
900
+
901
+ // Print optimizations
902
+ @media print {
903
+ .btn,
904
+ .card:hover,
905
+ .navbar,
906
+ .footer {
907
+ box-shadow: none !important;
908
+ transform: none !important;
909
+ }
910
+
911
+ a[href^="#"]::after {
912
+ content: " (" attr(href) ")";
913
+ font-size: 0.8em;
914
+ color: #666;
915
+ }
916
+ }
@@ -1,27 +1,93 @@
1
1
  document.addEventListener('DOMContentLoaded', function () {
2
+ // Enhanced code copy functionality with better UX
2
3
  document
3
- .querySelectorAll('pre.highlight')
4
+ .querySelectorAll('pre.highlight, pre code')
4
5
  .forEach(function (pre) {
6
+ // Skip if already has copy button
7
+ if (pre.querySelector('.copy')) return;
8
+
9
+ // Find the actual pre element (might be parent)
10
+ var preElement = pre.tagName === 'PRE' ? pre : pre.closest('pre');
11
+ if (!preElement) return;
12
+
5
13
  var button = document.createElement('button');
6
14
  var copyText = 'Copy';
15
+ var copiedText = 'Copied!';
7
16
  button.className = 'copy';
8
17
  button.type = 'button';
9
- button.ariaLabel = 'Copy code to clipboard';
10
- button.innerText = copyText;
11
- button.tabIndex = 1; // Add this line to make the button focusable with the keyboard
12
- button.addEventListener('click', function () {
13
- var code = pre.querySelector('code').innerText
18
+ button.setAttribute('aria-label', 'Copy code to clipboard');
19
+ button.setAttribute('title', 'Copy code to clipboard');
20
+ button.innerHTML = '<i class="bi bi-clipboard me-1"></i>' + copyText;
21
+ button.tabIndex = 0;
22
+
23
+ // Enhanced click handler with better feedback
24
+ button.addEventListener('click', function (e) {
25
+ e.preventDefault();
26
+ e.stopPropagation();
27
+
28
+ var codeElement = preElement.querySelector('code');
29
+ if (!codeElement) return;
30
+
31
+ var code = codeElement.innerText
14
32
  .split('\n')
15
33
  .filter(line => !line.trim().startsWith('#'))
16
34
  .join('\n')
17
35
  .trim();
18
- navigator.clipboard.writeText(code);
19
- button.innerText = 'Copied';
20
- setTimeout(function () {
21
- button.innerText = copyText;
22
- }, 4000);
36
+
37
+ // Use modern Clipboard API with fallback
38
+ if (navigator.clipboard && navigator.clipboard.writeText) {
39
+ navigator.clipboard.writeText(code).then(function() {
40
+ // Success feedback
41
+ button.innerHTML = '<i class="bi bi-check-circle me-1"></i>' + copiedText;
42
+ button.classList.add('copied');
43
+
44
+ setTimeout(function () {
45
+ button.innerHTML = '<i class="bi bi-clipboard me-1"></i>' + copyText;
46
+ button.classList.remove('copied');
47
+ }, 2000);
48
+ }).catch(function(err) {
49
+ console.error('Failed to copy:', err);
50
+ fallbackCopy(code, button, copyText);
51
+ });
52
+ } else {
53
+ fallbackCopy(code, button, copyText);
54
+ }
23
55
  });
24
- pre.appendChild(button);
25
- pre.classList.add('has-copy-button'); // Add a class to the pre element
56
+
57
+ // Ensure pre has position relative for absolute positioning
58
+ if (getComputedStyle(preElement).position === 'static') {
59
+ preElement.style.position = 'relative';
60
+ }
61
+
62
+ preElement.appendChild(button);
63
+ preElement.classList.add('has-copy-button');
26
64
  });
65
+
66
+ // Fallback copy method for older browsers
67
+ function fallbackCopy(text, button, copyText) {
68
+ var textArea = document.createElement('textarea');
69
+ textArea.value = text;
70
+ textArea.style.position = 'fixed';
71
+ textArea.style.opacity = '0';
72
+ document.body.appendChild(textArea);
73
+ textArea.select();
74
+
75
+ try {
76
+ document.execCommand('copy');
77
+ button.innerHTML = '<i class="bi bi-check-circle me-1"></i>Copied!';
78
+ button.classList.add('copied');
79
+ setTimeout(function () {
80
+ button.innerHTML = '<i class="bi bi-clipboard me-1"></i>' + copyText;
81
+ button.classList.remove('copied');
82
+ }, 2000);
83
+ } catch (err) {
84
+ console.error('Fallback copy failed:', err);
85
+ button.innerHTML = '<i class="bi bi-x-circle me-1"></i>Failed';
86
+ setTimeout(function () {
87
+ button.innerHTML = '<i class="bi bi-clipboard me-1"></i>' + copyText;
88
+ }, 2000);
89
+ }
90
+
91
+ document.body.removeChild(textArea);
92
+ }
27
93
  });