Skip to content

Commit

Permalink
feat: demo ui-ux improvements (#3634)
Browse files Browse the repository at this point in the history
https://linear.app/unleash/issue/2-914/improve-demo-guide-uiux

Includes a big batch of UI/UX improvements, including but not limited
to:

- Updating steps text;
- Improve behavior of intro step dialogs (use normal dialogs);
- Improve overall design;
- Improve escape key and backdrop click behaviors;
- Add plans dialog;
- Add sticky demo banner;
- Assume `demo-app` project and `dev` environment to better fit our demo
instance;
- Misc fixes and refactors;

Relates to [roadmap](https://github.com/orgs/Unleash/projects/10) item:
#3537


![image](https://user-images.githubusercontent.com/14320932/234637210-1936fd48-ce40-4980-81ae-f1fe64e65545.png)
  • Loading branch information
nunogois committed Apr 27, 2023
1 parent 2164048 commit 3599e74
Show file tree
Hide file tree
Showing 17 changed files with 575 additions and 201 deletions.
9 changes: 9 additions & 0 deletions frontend/src/assets/img/stars.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 0 additions & 8 deletions frontend/src/component/App.tsx
Expand Up @@ -20,7 +20,6 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import MaintenanceBanner from './maintenance/MaintenanceBanner';
import { styled } from '@mui/material';
import { InitialRedirect } from './InitialRedirect';
import { Demo } from './demo/Demo';

const StyledContainer = styled('div')(() => ({
'& ul': {
Expand Down Expand Up @@ -101,13 +100,6 @@ export const App = () => {

<FeedbackNPS openUrl="http://feedback.unleash.run" />

<ConditionallyRender
condition={Boolean(
uiConfig.flags.demo
)}
show={<Demo />}
/>

<SplashPageRedirect />
</StyledContainer>
</>
Expand Down
29 changes: 26 additions & 3 deletions frontend/src/component/demo/Demo.tsx
Expand Up @@ -5,6 +5,9 @@ import { createLocalStorage } from 'utils/createLocalStorage';
import { TOPICS } from './demo-topics';
import { DemoDialogWelcome } from './DemoDialog/DemoDialogWelcome/DemoDialogWelcome';
import { DemoDialogFinish } from './DemoDialog/DemoDialogFinish/DemoDialogFinish';
import { DemoDialogPlans } from './DemoDialog/DemoDialogPlans/DemoDialogPlans';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { DemoBanner } from './DemoBanner/DemoBanner';

const defaultProgress = {
welcomeOpen: true,
Expand All @@ -13,14 +16,21 @@ const defaultProgress = {
steps: [0],
};

const { value: storedProgress, setValue: setStoredProgress } =
createLocalStorage('Tutorial:v1', defaultProgress);
interface IDemoProps {
children: JSX.Element;
}

export const Demo = ({ children }: IDemoProps): JSX.Element => {
const { uiConfig } = useUiConfig();

const { value: storedProgress, setValue: setStoredProgress } =
createLocalStorage('Tutorial:v1', defaultProgress);

export const Demo = () => {
const [welcomeOpen, setWelcomeOpen] = useState(
storedProgress.welcomeOpen ?? defaultProgress.welcomeOpen
);
const [finishOpen, setFinishOpen] = useState(false);
const [plansOpen, setPlansOpen] = useState(false);

const [expanded, setExpanded] = useState(
storedProgress.expanded ?? defaultProgress.expanded
Expand Down Expand Up @@ -59,8 +69,16 @@ export const Demo = () => {
}
};

if (!uiConfig.flags.demo) return children;

return (
<>
<DemoBanner
onPlans={() => {
setPlansOpen(true);
}}
/>
{children}
<DemoDialogWelcome
open={welcomeOpen}
onClose={() => {
Expand All @@ -76,12 +94,17 @@ export const Demo = () => {
open={finishOpen}
onClose={() => {
setFinishOpen(false);
setPlansOpen(true);
}}
onRestart={() => {
setFinishOpen(false);
onStart();
}}
/>
<DemoDialogPlans
open={plansOpen}
onClose={() => setPlansOpen(false)}
/>
<DemoTopics
expanded={expanded}
setExpanded={setExpanded}
Expand Down
51 changes: 51 additions & 0 deletions frontend/src/component/demo/DemoBanner/DemoBanner.tsx
@@ -0,0 +1,51 @@
import { Button, styled } from '@mui/material';

const StyledBanner = styled('div')(({ theme }) => ({
position: 'sticky',
top: 0,
zIndex: theme.zIndex.appBar,
display: 'flex',
gap: theme.spacing(1),
justifyContent: 'center',
alignItems: 'center',
backgroundColor: theme.palette.web.main,
color: theme.palette.web.contrastText,
padding: theme.spacing(1),
}));

const StyledButton = styled(Button)(({ theme }) => ({
whiteSpace: 'nowrap',
flexShrink: 0,
'&&&': {
fontSize: theme.fontSizes.smallBody,
},
}));

const StyledQuestionsButton = styled(StyledButton)(({ theme }) => ({
color: theme.palette.web.contrastText,
border: `1px solid rgba(255, 255, 255, 0.5)`,
})) as typeof Button;

interface IDemoBannerProps {
onPlans: () => void;
}

export const DemoBanner = ({ onPlans }: IDemoBannerProps) => (
<StyledBanner>
<span>
This is a <strong>demo of Unleash</strong>. Play around as much as
you want. Reach out when you're ready.
</span>
<StyledQuestionsButton
variant="outlined"
sx={{ ml: 1 }}
href="https://slack.unleash.run/"
target="_blank"
>
Ask questions
</StyledQuestionsButton>
<StyledButton variant="contained" color="primary" onClick={onPlans}>
Get Unleash
</StyledButton>
</StyledBanner>
);
19 changes: 15 additions & 4 deletions frontend/src/component/demo/DemoDialog/DemoDialog.tsx
@@ -1,4 +1,10 @@
import { Dialog, IconButton, Typography, styled } from '@mui/material';
import {
Dialog,
DialogProps,
IconButton,
Typography,
styled,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';

const StyledDialog = styled(Dialog)(({ theme }) => ({
Expand All @@ -22,14 +28,19 @@ const StyledHeader = styled(Typography)(({ theme }) => ({
fontWeight: theme.fontWeight.bold,
}));

interface IDemoDialogProps {
interface IDemoDialogProps extends DialogProps {
open: boolean;
onClose: () => void;
children: React.ReactNode;
}

export const DemoDialog = ({ open, onClose, children }: IDemoDialogProps) => (
<StyledDialog open={open} onClose={onClose}>
export const DemoDialog = ({
open,
onClose,
children,
...props
}: IDemoDialogProps) => (
<StyledDialog open={open} onClose={onClose} {...props}>
<StyledCloseButton aria-label="close" onClick={onClose}>
<CloseIcon />
</StyledCloseButton>
Expand Down
Expand Up @@ -39,26 +39,26 @@ export const DemoDialogFinish = ({
}
/>
<DemoDialog open={open} onClose={onClose}>
<DemoDialog.Header>You finished the tutorial</DemoDialog.Header>
<DemoDialog.Header>You finished the demo</DemoDialog.Header>
<Typography color="textSecondary" sx={{ mt: 4 }}>
Great job! Keep exploring Unleash, as this was just a small
example of its full potential. You can do the tutorial again at
any moment.
example of its full potential. You can do the demo again at any
moment.
</Typography>
<StyledActions>
<StyledButton
variant="outlined"
color="primary"
onClick={onRestart}
>
Restart tutorial
Restart demo
</StyledButton>
<StyledButton
variant="contained"
color="primary"
onClick={onClose}
>
Close
Continue
</StyledButton>
</StyledActions>
</DemoDialog>
Expand Down
@@ -0,0 +1,130 @@
import { Button, Typography, styled } from '@mui/material';
import { DemoDialog } from '../DemoDialog';
import { GitHub } from '@mui/icons-material';
import { Launch } from '@mui/icons-material';

const StyledDemoDialog = styled(DemoDialog)(({ theme }) => ({
'& .MuiDialog-paper': {
maxWidth: theme.spacing(120),
},
}));

const StyledPlans = styled('div')(({ theme }) => ({
display: 'grid',
gridTemplateColumns: 'auto auto auto',
gap: theme.spacing(1),
marginTop: theme.spacing(6),
}));

const StyledPlan = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
backgroundColor: theme.palette.background.elevation1,
borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(4, 3),
'& > a': {
whiteSpace: 'nowrap',
},
height: theme.spacing(34),
width: theme.spacing(34),
}));

const StyledCompareLink = styled('a')(({ theme }) => ({
fontSize: theme.fontSizes.mainHeader,
textDecoration: 'none',
'&:hover': {
textDecoration: 'underline',
},
margin: 'auto',
marginTop: theme.spacing(4),
display: 'inline-flex',
alignItems: 'center',
gap: theme.spacing(1),
'& > svg': {
fontSize: theme.fontSizes.mainHeader,
},
}));

interface IDemoDialogPlansProps {
open: boolean;
onClose: () => void;
}

export const DemoDialogPlans = ({ open, onClose }: IDemoDialogPlansProps) => (
<StyledDemoDialog open={open} onClose={onClose}>
<DemoDialog.Header>Want to keep going with Unleash?</DemoDialog.Header>
<StyledPlans>
<StyledPlan>
<Typography variant="h5" fontWeight="bold">
Open Source
</Typography>
<Typography variant="body2" color="textSecondary">
Self-hosted basic feature management solution
</Typography>
<Typography variant="h6" fontWeight="normal">
Free
</Typography>
<Button
variant="outlined"
color="primary"
startIcon={<GitHub />}
href="https://github.com/unleash/unleash"
target="_blank"
>
View project on GitHub
</Button>
</StyledPlan>
<StyledPlan>
<Typography variant="h5" fontWeight="bold">
Pro
</Typography>
<Typography variant="body2" color="textSecondary">
Free your team to collaborate. We'll do the heavy lifting.
</Typography>
<div>
<Typography variant="h6" fontWeight="normal">
$80/month
</Typography>
<Typography variant="body2">includes 5 seats</Typography>
</div>
<Button
variant="contained"
color="primary"
href="https://www.getunleash.io/plans/pro"
target="_blank"
>
Start 14-day free trial
</Button>
</StyledPlan>
<StyledPlan>
<Typography variant="h5" fontWeight="bold">
Enterprise
</Typography>
<Typography variant="body2" color="textSecondary">
Security, compliance, and development controls for scale.
</Typography>
<div>
<Typography variant="h6" fontWeight="normal">
Custom
</Typography>
<Typography variant="body2">unlimited seats</Typography>
</div>
<Button
variant="contained"
color="web"
href="https://www.getunleash.io/plans/enterprise"
target="_blank"
>
Contact sales
</Button>
</StyledPlan>
</StyledPlans>
<StyledCompareLink
href="https://www.getunleash.io/plans"
target="_blank"
>
Compare plans <Launch />
</StyledCompareLink>
</StyledDemoDialog>
);
Expand Up @@ -60,8 +60,8 @@ export const DemoDialogWelcome = ({
<DemoDialog.Header>Explore Unleash</DemoDialog.Header>
<Typography color="textSecondary" sx={{ mt: 2 }}>
You can explore Unleash on your own, however for the best experience
it's recommended you follow our interactive tutorial. To get
started, you will need to open the demo website below.
it's recommended you follow our interactive demo. To get started,
you will need to open the demo website below.
</Typography>
<StyledDemoPane>
<StyledScanMessage>
Expand All @@ -87,7 +87,7 @@ export const DemoDialogWelcome = ({
color="primary"
onClick={onStart}
>
Start Unleash tutorial
Try Unleash demo
</StyledStartButton>
</DemoDialog>
);

0 comments on commit 3599e74

Please sign in to comment.