bslib icon indicating copy to clipboard operation
bslib copied to clipboard

New Bootstrap 4 Layout Ideas

Open zac-garland opened this issue 4 years ago • 2 comments

Super excited for this package to see continual development.

I recently posted about the perfect dashboard design (full height sidebar, full width body for multiple tabpanels) using vanilla shiny.

In bootstrap 4 this is possible.

Below is a reprex for implementing the bootstrap 4 dashboard.

This post is meant to start the conversation for new layout designs that offer more flexibility in UI design.

Min Reprex App

# package load ------------------------------------------------------------
library(shiny)
library(bootstraplib)

# boot dash layout funs ---------------------------------------------------


boot_side_layout <- function(...) {
  div(class = "d-flex wrapper", ...)
}

boot_sidebar <- function(...) {
  div(
    class = "bg-light border-right sidebar-wrapper",
    div(class = "list-group list-group-flush", ...)
  )
}

boot_main <- function(...) {
  div(
    class = "page-content-wrapper",
    div(class = "container-fluid", ...)
  )
}



# title -------------------------------------------------------------------
html_title <-
  '<span class="logo">
    <div style="display:inline-block;">
      <a href="https://www.google.com"><img src="https://jeroen.github.io/images/Rlogo.png" height="35"/></a>
      <b>my company name</b> a subtitle of application or dashboard
    </div>
  </span>'


# css ---------------------------------------------------------------------

css_def <- "
body {
  overflow-x: hidden;
}

.container-fluid, .container-sm, .container-md, .container-lg, .container-xl {
    padding-left: 0px;
}

.sidebar-wrapper {
  min-height: 100vh;
  margin-left: -15rem;
  padding-left: 15px;
  padding-right: 15px;
  -webkit-transition: margin .25s ease-out;
  -moz-transition: margin .25s ease-out;
  -o-transition: margin .25s ease-out;
  transition: margin .25s ease-out;
}


.sidebar-wrapper .list-group {
  width: 15rem;
}

.page-content-wrapper {
  min-width: 100vw;
  padding: 20px;
}

.wrapper.toggled .sidebar-wrapper {
  margin-left: 0;
}

.sidebar-wrapper, .page-content-wrapper {
  padding-top: 20px;
}

.navbar{
  margin-bottom: 0px;
}

@media (max-width: 768px) {
  .sidebar-wrapper {
    padding-right: 0px;
    padding-left: 0px;

  }
}

@media (min-width: 768px) {
  .sidebar-wrapper {
    margin-left: 0;
  }

  .page-content-wrapper {
    min-width: 0;
    width: 100%;
  }

  .wrapper.toggled .sidebar-wrapper {
    margin-left: -15rem;
  }
}

"


# app ---------------------------------------------------------------------
ui <- navbarPage(
  collapsible = TRUE,
  title = HTML(html_title),
  theme = bslib::bs_theme() %>%
    bslib::bs_add_rules(css_def),
  tabPanel(
    "Tab 1",
    boot_side_layout(
      boot_sidebar(
        sliderInput(
          inputId = "bins",
          label = "Number of bins:",
          min = 1,
          max = 50,
          value = 30
        )
      ),
      boot_main(
        fluidRow(column(6, h1("Plot 1")), column(6, h1("Plot 2"))),
        fluidRow(
          column(6, plotOutput(outputId = "distPlot")),
          column(6, plotOutput(outputId = "distPlot2"))
        )
      )
    )
  ),
  tabPanel(
    "Tab 2",
    boot_side_layout(
      boot_sidebar(h1("sidebar input")),
      boot_main(h1("main output"))
    )
  )
)

server <- function(input, output) {
  output$distPlot <- renderPlot({
    x <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    
    hist(x,
         breaks = bins, col = "#75AADB", border = "white",
         xlab = "Waiting time to next eruption (in mins)",
         main = "Histogram of waiting times"
    )
  })
  
  output$distPlot2 <- renderPlot({
    x <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    
    hist(x,
         breaks = bins, col = "#75AADB", border = "white",
         xlab = "Waiting time to next eruption (in mins)",
         main = "Histogram of waiting times"
    )
  })
}

shinyApp(ui, server)

zac-garland avatar Jun 30 '20 17:06 zac-garland

@zac-garland thanks for your idea! It is really nice, now I can specify the complete UI of a page with sidebar & content in a module UI and just use the module UI as a tabPanel in your layout. However, I've noticed that the navigation/tab links in the navigation bar are displayed directly after the title and not after the sidebar ends as in the classical navbarPage layout. If I understand it correctly, the width of the sidebar is 15rem as defined in .sidebar-wrapper .list-group.

I've tried to add margin-left: 15rem to navbar-nav from the original shiny CSS, but this offsets the navigation/tab links 15rem from the end of the title and not from the left viewport border (so now it's too far on the right side). Do you know a solution for this? (I'm sorry if this is trivial, I'm a beginner in CSS.)

jonas-hag avatar Sep 08 '20 20:09 jonas-hag

Does #296 implement this?

ccuts avatar Oct 11 '21 23:10 ccuts

New layout helpers are certainly on our road map, and the development version just added layout_column_wrap(), which can be used to implement a "basic" sidebar layout, here's one such example https://testing-apps.shinyapps.io/card/

That said, I'd like to create a "more official" layout_sidebar() that would make it even easier (and have things like a collapsible sidebar)

cpsievert avatar Oct 27 '22 15:10 cpsievert

I'm going to close this since it's such a open-ended request, but make sure to check out {bslib}'s new layout capabilities in https://rstudio.github.io/bslib/articles/dashboards.html

cpsievert avatar Jun 03 '23 15:06 cpsievert

This issue has been automatically locked. If you have found a related problem, please open a new issue (with a reproducible example or feature request) and link to this issue. :raising_hand: Need help? Connect with us on Discord or Posit Community.

github-actions[bot] avatar Aug 07 '23 05:08 github-actions[bot]