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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +115 -10
- data/README.md +7 -7
- data/_data/authors.yml +2 -2
- data/_data/features.yml +676 -0
- data/_data/navigation/README.md +54 -0
- data/_data/navigation/about.yml +7 -5
- data/_data/navigation/docs.yml +77 -31
- data/_data/navigation/home.yml +4 -3
- data/_data/navigation/main.yml +16 -7
- data/_data/navigation/quickstart.yml +4 -2
- data/_includes/components/cookie-consent.html +81 -9
- data/_includes/components/js-cdn.html +2 -2
- data/_includes/components/mermaid.html +260 -14
- data/_includes/core/head.html +1 -0
- data/_includes/landing/landing-install-cards.html +8 -8
- data/_includes/landing/landing-quick-links.html +4 -4
- data/_includes/navigation/breadcrumbs.html +29 -6
- data/_includes/navigation/nav-tree.html +181 -0
- data/_includes/navigation/navbar.html +262 -9
- data/_includes/navigation/sidebar-left.html +22 -23
- data/_layouts/default.html +1 -1
- data/_layouts/landing.html +21 -21
- data/_layouts/notebook.html +4 -4
- data/_layouts/root.html +2 -2
- data/_sass/core/_nav-tree.scss +145 -0
- data/_sass/core/code-copy.scss +45 -6
- data/_sass/custom.scss +541 -1
- data/assets/js/code-copy.js +79 -13
- data/assets/js/modules/navigation/config.js +149 -0
- data/assets/js/modules/navigation/focus.js +189 -0
- data/assets/js/modules/navigation/gestures.js +179 -0
- data/assets/js/modules/navigation/index.js +227 -0
- data/assets/js/modules/navigation/keyboard.js +237 -0
- data/assets/js/modules/navigation/scroll-spy.js +219 -0
- data/assets/js/modules/navigation/sidebar-state.js +267 -0
- data/assets/js/modules/navigation/smooth-scroll.js +153 -0
- data/assets/js/ui-enhancements.js +194 -0
- data/scripts/migrate-nav-modes.sh +146 -0
- metadata +20 -7
- 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
|
+
}
|
data/assets/js/code-copy.js
CHANGED
|
@@ -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.
|
|
10
|
-
button.
|
|
11
|
-
button.
|
|
12
|
-
button.
|
|
13
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
25
|
-
|
|
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
|
});
|