diff --git a/web/package.json b/web/package.json index 2bfcfe9..9be89ca 100644 --- a/web/package.json +++ b/web/package.json @@ -12,6 +12,7 @@ "dependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.14.6", "@mui/material": "^5.14.3", "@types/node": "20.4.8", "@types/react": "18.2.18", diff --git a/web/src/app/layout.tsx b/web/src/app/layout.tsx index 73c0a4b..ddbd120 100644 --- a/web/src/app/layout.tsx +++ b/web/src/app/layout.tsx @@ -1,7 +1,8 @@ import type { Metadata } from 'next' -import { Inter } from 'next/font/google' +import { ThemeProvider } from '@mui/material' -const inter = Inter({ subsets: ['latin'] }) +import { theme } from '@/assets/theme' +import Wrapper from './wrapper'; export const metadata: Metadata = { title: 'Create Next App', @@ -15,7 +16,9 @@ export default function RootLayout({ }) { return ( - {children} + + {children} + ) } diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 1d790e1..6c76689 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -1,11 +1,11 @@ -import Button from '@mui/material/Button'; +import { Box, Typography } from "@mui/material"; export default function Home() { return (
-
- -
+ + Content goes here +
) } diff --git a/web/src/app/wrapper.tsx b/web/src/app/wrapper.tsx new file mode 100644 index 0000000..e0f4dd0 --- /dev/null +++ b/web/src/app/wrapper.tsx @@ -0,0 +1,50 @@ +'use client' + +import { FC, useState } from 'react'; +import { Open_Sans } from 'next/font/google' +import { Box, Container } from '@mui/material' + +import Header from '@/components/organisms/Header'; +import NavBar from '@/components/organisms/Navbar'; + +const openSansFont = Open_Sans({ + subsets: ["latin"], + weight: ["300", "400", "500", "600", "700"], +}); + +interface Props { + children: React.ReactNode +} + +export const Wrapper:FC = ({ + children + }) => { + + const [isExpanded, setIsExpanded] = useState(true) + let isOpen = true; + + const handleToggle = () => { + setIsExpanded(!isExpanded) + isOpen = !isOpen + } + + return ( + +
+ + + + {children} + + + + ) +} + +export default Wrapper \ No newline at end of file diff --git a/web/src/assets/colors.ts b/web/src/assets/colors.ts new file mode 100644 index 0000000..191791e --- /dev/null +++ b/web/src/assets/colors.ts @@ -0,0 +1,24 @@ +import { PaletteOptions } from "@mui/material"; + +export const customColors: PaletteOptions = { + primary: { + main: "#2A3F52", + 100: "#F0F9FF", + 200: "#DAEFFC", + 300: "#B9DBF1", + 400: "#86B1CC", + 500: "#5B829B", + 700: "#3E5367", + 900: "#2A3F52", + }, + secondary: { + main: "#5B829B", + }, + dark: "#293743", + neutral: "#65707A", + disabled: "#999999", + light: "#ACB5BD", + white: "#FFFFFF", + "background-primary": "#F0F0F0", + "background-secondary": "#F6F6F6", +}; diff --git a/web/src/assets/icons/Logo.tsx b/web/src/assets/icons/Logo.tsx new file mode 100644 index 0000000..088c7a6 --- /dev/null +++ b/web/src/assets/icons/Logo.tsx @@ -0,0 +1,12 @@ +export const Logo = () => ( + + + + + + + + + + +) \ No newline at end of file diff --git a/web/src/assets/theme.ts b/web/src/assets/theme.ts new file mode 100644 index 0000000..703245e --- /dev/null +++ b/web/src/assets/theme.ts @@ -0,0 +1,215 @@ +"use client"; + +import { createTheme } from "@mui/material/styles"; +import { Open_Sans } from "next/font/google"; + +import { customColors } from "./colors"; + +const openSansFont = Open_Sans({ + subsets: ["latin"], + weight: ["300", "400", "500", "600", "700"], +}); + +declare module "@mui/material/styles" { + interface TypographyVariants { + body1r: React.CSSProperties; + body1b: React.CSSProperties; + body2r: React.CSSProperties; + body2b: React.CSSProperties; + body3r: React.CSSProperties; + body3b: React.CSSProperties; + label1r: React.CSSProperties; + label1b: React.CSSProperties; + label2r: React.CSSProperties; + label2b: React.CSSProperties; + label3r: React.CSSProperties; + label3b: React.CSSProperties; + label4r: React.CSSProperties; + label4b: React.CSSProperties; + } + + // allow configuration using `createTheme` + interface TypographyVariantsOptions { + body1r: React.CSSProperties; + body1b: React.CSSProperties; + body2r: React.CSSProperties; + body2b: React.CSSProperties; + body3r: React.CSSProperties; + body3b: React.CSSProperties; + label1r: React.CSSProperties; + label1b: React.CSSProperties; + label2r: React.CSSProperties; + label2b: React.CSSProperties; + label3r: React.CSSProperties; + label3b: React.CSSProperties; + label4r: React.CSSProperties; + label4b: React.CSSProperties; + } + + interface Palette { + dark: string; + neutral: string; + disabled: string; + light: string; + white: string; + "background-primary": string; + "background-secondary": string; + } + interface PaletteOptions { + dark?: string; + neutral?: string; + disabled?: string; + light?: string; + white?: string; + "background-primary"?: string; + "background-secondary"?: string; + } +} + +// Update the Typography's variant prop options +declare module "@mui/material/Typography" { + interface TypographyPropsVariantOverrides { + body1r: true; + body1b: true; + body2r: true; + body2b: true; + body3r: true; + body3b: true; + label1r: true; + label1b: true; + label2r: true; + label2b: true; + label3r: true; + label3b: true; + label4r: true; + label4b: true; + } +} + +const customDefaultFontFamily = { + fontFamily: openSansFont.style.fontFamily, +}; + +export const theme = createTheme({ + palette: { ...customColors }, + typography: { + allVariants: { + ...customDefaultFontFamily, + color: customColors.dark, + }, + label1r: { + fontSize: 16, + fontWeight: 400, + lineHeight: "125%", + color: customColors.dark, + }, + label1b: { + fontSize: 16, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + label2r: { + fontSize: 14, + fontWeight: 400, + lineHeight: "125%", + color: customColors.dark, + }, + label2b: { + fontSize: 14, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + label3r: { + fontSize: 12, + fontWeight: 400, + lineHeight: "125%", + color: customColors.dark, + }, + label3b: { + fontSize: 12, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + label4r: { + fontSize: 10, + fontWeight: 400, + lineHeight: "125%", + color: customColors.dark, + }, + label4b: { + fontSize: 10, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + body1r: { + fontSize: 16, + fontWeight: 400, + lineHeight: "150%", + color: customColors.dark, + }, + body1b: { + fontSize: 16, + fontWeight: 500, + lineHeight: "150%", + color: customColors.dark, + }, + body2r: { + fontSize: 14, + fontWeight: 400, + lineHeight: "150%", + color: customColors.dark, + }, + body2b: { + fontSize: 14, + fontWeight: 500, + lineHeight: "150%", + color: customColors.dark, + }, + body3r: { + fontSize: 12, + fontWeight: 400, + lineHeight: "150%", + color: customColors.dark, + }, + body3b: { + fontSize: 12, + fontWeight: 500, + lineHeight: "150%", + color: customColors.dark, + }, + h1: { + fontSize: 40, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + h2: { + fontSize: 32, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + h3: { + fontSize: 24, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + h4: { + fontSize: 18, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + h5: { + fontSize: 14, + fontWeight: 600, + lineHeight: "125%", + color: customColors.dark, + }, + }, +}); diff --git a/web/src/components/molecules/NavBarItem.tsx b/web/src/components/molecules/NavBarItem.tsx new file mode 100644 index 0000000..9ad1c54 --- /dev/null +++ b/web/src/components/molecules/NavBarItem.tsx @@ -0,0 +1,64 @@ +import Link from 'next/link' +import React, { FC } from 'react' +import { Box, Typography } from '@mui/material' +import {SvgIconComponent} from '@mui/icons-material' + +interface Props { + label: string, + Icon: SvgIconComponent + active?: boolean, + width?: number | string, + height?: number | string, + paddingX?: number | string, + gap?: number, + linkTo?: string +} + +const NavBarItem: FC = ({ + label, + Icon, + active = false, + width = 200, + height = 40, + paddingX = 2, + gap = 1, + linkTo = "/" + }) => { + + const backgroundColor = active ? 'primary.100' : 'primary.700' + const textColor = active? 'dark': 'white' + + return( + + div > span": { + color: 'dark', + }, + "> div > svg": { + color: 'dark', + }, + } + }}> + + + + {label} + + + + ) +} + +export default NavBarItem diff --git a/web/src/components/organisms/Header.tsx b/web/src/components/organisms/Header.tsx new file mode 100644 index 0000000..3d751f8 --- /dev/null +++ b/web/src/components/organisms/Header.tsx @@ -0,0 +1,35 @@ +import React, { FC } from 'react' +import { Box, Stack, Typography } from '@mui/material' + +import {Logo} from '../../assets/icons/Logo' +import HeaderProfile from './HeaderProfile' + +interface Props { + height?: number | string, +} + +const Header: FC = ({height = 64}) => { + return( + + + + MeetsOne + + + + ) +} + +export default Header diff --git a/web/src/components/organisms/HeaderProfile.tsx b/web/src/components/organisms/HeaderProfile.tsx new file mode 100644 index 0000000..e620be6 --- /dev/null +++ b/web/src/components/organisms/HeaderProfile.tsx @@ -0,0 +1,125 @@ +'use client' + +import React, { FC } from 'react' +import ClickAwayListener from '@mui/material/ClickAwayListener'; +import {Create, Logout, ArrowDropDown} from '@mui/icons-material' +import { Box, Typography, Paper, Button, Stack, Avatar, Popper, Grow, IconButton } from '@mui/material' + +interface Props { + name?: string, + email?: string, + avatar?: string, +} + +const HeaderProfile: FC = ({ + name = "John Doe", + email = "johndoe@sun-asterisk.com" +}) => { + const [open, setOpen] = React.useState(false); + const anchorRef = React.useRef(null); + + const handleToggle = () => { + setOpen((prevOpen) => !prevOpen); + }; + + const handleClose = (event: Event | React.SyntheticEvent) => { + if ( + anchorRef.current && + anchorRef.current.contains(event.target as HTMLElement) + ) { + return; + } + + setOpen(false); + }; + + return( + + + + + + + + + + {({ TransitionProps }) => ( + + + + + + + + + {name} + {email} + + + + + + + + )} + + + ) +} + +export default HeaderProfile diff --git a/web/src/components/organisms/Navbar.tsx b/web/src/components/organisms/Navbar.tsx new file mode 100644 index 0000000..0fa7687 --- /dev/null +++ b/web/src/components/organisms/Navbar.tsx @@ -0,0 +1,72 @@ +"use client" + +import React, { FC } from 'react' +import { Menu } from '@mui/icons-material' +import { Box, ButtonBase } from '@mui/material' + +import NavBarItem from '../molecules/NavBarItem' +import { Menus } from '@/utils/constants/navbarMenu' + +interface Props { + expanded?: boolean, + width?: number |string, + height?: number | string, + paddingY?: number |string, + rowGap?: number |string, + handleToggle: () => void +} + +const NavBar: FC = ({ + expanded = true, + width = 200, + paddingY = 2, + rowGap = 2, + handleToggle + }) => { + + return( + + + + + + + + + {Menus.map((item, index) => ( + + + + ) + )} + + + ) +} + +export default NavBar diff --git a/web/src/utils/constants/navbarMenu.ts b/web/src/utils/constants/navbarMenu.ts new file mode 100644 index 0000000..1d2cfc2 --- /dev/null +++ b/web/src/utils/constants/navbarMenu.ts @@ -0,0 +1,30 @@ +import { + Home, + CalendarMonth, + Person, + SvgIconComponent, +} from "@mui/icons-material"; + +export interface IMenu { + name: string; + Icon: SvgIconComponent; + href: string; +} + +export const Menus: IMenu[] = [ + { + name: "Job List", + Icon: Home, + href: "/", + }, + { + name: "Calendar", + Icon: CalendarMonth, + href: "/", + }, + { + name: "Customer", + Icon: Person, + href: "/", + }, +]; diff --git a/web/yarn.lock b/web/yarn.lock index f7604ce..8662640 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -270,6 +270,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.22.10": + version "7.22.11" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.11.tgz#7a9ba3bbe406ad6f9e8dd4da2ece453eb23a77a4" + integrity sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.5", "@babel/template@^7.3.3": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" @@ -675,6 +682,13 @@ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.4.tgz#a517265647ee9660170107d68905db5e400576c5" integrity sha512-pW2XghSi3hpYKX57Wu0SCWMTSpzvXZmmucj3TcOJWaCiFt4xr05w2gcwBZi36dAp9uvd9//9N51qbblmnD+GPg== +"@mui/icons-material@^5.14.6": + version "5.14.6" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.6.tgz#0efdcba2c30d6b22e6ead787b67247da173bd11a" + integrity sha512-7Cujy7lRGTj2T3SvY9C9ZOTFDtrXJogeNnRcU/ODyNoxwskMNPFOcc15F+98MAdJenBVLJPYu+vPP6DUvEpNrA== + dependencies: + "@babel/runtime" "^7.22.10" + "@mui/material@^5.14.3": version "5.14.4" resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.4.tgz#9d4d1834a929a4acc59e550e34ca64c0fd60b3a6"