Files
fleet/frontend/components/TableContainer/_styles.scss
T

306 lines
6.7 KiB
SCSS

.table-container {
display: flex;
flex-direction: column;
gap: $gap-page-component-inner;
// Container is responsive design used when customControl is rendered
.container {
display: grid;
grid-template-columns: 1fr auto; /* First column takes all remaining space */
grid-template-rows: auto auto; /* Two rows for smaller screens*/
width: 100%;
height: max-content;
gap: $gap-table-elements;
}
.stackable-header {
min-width: max-content;
align-content: center;
display: flex;
flex-direction: row;
gap: $gap-table-elements;
> div {
display: flex;
flex-direction: row;
}
// only if in stackable header
.table-container__search {
width: 100%;
}
}
.top-shift-header {
grid-column: 1 / -1; /* Span across all columns */
grid-row: 1; /* Place in the first row */
.table-container__search {
flex: 1; // Fill remaining width when stacked
}
.Select-multi-value-wrapper {
height: 36px; // Fixes height issues
width: 236px;
}
}
.stackable-header:nth-child(1) {
grid-column: 1 / span 2; /* Make Header 1 expand across two columns */
grid-row: 2;
.form-field--dropdown {
width: 235px;
}
}
/* Media query for larger screens */
@media (min-width: $break-md) {
.container {
grid-template-columns: 1fr auto; /* First column takes all remaining space */
grid-template-rows: auto; /* Single row */
}
.top-shift-header {
grid-column: 2; /* Single row */
}
.stackable-header:nth-child(1) {
grid-column: 1; /* Ensure Header 1 stays in the first column */
grid-row: 1; /* Single row */
}
}
// TODO: Fix hacky solution to clientside search being 0 no longer accessing rows.length
.client-result-count-0 {
display: none;
}
&__header {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
gap: $gap-table-elements;
// Hide the header entirely when it has no visible content (no
// results count, no filter/action controls, and no search bar).
&:not(:has(.table-container__results-count)):not(:has(.controls
> *)):not(:has(.table-container__search)) {
display: none;
}
&.stack-table-controls {
align-items: start;
@media (min-width: $break-xs) {
flex-direction: row;
align-items: end;
justify-content: space-between;
.table-container__search {
order: -2;
}
.table-container__results-count {
order: -1;
}
}
@media (min-width: $break-md) {
align-items: center;
.table-container__search {
order: initial;
}
}
}
// filter and search bar height
.dropdown__select,
.input-with-icon {
height: 36px;
}
.children-wrapper {
white-space: nowrap;
}
}
&__header-left {
display: flex;
width: 100%;
justify-content: space-between;
flex-direction: row;
align-items: center;
gap: $gap-table-elements; // space between filters and host count on low screen widths
&.stack-table-controls {
flex-direction: column;
align-items: start;
@media (min-width: $break-md) {
justify-content: space-between;
}
}
}
&__results-count {
display: flex;
align-items: center;
font-size: $x-small;
font-weight: $bold;
color: $core-fleet-black;
margin: 0;
height: 36px;
gap: $gap-table-elements;
> span {
min-width: fit-content;
line-height: 1; // Normalize line-height so different font sizes share a consistent center
}
.count-error {
color: $ui-error;
}
.count-loading {
color: $ui-fleet-black-50;
}
}
&__edit-columns-button:hover {
cursor: pointer;
text-decoration: underline;
color: $core-vibrant-blue-over;
}
&__search-input {
position: relative;
color: $core-fleet-blue;
width: 100%;
.input-with-icon {
width: 100%;
min-width: 250px;
}
.input-with-icon:placeholder-shown {
text-overflow: ellipsis;
}
&.stack-table-controls {
padding-bottom: $pad-large;
margin-left: 0;
@media (min-width: $break-xs) {
padding-bottom: 0;
}
}
.input-field {
padding-left: 42px;
width: 100%;
}
.fleeticon {
position: absolute;
top: 10px;
left: 12px;
font-size: $medium;
color: $core-fleet-black;
}
}
// Tooltip wrapper around search input needs full width so the input can
// expand to fill the available space (applies to both stacked and non-stacked layouts).
&__search {
.component__tooltip-wrapper {
width: 100%;
&__element {
width: 100%;
}
}
}
.table-container__search-input.wide-search {
margin-left: 0;
margin-bottom: $pad-small;
}
#search-tooltip {
width: 190px;
text-align: center;
}
.fleet-checkbox__tick {
top: 1px;
}
// Truncates clickable button cells (not compatible with buttons with icons)
tbody {
.children-wrapper {
overflow: hidden;
white-space: nowrap;
display: flex;
text-overflow: ellipsis;
}
.icon {
vertical-align: center;
}
}
.linkToFilteredHosts__header {
width: 120px;
}
// This hides View all host button unless the row is hovered
tr {
.row-hover-button {
opacity: 0;
// Suppress pointer events while hidden so the invisible button can't
// intercept clicks meant for the row. Tab navigation still works —
// pointer-events only gates mouse/touch, not keyboard focus.
pointer-events: none;
transition: 250ms;
text-overflow: none;
// Reveal on the button's own keyboard focus, not just row hover/focus —
// otherwise tabbing directly to a hidden row-hover button never shows it.
&:focus-visible {
opacity: 1;
pointer-events: auto;
}
// React-select's dropdown opacity must be controlled at input level for keyboard nav
// So must be controlled at input level here as well
&.actions-dropdown {
opacity: 1;
// React-select handles its own keyboard nav; keep it hit-testable
// so focus/blur bookkeeping continues to work even before row hover.
pointer-events: auto;
.actions-dropdown-select__control {
opacity: 0;
&:hover,
&--is-focused {
opacity: 1;
}
}
}
}
&:hover,
&:focus-visible {
.row-hover-button {
opacity: 1;
pointer-events: auto;
}
.row-hover-button.actions-dropdown {
.actions-dropdown-select__control {
opacity: 1;
}
}
}
}
}