@@ -399,6 +399,38 @@ def _is_valueless(obj: dc.Object):
399
399
return False
400
400
401
401
402
+ def _insert_contents (
403
+ x : dict | list ,
404
+ contents : list ,
405
+ sentinel : str = "{{ contents }}" ,
406
+ ):
407
+ """Splice `contents` into a list.
408
+
409
+ Splices `contents` into the first element in `x` that exactly matches
410
+ `sentinel`. This functions recurses into dictionaries, but because
411
+ `contents` is a list, we only look within lists in `x` for the sentinel
412
+ value where `contents` should be inserted.
413
+
414
+ Returns
415
+ -------
416
+ :
417
+ Returns `True` if `contents` was inserted into `x`, otherwise returns
418
+ `False`. Note that `x` is modified in place.
419
+ """
420
+ if isinstance (x , dict ):
421
+ for value in x .values ():
422
+ if _insert_contents (value , contents ):
423
+ return True
424
+ elif isinstance (x , list ):
425
+ for i , item in enumerate (x ):
426
+ if item == sentinel :
427
+ x [i : i + 1 ] = contents # noqa: E203
428
+ return True
429
+ elif _insert_contents (item , contents ):
430
+ return True
431
+ return False
432
+
433
+
402
434
# pkgdown =====================================================================
403
435
404
436
@@ -426,7 +458,11 @@ class Builder:
426
458
out_index:
427
459
The output path of the index file, used to list all API functions.
428
460
sidebar:
429
- The output path for a sidebar yaml config (by default no config generated).
461
+ The output path for a sidebar yaml config (by default no config
462
+ generated). Alternatively, can be a dictionary of [Quarto sidebar
463
+ options](https://quarto.org/docs/websites/website-navigation.html#side-navigation)
464
+ with an additional `file` key containing the output path for the sidebar
465
+ YAML config file (by default `_quartodoc-sidebar.yml` if not specified).
430
466
css:
431
467
The output path for the default css styles.
432
468
rewrite_all_pages:
@@ -487,7 +523,7 @@ def __init__(
487
523
title : str = "Function reference" ,
488
524
renderer : "dict | Renderer | str" = "markdown" ,
489
525
out_index : str = None ,
490
- sidebar : "str | None" = None ,
526
+ sidebar : "str | dict[str, Any] | None" = None ,
491
527
css : "str | None" = None ,
492
528
rewrite_all_pages = False ,
493
529
source_dir : "str | None" = None ,
@@ -504,7 +540,13 @@ def __init__(
504
540
self .version = None
505
541
self .dir = dir
506
542
self .title = title
507
- self .sidebar = sidebar
543
+
544
+ if isinstance (sidebar , str ):
545
+ sidebar = {"file" : sidebar }
546
+ elif isinstance (sidebar , dict ) and "file" not in sidebar :
547
+ sidebar ["file" ] = "_quartodoc-sidebar.yml"
548
+ self .sidebar : "dict[str, Any] | None" = sidebar
549
+
508
550
self .css = css
509
551
self .parser = parser
510
552
@@ -588,7 +630,7 @@ def build(self, filter: str = "*"):
588
630
# sidebar ----
589
631
590
632
if self .sidebar :
591
- _log .info (f"Writing sidebar yaml to { self .sidebar } " )
633
+ _log .info (f"Writing sidebar yaml to { self .sidebar [ 'file' ] } " )
592
634
self .write_sidebar (blueprint )
593
635
594
636
# css ----
@@ -659,7 +701,9 @@ def create_inventory(self, items):
659
701
660
702
# sidebar ----
661
703
662
- def _generate_sidebar (self , blueprint : layout .Layout ):
704
+ def _generate_sidebar (
705
+ self , blueprint : layout .Layout , options : "dict | None" = None
706
+ ):
663
707
contents = [f"{ self .dir } /index{ self .out_page_suffix } " ]
664
708
in_subsection = False
665
709
crnt_entry = {}
@@ -686,14 +730,33 @@ def _generate_sidebar(self, blueprint: layout.Layout):
686
730
if crnt_entry :
687
731
contents .append (crnt_entry )
688
732
689
- entries = [{"id" : self .dir , "contents" : contents }, {"id" : "dummy-sidebar" }]
733
+ # Create sidebar with user options, ensuring we control `id` and `contents`
734
+ if self .sidebar is None :
735
+ sidebar = {}
736
+ else :
737
+ sidebar = {k : v for k , v in self .sidebar .items () if k != "file" }
738
+
739
+ if "id" not in sidebar :
740
+ sidebar ["id" ] = self .dir
741
+
742
+ if "contents" not in sidebar :
743
+ sidebar ["contents" ] = contents
744
+ else :
745
+ if not isinstance (sidebar ["contents" ], list ):
746
+ raise TypeError ("`sidebar.contents` must be a list" )
747
+
748
+ if not _insert_contents (sidebar ["contents" ], contents ):
749
+ # otherwise append contents to existing list
750
+ sidebar ["contents" ].extend (contents )
751
+
752
+ entries = [sidebar , {"id" : "dummy-sidebar" }]
690
753
return {"website" : {"sidebar" : entries }}
691
754
692
755
def write_sidebar (self , blueprint : layout .Layout ):
693
756
"""Write a yaml config file for API sidebar."""
694
757
695
758
d_sidebar = self ._generate_sidebar (blueprint )
696
- yaml .dump (d_sidebar , open (self .sidebar , "w" ))
759
+ yaml .dump (d_sidebar , open (self .sidebar [ "file" ] , "w" ))
697
760
698
761
def write_css (self ):
699
762
"""Write default css styles to a file."""
0 commit comments