3030# ' \section{WebR}{
3131# ' \ifelse{html}{
3232# ' \out{
33- # ' <a href="webR_URL">\U0001F310 View in webR REPL</a >
33+ # ' <div class="rocleteer-webr-container">...</div >
3434# ' }
3535# ' }{
3636# ' \ifelse{latex}{
5656# ' - **LaTeX/PDF**: Plain URL link to webR session
5757# ' - **Other formats**: Informational message about limited support
5858# '
59+ # ' @section Styling and Theming:
60+ # '
61+ # ' The webR Section HTML output uses Bootstrap-compatible CSS classes and custom
62+ # ' properties to link themeing to pkgdown's existing CSS themes. The styles
63+ # ' follow the CSS custom properties pattern:
64+ # '
65+ # ' - Private variables (`--_*`): Used internally
66+ # ' - Public variables (`--rocleteer-webr-*`): For user customization
67+ # ' - Bootstrap variables (`--bs-*`): Used as fallbacks
68+ # '
69+ # ' Main CSS classes are:
70+ # '
71+ # ' - `.rocleteer-webr-container`: Main container
72+ # ' - `.rocleteer-webr-warning`: Experimental feature warning
73+ # ' - `.rocleteer-webr-btn`, `.rocleteer-webr-btn-primary`, etc.: Button styling
74+ # '
75+ # ' To customize appearance in pkgdown sites, override CSS custom properties by
76+ # ' including into a file:
77+ # '
78+ # ' ```css
79+ # ' .rocleteer-webr-container {
80+ # ' --rocleteer-webr-container-bg: #f0f8ff;
81+ # ' --rocleteer-webr-btn-primary-bg: #1976d2;
82+ # ' }
83+ # ' ```
84+ # '
5985# ' @section Parameters:
6086# '
6187# ' The tag supports optional parameters (these override global `DESCRIPTION` config):
@@ -326,7 +352,7 @@ encode_webr_code <- function(code, filename = "example.R", autorun = FALSE) {
326352 if (! requireNamespace(" base64enc" , quietly = TRUE )) {
327353 stop(" Package 'base64enc' is required for @examplesWebR tag" )
328354 }
329-
355+
330356 # Create the share item structure exactly as webR expects
331357 share_item <- list (
332358 list (
@@ -519,6 +545,132 @@ parse_webr_params <- function(tag_line, global_config = list()) {
519545 return (params )
520546}
521547
548+ # ' Generate Rocleteer webR CSS styles
549+ # '
550+ # ' Create the complete CSS for webR components as an inline style block
551+ # '
552+ # ' @return
553+ # ' HTML string with complete CSS styles
554+ # '
555+ # ' @noRd
556+ webr_inline_css <- function () {
557+ paste0(
558+ ' <style id="rocleteer-webr-styles">' ,
559+ ' /* WebR Interactive Examples CSS - rocleteer package */' ,
560+ ' .rocleteer-webr-container {' ,
561+ ' --_container-bg: var(--rocleteer-webr-container-bg, var(--bs-light, #f8f9fa));' ,
562+ ' --_container-border: var(--rocleteer-webr-container-border, var(--bs-border-color, #dee2e6));' ,
563+ ' --_container-border-radius: var(--rocleteer-webr-container-border-radius, var(--bs-border-radius, 8px));' ,
564+ ' --_warning-bg: var(--rocleteer-webr-warning-bg, var(--bs-info-bg-subtle, #e7f3ff));' ,
565+ ' --_warning-border: var(--rocleteer-webr-warning-border, var(--bs-info-border-subtle, #b3d9ff));' ,
566+ ' --_warning-text: var(--rocleteer-webr-warning-text, var(--bs-info-text-emphasis, #0c5aa6));' ,
567+ ' --_btn-primary-bg: var(--rocleteer-webr-btn-primary-bg, var(--bs-primary, #007bff));' ,
568+ ' --_btn-primary-hover: var(--rocleteer-webr-btn-primary-hover, var(--bs-primary-hover, #0056b3));' ,
569+ ' --_btn-success-bg: var(--rocleteer-webr-btn-success-bg, var(--bs-success, #28a745));' ,
570+ ' --_btn-success-hover: var(--rocleteer-webr-btn-success-hover, var(--bs-success-hover, #1e7e34));' ,
571+ ' --_btn-secondary-bg: var(--rocleteer-webr-btn-secondary-bg, var(--bs-secondary, #6c757d));' ,
572+ ' --_btn-secondary-hover: var(--rocleteer-webr-btn-secondary-hover, var(--bs-secondary-hover, #545b62));' ,
573+ ' --_text-color: var(--rocleteer-webr-text-color, var(--bs-body-color, #333));' ,
574+ ' --_text-emphasis: var(--rocleteer-webr-text-emphasis, var(--bs-emphasis-color, #000));' ,
575+ ' --_container-padding: var(--rocleteer-webr-container-padding, 16px);' ,
576+ ' --_container-margin: var(--rocleteer-webr-container-margin, 16px 0);' ,
577+ ' --_btn-padding: var(--rocleteer-webr-btn-padding, 12px 20px);' ,
578+ ' --_btn-margin: var(--rocleteer-webr-btn-margin, 0 8px 0 0);' ,
579+ ' --_font-size: var(--rocleteer-webr-font-size, var(--bs-body-font-size, 14px));' ,
580+ ' --_font-weight-bold: var(--rocleteer-webr-font-weight-bold, var(--bs-font-weight-bold, 700));' ,
581+ ' border: 1px solid var(--_container-border);' ,
582+ ' border-radius: var(--_container-border-radius);' ,
583+ ' padding: var(--_container-padding);' ,
584+ ' margin: var(--_container-margin);' ,
585+ ' background-color: var(--_container-bg);' ,
586+ ' color: var(--_text-color);' ,
587+ ' font-size: var(--_font-size);' ,
588+ ' }' ,
589+ ' .rocleteer-webr-warning {' ,
590+ ' background-color: var(--_warning-bg);' ,
591+ ' border: 1px solid var(--_warning-border);' ,
592+ ' border-radius: var(--bs-border-radius, 4px);' ,
593+ ' padding: 12px;' ,
594+ ' margin-bottom: 16px;' ,
595+ ' color: var(--_warning-text);' ,
596+ ' font-size: var(--_font-size);' ,
597+ ' }' ,
598+ ' .rocleteer-webr-warning strong {' ,
599+ ' font-weight: var(--_font-weight-bold);' ,
600+ ' }' ,
601+ ' .rocleteer-webr-btn {' ,
602+ ' display: inline-block;' ,
603+ ' padding: var(--_btn-padding);' ,
604+ ' margin: var(--_btn-margin);' ,
605+ ' border: none;' ,
606+ ' border-radius: var(--bs-border-radius, 4px);' ,
607+ ' cursor: pointer;' ,
608+ ' text-decoration: none;' ,
609+ ' font-size: var(--_font-size);' ,
610+ ' color: white;' ,
611+ ' transition: background-color 0.15s ease-in-out;' ,
612+ ' }' ,
613+ ' .rocleteer-webr-btn-primary {' ,
614+ ' background-color: var(--_btn-primary-bg);' ,
615+ ' }' ,
616+ ' .rocleteer-webr-btn-primary:hover {' ,
617+ ' background-color: var(--_btn-primary-hover);' ,
618+ ' color: white;' ,
619+ ' text-decoration: none;' ,
620+ ' }' ,
621+ ' .rocleteer-webr-btn-success {' ,
622+ ' background-color: var(--_btn-success-bg);' ,
623+ ' }' ,
624+ ' .rocleteer-webr-btn-success:hover {' ,
625+ ' background-color: var(--_btn-success-hover);' ,
626+ ' }' ,
627+ ' .rocleteer-webr-btn-secondary {' ,
628+ ' background-color: var(--_btn-secondary-bg);' ,
629+ ' }' ,
630+ ' .rocleteer-webr-btn-secondary:hover {' ,
631+ ' background-color: var(--_btn-secondary-hover);' ,
632+ ' }' ,
633+ ' .rocleteer-webr-initial-text {' ,
634+ ' margin: 8px 0;' ,
635+ ' font-weight: var(--_font-weight-bold);' ,
636+ ' color: var(--_text-emphasis);' ,
637+ ' }' ,
638+ ' .rocleteer-webr-iframe-container {' ,
639+ ' display: none;' ,
640+ ' }' ,
641+ ' .rocleteer-webr-iframe-controls {' ,
642+ ' margin-bottom: 12px;' ,
643+ ' }' ,
644+ ' .rocleteer-webr-iframe-controls .rocleteer-webr-btn {' ,
645+ ' padding: 8px 16px;' ,
646+ ' font-size: var(--_font-size);' ,
647+ ' }' ,
648+ ' .rocleteer-webr-iframe {' ,
649+ ' width: 100\\ %;' ,
650+ ' border: 1px solid var(--_container-border);' ,
651+ ' border-radius: var(--bs-border-radius, 4px);' ,
652+ ' }' ,
653+ ' @media (max-width: 576px) {' ,
654+ ' .rocleteer-webr-container {' ,
655+ ' --_container-padding: 12px;' ,
656+ ' --_btn-padding: 10px 16px;' ,
657+ ' --_font-size: 13px;' ,
658+ ' }' ,
659+ ' .rocleteer-webr-btn {' ,
660+ ' display: block;' ,
661+ ' margin: 4px 0;' ,
662+ ' text-align: center;' ,
663+ ' }' ,
664+ ' .rocleteer-webr-iframe-controls .rocleteer-webr-btn {' ,
665+ ' display: inline-block;' ,
666+ ' margin: 0 4px 0 0;' ,
667+ ' }' ,
668+ ' }' ,
669+ ' </style>' ,
670+ collapse = " \n "
671+ )
672+ }
673+
522674# ' Generate webR warning HTML
523675# '
524676# ' Create standardized warning message for webR examples
@@ -529,7 +681,7 @@ parse_webr_params <- function(tag_line, global_config = list()) {
529681# ' @noRd
530682webr_experimental_warning <- function () {
531683 paste0(
532- ' <div class="webr-warning" style="background-color: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 4px; padding: 12px; margin-bottom: 16px; font-size: 14px; color: #0c5aa6; ">' ,
684+ ' <div class="rocleteer- webr-warning">' ,
533685 ' <strong>\U 0001F9EA Experimental:</strong> Interactive webR examples are a new feature. ' ,
534686 ' Loading may take a moment, and the package version might differ from this documentation.' ,
535687 ' </div>'
@@ -590,15 +742,17 @@ webr_repl_href <- function(encoded_code, version = "latest", mode = "", channel
590742webr_repl_link <- function (encoded_code , version = " latest" , mode = " " , channel = " " ) {
591743 url <- webr_repl_href(encoded_code , version , mode , channel )
592744 html <- paste0(
593- ' <div class="webr-container" style="border: 1px solid #ddd; border-radius: 8px; padding: 16px; margin: 16px 0; background-color: #f8f9fa;">' ,
745+ # Include CSS
746+ # TODO: Figure out how to include it once? Post parser re-write?
747+ webr_inline_css(),
748+
749+ ' <div class="rocleteer-webr-container">' ,
594750
595751 # Warning message
596752 webr_experimental_warning(),
597753
598754 # Link button
599- ' <p><a href="' , url , ' " target="_blank" ' ,
600- ' style="background-color: #007bff; color: white; padding: 12px 20px; ' ,
601- ' text-decoration: none; border-radius: 4px; font-size: 14px; display: inline-block;">' ,
755+ ' <p><a href="' , url , ' " target="_blank" class="rocleteer-webr-btn rocleteer-webr-btn-primary">' ,
602756 ' \U 0001F310 View in webR REPL</a></p>' ,
603757
604758 ' </div>'
@@ -622,43 +776,42 @@ webr_repl_link <- function(encoded_code, version = "latest", mode = "", channel
622776# ' @noRd
623777webr_repl_iframe <- function (encoded_code , version = " latest" , height = 300 , mode = " " , channel = " " ) {
624778 url <- webr_repl_href(encoded_code , version , mode , channel )
625-
779+
626780 # Create an ID for this iframe (based on the encoded code)
627781 hashed_id <- abs(sum(utf8ToInt(substr(encoded_code , 1 , 10 ))))
628782 iframe_id <- paste0(" webr_iframe_" , hashed_id )
629783
630784 html <- paste0(
631- ' <div class="webr-container" style="border: 1px solid #ddd; border-radius: 8px; padding: 16px; margin: 16px 0; background-color: #f8f9fa;">' ,
785+ # Include CSS
786+ webr_inline_css(),
787+
788+ ' <div class="rocleteer-webr-container">' ,
632789
633790 # Warning message
634791 webr_experimental_warning(),
635792
636793 # Initial buttons (before iframe loads)
637- ' <div id="' , iframe_id , ' _initial" class="webr-initial">' ,
638- ' <p style="margin: 8px 0; font-weight: bold; color: #333; ">Interactive Example Available</p>' ,
794+ ' <div id="' , iframe_id , ' _initial" class="rocleteer- webr-initial">' ,
795+ ' <p class="rocleteer-webr-initial-text ">Interactive Example Available</p>' ,
639796 ' <button onclick="loadWebRIframe(\' ' , iframe_id , ' \' , \' ' , url , ' \' , ' , height , ' )" ' ,
640- ' style="background-color: #28a745; color: white; padding: 12px 20px; border: none; border-radius: 4px; ' ,
641- ' cursor: pointer; font-size: 14px; margin-right: 8px;">' ,
797+ ' class="rocleteer-webr-btn rocleteer-webr-btn-success rocleteer-webr-btn-try">' ,
642798 ' \U 0001F680 Try it in your browser</button>' ,
643799 ' <button onclick="window.open(\' ' , url , ' \' , \' _blank\' )" ' ,
644- ' style="background-color: #007bff; color: white; padding: 12px 20px; border: none; border-radius: 4px; ' ,
645- ' cursor: pointer; font-size: 14px;">' ,
800+ ' class="rocleteer-webr-btn rocleteer-webr-btn-primary rocleteer-webr-btn-open">' ,
646801 ' \U 0001F310 Open in Tab</button>' ,
647802 ' </div>' ,
648803
649804 # Iframe container (hidden initially)
650- ' <div id="' , iframe_id , ' _container" class="webr-iframe-container" style="display: none; ">' ,
651- ' <div style="margin-bottom: 12px; ">' ,
805+ ' <div id="' , iframe_id , ' _container" class="rocleteer- webr-iframe-container">' ,
806+ ' <div class="rocleteer-webr-iframe-controls ">' ,
652807 ' <button onclick="hideWebRIframe(\' ' , iframe_id , ' \' )" ' ,
653- ' style="background-color: #6c757d; color: white; padding: 8px 16px; border: none; border-radius: 4px; ' ,
654- ' cursor: pointer; font-size: 14px; margin-right: 8px;">' ,
808+ ' class="rocleteer-webr-btn rocleteer-webr-btn-secondary rocleteer-webr-btn-back">' ,
655809 ' \U 0001F519 Go back</button>' ,
656810 ' <button onclick="window.open(\' ' , url , ' \' , \' _blank\' )" ' ,
657- ' style="background-color: #007bff; color: white; padding: 8px 16px; border: none; border-radius: 4px; ' ,
658- ' cursor: pointer; font-size: 14px;">' ,
811+ ' class="rocleteer-webr-btn rocleteer-webr-btn-primary rocleteer-webr-btn-open">' ,
659812 ' \U 0001F310 Open in Tab</button>' ,
660813 ' </div>' ,
661- ' <div id="' , iframe_id , ' _content"></div>' ,
814+ ' <div id="' , iframe_id , ' _content" class="rocleteer-webr-iframe-content" ></div>' ,
662815 ' </div>' ,
663816
664817 ' </div>' ,
@@ -669,8 +822,8 @@ webr_repl_iframe <- function(encoded_code, version = "latest", height = 300, mod
669822 ' document.getElementById(id + "_initial").style.display = "none";' ,
670823 ' document.getElementById(id + "_container").style.display = "block";' ,
671824 ' document.getElementById(id + "_content").innerHTML = ' ,
672- ' \' <iframe src="\' + url + \' " width="100 \\ % " height="\' + height + \' px" \' +' ,
673- ' \' style="border: 1px solid #ddd; border-radius: 4px;" title="webR REPL"></iframe>\' ;' ,
825+ ' \' <iframe src="\' + url + \' " class="rocleteer-webr-iframe " height="\' + height + \' px" \' +' ,
826+ ' \' title="webR REPL"></iframe>\' ;' ,
674827 ' }' ,
675828 ' function hideWebRIframe(id) {' ,
676829 ' document.getElementById(id + "_initial").style.display = "block";' ,
0 commit comments