mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 14:25:02 +00:00
code: tsx,nextjs,frontends (7 files)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { AppBar, Slide, Toolbar, useScrollTrigger } from '@mui/material'
|
||||
import { forwardRef, ReactNode } from 'react'
|
||||
import { AppBar, Toolbar, Slide } from '@/fakemui'
|
||||
import { forwardRef, ReactNode, useEffect, useState } from 'react'
|
||||
|
||||
import {
|
||||
NavigationContent,
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from './NavigationMenuItems'
|
||||
import { NavigationMobileToggle } from './NavigationResponsive'
|
||||
import { NavigationBrand, NavigationSeparator, NavigationSpacer } from './NavigationStyling'
|
||||
import styles from './Navigation.module.scss'
|
||||
|
||||
interface NavigationProps {
|
||||
children: ReactNode
|
||||
@@ -22,6 +23,29 @@ interface NavigationProps {
|
||||
hideOnScroll?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook to detect scroll direction for hide-on-scroll behavior
|
||||
*/
|
||||
const useScrollTrigger = (): boolean => {
|
||||
const [trigger, setTrigger] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
let lastScrollY = window.scrollY
|
||||
const threshold = 100
|
||||
|
||||
const handleScroll = () => {
|
||||
const currentScrollY = window.scrollY
|
||||
setTrigger(currentScrollY > threshold && currentScrollY > lastScrollY)
|
||||
lastScrollY = currentScrollY
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true })
|
||||
return () => window.removeEventListener('scroll', handleScroll)
|
||||
}, [])
|
||||
|
||||
return trigger
|
||||
}
|
||||
|
||||
const Navigation = forwardRef<HTMLElement, NavigationProps>(
|
||||
(
|
||||
{
|
||||
@@ -41,21 +65,16 @@ const Navigation = forwardRef<HTMLElement, NavigationProps>(
|
||||
ref={ref}
|
||||
position={position}
|
||||
color={color}
|
||||
elevation={elevation}
|
||||
sx={{
|
||||
bgcolor: 'background.paper',
|
||||
borderBottom: 1,
|
||||
borderColor: 'divider',
|
||||
}}
|
||||
className={styles.appBar}
|
||||
{...props}
|
||||
>
|
||||
<Toolbar>{children}</Toolbar>
|
||||
<Toolbar className={styles.toolbar}>{children}</Toolbar>
|
||||
</AppBar>
|
||||
)
|
||||
|
||||
if (hideOnScroll) {
|
||||
return (
|
||||
<Slide appear={false} direction="down" in={!trigger}>
|
||||
<Slide direction="down" in={!trigger}>
|
||||
{appBar}
|
||||
</Slide>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ExpandMore as ExpandMoreIcon } from '@/fakemui/icons'
|
||||
import { Box, Button, ListItemIcon, ListItemText, Menu, MenuItem } from '@mui/material'
|
||||
import { Box, Button, Menu, MenuItem, ListItemIcon, ListItemText } from '@/fakemui'
|
||||
import { ElementType, forwardRef, type MouseEvent, ReactNode } from 'react'
|
||||
import styles from './Navigation.module.scss'
|
||||
|
||||
interface NavigationMenuProps {
|
||||
children: ReactNode
|
||||
@@ -12,11 +13,7 @@ const NavigationMenu = forwardRef<HTMLDivElement, NavigationMenuProps>(
|
||||
<Box
|
||||
ref={ref}
|
||||
component="nav"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 0.5,
|
||||
}}
|
||||
className={styles.navMenu}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -36,14 +33,7 @@ const NavigationList = forwardRef<HTMLUListElement, NavigationListProps>(
|
||||
<Box
|
||||
ref={ref}
|
||||
component="ul"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 0.5,
|
||||
listStyle: 'none',
|
||||
m: 0,
|
||||
p: 0,
|
||||
}}
|
||||
className={styles.navList}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -60,7 +50,7 @@ interface NavigationItemProps {
|
||||
const NavigationItem = forwardRef<HTMLLIElement, NavigationItemProps>(
|
||||
({ children, ...props }, ref) => {
|
||||
return (
|
||||
<Box component="li" ref={ref} sx={{ position: 'relative' }} {...props}>
|
||||
<Box component="li" ref={ref} className={styles.navItem} {...props}>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
@@ -80,16 +70,9 @@ const NavigationTrigger = forwardRef<HTMLButtonElement, NavigationTriggerProps>(
|
||||
<Button
|
||||
ref={ref}
|
||||
onClick={onClick}
|
||||
color="inherit"
|
||||
endIcon={hasDropdown ? <ExpandMoreIcon fontSize="small" /> : undefined}
|
||||
sx={{
|
||||
textTransform: 'none',
|
||||
fontWeight: 500,
|
||||
color: 'text.primary',
|
||||
'&:hover': {
|
||||
bgcolor: 'action.hover',
|
||||
},
|
||||
}}
|
||||
variant="ghost"
|
||||
endIcon={hasDropdown ? <ExpandMoreIcon /> : undefined}
|
||||
className={styles.navTrigger}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -114,21 +97,7 @@ const NavigationContent = forwardRef<HTMLDivElement, NavigationContentProps>(
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
PaperProps={{
|
||||
elevation: 2,
|
||||
sx: {
|
||||
mt: 1,
|
||||
minWidth: 200,
|
||||
},
|
||||
}}
|
||||
className={styles.navContent}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -149,7 +118,7 @@ interface NavigationLinkProps {
|
||||
component?: ElementType
|
||||
}
|
||||
|
||||
const NavigationLink = forwardRef<HTMLElement, NavigationLinkProps>(
|
||||
const NavigationLink = forwardRef<HTMLButtonElement, NavigationLinkProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
@@ -164,35 +133,25 @@ const NavigationLink = forwardRef<HTMLElement, NavigationLinkProps>(
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
if (asChild || component) {
|
||||
return (
|
||||
<MenuItem
|
||||
ref={ref}
|
||||
component={component || 'a'}
|
||||
href={href}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
selected={active}
|
||||
{...props}
|
||||
>
|
||||
{icon && <ListItemIcon>{icon}</ListItemIcon>}
|
||||
<ListItemText>{children}</ListItemText>
|
||||
</MenuItem>
|
||||
)
|
||||
const handleClick = () => {
|
||||
if (href && !onClick) {
|
||||
window.location.href = href
|
||||
} else if (onClick) {
|
||||
onClick()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
onClick={onClick}
|
||||
ref={ref}
|
||||
onClick={handleClick}
|
||||
disabled={disabled}
|
||||
selected={active}
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
}}
|
||||
className={`${styles.navLink} ${active ? styles.active : ''}`}
|
||||
{...props}
|
||||
>
|
||||
{icon && <ListItemIcon>{icon}</ListItemIcon>}
|
||||
<ListItemText>{children}</ListItemText>
|
||||
{icon && <span className={styles.linkIcon}>{icon}</span>}
|
||||
<span>{children}</span>
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Menu as MenuIcon } from '@/fakemui/icons'
|
||||
import { IconButton } from '@mui/material'
|
||||
import { IconButton } from '@/fakemui'
|
||||
import { forwardRef } from 'react'
|
||||
import styles from './Navigation.module.scss'
|
||||
|
||||
interface NavigationMobileToggleProps {
|
||||
onClick: () => void
|
||||
@@ -12,12 +13,7 @@ const NavigationMobileToggle = forwardRef<HTMLButtonElement, NavigationMobileTog
|
||||
<IconButton
|
||||
ref={ref}
|
||||
onClick={onClick}
|
||||
edge="start"
|
||||
color="inherit"
|
||||
sx={{
|
||||
display: { sm: 'none' },
|
||||
mr: 2,
|
||||
}}
|
||||
className={styles.mobileToggle}
|
||||
{...props}
|
||||
>
|
||||
<MenuIcon />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Box, Divider } from '@mui/material'
|
||||
import { Box, Divider } from '@/fakemui'
|
||||
import { forwardRef, ReactNode } from 'react'
|
||||
import styles from './Navigation.module.scss'
|
||||
|
||||
interface NavigationBrandProps {
|
||||
children: ReactNode
|
||||
@@ -13,12 +14,7 @@ const NavigationBrand = forwardRef<HTMLDivElement, NavigationBrandProps>(
|
||||
<Box
|
||||
ref={ref}
|
||||
onClick={onClick}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
cursor: onClick || href ? 'pointer' : 'default',
|
||||
mr: 2,
|
||||
}}
|
||||
className={`${styles.brand} ${onClick || href ? styles.clickable : ''}`}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -29,12 +25,12 @@ const NavigationBrand = forwardRef<HTMLDivElement, NavigationBrandProps>(
|
||||
NavigationBrand.displayName = 'NavigationBrand'
|
||||
|
||||
const NavigationSeparator = forwardRef<HTMLHRElement, Record<string, never>>((props, ref) => {
|
||||
return <Divider ref={ref} orientation="vertical" flexItem sx={{ mx: 1 }} {...props} />
|
||||
return <Divider ref={ref} vertical className={styles.separator} {...props} />
|
||||
})
|
||||
NavigationSeparator.displayName = 'NavigationSeparator'
|
||||
|
||||
const NavigationSpacer = forwardRef<HTMLDivElement, Record<string, never>>((props, ref) => {
|
||||
return <Box ref={ref} sx={{ flexGrow: 1 }} {...props} />
|
||||
return <Box ref={ref} className={styles.spacer} {...props} />
|
||||
})
|
||||
NavigationSpacer.displayName = 'NavigationSpacer'
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
'use client'
|
||||
|
||||
import { Menu as MenuIcon } from '@/fakemui/icons'
|
||||
import { Box, Drawer, IconButton, useMediaQuery, useTheme } from '@mui/material'
|
||||
import { Box, Drawer, IconButton, useMediaQuery } from '@/fakemui'
|
||||
import { forwardRef, ReactNode } from 'react'
|
||||
|
||||
import { MenuItemList, type MenuItemListProps, type SidebarItem } from './MenuItemList'
|
||||
import { SidebarHeader, type SidebarHeaderProps } from './Sidebar/Header'
|
||||
import { SidebarSection, SidebarSeparator } from './Sidebar/NavSections'
|
||||
import styles from './Navigation.module.scss'
|
||||
|
||||
interface SidebarProps {
|
||||
children?: ReactNode
|
||||
@@ -30,8 +31,8 @@ const Sidebar = forwardRef<HTMLDivElement, SidebarProps>(
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const theme = useTheme()
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
|
||||
// Use media query to determine mobile vs desktop
|
||||
const isMobile = useMediaQuery('(max-width: 959px)')
|
||||
const actualVariant = isMobile ? 'temporary' : variant
|
||||
|
||||
return (
|
||||
@@ -41,20 +42,16 @@ const Sidebar = forwardRef<HTMLDivElement, SidebarProps>(
|
||||
anchor={anchor}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
sx={{
|
||||
width: open ? width : 0,
|
||||
flexShrink: 0,
|
||||
'& .MuiDrawer-paper': {
|
||||
width: width,
|
||||
boxSizing: 'border-box',
|
||||
bgcolor: 'background.paper',
|
||||
borderRight: 1,
|
||||
borderColor: 'divider',
|
||||
},
|
||||
}}
|
||||
className={styles.sidebar}
|
||||
style={{
|
||||
'--sidebar-width': `${width}px`,
|
||||
width: open ? width : 0
|
||||
} as React.CSSProperties}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<div className={styles.sidebarPaper} style={{ width }}>
|
||||
{children}
|
||||
</div>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
@@ -69,11 +66,7 @@ const SidebarContent = forwardRef<HTMLDivElement, SidebarContentProps>(
|
||||
({ children, ...props }, ref) => (
|
||||
<Box
|
||||
ref={ref}
|
||||
sx={{
|
||||
flex: 1,
|
||||
overflow: 'auto',
|
||||
py: 1,
|
||||
}}
|
||||
className={styles.sidebarContent}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -90,11 +83,7 @@ const SidebarFooter = forwardRef<HTMLDivElement, SidebarFooterProps>(
|
||||
({ children, ...props }, ref) => (
|
||||
<Box
|
||||
ref={ref}
|
||||
sx={{
|
||||
p: 2,
|
||||
borderTop: 1,
|
||||
borderColor: 'divider',
|
||||
}}
|
||||
className={styles.sidebarFooter}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -109,7 +98,7 @@ interface SidebarToggleProps {
|
||||
|
||||
const SidebarToggle = forwardRef<HTMLButtonElement, SidebarToggleProps>(
|
||||
({ onClick, ...props }, ref) => (
|
||||
<IconButton ref={ref} onClick={onClick} edge="start" {...props}>
|
||||
<IconButton ref={ref} onClick={onClick} {...props}>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChevronLeft as ChevronLeftIcon } from '@/fakemui/icons'
|
||||
import { Box, IconButton } from '@mui/material'
|
||||
import { Box, IconButton } from '@/fakemui'
|
||||
import { forwardRef, ReactNode } from 'react'
|
||||
import styles from '../Navigation.module.scss'
|
||||
|
||||
interface SidebarHeaderProps {
|
||||
children?: ReactNode
|
||||
@@ -13,18 +14,12 @@ const SidebarHeader = forwardRef<HTMLDivElement, SidebarHeaderProps>(
|
||||
return (
|
||||
<Box
|
||||
ref={ref}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
p: 2,
|
||||
minHeight: 64,
|
||||
}}
|
||||
className={styles.sidebarHeader}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
{showCloseButton && onClose && (
|
||||
<IconButton onClick={onClose} size="small">
|
||||
<IconButton onClick={onClose} sm>
|
||||
<ChevronLeftIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Box, Divider, Typography } from '@mui/material'
|
||||
import { Box, Divider, Typography } from '@/fakemui'
|
||||
import { forwardRef, ReactNode } from 'react'
|
||||
import styles from '../Navigation.module.scss'
|
||||
|
||||
interface SidebarSectionProps {
|
||||
title?: string
|
||||
@@ -9,19 +10,11 @@ interface SidebarSectionProps {
|
||||
const SidebarSection = forwardRef<HTMLDivElement, SidebarSectionProps>(
|
||||
({ title, children, ...props }, ref) => {
|
||||
return (
|
||||
<Box ref={ref} sx={{ py: 1 }} {...props}>
|
||||
<Box ref={ref} className={styles.sidebarSection} {...props}>
|
||||
{title && (
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
px: 2,
|
||||
py: 1,
|
||||
display: 'block',
|
||||
color: 'text.secondary',
|
||||
fontWeight: 600,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: '0.05em',
|
||||
}}
|
||||
className={styles.sectionTitle}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
@@ -34,7 +27,7 @@ const SidebarSection = forwardRef<HTMLDivElement, SidebarSectionProps>(
|
||||
SidebarSection.displayName = 'SidebarSection'
|
||||
|
||||
const SidebarSeparator = forwardRef<HTMLHRElement, Record<string, never>>((props, ref) => {
|
||||
return <Divider ref={ref} sx={{ my: 1 }} {...props} />
|
||||
return <Divider ref={ref} className={styles.sidebarSeparator} {...props} />
|
||||
})
|
||||
SidebarSeparator.displayName = 'SidebarSeparator'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user