diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a1d0cbf0..1ac3f2e4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@popperjs/core": "^2.11.6", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", + "clsx": "^2.1.1", "react-hook-form": "^7.46.1", "react-popper": "^2.3.0", "vite-tsconfig-paths": "^4.3.1" @@ -3540,6 +3541,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -12930,6 +12939,11 @@ "wrap-ansi": "^7.0.0" } }, + "clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 73d8e4b2..a82f5797 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -70,6 +70,7 @@ "@popperjs/core": "^2.11.6", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", + "clsx": "^2.1.1", "react-hook-form": "^7.46.1", "react-popper": "^2.3.0", "vite-tsconfig-paths": "^4.3.1" diff --git a/frontend/src/pages/Demo/DemoTailwind.tsx b/frontend/src/pages/Demo/DemoTailwind.tsx index 54759963..652be178 100644 --- a/frontend/src/pages/Demo/DemoTailwind.tsx +++ b/frontend/src/pages/Demo/DemoTailwind.tsx @@ -1,14 +1,77 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import Typography from "tw-components/Typography"; +import { Button, IconButton } from "tw-components/Buttons"; const DemoTailwind = () => { + // Add a setDarkMode for testing dark mode styles + const [darkMode, setDarkMode] = useState(false); + + useEffect(() => { + if (darkMode) { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + }, [darkMode]); + return (
+
+ + Buttons + + + + + {/* Regular Buttons, active is the default state */} + + Active + +
+ + + {/* Medium is the default*/} + + + + +
+ + {/* Disabled Buttons */} + + Disabled + +
+ + +
+ + {/* Hover & Active/Focused States */} + + Hover, Focused and Active + +
+ + + +
+ + {/* Icon Buttons */} + + Search Icon + +
+ + +
+
+
Typography Demo (Title 1 - Roboto Bold 48/137% +0) - Title Styles (Title 2 - Roboto Bold 36/137% +0) diff --git a/frontend/src/tw-components/Buttons.tsx b/frontend/src/tw-components/Buttons.tsx new file mode 100644 index 00000000..8d0d3fc5 --- /dev/null +++ b/frontend/src/tw-components/Buttons.tsx @@ -0,0 +1,113 @@ +import React from "react"; +import clsx from "clsx"; +import Typography from "tw-components/Typography"; + +const buttonSizes = { + small: "px-[24px] h-[32px]", + "small-long": "px-[40px] h-[32px]", + medium: "px-[32px] h-[42px]", + "medium-long": "px-[48px] h-[42px]", + large: "px-[40px] h-[51px]", + "large-long": "px-[56px] h-[51px]", + "icon-only": "px-[24px] h-[42px]", +}; + +type ButtonSize = keyof typeof buttonSizes; + +type BaseButtonProps = { + size?: ButtonSize; + disabled?: boolean; + className?: string; + children?: React.ReactNode; + onClick?: () => void; +}; + +// Shared styles +const baseButtonStyles = + "transition-all duration-200 flex items-center justify-center rounded-[64px] bg-blue-dark text-white hover:bg-blue-dark-hover focus:bg-blue-dark-focused focus:outline-none active:bg-blue-dark-focused disabled:bg-grey disabled:text-white disabled:cursor-not-allowed"; + +// Dark mode styles for enabled buttons +const enabledDarkModeStyles = + "dark:bg-white dark:text-blue-dark dark:hover:bg-grey-light dark:focus:bg-[#D9DBDF] dark:active:bg-[#D9DBDF] dark:disabled:bg-grey dark:disabled:text-grey-light"; + +// Base Button, no text, just styling +const BaseButton: React.FC = ({ + size = "medium", + disabled = false, + className, + children, + onClick, +}) => { + return ( + + ); +}; + +// Default Button, extends base button, adds typography +const buttonTypography: Record< + Exclude, + React.ElementType +> = { + small: Typography.Title7, + "small-long": Typography.Title7, + medium: Typography.Title6, + "medium-long": Typography.Title6, + large: Typography.Title5, + "large-long": Typography.Title5, +}; + +type ButtonProps = Omit & { + size?: Exclude; + children: React.ReactNode; +}; + +const Button: React.FC = ({ + size = "medium", + children, + ...props +}) => { + const TextComponent = buttonTypography[size]; + return ( + + {children} + + ); +}; + +// Icon Button, extends base button, adds static svg +type IconButtonProps = Omit; + +const IconButton: React.FC = (props) => { + return ( + + + + + + ); +}; + +export { Button, IconButton }; diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index d6a6985e..7541c68e 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,5 +1,6 @@ /** @type {import('tailwindcss').Config} */ module.exports = { + darkMode: "class", // Enables dark mode with a class content: [ "./src/pages/Demo/DemoTailwind.tsx", "./src/pages/Authentication/*.tsx",