ui redesign

This commit is contained in:
nvrl committed 2026-09-04 23:38:55 +02:00
1 parent d0a027a2a1
commit 67da3061a6
49 files changed
+1496 -458

No files matched your search

+9 -1
View File
@@ -45,7 +45,15 @@ export const BrandMark = ({ onNavigate, compact = false }: BrandMarkProps) => {
>
<Typography
component="span"
sx={{ fontWeight: 900, fontSize: '1.15rem', lineHeight: 1, color: '#fff' }}
// The tile is the primary gradient, so the monogram must use the
// contrast colour the palette computes for it — a literal white
// disappears on the light-accent themes (latte, t0p_sai, mint).
sx={{
fontWeight: 900,
fontSize: '1.15rem',
lineHeight: 1,
color: 'primary.contrastText',
}}
>
H
</Typography>
+66 -73
View File
@@ -12,10 +12,13 @@ export interface CategoryBarProps {
}
/**
* Horizontal nav pinned just under the top bar on every breakpoint. Categories
* are the dominant browse axis — laid out as a scrollable row of tabs — with
* Home / Community / Dashboard as primary links on the left. Replaces the old
* left rail on desktop and mirrors the same sticky chrome on mobile.
* The browse row. Categories are the dominant browse axis, so they get a
* scrollable row of their own with Home / Community / Dashboard leading it.
*
* This renders as the *second row inside* the nav pane (see `GlassAppBar`) —
* it deliberately carries no sticky positioning or glass of its own, so the
* two rows share one pane, one rim and one blur pass instead of stacking two
* translucent bars on top of each other.
*/
export const CategoryBar = ({ categories }: CategoryBarProps) => {
const { t } = useTranslation();
@@ -27,12 +30,16 @@ export const CategoryBar = ({ categories }: CategoryBarProps) => {
const tabSx = (active: boolean) => ({
flexShrink: 0,
borderRadius: 2,
borderRadius: (theme: Theme) => `${theme.tokens.radius.pill}px`,
px: 1.75,
py: 0.75,
fontWeight: active ? 700 : 500,
color: active ? 'primary.main' : 'text.secondary',
bgcolor: active ? (theme: Theme) => alpha(theme.palette.primary.main, 0.12) : 'transparent',
bgcolor: active ? (theme: Theme) => alpha(theme.palette.primary.main, 0.14) : 'transparent',
border: '1px solid',
borderColor: active ? (theme: Theme) => alpha(theme.palette.primary.main, 0.35) : 'transparent',
transition: (theme: Theme) =>
`background-color ${theme.tokens.motion.fast} ${theme.tokens.motion.ease}, border-color ${theme.tokens.motion.fast} ${theme.tokens.motion.ease}`,
'&:hover': {
color: 'text.primary',
bgcolor: 'action.hover',
@@ -43,80 +50,66 @@ export const CategoryBar = ({ categories }: CategoryBarProps) => {
<Box
component="nav"
sx={{
position: 'sticky',
top: { xs: 56, sm: 64 },
zIndex: (theme) => theme.zIndex.appBar - 1,
borderBottom: '1px solid',
borderColor: (theme) => theme.tokens.glass.border,
backgroundColor: (theme) =>
alpha(theme.palette.background.default, theme.palette.mode === 'light' ? 0.8 : 0.6),
backdropFilter: (theme) => theme.tokens.glass.blurStrong,
WebkitBackdropFilter: (theme) => theme.tokens.glass.blurStrong,
maxWidth: 1400,
mx: 'auto',
px: { xs: 1, sm: 4, md: 6 },
display: 'flex',
alignItems: 'center',
gap: { xs: 0.5, md: 1 },
minHeight: { xs: 46, md: 52 },
overflowX: 'auto',
'&::-webkit-scrollbar': { display: 'none' },
scrollbarWidth: 'none',
}}
>
<Button
component={Link}
to="/"
disableRipple
sx={{ ...tabSx(isActive('/')), ml: { xs: -0.5, md: -1.75 } }}
>
<HomeOutlinedIcon sx={{ fontSize: '1.1rem', mr: 0.75 }} />
{t('nav.home')}
</Button>
{user && (
<Button component={Link} to="/community" disableRipple sx={tabSx(isActive('/community'))}>
<GroupsOutlinedIcon sx={{ fontSize: '1.1rem', mr: 0.75 }} />
{t('nav.community')}
</Button>
)}
{user && (
<Button component={Link} to="/dashboard" disableRipple sx={tabSx(isActive('/dashboard'))}>
<CollectionsBookmarkOutlinedIcon sx={{ fontSize: '1.1rem', mr: 0.75 }} />
{t('nav.dashboard')}
</Button>
)}
<Box
sx={{
maxWidth: 1400,
mx: 'auto',
px: { xs: 1, sm: 4, md: 6 },
display: 'flex',
alignItems: 'center',
gap: { xs: 0.5, md: 1 },
minHeight: { xs: 46, md: 52 },
overflowX: 'auto',
'&::-webkit-scrollbar': { display: 'none' },
scrollbarWidth: 'none',
alignSelf: 'stretch',
my: 1.25,
mx: 0.5,
borderLeft: '1px solid',
borderColor: 'divider',
}}
>
<Button
component={Link}
to="/"
disableRipple
sx={{ ...tabSx(isActive('/')), ml: { xs: -0.5, md: -1.75 } }}
>
<HomeOutlinedIcon sx={{ fontSize: '1.1rem', mr: 0.75 }} />
{t('nav.home')}
</Button>
/>
{user && (
<Button component={Link} to="/community" disableRipple sx={tabSx(isActive('/community'))}>
<GroupsOutlinedIcon sx={{ fontSize: '1.1rem', mr: 0.75 }} />
{t('nav.community')}
{categories.map((cat) => {
const path = `/category/${cat.slug}`;
return (
<Button
key={cat.slug}
component={Link}
to={path}
disableRipple
sx={tabSx(location.pathname === path)}
>
{t(`categories.${cat.slug}`, { defaultValue: cat.name })}
</Button>
)}
{user && (
<Button component={Link} to="/dashboard" disableRipple sx={tabSx(isActive('/dashboard'))}>
<CollectionsBookmarkOutlinedIcon sx={{ fontSize: '1.1rem', mr: 0.75 }} />
{t('nav.dashboard')}
</Button>
)}
<Box
sx={{
alignSelf: 'stretch',
my: 1.25,
mx: 0.5,
borderLeft: '1px solid',
borderColor: 'divider',
}}
/>
{categories.map((cat) => {
const path = `/category/${cat.slug}`;
return (
<Button
key={cat.slug}
component={Link}
to={path}
disableRipple
sx={tabSx(location.pathname === path)}
>
{t(`categories.${cat.slug}`, { defaultValue: cat.name })}
</Button>
);
})}
</Box>
);
})}
</Box>
);
};
+8 -2
View File
@@ -22,20 +22,25 @@ import AdminPanelSettingsOutlinedIcon from '@mui/icons-material/AdminPanelSettin
import LogoutOutlinedIcon from '@mui/icons-material/LogoutOutlined';
import { useTranslation } from 'react-i18next';
import { GlassAppBar } from '../ui';
import { CategoryBar } from './CategoryBar';
import { GlobalSearch } from '../../app/GlobalSearch';
import { useAuth } from '../../hooks/useAuth';
import { BrandMark } from './BrandMark';
import { NotificationMenu } from './NotificationMenu';
export interface TopBarProps {
categories: { name: string; slug: string }[];
}
/**
* Top bar for every breakpoint. Promotes global search to the primary, centered
* slot; notifications + an account menu sit on the right. Everything that used to
* be a flat sidebar row (profile, dashboard, settings, support, admin, following,
* 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.
* in the CategoryBar, which now rides as the second row of this same glass pane.
*/
export const TopBar = () => {
export const TopBar = ({ categories }: TopBarProps) => {
const { t } = useTranslation();
const { user, following, logout } = useAuth();
@@ -49,6 +54,7 @@ export const TopBar = () => {
return (
<GlassAppBar
toolbarSx={{ maxWidth: 1400, width: '100%', mx: 'auto', px: { xs: 1, sm: 4, md: 6 } }}
secondary={<CategoryBar categories={categories} />}
>
<BrandMark />