Added header

This commit is contained in:
Sianida26 2024-01-22 01:37:49 +07:00
parent 1cae4e924d
commit 24eefcc253
6 changed files with 379 additions and 257 deletions

View File

@ -9,10 +9,10 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@auth/prisma-adapter": "^1.0.14", "@auth/prisma-adapter": "^1.0.16",
"@mantine/core": "^7.4.0", "@mantine/core": "^7.4.2",
"@mantine/form": "^7.4.0", "@mantine/form": "^7.4.2",
"@mantine/hooks": "^7.4.0", "@mantine/hooks": "^7.4.2",
"@prisma/client": "5.7.1", "@prisma/client": "5.7.1",
"@tanstack/react-query": "^4.36.1", "@tanstack/react-query": "^4.36.1",
"@tanstack/react-query-devtools": "^4.36.1", "@tanstack/react-query-devtools": "^4.36.1",
@ -23,8 +23,9 @@
"@types/bcrypt": "^5.0.2", "@types/bcrypt": "^5.0.2",
"@types/jsonwebtoken": "^9.0.5", "@types/jsonwebtoken": "^9.0.5",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"clsx": "^2.1.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"next": "14.0.4", "next": "14.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-icons": "^5.0.1", "react-icons": "^5.0.1",
@ -33,16 +34,16 @@
"zod": "^3.22.4" "zod": "^3.22.4"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.10.6", "@types/node": "^20.11.5",
"@types/react": "^18.2.47", "@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.18",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.17",
"eslint": "^8.56.0", "eslint": "^8.56.0",
"eslint-config-next": "14.0.4", "eslint-config-next": "14.0.4",
"postcss": "^8.4.33", "postcss": "^8.4.33",
"postcss-preset-mantine": "^1.12.3", "postcss-preset-mantine": "^1.12.3",
"postcss-simple-vars": "^7.0.1", "postcss-simple-vars": "^7.0.1",
"prisma": "^5.7.1", "prisma": "^5.8.1",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,90 @@
"use client" import React, { useState } from "react";
import React from 'react' import {
import { AppShell, Burger, Group } from "@mantine/core" AppShell,
import { useDisclosure } from '@mantine/hooks' Avatar,
import Image from 'next/image' Burger,
import logo from "@/assets/logos/logo-dsg.png" Group,
Menu,
UnstyledButton,
Text,
rem,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import Image from "next/image";
import logo from "@/assets/logos/logo-dsg.png";
import cx from "clsx";
import classNames from "./styles.module.css";
import { TbChevronDown, TbLogout, TbSettings } from "react-icons/tb";
import userMenuItems from "./_data/UserMenuItems";
import UserMenuItem from "./_components/UserMenuItem/UserMenuItem";
interface Props { interface Props {
openNavbar: boolean, openNavbar: boolean;
toggle: () => void toggle: () => void;
} }
const mockUserData = {
name: "Fulan bin Fulanah",
email: "janspoon@fighter.dev",
image: "https://raw.githubusercontent.com/mantinedev/mantine/master/.demo/avatars/avatar-5.png",
};
export default function AppHeader(props: Props) { export default function AppHeader(props: Props) {
const [userMenuOpened, setUserMenuOpened] = useState(false);
const userMenus = userMenuItems.map((item, i) => (
<UserMenuItem item={item} key={i} />
));
return ( return (
<AppShell.Header> <AppShell.Header>
<Group h="100%" px="md"> <Group h="100%" px="md" justify="space-between">
<Burger <Burger
opened={props.openNavbar} opened={props.openNavbar}
onClick={props.toggle} onClick={props.toggle}
hiddenFrom="sm" hiddenFrom="sm"
size="sm" size="sm"
/> />
<Image src={logo} alt='' height={57} /> <Image src={logo} alt="" height={57} />
<Menu
width={260}
position="bottom-end"
transitionProps={{ transition: "pop-top-right" }}
onOpen={() => setUserMenuOpened(true)}
onClose={() => setUserMenuOpened(false)}
withinPortal
>
<Menu.Target>
<UnstyledButton
className={cx(classNames.user, {
[classNames.userActive]: userMenuOpened,
})}
>
<Group gap={7}>
<Avatar
src={mockUserData.image}
alt={mockUserData.name}
radius="xl"
size={20}
/>
<Text fw={500} size="sm" lh={1} mr={3}>
{mockUserData.name}
</Text>
<TbChevronDown
style={{ width: rem(12), height: rem(12) }}
strokeWidth={1.5}
/>
</Group>
</UnstyledButton>
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>Settings</Menu.Label>
{userMenus}
</Menu.Dropdown>
</Menu>
</Group> </Group>
</AppShell.Header> </AppShell.Header>
) );
} }

View File

@ -0,0 +1,23 @@
import { Menu, rem } from '@mantine/core'
import React from 'react'
import { UserMenuItem } from '../../_data/UserMenuItems'
interface Props {
item: UserMenuItem
}
export default function UserMenuItem({item}: Props) {
return (
<Menu.Item
color={item.color}
leftSection={
<item.icon
style={{ width: rem(16), height: rem(16) }}
strokeWidth={1.5}
/>
}
>
{item.label}
</Menu.Item>
)
}

View File

@ -0,0 +1,23 @@
import { ThemeIconProps } from "@mantine/core"
import React from "react"
import { TbLogout, TbSettings } from "react-icons/tb"
export interface UserMenuItem {
label: string,
icon: React.FC<any>,
color?: ThemeIconProps['color']
}
const userMenuItems: UserMenuItem[] = [
{
label: "Account Settings",
icon: TbSettings
},
{
label: "Logout",
icon: TbLogout,
color: "red"
}
];
export default userMenuItems;

View File

@ -0,0 +1,24 @@
.user {
color: light-dark(var(--mantine-color-black), var(--mantine-color-dark-0));
padding: var(--mantine-spacing-xs) var(--mantine-spacing-sm);
border-radius: var(--mantine-radius-sm);
transition: background-color 100ms ease;
&:hover {
background-color: light-dark(
var(--mantine-color-white),
var(--mantine-color-dark-8)
);
}
@media (max-width: $mantine-breakpoint-xs) {
display: none;
}
}
.userActive {
background-color: light-dark(
var(--mantine-color-white),
var(--mantine-color-dark-8)
);
}