/***************************************************************************** * Open MCT, Copyright (c) 2014-2020, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * * Open MCT is licensed under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * Open MCT includes source code licensed under additional open source * licenses. See the Open Source Licenses file (LICENSES.md) included with * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ /*********************************************************************** CLOCKS AND TIMERS */ .c-clock, .c-timer { display: flex; align-items: center; font-size: 1.25em; overflow: hidden; > * { flex: 0 0 auto; display: flex; align-items: center; } &__value { color: $colorBodyFgEm; } .c-frame & { // When in a Display or Flexible Layout @include abs(); padding: $interiorMargin; } } .c-clock { > * + * { margin-left: $interiorMargin; } } .c-timer { $ctrlW: 22px; &__controls { font-size: 1rem !important; margin-right: 0; min-width: 0; overflow: hidden; transition: $transOut; width: 0; .c-icon-button:before { font-size: 1em; } } &__direction { font-size: 0.9rem !important; margin-right: $interiorMargin; } &__ng-controller { font-size: 0; width: 0; } &:hover { .c-timer__controls { transition: $transOut; // On purpose: want this to take a bit longer margin-right: $interiorMargin; width: $ctrlW * 2; } &.is-stopped .c-timer__controls { width: $ctrlW; } } &__direction, &__value { opacity: 0.5; } &.is-started { .c-timer { &__direction, &__value { opacity: 1; } } } } /*********************************************************************** SUMMARY WIDGETS */ /************************* WIDGET OBJECT */ @mixin cSummaryWidget() { box-shadow: $shdwBtns; border-radius: $basicCr; border-style: solid; border-width: 1px; cursor: default; display: inline-flex; align-items: center; justify-content: center; &[href] { cursor: pointer; } &__icon { // Hide the icon holder element. Selector below shows this once 'icon-*' is added. display: none; font-size: 0.9em; } &__label { @include ellipsize(); } [class*='icon-'] { // When 'icon-*' is added, show this element and add margin display: block; margin-right: $interiorMarginSm; } } .c-summary-widget, .c-sw { @include cSummaryWidget(); padding: $interiorMarginLg $interiorMarginLg * 2; &--thumb { max-width: 30%; padding: $interiorMarginSm $interiorMargin; } } .widget-edit-holder { // Hide edit area when in browse mode display: none; } .widget-rule-header { display: flex; align-items: center; > * + * { margin-left: $interiorMargin; } } [class*='action-buttons-wrapper'] { white-space: nowrap; line-height: $btnStdH; } .widget-rules-wrapper, .widget-rule-content, .w-widget-test-data-content { transition: $transIn; min-height: 0; height: 0; opacity: 0; overflow: hidden; pointer-events: none; } .widget-rules-wrapper { flex: 1 1 auto !important; } .widget-rule-content.expanded { overflow: visible !important; min-height: 50px; height: auto; margin-top: $interiorMargin; opacity: 1; pointer-events: inherit; } .w-widget-test-data-content { .l-enable { padding: $interiorMargin 0; } .w-widget-test-data-items { max-height: 20vh; overflow-y: scroll !important; padding-right: $interiorMargin; } } .l-widget-thumb-wrapper, .l-compact-form label { $ruleLabelW: 40%; $ruleLabelMaxW: 150px; display: flex; max-width: $ruleLabelMaxW; width: $ruleLabelW; } .js-summary-widget__message { display: none; } /**************\ EDITING A WIDGET */ .w-summary-widget { // Classes for editor layout while editing a widget // This selector is ugly and brittle, but needed to prevent interface from showing when widget is in a layout // being edited. @include abs(); display: flex; flex-direction: column; > .l-summary-widget { // Main view of the summary widget // Give some airspace and center the widget in the area margin: 30px auto; } .widget-edit-holder { display: flex; // Overrides `display: none` during Browse mode flex: 1 1 auto; overflow: hidden; .flex-accordion-holder { // Needed because otherwise accordion elements "creep" when contents expand and contract display: block !important; } &.expanded-widget-test-data { .w-widget-test-data-content { min-height: 50px; height: auto; opacity: 1; pointer-events: inherit; } &:not(.expanded-widget-rules) { // Test data is expanded and rules are collapsed // Make text data take up all the vertical space .flex-accordion-holder { display: flex; } } } &.expanded-widget-rules { .widget-rules-wrapper { min-height: 50px; height: 100%; // Fix for Chrome 73 scrolling bug opacity: 1; pointer-events: inherit; } } } &.s-status-no-data { .widget-edit-holder { opacity: 0.3; pointer-events: none; } .js-summary-widget__message { display: flex; } } .l-compact-form { // Overrides on .l-compact-form ul { &:last-child { margin: 0; } li { &:not(.widget-rule-header) { &:not(.connects-to-previous) { border-top: 1px solid $colorFormLines; } } &.connects-to-previous { padding: $interiorMargin 0; } > label { display: block; // Needed to align text to right text-align: right; width: 90px; flex: 0 0 auto; } .controls { display: flex; flex-wrap: wrap; align-items: center; align-content: stretch; > * + * { margin-left: $interiorMarginSm; } } } } &.s-widget-test-data-item { // Single line of ul li label span, etc. ul { li { border: none !important; > label { display: inline-block; width: auto; text-align: left; } } } } } .t-condition .controls { > * { margin-bottom: $interiorMargin; } } } .widget-edit-holder { font-size: 0.8rem; } .widget-rules-wrapper { // Wrapper area that holds n rules box-sizing: border-box; overflow-y: scroll; padding-right: $interiorMargin; } .l-widget-rule, .l-widget-test-data-item { box-sizing: border-box; margin-bottom: $interiorMarginSm; padding: $interiorMargin $interiorMarginLg; } .rule-title { flex: 0 1 auto; color: pullForward($colorBodyFg, 50%); } .rule-description { flex: 1 1 auto; @include ellipsize(); color: pushBack($colorBodyFg, 20%); } .s-widget-rule, .s-widget-test-data-item { background-color: rgba($colorBodyFg, 0.1); border-radius: $basicCr; } .c-sw-edit { padding: $interiorMargin; &__ui { display: flex; flex-direction: column; &__header { border-top: 1px solid $colorInteriorBorder; display: flex; align-items: center; margin: $interiorMargin 0; padding: $interiorMargin 0; text-transform: uppercase; > * + * { margin-left: $interiorMarginSm; } } } } .c-sw-rule { &__grippy-wrapper { $d: 8px; flex: 0 0 auto; cursor: move; width: $d; height: $d; transform: translateY(-1px); } &__grippy { @include grippy($c: $colorItemTreeVC, $dir: 'y'); @include abs(); } } /******************************************************************* CHANNEL SELECTOR */ .channel-selector { .line { margin-bottom: $interiorMargin; min-height: $formInputH; } .treeview { $myBg: darken($colorBodyBg, 2%); @include reactive-input(); min-height: 300px; max-height: 400px; overflow: auto; padding: $interiorMargin; } .btns-add-remove { margin-top: 150px; .s-button { display: block; margin-bottom: $interiorMargin; text-align: center; } } } /******************************************************************* AUTOFLOW TABULAR */ // NOT UNIT TESTED AS OF 3/12/19 .autoflow { $headerH: $formInputH; $colMargin: $interiorMargin; $colW: 225px; $valW: 70px; $valPad: 5px; $rowH: 15px; font-size: 0.75rem; &:hover { .l-autoflow-header .s-button.change-column-width { transition: $transIn; opacity: 1; } } .l-autoflow-header { bottom: auto; height: $headerH; line-height: $headerH; min-width: $colW; .t-last-update { overflow: hidden; } .s-button.change-column-width { transition: $transOut; opacity: 0; } .l-filter { display: block; margin-right: $interiorMargin; input.t-filter-input { width: 150px; } } } .l-autoflow-items { overflow-x: scroll; overflow-y: hidden; top: $headerH + $interiorMargin * 2; white-space: nowrap; .l-autoflow-col { box-sizing: border-box; border-left: 1px solid $colorInteriorBorder; display: inline-block; padding-left: $colMargin; padding-right: $colMargin; vertical-align: top; width: $colW; .l-autoflow-row { box-sizing: border-box; border-bottom: 1px solid rgba(#fff,0.05); display: block; height: $rowH; line-height: $rowH; margin-bottom: 1px; margin-top: 1px; position: relative; &:first-child { border-top: none; } &:hover { background: rgba(#fff, 0.1); } .l-autoflow-item.r { color: lighten($colorBodyFg, 10%); } &.first-in-group { border-top: 1px solid lighten($colorInteriorBorder, 20%); } .l-autoflow-item { display: block; &.l { float: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: auto; } &.r { border-radius: $smallCr; float: right; margin-left: $interiorMargin; padding-left: $valPad; padding-right: $valPad; text-align: right; } } } &:first-child { border-left: none; padding-left: 0; } } } } .frame { &.child-frame.panel { .autoflow .l-autoflow-header .l-filter { display: none; } } } /******************************************************************* INDICATORS */ /* Indicators are generally only displayed in the ue-bottom-bar element of the main interface */ .h-indicator, mct-indicators mct-include { display: inline; // Fallback for display: contents display: contents; } /************************************************* DATETIME UI */ @mixin complexFieldHolder($myW) { width: $myW + $interiorMargin; input[type="text"] { width: $myW; } } .complex.datetime { span { display: inline-block; margin-right: $interiorMargin; } .fields { margin-top: $interiorMarginSm 0; padding: $interiorMarginSm 0; } .date { @include complexFieldHolder(80px); } .time.md { @include complexFieldHolder(60px); } .time.sm { @include complexFieldHolder(40px); } } /************************************************* INFO BUBBLES */ .l-infobubble-wrapper { $arwSize: 5px; box-shadow: rgba(black, 0.4) 0 1px 5px; position: relative; z-index: 50; .l-infobubble { display: inline-block; min-width: $bubbleMinW; max-width: $bubbleMaxW; padding: 5px 10px; &:before { content:""; position: absolute; width: 0; height: 0; } table { width: 100%; tr { td { padding: 2px 0; vertical-align: top; &.label { padding-right: $interiorMargin * 2; white-space: nowrap; } &.value { //word-wrap: break-word; // Doesn't work in ? word-break: break-all; } &.align-wrap { white-space: normal; } } } } .title { @include ellipsize(); margin-bottom: $interiorMargin; } } &.arw-down { margin-bottom: $arwSize*2; .l-infobubble::before { left: 50%; top: 100%; margin-left: -1 * $arwSize; border-left: $arwSize solid transparent; border-right: $arwSize solid transparent; border-top: ($arwSize * 1.5) solid $colorInfoBubbleBg; } } .arw { z-index: 2; } &.arw-up .arw.arw-down, &.arw-down .arw.arw-up { display: none; } } body.desktop { .l-infobubble { &.arw-left { margin-left: $bubbleArwSize*2; &:before { @include triangle('left', $bubbleArwSize, 1.5, $colorInfoBubbleBg); right: 100%; } } &.arw-right { margin-right: $bubbleArwSize*2; &:before { @include triangle('right', $bubbleArwSize, 1.5, $colorInfoBubbleBg); left: 100%; } } &.arw-top { &:before { top: $bubbleArwSize * 2; } } &.arw-btm { &:before { bottom: $bubbleArwSize * 2; } } } } .l-thumbsbubble-wrapper { .arw-up { @include triangle('up', $bubbleArwSize, 1.5, $colorThumbsBubbleBg); } .arw-down { @include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg); } } .s-infobubble { $emFg: darken($colorInfoBubbleFg, 20%); border-radius: $basicCr; box-shadow: rgba(black, 0.4) 0 1px 5px; background: $colorInfoBubbleBg; color: $colorInfoBubbleFg; font-size: 0.8rem; .title { color: $emFg; font-weight: bold; } table { tr { td { border: none; border-top: 1px solid darken($colorInfoBubbleBg, 10%) !important; font-size: 0.9em; } &:first-child td { border-top: none !important; } } } &:first-child td { border-top: none; } .label { color: lighten($emFg, 30%); } .value { color: $emFg; } } .s-thumbsbubble { background: $colorThumbsBubbleBg; color: $colorThumbsBubbleFg; } /***************************************************************** SPLITTERS */ .splitter { display: block; position: absolute; z-index: 3; &:after { // The handle content:""; pointer-events: none; @include abs(0); background: $colorSplitterBg; display: block; z-index: 4; } &:active { &:after { background-color: $colorSplitterActive !important; } } @if $colorSplitterHover != 'none' { &:not(:active) { &:hover { &:after { background-color: $colorSplitterHover !important; transiiton: background-color, 150ms; } } } } } .split-layout { $inset: $splitterHandleHitMargin; &.horizontal { // Slides vertically up and down, splitting the element horizontally overflow: hidden; // Suppress overall scroll; each internal pane handles its own overflow .pane { left: 0; right: 0; &.top { bottom: auto; } &.bottom { top: auto; } } >.splitter { cursor: row-resize; left: 0; right: 0; height: $splitterHandleD; &:after { top: $inset; bottom: $inset; } } } &.vertical { // Slides horizontally left to right, splitting the element vertically .pane { top: 0; bottom: 0; &.left { right: auto; } &.right { left: auto; } } >.splitter { cursor: col-resize; top: 0; bottom: 0; width: $splitterHandleD; &:after { left: $inset; right: $inset; //width: $splitterHandleD; } &.flush-right { width: ceil($splitterHandleD / 2); &:after { width: $splitterHandleD; left: auto; right: 0; } &.edge-shdw { background-image: linear-gradient(90deg, rgba(black, 0) 40%, rgba(black, 0.05) 70%, rgba(black, 0.2) 100%); } } } } } /******************************************************************* FLEX STYLES */ .l-flex-row, .l-flex-col { display: flex; flex-wrap: nowrap; .flex-elem { min-height: 0; // Needed to allow element to shrink within parent position: relative; &:not(.grows) { flex: 0 0 auto; &.flex-can-shrink { flex: 0 1 auto; } } &.grows { flex: 1 1 auto; } &.contents-align-right { text-align: right; } } .flex-container { // Apply to wrapping elements, mct-includes, etc. display: flex; flex-wrap: nowrap; flex: 1 1 auto; min-height:0; } } .l-flex-row { flex-direction: row; &.flex-elem { flex: 1 1 auto; } > .flex-elem { min-width: 0; &.holder:not(:last-child) { margin-right: $interiorMargin; } } .flex-container { flex-direction: row; } } .l-flex-col { flex-direction: column; > .flex-elem { min-height: 0; &.holder:not(:last-child) { margin-bottom: $interiorMarginLg; } } &.l-flex-accordion .flex-accordion-holder { display: flex; flex-direction: column; } .flex-container { flex-direction: column; } } .flex-fixed { flex: 0 0 auto; } .flex-justify-end { justify-content: flex-end; } /******************************************************************* GRID STYLES */ .grid-two-column, .grid-properties { display: grid; grid-row-gap: 0; grid-template-columns: 1fr 2fr; } .grid-span-all, .grid-two-column-span-cols { grid-column: 1 / 3; } .grid-elem { &:not(:first-child) { border-top: 1px solid $colorInteriorBorder; } &.label { background-color: rgba(0,0,128,0.2); } &.value { background-color: rgba(0,128,0,0.2); } } .grid-row { display: contents; } .grid-row { .grid-cell { padding: 3px $interiorMarginLg 3px 0; &[title]:not([title=""]) { // When a cell has a title, assume it's helpful text cursor: help; } } &.force-border, &:not(:first-of-type) { // Row borders, effected via border-top on child elements of the row .grid-cell { border-top: 1px solid $colorInspectorSectionHeaderBg; } } } /******************************************************************* ABOUT SCREEN */ .l-about { &.abs { overflow: auto; } $contentH: 200px; .l-splash { position: relative; height: 45%; } .l-content { position: relative; margin-top: $interiorMarginLg; } } .s-about { line-height: 120%; a { color: $colorAboutLink; } h1, h2, h3 { color: pullForward($colorBodyFg, 20%); margin-bottom: 1em; } h1 { font-size: 2.25em; } h2 { border-top: 1px solid $colorInteriorBorder; font-size: 1.5em; margin-top: 2em; padding-top: 1em; } h3 { margin-top: 2em; } .s-description, .s-button { line-height: 2em; } .l-licenses-software { .l-license-software { border-top: 1px solid $colorInteriorBorder; padding: 0.5em 0; &:first-child { border-top: none; } em { color: pushBack($colorBodyFg, 20%); } h3 { font-size: 1.25em; } .s-license-text { font-size: 0.9em; } } } } /******************************************************************* STARTUP / SPLASH SCREEN */ @mixin splashElem($m: 20%) { top: $m; right: $m * 1.25; bottom: $m; left: $m * 1.25; } .l-splash, .l-splash:before, .l-splash:after { background-position: center; background-repeat: no-repeat; position: absolute; } .l-splash { background-size: cover; top: 0; right: 0; bottom: 0; left: 0; &:before, &:after { background-size: contain; content: ''; } &:before { // NASA logo, dude $w: 5%; $m: 10px; background-image: url('../ui/layout/assets/images/logo-nasa.svg'); top: $m; right: auto; bottom: auto; left: $m; height: auto; width: $w * 2; padding-bottom: $w; padding-top: $w; } &:after { // App logo top: 0; right: 15%; bottom: 0; left: 15%; } } .l-splash-holder { // Main outer holder for splash. position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 10000; opacity: 1; .l-splash { // The splash element. @include splashElem(); } } @media only screen and (max-device-width: 767px) { .l-splash-holder .l-splash { @include splashElem(0); border-radius: 0; box-shadow: none; } } @media only screen and (max-device-width: 767px) and (orientation: portrait) { .l-splash-holder .l-splash { &:before { // Make the NASA logo a bit bigger when we're in portrait mode. $w: 12%; width: $w * 2; padding-bottom: $w; padding-top: $w; } } } /******************************************************************* VARIOUS */ .c-overlay mct-include { display: inline; // Fallback for display: contents display: contents; } mct-container { display: block; } .overlay { .outer-holder { background: $colorMenuBg; color: $colorMenuFg !important; } } .t-popup { z-index: 75; } .form .form-row { .label { color: $colorMenuFg !important; } .selector-list { @include reactive-input(); background: $colorInputBg !important; color: $colorInputFg !important; } } .ui-symbol.view-control { display: block; transform-origin: center center; &:before { content: $glyph-icon-arrow-right-equilateral; } &.expanded { transform: rotate(90deg); } } .t-frame-outer { min-width: 200px; min-height: 200px; } .l-iframe { iframe { display: block; height: 100%; width: 100%; border: none; } } // Alert elements in views .s-unsynced { @include sUnsynced(); } .s-status-timeconductor-unsynced { // Plot areas .gl-plot .gl-plot-display-area { @include sUnsynced(); } // Object headers .object-header { .t-object-alert { display: inline; } } } .abs { position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: auto; width: auto; } .code { font-family: "Lucida Console", monospace; font-size: 0.7em; line-height: 150%; white-space: pre; } .codehilite { @extend .code; background-color: rgba($colorBodyFg, 0.1); padding: 1em; } .s-status-missing { // Labels. Expects .s-status-missing to be applied to mct-representation that contains .t-object-label .t-item-icon:before { content: $glyph-icon-object-unknown; } // Item, grid item. Expects .s-status-missing to be applied to mct-representation that contains .item.grid-item .item .t-item-icon-glyph:before { content: $glyph-icon-object-unknown; } // Object header. Expects .s-status-missing to be applied to mct-representation.object-header &.object-header { .type-icon:before { content: $glyph-icon-object-unknown; } } // Tree item. Expects .s-status-missing to be applied to .tree-item, // and mct-representation.search-item &.tree-item, &.search-item { > .rep-object-label .t-item-icon:before { content: $glyph-icon-object-unknown; } } } .align-right { text-align: right; } .centered { text-align: center; } .no-selection { // aka selection = "None". Used in palettes and their menu buttons. $c: red; $s: 48%; $e: 52%; background-image: linear-gradient(-45deg, transparent $s - 5%, $c $s, $c $e, transparent $e + 5% ); box-shadow:inset rgba(black, 0.3) 0 0 0 1px; background-repeat: no-repeat; background-size: contain; } .scrolling, .scroll { overflow: auto; } .vscroll { overflow-x: hidden; overflow-y: auto; &.scroll-pad { padding-right: $interiorMargin; } } .vscroll--persist { overflow-x: hidden; overflow-y: scroll; } .slidable { cursor: move; // Fallback cursor: grab; cursor: -moz-grab; cursor: -webkit-grab; &.horz { cursor: col-resize; } &.vert { cursor: row-resize; } } .no-margin { margin: 0; } .ds { box-shadow: rgba(#000, 0.7) 0 4px 10px 2px; } .capitalize { text-transform: capitalize; } .hide, .hidden, .t-main-view .hide-in-t-main-view { display: none !important; } .hide-nice { opacity: 0; pointer-events: none; } .invisible { display: block; visibility: hidden; height: 0; padding: 0; border: 0; margin: 0 !important; transform: scale(0); pointer-events: none; position: absolute; } .sep { color: rgba(#fff, 0.2); } .comma-list span { &:not(:first-child) { &:before { content: ', '; } } }