35
35
# ' The default, `bs4_book_theme()`, resets the base font size to 1rem to
36
36
# ' make reading easier and uses a primary colour with greater constrast
37
37
# ' against the background.
38
- # ' @param repo Link to repository where book is hosted, used to generate
39
- # ' view source and edit buttons. Currently assumes GitHub and that the book
40
- # ' is in the root directory of the repo .
38
+ # ' @param repo Either link to repository where book is hosted, used to generate
39
+ # ' view source and edit buttons or a list with repository `base` link, default
40
+ # ' `branch`, `subdir` and `icon` (see "Specifying the repository") .
41
41
# ' @param lib_dir,pandoc_args,extra_dependencies,... Passed on to
42
42
# ' [rmarkdown::html_document()].
43
+ # '
44
+ # ' @section Specifying the repository:
45
+ # '
46
+ # ' If your book has a default branch called main you can use
47
+ # '
48
+ # ' ```yaml
49
+ # ' bookdown::bs4_book:
50
+ # ' repo:
51
+ # ' base: https://github.com/hadley/ggplot2-book
52
+ # ' branch: main
53
+ # ' ```
54
+ # '
55
+ # ' If your book is furthermore located in a subdirectory called "book" you can use
56
+ # '
57
+ # ' ```yaml
58
+ # ' bookdown::bs4_book:
59
+ # ' repo:
60
+ # ' base: https://github.com/hadley/ggplot2-book
61
+ # ' branch: main
62
+ # ' subdir: book
63
+ # ' ```
64
+ # '
65
+ # ' By default if the repo URL contains "github" it will get a GitHub font-awesome
66
+ # ' icon, and otherwise a GitLab font-awesome icon.
67
+ # ' To use another icon, specify it with the correct prefix (`fas`, `fab`, ...) (Font Awesome 5).
68
+ # '
69
+ # ' ```yaml
70
+ # ' bookdown::bs4_book:
71
+ # ' repo:
72
+ # ' base: https://github.com/hadley/ggplot2-book
73
+ # ' branch: main
74
+ # ' subdir: book
75
+ # ' icon: "fas fa-air-freshener"
76
+ # ' ```
77
+ # '
43
78
# ' @export
44
79
# ' @md
45
- bs4_book <- function (
46
- theme = bs4_book_theme(),
80
+ bs4_book <- function (theme = bs4_book_theme(),
47
81
repo = NULL ,
48
82
... ,
49
83
lib_dir = " libs" ,
50
84
pandoc_args = NULL ,
51
- extra_dependencies = NULL
52
- ) {
53
- check_packages(c(" bslib" , " downlit" , " jsonlite" , " xml2" ))
85
+ extra_dependencies = NULL ) {
86
+ check_packages(bs4_book_deps())
54
87
bs4_check_dots(... )
55
88
56
89
# Allow theme specification in yaml metadata
@@ -102,8 +135,7 @@ bs4_book_theme <- function(primary = "#0068D9", ...) {
102
135
bs4_book_build <- function (output = " bookdown.html" ,
103
136
repo = NULL ,
104
137
lib_dir = " libs" ,
105
- output_dir = opts $ get(" output_dir" )
106
- ) {
138
+ output_dir = opts $ get(" output_dir" )) {
107
139
move_files_html(output , lib_dir )
108
140
109
141
rmd_index <- new.env(parent = emptyenv())
@@ -121,7 +153,7 @@ bs4_book_build <- function(output = "bookdown.html",
121
153
output_dir <- " _book"
122
154
}
123
155
124
- if (isTRUE(opts $ get(' preview' ))) {
156
+ if (isTRUE(opts $ get(" preview" ))) {
125
157
bs4_chapter_tweak(
126
158
output2 ,
127
159
repo = repo ,
@@ -179,8 +211,8 @@ build_toc <- function(output) {
179
211
if (any(is_appendix )) {
180
212
app <- toc [
181
213
seq_along(is_appendix ) > which(is_appendix )[[1 ]] &
182
- toc $ level == 1 &
183
- ! is.na(toc $ num ),
214
+ toc $ level == 1 &
215
+ ! is.na(toc $ num ),
184
216
]
185
217
app $ label <- LETTERS [seq_len(nrow(app ))]
186
218
# TODO: make less of a hack
@@ -202,17 +234,17 @@ build_toc <- function(output) {
202
234
toc
203
235
}
204
236
205
- bs4_book_page = function (head ,
206
- toc ,
207
- chapter ,
208
- link_prev ,
209
- link_next ,
210
- rmd_cur ,
211
- html_cur ,
212
- foot ,
213
- rmd_index = NULL ) {
237
+ bs4_book_page <- function (head ,
238
+ toc ,
239
+ chapter ,
240
+ link_prev ,
241
+ link_next ,
242
+ rmd_cur ,
243
+ html_cur ,
244
+ foot ,
245
+ rmd_index = NULL ) {
214
246
rmd_index [[html_cur ]] <- rmd_cur
215
- paste(c(head , toc , chapter , foot ), collapse = ' \n ' )
247
+ paste(c(head , toc , chapter , foot ), collapse = " \n " )
216
248
}
217
249
218
250
bs4_book_dependency <- function (theme ) {
@@ -239,7 +271,6 @@ bs4_chapters_tweak <- function(output,
239
271
rmd_index = NULL ,
240
272
repo = NULL ,
241
273
output_dir = opts $ get(" output_dir" )) {
242
-
243
274
toc <- build_toc(output )
244
275
files <- toc [! duplicated(toc $ file_name ) & ! is.na(toc $ file_name ), ]
245
276
files $ path <- file.path(output_dir , files $ file_name )
@@ -283,7 +314,6 @@ bs4_chapter_tweak <- function(path, toc, rmd_index = NULL, repo = NULL) {
283
314
chapter = h1 ,
284
315
path = basename(path )
285
316
)
286
-
287
317
}
288
318
289
319
tweak_chapter <- function (html ) {
@@ -390,17 +420,36 @@ tweak_tables <- function(html) {
390
420
}
391
421
392
422
tweak_navbar <- function (html , toc , active = " " , rmd_index = NULL , repo = NULL ) {
423
+ if (! is.null(repo ) && length(repo ) == 1 ) {
424
+ repo <- list (
425
+ base = repo ,
426
+ branch = " master" ,
427
+ subdir = NULL
428
+ )
429
+ }
393
430
394
431
# Source links ------------------------------------------------------------
395
432
if (! is.null(repo ) && active %in% names(rmd_index )) {
396
- repo_edit <- paste0(repo , " /edit/master/" , rmd_index [[active ]])
397
- repo_view <- paste0(repo , " /blob/master/" , rmd_index [[active ]])
433
+ if (! is.null(repo $ subdir )) {
434
+ repo $ subdir <- paste0(repo $ subdir , " /" )
435
+ }
436
+
437
+ repo_edit <- paste0(repo $ base , " /edit/" , repo $ branch , " /" , repo $ subdir , rmd_index [[active ]])
438
+ repo_view <- paste0(repo $ base , " /blob/" , repo $ branch , " /" , repo $ subdir , rmd_index [[active ]])
398
439
} else {
399
440
repo_edit <- NULL
400
441
repo_view <- NULL
401
442
}
402
443
403
- template_link(html , " .//a[@id='book-repo']" , repo )
444
+ if (! is.null(repo $ base )) {
445
+ icon <- repo $ icon %n %
446
+ ifelse(grepl(" github\\ .com" , repo $ base ), " fab fa-github" , " fab fa-gitlab" )
447
+ template_link_icon(html , " .//a[@id='book-repo']" , icon )
448
+ template_link_icon(html , " .//a[@id='book-source']" , icon )
449
+ template_link_icon(html , " .//a[@id='book-edit']" , icon )
450
+ }
451
+
452
+ template_link(html , " .//a[@id='book-repo']" , repo $ base )
404
453
template_link(html , " .//a[@id='book-source']" , repo_view )
405
454
template_link(html , " .//a[@id='book-edit']" , repo_edit )
406
455
@@ -516,10 +565,16 @@ template_link <- function(html, xpath, href) {
516
565
}
517
566
}
518
567
568
+ template_link_icon <- function (html , xpath , icon ) {
569
+ icon_node <- xml2 :: xml_child(xml2 :: xml_find_first(html , xpath ))
570
+ xml2 :: xml_attr(icon_node , " class" ) <- icon
571
+ }
572
+
519
573
# index -------------------------------------------------------------------
520
574
521
575
bs4_index_data <- function (node , chapter , path ) {
522
- children <- xml2 :: xml_find_all(node ,
576
+ children <- xml2 :: xml_find_all(
577
+ node ,
523
578
" ./*[not(self::div and contains(@class, 'section'))]"
524
579
)
525
580
if (length(children ) == 0 || ! is_heading(children [[1 ]])) {
@@ -616,3 +671,10 @@ bs4_check_dots <- function(...) {
616
671
)
617
672
}
618
673
}
674
+
675
+ # these dependencies are required to use bs4_book() but are suggested deps
676
+ # of bookdown. Hence the need to check they are available
677
+ # TODO: remove this and the check in bs4_book when we add them as Imports (if we do it)
678
+ bs4_book_deps <- function () {
679
+ c(" bslib" , " downlit" , " jsonlite" , " xml2" )
680
+ }
0 commit comments