mui-treasury
itemapp-analyticssource: ok · refreshed
App Analytics
A app-analytics item.
npx shadcn add "https://mui-treasury.com/r/app-analytics.json"free
No selection tags yet — empty means no evidence, not lack of support.
Dependencies
Bundle weight · light@mui/icons-material@mui/material@emotion/react@emotion/styled
Registry dependencies
https://www.mui-treasury.com/r/layout-core.json
Files8 · source cached 10/8/2026, 4:45:06 AM
layout/app-analytics/app-analytics.tsx
'use client';
import React from 'react';
import ChevronLeftRounded from '@mui/icons-material/ChevronLeftRounded';
import MenuRounded from '@mui/icons-material/MenuRounded';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import IconButton from '@mui/material/IconButton';
import Tab from '@mui/material/Tab';
import Typography from '@mui/material/Typography';
import useScrollTrigger from '@mui/material/useScrollTrigger';
import {
Content,
EdgeDrawerClose,
EdgeDrawerTrigger,
EdgeSidebar,
EdgeSidebarCollapser,
EdgeSidebarContent,
Header,
Root,
} from '../layout-core';
import { layoutVisibility } from '../layout-core/layoutVisibility';
import {
IconNavMockup,
LinkNavMockup,
SideNavUserInfoMockup,
StatCardMockup,
TopUsersCardMockup,
UserActiveCardMockup,
} from './mockups/dashboard';
import { UnderlineTabs } from './mockups/tabs';
import { Word } from './mockups/typography';
export function LayoutV6AppAnalytics() {
const [tabIndex, setTabIndex] = React.useState(0);
const trigger = useScrollTrigger({
threshold: 0,
disableHysteresis: true,
});
return (
<Root>
<Header
height={{ xs: '48px', sm: '64px', md: '72px' }}
sx={{
bgcolor: 'rgba(255,255,255,0.5)',
backdropFilter: 'blur(12px)',
...(trigger && {
transition: '0.2s',
boxShadow: '0 0 4px 0 #e2e8f0',
'&:before': {
content: '""',
position: 'absolute',
display: 'block',
width: '100%',
height: '1px',
bgcolor: 'grey.200',
bottom: 0,
},
}),
}}
>
<Box
sx={{
px: { xs: 1, md: 2.5 },
display: 'flex',
alignItems: 'center',
gap: 1,
}}
>
<EdgeDrawerTrigger
render={
<IconButton>
<MenuRounded />
</IconButton>
}
/>
<EdgeSidebarCollapser
render={
<IconButton>
<ChevronLeftRounded
className={layoutVisibility.visibleOnEdgePermanentUncollapsed}
/>
<MenuRounded
className={layoutVisibility.visibleOnEdgePermanentCollapsed}
/>
</IconButton>
}
/>
<Typography
variant="h6"
sx={{ fontSize: 'clamp(18px, 1vw + 1rem, 24px)' }}
>
<b>Analytics</b>
</Typography>
</Box>
</Header>
<EdgeSidebar
permanentAutoCollapse="xl"
variant={{
xs: ['drawer'],
lg: [
'permanent',
{
width: '300px',
collapsedWidth: '80px',
hoverUncollapse: true,
},
],
}}
>
<EdgeDrawerClose />
<EdgeSidebarContent>
<SideNavUserInfoMockup />
<Box
sx={{
borderTop: '1px solid',
borderColor: 'grey.200',
display: 'flex',
height: '100%',
}}
>
<IconNavMockup size="small" />
<LinkNavMockup />
</Box>
</EdgeSidebarContent>
</EdgeSidebar>
<Content>
<UnderlineTabs
value={tabIndex}
onChange={(_event, index) => setTabIndex(index)}
sx={{
minHeight: { xs: 44, md: 48 },
px: 2,
'& .MuiTab-root': {
minHeight: { xs: 44, md: 48 },
minWidth: 0,
fontSize: { md: 16 },
},
}}
>
<Tab label={<Word cached />} disableTouchRipple />
<Tab label={<Word cached />} disableTouchRipple />
<Tab label={<Word cached />} disableTouchRipple />
</UnderlineTabs>
<Box
sx={{
height: '16vh',
minHeight: 240,
borderRadius: 2,
bgcolor: 'rgba(0 0 0 / 0.12)',
m: 2,
}}
/>
<Box sx={{ px: 2 }}>
<Grid container spacing={2}>
<Grid size={{ xs: 12, sm: 6, md: 8 }}>
<Grid container spacing={2}>
<Grid size={6}>
<StatCardMockup />
</Grid>
<Grid size={6}>
<StatCardMockup />
</Grid>
<Grid size={6}>
<StatCardMockup />
</Grid>
<Grid size={6}>
<StatCardMockup />
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<UserActiveCardMockup />
</Grid>
</Grid>
</Grid>
<Grid size={{ xs: 12, sm: 6, md: 4 }}>
<TopUsersCardMockup sx={{ height: '100%' }} />
</Grid>
</Grid>
</Box>
<br />
<br />
<br />
</Content>
</Root>
);
}
layout/app-analytics/mockups/dashboard.tsx
'use client';
import React from 'react';
import AppRegistrationRounded from '@mui/icons-material/AppRegistrationRounded';
import EventNoteRounded from '@mui/icons-material/EventNoteRounded';
import ForumRounded from '@mui/icons-material/ForumRounded';
import HomeRounded from '@mui/icons-material/HomeRounded';
import SearchRounded from '@mui/icons-material/SearchRounded';
import SettingsRounded from '@mui/icons-material/SettingsRounded';
import Avatar from '@mui/material/Avatar';
import Box, { BoxProps } from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import IconButton, { IconButtonProps } from '@mui/material/IconButton';
import LinearProgress from '@mui/material/LinearProgress';
import List, { ListProps } from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import ListItemButton from '@mui/material/ListItemButton';
import Typography from '@mui/material/Typography';
import { alpha } from '@mui/material/styles';
import { Circle, Square } from './shapes';
import { Word } from './typography';
import { getLightGrey, getLightestGrey } from './utils';
// --- IconNav ---
const defaultIcons = [
<SearchRounded key="search" />,
<HomeRounded key="home" />,
<ForumRounded key="forum" />,
<SettingsRounded key="settings" />,
<AppRegistrationRounded key="app" />,
<EventNoteRounded key="event" />,
];
export const IconNavMockup = ({
activeIndex = 1,
icons = defaultIcons,
size,
...props
}: { icons?: Array<React.ReactNode>; activeIndex?: number } & Pick<
IconButtonProps,
'size'
> &
BoxProps) => {
return (
<Box
{...props}
sx={{
display: 'inline-flex',
flexDirection: 'column',
gap: 2,
p: 2,
bgcolor: getLightestGrey,
'& .MuiIconButton-root': {
borderRadius: 2,
},
...props.sx,
}}
>
{icons.map((icon, index) => (
<IconButton
key={index}
disableTouchRipple
size={size}
sx={{
...(index === 0 && { mb: 0 }),
...(index === activeIndex && {
bgcolor: (theme) => alpha(theme.palette.primary.main, 0.12),
'& svg': {
color: (theme) => theme.palette.primary.main,
},
}),
}}
>
{icon}
</IconButton>
))}
</Box>
);
};
// --- LinkNav ---
export const LinkNavMockup = ({
lineCount = 5,
...props
}: { lineCount?: number } & ListProps) => {
return (
<List
{...props}
sx={{
flexGrow: 1,
p: 2,
'& .MuiListItemButton-root': {
borderRadius: 2,
'&:hover': {
bgcolor: (theme) => alpha(theme.palette.grey[300], 0.2),
color: 'grey.500',
},
},
...props.sx,
}}
>
{[...Array(lineCount).fill(undefined)].map((_, index) => (
<ListItem key={index} disablePadding>
<ListItemButton>
<Word sx={{ my: 1 }} />
</ListItemButton>
</ListItem>
))}
</List>
);
};
// --- SideNavUserInfo ---
export const SideNavUserInfoMockup = ({
collapsed,
...props
}: { collapsed?: boolean } & BoxProps) => {
return (
<Box
{...props}
sx={{
bgcolor: getLightestGrey,
mr: '1px',
p: 1.5,
display: 'flex',
alignItems: 'center',
...props.sx,
}}
>
<Circle sx={{ fontSize: collapsed ? 36 : 48, transition: '0.2s' }} />
{!collapsed && (
<Box sx={{ ml: 1.5, minWidth: '0px' }}>
<Word />
<Word
sx={{
height: 10,
borderRadius: 2,
mt: 0.75,
bgcolor: getLightGrey,
}}
/>
</Box>
)}
</Box>
);
};
// --- StatCard ---
export const StatCardMockup = (props: BoxProps) => {
return (
<Box
{...props}
sx={{
borderRadius: 1,
border: '1px solid',
borderColor: getLightGrey,
bgcolor: 'background.paper',
p: 1.5,
display: 'flex',
alignItems: 'center',
boxShadow: '0 2px 6px 0 rgba(0,0,0,0.08)',
...props.sx,
}}
>
<Square />
<Box sx={{ ml: 1.5, minWidth: '0px' }}>
<Word
sx={{
height: 10,
borderRadius: 3,
bgcolor: getLightGrey,
m: 0,
}}
/>
<Word sx={{ mt: 0.5, mb: 0 }} />
</Box>
</Box>
);
};
// --- TopUsersCard ---
export const TopUsersCardMockup = ({
userCount = 5,
...props
}: { userCount?: number } & BoxProps) => {
return (
<Box
{...props}
sx={{
borderRadius: 1,
border: '1px solid',
borderColor: getLightGrey,
bgcolor: 'background.paper',
boxShadow: '0 2px 6px 0 rgba(0,0,0,0.08)',
...props.sx,
}}
>
<Box sx={{ display: 'flex', p: 1.5, alignItems: 'center' }}>
<Box>
<Word
sx={{
height: 10,
borderRadius: 3,
bgcolor: getLightGrey,
m: 0,
width: 40,
}}
/>
<Word sx={{ mt: 0.5, mb: 0 }} />
</Box>
<Circle sx={{ ml: 'auto', fontSize: 24 }} />
</Box>
<Divider />
<List>
{[...Array(userCount).fill(undefined)].map((_, index) => (
<ListItem key={index}>
<ListItemAvatar>
<Avatar />
</ListItemAvatar>
<Word />
</ListItem>
))}
</List>
</Box>
);
};
// --- UserActiveCard ---
export const UserActiveCardMockup = (props: BoxProps) => {
return (
<Box
{...props}
sx={{
borderRadius: 1,
border: '1px solid',
borderColor: getLightGrey,
bgcolor: 'background.paper',
p: 1.5,
boxShadow: '0 2px 6px 0 rgba(0,0,0,0.08)',
...props.sx,
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', width: '100%' }}>
<Word sx={{ bgcolor: getLightGrey }} />
<Circle sx={{ fontSize: 20, ml: 'auto' }} />
</Box>
<br />
<Box sx={{ display: 'flex', justifyContent: 'space-around' }}>
<Box>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Square sx={{ fontSize: 16, bgcolor: 'primary.main', mr: 1 }} />
<Typography variant="h4">
<b>92%</b>
</Typography>
</Box>
<Word
sx={{
bgcolor: getLightGrey,
ml: 3,
height: 12,
borderRadius: 2,
width: 48,
}}
/>
</Box>
<Box>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Square sx={{ fontSize: 16, bgcolor: 'error.main', mr: 1 }} />
<Typography variant="h4">
<b>8%</b>
</Typography>
</Box>
<Word
sx={{
bgcolor: getLightGrey,
ml: 3,
height: 12,
borderRadius: 2,
width: 48,
}}
/>
</Box>
</Box>
<br />
<LinearProgress
variant="determinate"
value={92}
sx={{
height: 10,
borderRadius: 3,
bgcolor: getLightGrey,
'& > .MuiLinearProgress-bar': {
borderRadius: 3,
},
}}
/>
<Box
sx={{
height: 16,
}}
/>
<LinearProgress
variant="determinate"
value={8}
sx={{
height: 10,
borderRadius: 3,
bgcolor: getLightGrey,
'& > .MuiLinearProgress-bar': {
borderRadius: 3,
bgcolor: 'error.main',
},
}}
/>
<br />
</Box>
);
};
layout/app-analytics/mockups/index.ts
export * from './utils';
export * from './shapes';
export * from './typography';
export * from './dashboard';
export * from './tabs';
layout/app-analytics/mockups/shapes.tsx
'use client';
import React from 'react';
import Box, { BoxProps } from '@mui/material/Box';
import { getBaseGrey } from './utils';
export const Circle = (props: BoxProps) => (
<Box
{...props}
sx={{
width: '1em',
height: '1em',
fontSize: '40px',
backgroundColor: getBaseGrey,
borderRadius: 10,
flexShrink: 0,
...props.sx,
}}
/>
);
export const Pill = (props: BoxProps) => (
<Box
{...props}
sx={{
width: 56,
height: 24,
backgroundColor: getBaseGrey,
borderRadius: 5,
...props.sx,
}}
/>
);
export const Square = (props: BoxProps) => (
<Box
{...props}
sx={{
width: '1em',
height: '1em',
fontSize: '40px',
backgroundColor: getBaseGrey,
borderRadius: 1,
flexShrink: 0,
...props.sx,
}}
/>
);
layout/app-analytics/mockups/tabs.tsx
'use client';
import Tabs from '@mui/material/Tabs';
import { styled } from '@mui/material/styles';
export const UnderlineTabs = styled(Tabs)(({ theme }) => ({
'&:before': {
content: '""',
display: 'block',
height: '1px',
backgroundColor: theme.palette.grey[200],
left: 0,
bottom: 0,
width: '100%',
position: 'absolute',
},
'& .MuiTab-root': {
textTransform: 'none',
paddingLeft: 0,
paddingRight: 0,
marginLeft: theme.spacing(2),
marginRight: theme.spacing(2),
'&:first-of-type': {
marginLeft: 0,
},
'&:last-of-type': {
marginRight: 0,
},
},
}));
layout/app-analytics/mockups/typography.tsx
'use client';
import React from 'react';
import Box, { BoxProps } from '@mui/material/Box';
import { SxProps, Theme } from '@mui/material/styles';
import { getBaseGrey } from './utils';
const createTypography = (generateSx: () => BoxProps['sx']) => {
const Component = ({
cached,
sx = [],
...props
}: { cached?: boolean } & BoxProps) => {
const ref = React.useRef(generateSx());
const resolvedSx: SxProps<Theme> =
(cached ? ref.current : generateSx()) || [];
return (
<Box
{...props}
sx={[
{
height: 16,
borderRadius: 1,
bgcolor: getBaseGrey,
},
...(Array.isArray(resolvedSx) ? resolvedSx : [resolvedSx]),
...(Array.isArray(sx) ? sx : [sx]),
]}
/>
);
};
return Component;
};
export const H1 = createTypography(() => ({
height: 40,
width: '16ch',
maxWidth: '100%',
mt: 3,
mb: 1,
}));
export const Text = createTypography(() => ({
height: 16,
mt: 1.5,
mb: 1.5,
width: '100%',
maxWidth: '100%',
}));
export const Word = createTypography(() => ({
height: 16,
width: '10ch',
maxWidth: '100%',
}));
layout/app-analytics/mockups/utils.ts
'use client';
import { Theme } from '@mui/material/styles';
export const getBaseGrey = (theme: Theme): string =>
theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.12)' : 'grey.300';
export const getLightGrey = (theme: Theme): string =>
theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.09)' : 'grey.200';
export const getLightestGrey = (theme: Theme): string =>
theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.07)' : 'grey.50';
let seed = 0;
function seededRandom() {
seed = (seed * 9301 + 49297) % 233280;
return seed / 233280;
}
export const randomBetween = (min: number, max: number, unit?: string) => {
const result = Math.floor(seededRandom() * (max - min)) + min;
if (unit) return `${result}${unit}`;
return result;
};
layout/app-analytics/index.ts
export * from './app-analytics';
export * from './dashboard';
export * from './index';
export * from './shapes';
export * from './tabs';
export * from './typography';
export * from './utils';