mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-03 16:41:27 +01:00
removed sidebar
This commit is contained in:
1 parent
0621437546
commit
e714e1ea51
4 files changed
+16
-504
No files matched your search
+5
-110
@@ -1,32 +1,14 @@
|
|||||||
import React, { Suspense, lazy, useEffect, useState } from 'react';
|
import React, { Suspense, lazy, useEffect } from 'react';
|
||||||
import { Routes, Route, Link, Navigate } from 'react-router-dom';
|
import { Routes, Route, Link, Navigate } from 'react-router-dom';
|
||||||
import {
|
import { Typography, Button, Box, CircularProgress, useTheme as useMuiTheme } from '@mui/material';
|
||||||
Typography,
|
|
||||||
Button,
|
|
||||||
Box,
|
|
||||||
IconButton,
|
|
||||||
SwipeableDrawer,
|
|
||||||
CircularProgress,
|
|
||||||
Badge,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme as useMuiTheme,
|
|
||||||
} from '@mui/material';
|
|
||||||
import { GlassAppBar } from './components/ui';
|
|
||||||
import MenuIcon from '@mui/icons-material/Menu';
|
|
||||||
import NotificationsIcon from '@mui/icons-material/Notifications';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import CookieBanner from './components/CookieBanner';
|
import CookieBanner from './components/CookieBanner';
|
||||||
import { GlobalSearch } from './app/GlobalSearch';
|
|
||||||
import { useAuth } from './hooks/useAuth';
|
import { useAuth } from './hooks/useAuth';
|
||||||
import { useTheme } from './hooks/useTheme';
|
import { useTheme } from './hooks/useTheme';
|
||||||
import { useDrawerAnchor } from './hooks/useDrawerAnchor';
|
import { TopBar } from './components/layout/TopBar';
|
||||||
import { NavSidebar } from './components/layout/NavSidebar';
|
|
||||||
import { BrandMark } from './components/layout/BrandMark';
|
|
||||||
import { DesktopTopBar } from './components/layout/DesktopTopBar';
|
|
||||||
import { CategoryBar } from './components/layout/CategoryBar';
|
import { CategoryBar } from './components/layout/CategoryBar';
|
||||||
import { useCategories } from './api/queries/useCategories';
|
import { useCategories } from './api/queries/useCategories';
|
||||||
import { NotificationMenu } from './components/layout/NotificationMenu';
|
|
||||||
import { RequireSuperuser } from './components/auth/RequireSuperuser';
|
import { RequireSuperuser } from './components/auth/RequireSuperuser';
|
||||||
import type { CatppuccinTheme } from './theme';
|
import type { CatppuccinTheme } from './theme';
|
||||||
|
|
||||||
@@ -58,14 +40,10 @@ const AdminReplyDetail = lazy(() => import('./pages/AdminReplyDetail'));
|
|||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const muiTheme = useMuiTheme();
|
const muiTheme = useMuiTheme();
|
||||||
const { user, loadingUser } = useAuth();
|
const { user } = useAuth();
|
||||||
const { themeName, handleThemeChange } = useTheme();
|
const { themeName, handleThemeChange } = useTheme();
|
||||||
const { anchor: mobileAnchor } = useDrawerAnchor();
|
|
||||||
|
|
||||||
const [notifAnchorEl, setNotifAnchorEl] = useState<null | HTMLElement>(null);
|
|
||||||
const { data: categories = [] } = useCategories();
|
const { data: categories = [] } = useCategories();
|
||||||
const isMobile = useMediaQuery(muiTheme.breakpoints.down('md'));
|
|
||||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.body.style.backgroundColor = muiTheme.palette.background.default;
|
document.body.style.backgroundColor = muiTheme.palette.background.default;
|
||||||
@@ -76,33 +54,6 @@ const App: React.FC = () => {
|
|||||||
await handleThemeChange(name, !!user);
|
await handleThemeChange(name, !!user);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hamburger = (
|
|
||||||
<IconButton
|
|
||||||
color="inherit"
|
|
||||||
onClick={() => setDrawerOpen((o) => !o)}
|
|
||||||
aria-label="toggle navigation"
|
|
||||||
sx={{ mx: 0.5 }}
|
|
||||||
>
|
|
||||||
<MenuIcon />
|
|
||||||
</IconButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
const notificationsMenu = (
|
|
||||||
<>
|
|
||||||
<IconButton color="inherit" onClick={(e) => setNotifAnchorEl(e.currentTarget)} sx={{ ml: 1 }}>
|
|
||||||
<Badge badgeContent={user?.unread_notifications_count || 0} color="error">
|
|
||||||
<NotificationsIcon />
|
|
||||||
</Badge>
|
|
||||||
</IconButton>
|
|
||||||
<NotificationMenu
|
|
||||||
anchorEl={notifAnchorEl}
|
|
||||||
open={Boolean(notifAnchorEl)}
|
|
||||||
onClose={() => setNotifAnchorEl(null)}
|
|
||||||
menuSx={{ mt: 1 }}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@@ -112,63 +63,7 @@ const App: React.FC = () => {
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isMobile && (
|
<TopBar />
|
||||||
<GlassAppBar>
|
|
||||||
{mobileAnchor === 'left' && hamburger}
|
|
||||||
|
|
||||||
<Box sx={{ mr: 1, display: 'flex', alignItems: 'center' }}>
|
|
||||||
<BrandMark compact />
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<GlobalSearch />
|
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
|
||||||
{!loadingUser && (
|
|
||||||
<>
|
|
||||||
{user && notificationsMenu}
|
|
||||||
|
|
||||||
{!user && (
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
component={Link}
|
|
||||||
to="/login"
|
|
||||||
sx={{ borderRadius: 2, ml: 1 }}
|
|
||||||
>
|
|
||||||
{t('nav.login')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{mobileAnchor === 'right' && hamburger}
|
|
||||||
</Box>
|
|
||||||
</GlassAppBar>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isMobile && <DesktopTopBar />}
|
|
||||||
|
|
||||||
{isMobile && (
|
|
||||||
<SwipeableDrawer
|
|
||||||
anchor={mobileAnchor}
|
|
||||||
open={drawerOpen}
|
|
||||||
onOpen={() => setDrawerOpen(true)}
|
|
||||||
onClose={() => setDrawerOpen(false)}
|
|
||||||
disableBackdropTransition
|
|
||||||
disableDiscovery
|
|
||||||
slotProps={{
|
|
||||||
paper: {
|
|
||||||
sx: {
|
|
||||||
height: '100vh',
|
|
||||||
maxHeight: '100vh',
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<NavSidebar categories={categories} onNavigate={() => setDrawerOpen(false)} />
|
|
||||||
</SwipeableDrawer>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<CategoryBar categories={categories} />
|
<CategoryBar categories={categories} />
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export const BrandMark = ({ onNavigate, compact = false }: BrandMarkProps) => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{!compact && (
|
{!compact && (
|
||||||
<Box sx={{ minWidth: 0 }}>
|
<Box sx={{ minWidth: 0, display: { xs: 'none', md: 'block' } }}>
|
||||||
<Typography sx={{ fontWeight: 800, lineHeight: 1.1, letterSpacing: '-0.01em' }} noWrap>
|
<Typography sx={{ fontWeight: 800, lineHeight: 1.1, letterSpacing: '-0.01em' }} noWrap>
|
||||||
{t('brand.name')}
|
{t('brand.name')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -1,387 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
|
||||||
import {
|
|
||||||
Avatar,
|
|
||||||
Badge,
|
|
||||||
Box,
|
|
||||||
Collapse,
|
|
||||||
Divider,
|
|
||||||
List,
|
|
||||||
ListItem,
|
|
||||||
ListItemAvatar,
|
|
||||||
ListItemButton,
|
|
||||||
ListItemIcon,
|
|
||||||
ListItemText,
|
|
||||||
Typography,
|
|
||||||
} from '@mui/material';
|
|
||||||
import ExpandLess from '@mui/icons-material/ExpandLess';
|
|
||||||
import ExpandMore from '@mui/icons-material/ExpandMore';
|
|
||||||
import HomeOutlinedIcon from '@mui/icons-material/HomeOutlined';
|
|
||||||
import GroupsOutlinedIcon from '@mui/icons-material/GroupsOutlined';
|
|
||||||
import CategoryOutlinedIcon from '@mui/icons-material/CategoryOutlined';
|
|
||||||
import PersonOutlineOutlinedIcon from '@mui/icons-material/PersonOutlineOutlined';
|
|
||||||
import CollectionsBookmarkOutlinedIcon from '@mui/icons-material/CollectionsBookmarkOutlined';
|
|
||||||
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
|
|
||||||
import HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineOutlined';
|
|
||||||
import AdminPanelSettingsOutlinedIcon from '@mui/icons-material/AdminPanelSettingsOutlined';
|
|
||||||
import LogoutOutlinedIcon from '@mui/icons-material/LogoutOutlined';
|
|
||||||
import LoginOutlinedIcon from '@mui/icons-material/LoginOutlined';
|
|
||||||
import NotificationsOutlinedIcon from '@mui/icons-material/NotificationsOutlined';
|
|
||||||
import PeopleOutlineOutlinedIcon from '@mui/icons-material/PeopleOutlineOutlined';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useAuth } from '../../hooks/useAuth';
|
|
||||||
import { GlobalSearch } from '../../app/GlobalSearch';
|
|
||||||
import { NotificationMenu } from './NotificationMenu';
|
|
||||||
import { BrandMark } from './BrandMark';
|
|
||||||
|
|
||||||
export const NAV_SIDEBAR_WIDTH = 280;
|
|
||||||
|
|
||||||
export interface NavSidebarProps {
|
|
||||||
categories: { name: string; slug: string }[];
|
|
||||||
onNavigate?: () => void;
|
|
||||||
showSearch?: boolean;
|
|
||||||
showNotifications?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NavSidebar = ({
|
|
||||||
categories,
|
|
||||||
onNavigate,
|
|
||||||
showSearch = false,
|
|
||||||
showNotifications = false,
|
|
||||||
}: NavSidebarProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const location = useLocation();
|
|
||||||
const { user, following, logout } = useAuth();
|
|
||||||
// Categories are the primary browse axis — open by default so they're
|
|
||||||
// discoverable without an extra click (UX audit #4).
|
|
||||||
const [catOpen, setCatOpen] = useState(true);
|
|
||||||
const [followingOpen, setFollowingOpen] = useState(false);
|
|
||||||
const [notifAnchorEl, setNotifAnchorEl] = useState<null | HTMLElement>(null);
|
|
||||||
|
|
||||||
const close = () => onNavigate?.();
|
|
||||||
const isActive = (path: string) =>
|
|
||||||
path === '/' ? location.pathname === '/' : location.pathname.startsWith(path);
|
|
||||||
|
|
||||||
const unreadCount = user?.unread_notifications_count || 0;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: NAV_SIDEBAR_WIDTH,
|
|
||||||
height: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}
|
|
||||||
role="presentation"
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
p: 2,
|
|
||||||
borderBottom: '1px solid',
|
|
||||||
borderColor: 'divider',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<BrandMark onNavigate={close} />
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{user ? (
|
|
||||||
<Box
|
|
||||||
component={Link}
|
|
||||||
to={`/profile/${user.username}`}
|
|
||||||
onClick={close}
|
|
||||||
sx={{
|
|
||||||
p: 2,
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 1.5,
|
|
||||||
color: 'inherit',
|
|
||||||
textDecoration: 'none',
|
|
||||||
borderBottom: '1px solid',
|
|
||||||
borderColor: 'divider',
|
|
||||||
'&:hover': { bgcolor: 'action.hover' },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Avatar
|
|
||||||
src={user.avatar || undefined}
|
|
||||||
sx={{
|
|
||||||
width: 44,
|
|
||||||
height: 44,
|
|
||||||
border: '2px solid',
|
|
||||||
borderColor: 'primary.main',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{user.username.charAt(0).toUpperCase()}
|
|
||||||
</Avatar>
|
|
||||||
<Box sx={{ minWidth: 0, flex: 1 }}>
|
|
||||||
<Typography
|
|
||||||
variant="subtitle1"
|
|
||||||
sx={{
|
|
||||||
fontWeight: 700,
|
|
||||||
lineHeight: 1.2,
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{user.username}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="caption" color="text.secondary">
|
|
||||||
{t('nav.profile')}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{showSearch && (
|
|
||||||
<Box sx={{ p: 2, borderBottom: '1px solid', borderColor: 'divider' }}>
|
|
||||||
<GlobalSearch compact />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<List sx={{ flex: 1, overflowY: 'auto', py: 1 }}>
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton component={Link} to="/" onClick={close} selected={isActive('/')}>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<HomeOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.home')} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
|
|
||||||
{user && (
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to="/community"
|
|
||||||
onClick={close}
|
|
||||||
selected={isActive('/community')}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<GroupsOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.community')} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{user && showNotifications && (
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton onClick={(e) => setNotifAnchorEl(e.currentTarget)}>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<Badge badgeContent={unreadCount} color="error">
|
|
||||||
<NotificationsOutlinedIcon />
|
|
||||||
</Badge>
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.notifications', { defaultValue: 'Notifications' })} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ListItemButton
|
|
||||||
onClick={() => setCatOpen(!catOpen)}
|
|
||||||
selected={location.pathname.startsWith('/category/')}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<CategoryOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.categories')} />
|
|
||||||
{catOpen ? <ExpandLess /> : <ExpandMore />}
|
|
||||||
</ListItemButton>
|
|
||||||
<Collapse in={catOpen} timeout="auto" unmountOnExit>
|
|
||||||
<List component="div" disablePadding>
|
|
||||||
{categories.map((cat) => (
|
|
||||||
<ListItemButton
|
|
||||||
key={cat.slug}
|
|
||||||
component={Link}
|
|
||||||
to={`/category/${cat.slug}`}
|
|
||||||
onClick={close}
|
|
||||||
selected={location.pathname === `/category/${cat.slug}`}
|
|
||||||
sx={{ pl: 7 }}
|
|
||||||
>
|
|
||||||
<ListItemText primary={t(`categories.${cat.slug}`, { defaultValue: cat.name })} />
|
|
||||||
</ListItemButton>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
</Collapse>
|
|
||||||
|
|
||||||
{user && (
|
|
||||||
<>
|
|
||||||
<Divider sx={{ my: 1 }} />
|
|
||||||
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to={`/profile/${user.username}`}
|
|
||||||
onClick={close}
|
|
||||||
selected={location.pathname === `/profile/${user.username}`}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<PersonOutlineOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.profile')} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to="/dashboard"
|
|
||||||
onClick={close}
|
|
||||||
selected={isActive('/dashboard')}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<CollectionsBookmarkOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.dashboard')} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to="/settings"
|
|
||||||
onClick={close}
|
|
||||||
selected={isActive('/settings')}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<SettingsOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.settings')} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to="/support"
|
|
||||||
onClick={close}
|
|
||||||
selected={isActive('/support')}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<HelpOutlineOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('support.title')} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
|
|
||||||
{user.is_superuser && (
|
|
||||||
<>
|
|
||||||
<Divider sx={{ my: 1 }} />
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to="/admin-panel"
|
|
||||||
onClick={close}
|
|
||||||
selected={isActive('/admin-panel')}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<AdminPanelSettingsOutlinedIcon color="primary" />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText
|
|
||||||
primary={t('admin.panelTitle', { defaultValue: 'Admin Panel' })}
|
|
||||||
primaryTypographyProps={{ sx: { color: 'primary.main', fontWeight: 700 } }}
|
|
||||||
/>
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{following.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Divider sx={{ my: 1 }} />
|
|
||||||
<ListItemButton onClick={() => setFollowingOpen(!followingOpen)}>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<PeopleOutlineOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText
|
|
||||||
primary={
|
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
||||||
<span>{t('nav.following')}</span>
|
|
||||||
<Typography variant="caption" color="text.secondary">
|
|
||||||
{following.length}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{followingOpen ? <ExpandLess /> : <ExpandMore />}
|
|
||||||
</ListItemButton>
|
|
||||||
<Collapse in={followingOpen} timeout="auto" unmountOnExit>
|
|
||||||
<List component="div" disablePadding>
|
|
||||||
{following.map((f) => (
|
|
||||||
<ListItem key={f.id} disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to={`/profile/${f.username}`}
|
|
||||||
onClick={close}
|
|
||||||
selected={location.pathname === `/profile/${f.username}`}
|
|
||||||
sx={{ pl: 5 }}
|
|
||||||
>
|
|
||||||
<ListItemAvatar sx={{ minWidth: 40 }}>
|
|
||||||
<Avatar src={f.avatar || undefined} sx={{ width: 28, height: 28 }}>
|
|
||||||
{!f.avatar && f.username.charAt(0).toUpperCase()}
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary={f.username}
|
|
||||||
primaryTypographyProps={{ variant: 'body2' }}
|
|
||||||
/>
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
</Collapse>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!user && (
|
|
||||||
<>
|
|
||||||
<Divider sx={{ my: 1 }} />
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<ListItemButton
|
|
||||||
component={Link}
|
|
||||||
to="/login"
|
|
||||||
onClick={close}
|
|
||||||
selected={isActive('/login')}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40 }}>
|
|
||||||
<LoginOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('nav.login')} />
|
|
||||||
</ListItemButton>
|
|
||||||
</ListItem>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
|
|
||||||
{user && (
|
|
||||||
<Box sx={{ borderTop: '1px solid', borderColor: 'divider' }}>
|
|
||||||
<ListItemButton
|
|
||||||
onClick={() => {
|
|
||||||
close();
|
|
||||||
logout();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ListItemIcon sx={{ minWidth: 40, color: 'error.main' }}>
|
|
||||||
<LogoutOutlinedIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText
|
|
||||||
primary={t('nav.logout')}
|
|
||||||
primaryTypographyProps={{ sx: { color: 'error.main', fontWeight: 600 } }}
|
|
||||||
/>
|
|
||||||
</ListItemButton>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{showNotifications && (
|
|
||||||
<NotificationMenu
|
|
||||||
anchorEl={notifAnchorEl}
|
|
||||||
open={Boolean(notifAnchorEl)}
|
|
||||||
onClose={() => setNotifAnchorEl(null)}
|
|
||||||
onItemNavigate={close}
|
|
||||||
anchorOrigin={{ vertical: 'center', horizontal: 'right' }}
|
|
||||||
transformOrigin={{ vertical: 'center', horizontal: 'left' }}
|
|
||||||
paperSx={{ ml: 1 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
+10
-6
@@ -28,12 +28,14 @@ import { BrandMark } from './BrandMark';
|
|||||||
import { NotificationMenu } from './NotificationMenu';
|
import { NotificationMenu } from './NotificationMenu';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Desktop top bar (md+). Promotes global search to the primary, centered slot;
|
* Top bar for every breakpoint. Promotes global search to the primary, centered
|
||||||
* notifications + an account menu sit on the right. Everything that used to be
|
* slot; notifications + an account menu sit on the right. Everything that used to
|
||||||
* a flat sidebar row (profile, dashboard, settings, support, admin, following,
|
* be a flat sidebar row (profile, dashboard, settings, support, admin, following,
|
||||||
* logout) now lives behind the avatar menu so the chrome stays light.
|
* logout) lives behind the avatar menu — so there's no mobile drawer anymore, the
|
||||||
|
* same dropdown serves all sizes. Browse links (home/community/categories) live
|
||||||
|
* in the CategoryBar below.
|
||||||
*/
|
*/
|
||||||
export const DesktopTopBar = () => {
|
export const TopBar = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { user, following, logout } = useAuth();
|
const { user, following, logout } = useAuth();
|
||||||
|
|
||||||
@@ -45,7 +47,9 @@ export const DesktopTopBar = () => {
|
|||||||
const unreadCount = user?.unread_notifications_count || 0;
|
const unreadCount = user?.unread_notifications_count || 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GlassAppBar toolbarSx={{ maxWidth: 1400, width: '100%', mx: 'auto', px: { md: 6 } }}>
|
<GlassAppBar
|
||||||
|
toolbarSx={{ maxWidth: 1400, width: '100%', mx: 'auto', px: { xs: 1, sm: 4, md: 6 } }}
|
||||||
|
>
|
||||||
<BrandMark />
|
<BrandMark />
|
||||||
|
|
||||||
<GlobalSearch />
|
<GlobalSearch />
|
||||||
Reference in new issue
Block a user