@@ -211,6 +211,24 @@ <h2 class="section-heading" style="justify-content: flex-start;">Technologies &
211211 <!-- ADD THIS LINE TO LOAD THE PYTHON LANGUAGE -->
212212 < script src ="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js "> </ script >
213213
214+ <!-- ===== Mobile TOC Start ===== -->
215+ < button id ="mobile-toc-toggle " class ="mobile-toc-toggle " aria-label ="Table of contents ">
216+ < i class ="fas fa-list-ul "> </ i >
217+ </ button >
218+
219+ < div id ="mobile-toc-overlay " class ="mobile-toc-overlay ">
220+ < div class ="mobile-toc-panel ">
221+ < div class ="mobile-toc-header ">
222+ < span class ="mobile-toc-title "> On This Page</ span >
223+ < button id ="mobile-toc-close " class ="mobile-toc-close " aria-label ="Close ">
224+ < i class ="fas fa-xmark "> </ i >
225+ </ button >
226+ </ div >
227+ < div id ="mobile-toc-container " class ="mobile-toc-container "> </ div >
228+ </ div >
229+ </ div >
230+ <!-- ===== Mobile TOC End ===== -->
231+
214232 <!-- ===== Style Switcher Start ===== -->
215233 < div class ="theme-toggle-container ">
216234 < div id ="theme-toggle-icon " class ="theme-icon ">
@@ -399,6 +417,175 @@ <h2 class="section-heading" style="justify-content: flex-start;">Technologies &
399417 margin-right : 0.4rem ;
400418 color : gray;
401419 }
420+
421+ /* ===== Mobile TOC Floating Button ===== */
422+ .mobile-toc-toggle {
423+ display : none;
424+ /* Hidden by default — shown via JS + media query */
425+ }
426+
427+ /* ===== Mobile TOC Overlay ===== */
428+ .mobile-toc-overlay {
429+ display : none;
430+ position : fixed;
431+ inset : 0 ;
432+ z-index : 999 ;
433+ background : rgba (0 , 0 , 0 , 0.5 );
434+ backdrop-filter : blur (4px );
435+ -webkit-backdrop-filter : blur (4px );
436+ }
437+
438+ .mobile-toc-overlay .open {
439+ display : flex;
440+ align-items : flex-end;
441+ justify-content : center;
442+ animation : tocFadeIn 0.2s ease-out;
443+ }
444+
445+ @keyframes tocFadeIn {
446+ from {
447+ opacity : 0 ;
448+ }
449+
450+ to {
451+ opacity : 1 ;
452+ }
453+ }
454+
455+ @keyframes tocSlideUp {
456+ from {
457+ transform : translateY (100% );
458+ }
459+
460+ to {
461+ transform : translateY (0 );
462+ }
463+ }
464+
465+ .mobile-toc-panel {
466+ background : var (--bg-color );
467+ border-radius : 16px 16px 0 0 ;
468+ width : 100% ;
469+ max-width : 500px ;
470+ max-height : 70vh ;
471+ display : flex;
472+ flex-direction : column;
473+ box-shadow : 0 -4px 24px rgba (0 , 0 , 0 , 0.15 );
474+ animation : tocSlideUp 0.3s ease-out;
475+ }
476+
477+ .mobile-toc-header {
478+ display : flex;
479+ align-items : center;
480+ justify-content : space-between;
481+ padding : 1rem 1.25rem ;
482+ border-bottom : 1px solid var (--border-color );
483+ flex-shrink : 0 ;
484+ }
485+
486+ .mobile-toc-title {
487+ font-weight : 700 ;
488+ font-size : 1.1rem ;
489+ text-transform : uppercase;
490+ letter-spacing : 0.5px ;
491+ }
492+
493+ .mobile-toc-close {
494+ background : none;
495+ border : none;
496+ font-size : 1.2rem ;
497+ color : var (--text-color );
498+ cursor : pointer;
499+ padding : 0.25rem 0.5rem ;
500+ border-radius : 4px ;
501+ transition : background 0.2s ;
502+ }
503+
504+ .mobile-toc-close : hover {
505+ background : var (--card-bg-color );
506+ }
507+
508+ .mobile-toc-container {
509+ overflow-y : auto;
510+ padding : 0.75rem 1.25rem 1.5rem ;
511+ }
512+
513+ .mobile-toc-container .toc-list {
514+ list-style : none;
515+ padding-left : 0 ;
516+ margin : 0 ;
517+ display : flex;
518+ flex-direction : column;
519+ gap : 0.15rem ;
520+ }
521+
522+ .mobile-toc-container .toc-link {
523+ display : block;
524+ color : var (--text-color );
525+ text-decoration : none;
526+ line-height : 1.4 ;
527+ padding : 0.5rem 0.5rem 0.5rem 0.75rem ;
528+ border-left : 2px solid transparent;
529+ border-radius : 0 6px 6px 0 ;
530+ transition : all 0.15s ease;
531+ font-size : 0.95rem ;
532+ }
533+
534+ .mobile-toc-container .toc-link : hover ,
535+ .mobile-toc-container .toc-link : active {
536+ background : var (--card-bg-color );
537+ color : var (--link-color );
538+ border-left-color : var (--link-color );
539+ }
540+
541+ /* ===== Mobile: hide sidebar TOC, show toggle, stack nav ===== */
542+ @media (max-width : 48rem ) {
543+ .post-sidebar-left {
544+ display : none !important ;
545+ }
546+
547+ .mobile-toc-toggle .has-toc {
548+ display : flex;
549+ align-items : center;
550+ justify-content : center;
551+ position : fixed;
552+ bottom : 5.5rem ;
553+ right : 1.25rem ;
554+ z-index : 50 ;
555+ width : 48px ;
556+ height : 48px ;
557+ border-radius : 50% ;
558+ border : 1px solid var (--border-color );
559+ background : var (--card-bg-color );
560+ color : var (--link-color );
561+ font-size : 1.15rem ;
562+ cursor : pointer;
563+ box-shadow : 0 2px 10px rgba (0 , 0 , 0 , 0.12 );
564+ transition : all 0.2s ease;
565+ }
566+
567+ .mobile-toc-toggle .has-toc : hover ,
568+ .mobile-toc-toggle .has-toc : active {
569+ border-color : var (--link-color );
570+ box-shadow : 0 4px 16px rgba (0 , 119 , 204 , 0.2 );
571+ transform : scale (1.05 );
572+ }
573+
574+ /* Stack prev/next navigation vertically */
575+ .post-navigation {
576+ flex-direction : column;
577+ gap : 1rem ;
578+ }
579+
580+ .nav-link {
581+ width : 100% ;
582+ }
583+
584+ .next-link {
585+ text-align : left;
586+ justify-content : flex-start;
587+ }
588+ }
402589 </ style >
403590
404591 < script >
@@ -474,6 +661,58 @@ <h2 class="section-heading" style="justify-content: flex-start;">Technologies &
474661
475662 tocContainer . appendChild ( tocList ) ;
476663
664+ // ===== Mobile TOC: clone into overlay =====
665+ const mobileTocContainer = document . getElementById ( 'mobile-toc-container' ) ;
666+ const mobileTocToggle = document . getElementById ( 'mobile-toc-toggle' ) ;
667+ const mobileTocOverlay = document . getElementById ( 'mobile-toc-overlay' ) ;
668+ const mobileTocClose = document . getElementById ( 'mobile-toc-close' ) ;
669+
670+ if ( mobileTocContainer && mobileTocToggle ) {
671+ // Show the floating toggle button (CSS will only display it on mobile)
672+ mobileTocToggle . classList . add ( 'has-toc' ) ;
673+
674+ // Clone the TOC list into the mobile panel
675+ const mobileList = tocList . cloneNode ( true ) ;
676+ mobileTocContainer . appendChild ( mobileList ) ;
677+
678+ // Handle link clicks in mobile TOC
679+ mobileList . querySelectorAll ( '.toc-link' ) . forEach ( mobileLink => {
680+ mobileLink . addEventListener ( 'click' , ( e ) => {
681+ e . preventDefault ( ) ;
682+ const targetId = mobileLink . getAttribute ( 'href' ) . substring ( 1 ) ;
683+ const targetEl = document . getElementById ( targetId ) ;
684+ if ( targetEl ) {
685+ // Close overlay
686+ mobileTocOverlay . classList . remove ( 'open' ) ;
687+ // Navigate
688+ history . pushState ( null , null , '#' + targetId ) ;
689+ setTimeout ( ( ) => {
690+ targetEl . scrollIntoView ( { behavior : 'smooth' } ) ;
691+ } , 100 ) ;
692+ }
693+ } ) ;
694+ } ) ;
695+
696+ // Toggle button opens overlay
697+ mobileTocToggle . addEventListener ( 'click' , ( ) => {
698+ mobileTocOverlay . classList . toggle ( 'open' ) ;
699+ } ) ;
700+
701+ // Close button
702+ if ( mobileTocClose ) {
703+ mobileTocClose . addEventListener ( 'click' , ( ) => {
704+ mobileTocOverlay . classList . remove ( 'open' ) ;
705+ } ) ;
706+ }
707+
708+ // Click backdrop to close
709+ mobileTocOverlay . addEventListener ( 'click' , ( e ) => {
710+ if ( e . target === mobileTocOverlay ) {
711+ mobileTocOverlay . classList . remove ( 'open' ) ;
712+ }
713+ } ) ;
714+ }
715+
477716 // Scrollspy logic
478717 function updateScrollSpy ( ) {
479718 let currentActive = null ;
0 commit comments