netbox.scss 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. // Netbox-specific Styles and Overrides.
  2. @use 'sass:map';
  3. :root {
  4. --nbx-logo-color-1: #9cc8f8;
  5. --nbx-logo-color-2: #1685fc;
  6. --nbx-sidebar-bg: #{$gray-100};
  7. --nbx-sidebar-link-color: #{$gray-800};
  8. --nbx-sidebar-link-hover-bg: #{$blue-100};
  9. --nbx-sidebar-title-color: #{$text-muted};
  10. --nbx-breadcrumb-bg: #{$light};
  11. --nbx-body-bg: #{$white};
  12. --nbx-body-color: #{$gray-800};
  13. --nbx-pre-bg: #{$gray-100};
  14. --nbx-pre-border-color: #{$gray-600};
  15. --nbx-change-added: #{rgba($green, 0.4)};
  16. --nbx-change-removed: #{rgba($red, 0.4)};
  17. --nbx-cable-node-bg: #{$gray-100};
  18. --nbx-cable-node-border-color: #{$gray-200};
  19. --nbx-cable-termination-bg: #{$gray-200};
  20. --nbx-cable-termination-border-color: #{$gray-300};
  21. --nbx-search-filter-border-left-color: #{$gray-300};
  22. --nbx-color-mode-toggle-color: #{$primary};
  23. --nbx-stat-badge-bg: #{$gray-600};
  24. body[data-netbox-color-mode='dark'] {
  25. --nbx-logo-color-1: #{$white};
  26. --nbx-logo-color-2: #{$gray-200};
  27. --nbx-sidebar-bg: #{$gray-800};
  28. --nbx-sidebar-link-color: #{$gray-200};
  29. --nbx-sidebar-link-hover-bg: #{rgba($blue-300, 0.15)};
  30. --nbx-sidebar-title-color: #{$gray-300};
  31. --nbx-breadcrumb-bg: #{$gray-800};
  32. --nbx-body-bg: #{$gray-900};
  33. --nbx-body-color: #{$gray-50};
  34. --nbx-pre-bg: #{$gray-700};
  35. --nbx-pre-border-color: #{$gray-600};
  36. --nbx-change-added: #{rgba($green-300, 0.4)};
  37. --nbx-change-removed: #{rgba($red-300, 0.4)};
  38. --nbx-cable-node-bg: #{$gray-700};
  39. --nbx-cable-node-border-color: #{$gray-600};
  40. --nbx-cable-termination-bg: #{$gray-800};
  41. --nbx-cable-termination-border-color: #{$gray-700};
  42. --nbx-search-filter-border-left-color: #{$gray-600};
  43. --nbx-color-mode-toggle-color: #{$yellow-300};
  44. --nbx-stat-badge-bg: #{$gray-600};
  45. }
  46. }
  47. * {
  48. transition: background-color, color 0.15s ease-in-out;
  49. }
  50. .text-xs {
  51. font-size: $font-size-xs;
  52. line-height: $line-height-sm;
  53. }
  54. // Automatically space out adjacent columns.
  55. .col:not(:last-child):not(:only-child) {
  56. margin-bottom: $spacer;
  57. }
  58. // Use proper contrasting color for badge & progress-bar foreground color.
  59. @each $color, $value in $theme-colors {
  60. .badge,
  61. .toast,
  62. .progress-bar {
  63. &.bg-#{$color} {
  64. color: color-contrast($value);
  65. }
  66. }
  67. }
  68. // Ensure progress bars (utilization graph) in tables aren't too narrow to display the percentage.
  69. table td > .progress {
  70. min-width: 6rem;
  71. }
  72. div#advanced-search-content div.card div.card-body div.col:not(:last-child) {
  73. margin-right: 1rem;
  74. }
  75. body {
  76. background-color: var(--nbx-body-bg);
  77. color: var(--nbx-body-color);
  78. g#netbox-logo-1 {
  79. fill: #9cc8f8;
  80. stroke: #9cc8f8;
  81. }
  82. g#netbox-logo-2 {
  83. fill: #1685fc;
  84. stroke: #1685fc;
  85. }
  86. span.badge.stat-badge {
  87. margin-left: map.get($spacers, 2);
  88. background-color: var(--nbx-stat-badge-bg);
  89. }
  90. &[data-netbox-color-mode='light'] {
  91. .btn.btn-primary,
  92. .progress-bar.bg-primary,
  93. .badge.bg-primary,
  94. .nav.nav-pills .nav-item .nav-link.active,
  95. .nav.nav-pills .nav-item .show > .nav-link {
  96. color: $gray-50;
  97. }
  98. }
  99. &[data-netbox-color-mode='dark'] {
  100. .btn.btn-primary,
  101. .progress-bar.bg-primary,
  102. .badge.bg-primary,
  103. .nav.nav-pills .nav-item .nav-link.active,
  104. .nav.nav-pills .nav-item .show > .nav-link {
  105. color: $black;
  106. }
  107. }
  108. &[data-netbox-color-mode='dark'] {
  109. a:not(.btn) {
  110. color: $blue-300;
  111. }
  112. .breadcrumb .breadcrumb-item > a {
  113. color: $blue-300;
  114. }
  115. .badge {
  116. color: $black;
  117. }
  118. .card,
  119. .sidebar {
  120. .text-muted {
  121. color: $gray-400 !important;
  122. }
  123. }
  124. .text-body[class] {
  125. color: var(--nbx-body-color) !important;
  126. }
  127. g#netbox-logo-1 {
  128. fill: $white;
  129. stroke: $white;
  130. }
  131. g#netbox-logo-2 {
  132. fill: $gray-200;
  133. stroke: $gray-200;
  134. }
  135. }
  136. & table,
  137. &[data-netbox-color-mode] table {
  138. a {
  139. text-decoration: none;
  140. &:hover {
  141. text-decoration: underline;
  142. }
  143. }
  144. &.table > :not(caption) > * > * {
  145. padding-left: $table-cell-padding-x-sm !important;
  146. padding-right: $table-cell-padding-x-sm !important;
  147. }
  148. td,
  149. th {
  150. font-size: $font-size-xs;
  151. line-height: $line-height-sm;
  152. vertical-align: middle;
  153. & input.form-check-input {
  154. // Ensure checkboxes aren't too small inside object tables.
  155. font-size: $font-size-base;
  156. }
  157. }
  158. &.attr-table {
  159. td,
  160. th {
  161. font-size: $font-size-sm;
  162. line-height: $line-height-sm;
  163. }
  164. }
  165. }
  166. }
  167. div.title-container {
  168. display: flex;
  169. justify-content: space-between;
  170. flex-wrap: wrap;
  171. align-items: center;
  172. div#content-title {
  173. display: flex;
  174. flex-direction: column;
  175. flex: 1 0 auto;
  176. padding-bottom: map.get($spacers, 2);
  177. }
  178. }
  179. nav.search {
  180. background-color: var(--nbx-body-bg);
  181. form button.dropdown-toggle {
  182. border-color: $input-border-color;
  183. font-weight: $input-group-addon-font-weight;
  184. line-height: $input-line-height;
  185. color: $input-group-addon-color;
  186. background-color: $input-group-addon-bg;
  187. border: $input-border-width solid $input-group-addon-border-color;
  188. @include border-radius($input-border-radius);
  189. border-left: 1px solid var(--nbx-search-filter-border-left-color);
  190. &:focus {
  191. box-shadow: unset !important;
  192. }
  193. }
  194. }
  195. main.login-container {
  196. display: flex;
  197. height: calc(100vh - 4rem);
  198. width: 100%;
  199. max-width: 100vw;
  200. align-items: center;
  201. justify-content: center;
  202. flex-direction: column;
  203. padding-top: 40px;
  204. padding-bottom: 40px;
  205. & + footer.footer button.color-mode-toggle {
  206. color: var(--nbx-color-mode-toggle-color);
  207. }
  208. }
  209. footer.login-footer {
  210. height: 4rem;
  211. margin-top: auto;
  212. .container-fluid {
  213. display: flex;
  214. justify-content: flex-end;
  215. padding: $container-padding-x $grid-gutter-width;
  216. }
  217. }
  218. h1 {
  219. font-weight: $font-weight-bolder;
  220. }
  221. h2 {
  222. font-weight: $font-weight-bold;
  223. }
  224. h3,
  225. h4 {
  226. font-weight: $font-weight-medium;
  227. }
  228. h5,
  229. h6 {
  230. font-weight: $font-weight-medium;
  231. }
  232. h1.accordion-item-title,
  233. h2.accordion-item-title,
  234. h3.accordion-item-title,
  235. h4.accordion-item-title,
  236. h5.accordion-item-title,
  237. h6.accordion-item-title {
  238. // padding: 0 0.5rem;
  239. padding: 0.25rem 0.5rem;
  240. font-weight: $font-weight-bold;
  241. text-transform: uppercase;
  242. color: var(--nbx-sidebar-title-color);
  243. font-size: $font-size-sm;
  244. }
  245. .form-login {
  246. width: 100%;
  247. max-width: 330px;
  248. padding: 15px;
  249. & input:focus {
  250. z-index: 1;
  251. }
  252. }
  253. .form-login input[type='text'] {
  254. margin-bottom: -1px;
  255. border-bottom-left-radius: 0;
  256. border-bottom-right-radius: 0;
  257. }
  258. .form-login input[type='password'] {
  259. margin-bottom: 10px;
  260. border-top-left-radius: 0;
  261. border-top-right-radius: 0;
  262. }
  263. .form-login .form-control {
  264. position: relative;
  265. box-sizing: border-box;
  266. height: auto;
  267. padding: 10px;
  268. font-size: 16px;
  269. }
  270. li.dropdown-item.dropdown-item-btns {
  271. display: flex;
  272. justify-content: space-between;
  273. align-items: center;
  274. }
  275. .sidebar-sticky {
  276. position: relative;
  277. top: 0;
  278. height: calc(100vh - 48px);
  279. padding-top: 0.5rem;
  280. overflow-x: hidden;
  281. overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
  282. }
  283. .navbar-brand {
  284. padding-top: 0.75rem;
  285. padding-bottom: 0.75rem;
  286. font-size: 1rem;
  287. }
  288. nav.nav.nav-pills {
  289. .nav-item.nav-link {
  290. padding: 0.25rem 0.5rem;
  291. font-size: $font-size-sm;
  292. border-radius: $border-radius;
  293. &:hover {
  294. background-color: $accordion-button-active-bg;
  295. color: $accordion-button-active-color;
  296. }
  297. }
  298. }
  299. // Ensure the content container is full-height, and that the content block is also full height so
  300. // that the footer is always at the bottom.
  301. div.content-container {
  302. min-height: 100vh;
  303. display: flex;
  304. flex-direction: column;
  305. div.content {
  306. flex: 1;
  307. }
  308. }
  309. // Prevent scrolling of body content when nav menu is open on mobile.
  310. .sidebar.collapse.show ~ .content-container {
  311. @media (max-width: map.get($grid-breakpoints, 'md')) {
  312. position: fixed;
  313. overflow-y: hidden;
  314. }
  315. }
  316. .sidebar {
  317. position: fixed;
  318. top: 0;
  319. bottom: 0;
  320. left: 0;
  321. z-index: 100; /* Behind the navbar */
  322. border-right: 1px solid $border-color;
  323. background-color: var(--nbx-sidebar-bg);
  324. @media (max-width: map.get($grid-breakpoints, 'md')) {
  325. top: 8.125rem;
  326. }
  327. div.accordion-item {
  328. div.accordion-collapse {
  329. &.collapse.show,
  330. &.collapsing {
  331. background-color: $accordion-body-active-bg;
  332. }
  333. }
  334. & > a.accordion-button.nav-link {
  335. &:hover {
  336. color: $accordion-button-active-color;
  337. background-color: $accordion-button-active-bg;
  338. }
  339. &:focus {
  340. border-color: unset;
  341. box-shadow: unset;
  342. }
  343. }
  344. }
  345. .accordion-body {
  346. max-height: calc(100vh - 24rem);
  347. overflow-y: auto;
  348. .nav-item {
  349. .nav-link {
  350. padding: 0.25rem 0.6rem;
  351. font-size: $font-size-sm;
  352. border-radius: $border-radius;
  353. &:hover {
  354. color: $accordion-button-active-color;
  355. background-color: $accordion-button-active-bg;
  356. }
  357. }
  358. }
  359. }
  360. // Ensure navigation accounts for the height of the header on mobile when nav is expanded.
  361. &.collapse.show div.position-sticky {
  362. @media (max-width: map.get($grid-breakpoints, 'md')) {
  363. height: calc(100vh - 16.125rem);
  364. overflow-y: auto;
  365. }
  366. }
  367. div.position-sticky {
  368. height: calc(100vh - 8rem);
  369. }
  370. div.sidebar-bottom {
  371. padding-left: 0.5rem;
  372. padding-right: 0.5rem;
  373. position: sticky;
  374. height: 8rem;
  375. background-color: var(--nbx-sidebar-bg);
  376. .nav-link {
  377. padding: 0.5rem 0.25rem;
  378. }
  379. }
  380. a.sidebar-logo {
  381. display: flex;
  382. flex-shrink: 1;
  383. width: 100%;
  384. height: 4rem;
  385. }
  386. }
  387. .tooltip {
  388. pointer-events: none;
  389. }
  390. .ws-nowrap {
  391. white-space: nowrap !important;
  392. }
  393. #object-type-selector {
  394. button.dropdown-item,
  395. h6.dropdown-header {
  396. font-size: $font-size-sm;
  397. }
  398. }
  399. .stats-container {
  400. min-height: 50vh;
  401. }
  402. span.color-label {
  403. width: 5rem;
  404. height: 1rem;
  405. display: block;
  406. box-shadow: $box-shadow-sm;
  407. border-radius: $border-radius;
  408. padding: $badge-padding-y $badge-padding-x;
  409. }
  410. pre {
  411. border-radius: $border-radius;
  412. border: 1px solid var(--nbx-pre-border-color);
  413. background-color: var(--nbx-pre-bg);
  414. padding: $spacer;
  415. white-space: pre;
  416. }
  417. .btn {
  418. white-space: nowrap;
  419. }
  420. .card {
  421. box-shadow: $box-shadow-sm;
  422. .card-header {
  423. color: $body-color;
  424. border-bottom: none;
  425. padding: $card-cap-padding-x;
  426. }
  427. .card-header + .card-body {
  428. padding-top: 0;
  429. }
  430. .card-body {
  431. overflow-x: auto;
  432. }
  433. }
  434. .form-floating {
  435. position: relative;
  436. > .input-group > .form-control,
  437. > .input-group > .form-select {
  438. height: $form-floating-height;
  439. padding: $form-floating-padding-y $form-floating-padding-x;
  440. }
  441. > .input-group > label {
  442. position: absolute;
  443. top: 0;
  444. left: 0;
  445. height: 100%; // allow textareas
  446. padding: $form-floating-padding-y $form-floating-padding-x;
  447. pointer-events: none;
  448. border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model
  449. transform-origin: 0 0;
  450. @include transition($form-floating-transition);
  451. }
  452. > .input-group > .form-control {
  453. &::placeholder {
  454. color: transparent;
  455. }
  456. &:focus,
  457. &:not(:placeholder-shown) {
  458. padding-top: $form-floating-input-padding-t;
  459. padding-bottom: $form-floating-input-padding-b;
  460. }
  461. // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
  462. &:-webkit-autofill {
  463. padding-top: $form-floating-input-padding-t;
  464. padding-bottom: $form-floating-input-padding-b;
  465. }
  466. }
  467. > .input-group > .form-select,
  468. > .choices > .choices__inner,
  469. > .ss-main span.placeholder, // SlimSelect Single
  470. > .ss-main div.ss-values // SlimSelect Multiple
  471. {
  472. padding-top: $form-floating-input-padding-t;
  473. padding-bottom: $form-floating-input-padding-b;
  474. }
  475. > .input-group > .form-control:focus,
  476. > .input-group > .form-control:not(:placeholder-shown),
  477. > .input-group > .form-select,
  478. > .choices,
  479. > .ss-main {
  480. ~ label {
  481. opacity: $form-floating-label-opacity;
  482. transform: $form-floating-label-transform;
  483. z-index: 4;
  484. }
  485. }
  486. // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
  487. > .input-group > .form-control:-webkit-autofill {
  488. ~ label {
  489. opacity: $form-floating-label-opacity;
  490. transform: $form-floating-label-transform;
  491. z-index: 4;
  492. }
  493. }
  494. }
  495. textarea.form-control[rows='10'] {
  496. height: 18rem;
  497. }
  498. textarea#id_local_context_data,
  499. textarea.markdown,
  500. textarea#id_public_key,
  501. textarea.form-control[name='csv'],
  502. textarea.form-control[name='data'] {
  503. font-family: $font-family-monospace;
  504. }
  505. table tr.vertical-align {
  506. vertical-align: middle;
  507. }
  508. .card:not(:only-of-type) {
  509. margin-bottom: $spacer;
  510. }
  511. .stat-btn {
  512. min-width: $spacer * 3;
  513. }
  514. nav.breadcrumb-container {
  515. padding: $badge-padding-y $badge-padding-x;
  516. font-size: $font-size-sm;
  517. width: fit-content;
  518. ol.breadcrumb {
  519. margin-bottom: 0;
  520. li.breadcrumb-item > a {
  521. text-decoration: none;
  522. }
  523. li.breadcrumb-item > a:hover {
  524. text-decoration: underline;
  525. }
  526. }
  527. }
  528. div.paginator > form > div.input-group {
  529. width: fit-content;
  530. }
  531. div.field-group:not(:first-of-type) {
  532. margin-top: $spacer * 3;
  533. h1,
  534. h2,
  535. h3,
  536. h4,
  537. h5,
  538. h6 {
  539. margin-bottom: $spacer;
  540. }
  541. }
  542. label.required {
  543. font-weight: $font-weight-bold;
  544. &::after {
  545. font-family: 'Material Design Icons';
  546. content: '\f06C4';
  547. font-weight: normal;
  548. font-size: 8px;
  549. font-style: normal;
  550. margin: 0 0 0 2px;
  551. text-decoration: none;
  552. display: inline-block;
  553. position: absolute;
  554. }
  555. }
  556. div.bulk-buttons {
  557. display: flex;
  558. & > * {
  559. margin: $spacer / 4;
  560. }
  561. }
  562. i.bi-plus:before,
  563. span.bi-plus:before {
  564. font-weight: $font-weight-bold !important;
  565. }
  566. table tbody {
  567. @each $color, $value in $theme-colors {
  568. tr.#{$color} {
  569. background-color: rgba($value, 0.15);
  570. border-color: $gray-500;
  571. }
  572. }
  573. }
  574. // Cable Tracing
  575. .cable-trace {
  576. max-width: 38rem;
  577. margin: 1rem auto;
  578. text-align: center;
  579. }
  580. .cable-trace .node {
  581. background-color: var(--nbx-cable-node-bg);
  582. border: $border-width solid var(--nbx-cable-node-border-color);
  583. border-radius: $border-radius;
  584. padding: 1.5rem 1rem;
  585. position: relative;
  586. z-index: 1;
  587. }
  588. .cable-trace .termination {
  589. background-color: var(--nbx-cable-termination-bg);
  590. border: $border-width solid var(--nbx-cable-termination-border-color);
  591. box-shadow: $box-shadow;
  592. border-radius: $border-radius;
  593. margin: -1rem auto;
  594. padding: 0.5rem;
  595. position: relative;
  596. width: 60%;
  597. z-index: 2;
  598. }
  599. .cable-trace .active {
  600. border: 0.25rem solid $success;
  601. }
  602. .cable-trace .cable {
  603. border-left-style: solid;
  604. border-left-width: 0.25rem;
  605. margin: 1rem 0 1rem 50%;
  606. padding: 1.5rem;
  607. text-align: left;
  608. width: 50%;
  609. }
  610. .cable-trace .trace-end {
  611. margin-top: 2rem;
  612. text-align: center;
  613. }
  614. pre.change-data {
  615. padding-left: 0;
  616. padding-right: 0;
  617. & > span {
  618. display: block;
  619. padding-left: $spacer;
  620. padding-right: $spacer;
  621. &.added {
  622. background-color: var(--nbx-change-added);
  623. }
  624. &.removed {
  625. background-color: var(--nbx-change-removed);
  626. }
  627. }
  628. }
  629. pre.change-diff {
  630. border-color: transparent;
  631. &.change-removed {
  632. background-color: var(--nbx-change-removed);
  633. }
  634. &.change-added {
  635. background-color: var(--nbx-change-added);
  636. }
  637. }
  638. div.card-overlay {
  639. position: absolute;
  640. width: 100%;
  641. height: 100%;
  642. background-color: rgba($white, 0.75);
  643. border-radius: $border-radius;
  644. display: flex;
  645. justify-content: center;
  646. align-items: center;
  647. & > div.spinner-border {
  648. width: 6rem;
  649. height: 6rem;
  650. color: $secondary;
  651. }
  652. }
  653. div.card > div.card-header > div.table-controls {
  654. max-width: 25%;
  655. width: 100%;
  656. }