@c8y/style
Version:
Styles for Cumulocity IoT applications
759 lines (646 loc) • 14.8 kB
text/less
@import "../../../mixins/_c8y-scrollbar.less";
@import "../../../mixins/_tab-focus.less";
@import "../../../mixins/_vendor-prefixes.less";
/**
* Card - Base card component with all variants
*
* Note: Uses @size-* tokens extensively; @font-size-* tokens, and component variables.
*
* Intentionally hardcoded values:
* - Component-specific dimensions (56px, 60px, 66px, 80px, 90px, 100px, 140px): Card sizes and minimums
* - Typography sizes (18px, 20px, 22px, 36px): Icon and heading font sizes
* - Border widths (1px, 2px): Standard borders and outlines
* - Negative offsets (-1px, -2px): Fine-tuning
* - Percentages (100%): Layout
* - Z-index values: Stacking order
* - Opacity values: Visual states
* - Transition durations: Animation timing
* - Box-shadow values: Elevation effects
* - RGBA values: Transparency
*/
// Shared mixin for card status color variants
.card-status-variant(@bg-color; @text-color; @muted-color) {
background-color: @bg-color;
color: @text-color;
--c8y-component-color-text-muted: @{muted-color};
--c8y-component-border-color: rgba(black, 0.1);
}
.card {
position: relative;
display: block;
margin-bottom: @size-16;
padding: 0;
border-radius: @component-border-radius-base;
background: @component-background-default;
box-shadow: var(--c8y-elevation-sm);
@media (min-width: @screen-sm-min) {
margin-bottom: @size-24;
}
&.pointer {
align-items: unset;
border: 0;
background-image: none;
text-align: unset;
&:focus {
.c8y-focus-inset();
}
}
// to use cards as buttons
&--btn {
outline: 1px solid @component-border-color;
position: relative;
z-index: 10;
width: 140px;
flex-grow: 1;
&:hover {
outline: 2px solid @component-brand-primary;
outline-offset: -2px;
z-index: 20;
text-decoration: none;
}
&:focus {
.c8y-focus-inset();
text-decoration: none;
z-index: 20;
}
}
// to prevent rendering cards inside a container
.hide-inner-cards & {
margin-bottom: 0;
.box-shadow(none);
.card-inner-scroll {
position: unset;
overflow: unset;
}
}
// border highlight
&.card-highlight {
border: 3px solid @component-color-accent;
}
// remove margin from hr direct child
> hr {
margin: 0;
}
// state colors
&.danger {
.card-status-variant(var(--palette-status-danger-light, var(--c8y-palette-status-danger-light)),
var(--palette-status-danger-dark, var(--c8y-palette-status-danger-dark)),
var(--palette-status-danger, var(--c8y-palette-status-danger)));
}
&.warning {
.card-status-variant(var(--palette-status-warning-light, var(--c8y-palette-status-warning-light)),
var(--palette-status-warning-dark, var(--c8y-palette-status-warning-dark)),
var(--palette-status-warning, var(--c8y-palette-status-warning)));
}
&.success {
.card-status-variant(var(--palette-status-success-light, var(--c8y-palette-status-success-light)),
var(--palette-status-success-dark, var(--c8y-palette-status-success-dark)),
var(--palette-status-success, var(--c8y-palette-status-success)));
}
&.info {
.card-status-variant(var(--palette-status-info-light, var(--c8y-palette-status-info-light)),
var(--palette-status-info-dark, var(--c8y-palette-status-info-dark)),
var(--palette-status-info, var(--c8y-palette-status-info)));
}
&.brand {
.card-status-variant(var(--brand-primary, var(--c8y-brand-primary));
@palette-high;
@palette-high);
}
&.not-active {
background: transparent;
opacity: @component-disabled-opacity;
filter: grayscale(100%);
cursor: default;
}
}
// tabs inside card
.card-has-tabs {
.nav.nav-tabs {
padding: 0 @size-16 0;
.nav-item {
padding-top: 7px;
&:last-child:first-child {
display: none;
}
}
}
.tab-container {
display: flex;
flex-direction: column;
height: 100%;
.tab-content {
display: flex;
flex-direction: column;
flex-grow: 1;
max-height: 100%;
.tab-pane,
.card--grid {
height: 100%;
}
}
}
}
// include tabs with scrolling content inside a card-grid
.card-tabs-wrapper {
display: contents;
.nav-tabs {
padding-right: @component-padding-base-horizontal;
padding-left: @component-padding-base-horizontal;
}
.tab-content {
display: contents;
}
.tab-pane {
.card {
margin-bottom: 0;
}
@media (min-width: @screen-md-min) {
.c8y-scrollbar();
overflow: auto;
flex-grow: 1;
height: 10rem;
}
}
}
//TODO: check and remove from UI
.page-footer {
min-height: 56px;
border-top: 0;
}
// Header
.card-header {
display: flex;
align-items: center;
flex-flow: row nowrap;
padding: @font-size-base @component-padding;
.card-tabs {
position: inherit;
box-shadow: none;
width: 100%;
z-index: unset;
}
// border on the bottom
&.separator {
box-shadow: inset 0 -1px 0 @component-border-color;
}
.card-icon,
.card-title {
order: 0;
padding-right: @size-base;
}
.card-icon {
margin-top: -6px;
min-width: 30px;
max-height: @size-20;
font-size: 22px;
line-height: @line-height-computed;
}
.card-icon,
.card-title .statusContainer {
.interact-list & {
margin-top: 0;
max-height: @size-20;
font-size: 20px;
}
}
.card-title .statusContainer {
line-height: 1;
}
h4,
h4.card-title,
.card-title,
.card-title.h4 {
overflow: hidden;
margin: 0;
padding: 0;
min-height: @size-20;
height: auto;
text-overflow: ellipsis;
font-weight: 500;
font-size: @font-size-h4;
line-height: @headings-line-height;
}
&:not(.separator) + .card-block {
padding-top: 0;
}
}
.card-appicon {
padding: @size-24 @size-8 0;
height: 66px;
font-size: @font-size-h1;
line-height: 1;
}
.card-subtitle {
margin: @size-4 0 0;
width: 100%;
color: @component-color-text-muted;
font-size: 110%;
}
.card-inner-scroll {
position: relative;
overflow-y: auto;
overscroll-behavior: contain;
//TBD: remove?
.c8y-alarm-list & {
@media screen and (min-width: @screen-lg-min) {
height: 50vh;
}
}
> p {
padding: 0 @component-padding;
&:first-child {
padding-top: @size-16;
}
}
// fix cropping svgs
svg {
padding-top: @size-4;
padding-bottom: @size-4;
}
}
.card-header-actions-no-title {
position: absolute;
z-index: 13;
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0 @size-4 0 @size-8;
width: 100%;
height: @size-4;
.card-header-title {
display: none;
}
.header-actions {
margin-top: -6px;
margin-right: calc(-1 * @size-20);
.optionsBtn:not(.open) {
border-radius: 50%;
background-color: @component-background-default;
opacity: 0;
}
}
}
// content
.card-block {
overflow: hidden;
padding: @component-padding;
text-overflow: ellipsis;
&--formly {
padding: 0;
formly-form {
display: block;
padding: @component-padding;
}
}
p:last-child {
margin-bottom: 0;
}
hr {
margin: @size-base calc(@component-padding * -1);
}
.flex-row.row {
margin-right: calc(@component-padding * -1);
margin-left: calc(@component-padding * -1);
}
}
// footer
.card-footer {
padding: @component-padding;
@media (min-width: @screen-sm-min) {
.btn:not(.btn-xs):not(.btn-sm) {
min-width: 100px;
}
}
@media (max-width: @screen-xs-max) {
.btn:not(.btn-xs):not(.btn-sm) {
min-width: 80px;
}
}
&.separator {
box-shadow: inset 0 1px 0 @component-border-color;
}
}
.card-actions {
position: absolute;
top: calc(@size-base * 0.5);
right: 0;
&.collapsible {
display: flex;
width: calc(@size-base * 10);
}
> .dropdown {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
order: 1000;
}
> .btn,
.dropdown > .c8y-dropdown {
display: flex;
align-items: center;
justify-content: center;
padding: @size-8 11.25px;
min-width: calc(@size-base * 5);
min-height: calc(@size-base * 5);
> [class^='dlt-c8y-icon-'],
> [class*=' dlt-c8y-icon-'] {
transition: all 0.35s ease;
}
&:focus,
&:hover,
&:active {
outline: 2px solid @component-color-focus;
outline-offset: -2px;
opacity: 1;
}
&:focus {
border-radius: @component-border-radius-focus ;
color: @component-brand-primary;
}
}
// Removed unused button selector - verified 0 usages: .btn-collapse
.dropdown-toggle,
.btn-link {
color: @component-color-actions;
opacity: @component-actions-opacity;
&:hover {
text-decoration: none;
opacity: 1;
}
&[disabled] {
opacity: @component-disabled-opacity ;
cursor: @cursor-disabled ;
pointer-events: auto ;
}
}
.dropdown.open .dropdown-toggle,
.btn-link.active {
opacity: 1;
}
}
.card-actions-group {
padding: calc(@size-base + 2px) @component-padding;
text-align: center;
&.separator {
box-shadow: inset 0 1px 0 @component-border-color;
}
a:not(.btn),
button:not(.btn) {
padding: 1px 5px;
border: 0;
border-radius: 0;
background-color: transparent;
background-image: none;
color: @component-color-actions;
text-transform: uppercase;
font-weight: bold;
font-size: @font-size-xs;
line-height: 1.5;
.box-shadow(none);
&:hover,
&:focus {
outline: none;
color: @component-brand-primary;
text-decoration: none;
}
}
.btn-xs {
margin-top: 3px;
margin-bottom: 3px;
}
}
//Card header actions
.card-header-actions {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0 0 0 @component-padding;
height: @size-48;
&:after {
position: absolute;
top: calc(@size-48 - @size-4);
left: 0;
z-index: 10;
display: block;
width: 100%;
height: @size-4;
content: '';
&:extend(.shadow-scroll);
}
// Removed unused scroll utility - verified 0 usages: .no-scroll
c8y-alarm-list & {
&:after {
display: none;
}
}
&.critical {
.card-icon,
.card-title {
background-color: var(--palette-status-danger, var(--c8y-palette-status-danger));
color: white;
}
.title {
opacity: 1;
}
}
&.major {
.card-icon,
.card-title {
background-color: var(--palette-status-warning-dark, var(--c8y-palette-status-warning-dark));
color: white;
}
.title {
opacity: 1;
}
}
&.minor {
.card-icon,
.card-title {
background-color: var(--palette-status-warning, var(--c8y-palette-status-warning));
color: white;
}
.title {
opacity: 1;
}
}
&.warning {
.card-icon,
.card-title {
background-color: var(--palette-status-info, var(--c8y-palette-status-info));
color: white;
}
.title {
opacity: 1;
}
}
.card-title {
display: flex;
align-items: center;
align-self: stretch;
padding: 0;
min-height: calc(@size-base * 6);
font-size: @font-size-small;
> span {
text-transform: uppercase;
}
}
.card-icon {
display: flex;
align-items: center;
align-self: stretch;
justify-content: center;
margin-left: calc(@component-padding * -1);
width: calc(@size-base * 6);
text-align: center;
+ .card-title {
padding: 0 calc(@size-base * 2) 0 0;
}
}
// action buttons on the right
.header-actions {
margin-left: auto;
.btn-link {
min-width: calc(@size-base * 5);
color: @component-color-actions;
&:hover {
color: @component-color-actions-hover;
text-decoration: none;
opacity: 1;
}
&:focus {
outline: none;
text-decoration: none;
opacity: 1;
}
}
.btn + .btn {
margin: 0;
}
.optionsBtn {
margin-right: @size-4;
}
.btn-icon {
min-width: calc(@size-base * 5);
color: @component-color-actions;
text-align: center;
.optionsBtn &{
opacity: @component-actions-opacity;
}
&:hover {
color: @component-color-actions-hover;
opacity: 1;
}
&:hover,
&:focus,
&:active {
outline: 2px solid @component-color-focus ;
outline-offset: -2px;
opacity: 1;
}
}
}
// scroll and shadow
+ .card-inner-scroll {
&:before {
position: absolute;
top: 0;
right: 0;
left: 0;
z-index: 10;
height: @size-4;
background-color: @component-background-default;
content: '';
}
}
}
.card-navbar {
padding: @size-4 @component-padding;
}
.card-select {
.card {
outline: 0 solid @component-color-focus;
cursor: pointer;
transition: outline 0.15s linear;
}
.card:hover,
.card:focus {
outline: 3px solid @component-color-focus;
}
.card.active {
outline: 3px solid @component-color-focus;
}
}
c8y-device-request-card {
display: contents;
}
// utility class to remove the left and right padding from the header and footer when the
// component is not contained in a card
.no-card-context {
.card-header,
.card-footer {
padding-left: 0;
padding-right: 0;
}
// .modal-dialog & {
// .card-header {
// padding-top: 0;
// }
// }
// display the tile as a label
.card-header {
> h4,
> .h4,
> .card-title {
font-size: @font-size-base;
font-weight: @form-label-font-weight;
line-height: @line-height-computed;
}
}
}
// Card ribbon
.card__ribbon {
width: 60px;
height: 60px;
overflow: hidden;
position: absolute;
top: calc(-1 * @size-4);
left: calc(-1 * @size-4);
&::before,
&::after {
position: absolute;
z-index: 0;
content: '';
display: block;
border: 2px solid @gray-50;
border-top-color: transparent;
border-left-color: transparent;
}
&::before {
top: 0;
right: 0;
}
&::after {
bottom: 0;
left: 0;
}
span,
button {
position: absolute;
display: block;
width: 90px;
padding: 2px @size-16;
background: @gray-40;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
color: @palette-high;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
text-align: center;
right: calc(-1 * @size-10);
top: 17px;
transform: rotate(-45deg);
font-size: @size-base;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}