Merge remote-tracking branch 'upstream/master' into feat/Integrations

This commit is contained in:
M M committed 2024-05-21 15:46:11 -07:00
commit 5ec8c70176
48 files changed
+2330 -710

No files matched your search

+2
View File
@@ -5,6 +5,7 @@ import Login from "./Pages/Login";
import Register from "./Pages/Register";
import HomeLayout from "./Layouts/HomeLayout";
import Demo from "./Pages/Demo/Demo";
import PlayGround from "./Pages/PlayGround/PlayGround";
function App() {
return (
@@ -15,6 +16,7 @@ function App() {
<Route exact path="/login" element={<Login />} />
<Route exact path="/demo" element={<Demo />} />
<Route path="*" element={<NotFound />} />
<Route path="/playground" element={<PlayGround />} />
</Routes>
</>
);
@@ -0,0 +1,71 @@
import "./announcementUpdateSubscription.css";
import React from "react";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.title - Title text for the update subscription dialog (required)
* @param {string} props.text - Body text for the update subscription dialog (required)
* @param {string} props.cancel - Text for the negative (cancel) button (required)
* @param {string} props.positive - Text for the positive button (required)
* @param {string} props.header - Title text for the email subscription section (required)
* @param {string} props.button - Text for the subscribe button (required)
* @returns {JSX.Element} - Renders the announcement update subscription component
*/
const AnnouncementUpdateSubscription = ({
title,
text,
cancel,
positive,
header,
button,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="update-subscription" style={{ fontFamily: fontFamily }}>
<div className="update-subscription-dialog">
<div className="subscription-dialog-title">{title}</div>
<div className="v-spacing-small"></div>
<div className="subscription-dialog-text">{text}</div>
<div className="v-spacing-medium"></div>
<div className="subscription-dialog-controls">
<button className="controls-negative">{cancel}</button>
<button className="controls-positive">{positive}</button>
</div>
<div className="v-spacing-medium"></div>
</div>
<div className="v-spacing-medium"></div>
<div className="update-subscription-title">{header}</div>
<div className="subscription-email">
<input
className="subscription-email-field"
type="text"
placeholder="olivia@untitledui.com"
/>
<button className="subscribe-button">{button}</button>
</div>
<div className="v-spacing-medium"></div>
</div>
);
};
AnnouncementUpdateSubscription.propTypes = {
title: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
cancel: PropTypes.string.isRequired,
positive: PropTypes.string.isRequired,
header: PropTypes.string.isRequired,
button: PropTypes.string.isRequired,
};
export default AnnouncementUpdateSubscription;
@@ -0,0 +1,103 @@
:root {
--update-subscription-color-0: #101828;
--update-subscription-color-1: #475467;
--update-subscription-color-2: #fff;
--update-subscription-color-3: #eaecf0;
--update-subscription-color-4: #7f56d9;
--update-subscription-color-5: #1570ef;
--update-subscription-color-6: #344054;
--update-subscription-color-7: #d0d5dd;
--update-subscription-padding-0: 12px 16px;
--update-subscription-margin-right: 12px;
--update-subscription-font-size: 13px;
--update-subscription-radius-0: 4px;
--spacing-1: 16px;
--spacing-2: 20px;
}
.update-subscription {
margin: var(--spacing-2);
}
.update-subscription,
.update-subscription-dialog {
max-width: 770px;
border-radius: 4px;
border: 1px solid #eaecf0;
}
.update-subscription-dialog {
padding: 15px 30px;
}
.subscription-dialog-title {
font-size: 1rem;
font-weight: 700;
color: var(--update-subscription-color-0);
}
.v-spacing-small {
height: 10px;
}
.v-spacing-medium {
height: 15px;
}
.subscription-dialog-text {
font-size: 13px;
color: var(--update-subscription-color-1);
}
.subscription-dialog-controls {
display: flex;
}
.controls-negative {
padding: var(--update-subscription-padding-0);
margin-right: var(--update-subscription-margin-right);
border-radius: var(--update-subscription-radius-0);
border: 1px solid var(--update-subscription-color-3);
background-color: var(--update-subscription-color-2);
font-size: var(--update-subscription-font-size);
}
.controls-positive,
.subscribe-button {
padding: var(--update-subscription-padding-0);
margin-right: var(--update-subscription-margin-right);
border-radius: var(--update-subscription-radius-0);
border: 1px solid var(--update-subscription-color-4);
background-color: var(--update-subscription-color-5);
color: var(--update-subscription-color-2);
font-size: var(--update-subscription-font-size);
}
.update-subscription-title {
color: var(--update-subscription-color-6);
padding: 0 var(--spacing-2);
font-weight: 700;
font-size: 13px;
margin-bottom: 10px;
}
.subscription-email {
display: flex;
padding: 0 var(--spacing-2);
}
.subscription-email-field {
width: 290px;
height: 24px;
border-radius: var(--update-subscription-radius-0);
border: 1px solid var(--update-subscription-color-7);
box-shadow: 0px 1px 2px 0px rgba(101, 182, 28, 0.05);
padding: 5px 15px;
margin-right: var(--spacing-2);
}
.subscribe-button {
width: 100px;
height: 34px;
padding: 2px 15px;
}
@@ -0,0 +1,55 @@
import "./announcementsDualButton.css";
import React from "react";
import CloseIcon from "@mui/icons-material/Close";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.subject - The announcement subject text
* @param {string} props.body - The announcement body text content
* @param {string} props.esc - The text for the escape button
* @param {string} props.primary - The text for the primary button
* @returns {JSX.Element} - Renders the announcement dual button component
*/
const AnnouncementsDualButton = ({ subject, body, esc, primary }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div
className="announcement-without-tile"
style={{ fontFamily: fontFamily }}
>
<div className="announcement-without-content">
<div className="announcement-without-content-subject">{subject}</div>
<div className="v-spacing"></div>
<div className="announcement-without-content-body">{body}</div>
<div className="announcement-content-controllers">
<div className="controllers-button-esc">{esc}</div>
<div className="controllers-button-primary">{primary}</div>
</div>
</div>
<div className="h-spacing"></div>
<div className="announcement-close">
<CloseIcon style={{ fill: "#98A2B3" }} />
</div>
</div>
);
};
AnnouncementsDualButton.propTypes = {
subject: PropTypes.string.isRequired,
body: PropTypes.string.isRequired,
esc: PropTypes.string.isRequired,
primary: PropTypes.string.isRequired,
};
export default AnnouncementsDualButton;
@@ -0,0 +1,38 @@
:root {
--announcement-border-color: #d0d5dd;
--announcement-border-radius: 4px;
--announcement-border-radius-2: 8px;
--announcement-font-size-0: 13px;
--announcement-font-color-0: #344054;
--announcement-font-color-1: #475467;
--announcement-font-color-2: #1570ef;
--announcement-padding: 16px;
--info-icon-frame-color: #eaecf0;
--margin: 20px;
}
.announcement-without-tile {
margin: var(--margin);
max-width: 343px;
width: fit-content;
display: flex;
border: 1px solid var(--announcement-border-color);
padding: var(--announcement-padding);
border-radius: var(--announcement-border-radius);
}
.h-spacing {
width: 20px;
}
.announcement-without-content-subject {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-0);
font-weight: 700;
margin-bottom: 10px;
}
.announcement-without-content-body {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-1);
}
@@ -0,0 +1,65 @@
import "./announcementsDualButtonWithIcon.css";
import React from "react";
import CloseIcon from "@mui/icons-material/Close";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {React.ReactNode} props.icon - Optional React node for an announcement icon
* @param {string} props.subject - The announcement subject text
* @param {string} props.body - The announcement body text content
* @param {string} props.esc - The text for the escape button (usually "Close")
* @param {string} props.primary - The text for the primary button
* @returns {JSX.Element} - Renders the announcement dual button with icon component
*/
const AnnouncementsDualButtonWithIcon = ({
icon,
subject,
body,
esc,
primary,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="announcement-tile" style={{ fontFamily: fontFamily }}>
{icon && <div className="announcement-icon">{icon}</div>}
<div className="announcement-content">
{subject && (
<div className="announcement-content-subject">{subject}</div>
)}
{body && <div className="announcement-content-body">{body}</div>}
{(esc || primary) && (
<div className="announcement-content-controllers">
{esc && <div className="controllers-button-esc">{esc}</div>}
{primary && (
<div className="controllers-button-primary">{primary}</div>
)}
</div>
)}
</div>
<div className="announcement-close">
<CloseIcon style={{ fill: "#98A2B3" }} />
</div>
</div>
);
};
AnnouncementsDualButtonWithIcon.propTypes = {
icon: PropTypes.object,
subject: PropTypes.string,
body: PropTypes.string,
esc: PropTypes.string,
primary: PropTypes.string,
};
export default AnnouncementsDualButtonWithIcon;
@@ -0,0 +1,71 @@
:root {
--announcement-border-color: #d0d5dd;
--announcement-border-radius: 4px;
--announcement-border-radius-2: 8px;
--announcement-font-size-0: 13px;
--announcement-font-color-0: #344054;
--announcement-font-color-1: #475467;
--announcement-font-color-2: #1570ef;
--announcement-padding: 16px;
--info-icon-frame-color: #eaecf0;
--tile-margin: 20px;
}
.announcement-tile {
margin: var(--tile-margin);
width: fit-content;
display: flex;
border: 1px solid var(--announcement-border-color);
padding: var(--announcement-padding);
border-radius: var(--announcement-border-radius);
}
.info-icon-frame {
display: flex;
width: 40px;
height: 40px;
border: 1px solid var(--info-icon-frame-color);
border-radius: var(--announcement-border-radius-2);
justify-content: center;
align-items: center;
}
.announcement-content {
padding: 0 var(--announcement-padding);
}
.announcement-content-subject {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-0);
font-weight: 700;
margin-bottom: 10px;
}
.announcement-content-body {
font-size: var(--announcement-font-size-0);
color: var(--announcement-font-color-1);
font-weight: 300;
}
.announcement-content-controllers {
display: flex;
font-size: var(--announcement-font-size-0);
margin-top: 15px;
}
.controllers-button-esc {
font-size: var(--announcement-font-size-0);
font-weight: 600;
margin-right: 12px;
}
.controllers-button-primary {
font-size: var(--announcement-font-size-0);
font-weight: 600;
color: var(--announcement-font-color-2);
}
.announcement-close {
width: 24px;
height: 24px;
}
@@ -0,0 +1,36 @@
import "./announcementsMessageBar.css";
import React from "react";
import CloseIcon from "@mui/icons-material/Close";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.message - The announcement message text content (required)
* @returns {JSX.Element} - Renders the announcement message bar component
*/
const AnnouncementsMessageBar = ({ message }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="announcement-tile" style={{ fontFamily: fontFamily }}>
<div className="announcement-messagebar-body">{message}</div>
<div className="announcement-close">
<CloseIcon style={{ fill: "#98A2B3" }} />
</div>
</div>
);
};
AnnouncementsMessageBar.propTypes = {
message: PropTypes.string.isRequired,
};
export default AnnouncementsMessageBar;
@@ -0,0 +1,14 @@
:root {
--announcement-font-size-0: 13px;
--announcement-padding: 16px;
--margin: 20px;
}
.announcement-messagebar-body {
margin: var(--margin);
font-size: var(--announcement-font-size-0);
padding: 0 var(--announcement-padding) 0 0;
justify-content: center;
align-items: center;
margin: auto;
}
@@ -0,0 +1,37 @@
import React from "react";
import "./serverStatus.css";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.title - The title text for the server status (required)
* @param {string} props.value - The value text to be displayed (required)
* @param {string} props.state - The state of the server (e.g., "online", "offline", "warning") (required)
* @returns {JSX.Element} - Renders the server status component
*/
const ServerStatus = ({ title, value, state }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="server-status-tile" style={{ fontFamily: fontFamily }}>
<div className="server-status-tile-title">{title}</div>
<div className={`server-status-tile-value ` + " " + state}>{value}</div>
</div>
);
};
ServerStatus.propTypes = {
title: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
state: PropTypes.string.isRequired,
};
export default ServerStatus;
@@ -0,0 +1,44 @@
:root {
--spacing-general-0: 10px 25px;
--spacing-general-1: 20px;
--color-border-0: #eaecf0;
--border-radius-0: 4px;
--font-size-0: 1rem;
--font-size-2: 36px;
--color-up: #17b26a;
--color-down: #f04438;
--color-pause: #fdb022;
}
.server-status-tile {
width: 230px;
margin: var(--spacing-general-0);
margin-left: 10px;
padding: var(--spacing-general-1);
border: 1px solid var(--color-border-0);
border-radius: var(--border-radius-0);
}
.server-status-tile-title {
font-size: var(--font-size-0);
font-weight: bold;
margin-bottom: 25px;
}
.server-status-tile-value {
font-size: var(--font-size-2);
font-weight: bolder;
}
.up {
color: var(--color-up);
}
.down {
color: var(--color-down);
}
.pause {
color: var(--color-pause);
}
@@ -0,0 +1,35 @@
import React from "react";
import "./statistic.css";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.title - The title text for the statistic (required)
* @param {string} props.value - The numerical or textual value for the statistic (required)
* @returns {JSX.Element} - Renders the statistic component
*/
const Statistic = ({ title, value }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="statistic-tile" style={{ fontFamily: fontFamily }}>
<div className="statistic-tile-title">{title}</div>
<div className="statistic-tile-value">{value}</div>
</div>
);
};
Statistic.propTypes = {
title: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
};
export default Statistic;
@@ -0,0 +1,31 @@
:root {
--stats-spacing-general-0: 5px 10px;
--color-border-0: #eaecf0;
--border-radius-0: 4px;
--font-size-0: 1rem;
--font-size-1: 13px;
--font-color-0: #344054;
--margin-bottom-0: 10px;
}
.statistic-tile {
margin: var(--stats-spacing-general-0);
padding: var(--stats-spacing-general-0);
border: 1px solid var(--color-border-0);
border-radius: var(--border-radius-0);
width: 180px;
}
.statistic-tile-title {
font-size: var(--font-size-0);
color: var(--font-color-0);
margin-bottom: var(--margin-bottom-0);
}
.statistic-tile-value {
font-size: var(--font-size-1);
color: var(--font-color-0);
font-weight: 700;
margin-bottom: var(--margin-bottom-0);
}
@@ -0,0 +1,36 @@
import "./complexAlert.css";
import React from "react";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import PropTypes from "prop-types";
/**
* @component
* @param {Object} props
* @param {"red" | "green"} props.theme - The color theme for the alert (required) - must be either "red" or "green"
* @returns {JSX.Element} - Renders the complex alert component with dynamic color theme
*/
const ComplexAlert = ({ theme }) => {
if (theme === "red") {
return (
<div className="icon-holder-outer-red">
<div className="icon-holder-inner-red">
<ErrorOutlineIcon className="icon-core" style={{ fill: "#D92D20" }} />
</div>
</div>
);
} else if (theme === "green") {
return (
<div className="icon-holder-outer-green">
<div className="icon-holder-inner-green">
<ErrorOutlineIcon className="icon-core" style={{ fill: "#079455" }} />
</div>
</div>
);
}
};
ComplexAlert.propTypes = {
theme: PropTypes.string.isRequired,
};
export default ComplexAlert;
@@ -0,0 +1,44 @@
.icon-holder-outer-red {
width: 38px;
height: 38px;
border-radius: 50%;
border: 2px solid #d92d2019;
display: flex;
justify-content: center;
align-items: center;
}
.icon-holder-inner-red {
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid #d92d204d;
display: flex;
justify-content: center;
align-items: center;
}
.icon-holder-outer-green {
width: 38px;
height: 38px;
border-radius: 50%;
border: 2px solid #07945519;
display: flex;
justify-content: center;
align-items: center;
}
.icon-holder-inner-green {
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid #0794554d;
display: flex;
justify-content: center;
align-items: center;
}
.icon-core {
width: 20px;
height: 20px;
}
@@ -0,0 +1,55 @@
import "./dualButtonPopupModal.css";
import React from "react";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {boolean} [props.open=true] - Controls the visibility of the modal (defaults to true)
* @param {string} props.subject - The title text for the modal (required)
* @param {string} props.description - The description text for the modal (required)
* @param {string} props.esc - The text for the discard button (usually "Cancel", "Dismiss" or "Discard") (required)
* @param {string} props.save - The text for the save button (required)
* @returns {JSX.Element} - Renders the dual button popup modal component
*/
const DualButtonPopupModal = ({
open = true,
subject,
description,
esc,
save,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div
className="dual-button-popup-modal-holder"
style={{ fontFamily: fontFamily }}
>
<div className="dual-button-popup-modal-subject">{subject}</div>
<div className="dual-button-popup-modal-description">{description}</div>
<div className="dual-modal-spacing"></div>
<div className="dual-button-popup-modal-controllers">
<button className="transparent-discard-button">{esc}</button>
<button className="blue-save-button">{save}</button>
</div>
</div>
);
};
DualButtonPopupModal.propTypes = {
open: PropTypes.bool,
subject: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
esc: PropTypes.string.isRequired,
save: PropTypes.string.isRequired,
};
export default DualButtonPopupModal;
@@ -0,0 +1,60 @@
:root {
--popup-color-border-0: #f2f2f2;
--popup-color-0: #101828;
--popup-color-1: #475467;
--color-0: #1570ef;
--color-1: #175cd3;
}
.dual-button-popup-modal-holder {
width: 380px;
height: 130px;
margin: 10px 20px;
padding: 30px;
box-shadow: 0px 8px 8px -4px rgba(16, 24, 40, 0.03),
0px 20px 24px -4px rgba(16, 24, 40, 0.08);
border: 1px solid var(--popup-color-border-0);
border-radius: 4px;
}
.dual-button-popup-modal-subject {
color: var(--popup-color-0);
font-weight: bolder;
font-size: 16px;
}
.dual-button-popup-modal-description {
color: var(--popup-color-1);
font-size: 13px;
margin-top: 10px;
}
.dual-modal-spacing {
height: 40px;
}
.dual-button-popup-modal-controllers {
display: flex;
justify-content: end;
}
.blue-save-button {
width: 145px;
height: 35px;
padding: 5px 20px;
background-color: var(--color-0);
border: 1px solid var(--color-1);
border-radius: 4px;
margin: 5px 0;
margin-left: 20px;
color: white;
cursor: pointer;
font-size: 13px;
}
.transparent-discard-button {
border: none;
background-color: transparent;
margin: 5px 10px;
font-size: 13px;
}
@@ -0,0 +1,73 @@
import "./dualButtonPopupModalWithTextfields.css";
import React from "react";
import CloseIcon from "@mui/icons-material/Close";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.title - The title text for the modal (required)
* @returns {JSX.Element} - Renders a single text field component within a popup modal
*/
const PopupModalTextfield = ({ title }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="popup-modal-input" style={{ fontFamily: fontFamily }}>
<div className="popup-modal-input-title">{title}</div>
<input type="text" className="popup-modal-text-field" />
</div>
);
};
/**
* @component
* @param {Object} props
* @param {string} props.title - The title text for the modal (required)
* @param {string} props.esc - The text for the cancel button (required)
* @param {string} props.save - The text for the save button (required)
* @returns {JSX.Element} - Renders the dual button popup modal component with text fields
*/
const DualButtonPopupModalWithTextfields = ({ title, esc, save }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="popup-modal-holder" style={{ fontFamily: fontFamily }}>
<div className="popup-modal-header">
<div className="popup-modal-title">{title}</div>
<div className="popup-modal-close">
<CloseIcon style={{ fill: "#98A2B3" }} />
</div>
</div>
<div className="spacing-height"></div>
<PopupModalTextfield title="Name" />
<div className="spacing-height"></div>
<div className="spacing-height"></div>
<div className="popup-modal-controllers">
<button className="white-cancel-button">{esc}</button>
<button className="blue-save-button">{save}</button>
</div>
</div>
);
};
DualButtonPopupModalWithTextfields.propTypes = {
title: PropTypes.string.isRequired,
esc: PropTypes.string.isRequired,
save: PropTypes.string.isRequired,
};
export default DualButtonPopupModalWithTextfields;
@@ -0,0 +1,61 @@
:root {
--popup-color-with-input-border-0: #f2f2f2;
--popup-color-with-input-border-1: #d0d5dd;
--popup-modal-with-input-title-color: #344054;
}
.popup-modal-holder {
width: 480px;
font-family: var(--popup-font-family-0);
padding: 50px 40px;
border-radius: 4px;
margin: 10px 20px;
border: 1px solid var(--popup-color-with-input-border-0);
box-shadow: 0px 8px 8px -4px rgba(16, 24, 40, 0.03),
0px 20px 24px -4px rgba(16, 24, 40, 0.08);
}
.popup-modal-header {
display: flex;
justify-content: space-between;
font-weight: bold;
}
.popup-modal-close {
cursor: pointer;
}
.spacing-height {
height: 30px;
}
.popup-modal-input-title {
margin-bottom: 15px;
color: var(--popup-modal-with-input-title-color);
}
.popup-modal-text-field {
width: 100%;
height: 35px;
border: 1px solid var(--popup-color-with-input-border-1);
border-radius: 4px;
}
.popup-modal-controllers {
display: flex;
justify-content: end;
}
.white-cancel-button {
border: none;
background-color: transparent;
font-family: var(--popup-font-family-0);
margin: 5px 10px;
width: 145px;
height: 35px;
padding: 5px 20px;
border: 1px solid var(--popup-color-with-input-border-1);
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
@@ -0,0 +1,47 @@
import React from "react";
import "./descriptionTextField.css";
import { TextField } from "@mui/material";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.hintText - The hint text displayed within the text field (required)
* @param {boolean} props.hasError - A flag indicating if the text field has an error (required)
* @returns {JSX.Element} - Renders the description text field component
*/
const DescriptionTextField = ({ hintText, hasError }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div
className="description-field-holder"
style={{ fontFamily: fontFamily }}
>
<div className="text-field-title">Description</div>
<TextField
id="description-field-area"
error={hasError}
className="description-field-area"
multiline
rows={4}
placeholder="Enter a description..."
helperText={hintText}
/>
</div>
);
};
DescriptionTextField.propTypes = {
hintText: PropTypes.string.isRequired,
hasError: PropTypes.bool.isRequired,
};
export default DescriptionTextField;
@@ -0,0 +1,45 @@
:root {
--color-title-1: #344054;
--text-field-margin-0: 10px 20px;
--description-color-0: #344054;
}
.description-field-holder {
margin: var(--text-field-margin-0);
margin-top: 20px;
}
.text-field-title {
color: var(--color-title-1);
font-weight: bold;
margin-bottom: 10px;
font-size: 13px;
color: var(--description-color-0);
font-weight: bold;
}
.description-field-area {
min-width: 320px;
font-size: 13px;
border-radius: 8px;
}
.description-field-label {
margin-top: 10px;
font-size: 11px;
}
.with-error {
color: red;
}
#description-field-area-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: 11px;
}
#description-field-area {
min-width: 320px;
font-size: 13px;
}
@@ -0,0 +1,88 @@
import React, { useState } from "react";
import "./emailTextField.css";
import { InputAdornment, TextField } from "@mui/material";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.id - Unique ID for the text field (optional)
* @param {string} props.label - The label text displayed above the text field (optional)
* @param {"standard" | "outlined" | "filled"} props.variant - The variant of the text field (e.g., "outlined") (optional)
* @param {string} props.placeholder - The placeholder text displayed within the text field (optional)
* @param {"error" | "help"} [props.icon] - The type of icon to display (error or help) (optional)
* @param {string} props.helperText - The helper text displayed below the text field (optional)
* @param {boolean} props.error - A flag indicating if the text field has an error (required)
* @returns {JSX.Element} - Renders the email text field component with dynamic icon display
*/
const EmailTextField = ({
id,
label,
variant,
placeholder,
icon,
helperText,
error,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
const [showIcon, setShowIcon] = useState(false);
const handleMouseEnter = () => setShowIcon(true);
const handleMouseLeave = () => setShowIcon(false);
return (
<div style={{ fontFamily: fontFamily }}>
<div className="email-text-field-title">Email</div>
<div className="email-text-field">
<TextField
error={error}
className="email-text-field-input"
id={id}
label={label}
variant={variant}
placeholder={placeholder}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<div className="icon-holder">
{error && showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{error && !showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{!error && showIcon && (
<HelpOutlineIcon
className="text-field-icon"
style={{ width: "16px", height: "16px" }}
/>
)}
</div>
</InputAdornment>
),
}}
helperText={helperText}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
/>
</div>
</div>
);
};
export default EmailTextField;
@@ -0,0 +1,41 @@
:root {
--textfield-color-0: #344054;
}
.email-text-field {
position: relative;
margin: 10px 20px;
}
#outlined-basic {
width: 320px;
height: 14px;
font-size: 13px;
padding: 8px 12px;
}
.email-text-field-title {
margin: 0 20px;
margin-top: 30px;
font-size: 13px;
color: var(--textfield-color-0);
font-weight: bold;
}
#outlined-basic-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: 11px;
}
.text-field-icon {
width: 16px;
height: 16px;
}
.icon-holder {
width: 16px;
height: 16px;
padding: 0;
margin: 0;
}
@@ -0,0 +1,72 @@
import React, { useState } from "react";
import "./websiteTextField.css";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {boolean} [props.showHelp=true] - Controls the visibility of the help icon (defaults to true)
* @param {boolean} [props.hasCopyButton=false] - Controls the visibility of the copy button (defaults to false)
* @param {string} props.hintText - The hint text displayed below the text field (required)
* @returns {JSX.Element} - Renders the website text field component with optional help and copy features
*/
const WebsiteTextField = ({
showHelp = true,
hasCopyButton = false,
hintText,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
const [copied, setCopied] = useState(false);
const handleCopy = () => {
setCopied(true);
setTimeout(() => setCopied(false), 1000);
};
return (
<div style={{ fontFamily: fontFamily }}>
<div className="website-textfield-title">Website</div>
<div className="website-textfield">
<label className="website-label">http://</label>
<input
type="url"
name="website-url"
id="website-url"
className="website-url"
/>
{showHelp && (
<div
className={
`website-icon-holder ` + !hasCopyButton
? "with-no-copy-button"
: ""
}
>
<HelpOutlineIcon style={{ fill: "var(--icon-color)" }} />
</div>
)}
{hasCopyButton && (
<div className="copy-to-clipboard-button" onClick={handleCopy}>
<ContentCopyIcon
className="copy-icon"
style={{ width: "20px", height: "20px" }}
/>
<span className="">{copied ? " Copied " : " Copy "}</span>
</div>
)}
</div>
<label className="website-textfield-hint">{hintText}</label>
</div>
);
};
export default WebsiteTextField;
@@ -0,0 +1,82 @@
:root {
--website-color-0: #344054;
--border-color: #d0d5dd;
--label-font-color: #475467;
--icon-color: #98a2b3;
--text-field-margin-0: 10px 20px;
--text-field-margin-1: 10px 20px 5px;
}
.website-textfield-title {
margin: 0 20px;
margin-top: 30px;
font-size: 13px;
color: var(--website-color-0);
font-weight: bold;
}
.website-textfield {
display: flex;
align-items: center;
position: relative;
margin: var(--text-field-margin-1);
}
.website-textfield-hint {
margin: var(--text-field-margin-0);
font-size: 11px;
}
.website-label {
padding: 6px 20px 6px 10px;
border: solid 1px var(--border-color);
border-right: none;
border-radius: 4px 0 0 4px;
font-size: 13px;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
color: var(--label-font-color);
}
.website-url {
width: 248px;
height: 31.5px;
padding: 0px 15px;
border: solid 1px var(--border-color);
}
.website-icon-holder {
width: 40px;
height: 33px;
padding: 5px;
border: solid 1px var(--border-color);
border-left: none;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.copy-to-clipboard-button {
padding: 5.5px 20px 6px 10px;
border: solid 1px var(--border-color);
border-left: none;
border-radius: 0 8px 8px 0;
font-size: 13px;
text-align: center;
display: flex;
justify-content: space-evenly;
align-items: center;
color: var(--label-font-color);
cursor: pointer;
}
.copy-icon {
margin-right: 5px;
}
.with-no-copy-button {
display: none;
}
@@ -0,0 +1,45 @@
import "./tooltipWithTail.css";
import React from "react";
import { styled } from "@mui/material/styles";
import Tooltip, { tooltipClasses } from "@mui/material/Tooltip";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
const CustomizedTooltip = styled(
({ className, placement, arrow, ...props }) => (
<Tooltip
{...props}
placement={placement}
arrow={arrow}
classes={{ popper: className }}
/>
)
)(({ theme }) => ({
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: "black",
},
[`& .${tooltipClasses.arrow}`]: {
color: "black",
},
}));
function TooltipWithTail({ placement, arrow = false, title, text }) {
return (
<div>
<CustomizedTooltip
arrow={arrow}
placement={placement}
title={
<React.Fragment>
{title && <div className="tooltip-title">{title}</div>}
<div className="tooltip-description">{text}</div>
</React.Fragment>
}
className="tooltip-holder"
>
<HelpOutlineIcon style={{ fill: "#98A2B3" }} />
</CustomizedTooltip>
</div>
);
}
export default TooltipWithTail;
@@ -0,0 +1,17 @@
:root {
--tooltip-color-0: #d0d5dd;
--tooltip-margin: 5px;
--tooltip-font-size: 12px;
}
.tooltip-title {
font-size: var(--tooltip-font-size);
font-weight: bold;
margin: var(--tooltip-margin);
}
.tooltip-description {
font-size: var(--tooltip-font-size);
color: var(--tooltip-color-0);
margin: var(--tooltip-margin);
}
@@ -0,0 +1,25 @@
import React from "react";
import "./playGround.css";
import Statistic from "../../Components/Charts/Statistics/Statistic";
import ServerStatus from "../../Components/Charts/Servers/ServerStatus";
function PlayGroundCharts() {
return (
<>
<div className="play-ground-charts">
<Statistic title="Currently up for" value="4h 30m 2s" />
<Statistic title="Last checked" value="15 seconds ago" />
<Statistic title="Incidents" value="2" />
<Statistic title="Certificate expiry" value="284 days" />
</div>
<div className="play-ground-charts-spacing" />
<div className="play-ground-charts">
<ServerStatus title="Up" value="4" state="up" />
<ServerStatus title="Down" value="0" state="down" />
<ServerStatus title="Paused" value="0" state="pause" />
</div>
</>
);
}
export default PlayGroundCharts;
@@ -0,0 +1,25 @@
import React from "react";
import DualButtonPopupModal from "../../Components/PopupModals/DualButtonPopupModal/DualButtonPopupModal";
import DualButtonPopupModalWithTextfields from "../../Components/PopupModals/DualButtonPopupModalWithTextfields/DualButtonPopupModalWithTextfields";
function PlayGroundPopupModals() {
return (
<div style={{ display: "flex" }}>
<DualButtonPopupModal
subject="Unsaved changes"
description="Do you want to save or discard changes?"
esc="Discard"
save="Save changes"
/>
<br />
<br />
<DualButtonPopupModalWithTextfields
title="Create new organization"
esc="Cancel"
save="Save"
/>
</div>
);
}
export default PlayGroundPopupModals;
@@ -0,0 +1,34 @@
import React from "react";
import TooltipWithTail from "../../Components/Tooltips/TooltipWithTail/TooltipWithTail";
import "./playGround.css";
function PlayGroundTooltips() {
return (
<div className="tooltip-playground">
<br />
<TooltipWithTail
placement="left"
arrow={true}
title="This is a tooltip"
text="This is a tooltip"
/>
<br />
<TooltipWithTail placement="top" arrow={true} text="This is a tooltip" />
<br />
<TooltipWithTail
placement="bottom"
arrow={false}
text="This is a tooltip"
/>
<br />
<TooltipWithTail
placement="right"
arrow={true}
title="This is a tooltip"
text="Tooltips are used to describe or identify an element. In most scenarios, tooltips help the user understand meaning, function or alt-text."
/>
</div>
);
}
export default PlayGroundTooltips;
@@ -0,0 +1,73 @@
import "./playGround.css";
import React from "react";
import AnnouncementsDualButtonWithIcon from "../../Components/Announcements/AnnouncementsDualButtonWithIcon/AnnouncementsDualButtonWithIcon";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import ComplexAlert from "../../Components/Icons/ComplexAlert/ComplexAlert";
import AnnouncementsMessageBar from "../../Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar";
import AnnouncementsDualButton from "../../Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton";
import AnnouncementUpdateSubscription from "../../Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription";
function PlayGroundAnnouncements() {
return (
<div className="playground">
<AnnouncementsDualButtonWithIcon
icon={
<div className="info-icon-frame">
<InfoOutlinedIcon style={{ fill: "#344054" }} />
</div>
}
subject="We’ve just released a new feature"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="View changes"
/>
<br />
<br />
<AnnouncementsDualButtonWithIcon
icon={<ComplexAlert theme="red" />}
subject="There was a problem with that action"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="Learn more"
/>
<br />
<br />
<AnnouncementsDualButtonWithIcon
icon={<ComplexAlert theme="green" />}
subject="Successfully updated profile"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="Learn more"
/>
<br />
<br />
<AnnouncementsDualButton
subject="We’ve just released a new feature"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="View changes"
/>
<br />
<br />
<AnnouncementsMessageBar message="New employee created successfully" />
<br />
<br />
<AnnouncementUpdateSubscription
title="We’ve just released a new update!"
text="Check out the all new dashboard view. Pages and now load faster."
cancel="Dismiss"
positive="Changelog"
header="Subscribe to updates"
button="Subscribe"
/>
<br />
<br />
</div>
);
}
export default PlayGroundAnnouncements;
+126
View File
@@ -0,0 +1,126 @@
import React from "react";
import EmailTextField from "../../Components/TextFields/Email/EmailTextField";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import WebsiteTextField from "../../Components/TextFields/Website/WebsiteTextField";
import DescriptionTextField from "../../Components/TextFields/Description/DescriptionTextField";
import AnnouncementsDualButton from "../../Components/Announcements/AnnouncementsDualButton/AnnouncementsDualButton";
import AnnouncementsDualButtonWithIcon from "../../Components/Announcements/AnnouncementsDualButtonWithIcon/AnnouncementsDualButtonWithIcon";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import ComplexAlert from "../../Components/Icons/ComplexAlert/ComplexAlert";
import AnnouncementsMessageBar from "../../Components/Announcements/AnnouncementsMessageBar/AnnouncementsMessageBar";
import AnnouncementUpdateSubscription from "../../Components/Announcements/AnnouncementUpdateSubscription/AnnouncementUpdateSubscription";
import PlayGroundCharts from "./PlayGround-Charts";
import PlayGroundPopupModals from "./PlayGround-Popup-Modals";
import PlayGroundTooltips from "./PlayGround-Tooltips";
// This Component is just for the development and test
// purposes and just to see what my components look like while development
// and will be removed in the end
function PlayGround() {
return (
<div>
{/* Default state of Email Text Fields */}
<EmailTextField
error={false}
placeholder="olivia@untitledui.com"
id="outlined-basic"
helperText="This is a hint text to help user."
/>
{/* Email Text Field when validation error occures */}
<EmailTextField
error={true}
placeholder="olivia@untitledui.com"
id="outlined-basic"
icon={<ErrorOutlineIcon style={{ fill: "red" }} />}
helperText="This is an error message"
/>
{/* Email Text Field while mouse hover */}
<EmailTextField
error={false}
placeholder="olivia@untitledui.com"
id="outlined-basic"
icon={<HelpOutlineIcon />}
helperText="This is a hint text to help user."
/>
<hr />
{/* Now, illustration of the Website text fields */}
<WebsiteTextField hintText="This is a hint text to help user." />
<WebsiteTextField
hasCopyButton={true}
hintText="This is a hint text to help user."
/>
<hr />
{/* Now, illustration of the Description text fields */}
<DescriptionTextField
hasError={false}
hintText="This is a hint text to help user."
/>
<DescriptionTextField
hasError={true}
hintText="This is a hint text to help user."
/>
<AnnouncementsDualButtonWithIcon
icon={
<div className="info-icon-frame">
<InfoOutlinedIcon style={{ fill: "#344054" }} />
</div>
}
subject="We’ve just released a new feature"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="View changes"
/>
<AnnouncementsDualButtonWithIcon
icon={<ComplexAlert theme="red" />}
subject="There was a problem with that action"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="Learn more"
/>
<AnnouncementsDualButtonWithIcon
icon={<ComplexAlert theme="green" />}
subject="Successfully updated profile"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="Learn more"
/>
<AnnouncementsDualButton
subject="We’ve just released a new feature"
body="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid
pariatur, ipsum dolor."
esc="Dismiss"
primary="View changes"
/>
<AnnouncementsMessageBar message="New employee created successfully" />
<AnnouncementUpdateSubscription
title="We’ve just released a new update!"
text="Check out the all new dashboard view. Pages and now load faster."
cancel="Dismiss"
positive="Changelog"
header="Subscribe to updates"
button="Subscribe"
/>
<hr />
<PlayGroundCharts />
<hr />
<PlayGroundPopupModals />
<hr />
<PlayGroundTooltips />
</div>
);
}
export default PlayGround;
@@ -0,0 +1,19 @@
.play-ground-charts {
display: flex;
}
.play-ground-charts-spacing {
height: 110px;
}
.tooltip-playground {
margin: auto;
padding: 5%;
width: 5%;
justify-content: center;
text-align: center;
}
.playground {
padding: 40px;
}
+9
View File
@@ -16,6 +16,10 @@ const labelRed = "#F04438";
//Section colros
const sectionBorder = "#D0D5DD";
const sectionBg = "#F8F9F8";
// Global Font Family
const fontFamilyDefault = '"Roboto", "Helvetica", "Arial", sans-serif';
const theme = createTheme({
palette: {
primary: {
@@ -48,6 +52,11 @@ const theme = createTheme({
bgColor: sectionBg,
},
},
font :{
default: {
font: fontFamilyDefault,
},
},
shape: {
borderRadius: 4,
},
@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00004 5.33333V8M8.00004 10.6667H8.00671M14.6667 8C14.6667 11.6819 11.6819 14.6667 8.00004 14.6667C4.31814 14.6667 1.33337 11.6819 1.33337 8C1.33337 4.3181 4.31814 1.33333 8.00004 1.33333C11.6819 1.33333 14.6667 4.3181 14.6667 8Z" stroke="#F04438" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 434 B