Skip to content

Commit

Permalink
feat(web,novui): Add Studio onboarding (novuhq#5646)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidsoderberg authored Jun 17, 2024
1 parent d27cf87 commit b0402e4
Show file tree
Hide file tree
Showing 35 changed files with 1,175 additions and 263 deletions.
5 changes: 3 additions & 2 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -638,12 +638,13 @@
"zwnj",
"prepush",
"xcodebuild",
"liquidjs",
"vstack",
"nimma",
"jpath",
"Nimma",
"jpath"
"jpath",
"vstack",
"liquidjs"
],
"flagWords": [],
"patterns": [
Expand Down
2 changes: 1 addition & 1 deletion .source
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,4 @@
}
]
}
}
}
5 changes: 5 additions & 0 deletions apps/web/panda.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export default defineConfig({
*/
theme: {
extend: {
tokens: {
sizes: {
onboarding: { value: '880px' },
},
},
semanticTokens: {
colors: {
workflow: {
Expand Down
1 change: 1 addition & 0 deletions apps/web/public/static/images/novu-text.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions apps/web/src/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ import { TenantsPage } from './pages/tenants/TenantsPage';
import { UpdateTenantPage } from './pages/tenants/UpdateTenantPage';
import { TranslationRoutes } from './pages/TranslationPages';
import { useSettingsRoutes } from './SettingsRoutes';
import { StudioOnboarding } from './pages/studio-onboarding/index';
import { StudioOnboardingPreview } from './pages/studio-onboarding/preview';
import { StudioOnboardingSuccess } from './pages/studio-onboarding/success';
import {
WorkflowsListPage,
WorkflowsDetailPage,
Expand Down Expand Up @@ -155,6 +158,9 @@ export const AppRoutes = () => {
<Route path="/translations/*" element={<TranslationRoutes />} />
<Route path={ROUTES.ANY} element={<HomePage />} />
</Route>
<Route path={ROUTES.STUDIO_ONBOARDING} element={<StudioOnboarding />} />
<Route path={ROUTES.STUDIO_ONBOARDING_PREVIEW} element={<StudioOnboardingPreview />} />
<Route path={ROUTES.STUDIO_ONBOARDING_SUCCESS} element={<StudioOnboardingSuccess />} />
</Routes>
);
};
32 changes: 21 additions & 11 deletions apps/web/src/components/Timeline/Timeline.styles.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { css } from '@novu/novui/css';
import { css, cx } from '@novu/novui/css';

export const TIMELINE_STYLES = {
item: css({
Expand All @@ -20,17 +20,27 @@ export const TIMELINE_STYLES = {
color: 'typography.text.main !important',
lineHeight: '1.5rem !important',
}),
itemBullet: css({
'&[data-with-child]': {
textStyle: 'text.strong',
border: 'none',
backgroundColor: {
base: 'surface.panel !important',
// TODO: fix when legacy colors are removed
_dark: 'legacy.B30 !important',
itemBullet: cx(
css({
'&[data-active]': {
backgroundColor: {
base: 'typography.text.feedback.success !important',
_dark: 'typography.text.feedback.success !important',
},
},
},
}),
}),
css({
'&[data-with-child]': {
textStyle: 'text.strong',
border: 'none',
backgroundColor: {
base: 'surface.panel !important',
// TODO: fix when legacy colors are removed
_dark: 'legacy.B30 !important',
},
},
})
),
itemBody: css({
lineHeight: '1.25rem',
color: 'typography.text.secondary',
Expand Down
26 changes: 17 additions & 9 deletions apps/web/src/components/docs/DocsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,22 @@ const popoverTextRecipe = cva<{ colorScheme: Record<ColorScheme, SystemStyleObje
},
});

export const DocsButton = () => {
const DefaultButton = ({ onClick }: { onClick: () => void }) => (
<ActionButton
className={css({
height: '150 !important',
minHeight: '150 !important',
})}
Icon={() => <IconOutlineMenuBook />}
onClick={onClick}
/>
);

export const DocsButton = ({
TriggerButton = DefaultButton,
}: {
TriggerButton?: React.FC<{ onClick: () => void }>;
}) => {
const { colorScheme } = useColorScheme();
const [opened, setOpened] = useState<boolean>(false);
const segment = useSegment();
Expand Down Expand Up @@ -110,14 +125,7 @@ export const DocsButton = () => {
withArrow
>
<Popover.Target>
<ActionButton
className={css({
height: '150 !important',
minHeight: '150 !important',
})}
Icon={() => <IconOutlineMenuBook />}
onClick={() => toggle()}
/>
<TriggerButton onClick={() => toggle()} />
</Popover.Target>
<Popover.Dropdown className={popoverDropdownRecipe({ colorScheme })}>
<Flex gap="125" justify="space-between">
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/components/docs/docs.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const PATHS: { [key in ROUTES]?: string } = {
[ROUTES.WORKFLOWS]: 'workflows/notification-workflows',
[ROUTES.TENANTS]: 'tenants/introduction',
[ROUTES.TRANSLATIONS]: 'content-creation-design/translations',
[ROUTES.STUDIO_ONBOARDING]: 'echo/quickstart',
[ROUTES.STUDIO_ONBOARDING_PREVIEW]: 'echo/concepts/workflows',
};

export const DOCS_URL = 'https://docs.novu.co';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,20 @@ const useStyles = createStyles((theme) => ({
},
}));

export const ExecutionDetailsAccordion = ({ identifier, steps, subscriberVariables }) => {
export const ExecutionDetailsAccordion = ({ identifier, steps, subscriberVariables, defaultOpen = undefined }) => {
const { classes } = useStyles();

if (!steps || steps.length <= 0) {
return null;
}

return (
<Accordion key="execution-details-accordion" chevronPosition="right" classNames={classes}>
<Accordion
key="execution-details-accordion"
chevronPosition="right"
defaultValue={defaultOpen}
classNames={classes}
>
{steps.map((step) => (
<Accordion.Item key={`execution-details-step-${step.id}`} value={step.id}>
<Accordion.Control>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createStyles, Group } from '@mantine/core';
import { colors, Text } from '@novu/design-system';
import { cx } from '@novu/novui/css';
import { useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import Frame from 'react-frame-component';
Expand Down Expand Up @@ -93,6 +94,7 @@ export const PreviewWeb = ({
onLocaleChange,
selectedLocale,
locales,
className,
bridge = false,
}: {
integration: any;
Expand All @@ -104,6 +106,7 @@ export const PreviewWeb = ({
onLocaleChange: (locale: string) => void;
selectedLocale?: string;
locales: any[];
className?: string;
bridge?: boolean;
}) => {
const [isEditOverlayVisible, setIsEditOverlayVisible] = useState(false);
Expand Down Expand Up @@ -135,7 +138,7 @@ export const PreviewWeb = ({
<div className={classes.barAction}></div>
</Group>
</div>
<div className={classes.contentContainer}>
<div className={cx(classes.contentContainer, className)}>
<div className={classes.header}>
<Group
sx={{
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/constants/assets.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CONTEXT_PATH } from '../config';

export const COMPANY_LOGO_PATH = CONTEXT_PATH + '/static/images/novu.svg';

export const COMPANY_LOGO_TEXT_PATH = CONTEXT_PATH + '/static/images/novu-text.svg';
4 changes: 3 additions & 1 deletion apps/web/src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ export enum ROUTES {
ORGANIZATION = '/settings/organization',
SECURITY = '/settings/security',
BILLING = '/settings/billing',

/** Novu V2 routes */
STUDIO = '/studio',
STUDIO_FLOWS = '/studio/flows',
STUDIO_FLOWS_VIEW = '/studio/flows/:templateId',
STUDIO_ONBOARDING = '/studio/onboarding',
STUDIO_ONBOARDING_PREVIEW = '/studio/onboarding/preview',
STUDIO_ONBOARDING_SUCCESS = '/studio/onboarding/success',
STUDIO_FLOWS_STEP_EDITOR = '/studio/flows/:templateId/step/:stepId',
STUDIO_FLOWS_TEST_STEP = '/studio/flows/:templateId/step/:stepId/test',
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { Timeline as MantineTimeline } from '@mantine/core';

import useStyles from './Timeline.styles';
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/pages/get-started/consts/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ReactNode } from 'react';
import { GetStartedTabsViewsEnum } from './GetStartedTabsViewsEnum';
import { OnboardingUseCasesTabsEnum } from './OnboardingUseCasesTabsEnum';

Expand Down
104 changes: 104 additions & 0 deletions apps/web/src/pages/studio-onboarding/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { text } from '@novu/novui/recipes';
import { HStack, styled, VStack } from '@novu/novui/jsx';
import { Tooltip } from '@novu/design-system';
import { IconOutlineMenuBook } from '@novu/novui/icons';
import { useLocation, useNavigate } from 'react-router-dom';
import { css } from '@novu/novui/css';
import { When } from '../../../components/utils/When';
import { DocsButton } from '../../../components/docs/DocsButton';
import { Button } from '@novu/novui';
import { useSegment } from '../../../components/providers/SegmentProvider';
import { ROUTES } from '../../../constants/routes';

const Text = styled('a', text);

export const Footer = ({
canSkipSetup = true,
showLearnMore = true,
buttonText = 'Continue',
onClick,
loading = false,
tooltip = '',
disabled = false,
}: {
canSkipSetup?: boolean;
showLearnMore?: boolean;
buttonText?: string;
onClick?: () => void;
loading?: boolean;
tooltip?: string;
disabled?: boolean;
}) => {
const segment = useSegment();
const navigate = useNavigate();
const { pathname } = useLocation();

return (
<div
className={css({
paddingTop: '50',
paddingBottom: '100',
backgroundColor: 'surface.panel',
position: 'fixed',
bottom: 0,
left: 0,
right: 0,
zIndex: 'docked',
})}
>
<VStack alignContent="center" className={css({ height: '250' })}>
<HStack
justify="space-between"
className={css({
width: 'onboarding',
})}
>
<div>
<When truthy={showLearnMore}>
<DocsButton
TriggerButton={({ onClick: onDocsClick }) => (
<HStack gap="50" className={css({ color: 'typography.text.secondary' })}>
<IconOutlineMenuBook />
<Text
onClick={(e) => {
e.preventDefault();
segment.track('Documentation linked clicked - [Onboarding - Signup]', {
step: pathname,
});
onDocsClick();
}}
href=""
>
Learn more in our docs
</Text>
</HStack>
)}
/>
</When>
</div>
<HStack gap="100">
<When truthy={canSkipSetup}>
<Button
disabled={loading}
onClick={() => {
segment.track('Skip setup button clicked - [Onboarding - Signup]', {
step: pathname,
});
navigate(ROUTES.WORKFLOWS);
}}
variant="transparent"
>
Skip setup
</Button>
</When>
<Tooltip label={tooltip} disabled={!tooltip}>
<Button loading={loading} onClick={onClick} disabled={disabled}>
{buttonText}
</Button>
</Tooltip>
</HStack>
</HStack>
</VStack>
</div>
);
};
Loading

0 comments on commit b0402e4

Please sign in to comment.