1
0
mirror of https://github.com/Unleash/unleash.git synced 2026-02-04 20:10:52 +01:00

UI tweaks: Navigation sidebar improvements and layout refinements (#11242)

This PR includes various UI improvements and refinements. All changes
focus on improving the visual consistency and layout of the navigation
sidebar and related UI components.

Navigation sidebar layout is restructured to remain sticky while the
page scrolls
<img width="1328" height="734" alt="image"
src="https://github.com/user-attachments/assets/0a4f03ce-096a-4339-b8ad-2e78f5713caa"
/>

Footer is moved to under the main content and not the menu, to allow for
a fixed menu while scrolling
<img width="1374" height="808" alt="image"
src="https://github.com/user-attachments/assets/7a48ff6d-62be-4c2a-9732-b47a48e491ee"
/>

Moved change request banner to only overlay the content and not the
navigation.
<img width="1375" height="810" alt="image"
src="https://github.com/user-attachments/assets/83b86621-4936-49ab-869b-e4b208419a81"
/>

Changed headers on impact metric cards to improve typographic hierarchy
<img width="1367" height="798" alt="image"
src="https://github.com/user-attachments/assets/abb376e0-4790-44e7-abcb-46d7a5593f54"
/>

Header on "Strategy types" is made consistent with other page headers
<img width="1370" height="517" alt="image"
src="https://github.com/user-attachments/assets/de9d052f-6e9c-4640-acea-fdf0ac068f7a"
/>

Release template card titles are set to bold for typographic consistency
<img width="1375" height="799" alt="image"
src="https://github.com/user-attachments/assets/5f89a4a5-3aa2-4b01-b3ab-2be102400732"
/>

---------

Co-authored-by: Henning Sillerud <henning.sillerud@getunleash.io>
This commit is contained in:
Healsi 2026-01-22 12:39:25 +01:00 committed by GitHub
parent 36aad2556e
commit 05efc6b244
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 1498 additions and 1371 deletions

View File

@ -20,7 +20,7 @@ const StyledTab = styled(Button)<{ selected: boolean }>(
textAlign: 'left',
padding: theme.spacing(0, 2),
gap: theme.spacing(1),
fontSize: theme.fontSizes.bodySize,
fontSize: theme.typography.body2.fontSize,
fontWeight: selected
? theme.fontWeight.bold
: theme.fontWeight.medium,

View File

@ -108,7 +108,7 @@ export const ChartItem: FC<ChartItemProps> = ({
{config.mode === 'read' ? <StyledShieldIcon /> : null}
<StyledChartTitle>
{config.title && (
<Typography variant='h6'>{config.title}</Typography>
<Typography variant='h3'>{config.title}</Typography>
)}
<Typography variant='body2' color='text.secondary'>
{getConfigDescription(config)}

View File

@ -49,7 +49,7 @@ export const PlausibleChartItem: FC = () => (
<StyledWidget>
<StyledHeader>
<StyledChartTitle>
<Typography variant='h6'>Plausible Analytics</Typography>
<Typography variant='h3'>Plausible Analytics</Typography>
<Typography variant='body2' color='text.secondary'>
Favorite events from Plausible analytics
</Typography>

View File

@ -65,12 +65,19 @@ const subListItemButtonStyle = (theme: Theme) => ({
},
});
const CappedText = styled(Typography)(({ theme }) => ({
const CappedText = styled(Typography, {
shouldForwardProp: (prop) => prop !== 'bold',
})<{
bold?: boolean;
}>(({ theme, bold }) => ({
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
width: '100%',
paddingTop: theme.spacing(0.25),
fontWeight: bold
? theme.typography.fontWeightBold
: theme.typography.fontWeightMedium,
fontSize: theme.typography.body2.fontSize,
}));
const StyledListItemIcon = styled(ListItemIcon)(({ theme }) => ({
@ -138,11 +145,7 @@ export const MenuGroup = ({
{isActiveMenu ? activeIcon : icon}
</StyledListItemIcon>
<StyledListItemText>
<CappedText
sx={{ fontWeight: isActiveMenu ? 'bold' : 'normal' }}
>
{title}
</CappedText>
<CappedText bold={isActiveMenu}>{title}</CappedText>
</StyledListItemText>
</StyledAccordionSummary>
<AccordionDetails sx={{ p: 0 }}>{children}</AccordionDetails>
@ -170,7 +173,7 @@ export const AdminListItem: FC<{
>
<StyledListItemIcon>{children}</StyledListItemIcon>
<StyledListItemText>
<CappedText>{text}</CappedText>
<CappedText bold={selected}>{text}</CappedText>
</StyledListItemText>
{badge}
</ListItemButton>
@ -198,7 +201,7 @@ export const AdminSubListItem: FC<{
>
<StyledListItemIcon>{children}</StyledListItemIcon>
<StyledListItemText>
<CappedText>{text}</CappedText>
<CappedText bold={selected}>{text}</CappedText>
</StyledListItemText>
{badge}
</ListItemButton>

View File

@ -46,14 +46,20 @@ const SettingsHeader = styled(Typography)(({ theme }) => ({
fontWeight: theme.fontWeight.bold,
}));
const CappedText = styled(Typography)(({ theme }) => ({
const CappedText = styled(Typography, {
shouldForwardProp: (prop) => prop !== 'bold',
})<{
bold?: boolean;
}>(({ theme, bold }) => ({
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
width: '100%',
paddingTop: theme.spacing(0.25),
marginLeft: theme.spacing(0.75),
fontWeight: theme.typography.fontWeightBold,
fontWeight: bold
? theme.typography.fontWeightBold
: theme.typography.fontWeightMedium,
fontSize: theme.typography.body2.fontSize,
}));
const StyledListItemText = styled(ListItemText)(({ theme }) => ({
@ -107,7 +113,7 @@ export const DashboardLink = ({ onClick }: { onClick: () => void }) => {
>
<ArrowBackIcon />
<StyledListItemText>
<CappedText>Back to Unleash</CappedText>
<CappedText bold={false}>Back to Unleash</CappedText>
</StyledListItemText>
</ListItemButton>
</ListItem>

View File

@ -25,8 +25,6 @@ interface IMainLayoutProps {
}
const MainLayoutContainer = styled(Grid)(() => ({
height: '100%',
justifyContent: 'space-between',
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
@ -58,7 +56,6 @@ const MainLayoutContent = styled(Grid)(({ theme }) => ({
[theme.breakpoints.down('sm')]: {
minWidth: '100%',
},
minHeight: '94vh',
}));
const MainLayoutContentWrapper = styled('div')(({ theme }) => ({
@ -67,6 +64,8 @@ const MainLayoutContentWrapper = styled('div')(({ theme }) => ({
width: '100%',
backgroundColor: theme.palette.background.application,
position: 'relative',
display: 'flex',
flexDirection: 'column',
}));
const StyledImg = styled('img')(() => ({
@ -77,10 +76,10 @@ const StyledImg = styled('img')(() => ({
width: 400,
pointerEvents: 'none',
userSelect: 'none',
zIndex: 0,
}));
const MainLayoutContentContainer = styled('main')(({ theme }) => ({
height: '100%',
padding: theme.spacing(0, 0, 6.5, 0),
position: 'relative',
[theme.breakpoints.down('md')]: {
@ -89,6 +88,38 @@ const MainLayoutContentContainer = styled('main')(({ theme }) => ({
zIndex: 200,
}));
const LayoutFlexContainer = styled(Box)(() => ({
display: 'flex',
marginTop: 0,
}));
const MainContentWrapper = styled(Box)(() => ({
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
minWidth: 0,
}));
const HeaderContentContainer = styled(Box)(() => ({
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
flexShrink: 0,
}));
const ContentFlexContainer = styled(Box)(() => ({
flex: 1,
display: 'flex',
flexDirection: 'column',
minHeight: 0,
}));
const StyledMainLayoutContent = styled(MainLayoutContent)(() => ({
display: 'flex',
flexDirection: 'column',
flex: 1,
}));
export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
({ children }, ref) => {
const { uiConfig } = useUiConfig();
@ -105,20 +136,7 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
<SkipNavLink />
<MainLayoutContainer>
<MainLayoutContentWrapper>
<ConditionallyRender
condition={Boolean(
projectId &&
isChangeRequestConfiguredInAnyEnv(),
)}
show={<DraftBanner project={projectId || ''} />}
/>
<Box
sx={(_theme) => ({
display: 'flex',
mt: 0,
})}
>
<LayoutFlexContainer>
<ConditionallyRender
condition={!isSmallScreen}
show={
@ -132,26 +150,40 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
}
/>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
minWidth: 0,
}}
>
<Header />
<MainContentWrapper>
<ConditionallyRender
condition={Boolean(
projectId &&
isChangeRequestConfiguredInAnyEnv(),
)}
show={
<DraftBanner
project={projectId || ''}
/>
}
/>
<HeaderContentContainer>
<Header />
<MainLayoutContent>
<SkipNavTarget />
<MainLayoutContentContainer ref={ref}>
<BreadcrumbNav />
<Proclamation toast={uiConfig.toast} />
{children}
</MainLayoutContentContainer>
</MainLayoutContent>
</Box>
</Box>
<ContentFlexContainer>
<StyledMainLayoutContent>
<SkipNavTarget />
<MainLayoutContentContainer
ref={ref}
>
<BreadcrumbNav />
<Proclamation
toast={uiConfig.toast}
/>
{children}
</MainLayoutContentContainer>
</StyledMainLayoutContent>
</ContentFlexContainer>
</HeaderContentContainer>
<Footer />
</MainContentWrapper>
</LayoutFlexContainer>
<ThemeMode
darkmode={
@ -169,7 +201,6 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
}
/>
</MainLayoutContentWrapper>
<Footer />
</MainLayoutContainer>
{useNewNewInUnleash && <NewInUnleash />}
</EventTimelineProvider>

View File

@ -6,7 +6,7 @@ import {
MenuListItem,
SignOutItem,
} from './ListItems.tsx';
import { Box, List } from '@mui/material';
import { Box, List, styled } from '@mui/material';
import { IconRenderer } from './IconRenderer.tsx';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useNewAdminMenu } from 'hooks/useNewAdminMenu';
@ -16,11 +16,17 @@ import { useUiFlag } from 'hooks/useUiFlag.ts';
import { NewFeatureBadge } from 'component/layout/components/NewFeatureBadge/NewFeatureBadge.tsx';
import { useRoutes } from './useRoutes.ts';
const StyledNavigationList = styled(List)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(0.25),
}));
export const OtherLinksList = () => {
const { uiConfig } = useUiConfig();
return (
<List>
<StyledNavigationList>
{uiConfig.links.map((link) => (
<ExternalFullListItem
href={link.href}
@ -31,7 +37,7 @@ export const OtherLinksList = () => {
</ExternalFullListItem>
))}
<SignOutItem />
</List>
</StyledNavigationList>
);
};
@ -72,7 +78,7 @@ export const PrimaryNavigationList: FC<{
const showChangeRequestList = isEnterprise();
return (
<List>
<StyledNavigationList>
<PrimaryListItem href='/personal' text='Dashboard' />
<PrimaryListItem href='/projects' text='Projects' />
<PrimaryListItem href='/search' text='Flags overview' />
@ -95,7 +101,7 @@ export const PrimaryNavigationList: FC<{
activeItem={activeItem}
onClick={onClick}
/>
</List>
</StyledNavigationList>
);
};
@ -134,7 +140,7 @@ export const AdminSettingsLink: FC<{
onClick: (activeItem: string) => void;
}> = ({ mode, onClick }) => (
<Box>
<List>
<StyledNavigationList>
<MenuListItem
href='/admin'
text='Admin settings'
@ -142,6 +148,6 @@ export const AdminSettingsLink: FC<{
mode={mode}
icon={<IconRenderer path='/admin' />}
/>
</List>
</StyledNavigationList>
</Box>
);

View File

@ -30,18 +30,65 @@ export const StretchContainer = styled(Box, {
backgroundColor: admin
? theme.palette.background.application
: theme.palette.background.paper,
borderRight: admin ? `2px solid ${theme.palette.divider}` : 'none',
padding: theme.spacing(2),
borderRight: `1px solid ${theme.palette.divider}`,
alignSelf: 'stretch',
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2),
zIndex: 1,
overflowAnchor: 'none',
position: 'sticky',
top: 0,
height: '100vh',
minWidth: mode === 'full' ? theme.spacing(34) : 'auto',
width: mode === 'full' ? theme.spacing(34) : 'auto',
}));
const TopContainer = styled(Box, {
shouldForwardProp: (prop) => prop !== 'admin',
})<{ admin: boolean }>(({ theme, admin }) => ({
position: 'sticky',
top: 0,
width: '100%',
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
paddingTop: theme.spacing(0.5),
paddingBottom: theme.spacing(0.5),
backgroundColor: admin
? theme.palette.background.application
: theme.palette.background.paper,
zIndex: 2,
}));
const MidContainer = styled(Box)(({ theme }) => ({
flex: 1,
width: '100%',
overflowY: 'auto',
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
paddingTop: theme.spacing(0.5),
paddingBottom: theme.spacing(0.5),
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2),
}));
const BottomContainer = styled(Box, {
shouldForwardProp: (prop) => prop !== 'admin',
})<{ admin: boolean }>(({ theme, admin }) => ({
position: 'sticky',
bottom: 0,
width: '100%',
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
paddingTop: theme.spacing(0.5),
paddingBottom: theme.spacing(0.5),
backgroundColor: admin
? theme.palette.background.application
: theme.palette.background.paper,
borderTop: `1px solid ${theme.palette.divider}`,
zIndex: 2,
}));
const StyledLink = styled(Link)(({ theme }) => focusable(theme));
const StyledUnleashLogoWhite = styled(UnleashLogoWhite)({ width: '150px' });
@ -62,20 +109,6 @@ const StyledUnleashLogoOnlyWhite = styled(LogoOnlyWhite)(({ theme }) => ({
margin: '0 auto',
}));
// This component is needed when the sticky item could overlap with nav items. You can replicate it on a short screen.
const StickyContainer = styled(Box, {
shouldForwardProp: (prop) => prop !== 'admin',
})<{ admin: boolean }>(({ theme, admin }) => ({
position: 'sticky',
paddingBottom: theme.spacing(1.5),
paddingTop: theme.spacing(1),
bottom: theme.spacing(0),
backgroundColor: admin
? theme.palette.background.application
: theme.palette.background.paper,
borderTop: `1px solid ${theme.palette.divider}`,
}));
export const NavigationSidebar: FC<{
NewInUnleash?: typeof LegacyNewInUnleash;
}> = ({ NewInUnleash }) => {
@ -95,53 +128,70 @@ export const NavigationSidebar: FC<{
return (
<StretchContainer mode={mode} admin={showOnlyAdminMenu}>
<ConditionallyRender
condition={mode === 'full'}
show={
<StyledLink to='/' sx={flexRow} aria-label='Home'>
<ThemeMode
darkmode={
<ConditionallyRender
condition={celebrateUnleashFrontend}
show={<CelebatoryUnleashLogoWhite />}
elseShow={
<StyledUnleashLogoWhite aria-label='Unleash logo' />
}
/>
}
lightmode={
<ConditionallyRender
condition={celebrateUnleashFrontend}
show={<StyledCelebatoryLogo />}
elseShow={
<StyledUnleashLogo aria-label='Unleash logo' />
}
/>
}
/>
</StyledLink>
}
elseShow={
<StyledLink to='/' sx={flexRow} aria-label='Home'>
<ThemeMode
darkmode={<StyledUnleashLogoOnlyWhite />}
lightmode={<StyledUnleashLogoOnly />}
/>
</StyledLink>
}
/>
<TopContainer admin={showOnlyAdminMenu}>
<ConditionallyRender
condition={mode === 'full'}
show={
<StyledLink to='/' sx={flexRow} aria-label='Home'>
<ThemeMode
darkmode={
<ConditionallyRender
condition={celebrateUnleashFrontend}
show={<CelebatoryUnleashLogoWhite />}
elseShow={
<StyledUnleashLogoWhite aria-label='Unleash logo' />
}
/>
}
lightmode={
<ConditionallyRender
condition={celebrateUnleashFrontend}
show={<StyledCelebatoryLogo />}
elseShow={
<StyledUnleashLogo aria-label='Unleash logo' />
}
/>
}
/>
</StyledLink>
}
elseShow={
<StyledLink to='/' sx={flexRow} aria-label='Home'>
<ThemeMode
darkmode={<StyledUnleashLogoOnlyWhite />}
lightmode={<StyledUnleashLogoOnly />}
/>
</StyledLink>
}
/>
</TopContainer>
<ConditionallyRender
condition={!showOnlyAdminMenu}
show={
<>
<PrimaryNavigationList
mode={mode}
setMode={setMode}
onClick={setActiveItem}
activeItem={activeItem}
/>
<MidContainer>
<ConditionallyRender
condition={!showOnlyAdminMenu}
show={
<>
<PrimaryNavigationList
mode={mode}
setMode={setMode}
onClick={setActiveItem}
activeItem={activeItem}
/>
<AdminSettingsNavigation
onClick={setActiveItem}
mode={mode}
onSetFullMode={() => setMode('full')}
activeItem={activeItem}
onExpandChange={(expand) => {
changeExpanded('admin', expand);
}}
expanded={expanded.includes('admin')}
routes={routes.adminRoutes}
/>
</>
}
elseShow={
<AdminSettingsNavigation
onClick={setActiveItem}
mode={mode}
@ -153,40 +203,24 @@ export const NavigationSidebar: FC<{
expanded={expanded.includes('admin')}
routes={routes.adminRoutes}
/>
}
/>
</MidContainer>
{/* this will push the show/hide to the bottom on short nav list */}
<Box sx={{ flex: 1 }} />
<StickyContainer admin={showOnlyAdminMenu}>
{NewInUnleash ? (
<NewInUnleash
mode={mode}
onMiniModeClick={() => setMode('full')}
/>
) : null}
<ShowHide
mode={mode}
onChange={() => {
setMode(mode === 'full' ? 'mini' : 'full');
}}
/>
</StickyContainer>
</>
}
elseShow={
<AdminSettingsNavigation
onClick={setActiveItem}
<BottomContainer admin={showOnlyAdminMenu}>
{NewInUnleash ? (
<NewInUnleash
mode={mode}
onSetFullMode={() => setMode('full')}
activeItem={activeItem}
onExpandChange={(expand) => {
changeExpanded('admin', expand);
}}
expanded={expanded.includes('admin')}
routes={routes.adminRoutes}
onMiniModeClick={() => setMode('full')}
/>
}
/>
) : null}
<ShowHide
mode={mode}
onChange={() => {
setMode(mode === 'full' ? 'mini' : 'full');
}}
/>
</BottomContainer>
</StretchContainer>
);
};

View File

@ -8,12 +8,46 @@ import { FooterTitle } from './FooterTitle.tsx';
import { focusable } from 'themes/themeStyles';
const StyledFooter = styled('footer')(({ theme }) => ({
padding: theme.spacing(4, 8),
width: '100%',
flexGrow: 1,
position: 'relative',
backgroundColor: theme.palette.background.paper,
overflowY: 'hidden',
zIndex: 1,
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
}));
const FooterContentWrapper = styled('div')(({ theme }) => ({
minWidth: 0,
maxWidth: `1512px`,
margin: '0 auto',
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
[theme.breakpoints.up(1856)]: {
width: '100%',
},
[theme.breakpoints.down(1856)]: {
marginLeft: theme.spacing(7),
marginRight: theme.spacing(7),
},
[theme.breakpoints.down('lg')]: {
maxWidth: `1250px`,
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
},
[theme.breakpoints.down(1024)]: {
marginLeft: 0,
marginRight: 0,
},
[theme.breakpoints.down('sm')]: {
minWidth: '100%',
},
}));
const FooterGridContainer = styled(Grid)(({ theme }) => ({
paddingLeft: theme.spacing(4),
paddingRight: theme.spacing(4),
}));
const StyledList = styled(List)({
@ -39,314 +73,316 @@ export const Footer: VFC = () => {
return (
<StyledFooter>
<Grid
container
justifyContent='center'
spacing={10}
style={{ marginBottom: 0 }}
>
<Grid item md={4} xs={12}>
<ApiDetails uiConfig={uiConfig} />
</Grid>
<Grid item xs={12} md='auto'>
<Grid container spacing={7} direction='row'>
<Grid item>
<section title='Unleash SDK'>
<FooterTitle>Server SDKs</FooterTitle>
<StyledList dense>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/node'
target='_blank'
rel='noreferrer'
>
Node.js
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/java'
target='_blank'
rel='noreferrer'
>
Java
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/go'
target='_blank'
rel='noreferrer'
>
Go
</a>
}
/>
</StyledListItem>{' '}
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/rust'
target='_blank'
rel='noreferrer'
>
Rust
</a>
}
/>
</StyledListItem>{' '}
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/ruby'
target='_blank'
rel='noreferrer'
>
Ruby
</a>
}
/>
</StyledListItem>{' '}
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/python'
target='_blank'
rel='noreferrer'
>
Python
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/dotnet'
target='_blank'
rel='noreferrer'
>
.NET
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/php'
target='_blank'
rel='noreferrer'
>
PHP
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks'
target='_blank'
rel='noreferrer'
>
All SDKs
</a>
}
/>
</StyledListItem>
</StyledList>
</section>
</Grid>
<Grid item>
<section title='Unleash SDK'>
<FooterTitle>Frontend SDKs</FooterTitle>
<StyledList dense>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/javascript-browser'
target='_blank'
rel='noreferrer'
>
JavaScript
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/react'
target='_blank'
rel='noreferrer'
>
React
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/next-js'
target='_blank'
rel='noreferrer'
>
Next.js
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/vue'
target='_blank'
rel='noreferrer'
>
Vue
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/ios-proxy'
target='_blank'
rel='noreferrer'
>
iOS
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/android-proxy'
target='_blank'
rel='noreferrer'
>
Android
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/flutter'
target='_blank'
rel='noreferrer'
>
Flutter
</a>
}
/>
</StyledListItem>
</StyledList>
</section>
</Grid>
<Grid item>
<section>
<FooterTitle>About</FooterTitle>
<StyledList dense>
<StyledListItem>
<ListItemText
primary={
<a
href='https://www.getunleash.io/'
target='_blank'
rel='noreferrer'
>
getunleash.io
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://twitter.com/getunleash'
target='_blank'
rel='noreferrer'
>
Twitter
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://www.linkedin.com/company/getunleash'
target='_blank'
rel='noreferrer'
>
LinkedIn
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://github.com/Unleash/unleash'
target='_blank'
rel='noreferrer'
>
GitHub
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://slack.unleash.run'
target='_blank'
rel='noreferrer'
>
Slack Community
</a>
}
/>
</StyledListItem>
</StyledList>
</section>
<FooterContentWrapper>
<FooterGridContainer
container
justifyContent='space-between'
spacing={10}
style={{ marginBottom: 0 }}
>
<Grid item md={4} xs={12}>
<ApiDetails uiConfig={uiConfig} />
</Grid>
<Grid item xs={12} md='auto'>
<Grid container spacing={7} direction='row'>
<Grid item>
<section title='Unleash SDK'>
<FooterTitle>Server SDKs</FooterTitle>
<StyledList dense>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/node'
target='_blank'
rel='noreferrer'
>
Node.js
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/java'
target='_blank'
rel='noreferrer'
>
Java
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/go'
target='_blank'
rel='noreferrer'
>
Go
</a>
}
/>
</StyledListItem>{' '}
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/rust'
target='_blank'
rel='noreferrer'
>
Rust
</a>
}
/>
</StyledListItem>{' '}
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/ruby'
target='_blank'
rel='noreferrer'
>
Ruby
</a>
}
/>
</StyledListItem>{' '}
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/python'
target='_blank'
rel='noreferrer'
>
Python
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/dotnet'
target='_blank'
rel='noreferrer'
>
.NET
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/php'
target='_blank'
rel='noreferrer'
>
PHP
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks'
target='_blank'
rel='noreferrer'
>
All SDKs
</a>
}
/>
</StyledListItem>
</StyledList>
</section>
</Grid>
<Grid item>
<section title='Unleash SDK'>
<FooterTitle>Frontend SDKs</FooterTitle>
<StyledList dense>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/javascript-browser'
target='_blank'
rel='noreferrer'
>
JavaScript
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/react'
target='_blank'
rel='noreferrer'
>
React
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/next-js'
target='_blank'
rel='noreferrer'
>
Next.js
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/vue'
target='_blank'
rel='noreferrer'
>
Vue
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/ios-proxy'
target='_blank'
rel='noreferrer'
>
iOS
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/android-proxy'
target='_blank'
rel='noreferrer'
>
Android
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://docs.getunleash.io/sdks/flutter'
target='_blank'
rel='noreferrer'
>
Flutter
</a>
}
/>
</StyledListItem>
</StyledList>
</section>
</Grid>
<Grid item>
<section>
<FooterTitle>About</FooterTitle>
<StyledList dense>
<StyledListItem>
<ListItemText
primary={
<a
href='https://www.getunleash.io/'
target='_blank'
rel='noreferrer'
>
getunleash.io
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://twitter.com/getunleash'
target='_blank'
rel='noreferrer'
>
Twitter
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://www.linkedin.com/company/getunleash'
target='_blank'
rel='noreferrer'
>
LinkedIn
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://github.com/Unleash/unleash'
target='_blank'
rel='noreferrer'
>
GitHub
</a>
}
/>
</StyledListItem>
<StyledListItem>
<ListItemText
primary={
<a
href='https://slack.unleash.run'
target='_blank'
rel='noreferrer'
>
Slack Community
</a>
}
/>
</StyledListItem>
</StyledList>
</section>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</FooterGridContainer>
</FooterContentWrapper>
</StyledFooter>
);
};

View File

@ -117,7 +117,7 @@ export const StyledList = styled(List)(({ theme }) => ({
export const StyledCardTitle = styled('div')<{ lines?: number }>(
({ theme, lines = 2 }) => ({
fontWeight: theme.typography.fontWeightRegular,
fontWeight: theme.typography.fontWeightBold,
fontSize: theme.typography.body1.fontSize,
lineClamp: `${lines}`,
WebkitLineClamp: lines,

View File

@ -20,7 +20,6 @@ const StyledCardLink = styled(Link)(({ theme }) => ({
const StyledCardTitle = styled('h3')(({ theme }) => ({
margin: 0,
marginRight: 'auto',
fontWeight: theme.typography.fontWeightRegular,
fontSize: theme.typography.body1.fontSize,
lineHeight: '1.2',
}));

View File

@ -413,13 +413,15 @@ export const StrategiesList = () => {
<PageContent
isLoading={loading}
header={
<PageHeader>
<Title
title='Standard strategies'
description='Standard strategies let you enable a feature only for a specified audience. Select a starting setup, then customize your strategy with targeting and variants.'
link='https://docs.getunleash.io/concepts/activation-strategies'
/>
</PageHeader>
<PageHeader
titleElement={
<Title
title='Standard strategies'
description='Standard strategies let you enable a feature only for a specified audience. Select a starting setup, then customize your strategy with targeting and variants.'
link='https://docs.getunleash.io/concepts/activation-strategies'
/>
}
/>
}
>
<Box>
@ -475,13 +477,15 @@ export const StrategiesList = () => {
<PageContent
isLoading={loading}
header={
<PageHeader>
<Title
title='Advanced and custom strategies'
description='Advanced strategies let you target based on specific properties. Custom activation strategies let you define your own activation strategies to use with Unleash.'
link='https://docs.getunleash.io/concepts/activation-strategies#custom-strategies'
/>
</PageHeader>
<PageHeader
titleElement={
<Title
title='Advanced and custom strategies'
description='Advanced strategies let you target based on specific properties. Custom activation strategies let you define your own activation strategies to use with Unleash.'
link='https://docs.getunleash.io/concepts/activation-strategies#custom-strategies'
/>
}
/>
}
sx={{ mt: 2 }}
>