mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: new in unleash tooltip (#7991)
This commit is contained in:
parent
742504793c
commit
c69036c5a9
@ -105,7 +105,7 @@ const StageBox = styled(Box, {
|
|||||||
const ColorFill = styled(Box)(({ theme }) => ({
|
const ColorFill = styled(Box)(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.primary.light,
|
backgroundColor: theme.palette.primary.light,
|
||||||
color: theme.palette.primary.contrastText,
|
color: theme.palette.primary.contrastText,
|
||||||
borderRadius: theme.spacing(0, 0, 1, 1), // has to match the parent tooltip container
|
borderRadius: `0 0 ${theme.shape.borderRadiusMedium}px ${theme.shape.borderRadiusMedium}px`, // has to match the parent tooltip container
|
||||||
margin: theme.spacing(-1, -1.5), // has to match the parent tooltip container
|
margin: theme.spacing(-1, -1.5), // has to match the parent tooltip container
|
||||||
padding: theme.spacing(2, 3),
|
padding: theme.spacing(2, 3),
|
||||||
}));
|
}));
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
styled,
|
styled,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import Signals from '@mui/icons-material/Sensors';
|
import Signals from '@mui/icons-material/Sensors';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import type { NavigationMode } from 'component/layout/MainLayout/NavigationSidebar/NavigationMode';
|
import type { NavigationMode } from 'component/layout/MainLayout/NavigationSidebar/NavigationMode';
|
||||||
import { NewInUnleashItem } from './NewInUnleashItem';
|
import { NewInUnleashItem } from './NewInUnleashItem';
|
||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||||
@ -71,7 +70,9 @@ type NewItem = {
|
|||||||
label: string;
|
label: string;
|
||||||
icon: ReactNode;
|
icon: ReactNode;
|
||||||
link: string;
|
link: string;
|
||||||
|
docsLink: string;
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
longDescription: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface INewInUnleashProps {
|
interface INewInUnleashProps {
|
||||||
@ -86,7 +87,6 @@ export const NewInUnleash = ({
|
|||||||
onMiniModeClick,
|
onMiniModeClick,
|
||||||
}: INewInUnleashProps) => {
|
}: INewInUnleashProps) => {
|
||||||
const { trackEvent } = usePlausibleTracker();
|
const { trackEvent } = usePlausibleTracker();
|
||||||
const navigate = useNavigate();
|
|
||||||
const [seenItems, setSeenItems] = useLocalStorageState(
|
const [seenItems, setSeenItems] = useLocalStorageState(
|
||||||
'new-in-unleash-seen:v1',
|
'new-in-unleash-seen:v1',
|
||||||
new Set(),
|
new Set(),
|
||||||
@ -99,7 +99,35 @@ export const NewInUnleash = ({
|
|||||||
label: 'Signals & Actions',
|
label: 'Signals & Actions',
|
||||||
icon: <StyledSignalsIcon />,
|
icon: <StyledSignalsIcon />,
|
||||||
link: '/integrations/signals',
|
link: '/integrations/signals',
|
||||||
|
docsLink: 'https://docs.getunleash.io/reference/signals',
|
||||||
show: isEnterprise() && signalsEnabled,
|
show: isEnterprise() && signalsEnabled,
|
||||||
|
longDescription: (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
It allows you to respond to events in your real-time
|
||||||
|
monitoring system by automating tasks such as disabling
|
||||||
|
a beta feature in response to an increase in errors or a
|
||||||
|
drop in conversion rates.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<b>Signal endpoints</b> are used to send signals
|
||||||
|
to Unleash. This allows you to integrate Unleash
|
||||||
|
with any external tool.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<b>Actions</b>, which are configured inside
|
||||||
|
projects, allow you to react to those signals
|
||||||
|
and enable or disable flags based on certain
|
||||||
|
conditions.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -135,18 +163,15 @@ export const NewInUnleash = ({
|
|||||||
New in Unleash
|
New in Unleash
|
||||||
</StyledNewInUnleashHeader>
|
</StyledNewInUnleashHeader>
|
||||||
<StyledNewInUnleashList>
|
<StyledNewInUnleashList>
|
||||||
{visibleItems.map(({ label, icon, link }) => (
|
{visibleItems.map(
|
||||||
|
({ label, icon, link, longDescription, docsLink }) => (
|
||||||
<NewInUnleashItem
|
<NewInUnleashItem
|
||||||
key={label}
|
|
||||||
icon={icon}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
trackEvent('new-in-unleash-click', {
|
trackEvent('new-in-unleash-click', {
|
||||||
props: {
|
props: {
|
||||||
label,
|
label,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
navigate(link);
|
|
||||||
onItemClick?.();
|
|
||||||
}}
|
}}
|
||||||
onDismiss={() => {
|
onDismiss={() => {
|
||||||
trackEvent('new-in-unleash-dismiss', {
|
trackEvent('new-in-unleash-dismiss', {
|
||||||
@ -156,10 +181,14 @@ export const NewInUnleash = ({
|
|||||||
});
|
});
|
||||||
setSeenItems(new Set([...seenItems, label]));
|
setSeenItems(new Set([...seenItems, label]));
|
||||||
}}
|
}}
|
||||||
>
|
label={label}
|
||||||
{label}
|
icon={icon}
|
||||||
</NewInUnleashItem>
|
link={link}
|
||||||
))}
|
longDescription={longDescription}
|
||||||
|
docsLink={docsLink}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
</StyledNewInUnleashList>
|
</StyledNewInUnleashList>
|
||||||
</StyledNewInUnleash>
|
</StyledNewInUnleash>
|
||||||
);
|
);
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import type { ReactNode } from 'react';
|
import type * as React from 'react';
|
||||||
|
import { type ReactNode, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
IconButton,
|
IconButton,
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemButton,
|
ListItemButton,
|
||||||
Tooltip,
|
|
||||||
styled,
|
styled,
|
||||||
|
Tooltip,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import Close from '@mui/icons-material/Close';
|
import Close from '@mui/icons-material/Close';
|
||||||
|
import { NewInUnleashTooltip } from './NewInUnleashTooltip';
|
||||||
|
|
||||||
const StyledItemButton = styled(ListItemButton)(({ theme }) => ({
|
const StyledItemButton = styled(ListItemButton)(({ theme }) => ({
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
@ -30,26 +32,62 @@ interface INewInUnleashItemProps {
|
|||||||
icon: ReactNode;
|
icon: ReactNode;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
onDismiss: () => void;
|
onDismiss: () => void;
|
||||||
children: ReactNode;
|
label: string;
|
||||||
|
longDescription: ReactNode;
|
||||||
|
link: string;
|
||||||
|
docsLink: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useTooltip = () => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleTooltipClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTooltipOpen = () => {
|
||||||
|
setOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { open, handleTooltipOpen, handleTooltipClose };
|
||||||
|
};
|
||||||
|
|
||||||
export const NewInUnleashItem = ({
|
export const NewInUnleashItem = ({
|
||||||
icon,
|
icon,
|
||||||
onClick,
|
onClick,
|
||||||
onDismiss,
|
onDismiss,
|
||||||
children,
|
label,
|
||||||
|
longDescription,
|
||||||
|
link,
|
||||||
|
docsLink,
|
||||||
}: INewInUnleashItemProps) => {
|
}: INewInUnleashItemProps) => {
|
||||||
|
const { open, handleTooltipOpen, handleTooltipClose } = useTooltip();
|
||||||
|
|
||||||
const onDismissClick = (e: React.MouseEvent) => {
|
const onDismissClick = (e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onDismiss();
|
onDismiss();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem disablePadding onClick={onClick}>
|
<ListItem
|
||||||
|
disablePadding
|
||||||
|
onClick={() => {
|
||||||
|
onClick();
|
||||||
|
handleTooltipOpen();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<NewInUnleashTooltip
|
||||||
|
open={open}
|
||||||
|
onClose={handleTooltipClose}
|
||||||
|
title={label}
|
||||||
|
longDescription={longDescription}
|
||||||
|
link={link}
|
||||||
|
docsLink={docsLink}
|
||||||
|
>
|
||||||
<StyledItemButton>
|
<StyledItemButton>
|
||||||
<StyledItemButtonContent>
|
<StyledItemButtonContent>
|
||||||
{icon}
|
{icon}
|
||||||
{children}
|
{label}
|
||||||
</StyledItemButtonContent>
|
</StyledItemButtonContent>
|
||||||
<Tooltip title='Dismiss' arrow>
|
<Tooltip title='Dismiss' arrow>
|
||||||
<StyledItemButtonClose
|
<StyledItemButtonClose
|
||||||
@ -61,6 +99,7 @@ export const NewInUnleashItem = ({
|
|||||||
</StyledItemButtonClose>
|
</StyledItemButtonClose>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</StyledItemButton>
|
</StyledItemButton>
|
||||||
|
</NewInUnleashTooltip>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,129 @@
|
|||||||
|
import type * as React from 'react';
|
||||||
|
import type { FC, ReactNode } from 'react';
|
||||||
|
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Link,
|
||||||
|
styled,
|
||||||
|
Typography,
|
||||||
|
ClickAwayListener,
|
||||||
|
} from '@mui/material';
|
||||||
|
import { type Link as RouterLink, useNavigate } from 'react-router-dom';
|
||||||
|
import OpenInNew from '@mui/icons-material/OpenInNew';
|
||||||
|
import { ReactComponent as UnleashLogo } from 'assets/img/logoWithWhiteText.svg';
|
||||||
|
|
||||||
|
const Header = styled(Box)(({ theme }) => ({
|
||||||
|
backgroundColor: theme.palette.primary.light,
|
||||||
|
color: theme.palette.primary.contrastText,
|
||||||
|
borderRadius: `${theme.shape.borderRadiusMedium}px ${theme.shape.borderRadiusMedium}px 0 0`, // has to match the parent tooltip container
|
||||||
|
margin: theme.spacing(-1, -1.5), // has to match the parent tooltip container
|
||||||
|
padding: theme.spacing(2, 3),
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
minHeight: '120px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Body = styled(Box)(({ theme }) => ({
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledLink = styled(Link<typeof RouterLink | 'a'>)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
padding: 0,
|
||||||
|
color: theme.palette.links,
|
||||||
|
fontWeight: theme.fontWeight.medium,
|
||||||
|
'&:hover, &:focus': {
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledOpenInNew = styled(OpenInNew)(({ theme }) => ({
|
||||||
|
fontSize: theme.spacing(2.25),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledUnleashLogo = styled(UnleashLogo)({ width: '150px' });
|
||||||
|
|
||||||
|
const LongDescription = styled(Box)(({ theme }) => ({
|
||||||
|
ul: {
|
||||||
|
paddingLeft: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Title = styled(Typography)(({ theme }) => ({
|
||||||
|
margin: theme.spacing(2, 0),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ReadMore = styled(Box)(({ theme }) => ({
|
||||||
|
margin: theme.spacing(3, 0),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const NewInUnleashTooltip: FC<{
|
||||||
|
children: React.ReactElement<any, any>;
|
||||||
|
title: string;
|
||||||
|
longDescription: ReactNode;
|
||||||
|
docsLink: string;
|
||||||
|
link: string;
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}> = ({ children, title, longDescription, link, docsLink, open, onClose }) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HtmlTooltip
|
||||||
|
disableFocusListener
|
||||||
|
disableHoverListener
|
||||||
|
disableTouchListener
|
||||||
|
onClose={onClose}
|
||||||
|
open={open}
|
||||||
|
maxHeight={800}
|
||||||
|
maxWidth={350}
|
||||||
|
arrow
|
||||||
|
tabIndex={0}
|
||||||
|
placement='right-end'
|
||||||
|
title={
|
||||||
|
<ClickAwayListener onClickAway={onClose}>
|
||||||
|
<Box>
|
||||||
|
<Header>
|
||||||
|
<StyledUnleashLogo />
|
||||||
|
</Header>
|
||||||
|
<Body>
|
||||||
|
<Title>{title}</Title>
|
||||||
|
<LongDescription>{longDescription}</LongDescription>
|
||||||
|
<ReadMore>
|
||||||
|
<StyledLink
|
||||||
|
component='a'
|
||||||
|
href={docsLink}
|
||||||
|
underline='hover'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
target='_blank'
|
||||||
|
>
|
||||||
|
<StyledOpenInNew /> Read more in our
|
||||||
|
documentation
|
||||||
|
</StyledLink>
|
||||||
|
</ReadMore>
|
||||||
|
<Button
|
||||||
|
variant='contained'
|
||||||
|
color='primary'
|
||||||
|
type='submit'
|
||||||
|
size='small'
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
onClose();
|
||||||
|
navigate(link);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Check it out
|
||||||
|
</Button>
|
||||||
|
</Body>
|
||||||
|
</Box>
|
||||||
|
</ClickAwayListener>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</HtmlTooltip>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user