From fc8cee34be2955ba65713818c5d46bf6b1158931 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 5 Jan 2024 10:10:44 -0500 Subject: [PATCH] Restructure SCSS files --- netbox/project-static/bundle.js | 4 +- .../project-static/dist/netbox-external.css | Bin 346253 -> 346241 bytes netbox/project-static/dist/netbox.css | Bin 543174 -> 543174 bytes netbox/project-static/styles/_external.scss | 4 - netbox/project-static/styles/_netbox.scss | 14 - .../{variables.scss => _variables.scss} | 9 +- netbox/project-static/styles/bootstrap.scss | 40 - netbox/project-static/styles/extensions.scss | 45 - netbox/project-static/styles/external.scss | 4 + netbox/project-static/styles/netbox.scss | 1083 +---------------- netbox/project-static/styles/old/netbox.scss | 1078 ++++++++++++++++ .../styles/{ => old}/overrides.scss | 0 .../styles/{ => old}/theme-light.scss | 6 +- .../styles/{ => old}/utilities.scss | 0 .../_slim-select.scss} | 11 + .../styles/svg/cable_trace.scss | 2 +- .../styles/svg/rack_elevation.scss | 2 +- netbox/project-static/styles/temp.scss | 10 - .../transitional/{cards.scss => _cards.scss} | 0 .../{tables.scss => _tables.scss} | 0 20 files changed, 1113 insertions(+), 1199 deletions(-) delete mode 100644 netbox/project-static/styles/_external.scss delete mode 100644 netbox/project-static/styles/_netbox.scss rename netbox/project-static/styles/{variables.scss => _variables.scss} (89%) delete mode 100644 netbox/project-static/styles/bootstrap.scss delete mode 100644 netbox/project-static/styles/extensions.scss create mode 100644 netbox/project-static/styles/external.scss create mode 100644 netbox/project-static/styles/old/netbox.scss rename netbox/project-static/styles/{ => old}/overrides.scss (100%) rename netbox/project-static/styles/{ => old}/theme-light.scss (93%) rename netbox/project-static/styles/{ => old}/utilities.scss (100%) rename netbox/project-static/styles/{select.scss => overrides/_slim-select.scss} (96%) delete mode 100644 netbox/project-static/styles/temp.scss rename netbox/project-static/styles/transitional/{cards.scss => _cards.scss} (100%) rename netbox/project-static/styles/transitional/{tables.scss => _tables.scss} (100%) diff --git a/netbox/project-static/bundle.js b/netbox/project-static/bundle.js index 69b553282..85cf3c57b 100644 --- a/netbox/project-static/bundle.js +++ b/netbox/project-static/bundle.js @@ -73,8 +73,8 @@ async function bundleScripts() { async function bundleStyles() { try { const entryPoints = { - 'netbox-external': 'styles/_external.scss', - 'netbox': 'styles/_netbox.scss', + 'netbox-external': 'styles/external.scss', + 'netbox': 'styles/netbox.scss', rack_elevation: 'styles/svg/rack_elevation.scss', cable_trace: 'styles/svg/cable_trace.scss', graphiql: 'netbox-graphiql/graphiql.scss', diff --git a/netbox/project-static/dist/netbox-external.css b/netbox/project-static/dist/netbox-external.css index 1e1873436c48c01c98bc7bad00ff5b0c8fd90458..ff401f105aee3c9bbc3e28ded1a887bd8f874344 100644 GIT binary patch delta 41 ucmeC3DB3ttw4sHug{g(Pg=GtC6ytO|HCEZ}wT!IXydb8`_EmhWk1YWUiVP$G delta 58 zcmZpiDB3$ww4sHug{g(Pg=GtC6eCwbg^mFPZ;xYSRpCVvm<|+>*glVs^|2)Y74s3` diff --git a/netbox/project-static/dist/netbox.css b/netbox/project-static/dist/netbox.css index 0183904b822be5eec1ba3af7bb4d6b77af2b0a6d..cc0218f3535286f2d926e63baf4e8510682efe51 100644 GIT binary patch delta 48 zcmX>$S@GCp#fBEf7N!>F7M2#)7Pc1lEgX~Gr(ag*ke$9(g@b2$t0#xU_DSv>Cm9*J E0I3HM4*&oF delta 38 ucmX>$S@GCp#fBEf7N!>F7M2#)7Pc1lEgX~GxBqqLIKeo5k~>EhBNqS}+6{aF diff --git a/netbox/project-static/styles/_external.scss b/netbox/project-static/styles/_external.scss deleted file mode 100644 index 2036934e0..000000000 --- a/netbox/project-static/styles/_external.scss +++ /dev/null @@ -1,4 +0,0 @@ -// Entry for all 3rd party library imports that do not rely on Bootstrap or NetBox styles. -@import '../node_modules/@mdi/font/css/materialdesignicons.min.css'; -@import '../node_modules/flatpickr/dist/flatpickr.css'; -@import 'gridstack/dist/gridstack.min.css'; diff --git a/netbox/project-static/styles/_netbox.scss b/netbox/project-static/styles/_netbox.scss deleted file mode 100644 index c37c59b5a..000000000 --- a/netbox/project-static/styles/_netbox.scss +++ /dev/null @@ -1,14 +0,0 @@ -@import 'variables'; - -// Tabler -@import '../node_modules/@tabler/core/src/scss/_core.scss'; - -// slim-select -@import './select.scss'; - -// Transitional styling -@import './transitional/cards.scss'; -@import './transitional/tables.scss'; - -// Temporary overrides -@import './temp.scss'; diff --git a/netbox/project-static/styles/variables.scss b/netbox/project-static/styles/_variables.scss similarity index 89% rename from netbox/project-static/styles/variables.scss rename to netbox/project-static/styles/_variables.scss index 529456cfa..b387045f3 100644 --- a/netbox/project-static/styles/variables.scss +++ b/netbox/project-static/styles/_variables.scss @@ -1,4 +1,8 @@ -// NetBox CSS Variables +// Global variables + +// Set base fonts +$font-google: 'Inter'; +$font-google-monospaced: 'Roboto Mono'; // Set the navigation sidebar width $sidebar-width: 18rem; @@ -10,6 +14,3 @@ $btn-padding-y: 0.25rem; // Reduce the default table cell padding $table-cell-padding-x: 0.5rem; $table-cell-padding-y: 0.5rem; - -$font-google: 'Inter'; -$font-google-monospaced: 'Roboto Mono'; diff --git a/netbox/project-static/styles/bootstrap.scss b/netbox/project-static/styles/bootstrap.scss deleted file mode 100644 index 9f4191057..000000000 --- a/netbox/project-static/styles/bootstrap.scss +++ /dev/null @@ -1,40 +0,0 @@ -// Import the rest of bootstrap. -@import '../node_modules/bootstrap/scss/maps'; -@import '../node_modules/bootstrap/scss/mixins'; -@import '../node_modules/bootstrap/scss/utilities'; -@import './extensions'; -@import '../node_modules/bootstrap/scss/mixins'; -@import '../node_modules/bootstrap/scss/root'; -@import '../node_modules/bootstrap/scss/reboot'; -@import '../node_modules/bootstrap/scss/type'; -@import '../node_modules/bootstrap/scss/images'; -@import '../node_modules/bootstrap/scss/containers'; -@import '../node_modules/bootstrap/scss/grid'; -@import '../node_modules/bootstrap/scss/tables'; -@import '../node_modules/bootstrap/scss/forms'; -@import '../node_modules/bootstrap/scss/buttons'; -@import '../node_modules/bootstrap/scss/transitions'; -@import '../node_modules/bootstrap/scss/dropdown'; -@import '../node_modules/bootstrap/scss/button-group'; -@import '../node_modules/bootstrap/scss/nav'; -@import '../node_modules/bootstrap/scss/navbar'; -@import '../node_modules/bootstrap/scss/card'; -@import '../node_modules/bootstrap/scss/accordion'; -@import '../node_modules/bootstrap/scss/breadcrumb'; -@import '../node_modules/bootstrap/scss/pagination'; -@import '../node_modules/bootstrap/scss/badge'; -@import '../node_modules/bootstrap/scss/alert'; -@import '../node_modules/bootstrap/scss/progress'; -@import '../node_modules/bootstrap/scss/list-group'; -@import '../node_modules/bootstrap/scss/close'; -@import '../node_modules/bootstrap/scss/toasts'; -@import '../node_modules/bootstrap/scss/modal'; -@import '../node_modules/bootstrap/scss/tooltip'; -@import '../node_modules/bootstrap/scss/popover'; -@import '../node_modules/bootstrap/scss/carousel'; -@import '../node_modules/bootstrap/scss/spinners'; -@import '../node_modules/bootstrap/scss/offcanvas'; -@import '../node_modules/bootstrap/scss/placeholders'; -@import '../node_modules/bootstrap/scss/spinners'; -@import '../node_modules/bootstrap/scss/helpers'; -@import '../node_modules/bootstrap/scss/utilities/api'; diff --git a/netbox/project-static/styles/extensions.scss b/netbox/project-static/styles/extensions.scss deleted file mode 100644 index 79d19d17e..000000000 --- a/netbox/project-static/styles/extensions.scss +++ /dev/null @@ -1,45 +0,0 @@ -// Bootstrap utility extensions. -// See https://getbootstrap.com/docs/5.0/utilities/api/ - -// Add responsive max-width classes for more granular controls over max-width. -$max-width-extension: ( - 'max-width': ( - property: max-width, - class: mw, - responsive: true, - values: ( - 20: 20%, - 25: 25%, - 33: 33%, - 50: 50%, - 66: 66%, - 75: 75%, - 80: 80%, - 90: 90%, - 100: 100%, - ), - ), -); - -// Add more opacity classes. -$opacity-extension: ( - 'opacity': ( - property: opacity, - class: opacity, - values: ( - 0: 0, - 10: 0.1, - 20: 0.2, - 25: 0.25, - 33: 0.33, - 50: 0.5, - 66: 0.66, - 75: 0.75, - 80: 0.8, - 90: 0.9, - 100: 1, - ), - ), -); - -$utilities: map-merge($utilities, $max-width-extension, $opacity-extension); diff --git a/netbox/project-static/styles/external.scss b/netbox/project-static/styles/external.scss new file mode 100644 index 000000000..729f70596 --- /dev/null +++ b/netbox/project-static/styles/external.scss @@ -0,0 +1,4 @@ +// Entry for all 3rd party library imports that do not rely on Tabler or NetBox styles. +@import '../node_modules/@mdi/font/css/materialdesignicons.min.css'; +@import '../node_modules/flatpickr/dist/flatpickr.min.css'; +@import 'gridstack/dist/gridstack.min.css'; diff --git a/netbox/project-static/styles/netbox.scss b/netbox/project-static/styles/netbox.scss index 8d0192593..35f879b1e 100644 --- a/netbox/project-static/styles/netbox.scss +++ b/netbox/project-static/styles/netbox.scss @@ -1,1078 +1,11 @@ -// NetBox-specific Styles and Overrides. +@import 'variables'; -@use 'sass:map'; -@use 'sass:math'; -//@import './sidenav'; -@import './overrides'; -@import './utilities'; -@import './variables'; +// Tabler +@import '../node_modules/@tabler/core/src/scss/_core.scss'; -@each $color, $value in $theme-colors { - // Override CSS values on each theme color. +// Overrides of external libraries +@import 'overrides/slim-select'; - // Use Bootstrap's method of coloring alert links to appropriately color close buttons within - // another colored element. - // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52 - // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_close.scss#L12 - $shifted-bg: shift-color($value, $alert-bg-scale); - $shifted-color: shift-color($value, $alert-color-scale); - - @if (contrast-ratio($shifted-bg, $shifted-color) < $min-contrast-ratio) { - $shifted-color: mix($value, color-contrast($shifted-bg), abs($alert-color-scale)); - } - - $btn-close-bg: url("data:image/svg+xml,"); - .bg-#{$color} button.btn-close { - background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; - } - - .btn.btn-ghost-#{$color} { - color: $value; - &:hover { - background-color: rgba($value, 0.12); - } - } - - // Use Bootstrap's method of coloring the .alert-link class automatically. - // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52 - - .alert.alert-#{$color}, - .table-#{$color} { - // Exclude buttons. - a:not(.btn) { - font-weight: $font-weight-bold; - color: $shifted-color; - } - // Apply a border to buttons contained within colored elements, if they're not already a - // bordered button class. - .btn:not([class*='btn-outline']) { - border-color: $gray-700; - } - } - - // Toasts required a slightly different approach because the background color isn't "shifted", - // it's the direct theme color. - .toast.bg-#{$color} { - $shifted-color: shift-color($value, $alert-color-scale); - - @if (contrast-ratio($value, $shifted-color) < $min-contrast-ratio) { - $shifted-color: mix($value, color-contrast($value), abs($alert-color-scale)); - } - a:not(.btn) { - font-weight: $font-weight-bold; - color: $shifted-color; - } - } - - // Use proper contrasting color foreground color for special components. - .badge, - .toast, - .toast-header, - .progress-bar { - &.bg-#{$color} { - color: color-contrast($value); - } - } -} - -// Ensure progress bars (utilization graph) in tables aren't too narrow to display the percentage. -table td > .progress { - min-width: 6rem; -} - -// Override Bootstrap form-control font-size when contained by .small element. -.small .form-control { - font-size: $font-size-sm; -} - -// Automatically space out adjacent columns, but not within card bodies. -:not(.card-body) > .col:not(:last-child):not(:only-child) { - margin-bottom: $spacer; -} - -.nav-mobile { - display: none; - flex-direction: column; - align-items: center; - justify-content: space-between; - width: 100%; - - @include media-breakpoint-down(lg) { - display: flex; - } - - .nav-mobile-top { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - } -} - -.card > .table.table-flush { - margin-bottom: 0; - overflow: hidden; - border-bottom-right-radius: $card-border-radius; - border-bottom-left-radius: $card-border-radius; - - thead th[scope='col'] { - padding-top: map.get($spacers, 3); - padding-bottom: map.get($spacers, 3); - text-transform: uppercase; - vertical-align: middle; - background-color: $table-flush-header-bg; - border-top: 1px solid $card-border-color; - border-bottom-color: $card-border-color; - } - - th, - td { - padding-right: map.get($spacers, 4) !important; - padding-left: map.get($spacers, 4) !important; - border-right: 0; - border-left: 0; - } - tr[class] { - border-color: $card-border-color !important; - &:last-of-type { - border-bottom-color: transparent !important; - border-bottom-right-radius: $card-border-radius; - border-bottom-left-radius: $card-border-radius; - } - } -} - -// Primarily used for the new release notification, but could be used for other alerts as needed. -// Wrap any alerts in .header-alert-container to ensure the layout is consistent. -.header-alert-container { - // Center-align the alert(s). - display: flex; - align-items: center; - justify-content: center; - // Apply the same spacing that's applied to the #content div's first child (.px-3). - padding: 0 $spacer; - - // By default, alerts inside .header-alert-container should take up the full width. - .alert { - width: 100%; - - // Adjust the max-width for larger screens so there's not a big ugly blue blob taking up the - // entire screen. - @include media-breakpoint-up(md) { - max-width: 75%; - } - @include media-breakpoint-up(lg) { - max-width: 50%; - } - } -} - -.alert { - code { - color: $gray-600; - } -} - -span.profile-button .dropdown-menu { - right: 0; - left: auto; - display: block !important; - margin-top: 0.5rem; - box-shadow: $box-shadow; - transition: opacity 0.2s ease-in-out; - - &:not(.show) { - pointer-events: none; - opacity: 0; - } - &.show { - pointer-events: auto; - opacity: 1; - } -} - -div#advanced-search-content div.card div.card-body div.col:not(:last-child) { - margin-right: 1rem; -} - -table { - td { - a { - text-decoration: none; - &:hover { - text-decoration: underline; - } - } - .dropdown { - // Presence of 'overflow: scroll' on a table causes dropdowns to be improperly hidden when - // opened. See: https://github.com/twbs/bootstrap/issues/24251 - position: static; - } - } - th { - a, - a:hover { - color: $body-color; - text-decoration: none; - } - } - - td, - th { - font-size: $font-size-sm; - line-height: $line-height-sm; - vertical-align: middle; - &.min-width { - width: 1%; - } - .form-check-input { - // Ensure checkboxes aren't too small inside object tables. - margin-top: 0.125em; - font-size: $font-size-base; - } - - .btn-sm { - line-height: $line-height-xs; - } - - p { - // Remove spacing from paragraph elements within tables. - margin-bottom: 0.5em; - } - - p:last-child { - margin-bottom: 0; - } - } - - th.asc > a::after { - content: '\f0140'; - font-family: 'Material Design Icons'; - } - - th.desc > a::after { - content: '\f0143'; - font-family: 'Material Design Icons'; - } - - &.table > :not(caption) > * > * { - padding-right: $table-cell-padding-x-sm !important; - padding-left: $table-cell-padding-x-sm !important; - } - - &.object-list { - th { - font-size: $font-size-xs; - line-height: $line-height-xs; - vertical-align: bottom; - } - } - - &.attr-table { - th { - font-weight: normal; - width: 25%; - } - } -} - -div.title-container { - display: flex; - // On small screens, `flex-direction: column;` ensures the control buttons don't appear on the - // same line as the title, but rather break to the next line. - flex-direction: column; - flex-wrap: wrap; - justify-content: space-between; - - @include media-breakpoint-up(lg) { - // On large screens, `flex-direction: row;` allows the control buttons to appear vertically - // aligned with the title. - flex-direction: row; - } - - #content-title { - display: flex; - flex: 1 0; - flex-direction: column; - padding-bottom: map.get($spacers, 2); - } -} - -// Object list control buttons (Add/Clone/Import/Export) -.controls { - margin-bottom: map.get($spacers, 2); - - @media print { - // Never print controls. Use this over the .noprint utility so plugin authors don't need to - // remember to add the class. - display: none !important; - } - - // Each group of buttons. - .control-group { - display: flex; - flex-wrap: wrap; - // Left-align controls on mobile. - justify-content: flex-start; - - // Right-align controls on larger screens. - @include media-breakpoint-up(lg) { - justify-content: flex-end; - } - - > * { - // Pad each control button. - margin: map.get($spacers, 1); - - &:first-child { - // Don't pad the left side of the first control button. - margin-left: 0; - } - - &:last-child { - // Don't pad the right side of the last control button. - margin-right: 0; - } - } - } -} - -.object-subtitle { - display: block; - font-size: $font-size-sm; - color: $text-muted; - - @include media-breakpoint-up(md) { - display: inline-block; - } - - > span { - display: block; - - // Hide the separator on small screens. - &.separator { - display: none; - } - - &, - &.separator { - @include media-breakpoint-up(md) { - display: inline-block; - } - } - } -} - -// Global Search -nav.search { - // Don't overtake dropdowns - z-index: 999; - justify-content: center; - background-color: $navbar-light-color; - - .search-container { - display: flex; - width: 100%; - - @include media-breakpoint-down(lg) { - display: none; - } - } - - // Search Input & Selected Object Value & Object Selector - .input-group { - // Selected Object - .search-obj-selected { - border-color: $input-border-color; - } - - // Object Selector Dropdown Button - .dropdown-toggle { - // Generate the same styles as a regular Bootstrap button. - //@include button-variant($input-group-addon-bg, $input-border-color); - margin-left: 0; - font-weight: $input-group-addon-font-weight; - line-height: $input-line-height; - color: $input-group-addon-color; - background-color: $input-group-addon-bg; - border: $input-border-width solid $input-border-color; - @include border-radius($input-border-radius); - border-left: 1px solid var(--nbx-search-filter-border-left-color); - - &:focus { - box-shadow: unset !important; - } - // Don't show the dropdown icon — the filter icon is basically the same thing. - &:after { - display: none; - } - } - - // Object Selector Dropdown Menu - .search-obj-selector { - // Limit the height and enable scrolling on mobile devices. - max-height: 70vh; - overflow-y: auto; - - .dropdown-item, - .dropdown-header { - font-size: $font-size-sm; - } - - .dropdown-header { - text-transform: uppercase; - } - } - } -} - -// Styles for the quicksearch and its clear button; -// Overrides input-group styles and adds transition effects -.quicksearch { - input[type='search'] { - border-radius: $border-radius !important; - } - - button { - margin-left: -32px !important; - z-index: 100 !important; - outline: none !important; - border-radius: $border-radius !important; - transition: visibility 0s, opacity 0.2s linear; - } - - button :hover { - opacity: 50%; - transition: visibility 0s, opacity 0.1s linear; - } -} - -main.layout { - display: flex; - flex-wrap: nowrap; - height: 100vh; - height: -webkit-fill-available; - max-height: 100vh; - overflow-x: auto; - overflow-y: hidden; - - // Override styles when printing. Fixes issue where only the first page is visible when printing. - @media print { - position: static !important; - display: block !important; - height: 100%; - overflow-x: visible !important; - overflow-y: visible !important; - } -} - -main.login-container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - width: 100%; - max-width: 100vw; - height: calc(100vh - 4rem); - padding-top: 40px; - padding-bottom: 40px; - - + footer.footer button.color-mode-toggle { - color: var(--nbx-color-mode-toggle-color); - } -} - -.footer { - background-color: $tab-content-bg; - padding: 0; - .nav-link { - padding: 0.5rem; - } - - @include media-breakpoint-down(md) { - // Pad the bottom of the footer on mobile devices to account for mobile browser controls. - margin-bottom: 8rem; - } -} - -footer.login-footer { - height: 4rem; - margin-top: auto; - - .container-fluid { - display: flex; - justify-content: flex-end; - padding: $container-padding-x $grid-gutter-width; - } -} - -h1.accordion-item-title, -h2.accordion-item-title, -h3.accordion-item-title, -h4.accordion-item-title, -h5.accordion-item-title, -h6.accordion-item-title { - padding: 0.25rem 0.5rem; - font-size: $font-size-sm; - font-weight: $font-weight-bold; - color: var(--nbx-sidebar-title-color); - text-transform: uppercase; -} - -.form-login { - width: 100%; - max-width: 330px; - padding: 15px; - - input:focus { - z-index: 1; - } - - input[type='text'] { - margin-bottom: -1px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - } - input[type='password'] { - margin-bottom: 10px; - border-top-left-radius: 0; - border-top-right-radius: 0; - } - - .form-control { - position: relative; - box-sizing: border-box; - height: auto; - padding: 10px; - font-size: 16px; - } -} - -.navbar { - border-bottom: 1px solid $border-color; -} - -.navbar-brand { - padding-top: 0.75rem; - padding-bottom: 0.75rem; - font-size: 1rem; -} - -nav.nav.nav-pills { - .nav-item.nav-link { - padding: 0.25rem 0.5rem; - font-size: $font-size-sm; - border-radius: $border-radius; - - &:hover { - color: $accordion-button-active-color; - background-color: $accordion-button-active-bg; - } - } -} - -// Ensure the content container is full-height, and that the content block is also full height so -// that the footer is always at the bottom. -div.content-container { - position: relative; - display: flex; - flex-direction: column; - width: calc(100% - #{$sidenav-width-closed}); - min-height: 100vh; - overflow-x: hidden; - overflow-y: auto; - - // Don't show an outline when the content container is focused. - &:focus, - &:focus-visible { - outline: 0; - } - - div.content { - background-color: $tab-content-bg; - flex: 1; - } - - @include media-breakpoint-down(lg) { - width: 100%; - } - - // Make the content full-width when printing. - @media print { - width: 100% !important; - margin-left: 0 !important; - } -} - -// Prevent scrolling of body content when nav menu is open on mobile. -.sidebar.collapse.show ~ .content-container > .content { - @media (max-width: map.get($grid-breakpoints, 'md')) { - position: fixed; - top: 0; - left: 0; - overflow-y: hidden; - } -} - -.tooltip { - pointer-events: none; -} - -span.color-label { - display: block; - width: 5rem; - height: 1rem; - padding: $badge-padding-y $badge-padding-x; - border: 1px solid #303030; - border-radius: $border-radius; - box-shadow: $box-shadow-sm; -} - -.badge a { - color: inherit; -} - -.btn { - white-space: nowrap; -} - -.card { - box-shadow: $box-shadow-sm; - - .card-header { - padding: $card-cap-padding-x; - color: var(--nbx-body-color); - border-bottom: none; - } - - .card-header + .card-body { - padding-top: 0; - } - - .card-body.small .form-control, - .card-body.small .form-select { - font-size: $input-font-size-sm; - } - - .card-divider { - width: 100%; - height: 1px; - margin: $hr-margin-y 0; - border-top: 1px solid $card-border-color; - opacity: $hr-opacity; - } - - // Remove shadow when printing. - @media print { - box-shadow: unset !important; - } -} - -.form-floating { - position: relative; - - > .input-group > .form-control, - > .input-group > .form-select { - height: $form-floating-height; - padding: $form-floating-padding-y $form-floating-padding-x; - } - - > .input-group > label { - position: absolute; - top: 0; - left: 0; - height: 100%; // allow textareas - padding: $form-floating-padding-y $form-floating-padding-x; - pointer-events: none; - border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model - transform-origin: 0 0; - @include transition($form-floating-transition); - } - - > .input-group > .form-control { - &::placeholder { - color: transparent; - } - - &:focus, - &:not(:placeholder-shown) { - padding-top: $form-floating-input-padding-t; - padding-bottom: $form-floating-input-padding-b; - } - // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped - &:-webkit-autofill { - padding-top: $form-floating-input-padding-t; - padding-bottom: $form-floating-input-padding-b; - } - } - - > .input-group > .form-select, - > .choices > .choices__inner, - > .ss-main span.placeholder, // SlimSelect Single - > .ss-main div.ss-values // SlimSelect Multiple - { - padding-top: $form-floating-input-padding-t; - padding-bottom: $form-floating-input-padding-b; - } - - > .input-group > .form-control:focus, - > .input-group > .form-control:not(:placeholder-shown), - > .input-group > .form-select, - > .choices, - > .ss-main { - ~ label { - opacity: $form-floating-label-opacity; - transform: $form-floating-label-transform; - z-index: 4; - } - } - // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped - > .input-group > .form-control:-webkit-autofill { - ~ label { - z-index: 4; - opacity: $form-floating-label-opacity; - transform: $form-floating-label-transform; - } - } -} - -.form-object-edit { - margin: 0 auto; - max-width: 800px; -} - -textarea.form-control[rows='10'] { - height: 18rem; -} - -textarea.markdown, -textarea.form-control[name='csv'] { - font-family: $font-family-monospace; -} - -.card:not(:only-of-type) { - margin-bottom: $spacer; -} - -.stat-btn { - min-width: $spacer * 3; -} - -nav.breadcrumb-container { - width: fit-content; - padding: $badge-padding-y $badge-padding-x; - font-size: $font-size-sm; - - ol.breadcrumb { - margin-bottom: 0; - li.breadcrumb-item > a { - text-decoration: none; - } - li.breadcrumb-item > a:hover { - text-decoration: underline; - } - } -} - -label.required { - font-weight: $font-weight-bold; - - &:after { - position: absolute; - display: inline-block; - margin: 0 0 0 2px; - font-family: 'Material Design Icons'; - font-size: 8px; - font-style: normal; - font-weight: $font-weight-medium; - text-decoration: none; - content: '\f06C4'; - } -} - -// Applied to containing element around table bulk-action buttons (bulk-edit, bulk-disconnect -// bulk-delete, etc). Each usage of .bulk-buttons needs to have groups of buttons wrapped with -// .bulk-button-group so that proper spacing is applied (even if there is only one group). -div.bulk-buttons { - display: flex; - justify-content: space-between; - margin: math.div($spacer, 2) 0; - - // Each group of buttons needs to be contained separately for alignment purposes. This way, you - // can put some buttons in a group that aligns left, and other buttons in a group that aligns - // right. - > div.bulk-button-group { - display: flex; - flex-wrap: wrap; - // For small screens: don't fill the available space (thereby expanding the size of the button). - align-items: flex-start; - - &:first-of-type:not(:last-of-type) { - // If there are multiple bulk button groups and this is the first, the first button in the - // group should *not* have left spacing applied, so the button group aligns with the rest - // of the page elements. - > *:first-child { - margin-left: 0; - } - } - - &:last-of-type:not(:first-of-type) { - // If there are multiple bulk button groups and this is the last, the last button in the - // group should *not* have right spacing applied, so the button group aligns with the rest - // of the page elements. - > *:last-child { - margin-right: 0; - } - } - - // However, the rest of the buttons should have spacing applied in all directions. - > * { - margin: math.div($spacer, 4); - } - } -} - -table tbody { - @each $color, $value in $theme-colors { - tr.#{$color} { - background-color: rgba($value, 0.15); - border-color: $gray-500; - } - } -} - -// Style objects with statuses/roles within a table. As of implementation, used for IP addresses -// assigned to interfaces. -table .table-badge-group { - .table-badge { - display: block; - width: min-content; - font-size: $font-size-sm; - font-weight: $font-weight-base; - - &:not(.badge) { - // Apply badge horizontal padding so that IP addresses *not* within a badge appear aligned - // with IP addresses that *are* within a badge. - padding: 0 $badge-padding-x; - } - - &.badge:not(:last-of-type):not(:only-child) { - margin-bottom: map.get($spacers, 1); - } - } -} - -pre.change-data { - padding-right: 0; - padding-left: 0; - - > span { - display: block; - padding-right: $spacer; - padding-left: $spacer; - - &.added { - background-color: var(--nbx-change-added); - } - - &.removed { - background-color: var(--nbx-change-removed); - } - } -} - -pre.change-diff { - border-color: transparent; - - &.change-removed { - background-color: var(--nbx-change-removed); - } - - &.change-added { - background-color: var(--nbx-change-added); - } -} - -div.card-overlay { - position: absolute; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - background-color: rgba($white, 0.75); - border-radius: $border-radius; - - > div.spinner-border { - width: 6rem; - height: 6rem; - color: $secondary; - } -} - -.table-controls { - display: flex; - - @include media-breakpoint-up(md) { - // `!important` needed because of inherited margin-bottom from `.col` - margin-top: 0 !important; - margin-bottom: 0 !important; - } - - .table-configure { - justify-content: flex-start; - - @include media-breakpoint-up(md) { - justify-content: flex-end; - } - } - - .form-switch.form-check-inline { - flex: 1 0 auto; - font-size: $font-size-sm; - } -} - -// Tabbed content -.nav-tabs { - background-color: $body-bg; - .nav-link { - &:hover { - // Don't show a bottom-border on a hovered nav link because it overlaps with the .nav-tab border. - border-bottom-color: transparent; - } - &.active { - // Set the background-color of an active tab to the same color as the .tab-content - // background-color so it visually indicates which tab is open. - background-color: $tab-content-bg; - border-bottom-color: $tab-content-bg; - // Move the active tab down 1px to overtake the .nav-tabs element's border, but only for that - // tab. This is an ugly hack, but it works. - transform: translateY(1px); - } - } -} - -.tab-content { - display: flex; - flex-direction: column; - padding: $spacer; -} - -// Override masonry-layout styles when printing. -.masonry { - @media print { - position: static !important; - display: block !important; - height: unset !important; - } - .masonry-item { - @media print { - position: static !important; - top: unset !important; - left: unset !important; - display: block !important; - } - } -} - -// Object hierarchy indicators. -.record-depth { - display: inline; - font-size: $font-size-base; - user-select: none; - opacity: 0.33; - - // Add spacing to the last or only dot. - span:only-of-type, - span:last-of-type { - margin-right: map.get($spacers, 1); - } -} - -// Remove the max-width from image preview popovers as this is controlled on the image element. -.popover.image-preview-popover { - max-width: unset; -} - -/* Rendered Markdown */ -.rendered-markdown table { - width: 100%; -} -.rendered-markdown th { - border-bottom: 2px solid #dddddd; - padding: 8px; -} -.rendered-markdown td { - border-top: 1px solid #dddddd; - padding: 8px; -} - -th[align="left"] { - text-align: left; -} - -th[align="center"] { - text-align: center; -} - -th[align="right"] { - text-align: right; -} - -/* Markdown widget */ -.markdown-widget { - .nav-link { - border-bottom: 0; - - &.active { - background-color: var(--nbx-body-bg); - } - } - - .nav-tabs { - background-color: var(--nbx-pre-bg); - } -} - -// Preformatted text blocks -td pre { - margin-bottom: 0; -} -pre.block { - padding: $spacer; - background-color: var(--nbx-pre-bg); - border: 1px solid var(--nbx-pre-border-color); - border-radius: $border-radius; -} - -#django-messages { - position: fixed; - right: $spacer; - bottom: 0; - margin: $spacer; -} - -// Page-specific styles. -html { - // Shade the home page content background-color. - &[data-netbox-url-name='home'] { - .content-container, - .search { - background-color: $gray-100 !important; - } - &[data-netbox-color-mode='dark'] { - .content-container, - .search { - background-color: $darkest !important; - } - } - } - - // Don't show the django-messages toasts on the login screen in favor of the alert component. - &[data-netbox-url-name='login'] { - #django-messages { - display: none; - } - } -} +// Transitional styling +@import 'transitional/cards'; +@import 'transitional/tables'; diff --git a/netbox/project-static/styles/old/netbox.scss b/netbox/project-static/styles/old/netbox.scss new file mode 100644 index 000000000..8d0192593 --- /dev/null +++ b/netbox/project-static/styles/old/netbox.scss @@ -0,0 +1,1078 @@ +// NetBox-specific Styles and Overrides. + +@use 'sass:map'; +@use 'sass:math'; +//@import './sidenav'; +@import './overrides'; +@import './utilities'; +@import './variables'; + +@each $color, $value in $theme-colors { + // Override CSS values on each theme color. + + // Use Bootstrap's method of coloring alert links to appropriately color close buttons within + // another colored element. + // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52 + // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_close.scss#L12 + $shifted-bg: shift-color($value, $alert-bg-scale); + $shifted-color: shift-color($value, $alert-color-scale); + + @if (contrast-ratio($shifted-bg, $shifted-color) < $min-contrast-ratio) { + $shifted-color: mix($value, color-contrast($shifted-bg), abs($alert-color-scale)); + } + + $btn-close-bg: url("data:image/svg+xml,"); + .bg-#{$color} button.btn-close { + background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; + } + + .btn.btn-ghost-#{$color} { + color: $value; + &:hover { + background-color: rgba($value, 0.12); + } + } + + // Use Bootstrap's method of coloring the .alert-link class automatically. + // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52 + + .alert.alert-#{$color}, + .table-#{$color} { + // Exclude buttons. + a:not(.btn) { + font-weight: $font-weight-bold; + color: $shifted-color; + } + // Apply a border to buttons contained within colored elements, if they're not already a + // bordered button class. + .btn:not([class*='btn-outline']) { + border-color: $gray-700; + } + } + + // Toasts required a slightly different approach because the background color isn't "shifted", + // it's the direct theme color. + .toast.bg-#{$color} { + $shifted-color: shift-color($value, $alert-color-scale); + + @if (contrast-ratio($value, $shifted-color) < $min-contrast-ratio) { + $shifted-color: mix($value, color-contrast($value), abs($alert-color-scale)); + } + a:not(.btn) { + font-weight: $font-weight-bold; + color: $shifted-color; + } + } + + // Use proper contrasting color foreground color for special components. + .badge, + .toast, + .toast-header, + .progress-bar { + &.bg-#{$color} { + color: color-contrast($value); + } + } +} + +// Ensure progress bars (utilization graph) in tables aren't too narrow to display the percentage. +table td > .progress { + min-width: 6rem; +} + +// Override Bootstrap form-control font-size when contained by .small element. +.small .form-control { + font-size: $font-size-sm; +} + +// Automatically space out adjacent columns, but not within card bodies. +:not(.card-body) > .col:not(:last-child):not(:only-child) { + margin-bottom: $spacer; +} + +.nav-mobile { + display: none; + flex-direction: column; + align-items: center; + justify-content: space-between; + width: 100%; + + @include media-breakpoint-down(lg) { + display: flex; + } + + .nav-mobile-top { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } +} + +.card > .table.table-flush { + margin-bottom: 0; + overflow: hidden; + border-bottom-right-radius: $card-border-radius; + border-bottom-left-radius: $card-border-radius; + + thead th[scope='col'] { + padding-top: map.get($spacers, 3); + padding-bottom: map.get($spacers, 3); + text-transform: uppercase; + vertical-align: middle; + background-color: $table-flush-header-bg; + border-top: 1px solid $card-border-color; + border-bottom-color: $card-border-color; + } + + th, + td { + padding-right: map.get($spacers, 4) !important; + padding-left: map.get($spacers, 4) !important; + border-right: 0; + border-left: 0; + } + tr[class] { + border-color: $card-border-color !important; + &:last-of-type { + border-bottom-color: transparent !important; + border-bottom-right-radius: $card-border-radius; + border-bottom-left-radius: $card-border-radius; + } + } +} + +// Primarily used for the new release notification, but could be used for other alerts as needed. +// Wrap any alerts in .header-alert-container to ensure the layout is consistent. +.header-alert-container { + // Center-align the alert(s). + display: flex; + align-items: center; + justify-content: center; + // Apply the same spacing that's applied to the #content div's first child (.px-3). + padding: 0 $spacer; + + // By default, alerts inside .header-alert-container should take up the full width. + .alert { + width: 100%; + + // Adjust the max-width for larger screens so there's not a big ugly blue blob taking up the + // entire screen. + @include media-breakpoint-up(md) { + max-width: 75%; + } + @include media-breakpoint-up(lg) { + max-width: 50%; + } + } +} + +.alert { + code { + color: $gray-600; + } +} + +span.profile-button .dropdown-menu { + right: 0; + left: auto; + display: block !important; + margin-top: 0.5rem; + box-shadow: $box-shadow; + transition: opacity 0.2s ease-in-out; + + &:not(.show) { + pointer-events: none; + opacity: 0; + } + &.show { + pointer-events: auto; + opacity: 1; + } +} + +div#advanced-search-content div.card div.card-body div.col:not(:last-child) { + margin-right: 1rem; +} + +table { + td { + a { + text-decoration: none; + &:hover { + text-decoration: underline; + } + } + .dropdown { + // Presence of 'overflow: scroll' on a table causes dropdowns to be improperly hidden when + // opened. See: https://github.com/twbs/bootstrap/issues/24251 + position: static; + } + } + th { + a, + a:hover { + color: $body-color; + text-decoration: none; + } + } + + td, + th { + font-size: $font-size-sm; + line-height: $line-height-sm; + vertical-align: middle; + &.min-width { + width: 1%; + } + .form-check-input { + // Ensure checkboxes aren't too small inside object tables. + margin-top: 0.125em; + font-size: $font-size-base; + } + + .btn-sm { + line-height: $line-height-xs; + } + + p { + // Remove spacing from paragraph elements within tables. + margin-bottom: 0.5em; + } + + p:last-child { + margin-bottom: 0; + } + } + + th.asc > a::after { + content: '\f0140'; + font-family: 'Material Design Icons'; + } + + th.desc > a::after { + content: '\f0143'; + font-family: 'Material Design Icons'; + } + + &.table > :not(caption) > * > * { + padding-right: $table-cell-padding-x-sm !important; + padding-left: $table-cell-padding-x-sm !important; + } + + &.object-list { + th { + font-size: $font-size-xs; + line-height: $line-height-xs; + vertical-align: bottom; + } + } + + &.attr-table { + th { + font-weight: normal; + width: 25%; + } + } +} + +div.title-container { + display: flex; + // On small screens, `flex-direction: column;` ensures the control buttons don't appear on the + // same line as the title, but rather break to the next line. + flex-direction: column; + flex-wrap: wrap; + justify-content: space-between; + + @include media-breakpoint-up(lg) { + // On large screens, `flex-direction: row;` allows the control buttons to appear vertically + // aligned with the title. + flex-direction: row; + } + + #content-title { + display: flex; + flex: 1 0; + flex-direction: column; + padding-bottom: map.get($spacers, 2); + } +} + +// Object list control buttons (Add/Clone/Import/Export) +.controls { + margin-bottom: map.get($spacers, 2); + + @media print { + // Never print controls. Use this over the .noprint utility so plugin authors don't need to + // remember to add the class. + display: none !important; + } + + // Each group of buttons. + .control-group { + display: flex; + flex-wrap: wrap; + // Left-align controls on mobile. + justify-content: flex-start; + + // Right-align controls on larger screens. + @include media-breakpoint-up(lg) { + justify-content: flex-end; + } + + > * { + // Pad each control button. + margin: map.get($spacers, 1); + + &:first-child { + // Don't pad the left side of the first control button. + margin-left: 0; + } + + &:last-child { + // Don't pad the right side of the last control button. + margin-right: 0; + } + } + } +} + +.object-subtitle { + display: block; + font-size: $font-size-sm; + color: $text-muted; + + @include media-breakpoint-up(md) { + display: inline-block; + } + + > span { + display: block; + + // Hide the separator on small screens. + &.separator { + display: none; + } + + &, + &.separator { + @include media-breakpoint-up(md) { + display: inline-block; + } + } + } +} + +// Global Search +nav.search { + // Don't overtake dropdowns + z-index: 999; + justify-content: center; + background-color: $navbar-light-color; + + .search-container { + display: flex; + width: 100%; + + @include media-breakpoint-down(lg) { + display: none; + } + } + + // Search Input & Selected Object Value & Object Selector + .input-group { + // Selected Object + .search-obj-selected { + border-color: $input-border-color; + } + + // Object Selector Dropdown Button + .dropdown-toggle { + // Generate the same styles as a regular Bootstrap button. + //@include button-variant($input-group-addon-bg, $input-border-color); + margin-left: 0; + font-weight: $input-group-addon-font-weight; + line-height: $input-line-height; + color: $input-group-addon-color; + background-color: $input-group-addon-bg; + border: $input-border-width solid $input-border-color; + @include border-radius($input-border-radius); + border-left: 1px solid var(--nbx-search-filter-border-left-color); + + &:focus { + box-shadow: unset !important; + } + // Don't show the dropdown icon — the filter icon is basically the same thing. + &:after { + display: none; + } + } + + // Object Selector Dropdown Menu + .search-obj-selector { + // Limit the height and enable scrolling on mobile devices. + max-height: 70vh; + overflow-y: auto; + + .dropdown-item, + .dropdown-header { + font-size: $font-size-sm; + } + + .dropdown-header { + text-transform: uppercase; + } + } + } +} + +// Styles for the quicksearch and its clear button; +// Overrides input-group styles and adds transition effects +.quicksearch { + input[type='search'] { + border-radius: $border-radius !important; + } + + button { + margin-left: -32px !important; + z-index: 100 !important; + outline: none !important; + border-radius: $border-radius !important; + transition: visibility 0s, opacity 0.2s linear; + } + + button :hover { + opacity: 50%; + transition: visibility 0s, opacity 0.1s linear; + } +} + +main.layout { + display: flex; + flex-wrap: nowrap; + height: 100vh; + height: -webkit-fill-available; + max-height: 100vh; + overflow-x: auto; + overflow-y: hidden; + + // Override styles when printing. Fixes issue where only the first page is visible when printing. + @media print { + position: static !important; + display: block !important; + height: 100%; + overflow-x: visible !important; + overflow-y: visible !important; + } +} + +main.login-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + max-width: 100vw; + height: calc(100vh - 4rem); + padding-top: 40px; + padding-bottom: 40px; + + + footer.footer button.color-mode-toggle { + color: var(--nbx-color-mode-toggle-color); + } +} + +.footer { + background-color: $tab-content-bg; + padding: 0; + .nav-link { + padding: 0.5rem; + } + + @include media-breakpoint-down(md) { + // Pad the bottom of the footer on mobile devices to account for mobile browser controls. + margin-bottom: 8rem; + } +} + +footer.login-footer { + height: 4rem; + margin-top: auto; + + .container-fluid { + display: flex; + justify-content: flex-end; + padding: $container-padding-x $grid-gutter-width; + } +} + +h1.accordion-item-title, +h2.accordion-item-title, +h3.accordion-item-title, +h4.accordion-item-title, +h5.accordion-item-title, +h6.accordion-item-title { + padding: 0.25rem 0.5rem; + font-size: $font-size-sm; + font-weight: $font-weight-bold; + color: var(--nbx-sidebar-title-color); + text-transform: uppercase; +} + +.form-login { + width: 100%; + max-width: 330px; + padding: 15px; + + input:focus { + z-index: 1; + } + + input[type='text'] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + } + input[type='password'] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + .form-control { + position: relative; + box-sizing: border-box; + height: auto; + padding: 10px; + font-size: 16px; + } +} + +.navbar { + border-bottom: 1px solid $border-color; +} + +.navbar-brand { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + font-size: 1rem; +} + +nav.nav.nav-pills { + .nav-item.nav-link { + padding: 0.25rem 0.5rem; + font-size: $font-size-sm; + border-radius: $border-radius; + + &:hover { + color: $accordion-button-active-color; + background-color: $accordion-button-active-bg; + } + } +} + +// Ensure the content container is full-height, and that the content block is also full height so +// that the footer is always at the bottom. +div.content-container { + position: relative; + display: flex; + flex-direction: column; + width: calc(100% - #{$sidenav-width-closed}); + min-height: 100vh; + overflow-x: hidden; + overflow-y: auto; + + // Don't show an outline when the content container is focused. + &:focus, + &:focus-visible { + outline: 0; + } + + div.content { + background-color: $tab-content-bg; + flex: 1; + } + + @include media-breakpoint-down(lg) { + width: 100%; + } + + // Make the content full-width when printing. + @media print { + width: 100% !important; + margin-left: 0 !important; + } +} + +// Prevent scrolling of body content when nav menu is open on mobile. +.sidebar.collapse.show ~ .content-container > .content { + @media (max-width: map.get($grid-breakpoints, 'md')) { + position: fixed; + top: 0; + left: 0; + overflow-y: hidden; + } +} + +.tooltip { + pointer-events: none; +} + +span.color-label { + display: block; + width: 5rem; + height: 1rem; + padding: $badge-padding-y $badge-padding-x; + border: 1px solid #303030; + border-radius: $border-radius; + box-shadow: $box-shadow-sm; +} + +.badge a { + color: inherit; +} + +.btn { + white-space: nowrap; +} + +.card { + box-shadow: $box-shadow-sm; + + .card-header { + padding: $card-cap-padding-x; + color: var(--nbx-body-color); + border-bottom: none; + } + + .card-header + .card-body { + padding-top: 0; + } + + .card-body.small .form-control, + .card-body.small .form-select { + font-size: $input-font-size-sm; + } + + .card-divider { + width: 100%; + height: 1px; + margin: $hr-margin-y 0; + border-top: 1px solid $card-border-color; + opacity: $hr-opacity; + } + + // Remove shadow when printing. + @media print { + box-shadow: unset !important; + } +} + +.form-floating { + position: relative; + + > .input-group > .form-control, + > .input-group > .form-select { + height: $form-floating-height; + padding: $form-floating-padding-y $form-floating-padding-x; + } + + > .input-group > label { + position: absolute; + top: 0; + left: 0; + height: 100%; // allow textareas + padding: $form-floating-padding-y $form-floating-padding-x; + pointer-events: none; + border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model + transform-origin: 0 0; + @include transition($form-floating-transition); + } + + > .input-group > .form-control { + &::placeholder { + color: transparent; + } + + &:focus, + &:not(:placeholder-shown) { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped + &:-webkit-autofill { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + } + + > .input-group > .form-select, + > .choices > .choices__inner, + > .ss-main span.placeholder, // SlimSelect Single + > .ss-main div.ss-values // SlimSelect Multiple + { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + + > .input-group > .form-control:focus, + > .input-group > .form-control:not(:placeholder-shown), + > .input-group > .form-select, + > .choices, + > .ss-main { + ~ label { + opacity: $form-floating-label-opacity; + transform: $form-floating-label-transform; + z-index: 4; + } + } + // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped + > .input-group > .form-control:-webkit-autofill { + ~ label { + z-index: 4; + opacity: $form-floating-label-opacity; + transform: $form-floating-label-transform; + } + } +} + +.form-object-edit { + margin: 0 auto; + max-width: 800px; +} + +textarea.form-control[rows='10'] { + height: 18rem; +} + +textarea.markdown, +textarea.form-control[name='csv'] { + font-family: $font-family-monospace; +} + +.card:not(:only-of-type) { + margin-bottom: $spacer; +} + +.stat-btn { + min-width: $spacer * 3; +} + +nav.breadcrumb-container { + width: fit-content; + padding: $badge-padding-y $badge-padding-x; + font-size: $font-size-sm; + + ol.breadcrumb { + margin-bottom: 0; + li.breadcrumb-item > a { + text-decoration: none; + } + li.breadcrumb-item > a:hover { + text-decoration: underline; + } + } +} + +label.required { + font-weight: $font-weight-bold; + + &:after { + position: absolute; + display: inline-block; + margin: 0 0 0 2px; + font-family: 'Material Design Icons'; + font-size: 8px; + font-style: normal; + font-weight: $font-weight-medium; + text-decoration: none; + content: '\f06C4'; + } +} + +// Applied to containing element around table bulk-action buttons (bulk-edit, bulk-disconnect +// bulk-delete, etc). Each usage of .bulk-buttons needs to have groups of buttons wrapped with +// .bulk-button-group so that proper spacing is applied (even if there is only one group). +div.bulk-buttons { + display: flex; + justify-content: space-between; + margin: math.div($spacer, 2) 0; + + // Each group of buttons needs to be contained separately for alignment purposes. This way, you + // can put some buttons in a group that aligns left, and other buttons in a group that aligns + // right. + > div.bulk-button-group { + display: flex; + flex-wrap: wrap; + // For small screens: don't fill the available space (thereby expanding the size of the button). + align-items: flex-start; + + &:first-of-type:not(:last-of-type) { + // If there are multiple bulk button groups and this is the first, the first button in the + // group should *not* have left spacing applied, so the button group aligns with the rest + // of the page elements. + > *:first-child { + margin-left: 0; + } + } + + &:last-of-type:not(:first-of-type) { + // If there are multiple bulk button groups and this is the last, the last button in the + // group should *not* have right spacing applied, so the button group aligns with the rest + // of the page elements. + > *:last-child { + margin-right: 0; + } + } + + // However, the rest of the buttons should have spacing applied in all directions. + > * { + margin: math.div($spacer, 4); + } + } +} + +table tbody { + @each $color, $value in $theme-colors { + tr.#{$color} { + background-color: rgba($value, 0.15); + border-color: $gray-500; + } + } +} + +// Style objects with statuses/roles within a table. As of implementation, used for IP addresses +// assigned to interfaces. +table .table-badge-group { + .table-badge { + display: block; + width: min-content; + font-size: $font-size-sm; + font-weight: $font-weight-base; + + &:not(.badge) { + // Apply badge horizontal padding so that IP addresses *not* within a badge appear aligned + // with IP addresses that *are* within a badge. + padding: 0 $badge-padding-x; + } + + &.badge:not(:last-of-type):not(:only-child) { + margin-bottom: map.get($spacers, 1); + } + } +} + +pre.change-data { + padding-right: 0; + padding-left: 0; + + > span { + display: block; + padding-right: $spacer; + padding-left: $spacer; + + &.added { + background-color: var(--nbx-change-added); + } + + &.removed { + background-color: var(--nbx-change-removed); + } + } +} + +pre.change-diff { + border-color: transparent; + + &.change-removed { + background-color: var(--nbx-change-removed); + } + + &.change-added { + background-color: var(--nbx-change-added); + } +} + +div.card-overlay { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + background-color: rgba($white, 0.75); + border-radius: $border-radius; + + > div.spinner-border { + width: 6rem; + height: 6rem; + color: $secondary; + } +} + +.table-controls { + display: flex; + + @include media-breakpoint-up(md) { + // `!important` needed because of inherited margin-bottom from `.col` + margin-top: 0 !important; + margin-bottom: 0 !important; + } + + .table-configure { + justify-content: flex-start; + + @include media-breakpoint-up(md) { + justify-content: flex-end; + } + } + + .form-switch.form-check-inline { + flex: 1 0 auto; + font-size: $font-size-sm; + } +} + +// Tabbed content +.nav-tabs { + background-color: $body-bg; + .nav-link { + &:hover { + // Don't show a bottom-border on a hovered nav link because it overlaps with the .nav-tab border. + border-bottom-color: transparent; + } + &.active { + // Set the background-color of an active tab to the same color as the .tab-content + // background-color so it visually indicates which tab is open. + background-color: $tab-content-bg; + border-bottom-color: $tab-content-bg; + // Move the active tab down 1px to overtake the .nav-tabs element's border, but only for that + // tab. This is an ugly hack, but it works. + transform: translateY(1px); + } + } +} + +.tab-content { + display: flex; + flex-direction: column; + padding: $spacer; +} + +// Override masonry-layout styles when printing. +.masonry { + @media print { + position: static !important; + display: block !important; + height: unset !important; + } + .masonry-item { + @media print { + position: static !important; + top: unset !important; + left: unset !important; + display: block !important; + } + } +} + +// Object hierarchy indicators. +.record-depth { + display: inline; + font-size: $font-size-base; + user-select: none; + opacity: 0.33; + + // Add spacing to the last or only dot. + span:only-of-type, + span:last-of-type { + margin-right: map.get($spacers, 1); + } +} + +// Remove the max-width from image preview popovers as this is controlled on the image element. +.popover.image-preview-popover { + max-width: unset; +} + +/* Rendered Markdown */ +.rendered-markdown table { + width: 100%; +} +.rendered-markdown th { + border-bottom: 2px solid #dddddd; + padding: 8px; +} +.rendered-markdown td { + border-top: 1px solid #dddddd; + padding: 8px; +} + +th[align="left"] { + text-align: left; +} + +th[align="center"] { + text-align: center; +} + +th[align="right"] { + text-align: right; +} + +/* Markdown widget */ +.markdown-widget { + .nav-link { + border-bottom: 0; + + &.active { + background-color: var(--nbx-body-bg); + } + } + + .nav-tabs { + background-color: var(--nbx-pre-bg); + } +} + +// Preformatted text blocks +td pre { + margin-bottom: 0; +} +pre.block { + padding: $spacer; + background-color: var(--nbx-pre-bg); + border: 1px solid var(--nbx-pre-border-color); + border-radius: $border-radius; +} + +#django-messages { + position: fixed; + right: $spacer; + bottom: 0; + margin: $spacer; +} + +// Page-specific styles. +html { + // Shade the home page content background-color. + &[data-netbox-url-name='home'] { + .content-container, + .search { + background-color: $gray-100 !important; + } + &[data-netbox-color-mode='dark'] { + .content-container, + .search { + background-color: $darkest !important; + } + } + } + + // Don't show the django-messages toasts on the login screen in favor of the alert component. + &[data-netbox-url-name='login'] { + #django-messages { + display: none; + } + } +} diff --git a/netbox/project-static/styles/overrides.scss b/netbox/project-static/styles/old/overrides.scss similarity index 100% rename from netbox/project-static/styles/overrides.scss rename to netbox/project-static/styles/old/overrides.scss diff --git a/netbox/project-static/styles/theme-light.scss b/netbox/project-static/styles/old/theme-light.scss similarity index 93% rename from netbox/project-static/styles/theme-light.scss rename to netbox/project-static/styles/old/theme-light.scss index f90843fa3..9b861c3a5 100644 --- a/netbox/project-static/styles/theme-light.scss +++ b/netbox/project-static/styles/old/theme-light.scss @@ -1,6 +1,6 @@ // Base NetBox Theme Overrides and Settings - color mode agnostic. -@import '../node_modules/bootstrap/scss/functions'; +@import '../../node_modules/bootstrap/scss/functions'; $card-cap-bg: 'unset'; @@ -31,8 +31,8 @@ $line-height-lg: 1.75; $darker: #1b1f22; $darkest: #171b1d; -@import '../node_modules/bootstrap/scss/variables'; -@import '../node_modules/bootstrap/scss/variables-dark'; +@import '../../node_modules/bootstrap/scss/variables'; +@import '../../node_modules/bootstrap/scss/variables-dark'; // This is the same value as the default from Bootstrap, but it needs to be in scope prior to // importing _variables.scss from Bootstrap. diff --git a/netbox/project-static/styles/utilities.scss b/netbox/project-static/styles/old/utilities.scss similarity index 100% rename from netbox/project-static/styles/utilities.scss rename to netbox/project-static/styles/old/utilities.scss diff --git a/netbox/project-static/styles/select.scss b/netbox/project-static/styles/overrides/_slim-select.scss similarity index 96% rename from netbox/project-static/styles/select.scss rename to netbox/project-static/styles/overrides/_slim-select.scss index d8fcd218e..419f765cd 100644 --- a/netbox/project-static/styles/select.scss +++ b/netbox/project-static/styles/overrides/_slim-select.scss @@ -184,3 +184,14 @@ $spacing-s: $input-padding-x; } } } + +// Fix slim-select 1.x placeholder styling +.ss-main { + .ss-single-selected { + .placeholder { + cursor: pointer; + opacity: 1; + background-color: transparent !important; + } + } +} diff --git a/netbox/project-static/styles/svg/cable_trace.scss b/netbox/project-static/styles/svg/cable_trace.scss index f184982ce..4a8fdf61a 100644 --- a/netbox/project-static/styles/svg/cable_trace.scss +++ b/netbox/project-static/styles/svg/cable_trace.scss @@ -1,4 +1,4 @@ -@import '../theme-light.scss'; +@import '../old/theme-light'; // Cable Trace Styles. diff --git a/netbox/project-static/styles/svg/rack_elevation.scss b/netbox/project-static/styles/svg/rack_elevation.scss index 0c08f167d..424dd823e 100644 --- a/netbox/project-static/styles/svg/rack_elevation.scss +++ b/netbox/project-static/styles/svg/rack_elevation.scss @@ -1,4 +1,4 @@ -@import '../theme-light.scss'; +@import '../old/theme-light'; // Rack Elevation Styles. diff --git a/netbox/project-static/styles/temp.scss b/netbox/project-static/styles/temp.scss deleted file mode 100644 index 5fa35f649..000000000 --- a/netbox/project-static/styles/temp.scss +++ /dev/null @@ -1,10 +0,0 @@ -// Fix slim-select 1.x placeholder styling -.ss-main { - .ss-single-selected { - .placeholder { - cursor: pointer; - opacity: 1; - background-color: transparent !important; - } - } -} diff --git a/netbox/project-static/styles/transitional/cards.scss b/netbox/project-static/styles/transitional/_cards.scss similarity index 100% rename from netbox/project-static/styles/transitional/cards.scss rename to netbox/project-static/styles/transitional/_cards.scss diff --git a/netbox/project-static/styles/transitional/tables.scss b/netbox/project-static/styles/transitional/_tables.scss similarity index 100% rename from netbox/project-static/styles/transitional/tables.scss rename to netbox/project-static/styles/transitional/_tables.scss