6060 }
6161
6262 .doc-page {
63- width : min (1220 px , 100% );
63+ width : min (900 px , 100% );
6464 display : flex;
6565 flex-direction : column;
6666 gap : clamp (20px , 3vw , 32px );
125125 }
126126
127127 main .doc-main {
128- display : grid ;
129- grid-template-columns : minmax ( 220 px , 320 px ) minmax ( 0 , 1 fr ) ;
128+ display : flex ;
129+ flex-direction : column ;
130130 gap : clamp (20px , 3vw , 36px );
131131 }
132132
133- nav .doc-nav {
133+ section .doc-content {
134134 background : var (--panel-surface );
135- border-radius : 22 px ;
135+ border-radius : 24 px ;
136136 border : 1px solid var (--border-color );
137- padding : clamp (18px , 2vw , 24px );
137+ padding : clamp (20px , 3vw , 32px );
138+ box-shadow : 0 26px 60px var (--shadow-color );
138139 display : flex;
139140 flex-direction : column;
140- gap : 18px ;
141- position : relative;
142- }
143-
144- nav .doc-nav ::after {
145- content : "" ;
146- position : absolute;
147- inset : 12px 16px 12px auto;
148- width : 4px ;
149- border-radius : 999px ;
150- background : linear-gradient (180deg , transparent, var (--accent ), transparent);
151- opacity : 0.28 ;
152- }
153-
154- nav .doc-nav h2 {
155- margin : 0 ;
156- font-size : 0.95rem ;
157- text-transform : uppercase;
158- letter-spacing : 0.12em ;
159- color : var (--text-muted );
141+ gap : 20px ;
142+ min-height : 420px ;
160143 }
161144
162- nav .doc-nav ul {
163- list-style : none;
164- margin : 0 ;
165- padding : 0 ;
145+ .doc-controls {
166146 display : flex;
167- flex-direction : column;
168- gap : 8px ;
169- }
170-
171- nav .doc-nav a {
172- display : grid;
173- grid-template-columns : 1fr auto;
174147 align-items : center;
148+ justify-content : space-between;
175149 gap : 12px ;
176- padding : 12px 16px ;
177- border-radius : 14px ;
178- text-decoration : none;
179- color : inherit;
180- background : transparent;
181- font-weight : 600 ;
182- transition : background 0.18s ease, transform 0.18s ease, color 0.18s ease;
183- position : relative;
184- overflow : hidden;
150+ flex-wrap : wrap;
185151 }
186152
187- nav .doc-nav a ::before {
188- content : "" ;
189- position : absolute;
190- inset : 0 ;
191- background : var (--accent-soft );
192- opacity : 0 ;
193- transition : opacity 0.18s ease;
194- pointer-events : none;
153+ .doc-progress {
154+ color : var (--text-muted );
155+ font-size : 0.9rem ;
156+ flex : 1 1 180px ;
157+ text-align : center;
195158 }
196159
197- nav .doc-nav a span .badge {
198- justify-self : end;
199- padding : 4px 10px ;
160+ .doc-nav-button {
161+ display : inline-flex;
162+ align-items : center;
163+ justify-content : center;
164+ gap : 8px ;
165+ padding : 10px 16px ;
200166 border-radius : 999px ;
167+ border : 1px solid var (--border-color );
201168 background : rgba (79 , 70 , 229 , 0.12 );
202169 color : var (--accent );
203- font-size : 0.75rem ;
204170 font-weight : 600 ;
205- letter-spacing : 0.04em ;
206- }
207-
208- nav .doc-nav a : hover {
209- transform : translateX (4px );
210- color : var (--accent );
171+ letter-spacing : 0.01em ;
172+ cursor : pointer;
173+ transition : transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
211174 }
212175
213- nav .doc-nav a : hover ::before {
214- opacity : 1 ;
176+ .doc-nav-button : hover {
177+ transform : translateY (-1px );
178+ box-shadow : 0 12px 24px rgba (79 , 70 , 229 , 0.18 );
179+ background : rgba (79 , 70 , 229 , 0.18 );
215180 }
216181
217- nav .doc-nav a : focus-visible {
182+ .doc-nav-button : focus-visible {
218183 outline : none;
219- color : var (--accent );
220- box-shadow : 0 0 0 3px rgba (79 , 70 , 229 , 0.35 );
221- }
222-
223- nav .doc-nav a .is-active {
224- color : var (--accent );
225- }
226-
227- nav .doc-nav a .is-active ::before {
228- opacity : 1 ;
184+ box-shadow : 0 0 0 3px rgba (129 , 140 , 248 , 0.45 );
229185 }
230186
231- section .doc-content {
232- background : var (--panel-surface );
233- border-radius : 24px ;
234- border : 1px solid var (--border-color );
235- padding : clamp (20px , 3vw , 32px );
236- box-shadow : 0 26px 60px var (--shadow-color );
237- display : flex;
238- flex-direction : column;
239- gap : 20px ;
240- min-height : 420px ;
187+ .doc-nav-button : disabled {
188+ opacity : 0.55 ;
189+ cursor : not-allowed;
190+ transform : none;
191+ box-shadow : none;
192+ background : rgba (148 , 163 , 209 , 0.18 );
193+ color : var (--text-muted );
241194 }
242195
243196 header .content-meta {
350303 border : none;
351304 }
352305
353- main .doc-main {
354- grid-template-columns : 1fr ;
355- }
356-
357- nav .doc-nav {
358- order : 2 ;
359- }
360-
361- section .doc-content {
362- order : 1 ;
306+ .doc-progress {
307+ order : 3 ;
308+ flex-basis : 100% ;
363309 }
364310 }
365311
377323 align-self : stretch;
378324 justify-content : center;
379325 }
380-
381- nav .doc-nav {
382- padding : 16px ;
383- }
384326 }
385327 </ style >
386328</ head >
@@ -394,32 +336,35 @@ <h1>Toolbox knowledge base</h1>
394336 < a class ="home-link " href ="/ " aria-label ="Return to the toolbox home "> ⌂ Home</ a >
395337 </ header >
396338 < main class ="doc-main ">
397- < nav class ="doc-nav " aria-label ="Documentation navigation ">
398- < h2 > Guides</ h2 >
399- < ul data-doc-nav > </ ul >
400- </ nav >
401339 < section class ="doc-content " aria-live ="polite ">
340+ < div class ="doc-controls ">
341+ < button type ="button " class ="doc-nav-button " data-doc-prev aria-label ="View previous guide "> ← Previous</ button >
342+ < p class ="doc-progress " data-doc-progress aria-live ="polite "> </ p >
343+ < button type ="button " class ="doc-nav-button " data-doc-next aria-label ="View next guide "> Next →</ button >
344+ </ div >
402345 < header class ="content-meta ">
403346 < h2 data-doc-title > Loading…</ h2 >
404347 < p data-doc-updated hidden > </ p >
405348 </ header >
406349 < p class ="doc-status " data-doc-status > </ p >
407350 < article class ="markdown-body " data-doc-content >
408- < p > Select a guide from the navigation to load documentation.</ p >
351+ < p > Use the buttons above to browse the documentation guides .</ p >
409352 </ article >
410353 </ section >
411354 </ main >
412355 </ div >
413356 < script src ="https://cdn.jsdelivr.net/npm/marked/marked.min.js "> </ script >
414357 < script >
415358 ( function ( ) {
416- const docListEl = document . querySelector ( '[data-doc-nav]' ) ;
359+ const prevButton = document . querySelector ( '[data-doc-prev]' ) ;
360+ const nextButton = document . querySelector ( '[data-doc-next]' ) ;
361+ const progressEl = document . querySelector ( '[data-doc-progress]' ) ;
417362 const contentEl = document . querySelector ( '[data-doc-content]' ) ;
418363 const titleEl = document . querySelector ( '[data-doc-title]' ) ;
419364 const updatedEl = document . querySelector ( '[data-doc-updated]' ) ;
420365 const statusEl = document . querySelector ( '[data-doc-status]' ) ;
421366
422- if ( ! docListEl || ! contentEl || ! titleEl || ! updatedEl || ! statusEl ) {
367+ if ( ! prevButton || ! nextButton || ! progressEl || ! contentEl || ! titleEl || ! updatedEl || ! statusEl ) {
423368 return ;
424369 }
425370
@@ -435,44 +380,46 @@ <h2 data-doc-title>Loading…</h2>
435380 ] ;
436381
437382 const guideMap = new Map ( guides . map ( ( guide ) => [ guide . id , guide ] ) ) ;
383+ let activeGuideId = '' ;
384+
385+ function updatePager ( id ) {
386+ const index = guides . findIndex ( ( guide ) => guide . id === id ) ;
387+ const total = guides . length ;
388+ if ( index === - 1 ) {
389+ prevButton . disabled = true ;
390+ nextButton . disabled = true ;
391+ prevButton . textContent = '← Previous' ;
392+ nextButton . textContent = 'Next →' ;
393+ prevButton . setAttribute ( 'aria-label' , 'Previous guide unavailable' ) ;
394+ nextButton . setAttribute ( 'aria-label' , 'Next guide unavailable' ) ;
395+ progressEl . textContent = total > 0 ? `0 of ${ total } ` : '' ;
396+ return ;
397+ }
438398
439- function renderNav ( ) {
440- docListEl . innerHTML = '' ;
441- guides . forEach ( ( guide ) => {
442- const item = document . createElement ( 'li' ) ;
443- const link = document . createElement ( 'a' ) ;
444- link . href = `#${ guide . id } ` ;
445- link . dataset . docId = guide . id ;
446- link . textContent = guide . title ;
447-
448- if ( guide . summary ) {
449- const badge = document . createElement ( 'span' ) ;
450- badge . className = 'badge' ;
451- badge . textContent = guide . summary ;
452- link . appendChild ( badge ) ;
453- }
399+ const prevGuide = guides [ index - 1 ] ;
400+ const nextGuide = guides [ index + 1 ] ;
454401
455- link . addEventListener ( 'click' , ( event ) => {
456- event . preventDefault ( ) ;
457- loadGuide ( guide . id , { pushState : true } ) ;
458- } ) ;
402+ if ( prevGuide ) {
403+ prevButton . disabled = false ;
404+ prevButton . textContent = `← ${ prevGuide . title } ` ;
405+ prevButton . setAttribute ( 'aria-label' , `View previous guide: ${ prevGuide . title } ` ) ;
406+ } else {
407+ prevButton . disabled = true ;
408+ prevButton . textContent = '← Previous' ;
409+ prevButton . setAttribute ( 'aria-label' , 'No previous guide' ) ;
410+ }
459411
460- item . appendChild ( link ) ;
461- docListEl . appendChild ( item ) ;
462- } ) ;
463- }
412+ if ( nextGuide ) {
413+ nextButton . disabled = false ;
414+ nextButton . textContent = `${ nextGuide . title } →` ;
415+ nextButton . setAttribute ( 'aria-label' , `View next guide: ${ nextGuide . title } ` ) ;
416+ } else {
417+ nextButton . disabled = true ;
418+ nextButton . textContent = 'Next →' ;
419+ nextButton . setAttribute ( 'aria-label' , 'No next guide' ) ;
420+ }
464421
465- function setActive ( id ) {
466- const links = docListEl . querySelectorAll ( 'a[data-doc-id]' ) ;
467- links . forEach ( ( link ) => {
468- const isActive = link . dataset . docId === id ;
469- link . classList . toggle ( 'is-active' , isActive ) ;
470- if ( isActive ) {
471- link . setAttribute ( 'aria-current' , 'page' ) ;
472- } else {
473- link . removeAttribute ( 'aria-current' ) ;
474- }
475- } ) ;
422+ progressEl . textContent = `Guide ${ index + 1 } of ${ total } ` ;
476423 }
477424
478425 function formatUpdated ( text ) {
@@ -496,6 +443,9 @@ <h2 data-doc-title>Loading…</h2>
496443 return ;
497444 }
498445
446+ activeGuideId = guide . id ;
447+ updatePager ( activeGuideId ) ;
448+
499449 if ( options . pushState ) {
500450 window . history . pushState ( { docId : guide . id } , '' , `#${ guide . id } ` ) ;
501451 } else if ( window . location . hash . replace ( '#' , '' ) !== guide . id ) {
@@ -519,9 +469,10 @@ <h2 data-doc-title>Loading…</h2>
519469
520470 contentEl . innerHTML = parsed ;
521471 titleEl . textContent = guide . title ;
522- setActive ( guide . id ) ;
523472 statusEl . textContent = '' ;
524473
474+ updatePager ( guide . id ) ;
475+
525476 const lastModified = response . headers . get ( 'last-modified' ) ;
526477 const fallback = formatUpdated ( lastModified ) ;
527478 if ( fallback ) {
@@ -537,7 +488,7 @@ <h2 data-doc-title>Loading…</h2>
537488 contentEl . innerHTML = '<p>Failed to load the requested guide. Please try again.</p>' ;
538489 titleEl . textContent = guide . title ;
539490 statusEl . textContent = 'An error occurred while loading the guide.' ;
540- setActive ( guide . id ) ;
491+ updatePager ( guide . id ) ;
541492 }
542493 }
543494
@@ -565,10 +516,25 @@ <h2 data-doc-title>Loading…</h2>
565516 }
566517 } ) ;
567518
568- renderNav ( ) ;
519+ prevButton . addEventListener ( 'click' , ( ) => {
520+ const index = guides . findIndex ( ( guide ) => guide . id === activeGuideId ) ;
521+ if ( index > 0 ) {
522+ loadGuide ( guides [ index - 1 ] . id , { pushState : true } ) ;
523+ }
524+ } ) ;
525+
526+ nextButton . addEventListener ( 'click' , ( ) => {
527+ const index = guides . findIndex ( ( guide ) => guide . id === activeGuideId ) ;
528+ if ( index !== - 1 && index < guides . length - 1 ) {
529+ loadGuide ( guides [ index + 1 ] . id , { pushState : true } ) ;
530+ }
531+ } ) ;
532+
569533 const initialId = getInitialGuideId ( ) ;
570534 if ( initialId ) {
571535 loadGuide ( initialId , { pushState : false } ) ;
536+ } else if ( guides [ 0 ] ) {
537+ loadGuide ( guides [ 0 ] . id , { pushState : false } ) ;
572538 }
573539 } ) ( ) ;
574540 </ script >
0 commit comments