diff --git a/Client/src/Components/Button/index.jsx b/Client/src/Components/Button/index.jsx
index f357e1dd2..66a345746 100644
--- a/Client/src/Components/Button/index.jsx
+++ b/Client/src/Components/Button/index.jsx
@@ -21,10 +21,14 @@ const levelConfig = {
};
/**
- * @typedef {Object} Props
- * @property {'primary' | 'secondary' | 'tertiary' | 'error'} level - The level of the button
- * @property {string} label - The label of the button
- * @property {boolean} [disabled] - Whether the button is disabled
+ * @param {Object} props
+ * @param {'primary' | 'secondary' | 'tertiary' | 'error'} props.level - The level of the button
+ * @param {string} props.label - The label of the button
+ * @param {boolean} [props.disabled] - Whether the button is disabled
+ * @returns {JSX.Element}
+ * @example
+ * // Render an error button
+ *
*/
const Button = ({ level, label, disabled }) => {
diff --git a/Client/src/Components/Label/BaseLabel.css b/Client/src/Components/Label/BaseLabel.css
new file mode 100644
index 000000000..6aed6326d
--- /dev/null
+++ b/Client/src/Components/Label/BaseLabel.css
@@ -0,0 +1,6 @@
+.label {
+ border: 1px solid #000;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/Client/src/Components/Label/BaseLabel.jsx b/Client/src/Components/Label/BaseLabel.jsx
new file mode 100644
index 000000000..aa23aeab3
--- /dev/null
+++ b/Client/src/Components/Label/BaseLabel.jsx
@@ -0,0 +1,54 @@
+import PropTypes from "prop-types";
+import "./BaseLabel.css";
+import { useTheme } from "@mui/material";
+
+/**
+ * @typedef {Object} Styles
+ * @param {string} [color] - The text color
+ * @param {string} [backgroundColor] - The background color
+ * @param {string} [borderColor] - The border color
+ */
+
+/**
+ * @component
+ * @param {Object} props
+ * @param {string} props.label - The label of the label
+ * @param {Styles} props.styles - CSS Styles passed from parent component
+ * @param {React.ReactNode} children - Children passed from parent component
+ * @returns {JSX.Element}
+ */
+
+const BaseLabel = ({ label, styles, children }) => {
+ const theme = useTheme();
+ // Grab the default borderRadius from the theme to match button style
+ const { borderRadius } = theme.shape;
+ // Calculate padding for the label to mimic button. Appears to scale correctly, not 100% sure though.
+ const padding = theme.spacing(1 * 0.75, 2);
+
+ return (
+
+ {children}
+ {label}
+
+ );
+};
+
+BaseLabel.propTypes = {
+ label: PropTypes.string.isRequired,
+ styles: PropTypes.shape({
+ color: PropTypes.string,
+ backgroundColor: PropTypes.string,
+ }),
+ children: PropTypes.node,
+};
+
+export default BaseLabel;
diff --git a/Client/src/Components/Label/ColoredLabel.jsx b/Client/src/Components/Label/ColoredLabel.jsx
new file mode 100644
index 000000000..744652050
--- /dev/null
+++ b/Client/src/Components/Label/ColoredLabel.jsx
@@ -0,0 +1,67 @@
+import { useTheme } from "@mui/material";
+import { PropTypes } from "prop-types";
+import BaseLabel from "./BaseLabel";
+
+// Produces a lighter color based on a hex color and a percent
+// lightenColor("#067647", 20) will produce a color 20% lighter than #067647
+const lightenColor = (color, percent) => {
+ let r = parseInt(color.substring(1, 3), 16);
+ let g = parseInt(color.substring(3, 5), 16);
+ let b = parseInt(color.substring(5, 7), 16);
+
+ const amt = Math.round((255 * percent) / 100);
+
+ r = r + amt <= 255 ? r + amt : 255;
+ g = g + amt <= 255 ? g + amt : 255;
+ b = b + amt <= 255 ? b + amt : 255;
+
+ r = r.toString(16).padStart(2, "0");
+ g = g.toString(16).padStart(2, "0");
+ b = b.toString(16).padStart(2, "0");
+
+ return `#${r}${g}${b}`;
+};
+
+/**
+ * @component
+ * @param {Object} props
+ * @param {string} props.label - The label of the label
+ * @param {string} props.color - The color of the label, specified in #RRGGBB format
+ * @returns {JSX.Element}
+ * @example
+ * // Render a red label
+ *
+ */
+
+const ColoredLabel = ({ label, color }) => {
+ const theme = useTheme();
+ // If an invalid color is passed, default to the labelGray color
+ if (
+ typeof color !== "string" ||
+ !/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)
+ ) {
+ color = theme.palette.labelGray.color;
+ }
+
+ // Calculate lighter shades for border and bg
+ const borderColor = lightenColor(color, 20);
+ const bgColor = lightenColor(color, 75);
+
+ return (
+
+ );
+};
+
+ColoredLabel.propTypes = {
+ label: PropTypes.string.isRequired,
+ color: PropTypes.string.isRequired,
+};
+
+export default ColoredLabel;
diff --git a/Client/src/Components/Label/StautsLabel.jsx b/Client/src/Components/Label/StautsLabel.jsx
new file mode 100644
index 000000000..108ca0f2f
--- /dev/null
+++ b/Client/src/Components/Label/StautsLabel.jsx
@@ -0,0 +1,46 @@
+import PropTypes from "prop-types";
+import BaseLabel from "./BaseLabel";
+import { Box } from "@mui/material";
+import { useTheme } from "@mui/material";
+
+/**
+ * @component
+ * @param {Object} props
+ * @param {'Seen' | 'Waiting' | 'New' | 'Active'} props.status - The status for the label
+ * @returns {JSX.Element}
+ * @example
+ * // Render an active label
+ *
+ */
+
+const StatusLabel = ({ status }) => {
+ const theme = useTheme();
+
+ const colorLookup = {
+ Seen: theme.palette.labelGray.color,
+ Waiting: theme.palette.labelRed.color,
+ New: theme.palette.labelOrange.color,
+ Active: theme.palette.labelGreen.color,
+ };
+
+ // Look up the color for the status, default to labelGray if not found
+ const color = colorLookup[status] || theme.palette.labelGray.color;
+
+ return (
+
+
+
+ );
+};
+
+StatusLabel.propTypes = {
+ status: PropTypes.oneOf(["Seen", "Waiting", "New", "Active"]),
+};
+
+export default StatusLabel;
diff --git a/Client/src/Pages/Home/index.jsx b/Client/src/Pages/Home/index.jsx
index f9a7cf14d..b3f9b7207 100644
--- a/Client/src/Pages/Home/index.jsx
+++ b/Client/src/Pages/Home/index.jsx
@@ -1,17 +1,18 @@
-import React from "react";
import DropdownTeamMember from "../../Components/DropdownTeamMember";
import "./index.css";
import Button from "../../Components/Button";
import Link from "../../Components/Link";
+import ColoredLabel from "../../Components/Label/ColoredLabel";
+import { useTheme } from "@mui/material";
+import StatusLabel from "../../Components/Label/StautsLabel";
const Home = () => {
+ const theme = useTheme();
return (
<>
Home
-
+
Buttons
@@ -33,6 +34,21 @@ const Home = () => {
url={"https://www.google.com"}
/>
+
Labels
+
+
+
+
+
+
+
+
Status Lables
+
+
+
+
+
+
>
);
diff --git a/Client/src/Utils/Theme.js b/Client/src/Utils/Theme.js
index 60e6da3ad..c24b18242 100644
--- a/Client/src/Utils/Theme.js
+++ b/Client/src/Utils/Theme.js
@@ -1,12 +1,22 @@
import { createTheme } from "@mui/material";
// Colors for MUI theme
+const primaryMain = "#1570EF";
const secondaryMain = "#475467";
const tertiaryMain = "#475467";
const tertiaryLinkHover = "#eff8ff";
+// Label Colors
+const labelOrange = "#F79009";
+const labelGray = "#475467";
+const labelPurple = "#6941C6";
+const labelGreen = "#067647";
+const labelRed = "#F04438";
const theme = createTheme({
palette: {
+ primary: {
+ main: primaryMain,
+ },
secondary: {
main: secondaryMain,
},
@@ -14,6 +24,21 @@ const theme = createTheme({
main: tertiaryMain,
linkHover: tertiaryLinkHover,
},
+ labelOrange: {
+ color: labelOrange,
+ },
+ labelGray: {
+ color: labelGray,
+ },
+ labelPurple: {
+ color: labelPurple,
+ },
+ labelGreen: {
+ color: labelGreen,
+ },
+ labelRed: {
+ color: labelRed,
+ },
},
});