netbox.scss 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. // Netbox-specific Styles and Overrides.
  2. @use 'sass:map';
  3. @use 'sass:math';
  4. @import './sidenav';
  5. @import './overrides';
  6. @import './utilities';
  7. @import './variables';
  8. @each $color, $value in $theme-colors {
  9. // Override CSS values on each theme color.
  10. // Use Bootstrap's method of coloring alert links to appropriately color close buttons within
  11. // another colored element.
  12. // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52
  13. // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_close.scss#L12
  14. $shifted-bg: shift-color($value, $alert-bg-scale);
  15. $shifted-color: shift-color($value, $alert-color-scale);
  16. @if (contrast-ratio($shifted-bg, $shifted-color) < $min-contrast-ratio) {
  17. $shifted-color: mix($value, color-contrast($shifted-bg), abs($alert-color-scale));
  18. }
  19. $btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$shifted-color}'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
  20. .bg-#{$color} button.btn-close {
  21. background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat;
  22. }
  23. .btn.btn-ghost-#{$color} {
  24. color: $value;
  25. &:hover {
  26. background-color: rgba($value, 0.12);
  27. }
  28. }
  29. // Use Bootstrap's method of coloring the .alert-link class automatically.
  30. // See: https://github.com/twbs/bootstrap/blob/2bdbb42dcf6bfb99b5e9e5444d9e64589eb8c08f/scss/_alert.scss#L50-L52
  31. .alert.alert-#{$color},
  32. .table-#{$color} {
  33. // Exclude buttons.
  34. a:not(.btn) {
  35. font-weight: $font-weight-bold;
  36. color: $shifted-color;
  37. }
  38. // Apply a border to buttons contained within colored elements, if they're not already a
  39. // bordered button class.
  40. .btn:not([class*='btn-outline']) {
  41. border-color: $gray-700;
  42. }
  43. }
  44. // Toasts required a slightly different approach because the background color isn't "shifted",
  45. // it's the direct theme color.
  46. .toast.bg-#{$color} {
  47. $shifted-color: shift-color($value, $alert-color-scale);
  48. @if (contrast-ratio($value, $shifted-color) < $min-contrast-ratio) {
  49. $shifted-color: mix($value, color-contrast($value), abs($alert-color-scale));
  50. }
  51. a:not(.btn) {
  52. font-weight: $font-weight-bold;
  53. color: $shifted-color;
  54. }
  55. }
  56. // Use proper contrasting color foreground color for special components.
  57. .badge,
  58. .toast,
  59. .toast-header,
  60. .progress-bar {
  61. &.bg-#{$color} {
  62. color: color-contrast($value);
  63. }
  64. }
  65. }
  66. // Ensure progress bars (utilization graph) in tables aren't too narrow to display the percentage.
  67. table td > .progress {
  68. min-width: 6rem;
  69. }
  70. // Override Bootstrap form-control font-size when contained by .small element.
  71. .small .form-control {
  72. font-size: $font-size-sm;
  73. }
  74. // Automatically space out adjacent columns, but not within card bodies.
  75. :not(.card-body) > .col:not(:last-child):not(:only-child) {
  76. margin-bottom: $spacer;
  77. }
  78. .nav-mobile {
  79. display: none;
  80. flex-direction: column;
  81. align-items: center;
  82. justify-content: space-between;
  83. width: 100%;
  84. @include media-breakpoint-down(lg) {
  85. display: flex;
  86. }
  87. .nav-mobile-top {
  88. display: flex;
  89. align-items: center;
  90. justify-content: space-between;
  91. width: 100%;
  92. }
  93. }
  94. .card > .table.table-flush {
  95. margin-bottom: 0;
  96. overflow: hidden;
  97. border-bottom-right-radius: $card-border-radius;
  98. border-bottom-left-radius: $card-border-radius;
  99. thead th[scope='col'] {
  100. padding-top: map.get($spacers, 3);
  101. padding-bottom: map.get($spacers, 3);
  102. text-transform: uppercase;
  103. vertical-align: middle;
  104. background-color: $table-flush-header-bg;
  105. border-top: 1px solid $card-border-color;
  106. border-bottom-color: $card-border-color;
  107. }
  108. th,
  109. td {
  110. padding-right: map.get($spacers, 4) !important;
  111. padding-left: map.get($spacers, 4) !important;
  112. border-right: 0;
  113. border-left: 0;
  114. }
  115. tr[class] {
  116. border-color: $card-border-color !important;
  117. &:last-of-type {
  118. border-bottom-color: transparent !important;
  119. border-bottom-right-radius: $card-border-radius;
  120. border-bottom-left-radius: $card-border-radius;
  121. }
  122. }
  123. }
  124. // Primarily used for the new release notification, but could be used for other alerts as needed.
  125. // Wrap any alerts in .header-alert-container to ensure the layout is consistent.
  126. .header-alert-container {
  127. // Center-align the alert(s).
  128. display: flex;
  129. align-items: center;
  130. justify-content: center;
  131. // Apply the same spacing that's applied to the #content div's first child (.px-3).
  132. padding: 0 $spacer;
  133. // By default, alerts inside .header-alert-container should take up the full width.
  134. .alert {
  135. width: 100%;
  136. // Adjust the max-width for larger screens so there's not a big ugly blue blob taking up the
  137. // entire screen.
  138. @include media-breakpoint-up(md) {
  139. max-width: 75%;
  140. }
  141. @include media-breakpoint-up(lg) {
  142. max-width: 50%;
  143. }
  144. }
  145. }
  146. span.profile-button .dropdown-menu {
  147. right: 0;
  148. left: auto;
  149. display: block !important;
  150. margin-top: 0.5rem;
  151. box-shadow: $box-shadow;
  152. transition: opacity 0.2s ease-in-out;
  153. &:not(.show) {
  154. pointer-events: none;
  155. opacity: 0;
  156. }
  157. &.show {
  158. pointer-events: auto;
  159. opacity: 1;
  160. }
  161. }
  162. div#advanced-search-content div.card div.card-body div.col:not(:last-child) {
  163. margin-right: 1rem;
  164. }
  165. table {
  166. td {
  167. a {
  168. text-decoration: none;
  169. &:hover {
  170. text-decoration: underline;
  171. }
  172. }
  173. .dropdown {
  174. // Presence of 'overflow: scroll' on a table causes dropdowns to be improperly hidden when
  175. // opened. See: https://github.com/twbs/bootstrap/issues/24251
  176. position: static;
  177. }
  178. }
  179. th {
  180. a,
  181. a:hover {
  182. color: $body-color;
  183. text-decoration: none;
  184. }
  185. }
  186. td,
  187. th {
  188. font-size: $font-size-sm;
  189. line-height: $line-height-sm;
  190. vertical-align: middle;
  191. &.min-width {
  192. width: 1%;
  193. }
  194. .form-check-input {
  195. // Ensure checkboxes aren't too small inside object tables.
  196. margin-top: 0.125em;
  197. font-size: $font-size-base;
  198. }
  199. .btn-sm {
  200. line-height: $line-height-xs;
  201. }
  202. p {
  203. // Remove spacing from paragraph elements within tables.
  204. margin-bottom: 0;
  205. }
  206. }
  207. th.asc a::after {
  208. content: "\f0140";
  209. font-family: 'Material Design Icons';
  210. }
  211. th.desc a::after {
  212. content: "\f0143";
  213. font-family: 'Material Design Icons';
  214. }
  215. &.table > :not(caption) > * > * {
  216. padding-right: $table-cell-padding-x-sm !important;
  217. padding-left: $table-cell-padding-x-sm !important;
  218. }
  219. &.object-list {
  220. th {
  221. font-size: $font-size-xs;
  222. line-height: $line-height-xs;
  223. vertical-align: bottom;
  224. }
  225. }
  226. &.attr-table {
  227. th {
  228. font-weight: normal;
  229. width: 25%;
  230. }
  231. }
  232. }
  233. div.title-container {
  234. display: flex;
  235. // On small screens, `flex-direction: column;` ensures the control buttons don't appear on the
  236. // same line as the title, but rather break to the next line.
  237. flex-direction: column;
  238. flex-wrap: wrap;
  239. justify-content: space-between;
  240. @include media-breakpoint-up(lg) {
  241. // On large screens, `flex-direction: row;` allows the control buttons to appear vertically
  242. // aligned with the title.
  243. flex-direction: row;
  244. }
  245. #content-title {
  246. display: flex;
  247. flex: 1 0;
  248. flex-direction: column;
  249. padding-bottom: map.get($spacers, 2);
  250. }
  251. }
  252. // Object list control buttons (Add/Clone/Import/Export)
  253. .controls {
  254. margin-bottom: map.get($spacers, 2);
  255. @media print {
  256. // Never print controls. Use this over the .noprint utility so plugin authors don't need to
  257. // remember to add the class.
  258. display: none !important;
  259. }
  260. // Each group of buttons.
  261. .control-group {
  262. display: flex;
  263. flex-wrap: wrap;
  264. // Left-align controls on mobile.
  265. justify-content: flex-start;
  266. // Right-align controls on larger screens.
  267. @include media-breakpoint-up(lg) {
  268. justify-content: flex-end;
  269. }
  270. > * {
  271. // Pad each control button.
  272. margin: map.get($spacers, 1);
  273. &:first-child {
  274. // Don't pad the left side of the first control button.
  275. margin-left: 0;
  276. }
  277. &:last-child {
  278. // Don't pad the right side of the last control button.
  279. margin-right: 0;
  280. }
  281. }
  282. }
  283. }
  284. .object-subtitle {
  285. display: block;
  286. font-size: $font-size-sm;
  287. color: $text-muted;
  288. @include media-breakpoint-up(md) {
  289. display: inline-block;
  290. }
  291. > span {
  292. display: block;
  293. // Hide the separator on small screens.
  294. &.separator {
  295. display: none;
  296. }
  297. &,
  298. &.separator {
  299. @include media-breakpoint-up(md) {
  300. display: inline-block;
  301. }
  302. }
  303. }
  304. }
  305. // Global Search
  306. nav.search {
  307. // Don't overtake dropdowns
  308. z-index: 999;
  309. justify-content: center;
  310. background-color: var(--nbx-body-bg);
  311. .search-container {
  312. display: flex;
  313. width: 100%;
  314. @include media-breakpoint-down(lg) {
  315. display: none;
  316. }
  317. }
  318. // Search Input & Selected Object Value & Object Selector
  319. .input-group {
  320. // Selected Object
  321. .search-obj-selected {
  322. border-color: $input-border-color;
  323. }
  324. // Object Selector Dropdown Button
  325. .dropdown-toggle {
  326. // Generate the same styles as a regular Bootstrap button.
  327. @include button-variant($input-group-addon-bg, $input-border-color);
  328. margin-left: 0;
  329. font-weight: $input-group-addon-font-weight;
  330. line-height: $input-line-height;
  331. color: $input-group-addon-color;
  332. background-color: $input-group-addon-bg;
  333. border: $input-border-width solid $input-border-color;
  334. @include border-radius($input-border-radius);
  335. border-left: 1px solid var(--nbx-search-filter-border-left-color);
  336. &:focus {
  337. box-shadow: unset !important;
  338. }
  339. // Don't show the dropdown icon — the filter icon is basically the same thing.
  340. &:after {
  341. display: none;
  342. }
  343. }
  344. // Object Selector Dropdown Menu
  345. .search-obj-selector {
  346. // Limit the height and enable scrolling on mobile devices.
  347. max-height: 70vh;
  348. overflow-y: auto;
  349. .dropdown-item,
  350. .dropdown-header {
  351. font-size: $font-size-sm;
  352. }
  353. .dropdown-header {
  354. text-transform: uppercase;
  355. }
  356. }
  357. }
  358. }
  359. main.layout {
  360. display: flex;
  361. flex-wrap: nowrap;
  362. height: 100vh;
  363. height: -webkit-fill-available;
  364. max-height: 100vh;
  365. overflow-x: auto;
  366. overflow-y: hidden;
  367. // Override styles when printing. Fixes issue where only the first page is visible when printing.
  368. @media print {
  369. position: static !important;
  370. display: block !important;
  371. height: 100%;
  372. overflow-x: visible !important;
  373. overflow-y: visible !important;
  374. }
  375. }
  376. main.login-container {
  377. display: flex;
  378. flex-direction: column;
  379. align-items: center;
  380. justify-content: center;
  381. width: 100%;
  382. max-width: 100vw;
  383. height: calc(100vh - 4rem);
  384. padding-top: 40px;
  385. padding-bottom: 40px;
  386. + footer.footer button.color-mode-toggle {
  387. color: var(--nbx-color-mode-toggle-color);
  388. }
  389. }
  390. .footer {
  391. padding: 0;
  392. .nav-link {
  393. padding: 0.5rem;
  394. }
  395. @include media-breakpoint-down(md) {
  396. // Pad the bottom of the footer on mobile devices to account for mobile browser controls.
  397. margin-bottom: 8rem;
  398. }
  399. }
  400. footer.login-footer {
  401. height: 4rem;
  402. margin-top: auto;
  403. .container-fluid {
  404. display: flex;
  405. justify-content: flex-end;
  406. padding: $container-padding-x $grid-gutter-width;
  407. }
  408. }
  409. h1.accordion-item-title,
  410. h2.accordion-item-title,
  411. h3.accordion-item-title,
  412. h4.accordion-item-title,
  413. h5.accordion-item-title,
  414. h6.accordion-item-title {
  415. padding: 0.25rem 0.5rem;
  416. font-size: $font-size-sm;
  417. font-weight: $font-weight-bold;
  418. color: var(--nbx-sidebar-title-color);
  419. text-transform: uppercase;
  420. }
  421. .form-login {
  422. width: 100%;
  423. max-width: 330px;
  424. padding: 15px;
  425. input:focus {
  426. z-index: 1;
  427. }
  428. input[type='text'] {
  429. margin-bottom: -1px;
  430. border-bottom-right-radius: 0;
  431. border-bottom-left-radius: 0;
  432. }
  433. input[type='password'] {
  434. margin-bottom: 10px;
  435. border-top-left-radius: 0;
  436. border-top-right-radius: 0;
  437. }
  438. .form-control {
  439. position: relative;
  440. box-sizing: border-box;
  441. height: auto;
  442. padding: 10px;
  443. font-size: 16px;
  444. }
  445. }
  446. .navbar-brand {
  447. padding-top: 0.75rem;
  448. padding-bottom: 0.75rem;
  449. font-size: 1rem;
  450. }
  451. nav.nav.nav-pills {
  452. .nav-item.nav-link {
  453. padding: 0.25rem 0.5rem;
  454. font-size: $font-size-sm;
  455. border-radius: $border-radius;
  456. &:hover {
  457. color: $accordion-button-active-color;
  458. background-color: $accordion-button-active-bg;
  459. }
  460. }
  461. }
  462. // Ensure the content container is full-height, and that the content block is also full height so
  463. // that the footer is always at the bottom.
  464. div.content-container {
  465. position: relative;
  466. display: flex;
  467. flex-direction: column;
  468. width: calc(100% - #{$sidenav-width-closed});
  469. min-height: 100vh;
  470. overflow-x: hidden;
  471. overflow-y: auto;
  472. // Don't show an outline when the content container is focused.
  473. &:focus,
  474. &:focus-visible {
  475. outline: 0;
  476. }
  477. div.content {
  478. flex: 1;
  479. }
  480. @include media-breakpoint-down(lg) {
  481. width: 100%;
  482. }
  483. // Make the content full-width when printing.
  484. @media print {
  485. width: 100% !important;
  486. margin-left: 0 !important;
  487. }
  488. }
  489. // Prevent scrolling of body content when nav menu is open on mobile.
  490. .sidebar.collapse.show ~ .content-container > .content {
  491. @media (max-width: map.get($grid-breakpoints, 'md')) {
  492. position: fixed;
  493. top: 0;
  494. left: 0;
  495. overflow-y: hidden;
  496. }
  497. }
  498. .tooltip {
  499. pointer-events: none;
  500. }
  501. span.color-label {
  502. display: block;
  503. width: 5rem;
  504. height: 1rem;
  505. padding: $badge-padding-y $badge-padding-x;
  506. border: 1px solid #303030;
  507. border-radius: $border-radius;
  508. box-shadow: $box-shadow-sm;
  509. }
  510. .btn {
  511. white-space: nowrap;
  512. }
  513. .card {
  514. box-shadow: $box-shadow-sm;
  515. .card-header {
  516. padding: $card-cap-padding-x;
  517. color: var(--nbx-body-color);
  518. border-bottom: none;
  519. }
  520. .card-header + .card-body {
  521. padding-top: 0;
  522. }
  523. .card-body.small .form-control,
  524. .card-body.small .form-select {
  525. font-size: $input-font-size-sm;
  526. }
  527. .card-divider {
  528. width: 100%;
  529. height: 1px;
  530. margin: $hr-margin-y 0;
  531. border-top: 1px solid $card-border-color;
  532. opacity: $hr-opacity;
  533. }
  534. // Remove shadow when printing.
  535. @media print {
  536. box-shadow: unset !important;
  537. }
  538. }
  539. .form-floating {
  540. position: relative;
  541. > .input-group > .form-control,
  542. > .input-group > .form-select {
  543. height: $form-floating-height;
  544. padding: $form-floating-padding-y $form-floating-padding-x;
  545. }
  546. > .input-group > label {
  547. position: absolute;
  548. top: 0;
  549. left: 0;
  550. height: 100%; // allow textareas
  551. padding: $form-floating-padding-y $form-floating-padding-x;
  552. pointer-events: none;
  553. border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model
  554. transform-origin: 0 0;
  555. @include transition($form-floating-transition);
  556. }
  557. > .input-group > .form-control {
  558. &::placeholder {
  559. color: transparent;
  560. }
  561. &:focus,
  562. &:not(:placeholder-shown) {
  563. padding-top: $form-floating-input-padding-t;
  564. padding-bottom: $form-floating-input-padding-b;
  565. }
  566. // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
  567. &:-webkit-autofill {
  568. padding-top: $form-floating-input-padding-t;
  569. padding-bottom: $form-floating-input-padding-b;
  570. }
  571. }
  572. > .input-group > .form-select,
  573. > .choices > .choices__inner,
  574. > .ss-main span.placeholder, // SlimSelect Single
  575. > .ss-main div.ss-values // SlimSelect Multiple
  576. {
  577. padding-top: $form-floating-input-padding-t;
  578. padding-bottom: $form-floating-input-padding-b;
  579. }
  580. > .input-group > .form-control:focus,
  581. > .input-group > .form-control:not(:placeholder-shown),
  582. > .input-group > .form-select,
  583. > .choices,
  584. > .ss-main {
  585. ~ label {
  586. opacity: $form-floating-label-opacity;
  587. transform: $form-floating-label-transform;
  588. z-index: 4;
  589. }
  590. }
  591. // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
  592. > .input-group > .form-control:-webkit-autofill {
  593. ~ label {
  594. z-index: 4;
  595. opacity: $form-floating-label-opacity;
  596. transform: $form-floating-label-transform;
  597. }
  598. }
  599. }
  600. .form-object-edit {
  601. margin: 0 auto;
  602. max-width: 800px;
  603. }
  604. textarea.form-control[rows='10'] {
  605. height: 18rem;
  606. }
  607. textarea#id_local_context_data,
  608. textarea.markdown,
  609. textarea#id_public_key,
  610. textarea.form-control[name='csv'],
  611. textarea.form-control[name='data'] {
  612. font-family: $font-family-monospace;
  613. }
  614. .card:not(:only-of-type) {
  615. margin-bottom: $spacer;
  616. }
  617. .stat-btn {
  618. min-width: $spacer * 3;
  619. }
  620. nav.breadcrumb-container {
  621. width: fit-content;
  622. padding: $badge-padding-y $badge-padding-x;
  623. font-size: $font-size-sm;
  624. ol.breadcrumb {
  625. margin-bottom: 0;
  626. li.breadcrumb-item > a {
  627. text-decoration: none;
  628. }
  629. li.breadcrumb-item > a:hover {
  630. text-decoration: underline;
  631. }
  632. }
  633. }
  634. label.required {
  635. font-weight: $font-weight-bold;
  636. &:after {
  637. position: absolute;
  638. display: inline-block;
  639. margin: 0 0 0 2px;
  640. font-family: 'Material Design Icons';
  641. font-size: 8px;
  642. font-style: normal;
  643. font-weight: $font-weight-medium;
  644. text-decoration: none;
  645. content: '\f06C4';
  646. }
  647. }
  648. // Applied to containing element around table bulk-action buttons (bulk-edit, bulk-disconnect
  649. // bulk-delete, etc). Each usage of .bulk-buttons needs to have groups of buttons wrapped with
  650. // .bulk-button-group so that proper spacing is applied (even if there is only one group).
  651. div.bulk-buttons {
  652. display: flex;
  653. justify-content: space-between;
  654. margin: math.div($spacer, 2) 0;
  655. // Each group of buttons needs to be contained separately for alignment purposes. This way, you
  656. // can put some buttons in a group that aligns left, and other buttons in a group that aligns
  657. // right.
  658. > div.bulk-button-group {
  659. display: flex;
  660. flex-wrap: wrap;
  661. // For small screens: don't fill the available space (thereby expanding the size of the button).
  662. align-items: flex-start;
  663. &:first-of-type:not(:last-of-type) {
  664. // If there are multiple bulk button groups and this is the first, the first button in the
  665. // group should *not* have left spacing applied, so the button group aligns with the rest
  666. // of the page elements.
  667. > *:first-child {
  668. margin-left: 0;
  669. }
  670. }
  671. &:last-of-type:not(:first-of-type) {
  672. // If there are multiple bulk button groups and this is the last, the last button in the
  673. // group should *not* have right spacing applied, so the button group aligns with the rest
  674. // of the page elements.
  675. > *:last-child {
  676. margin-right: 0;
  677. }
  678. }
  679. // However, the rest of the buttons should have spacing applied in all directions.
  680. > * {
  681. margin: math.div($spacer, 4);
  682. }
  683. }
  684. }
  685. table tbody {
  686. @each $color, $value in $theme-colors {
  687. tr.#{$color} {
  688. background-color: rgba($value, 0.15);
  689. border-color: $gray-500;
  690. }
  691. }
  692. }
  693. // Style objects with statuses/roles within a table. As of implementation, used for IP addresses
  694. // assigned to interfaces.
  695. table .table-badge-group {
  696. .table-badge {
  697. display: block;
  698. width: min-content;
  699. font-size: $font-size-sm;
  700. font-weight: $font-weight-base;
  701. &:not(.badge) {
  702. // Apply badge horizontal padding so that IP addresses *not* within a badge appear aligned
  703. // with IP addresses that *are* within a badge.
  704. padding: 0 $badge-padding-x;
  705. }
  706. &.badge:not(:last-of-type):not(:only-child) {
  707. margin-bottom: map.get($spacers, 1);
  708. }
  709. }
  710. }
  711. pre.change-data {
  712. padding-right: 0;
  713. padding-left: 0;
  714. > span {
  715. display: block;
  716. padding-right: $spacer;
  717. padding-left: $spacer;
  718. &.added {
  719. background-color: var(--nbx-change-added);
  720. }
  721. &.removed {
  722. background-color: var(--nbx-change-removed);
  723. }
  724. }
  725. }
  726. pre.change-diff {
  727. border-color: transparent;
  728. &.change-removed {
  729. background-color: var(--nbx-change-removed);
  730. }
  731. &.change-added {
  732. background-color: var(--nbx-change-added);
  733. }
  734. }
  735. div.card-overlay {
  736. position: absolute;
  737. display: flex;
  738. align-items: center;
  739. justify-content: center;
  740. width: 100%;
  741. height: 100%;
  742. background-color: rgba($white, 0.75);
  743. border-radius: $border-radius;
  744. > div.spinner-border {
  745. width: 6rem;
  746. height: 6rem;
  747. color: $secondary;
  748. }
  749. }
  750. .table-controls {
  751. display: flex;
  752. @include media-breakpoint-up(md) {
  753. // `!important` needed because of inherited margin-bottom from `.col`
  754. margin-top: 0 !important;
  755. margin-bottom: 0 !important;
  756. }
  757. .table-configure {
  758. justify-content: flex-start;
  759. @include media-breakpoint-up(md) {
  760. justify-content: flex-end;
  761. }
  762. }
  763. .form-switch.form-check-inline {
  764. flex: 1 0 auto;
  765. font-size: $font-size-sm;
  766. }
  767. }
  768. // Tabbed content
  769. .nav-tabs {
  770. .nav-link {
  771. &:hover {
  772. // Don't show a bottom-border on a hovered nav link because it overlaps with the .nav-tab border.
  773. border-bottom-color: transparent;
  774. }
  775. &.active {
  776. // Set the background-color of an active tab to the same color as the .tab-content
  777. // background-color so it visually indicates which tab is open.
  778. background-color: $tab-content-bg;
  779. border-bottom-color: $tab-content-bg;
  780. // Move the active tab down 1px to overtake the .nav-tabs element's border, but only for that
  781. // tab. This is an ugly hack, but it works.
  782. transform: translateY(1px);
  783. }
  784. }
  785. }
  786. .tab-content {
  787. display: flex;
  788. flex-direction: column;
  789. padding: $spacer;
  790. background-color: $tab-content-bg;
  791. border-bottom: 1px solid $nav-tabs-border-color;
  792. // Remove background and border when printing.
  793. @media print {
  794. background-color: var(--nbx-body-bg) !important;
  795. border-bottom: none !important;
  796. }
  797. }
  798. // Override masonry-layout styles when printing.
  799. .masonry {
  800. @media print {
  801. position: static !important;
  802. display: block !important;
  803. height: unset !important;
  804. }
  805. .masonry-item {
  806. @media print {
  807. position: static !important;
  808. top: unset !important;
  809. left: unset !important;
  810. display: block !important;
  811. }
  812. }
  813. }
  814. // Object hierarchy indicators.
  815. .record-depth {
  816. display: inline;
  817. font-size: $font-size-base;
  818. user-select: none;
  819. opacity: 0.33;
  820. // Add spacing to the last or only dot.
  821. span:only-of-type,
  822. span:last-of-type {
  823. margin-right: map.get($spacers, 1);
  824. }
  825. }
  826. // Remove the max-width from image preview popovers as this is controlled on the image element.
  827. .popover.image-preview-popover {
  828. max-width: unset;
  829. }
  830. // Preformatted text blocks
  831. td pre {
  832. margin-bottom: 0
  833. }
  834. pre.block {
  835. padding: $spacer;
  836. background-color: var(--nbx-pre-bg);
  837. border: 1px solid var(--nbx-pre-border-color);
  838. border-radius: $border-radius;
  839. }
  840. #django-messages {
  841. position: fixed;
  842. right: $spacer;
  843. bottom: 0;
  844. margin: $spacer;
  845. }
  846. // Page-specific styles.
  847. html {
  848. // Shade the home page content background-color.
  849. &[data-netbox-url-name='home'] {
  850. .content-container,
  851. .search {
  852. background-color: $gray-100 !important;
  853. }
  854. &[data-netbox-color-mode='dark'] {
  855. .content-container,
  856. .search {
  857. background-color: $darkest !important;
  858. }
  859. }
  860. }
  861. // Don't show the django-messages toasts on the login screen in favor of the alert component.
  862. &[data-netbox-url-name='login'] {
  863. #django-messages {
  864. display: none;
  865. }
  866. }
  867. }