Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More MUI-related improvements #47

Merged
merged 26 commits into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7d88d43
Use outlined color mode icons
koolskateguy89 Dec 24, 2022
7b1912b
Use tabs for navigation on desktop
koolskateguy89 Dec 25, 2022
ee9609c
Fix performance issue switching out of profile page
koolskateguy89 Dec 26, 2022
fca5f37
Bug fixed itself
koolskateguy89 Dec 26, 2022
00472d4
Add custom 404 page and update `dark` & `light` colours
koolskateguy89 Dec 26, 2022
7ac4339
Update 404 page
koolskateguy89 Dec 26, 2022
dbd6568
Add custom 500 page
koolskateguy89 Dec 27, 2022
8455822
Cleanup and update comments
koolskateguy89 Dec 27, 2022
43a7cf4
Cleanup
koolskateguy89 Dec 28, 2022
1267876
Move assets to /public/assets
koolskateguy89 Dec 28, 2022
90d3d58
Show mesh gradient in background (only in dark mode)
koolskateguy89 Dec 29, 2022
f45d2da
Make chip bar scrollable on mobile
koolskateguy89 Dec 29, 2022
525fba7
Remove title (I)
koolskateguy89 Dec 30, 2022
b89775b
Update globals.css
koolskateguy89 Dec 31, 2022
7860f4a
Remove specificity from anchor styling
koolskateguy89 Dec 31, 2022
119b833
Remove title (II), use tabs for desktop, use collapse for mobile nav
koolskateguy89 Dec 31, 2022
44ec266
Remove title (final)
koolskateguy89 Dec 31, 2022
9c9d51a
Update collapse styling
koolskateguy89 Jan 1, 2023
2b283e3
Remove no-longer-used Nav components
koolskateguy89 Jan 1, 2023
d08250c
Update AppBar bgcolor
koolskateguy89 Jan 1, 2023
5857833
Update comment
koolskateguy89 Jan 1, 2023
8847f8a
Add usehooks-ts and type-fest
koolskateguy89 Jan 2, 2023
74ead8b
Store theme in localStorage & use Menu Popover for theme switcher
koolskateguy89 Jan 3, 2023
3d0423c
Show skeleton for ThemeSwitcher until mounted
koolskateguy89 Jan 3, 2023
b425cf6
Cleanup
koolskateguy89 Jan 3, 2023
55f618a
Cleanup
koolskateguy89 Jan 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ To use our defined layout (sidebar and nav in top), you need to [add the propert
| Prop | Type | Description |
|------------------------|----------------------------------------------------------|----------------------------------------------|
| layout | `PageLayout` | Basically `Layout`'s props |
| layout.title | `ReactNode?` | Title to display in the centre of the navbar |
| layout.sidebar | `Sidebar` | |
| layout.sidebar.type | `SidebarType` | |
| layout.sidebar.content | `ReactNode?` (only needed if `sidebarType` === `CUSTOM`) | |
Expand Down Expand Up @@ -507,6 +506,8 @@ from the
| [dotenv](https://github.com/motdotla/dotenv) | 16.0 | Load development environment variables during database seeding |
| [lodash](https://lodash.com/) | 4.17 | Utility library |
| [lorem-ipsum](https://github.com/knicklabs/lorem-ipsum.js) | 2.0 | Generating placeholder text (for seeding) |
| [usehooks-ts](https://usehooks-ts.com/) | 2.9 | Utility React hooks |
| [type-fest](https://github.com/sindresorhus/type-fest) | 3.5 | Utility TypeScript types |
| ... | | |

<!-- https://stackoverflow.com/a/42424860 -->
Expand Down
2 changes: 2 additions & 0 deletions prototype_nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Expand Down
2 changes: 2 additions & 0 deletions prototype_nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"react-hot-toast": "^2.4.0",
"sharp": "^0.31.3",
"swr": "^2.0.0",
"usehooks-ts": "^2.9.1",
"zod": "^3.20.2",
"zustand": "^4.1.4"
},
Expand All @@ -61,6 +62,7 @@
"lorem-ipsum": "^2.0.8",
"prisma": "^4.8.0",
"ts-node": "^10.9.1",
"type-fest": "^3.5.0",
"typescript": "^4.9.3"
},
"prisma": {
Expand Down
20 changes: 20 additions & 0 deletions prototype_nextjs/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added prototype_nextjs/public/assets/signin/mesh-63.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions prototype_nextjs/src/components/DebouncedTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export type DebouncedTextFieldProps = Omit<TextFieldProps, 'value' | 'onChange'
};

/**
* A controlled TextField that uses debouncing for better performance. Should be used for searching.
* A controlled `TextField` that uses debouncing for better performance. Should be used for searching.
*
* @param debounceTimeoutMs The amount of time (ms) after user stops typing to wait before calling `onSearchSubmit`
* @param initialValue
* @param initialValue The initial value, default `''`
* @param onSearchSubmit The action to execute `debounceTimeoutMs`ms after user stops typing
* @param resetResults
* @param resetResults The action to execute when value is empty
* @see https://javascript.plainenglish.io/how-to-create-an-optimized-real-time-search-with-react-6dd4026f4fa9
*/
export default function DebouncedTextField({
Expand Down
8 changes: 8 additions & 0 deletions prototype_nextjs/src/components/EmailField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ import TextField, { type TextFieldProps } from '@mui/material/TextField';

export type EmailFieldProps = TextFieldProps;

/**
* A convenience wrapper around `TextField` for email input.
*
* Defaults:
* - type of `email`
* - autoComplete of `username`
* - label of `Email address`
*/
export default forwardRef(function EmailField(props: EmailFieldProps, ref: React.ForwardedRef<HTMLInputElement>) {
return (
<TextField
Expand Down
3 changes: 0 additions & 3 deletions prototype_nextjs/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ interface DefaultSidebar extends BaseSidebar {
type Sidebar = CustomSidebar | DefaultSidebar;

export type PageLayout = {
title?: React.ReactNode
sidebar: Sidebar
};

Expand All @@ -42,7 +41,6 @@ export interface LayoutProps extends PageLayout {
* Pages can use `flexGrow: 1` to take up the rest of the available space
*/
export default function Layout({
title,
sidebar,
children,
}: LayoutProps) {
Expand Down Expand Up @@ -88,7 +86,6 @@ export default function Layout({
<NavigationBar
noSidebar={noSidebar}
toggleSidebar={toggleSidebar}
title={title}
/>
{children}
</Stack>
Expand Down
4 changes: 2 additions & 2 deletions prototype_nextjs/src/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link(props,
[activeClassName]: router.pathname === pathname && activeClassName,
});

const isExternal =
typeof href === 'string' && (href.indexOf('http') === 0 || href.indexOf('mailto:') === 0);
const isExternal
= typeof href === 'string' && (href.indexOf('http') === 0 || href.indexOf('mailto:') === 0);

if (isExternal) {
if (noLinkStyle) {
Expand Down
14 changes: 10 additions & 4 deletions prototype_nextjs/src/components/PasswordField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ export type PasswordFieldProps = TextFieldProps & {
};

/**
* A reusable form input field for the user's password.
* A convenience wrapper around `TextField` for password input.
*
* - Customisable as it's a `forwardRef` component
* - Correct `autocomplete` of `current-password`
* - policyTooltip
* Features:
* - Toggle password visibility capability
* - Password policy tooltip
*
* Defaults:
* - label of `Password`
* - autoComplete of `current-password`
*/
export default forwardRef(function PasswordField({
label = 'Password',
autoComplete = 'current-password',
policyTooltip,
InputProps,
...props
}: PasswordFieldProps, ref: React.ForwardedRef<HTMLInputElement>) {
const [showPassword, setShowPassword] = useState(false);
Expand Down Expand Up @@ -62,6 +67,7 @@ export default forwardRef(function PasswordField({
</Stack>
</InputAdornment>
),
...InputProps,
}}
ref={ref}
{...props}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ export default function StyledCloseButtonDialog({
</Stack>
)}
{children}
</StyledDialog >
</StyledDialog>
);
}
2 changes: 1 addition & 1 deletion prototype_nextjs/src/components/TextAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface TextAvatarProps extends React.ComponentPropsWithoutRef<'span'>
size?: string
}

// https://mui.com/material-ui/react-avatar/#main-content
// TODO: https://mui.com/material-ui/react-avatar/#main-content
export default forwardRef(function LoadingButton({
size = '40px',
className,
Expand Down
128 changes: 109 additions & 19 deletions prototype_nextjs/src/components/layout/NavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,47 @@
import { useId, useState } from 'react';
import Link from 'next/link';
import { styled } from '@mui/material/styles';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Toolbar from '@mui/material/Toolbar';
import MenuIcon from '@mui/icons-material/Menu';
import MenuOpenIcon from '@mui/icons-material/MenuOpen';
import type { UrlObject } from 'url';

import Nav from '~/components/layout/nav/Nav';
import TextAvatar from '~/components/TextAvatar';
import ThemeSwitcher from '~/components/layout/ThemeSwitcher';
import NavCollapse from '~/components/layout/nav/NavCollapse';
import NavTabs from '~/components/layout/nav/NavTabs';
import useUserStore from '~/store/userStore';

export type PageData = {
label: string // page
href: UrlObject | string
};
// TODO: look at using icons, AT LEAST for mobile nav if menu (probably not for desktop)

const userPages: PageData[] = [
{ label: 'Home', href: '/home' },
{ label: 'Forum', href: '/forum' },
{ label: 'Projects', href: '/projects' },
{ label: 'Dashboard', href: '/dashboard' },
];
const managerPages: PageData[] = [
{ label: 'Home', href: '/home' },
{ label: 'Forum', href: '/forum' },
{ label: 'Projects', href: '/projects' },
{ label: 'Dashboard', href: '/dashboard' },
{ label: 'Staff', href: '/staff' },
];

const NavBarBox = styled(Box)({
// width: '100%',
flexBasis: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
});

/**
* - Material UI's `FormatAlignLeftIcon` doesn't look great
Expand Down Expand Up @@ -42,17 +80,32 @@ const faAlignLeftSvg = (
</svg>
);

// TODO: navbar sticky to top? if so then blur
export default function NavigationBar({ noSidebar, toggleSidebar, title }: {
export type NavigationBarProps = {
noSidebar: boolean
toggleSidebar: () => void
title: React.ReactNode
}) {
const renderToggleSidebarButton = !noSidebar && (
};

// TODO?: navbar sticky to top? if so then blur after scoll
export default function NavigationBar({
noSidebar,
toggleSidebar,
}: NavigationBarProps) {
const isManager = useUserStore((state) => state.user.isManager);
const pages = isManager ? managerPages : userPages;

const collapseId = useId();

const [isCollapseOpen, setIsCollapseOpen] = useState(false);

const handleToggleCollapse = () => setIsCollapseOpen((open) => !open);
const handleCloseCollapse = () => setIsCollapseOpen(false);

const toggleSidebarButton = !noSidebar && (
<Button
onClick={toggleSidebar}
variant="contained"
color="makeItAllGrey"
aria-label="Toggle Sidebar"
sx={(theme) => ({
paddingX: 1.5,
height: `calc(1.5rem + ${theme.spacing(1.5)})`,
Expand All @@ -66,35 +119,72 @@ export default function NavigationBar({ noSidebar, toggleSidebar, title }: {
<Box
display={{
xs: 'none',
md: 'inline-block',
md: 'inline',
}}
marginLeft={{
md: 1,
}}
component="span"
>
Toggle Sidebar
</Box>
</Button>
);

return (
<AppBar position="static">
<AppBar
position="static"
elevation={2}
>
<Toolbar>
{/* left */}
<Box width="100%" display="flex">
{renderToggleSidebarButton}
</Box>
<NavBarBox>
{toggleSidebarButton}
</NavBarBox>
{/* middle */}
<Box width="100%" display="flex">
<Box marginX="auto">
{title}
</Box>
</Box>
<NavBarBox justifyContent="center">
<NavTabs pages={pages} />
</NavBarBox>
{/* right */}
<Box width="100%" display="flex" justifyContent="flex-end">
<Nav />
</Box>
<NavBarBox justifyContent="end">
<ThemeSwitcher marginRight={{ xs: 0.5, md: 1.5 }} />

<Box
display={{ xs: 'none', lg: 'block' }}
>
<Link href="/profile">
<TextAvatar />
</Link>
</Box>

{/* TODO: change nav button to be same size width as toggle sidebar button (when only icon)
might have to use custom svg (which will make animating transition easier)
*/}
<Button
variant="contained"
color="contrast"
onClick={handleToggleCollapse}
aria-controls={collapseId}
aria-expanded={isCollapseOpen}
aria-label={`${isCollapseOpen ? 'collapse' : 'open'} navigation menu`}
sx={(theme) => ({
paddingX: 1.5,
height: `calc(1.5rem + ${theme.spacing(1.5)})`,
minWidth: 0,
display: { xs: 'block', lg: 'none' },
})}
>
{/* TODO: animate transition */}
{isCollapseOpen ? <MenuOpenIcon /> : <MenuIcon />}
</Button>
</NavBarBox>
</Toolbar>
<NavCollapse
pages={pages.concat({ label: 'Profile', href: '/profile' })}
collapseId={collapseId}
open={isCollapseOpen}
closeCollapse={handleCloseCollapse}
/>
</AppBar>
);
}
Loading