Merge pull request #161 from OneUptime/refactor-ui

Refactor UI
This commit is contained in:
Simon Larsen
2022-06-12 23:07:23 +01:00
committed by GitHub
41 changed files with 485 additions and 714 deletions

View File

@@ -9,9 +9,9 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-regular-svg-icons": "^6.1.0",
"@fortawesome/free-solid-svg-icons": "^6.1.0",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.1.18",
"bootstrap": "^5.2.0-beta1",
"Common": "file:../Common",
@@ -4652,8 +4652,9 @@
},
"node_modules/@fortawesome/fontawesome-svg-core": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.1.tgz",
"integrity": "sha512-NCg0w2YIp81f4V6cMGD9iomfsIj7GWrqmsa0ZsPh59G7PKiGN1KymZNxmF00ssuAlo/VZmpK6xazsGOwzKYUMg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.1.1"
},
@@ -4663,8 +4664,9 @@
},
"node_modules/@fortawesome/free-regular-svg-icons": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.1.tgz",
"integrity": "sha512-xXiW7hcpgwmWtndKPOzG+43fPH7ZjxOaoeyooptSztGmJxCAflHZxXNK0GcT0uEsR4jTGQAfGklDZE5NHoBhKg==",
"hasInstallScript": true,
"license": "(CC-BY-4.0 AND MIT)",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.1.1"
},
@@ -4674,8 +4676,9 @@
},
"node_modules/@fortawesome/free-solid-svg-icons": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.1.tgz",
"integrity": "sha512-0/5exxavOhI/D4Ovm2r3vxNojGZioPwmFrKg0ZUH69Q68uFhFPs6+dhAToh6VEQBntxPRYPuT5Cg1tpNa9JUPg==",
"hasInstallScript": true,
"license": "(CC-BY-4.0 AND MIT)",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.1.1"
},
@@ -4685,7 +4688,8 @@
},
"node_modules/@fortawesome/react-fontawesome": {
"version": "0.1.18",
"license": "MIT",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz",
"integrity": "sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ==",
"dependencies": {
"prop-types": "^15.8.1"
},
@@ -5812,24 +5816,32 @@
},
"@fortawesome/fontawesome-svg-core": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.1.tgz",
"integrity": "sha512-NCg0w2YIp81f4V6cMGD9iomfsIj7GWrqmsa0ZsPh59G7PKiGN1KymZNxmF00ssuAlo/VZmpK6xazsGOwzKYUMg==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.1.1"
}
},
"@fortawesome/free-regular-svg-icons": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.1.tgz",
"integrity": "sha512-xXiW7hcpgwmWtndKPOzG+43fPH7ZjxOaoeyooptSztGmJxCAflHZxXNK0GcT0uEsR4jTGQAfGklDZE5NHoBhKg==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.1.1"
}
},
"@fortawesome/free-solid-svg-icons": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.1.tgz",
"integrity": "sha512-0/5exxavOhI/D4Ovm2r3vxNojGZioPwmFrKg0ZUH69Q68uFhFPs6+dhAToh6VEQBntxPRYPuT5Cg1tpNa9JUPg==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.1.1"
}
},
"@fortawesome/react-fontawesome": {
"version": "0.1.18",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz",
"integrity": "sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ==",
"requires": {
"prop-types": "^15.8.1"
}

View File

@@ -11,9 +11,9 @@
"license": "MIT",
"type": "module",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-regular-svg-icons": "^6.1.0",
"@fortawesome/free-solid-svg-icons": "^6.1.0",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.1.18",
"bootstrap": "^5.2.0-beta1",
"Common": "file:../Common",

View File

@@ -2,28 +2,39 @@ import React, { FunctionComponent, ReactElement, useEffect } from 'react';
import { MouseOnClick, KeyboardEventProp } from '../../../Types/HtmlEvents';
import ShortcutKey from '../ShortcutKey/ShortcutKey';
import ButtonType from './ButtonTypes';
import CSS from 'csstype';
import Icon, { IconProp, SizeProp } from '../Icon/Icon';
export interface ComponentProps {
title: string;
onClick?: MouseOnClick;
disabled?: boolean;
id: string;
id?: string;
shortcutKey?: ShortcutKey;
type?: ButtonType;
isLoading?: boolean;
style?: CSS.Properties;
icon?: IconProp;
showIconOnRight?: boolean;
iconSize?: SizeProp;
}
const Button: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
// props validation
if (!props.type) {
props.type = ButtonType.Button;
}
const Button: FunctionComponent<ComponentProps> = ({
title,
onClick,
disabled,
id,
shortcutKey,
type = ButtonType.Button,
isLoading = false,
style,
icon,
iconSize,
showIconOnRight = false,
}: ComponentProps): ReactElement => {
useEffect(() => {
// componentDidMount
if (props.shortcutKey) {
if (shortcutKey) {
window.addEventListener('keydown', (e: KeyboardEventProp) => {
return handleKeyboard(e);
});
@@ -31,7 +42,7 @@ const Button: FunctionComponent<ComponentProps> = (
// componentDidUnmount
return () => {
if (props.shortcutKey) {
if (shortcutKey) {
window.removeEventListener(
'keydown',
(e: KeyboardEventProp) => {
@@ -46,12 +57,12 @@ const Button: FunctionComponent<ComponentProps> = (
if (
event.target instanceof HTMLBodyElement &&
event.key &&
props.shortcutKey
shortcutKey
) {
switch (event.key) {
case props.shortcutKey.toUpperCase():
case props.shortcutKey.toLowerCase():
props.onClick && props.onClick();
case shortcutKey.toUpperCase():
case shortcutKey.toLowerCase():
onClick && onClick();
return;
default:
return;
@@ -61,27 +72,53 @@ const Button: FunctionComponent<ComponentProps> = (
return (
<button
id={props.id}
onClick={props.onClick}
type={props.type}
disabled={props.disabled}
style={style}
id={id}
onClick={onClick}
type={type}
disabled={disabled}
className="button"
>
{!props.isLoading && (
{!isLoading && (
<div>
<div>
<div></div>
</div>
<span>
<span>{props.title}</span>
{props.shortcutKey && (
<span>
{icon && !showIconOnRight && (
<Icon
icon={icon}
size={
iconSize ? iconSize : SizeProp.Regular
}
/>
)}
</span>
<span>{title}</span>
<span
style={{
marginLeft: '5px',
}}
>
{icon && showIconOnRight && (
<Icon
icon={icon}
size={
iconSize ? iconSize : SizeProp.Regular
}
/>
)}
</span>
{shortcutKey && (
<span className="newButtonKeycode">
{props.shortcutKey}
{shortcutKey}
</span>
)}
</span>
</div>
)}
{props.isLoading && <div>Implement Loader here</div>}
{isLoading && <div>Implement Loader here</div>}
</button>
);
};

View File

@@ -1,37 +0,0 @@
import React, {
MouseEventHandler,
ReactElement,
FunctionComponent,
} from 'react';
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
import './DropdownButton.scss';
import { MenuOutlineButton } from '../../Dashboard/TopBar/TopbarMenuButton/MenuButton';
export interface ComponentProps {
showDropdown?: boolean;
onClick?: MouseEventHandler;
children?: Array<ReactElement>;
title: string;
}
const DropdownButton: FunctionComponent<ComponentProps> = ({
onClick,
title,
children,
showDropdown,
}: ComponentProps): ReactElement => {
return (
<div className="dropdownButton">
<MenuOutlineButton
text={title}
icon={faChevronDown}
onClick={onClick!}
/>
{showDropdown && (
<div className="dropdownButtonLists">{children}</div>
)}
</div>
);
};
export default DropdownButton;

View File

@@ -1,23 +0,0 @@
import React, {
FunctionComponent,
MouseEventHandler,
ReactElement,
} from 'react';
export interface ComponentProps {
title: string;
action?: MouseEventHandler;
}
const DropdownItem: FunctionComponent<ComponentProps> = ({
action,
title,
}: ComponentProps): ReactElement => {
return (
<div className="dropdownButtonListItem" onClick={action}>
{title}
</div>
);
};
export default DropdownItem;

View File

@@ -0,0 +1,11 @@
@use '../../../../Styles/BrandColors.scss';
.icon {
color: BrandColors.$color-grey !important;
&:hover {
color: BrandColors.$color-black !important;
}
}

View File

@@ -0,0 +1,48 @@
import React, { ReactElement, FunctionComponent } from 'react';
import useComponentOutsideClick from '../../../../Types/UseComponentOutsideClick';
import Icon, { IconProp, SizeProp } from '../../Icon/Icon';
import './IconButton.scss';
export interface ComponentProps {
icon?: IconProp;
onClick?: Function;
children: ReactElement | Array<ReactElement>;
size?: SizeProp;
}
const IconButton: FunctionComponent<ComponentProps> = ({
icon,
onClick,
children,
size,
}: ComponentProps): ReactElement => {
const { ref, isComponentVisible, setIsComponentVisible } =
useComponentOutsideClick(false);
return (
<div className="buttonLayout">
<div
className="iconButton"
ref={ref}
onClick={() => {
setIsComponentVisible(!isComponentVisible);
if (onClick) {
onClick();
}
}}
>
{icon && (
<Icon
className="icon"
icon={icon}
size={size ? size : SizeProp.Regular}
/>
)}
</div>
{isComponentVisible && (
<div className="dropdownButtonLists">{children}</div>
)}
</div>
);
};
export default IconButton;

View File

@@ -0,0 +1,42 @@
import React, { ReactElement, FunctionComponent } from 'react';
import './MenuButton.scss';
import Button from '../Button';
import useComponentOutsideClick from '../../../../Types/UseComponentOutsideClick';
import CSS from 'csstype';
import { IconProp, SizeProp } from '../../Icon/Icon';
export interface ComponentProps {
children: ReactElement | Array<ReactElement>;
title: string;
style?: CSS.Properties;
}
const MenuButton: FunctionComponent<ComponentProps> = ({
title,
children,
style,
}: ComponentProps): ReactElement => {
const { ref, isComponentVisible, setIsComponentVisible } =
useComponentOutsideClick(false);
return (
<div className="dropdownButton" ref={ref}>
<Button
title={title}
onClick={() => {
setIsComponentVisible(true);
}}
style={style ? style : {}}
icon={IconProp.ChevronDown}
showIconOnRight={true}
iconSize={SizeProp.Small}
/>
{isComponentVisible && (
<div className="dropdownButtonLists">{children}</div>
)}
</div>
);
};
export default MenuButton;

View File

@@ -0,0 +1,36 @@
import Route from 'Common/Types/API/Route';
import React, {
FunctionComponent,
MouseEventHandler,
ReactElement,
} from 'react';
import Navigation from '../../../../Utils/Navigation';
export interface ComponentProps {
title: string;
onClick?: MouseEventHandler;
route?: Route;
}
const MenuItem: FunctionComponent<ComponentProps> = ({
onClick,
title,
route,
}: ComponentProps): ReactElement => {
return (
<div
className="dropdownButtonListItem"
onClick={
route
? () => {
Navigation.navigate(route);
}
: onClick
}
>
{title}
</div>
);
};
export default MenuItem;

View File

@@ -0,0 +1,17 @@
import React, { FunctionComponent, ReactElement } from 'react';
export interface ComponentProps {
title: string;
}
const MenuLegend: FunctionComponent<ComponentProps> = ({
title,
}: ComponentProps): ReactElement => {
return (
<div className="lists">
<p className="legend">{title}</p>
</div>
);
};
export default MenuLegend;

View File

@@ -1,30 +1,73 @@
import React, { FunctionComponent, ReactElement } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faCircleQuestion,
faUser,
faCog,
faBell,
faFile,
faChevronDown,
faChevronRight,
IconDefinition,
faHome,
} from '@fortawesome/free-solid-svg-icons';
import Dictionary from 'Common/Types/Dictionary';
export enum SizeProp {
ExtraSmall = 'xs',
Small = 'sm',
Regular = '1x',
Large = 'lg',
ExtraLarge = '3x',
ExtraSmall = '8px',
Smaller = '10px',
Small = '12px',
Regular = '15px',
Large = '18px',
ExtraLarge = '25px',
}
export enum IconProp {
File = 'file',
File = 'File',
User = 'User',
Settings = 'Settings',
Notification = 'Notifications',
Help = 'Help',
ChevronDown = 'ChevronDown',
ChevronRight = 'ChevronRight',
Home = 'Home',
}
const IconDictionary: Dictionary<IconDefinition> = {
[IconProp.Help]: faCircleQuestion,
[IconProp.User]: faUser,
[IconProp.Notification]: faBell,
[IconProp.Settings]: faCog,
[IconProp.File]: faFile,
[IconProp.ChevronDown]: faChevronDown,
[IconProp.ChevronRight]: faChevronRight,
[IconProp.Home]: faHome,
};
export interface ComponentProps {
icon: IconProp;
size: SizeProp;
size?: SizeProp;
className?: string;
}
const Icon: FunctionComponent<ComponentProps> = ({
icon,
size = SizeProp.Regular,
icon,
className,
}: ComponentProps): ReactElement => {
return (
<span>
<FontAwesomeIcon icon={icon} size={size} />
<span
style={{
cursor: 'pointer',
}}
className={className ? className : ''}
>
<FontAwesomeIcon
icon={IconDictionary[icon] as IconDefinition}
style={{
fontSize: size,
}}
/>
</span>
);
};

View File

@@ -0,0 +1,26 @@
import Route from 'Common/Types/API/Route';
import React, { FunctionComponent, ReactElement } from 'react';
import Navigation from '../../../Utils/Navigation';
export interface ComponentProps {
title: string;
route?: Route;
}
const BreadcrumbItem: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
return (
<p
onClick={() => {
if (props.route) {
Navigation.navigate(props.route);
}
}}
>
{props.title}
</p>
);
};
export default BreadcrumbItem;

View File

@@ -1,25 +1,27 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { faChevronRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { FunctionComponent, ReactElement } from 'react';
import './Breadcrumb.scss';
import './Breadcrumbs.scss';
import Icon, { IconProp } from '../../Basic/Icon/Icon';
export interface ComponentProps {
icon: IconProp;
title: string;
children: Array<ReactElement>;
children: ReactElement | Array<ReactElement>;
}
const Breadcrumb: FunctionComponent<ComponentProps> = ({
const Breadcrumbs: FunctionComponent<ComponentProps> = ({
icon,
title,
children,
}: ComponentProps): ReactElement => {
if (!Array.isArray(children)) {
children = [children];
}
return (
<div className="breadcrumb-container">
<div className="breadcrumb_detail">
<div className="breadcrumb_detail__summary">
<FontAwesomeIcon icon={icon} />
<Icon icon={icon} />
<h2>{title}</h2>
</div>
<div className="breadcrumb_detail__crumbs">
@@ -27,7 +29,7 @@ const Breadcrumb: FunctionComponent<ComponentProps> = ({
return (
<React.Fragment key={index}>
{child}
<FontAwesomeIcon icon={faChevronRight} />
<Icon icon={IconProp.ChevronRight} />
</React.Fragment>
);
})}
@@ -37,4 +39,4 @@ const Breadcrumb: FunctionComponent<ComponentProps> = ({
);
};
export default Breadcrumb;
export default Breadcrumbs;

View File

@@ -0,0 +1,9 @@
@use '../../../../Styles/BrandColors.scss';
.dropdownButton > .button{
&:hover {
background: BrandColors.$color-black !important;
color: BrandColors.$color-white !important;
}
}

View File

@@ -0,0 +1,30 @@
import React, { FunctionComponent, ReactElement } from 'react';
import MenuButton, {
ComponentProps,
} from '../../../Basic/Button/MenuButton/MenuButton';
import './MenuButton.scss';
const TopBarMenyuButton: FunctionComponent<ComponentProps> = (
props: ComponentProps
): ReactElement => {
return (
<MenuButton
style={{
fontSize: '13px',
borderColor: 'black',
borderStyle: 'solid',
borderRadius: '20px',
paddingRight: '10px',
borderWidth: '1px',
paddingLeft: '10px',
background: 'transparent',
color: 'black',
}}
{...props}
>
{props.children}
</MenuButton>
);
};
export default TopBarMenyuButton;

View File

@@ -26,7 +26,7 @@ $primaryColor: rgb(246, 248, 250);
align-items: center;
& > * {
padding-left: 20px;
margin-left: 20px;
}
}
}

View File

@@ -1,54 +0,0 @@
$primaryColor: rgb(246, 248, 250);
$lightDark: #888;
$dark: #333;
$transition: all 0.1s ease;
.legend {
font-size: 1.3rem;
font-weight: 400;
text-transform: uppercase;
padding: 0 15px;
color: #888;
}
.menu-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 2px 0;
cursor: pointer;
&:hover {
background-color: $primaryColor;
}
div {
padding: 0 15px;
display: flex;
align-items: center;
& > * {
padding-right: 10px;
}
svg {
font-size: 1.1rem !important;
}
p {
padding: 0;
margin: 0;
font-size: 1.4rem !important;
}
code {
display: block;
color: #999;
background-color: lighten($dark, 75%);
padding: 0 5px;
margin: 0 1px;
border-radius: 2px;
font-size: 1.3rem;
}
}
}

View File

@@ -1,41 +0,0 @@
import React, {
ReactElement,
MouseEventHandler,
FunctionComponent,
} from 'react';
import Shortcut from '../../../Basic/ShortcutKey/Shortcut';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import Char from 'Common/Types/Char';
import './MenuItem.scss';
export interface ComponentProps {
text: string;
icon?: IconProp;
shortcuts?: Array<Char>;
action?: MouseEventHandler;
}
const MenuItem: FunctionComponent<ComponentProps> = ({
text,
icon,
shortcuts,
action,
}: ComponentProps): ReactElement => {
return (
<div onClick={action} className="menu-item">
<div className="name">
{icon && <FontAwesomeIcon icon={icon} />}
<p>{text}</p>
</div>
{shortcuts && (
<div className="shortcut">
<Shortcut shortcuts={shortcuts} />
</div>
)}
</div>
);
};
export default MenuItem;

View File

@@ -1,68 +0,0 @@
$primaryColor: rgb(246, 248, 250);
$lightDark: #888;
$dark: #333;
$black: black;
$transition: all 0.1s ease;
.legend {
font-size: 1.3rem;
font-weight: 400;
text-transform: uppercase;
padding: 0 15px;
margin: 0;
margin-bottom: 3px;
color: #888;
}
.menu-link {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0;
cursor: pointer;
&:hover {
background-color: $primaryColor;
}
div {
padding: 0 15px;
display: flex;
align-items: center;
font-size: 1.3rem;
transition: color 0.2s linear;
& > * {
padding-right: 10px;
}
svg {
font-size: 1.3rem;
font-weight: 700;
color: $black;
}
p {
font-weight: 500;
padding: 5px 0;
margin: 0;
font-size: 1.5rem;
color: $black;
padding-right: 7px;
}
&:hover > svg {
color: $dark;
}
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

View File

@@ -1,26 +0,0 @@
import React, { ReactElement, FunctionComponent } from 'react';
import { faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import './MenuLink.scss';
export interface ComponentProps {
text: string;
openInNewTab?: boolean;
}
const MenuLinkItem: FunctionComponent<ComponentProps> = ({
text,
openInNewTab,
}: ComponentProps): ReactElement => {
return (
<div className="menu-link">
<div className="name">
<p>{text}</p>
{openInNewTab && <FontAwesomeIcon icon={faUpRightFromSquare} />}
</div>
</div>
);
};
export default MenuLinkItem;

View File

@@ -1,25 +0,0 @@
import React, { ReactElement, FunctionComponent } from 'react';
import './MenuItem.tsx';
export interface ComponentProps {
legend?: string;
items: Array<ReactElement>;
}
const TopbarMenu: FunctionComponent<ComponentProps> = ({
legend,
items,
}: ComponentProps): ReactElement => {
return (
<div className="lists">
<p className="legend">{legend}</p>
<>
{items.map((item: ReactElement, index: number) => {
return <React.Fragment key={index}>{item}</React.Fragment>;
})}
</>
</div>
);
};
export default TopbarMenu;

View File

@@ -1,117 +0,0 @@
$primaryColor: rgb(246, 248, 250);
$lightDark: #000;
$dark: #000;
$transition: all 0.1s ease;
.buttonLayout {
user-select: none;
position: relative;
.iconButton {
display: flex;
align-items: center;
flex: 1;
cursor: pointer;
svg {
color: #000;
font-size: 1.6rem;
}
}
.button {
display: flex;
justify-content: center;
align-items: center;
font-weight: 300;
font-size: 1.3rem;
outline: 1px solid $lightDark;
color: $lightDark;
border-radius: 100px;
padding: 3px 15px;
cursor: pointer;
transition: $transition;
svg {
color: #000;
font-size: 1.2rem;
padding-left: 5px;
}
&:hover {
outline: 1px solid $dark;
color: white;
background-color: $dark;
}
&:hover > svg {
color: white;
}
}
.menuButton {
display: flex;
justify-content: center;
align-items: center;
font-size: 1.3rem;
font-weight: 300;
cursor: pointer;
outline: none !important;
svg {
padding-right: 2px;
font-size: 1.9rem;
}
&:hover {
outline: none !important;
}
}
.buttonModal {
position: absolute;
top: 35px;
right: -4px;
padding: 10px 5px;
min-width: 225px;
width: max-content;
max-width: max-content;
height: fit-content;
background-color: white;
border-radius: 7px;
box-shadow: 1px 3px 10px rgba(0, 0, 0, 0.2);
color: darken($primaryColor, 70%);
animation: fadeIn 0.2s linear;
z-index: 20;
&::after {
content: '';
position: absolute;
top: -7px;
right: 3px;
width: 15px;
height: 10px;
background-color: white;
box-shadow: -1px -30px 10px rgba(0, 0, 0, 0.6);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.modal-text {
padding: 0 10px;
}
.text {
font-size: 1.2rem;
}
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

View File

@@ -1,79 +0,0 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import React, {
ReactElement,
MouseEventHandler,
FunctionComponent,
} from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import './MenuButton.scss';
export interface MenuIconButtonComponentProps {
icon?: IconProp;
onClick?: MouseEventHandler;
modalContent?: ReactElement;
showModal?: boolean;
}
export interface MenuOutlineButtonComponentProps
extends MenuIconButtonComponentProps {
text?: string;
}
export const MenuIconButton: FunctionComponent<
MenuIconButtonComponentProps
> = ({
icon,
onClick,
showModal,
modalContent,
}: MenuIconButtonComponentProps): ReactElement => {
return (
<div className="buttonLayout">
<div className="iconButton" onClick={onClick}>
{icon && <FontAwesomeIcon icon={icon} />}
</div>
{showModal && <div className="buttonModal">{modalContent}</div>}
</div>
);
};
export const MenuOutlineButton: FunctionComponent<
MenuOutlineButtonComponentProps
> = ({
text,
icon,
onClick,
showModal,
modalContent,
}: MenuOutlineButtonComponentProps): ReactElement => {
return (
<div className="buttonLayout">
<div className={`button`} onClick={onClick}>
<span>{text}</span>
{icon && <FontAwesomeIcon icon={icon} />}
</div>
{showModal && <div className="buttonModal">{modalContent}</div>}
</div>
);
};
const MenuButton: FunctionComponent<MenuOutlineButtonComponentProps> = ({
text,
icon,
onClick,
showModal,
modalContent,
}: MenuOutlineButtonComponentProps): ReactElement => {
return (
<div className="buttonLayout">
<div className="menuButton" onClick={onClick}>
{icon && <FontAwesomeIcon icon={icon} />}
<span>{text}</span>
</div>
{showModal && <div className="buttonModal">{modalContent}</div>}
</div>
);
};
export default MenuButton;

View File

@@ -0,0 +1,10 @@
// basic colors
$color-black: #000000;
$color-white: #ffffff;
$color-grey: #575757;
$color-light-grey: rgb(144, 139, 139);
$color-very-light-grey: #F3F3F3;
// shadows
$color-box-shadow: rgba(0, 0, 0, 0.2);
$box-shadow: 1px 3px 10px $color-box-shadow;

View File

@@ -1,58 +0,0 @@
import React, {
ReactElement,
FunctionComponent,
useState,
MouseEventHandler,
} from 'react';
import { MenuOutlineButton } from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenuButton/MenuButton';
import TopbarMenu from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenu/TopbarMenu';
import MenuItem from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenu/MenuItem';
import {
faChevronDown,
faFileInvoice,
faRecycle,
faLink,
} from '@fortawesome/free-solid-svg-icons';
const CreateButton: FunctionComponent = (): ReactElement => {
const [showList, setShowList] = useState(false);
const toggle: Function = () => {
return setShowList(!showList);
};
return (
<MenuOutlineButton
text="Create"
icon={faChevronDown}
onClick={toggle as MouseEventHandler}
showModal={showList}
modalContent={
<TopbarMenu
legend="Online Payments"
items={[
<MenuItem
text="Invoice"
icon={faFileInvoice}
shortcuts={['c', 'i']}
key={1}
/>,
<MenuItem
text="Subscription"
icon={faRecycle}
shortcuts={['c', 's']}
key={2}
/>,
<MenuItem
text="Payment link"
icon={faLink}
shortcuts={['c', 'l']}
key={3}
/>,
]}
/>
}
/>
);
};
export default CreateButton;

View File

@@ -1,53 +0,0 @@
import React, {
FunctionComponent,
MouseEventHandler,
ReactElement,
useState,
} from 'react';
import MenuButton from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenuButton/MenuButton';
import MenuLinkItem from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenu/MenuLinkItem';
import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import TopbarMenu from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenu/TopbarMenu';
const HelpButton: FunctionComponent = (): ReactElement => {
const [showList, setShowList] = useState(false);
const toggle: Function = () => {
return setShowList(!showList);
};
return (
<MenuButton
icon={faQuestionCircle}
onClick={toggle as MouseEventHandler}
showModal={showList}
modalContent={
<>
<TopbarMenu
legend="Resources"
items={[
<MenuLinkItem
key={1}
text="Support articles"
openInNewTab={true}
/>,
<MenuLinkItem
key={2}
text="Developer docs"
openInNewTab={true}
/>,
<MenuLinkItem key={1} text="Keyboard shortcuts" />,
]}
/>
<hr />
<TopbarMenu
legend="Get in touch"
items={[<MenuLinkItem key={1} text="Share feedback" />]}
/>
</>
}
/>
);
};
export default HelpButton;

View File

@@ -1,24 +1,15 @@
import React, {
FunctionComponent,
MouseEventHandler,
ReactElement,
useState,
} from 'react';
import React, { FunctionComponent, ReactElement } from 'react';
import Container from 'CommonUI/src/Components/Dashboard/Container/Container/Container';
import Pagination from 'CommonUI/src/Components/Dashboard/Container/Container/Pagination';
import Table from 'CommonUI/src/Components/Dashboard/Table/Table';
import Button from 'CommonUI/src/Components/Basic/Button/Button';
import ButtonTypes from 'CommonUI/src/Components/Basic/Button/ButtonTypes';
import DropdownButton from 'CommonUI/src/Components/Basic/Button/DropdownButton';
import DropdownItem from 'CommonUI/src/Components/Basic/Button/DropdownItem';
import MenuButton from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuButton';
import MenuItem from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuItem';
import ShortcutKey from 'CommonUI/src/Components/Basic/ShortcutKey/ShortcutKey';
import { ColumnSort } from 'CommonUI/src/Components/Dashboard/Table/Type/Table';
const MonitorTable: FunctionComponent = (): ReactElement => {
const [showList, setShowList] = useState(false);
const toggleDropdown: Function = (): void => {
setShowList(!showList);
};
return (
<Container
title="Monitors"
@@ -39,16 +30,11 @@ const MonitorTable: FunctionComponent = (): ReactElement => {
</Pagination>
}
headerButtons={[
<DropdownButton
key={1}
title="Filter By"
onClick={toggleDropdown as MouseEventHandler}
showDropdown={showList}
>
<DropdownItem title="Clear Filters" />
<DropdownItem title="Unacknowledged" />
<DropdownItem title="Unresolved" />
</DropdownButton>,
<MenuButton key={1} title="Filter By">
<MenuItem title="Clear Filters" />
<MenuItem title="Unacknowledged" />
<MenuItem title="Unresolved" />
</MenuButton>,
<Button
key={2}
title="Create New Monitor"

View File

@@ -15,7 +15,7 @@ const CurrentProject: FunctionComponent = (): ReactElement => {
ref={ref}
className="preview"
onClick={() => {
return setIsComponentVisible(!isComponentVisible);
return setIsComponentVisible(true);
}}
>
<img src="/img/placeholder.png" alt="Project Image" />

View File

@@ -1,4 +1,4 @@
$primaryColor: rgb(246, 248, 250);
@use '../../../../CommonUI/src/Styles/BrandColors.scss';
.projectPreview {
position: relative;
@@ -20,13 +20,13 @@ $primaryColor: rgb(246, 248, 250);
padding: 0;
margin: 0;
font-size: 1.3rem;
color: rgb(77, 75, 75);
color: BrandColors.$color-grey;
font-weight: 400;
margin-right: 7px;
}
svg {
color: rgb(144, 139, 139);
color: BrandColors.$color-light-grey;
font-size: 1.2rem;
}
}
@@ -40,8 +40,8 @@ $primaryColor: rgb(246, 248, 250);
height: fit-content;
background-color: white;
border-radius: 5px;
box-shadow: 1px 3px 10px rgba(0, 0, 0, 0.2);
color: darken($primaryColor, 70%);
box-shadow: BrandColors.$box-shadow;
color: BrandColors.$color-grey;
animation: fadeIn 0.2s linear;
div {
@@ -71,8 +71,8 @@ $primaryColor: rgb(246, 248, 250);
}
&:hover {
color: $primaryColor !important;
background-color: #333;
color: BrandColors.$color-grey;
background-color: BrandColors.$color-very-light-grey;
}
}
}

View File

@@ -7,7 +7,6 @@ const SingleProject: FunctionComponent = (): ReactElement => {
<img src="/img/placeholder.png" alt="Project Image" />
<p>Project name</p>
</div>
<span>Edit</span>
</div>
);
};

View File

@@ -0,0 +1,20 @@
import React, { ReactElement, FunctionComponent } from 'react';
import MenuButton from 'CommonUI/src/Components/Dashboard/TopBar/MenuButton/MenuButton';
import MenuItem from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuItem';
import MenuLegend from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuLegend';
const CreateButton: FunctionComponent = (): ReactElement => {
return (
<MenuButton title={'Create'}>
<MenuLegend title={'Basic'} />
<MenuItem title="Monitors" />
<MenuItem title="Incident" />
<MenuItem title="Status Page" />
<MenuLegend title={'Advanced'} />
<MenuItem title="Automated Script" />
<MenuItem title="Logs" />
</MenuButton>
);
};
export default CreateButton;

View File

@@ -0,0 +1,21 @@
import React, { ReactElement, FunctionComponent } from 'react';
import MenuItem from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuItem';
import MenuLegend from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuLegend';
import IconButton from 'CommonUI/src/Components/Basic/Button/MenuButton/IconButton';
import { IconProp, SizeProp } from 'CommonUI/src/Components/Basic/Icon/Icon';
const CreateButton: FunctionComponent = (): ReactElement => {
return (
<IconButton icon={IconProp.Help} size={SizeProp.Large}>
<MenuLegend title="Basic" />
<MenuItem title="Monitors" />
<MenuItem title="Incident" />
<MenuItem title="Status Page" />
<MenuLegend title="Advanced" />
<MenuItem title="Automated Script" />
<MenuItem title="Logs" />
</IconButton>
);
};
export default CreateButton;

View File

@@ -0,0 +1,21 @@
import React, { ReactElement, FunctionComponent } from 'react';
import MenuItem from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuItem';
import MenuLegend from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuLegend';
import IconButton from 'CommonUI/src/Components/Basic/Button/MenuButton/IconButton';
import { IconProp, SizeProp } from 'CommonUI/src/Components/Basic/Icon/Icon';
const NotificationButton: FunctionComponent = (): ReactElement => {
return (
<IconButton icon={IconProp.Notification} size={SizeProp.Large}>
<MenuLegend title={'Basic'} />
<MenuItem title="Monitors" />
<MenuItem title="Incident" />
<MenuItem title="Status Page" />
<MenuLegend title={'Advanced'} />
<MenuItem title="Automated Script" />
<MenuItem title="Logs" />
</IconButton>
);
};
export default NotificationButton;

View File

@@ -1,12 +1,11 @@
import TopBar from 'CommonUI/src/Components/Dashboard/TopBar/TopBar';
import CurrentProject from '../../Components/ProjectPicker/CurrentProject';
import SearchBar from 'CommonUI/src/Components/Dashboard/TopBar/SearchBar/SearchBar';
import { MenuIconButton } from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenuButton/MenuButton';
import { faBell } from '@fortawesome/free-solid-svg-icons';
import CreateButton from '../../Components/CreateButton';
import HelpButton from '../../Components/HelpButton';
import UserProfileButton from '../../Components/UserProfile/UserProfileButton';
import CreateButton from './CreateButton';
import HelpButton from './HelpButton';
import UserProfileButton from './UserProfileButton';
import React, { FunctionComponent } from 'react';
import NotificationButton from './NotificationButton';
const TopBarComponent: FunctionComponent = () => {
return (
@@ -16,7 +15,7 @@ const TopBarComponent: FunctionComponent = () => {
rightContent={[
<CreateButton key={1} />,
<HelpButton key={2} />,
<MenuIconButton key={3} icon={faBell} />,
<NotificationButton key={3} />,
<UserProfileButton key={4} />,
]}
/>

View File

@@ -0,0 +1,17 @@
import React, { ReactElement, FunctionComponent } from 'react';
import MenuItem from 'CommonUI/src/Components/Basic/Button/MenuButton/MenuItem';
import UserInfo from 'CommonUI/src/Components/Dashboard/TopBar/UserProfile/UserInfo';
import { IconProp, SizeProp } from 'CommonUI/src/Components/Basic/Icon/Icon';
import IconButton from 'CommonUI/src/Components/Basic/Button/MenuButton/IconButton';
const CreateButton: FunctionComponent = (): ReactElement => {
return (
<IconButton icon={IconProp.User} size={SizeProp.Large}>
<UserInfo name="Username" role="Admin" />
<MenuItem title="Profile" />
<MenuItem title="Log out" />
</IconButton>
);
};
export default CreateButton;

View File

@@ -1,41 +0,0 @@
import React, {
ReactElement,
FunctionComponent,
useState,
MouseEventHandler,
} from 'react';
import TopbarMenu from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenu/TopbarMenu';
import MenuLinkItem from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenu/MenuLinkItem';
import { MenuIconButton } from 'CommonUI/src/Components/Dashboard/TopBar/TopbarMenuButton/MenuButton';
import { faUser } from '@fortawesome/free-solid-svg-icons';
import UserInfo from './UserInfo';
const UserProfileButton: FunctionComponent = (): ReactElement => {
const [showProfile, setShowProfile] = useState(false);
const toggle: Function = () => {
return setShowProfile(!showProfile);
};
return (
<MenuIconButton
icon={faUser}
showModal={showProfile}
onClick={toggle as MouseEventHandler}
modalContent={
<TopbarMenu
items={[
<UserInfo
name="Caleb Okpara"
role="Administrator"
key={1}
/>,
<MenuLinkItem text="Profile" key={2} />,
<MenuLinkItem text="Sign out" key={3} />,
]}
/>
}
/>
);
};
export default UserProfileButton;

View File

@@ -1,13 +1,20 @@
import React, { FunctionComponent, ReactElement } from 'react';
import PageContainer from 'CommonUI/src/Components/Dashboard/Container/PageContainer/PageContainer';
import PageComponentProps from '../PageComponentProps';
import Breadcrumbs from 'CommonUI/src/Components/Dashboard/Breadcrumbs/Breadcrumbs';
import BreadcrumbItem from 'CommonUI/src/Components/Dashboard/Breadcrumbs/BreadcrumbItem';
import { IconProp } from 'CommonUI/src/Components/Basic/Icon/Icon';
const Home: FunctionComponent<PageComponentProps> = (
_props: PageComponentProps
): ReactElement => {
return (
<PageContainer title="OneUptime | Home">
<div></div>
<Breadcrumbs icon={IconProp.Home} title="Home">
<BreadcrumbItem title="Home" />
<BreadcrumbItem title="Monitors" />
<div>Hello</div>
</Breadcrumbs>
</PageContainer>
);
};