Path: blob/main/src/resources/formats/dashboard/quarto-dashboard.scss
12926 views
/*-- scss:defaults --*/
$dashboard-card-toolbar-top-margin: 6px !default;
/*-- scss:mixins --*/
@mixin shiny-date-range {
.input-daterange {
width: inherit;
input[type="text"] {
height: 2.4em;
width: 10em;
}
.input-group-addon {
height: auto;
padding: 0;
margin-left: -5px !important;
margin-right: -5px;
.input-group-text {
padding-top: 0;
padding-bottom: 0;
height: 100%;
}
}
}
}
@mixin shiny-text-input {
input[type="text"] {
line-height: 1;
width: inherit;
}
}
@mixin shiny-input-checkboxgroup {
.shiny-input-checkboxgroup {
> label {
margin-top: $dashboard-card-toolbar-top-margin;
}
> .shiny-options-group {
margin-top: 0;
align-items: baseline;
}
}
}
@mixin shiny-input-radiogroup {
.shiny-input-radiogroup {
> label {
margin-top: $dashboard-card-toolbar-top-margin;
}
}
.shiny-input-radiogroup > .shiny-options-group {
align-items: baseline;
margin-top: 0;
> .radio {
margin-right: 0.3em;
}
}
}
@mixin shiny-input-checkbox {
div.checkbox {
margin-bottom: 0px;
}
> .checkbox:first-child {
margin-top: $dashboard-card-toolbar-top-margin;
}
}
@mixin shiny-input-slider {
span.irs.irs--shiny {
width: 10em;
.irs-line {
top: 9px;
}
.irs-min,
.irs-max,
.irs-from,
.irs-to,
.irs-single {
top: 20px;
}
.irs-bar {
top: 8px;
}
.irs-handle {
top: 0px;
}
}
}
@mixin shiny-input-select {
.form-select {
padding-top: 0.2em;
padding-bottom: 0.2em;
}
.shiny-input-select {
min-width: 6em;
}
}
@mixin shiny-input-container {
.shiny-input-container {
padding-bottom: 0;
margin-bottom: 0;
> * {
flex-shrink: 0;
flex-grow: 0;
}
}
.form-group.shiny-input-container:not([role="group"]) > label {
margin-bottom: 0;
}
.shiny-input-container.no-baseline {
align-items: start;
padding-top: $dashboard-card-toolbar-top-margin;
}
.shiny-input-container {
display: flex;
align-items: baseline;
label {
padding-right: 0.4em;
}
.bslib-input-switch {
margin-top: $dashboard-card-toolbar-top-margin;
}
}
}
@mixin shiny-toolbar-customizations {
@include toolbar-layout();
@include shiny-input-container();
@include shiny-text-input();
@include shiny-date-range();
@include shiny-input-slider();
@include shiny-input-checkboxgroup();
@include shiny-input-radiogroup();
@include shiny-input-select();
@include shiny-input-checkbox();
}
@mixin toolbar-layout {
.cell-output-display {
display: flex;
}
.shiny-input-container {
padding-bottom: 0.5em;
margin-bottom: 0.5em;
width: inherit;
> .checkbox:first-child {
margin-top: $dashboard-card-toolbar-top-margin;
}
}
> *:last-child {
margin-right: 0;
}
> * > * {
margin-right: 1em;
align-items: baseline;
> a {
text-decoration: none;
margin-top: auto;
margin-bottom: auto;
}
}
}
@mixin itables {
.itables {
@include media-breakpoint-down(md) {
div.dataTables_wrapper div.dataTables_length,
div.dataTables_wrapper div.dataTables_info,
div.dataTables_wrapper div.dataTables_paginate {
text-align: initial;
}
div.dataTables_wrapper div.dataTables_filter {
text-align: right;
}
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
justify-content: initial;
}
}
.dataTables_wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding-top: 0;
table {
flex-shrink: 0;
}
// The buttons control (download/copy)
.dt-buttons {
margin-bottom: 0.5em;
margin-left: auto;
width: fit-content;
float: right;
&.btn-group {
background: $body-bg;
border: none;
}
.btn-secondary {
background-color: $body-bg;
background-image: none;
border: solid $border-color $border-width;
padding: 0.2em 0.7em;
}
.btn span {
font-size: 0.8em;
color: $body-color;
}
}
// The number of items (info) text
.dataTables_info {
margin-left: 0.5em;
margin-bottom: 0.5em;
@include media-breakpoint-up(md) {
font-size: 0.875em;
}
@include media-breakpoint-down(md) {
font-size: 0.8em;
}
padding-top: 0;
}
// The table filter / search
.dataTables_filter {
margin-bottom: 0.5em;
font-size: 0.875em;
input[type="search"] {
padding: 1px 5px 1px 5px;
font-size: 0.875em;
}
}
// The pagination size selector
.dataTables_length {
flex-basis: 1 1 50%;
margin-bottom: 0.5em;
font-size: 0.875em;
select {
padding: 0.4em 3em 0.4em 0.5em;
font-size: 0.875em;
margin-left: 0.2em;
margin-right: 0.2em;
}
}
// The pagination control
.dataTables_paginate {
@include media-breakpoint-up(md) {
margin-left: auto;
}
flex-shrink: 0;
ul.pagination .paginate_button .page-link {
font-size: 0.8em;
}
}
}
}
}
@mixin observable-toolbar-inputs {
form {
width: fit-content;
label {
padding-top: 0.2em;
padding-bottom: 0.2em;
width: fit-content;
}
input[type="date"] {
width: fit-content;
}
input[type="color"] {
width: 3em;
}
button {
padding: 0.4em;
}
select {
width: fit-content;
}
}
}
@mixin observable-sidebar-inputs {
form {
flex-direction: column;
align-items: start;
margin-bottom: 1em;
div[class*="oi-"][class$="-input"] {
flex-direction: column;
}
&[class*="oi-"][class$="-toggle"] {
flex-direction: row-reverse;
align-items: center;
justify-content: start;
}
input[type="range"] {
margin-top: 0.5em;
margin-right: 0.8em;
margin-left: 1em;
}
}
label {
width: fit-content;
}
}
/*-- scss:rules --*/
// Value Boxes
$valuebox-bg-primary: theme-override-value(
$theme-name,
"valuebox-bg-primary",
$primary
) !default;
$valuebox-bg-secondary: theme-override-value(
$theme-name,
"valuebox-bg-secondary",
$secondary
) !default;
$valuebox-bg-success: theme-override-value(
$theme-name,
"valuebox-bg-success",
$success
) !default;
$valuebox-bg-info: theme-override-value(
$theme-name,
"valuebox-bg-info",
$info
) !default;
$valuebox-bg-warning: theme-override-value(
$theme-name,
"valuebox-bg-warning",
$warning
) !default;
$valuebox-bg-danger: theme-override-value(
$theme-name,
"valuebox-bg-danger",
$danger
) !default;
$valuebox-bg-light: theme-override-value(
$theme-name,
"valuebox-bg-light",
$light
) !default;
$valuebox-bg-dark: theme-override-value(
$theme-name,
"valuebox-bg-dark",
$dark
) !default;
$valuebox-colors: (
"primary": $valuebox-bg-primary,
"secondary": $valuebox-bg-secondary,
"success": $valuebox-bg-success,
"info": $valuebox-bg-info,
"warning": $valuebox-bg-warning,
"danger": $valuebox-bg-danger,
"light": $valuebox-bg-light,
"dark": $valuebox-bg-dark,
);
// Dashboards
.quarto-dashboard {
&.nav-fixed.dashboard-sidebar #quarto-content.quarto-dashboard-content {
padding: 0em;
}
#quarto-content.quarto-dashboard-content {
padding: 1em;
> * {
padding-top: 0;
}
}
@include media-breakpoint-up(sm) {
height: 100%;
}
@each $valuebox-color, $valuebox-color-value in $valuebox-colors {
.card.valuebox.bslib-card.bg-#{$valuebox-color} {
background-color: $valuebox-color-value !important;
}
}
&.dashboard-fill {
display: flex;
flex-direction: column;
}
#quarto-appendix {
display: none;
}
// Navbar / Navigation
#quarto-header #quarto-dashboard-header {
border-top: solid 1px theme-dim($navbar-bg, 10%);
border-bottom: solid 1px theme-dim($navbar-bg, 10%);
> nav {
padding-left: 1em;
padding-right: 1em;
.navbar-brand-container {
padding-left: 0;
}
}
.navbar-toggler {
margin-right: 0;
}
.navbar-toggler-icon {
height: 1em;
width: 1em;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#{colorToRGB($navbar-fg)}" class="bi bi-menu-button-wide" viewBox="0 0 16 16"><path d="M0 1.5A1.5 1.5 0 0 1 1.5 0h13A1.5 1.5 0 0 1 16 1.5v2A1.5 1.5 0 0 1 14.5 5h-13A1.5 1.5 0 0 1 0 3.5v-2zM1.5 1a.5.5 0 0 0-.5.5v2a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5h-13z"/><path d="M2 2.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm10.823.323-.396-.396A.25.25 0 0 1 12.604 2h.792a.25.25 0 0 1 .177.427l-.396.396a.25.25 0 0 1-.354 0zM0 8a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V8zm1 3v2a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2H1zm14-1V8a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v2h14zM2 8.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0 4a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5z"/></svg>');
}
.navbar-brand-container {
padding-right: 1em;
}
.navbar-title {
font-size: 1.1em;
}
.navbar-nav {
font-size: 0.9em;
}
}
#quarto-dashboard-header {
.navbar {
padding: 0;
.navbar-container {
padding-left: 1em;
}
&.slim {
.navbar-brand-container,
.navbar-nav {
.nav-link {
padding: 0.7em;
}
}
}
.quarto-color-scheme-toggle {
order: 9;
}
.navbar-toggler {
margin-left: 0.5em;
order: 10;
}
.navbar-nav {
.nav-link {
padding: 0.5em;
height: 100%;
display: flex;
align-items: center;
}
& .active {
background-color: theme-dim($navbar-bg, 8%);
}
}
.navbar-brand-container {
padding: 0.5em 0.5em 0.5em 0;
display: flex;
flex-direction: row;
margin-right: 2em;
align-items: center;
@include media-breakpoint-down(md) {
margin-right: auto;
}
}
.navbar-collapse {
@include media-breakpoint-up(md) {
order: 8;
}
@include media-breakpoint-down(md) {
order: 1000;
padding-bottom: 0.5em;
}
align-self: stretch;
.navbar-nav {
align-self: stretch;
}
}
.navbar-title {
font-size: 1.25em;
line-height: 1.1em;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: baseline;
.navbar-title-text {
margin-right: 0.4em;
}
a {
text-decoration: none;
color: inherit;
}
}
.navbar-subtitle,
.navbar-author {
font-size: 0.9rem;
margin-right: 0.5em;
}
.navbar-author {
margin-left: auto;
}
.navbar-logo {
max-height: 48px;
min-height: 30px;
object-fit: cover;
margin-right: 1em;
}
.quarto-dashboard-links {
order: 9;
padding-right: 1em;
}
.quarto-dashboard-link-text {
margin-left: 0.25em;
}
.quarto-dashboard-link {
padding-right: 0em;
padding-left: 0.7em;
text-decoration: none;
color: $navbar-fg;
}
}
}
.page-layout-custom .tab-content {
padding: 0;
border: none;
}
}
.quarto-dashboard-img-contain {
height: 100%;
width: 100%;
object-fit: contain;
}
.quarto-dashboard {
// Mobile sizes convert into 'scrolling' layouts
@include media-breakpoint-down(sm) {
.bslib-grid {
grid-template-rows: minmax(1em, max-content) !important;
}
.sidebar-content {
height: inherit;
}
.page-layout-custom {
min-height: 100vh;
}
}
&.dashboard-toolbar > .page-layout-custom,
&.dashboard-sidebar > .page-layout-custom {
padding: 0;
}
.quarto-dashboard-content.quarto-dashboard-pages {
padding: 0;
}
.callout {
margin-bottom: 0;
margin-top: 0;
}
.html-fill-container figure {
overflow: hidden;
}
bslib-tooltip {
.rounded-pill {
.svg {
fill: $body-color;
}
border: solid $text-muted 1px;
}
}
.tabset .dashboard-card-no-title .nav-tabs {
margin-left: 0;
margin-right: auto;
}
.tabset .tab-content {
border: none;
}
.tabset .card-header {
.nav-link[role="tab"] {
margin-top: -6px;
padding-top: 6px;
padding-bottom: 6px;
}
}
.card.valuebox,
.card.bslib-value-box {
min-height: 3rem;
.card-body {
padding: 0;
}
}
.bslib-value-box {
.value-box-value {
font-size: clamp(0.1em, 15cqw, 5em);
}
.value-box-showcase .bi {
font-size: clamp(0.1em, max(18cqw, 5.2cqh), 5em);
text-align: center;
height: 1em;
}
.value-box-showcase .bi::before {
vertical-align: 1em;
}
.value-box-area {
margin-top: auto;
margin-bottom: auto;
}
}
.card figure.quarto-float {
display: flex;
flex-direction: column;
align-items: center;
}
.dashboard-scrolling {
padding: 1em;
}
.full-height {
height: 100%;
}
.showcase-bottom {
.value-box-grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr auto;
grid-template-areas: "top" "bottom";
.value-box-showcase {
grid-area: bottom;
padding: 0;
margin: 0;
i.bi {
font-size: 4rem;
}
}
.value-box-area {
grid-area: top;
}
}
}
.tab-content {
margin-bottom: 0;
}
.bslib-card .bslib-navs-card-title {
justify-content: stretch;
align-items: end;
}
.card-header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.card-title {
display: flex;
flex-direction: column;
justify-content: center;
margin-bottom: 0;
}
}
.tabset {
.card-toolbar {
margin-bottom: 1em;
}
}
/* Sidebar */
.bslib-grid > .bslib-sidebar-layout {
border: none;
gap: var(--bslib-spacer, 1rem);
> .main {
padding: 0;
}
> .sidebar {
border-radius: $card-border-radius;
border: $card-border-width solid $card-border-color;
}
> .collapse-toggle {
display: none;
}
@include media-breakpoint-down(md) {
grid-template-columns: 1fr;
grid-template-rows: max-content 1fr;
> .main {
grid-column: 1;
grid-row: 2;
}
.sidebar {
grid-column: 1;
grid-row: 1;
}
}
}
.sidebar-right {
.sidebar {
padding-left: 2.5em;
}
.collapse-toggle {
left: 2px;
}
}
.quarto-dashboard .sidebar-right button.collapse-toggle:not(.transitioning) {
left: unset;
}
aside.sidebar {
padding-left: 1em;
padding-right: 1em;
background-color: $card-cap-bg;
color: $card-cap-color or $body-color;
}
.bslib-sidebar-layout {
> div.main {
padding: 0.7em;
}
button.collapse-toggle {
margin-top: 0.3em;
}
}
.bslib-sidebar-layout .collapse-toggle {
top: 0;
}
.bslib-sidebar-layout.sidebar-collapsed:not(.transitioning):not(
.sidebar-right
)
.collapse-toggle {
left: 2px;
}
.sidebar > section > .h3:first-of-type {
margin-top: 0em;
}
.sidebar .h3,
.sidebar .h4,
.sidebar .h5,
.sidebar .h6 {
margin-top: 0.5em;
}
.sidebar {
@include observable-sidebar-inputs();
.card-body {
margin-bottom: 2em;
}
.shiny-input-container {
margin-bottom: 1em;
}
.shiny-options-group {
margin-top: 0;
}
.control-label {
margin-bottom: 0.3em;
}
}
.card .card-body .quarto-layout-row {
align-items: stretch;
}
/* Toolbar */
.toolbar {
font-size: 0.9em;
display: flex;
flex-direction: row;
border-top: solid 1px theme-dim($secondary-bg-subtle, 10%);
padding: 1em;
flex-wrap: wrap;
background-color: $card-cap-bg;
@include shiny-toolbar-customizations();
@include observable-toolbar-inputs();
> * {
font-size: 0.9em;
flex-grow: 0;
}
.shiny-input-container {
label {
margin-bottom: 1px;
}
}
}
// Positions the toolbar at the bottom of the flexbox
.toolbar-bottom {
margin-top: 1em;
margin-bottom: 0 !important;
order: 2;
}
// If there is are pages, move the padding down inside the
// the nested tab contents (Global)
.quarto-dashboard-content
> .dashboard-toolbar-container
> .toolbar-content
> .tab-content
> .tab-pane
> *:not(.bslib-sidebar-layout) {
padding: 1em;
}
// If this is simple dashboard with a top level tool bar
.quarto-dashboard-content
> .dashboard-toolbar-container
> .toolbar-content
> *:not(.tab-content) {
padding: 1em;
}
// If there are pages, but no global toolbar
.quarto-dashboard-content
> .tab-content
> .dashboard-page
> .dashboard-toolbar-container
> .toolbar-content,
.quarto-dashboard-content
> .tab-content
> .dashboard-page:not(.dashboard-sidebar-container)
> *:not(.dashboard-toolbar-container) {
padding: 1em;
}
.toolbar-content {
padding: 0;
}
.quarto-dashboard-content.quarto-dashboard-pages
.tab-pane
> .dashboard-toolbar-container {
.toolbar {
border-radius: 0;
margin-bottom: 0;
}
}
.dashboard-toolbar-container.toolbar-toplevel {
.toolbar {
border-bottom: $card-border-width solid $card-border-color;
}
.toolbar-bottom {
margin-top: 0;
}
}
.dashboard-toolbar-container:not(.toolbar-toplevel) {
.toolbar {
margin-bottom: 1em;
border-top: none;
border-radius: $border-radius;
border: $card-border-width solid $card-border-color;
}
}
.vega-embed.has-actions {
details {
width: 1.7em;
height: 2em;
position: absolute !important;
top: 0;
right: 0;
}
}
.dashboard-toolbar-container {
padding: 0;
}
/* Card Toolbar */
/* Card */
.card {
.card-header,
.card-footer {
p:last-child {
margin-bottom: 0;
}
}
.card-body > .h4:first-child {
margin-top: 0;
}
// This ensures that elements in the card body (notably the expansion toggle)
// appear above the elements inside of it (notably itables, which cause issues)
.card-body {
z-index: 4;
// Customize appearance of elements within cards
@include itables();
}
.card-footer {
font-size: 0.9em;
}
.card-toolbar {
display: flex;
flex-grow: 1;
flex-direction: row;
width: 100%;
> * {
font-size: 0.8em;
flex-grow: 0;
}
> .card-title {
font-size: 1em;
flex-grow: 1;
align-self: flex-start;
margin-top: 0.1em;
}
flex-wrap: wrap;
@include toolbar-layout();
@include observable-toolbar-inputs();
@include shiny-toolbar-customizations();
}
}
/*-- Misc HTML elements --*/
.card-body > table > thead {
border-top: none;
}
.card-body > .table > :not(caption) > * > * {
background-color: $card-bg;
color: $card-color;
}
}
/*-- itables --*/
.tableFloatingHeaderOriginal {
background-color: $card-bg;
position: sticky !important;
top: 0 !important;
}
.dashboard-data-table {
margin-top: -1px;
}
/*-- ojs --*/
div.value-box-area span.observablehq--number {
/* the calculation below is pretty horrible, but it's our best effort to match
the font sizes of these two different ways of rendering a number in a value-box:
```{ojs}
//| content: valuebox
//| title: "Articles per day"
//| icon: pencil
//| color: primary
12
```
```{python}
#| content: valuebox
#| title: "Articles per day"
#| icon: pencil
#| color: primary
dict(
value = 12
)
```
See https://github.com/quarto-dev/quarto-cli/issues/8823
*/
font-size: calc(clamp(0.1em, 15cqw, 5em) * 1.25);
line-height: 1.2;
color: inherit;
font-family: var(--bs-body-font-family);
}