Add new loading spinner, edit text-icon buttons (spiffier) and rename SiteNavSidePanel (#1684)

- Update icon for "Edit columns" button on **Hosts** page
- Update `text-icon` button variant
- Add new loading spinner
- Rename `SiteNavSidePanel` to `SiteTopNav`
- Use `text-icon` button variant where appropriate
- Disable pagination on the **Schedule** page
This commit is contained in:
noahtalerman
2021-08-16 14:47:04 -04:00
committed by GitHub
parent 9cd4bbe784
commit 20792e7356
17 changed files with 96 additions and 60 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

@@ -219,13 +219,13 @@ const TableContainer = ({
className={`${baseClass}__table-action-button`}
>
<>
{actionButtonText}
{actionButtonIcon && (
<img
src={actionButtonIcon}
alt={`${actionButtonText} icon`}
/>
)}
{actionButtonText}
</>
</Button>
)}
@@ -149,21 +149,20 @@ $base-class: "button";
&--text-icon {
@include button-variant(transparent);
padding: 0;
border: 0;
box-shadow: none;
color: $core-fleet-black;
color: $core-vibrant-blue;
font-size: $x-small;
font-weight: $regular;
font-weight: $bold;
cursor: pointer;
img {
height: 14px;
width: 14px;
margin-right: $pad-small;
transform: scale(0.5);
}
&:active {
box-shadow: none;
color: $core-vibrant-blue-down;
}
&:focus {
@@ -171,9 +170,7 @@ $base-class: "button";
}
&:hover {
background-color: transparent;
box-shadow: none;
text-decoration: underline;
color: $core-vibrant-blue-over;
}
}
@@ -1,9 +1,16 @@
import React from "react";
const baseClass = "kolide-spinner";
const Spinner = (): JSX.Element => {
return <div className={baseClass} />;
return (
<div className="card">
<div className="ring">
<div />
<div />
<div />
<div />
</div>
</div>
);
};
export default Spinner;
@@ -1,39 +1,50 @@
.kolide-spinner {
@include size(64px);
animation: sk-rotateplane 2.4s infinite ease-in-out;
background-color: #ae6ddf;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
margin: 30px auto;
.card {
margin: 120px auto;
display: flex;
align-items: center;
justify-content: center;
background-color: $core-white;
width: 48px;
height: 48px;
box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
@keyframes sk-rotateplane {
.ring {
box-sizing: border-box;
display: inline-block;
position: relative;
width: 32px;
height: 32px;
border-radius: 100%;
border: 4px solid $core-vibrant-blue;
}
.ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 32px;
height: 32px;
margin: -4px;
border: 4px solid $core-white;
border-radius: 50%;
animation: ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: $ui-vibrant-blue-25 transparent transparent transparent;
}
.ring div:nth-child(1) {
animation-delay: -0.45s;
}
.ring div:nth-child(2) {
animation-delay: -0.3s;
}
.ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes ring {
0% {
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
transform: rotate(0deg);
}
20% {
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
background: #ff5850;
}
40% {
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
background: #ffad00;
}
60% {
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
background: #4fd061;
}
80% {
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
background: #4a90e2;
}
100% {
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
background: #ae6ddf;
transform: rotate(360deg);
}
}
@@ -1 +0,0 @@
export { default } from "./SiteNavSidePanel";
@@ -14,7 +14,7 @@ import QueriesIcon from "../../../../assets/images/icon-main-queries@2x-16x16@2x
import PacksIcon from "../../../../assets/images/icon-main-packs@2x-16x16@2x.png";
import AdminIcon from "../../../../assets/images/icon-main-settings@2x-16x16@2x.png";
class SiteNavSidePanel extends Component {
class SiteTopNav extends Component {
static propTypes = {
onLogoutUser: PropTypes.func,
onNavItemClick: PropTypes.func,
@@ -86,7 +86,12 @@ class SiteNavSidePanel extends Component {
onClick={onNavItemClick(navItem.location.pathname)}
>
{icon}
<span className={`${navItemBaseClass}__name`}>{name}</span>
<span
className={`${navItemBaseClass}__name`}
data-text={navItem.name}
>
{name}
</span>
</a>
</li>
);
@@ -119,4 +124,4 @@ class SiteNavSidePanel extends Component {
}
}
export default SiteNavSidePanel;
export default SiteTopNav;
@@ -40,10 +40,25 @@
}
&__name {
display: inline-flex;
flex-direction: column;
align-items: center;
text-decoration: none;
vertical-align: middle;
font-weight: $regular;
font-size: $x-small;
// Bolding text when the button is active causes a layout shift
// so we add a hidden pseudo element with the same text string
&:before {
content: attr(data-text);
height: 0;
visibility: hidden;
overflow: hidden;
user-select: none;
pointer-events: none;
font-weight: $bold;
}
}
a {
@@ -0,0 +1 @@
export { default } from "./SiteTopNav";
+2 -2
View File
@@ -7,7 +7,7 @@ import { push } from "react-router-redux";
import configInterface from "interfaces/config";
import FlashMessage from "components/flash_messages/FlashMessage";
import PersistentFlash from "components/flash_messages/PersistentFlash";
import SiteNavSidePanel from "components/side_panels/SiteNavSidePanel";
import SiteTopNav from "components/side_panels/SiteTopNav";
import userInterface from "interfaces/user";
import notificationInterface from "interfaces/notification";
import { hideFlash } from "redux/nodes/notifications/actions";
@@ -92,7 +92,7 @@ export class CoreLayout extends Component {
return (
<div className="app-wrap">
<nav className="site-nav">
<SiteNavSidePanel
<SiteTopNav
config={config}
onLogoutUser={onLogoutUser}
onNavItemClick={onNavItemClick}
@@ -317,7 +317,7 @@ export class HostDetailsPage extends Component {
{canTransferTeam && (
<Button
onClick={toggleTransferHostModal()}
variant="inverse"
variant="text-icon"
className={`${baseClass}__transfer-button`}
>
Transfer <img src={TransferIcon} alt="Transfer host icon" />
@@ -326,7 +326,7 @@ export class HostDetailsPage extends Component {
<div data-tip data-for="query" data-tip-disable={isOnline}>
<Button
onClick={toggleQueryHostModal()}
variant="inverse"
variant="text-icon"
disabled={!isOnline}
className={`${baseClass}__query-button`}
>
@@ -344,7 +344,7 @@ export class HostDetailsPage extends Component {
You cant query <br /> an offline host.
</span>
</ReactTooltip>
<Button onClick={toggleDeleteHostModal()} variant="inverse">
<Button onClick={toggleDeleteHostModal()} variant="text-icon">
Delete <img src={DeleteIcon} alt="Delete host icon" />
</Button>
</div>
@@ -41,7 +41,7 @@ import NoHosts from "./components/NoHosts";
import EmptyHosts from "./components/EmptyHosts";
import EditColumnsModal from "./components/EditColumnsModal/EditColumnsModal";
import TransferHostModal from "./components/TransferHostModal";
import EditColumnsIcon from "../../../../assets/images/icon-edit-columns-16x12@2x.png";
import EditColumnsIcon from "../../../../assets/images/icon-edit-columns-16x16@2x.png";
import PencilIcon from "../../../../assets/images/icon-pencil-14x14@2x.png";
import TrashIcon from "../../../../assets/images/icon-trash-14x14@2x.png";
@@ -94,14 +94,14 @@ const PacksListWrapper = (props: IPacksListWrapperProps): JSX.Element => {
name: "enable",
onActionButtonClick: onEnablePackClick,
buttonText: "Enable",
variant: "text-link",
variant: "text-icon",
icon: "check",
},
{
name: "disable",
onActionButtonClick: onDisablePackClick,
buttonText: "Disable",
variant: "text-link",
variant: "text-icon",
icon: "disable",
},
];
@@ -121,7 +121,7 @@ const PacksListWrapper = (props: IPacksListWrapperProps): JSX.Element => {
searchable
disablePagination
onPrimarySelectActionClick={onRemovePackClick}
primarySelectActionButtonVariant="text-link"
primarySelectActionButtonVariant="text-icon"
primarySelectActionButtonIcon="delete"
primarySelectActionButtonText={"Delete"}
secondarySelectActions={secondarySelectActions}
@@ -107,7 +107,7 @@ const QueriesListWrapper = (
searchable
disablePagination
onPrimarySelectActionClick={onRemoveQueryClick}
primarySelectActionButtonVariant="text-link"
primarySelectActionButtonVariant="text-icon"
primarySelectActionButtonIcon="delete"
primarySelectActionButtonText={"Delete"}
emptyComponent={NoQueriesComponent}
@@ -137,8 +137,9 @@ const ScheduleListWrapper = (props: IScheduleListWrapperProps): JSX.Element => {
onQueryChange={onQueryChange}
inputPlaceHolder="Search"
searchable={false}
disablePagination
onPrimarySelectActionClick={onRemoveScheduledQueryClick}
primarySelectActionButtonVariant="text-link"
primarySelectActionButtonVariant="text-icon"
primarySelectActionButtonIcon="close"
primarySelectActionButtonText={"Remove"}
emptyComponent={NoScheduledQueries}