From 6d023e30164352663f0474a3d9b38b487a043569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Barrenechea=20S=C3=A1nchez?= Date: Tue, 22 Jun 2021 10:43:50 +0200 Subject: [PATCH 1/9] Help: floatting button --- app/layout/help/component.tsx | 96 +++++++++++++++++++++++++++++++++++ app/layout/help/index.ts | 1 + app/pages/projects/index.tsx | 3 ++ app/svgs/ui/help.svg | 6 +-- 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 app/layout/help/component.tsx create mode 100644 app/layout/help/index.ts diff --git a/app/layout/help/component.tsx b/app/layout/help/component.tsx new file mode 100644 index 0000000000..9913587d19 --- /dev/null +++ b/app/layout/help/component.tsx @@ -0,0 +1,96 @@ +import React, { useState, useCallback } from 'react'; +import cx from 'classnames'; +import Icon from 'components/icon'; + +import { motion } from 'framer-motion'; + +import HELP_SVG from 'svgs/ui/help.svg?sprite'; + +export const HelpButton = () => { + const [active, setActive] = useState(false); + + const onToggleActive = useCallback(() => { + setActive(!active); + }, [active]); + + return ( +
+
+ + Activate guide +
+
+ ); +}; + +export default HelpButton; diff --git a/app/layout/help/index.ts b/app/layout/help/index.ts new file mode 100644 index 0000000000..b404d7fd44 --- /dev/null +++ b/app/layout/help/index.ts @@ -0,0 +1 @@ +export { default } from './component'; diff --git a/app/pages/projects/index.tsx b/app/pages/projects/index.tsx index de5b835b43..8a0e83b615 100644 --- a/app/pages/projects/index.tsx +++ b/app/pages/projects/index.tsx @@ -10,6 +10,7 @@ import Title from 'layout/title/project-title'; import ProjectsWelcome from 'layout/projects/all/welcome'; import ProjectsToolbar from 'layout/projects/all/toolbar'; import ProjectsList from 'layout/projects/all/list'; +import Help from 'layout/help'; export const getServerSideProps = withProtection(withUser()); @@ -28,6 +29,8 @@ const ProjectsPage: React.FC = () => { + + ); diff --git a/app/svgs/ui/help.svg b/app/svgs/ui/help.svg index 9cc2aa2815..9f7b363b52 100644 --- a/app/svgs/ui/help.svg +++ b/app/svgs/ui/help.svg @@ -1,5 +1,3 @@ - - -help - + + From 96d01af2da79232e311f623ce8e562b4e83f650d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Barrenechea=20S=C3=A1nchez?= Date: Tue, 22 Jun 2021 13:29:54 +0200 Subject: [PATCH 2/9] Help: guides by page --- app/layout/help/component.tsx | 155 +++++++++++------- app/layout/help/guides/index.ts | 9 + app/layout/help/guides/projects/[id]/index.ts | 14 ++ app/layout/help/guides/projects/index.ts | 14 ++ app/layout/help/guides/projects/new.ts | 14 ++ app/layout/projects/all/toolbar/component.tsx | 5 +- app/package.json | 1 + app/pages/projects/[pid]/index.tsx | 3 + app/pages/projects/new.tsx | 3 + app/yarn.lock | 109 +++++++++++- 10 files changed, 253 insertions(+), 74 deletions(-) create mode 100644 app/layout/help/guides/index.ts create mode 100644 app/layout/help/guides/projects/[id]/index.ts create mode 100644 app/layout/help/guides/projects/index.ts create mode 100644 app/layout/help/guides/projects/new.ts diff --git a/app/layout/help/component.tsx b/app/layout/help/component.tsx index 9913587d19..5328273142 100644 --- a/app/layout/help/component.tsx +++ b/app/layout/help/component.tsx @@ -1,96 +1,125 @@ import React, { useState, useCallback } from 'react'; import cx from 'classnames'; + +import Joyride from 'react-joyride'; import Icon from 'components/icon'; import { motion } from 'framer-motion'; import HELP_SVG from 'svgs/ui/help.svg?sprite'; -export const HelpButton = () => { - const [active, setActive] = useState(false); +import { useRouter } from 'next/router'; + +import GUIDES from './guides'; + +export const Help = () => { + const [run, setRun] = useState(false); + const { pathname } = useRouter(); + const { STEPS } = GUIDES[pathname]; const onToggleActive = useCallback(() => { - setActive(!active); - }, [active]); + setRun(!run); + }, [run]); return ( -
-
- - Activate guide + }} + variants={{ + enter: { + bottom: '100%', + y: '100%', + x: '-50%', + }, + exit: { + bottom: '0%', + y: '0%', + x: '-50%', + }, + }} + > + + +
+ + Activate guide +
); }; -export default HelpButton; +export default Help; diff --git a/app/layout/help/guides/index.ts b/app/layout/help/guides/index.ts new file mode 100644 index 0000000000..1bbd24fb19 --- /dev/null +++ b/app/layout/help/guides/index.ts @@ -0,0 +1,9 @@ +import PROJECTS_GUIDE from './projects'; +import PROJECTS_NEW_GUIDE from './projects/new'; +import PROJECTS_ID_GUIDE from './projects/[id]'; + +export default { + '/projects': PROJECTS_GUIDE, + '/projects/new': PROJECTS_NEW_GUIDE, + '/projects/[id]': PROJECTS_ID_GUIDE, +}; diff --git a/app/layout/help/guides/projects/[id]/index.ts b/app/layout/help/guides/projects/[id]/index.ts new file mode 100644 index 0000000000..5b28b551b8 --- /dev/null +++ b/app/layout/help/guides/projects/[id]/index.ts @@ -0,0 +1,14 @@ +export const STEPS = [ + { + target: '#scenarios-search', + content: 'This is my awesome feature!', + }, + { + target: '#scenarios-filters', + content: 'This another awesome feature!', + }, +]; + +export default { + STEPS, +}; diff --git a/app/layout/help/guides/projects/index.ts b/app/layout/help/guides/projects/index.ts new file mode 100644 index 0000000000..1781ed4a64 --- /dev/null +++ b/app/layout/help/guides/projects/index.ts @@ -0,0 +1,14 @@ +export const STEPS = [ + { + target: '#projects-search', + content: 'This is my awesome feature!', + }, + { + target: '#projects-new', + content: 'This another awesome feature!', + }, +]; + +export default { + STEPS, +}; diff --git a/app/layout/help/guides/projects/new.ts b/app/layout/help/guides/projects/new.ts new file mode 100644 index 0000000000..1781ed4a64 --- /dev/null +++ b/app/layout/help/guides/projects/new.ts @@ -0,0 +1,14 @@ +export const STEPS = [ + { + target: '#projects-search', + content: 'This is my awesome feature!', + }, + { + target: '#projects-new', + content: 'This another awesome feature!', + }, +]; + +export default { + STEPS, +}; diff --git a/app/layout/projects/all/toolbar/component.tsx b/app/layout/projects/all/toolbar/component.tsx index d2772bf60d..cddc5ffd81 100644 --- a/app/layout/projects/all/toolbar/component.tsx +++ b/app/layout/projects/all/toolbar/component.tsx @@ -22,8 +22,8 @@ export const ProjectsToolbar: React.FC = () => { return ( -
-
+
+ + ); +}; + +export default HelpTooltip; diff --git a/app/layout/help/tooltip/index.ts b/app/layout/help/tooltip/index.ts new file mode 100644 index 0000000000..b404d7fd44 --- /dev/null +++ b/app/layout/help/tooltip/index.ts @@ -0,0 +1 @@ +export { default } from './component'; diff --git a/app/svgs/ui/help-2.svg b/app/svgs/ui/help-2.svg new file mode 100644 index 0000000000..6dac2ec239 --- /dev/null +++ b/app/svgs/ui/help-2.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 74d75779738cfc5822c0a72671bb075d3373a8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Barrenechea=20S=C3=A1nchez?= Date: Tue, 22 Jun 2021 22:01:07 +0200 Subject: [PATCH 4/9] Help: tooltip fixes --- app/layout/help/component.tsx | 3 +++ app/layout/help/guides/index.ts | 4 ++-- .../help/guides/projects/{[id] => [pid]}/index.ts | 0 app/layout/help/tooltip/component.tsx | 15 ++++++++++++--- 4 files changed, 17 insertions(+), 5 deletions(-) rename app/layout/help/guides/projects/{[id] => [pid]}/index.ts (100%) diff --git a/app/layout/help/component.tsx b/app/layout/help/component.tsx index 64d04702d9..a89299a914 100644 --- a/app/layout/help/component.tsx +++ b/app/layout/help/component.tsx @@ -47,6 +47,9 @@ export const Help = () => { position: 'absolute', spread: 16, }, + floaterWithAnimation: { + transition: 'opacity 0.3s', + }, }, }} callback={(state) => { diff --git a/app/layout/help/guides/index.ts b/app/layout/help/guides/index.ts index 1bbd24fb19..7dc425ac54 100644 --- a/app/layout/help/guides/index.ts +++ b/app/layout/help/guides/index.ts @@ -1,9 +1,9 @@ import PROJECTS_GUIDE from './projects'; import PROJECTS_NEW_GUIDE from './projects/new'; -import PROJECTS_ID_GUIDE from './projects/[id]'; +import PROJECTS_ID_GUIDE from './projects/[pid]'; export default { '/projects': PROJECTS_GUIDE, '/projects/new': PROJECTS_NEW_GUIDE, - '/projects/[id]': PROJECTS_ID_GUIDE, + '/projects/[pid]': PROJECTS_ID_GUIDE, }; diff --git a/app/layout/help/guides/projects/[id]/index.ts b/app/layout/help/guides/projects/[pid]/index.ts similarity index 100% rename from app/layout/help/guides/projects/[id]/index.ts rename to app/layout/help/guides/projects/[pid]/index.ts diff --git a/app/layout/help/tooltip/component.tsx b/app/layout/help/tooltip/component.tsx index 3efaadd8d5..e9623e7708 100644 --- a/app/layout/help/tooltip/component.tsx +++ b/app/layout/help/tooltip/component.tsx @@ -4,6 +4,7 @@ import cx from 'classnames'; import Button from 'components/button'; import Icon from 'components/icon'; +import CLOSE_SVG from 'svgs/ui/close.svg?sprite'; import ARROW_LEFT_SVG from 'svgs/ui/arrow-left.svg?sprite'; import ARROW_RIGHT_SVG from 'svgs/ui/arrow-right.svg?sprite'; import HELP_2_SVG from 'svgs/ui/help-2.svg?sprite'; @@ -19,11 +20,13 @@ interface HelpTooltipProps extends TooltipRenderProps { export const HelpTooltip = ({ index, + size, step, backProps, primaryProps, skipProps, tooltipProps, + isLastStep, }: HelpTooltipProps) => { const { title, subtitle, content } = step; @@ -61,7 +64,8 @@ export const HelpTooltip = ({ className="flex items-center justify-center bg-gray-100 rounded hover:bg-primary-500 w-7 h-7 focus:outline-none" {...primaryProps} > - + {!isLastStep && ()} + {isLastStep && ()}
@@ -71,7 +75,7 @@ export const HelpTooltip = ({ {content}
-
+
-
+ +
+ {`${index + 1}/${size}`} +
+ +
); }; From 9dddadbb91139ec09eb2a276ce3620dac5a3889a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Barrenechea=20S=C3=A1nchez?= Date: Wed, 23 Jun 2021 10:41:05 +0200 Subject: [PATCH 5/9] Help: guides updated --- .../help/guides/projects/[pid]/index.ts | 20 ++++++++++++++++--- app/layout/help/guides/projects/index.ts | 7 +++++++ app/layout/help/guides/projects/new.ts | 6 ++++-- app/layout/projects/all/list/component.tsx | 1 + app/layout/projects/new/form/component.tsx | 2 +- app/layout/projects/new/map/component.tsx | 5 ++++- .../show/header/toolbar/component.tsx | 2 ++ .../projects/show/scenarios/component.tsx | 2 +- .../show/scenarios/toolbar/component.tsx | 2 +- 9 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/layout/help/guides/projects/[pid]/index.ts b/app/layout/help/guides/projects/[pid]/index.ts index 9f0d6ee63d..4245a056a7 100644 --- a/app/layout/help/guides/projects/[pid]/index.ts +++ b/app/layout/help/guides/projects/[pid]/index.ts @@ -1,15 +1,29 @@ export const STEPS = [ { title: 'Project detail', - subtitle: 'Quick search', + subtitle: 'Quick search & filtering', target: '#scenarios-search', content: 'This is my awesome feature!', disableBeacon: true, }, { title: 'Project detail', - subtitle: 'Quick filtering', - target: '#scenarios-filters', + subtitle: 'Scenarios list', + target: '#scenarios-list', + content: 'This another awesome feature!', + disableBeacon: true, + }, + { + title: 'Project detail', + subtitle: 'Upload scenario', + target: '#scenarios-upload', + content: 'This another awesome feature!', + disableBeacon: true, + }, + { + title: 'Project detail', + subtitle: 'Download project', + target: '#scenarios-download', content: 'This another awesome feature!', disableBeacon: true, }, diff --git a/app/layout/help/guides/projects/index.ts b/app/layout/help/guides/projects/index.ts index 3673021dc5..59ac97675f 100644 --- a/app/layout/help/guides/projects/index.ts +++ b/app/layout/help/guides/projects/index.ts @@ -13,6 +13,13 @@ export const STEPS = [ content: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt...', disableBeacon: true, }, + { + title: 'Project dashboard', + subtitle: 'Project list', + target: '#projects-list', + content: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt...', + disableBeacon: true, + }, ]; export default { diff --git a/app/layout/help/guides/projects/new.ts b/app/layout/help/guides/projects/new.ts index edc8160096..6bdeec891e 100644 --- a/app/layout/help/guides/projects/new.ts +++ b/app/layout/help/guides/projects/new.ts @@ -2,16 +2,18 @@ export const STEPS = [ { title: 'Title1', subtitle: 'SubTitle1', - target: '#projects-search', + target: '#project-new-form', content: 'This is my awesome feature!', disableBeacon: true, + placement: 'auto', }, { title: 'Title2', subtitle: 'SubTitle2', - target: '#projects-new', + target: '#project-new-map', content: 'This another awesome feature!', disableBeacon: true, + placement: 'auto', }, ]; diff --git a/app/layout/projects/all/list/component.tsx b/app/layout/projects/all/list/component.tsx index c88451c336..146b11b3f5 100644 --- a/app/layout/projects/all/list/component.tsx +++ b/app/layout/projects/all/list/component.tsx @@ -71,6 +71,7 @@ export const ProjectsList: React.FC = () => { {isFetched && !!data.length && (
= () => { className="flex flex-col justify-between flex-grow w-full overflow-hidden" >
-
+
diff --git a/app/layout/projects/new/map/component.tsx b/app/layout/projects/new/map/component.tsx index 4dcb0e77d5..ca88d5f902 100644 --- a/app/layout/projects/new/map/component.tsx +++ b/app/layout/projects/new/map/component.tsx @@ -97,7 +97,10 @@ export const ProjectNewMap: React.FC = ({ }; return ( -
+
= () => { >
+
, + document.body, + )} + + ); +}; + +export default HelpBeacon; diff --git a/app/layout/help/index.ts b/app/layout/help/beacon/index.ts similarity index 100% rename from app/layout/help/index.ts rename to app/layout/help/beacon/index.ts diff --git a/app/layout/help/component.tsx b/app/layout/help/button/component.tsx similarity index 63% rename from app/layout/help/component.tsx rename to app/layout/help/button/component.tsx index a89299a914..90f5449e87 100644 --- a/app/layout/help/component.tsx +++ b/app/layout/help/button/component.tsx @@ -1,67 +1,24 @@ -import React, { useState, useCallback, useMemo } from 'react'; +import React, { useCallback } from 'react'; import cx from 'classnames'; -import Joyride from 'react-joyride'; import Icon from 'components/icon'; import { motion } from 'framer-motion'; -import HELP_SVG from 'svgs/ui/help.svg?sprite'; - -import { useRouter } from 'next/router'; +import { useHelp } from 'hooks/help'; -import HelpTooltip from './tooltip'; -import GUIDES from './guides'; +import HELP_SVG from 'svgs/ui/help.svg?sprite'; -export const Help = () => { - const [run, setRun] = useState(false); - const { pathname } = useRouter(); - const { STEPS } = useMemo(() => { - return GUIDES[pathname]; - }, [pathname]); +export const HelpButton = () => { + const { active, onActive } = useHelp(); - const onToggleRun = useCallback((e) => { + const onToggleActive = useCallback((e) => { e.preventDefault(); - setRun(!run); - }, [run]); + onActive(!active); + }, [active, onActive]); return (
- { - const { action } = state; - - if (action === 'reset') { - setRun(false); - } - }} - tooltipComponent={HelpTooltip} - /> -
@@ -74,13 +31,13 @@ export const Help = () => { style={{ boxShadow: '2px 1px 3px 0px rgba(0,0,0,0.5) inset', }} - onClick={onToggleRun} + onClick={onToggleActive} >
{ width: 'calc(100% + 7px)', height: 'calc(100% + 7px)', }} - animate={run ? 'enter' : 'exit'} + animate={active ? 'enter' : 'exit'} transition={{ duration: 0.2, }} @@ -108,7 +65,7 @@ export const Help = () => {
{ ); }; -export default Help; +export default HelpButton; diff --git a/app/layout/help/button/index.ts b/app/layout/help/button/index.ts new file mode 100644 index 0000000000..b404d7fd44 --- /dev/null +++ b/app/layout/help/button/index.ts @@ -0,0 +1 @@ +export { default } from './component'; diff --git a/app/layout/help/tooltip/component.tsx b/app/layout/help/tooltip/component.tsx index e9623e7708..5827f4c314 100644 --- a/app/layout/help/tooltip/component.tsx +++ b/app/layout/help/tooltip/component.tsx @@ -1,39 +1,26 @@ -import React from 'react'; -import cx from 'classnames'; +import React, { ReactNode } from 'react'; -import Button from 'components/button'; import Icon from 'components/icon'; -import CLOSE_SVG from 'svgs/ui/close.svg?sprite'; -import ARROW_LEFT_SVG from 'svgs/ui/arrow-left.svg?sprite'; -import ARROW_RIGHT_SVG from 'svgs/ui/arrow-right.svg?sprite'; import HELP_2_SVG from 'svgs/ui/help-2.svg?sprite'; -import { Step, TooltipRenderProps } from 'react-joyride'; - -interface HelpTooltipProps extends TooltipRenderProps { - index: number; - step: Step & { - subtitle: string; - }, +interface HelpTooltipProps { + title: string; + subtitle: string; + content: ReactNode, } export const HelpTooltip = ({ - index, - size, - step, - backProps, - primaryProps, - skipProps, - tooltipProps, - isLastStep, + title, + subtitle, + content, }: HelpTooltipProps) => { - const { title, subtitle, content } = step; - return (
@@ -44,52 +31,11 @@ export const HelpTooltip = ({

{title}

{subtitle}

- -
- - - - -
{content}
- -
- - -
- {`${index + 1}/${size}`} -
- -
); }; diff --git a/app/layout/projects/all/list/component.tsx b/app/layout/projects/all/list/component.tsx index 146b11b3f5..de18bceb61 100644 --- a/app/layout/projects/all/list/component.tsx +++ b/app/layout/projects/all/list/component.tsx @@ -4,6 +4,7 @@ import cx from 'classnames'; import { useSelector } from 'react-redux'; import Wrapper from 'layout/wrapper'; +import HelpBeacon from 'layout/help/beacon'; import Loading from 'components/loading'; import ConfirmationPrompt from 'components/confirmation-prompt'; @@ -70,35 +71,48 @@ export const ProjectsList: React.FC = () => { /> {isFetched && !!data.length && ( -
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. + Beatae ratione cumque in nobis fugiat, + neque ullam aliquam, commodi dolorem unde inventore eaque, + dolorum eveniet! Corrupti voluptatum molestias quaerat voluptatem ipsa. +
+ )} > - {data.map((d) => { - return ( - { - setDelete(d); - }} - /> - ); - })} - - setDelete(null)} - onDismiss={() => setDelete(null)} - /> - -
+
+ {data.map((d) => { + return ( + { + setDelete(d); + }} + /> + ); + })} + + setDelete(null)} + onDismiss={() => setDelete(null)} + /> + +
+ )} {isFetched && !data.length && ( diff --git a/app/layout/projects/all/toolbar/component.tsx b/app/layout/projects/all/toolbar/component.tsx index cddc5ffd81..b2da435210 100644 --- a/app/layout/projects/all/toolbar/component.tsx +++ b/app/layout/projects/all/toolbar/component.tsx @@ -9,8 +9,10 @@ import Link from 'next/link'; import Search from 'components/search'; import Button from 'components/button'; import Icon from 'components/icon'; +import HelpBeacon from 'layout/help/beacon'; import PLUS_SVG from 'svgs/ui/plus.svg?sprite'; +import UPLOAD_SVG from 'svgs/ui/upload.svg?sprite'; export interface ProjectsToolbarProps { @@ -23,28 +25,75 @@ export const ProjectsToolbar: React.FC = () => { return (
- + + Lorem ipsum dolor sit amet consectetur adipisicing elit. + Beatae ratione cumque in nobis fugiat, + neque ullam aliquam, commodi dolorem unde inventore eaque, + dolorum eveniet! Corrupti voluptatum molestias quaerat voluptatem ipsa. +
+ )} + > +
+ { dispatch(setSearch(value)); }} + /> +
+ + +
+ + Lorem ipsum dolor sit amet consectetur adipisicing elit. + Beatae ratione cumque in nobis fugiat, + neque ullam aliquam, commodi dolorem unde inventore eaque, + dolorum eveniet! Corrupti voluptatum molestias quaerat voluptatem ipsa. +
+ )} + > + + -
+ )} + > + +
diff --git a/app/pages/_app.tsx b/app/pages/_app.tsx index 6110519ba6..a44df1aa54 100644 --- a/app/pages/_app.tsx +++ b/app/pages/_app.tsx @@ -6,6 +6,7 @@ import { Hydrate } from 'react-query/hydration'; import { OverlayProvider } from '@react-aria/overlays'; import { Provider as AuthenticationProvider } from 'next-auth/client'; import { ToastProvider } from 'hooks/toast'; +import { HelpProvider } from 'hooks/help'; import type { AppProps } from 'next/app'; @@ -36,9 +37,11 @@ const MarxanApp: React.ReactNode = ({ Component, pageProps }: AppProps) => { defaultAutoDismiss defaultAutoDismissTime={5000} > -
- -
+ +
+ +
+
diff --git a/app/pages/projects/[pid]/index.tsx b/app/pages/projects/[pid]/index.tsx index 204cbe9377..45245e92f6 100644 --- a/app/pages/projects/[pid]/index.tsx +++ b/app/pages/projects/[pid]/index.tsx @@ -5,7 +5,7 @@ import Title from 'layout/title/project-title'; import Header from 'layout/header'; import Wrapper from 'layout/wrapper'; import Protected from 'layout/protected'; -import Help from 'layout/help'; +import Help from 'layout/help/button'; import ProjectHeader from 'layout/projects/show/header'; import ProjectScenarios from 'layout/projects/show/scenarios'; diff --git a/app/pages/projects/index.tsx b/app/pages/projects/index.tsx index 8a0e83b615..3b78b6eb54 100644 --- a/app/pages/projects/index.tsx +++ b/app/pages/projects/index.tsx @@ -10,7 +10,7 @@ import Title from 'layout/title/project-title'; import ProjectsWelcome from 'layout/projects/all/welcome'; import ProjectsToolbar from 'layout/projects/all/toolbar'; import ProjectsList from 'layout/projects/all/list'; -import Help from 'layout/help'; +import Help from 'layout/help/button'; export const getServerSideProps = withProtection(withUser()); diff --git a/app/pages/projects/new.tsx b/app/pages/projects/new.tsx index 523697c0b0..dbd05def7a 100644 --- a/app/pages/projects/new.tsx +++ b/app/pages/projects/new.tsx @@ -6,7 +6,7 @@ import Header from 'layout/header'; import Protected from 'layout/protected'; import Wrapper from 'layout/wrapper'; -import Help from 'layout/help'; +import Help from 'layout/help/button'; import ProjectNewForm from 'layout/projects/new/form'; import Breadcrumb from 'components/breadcrumb'; diff --git a/app/tailwind.config.js b/app/tailwind.config.js index 3ce96fdb67..774c36045b 100644 --- a/app/tailwind.config.js +++ b/app/tailwind.config.js @@ -525,8 +525,15 @@ module.exports = { }, }, pulse: { - '50%': { - opacity: '.5', + '0%': { + transform: 'scale(0.75)', + boxShadow: '0 0 0 0 rgba(0, 191, 255, 0)', + opacity: 1, + }, + '100%': { + transform: 'scale(1.25)', + boxShadow: '0 0 0 10px rgba(0, 191, 255, 0.9)', + opacity: 0, }, }, bounce: { From 77efcc4e22f8d0513c20940bbd129698de6697bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Barrenechea=20S=C3=A1nchez?= Date: Thu, 24 Jun 2021 16:36:04 +0200 Subject: [PATCH 7/9] Help: spotlight --- app/layout/help/beacon/component.tsx | 22 +++- app/layout/help/guides/index.ts | 9 -- .../help/guides/projects/[pid]/index.ts | 34 ------ app/layout/help/guides/projects/index.ts | 27 ----- app/layout/help/guides/projects/new.ts | 22 ---- app/layout/help/spotlight/component.tsx | 108 ++++++++++++++++++ app/layout/help/spotlight/index.ts | 1 + 7 files changed, 126 insertions(+), 97 deletions(-) delete mode 100644 app/layout/help/guides/index.ts delete mode 100644 app/layout/help/guides/projects/[pid]/index.ts delete mode 100644 app/layout/help/guides/projects/index.ts delete mode 100644 app/layout/help/guides/projects/new.ts create mode 100644 app/layout/help/spotlight/component.tsx create mode 100644 app/layout/help/spotlight/index.ts diff --git a/app/layout/help/beacon/component.tsx b/app/layout/help/beacon/component.tsx index 23bfdf0a60..02b30a171a 100644 --- a/app/layout/help/beacon/component.tsx +++ b/app/layout/help/beacon/component.tsx @@ -10,6 +10,7 @@ import { usePopper } from 'react-popper'; import Tooltip from 'components/tooltip'; import HelpTooltip from 'layout/help/tooltip'; +import HelpSpotlight from 'layout/help/spotlight'; export interface HelpBeaconProps { title: string; @@ -34,9 +35,15 @@ export const HelpBeacon: React.FC = ({ }); // 'usePopper' + const flipModifier = { + name: 'flip', + enabled: false, + }; + const { styles, attributes, update } = usePopper(childrenRef.current, beaconRef, { placement: 'top-start', modifiers: [ + flipModifier, ], }); @@ -51,10 +58,8 @@ export const HelpBeacon: React.FC = ({ placement="bottom" visible={visible && active} maxWidth={350} - onClickOutside={(i, e) => { - if (!beaconRef.contains(e.target)) { - setVisible(false); - } + onClickOutside={() => { + setVisible(false); }} content={( = ({ {CHILDREN} - {typeof window !== 'undefined' && active && createPortal( + {typeof window !== 'undefined' && active && !visible && createPortal(
setBeaconRef(el))} className={cx({ @@ -93,6 +98,13 @@ export const HelpBeacon: React.FC = ({
, document.body, )} + + {typeof window !== 'undefined' && active && visible && createPortal( + , + document.body, + )} ); }; diff --git a/app/layout/help/guides/index.ts b/app/layout/help/guides/index.ts deleted file mode 100644 index 7dc425ac54..0000000000 --- a/app/layout/help/guides/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import PROJECTS_GUIDE from './projects'; -import PROJECTS_NEW_GUIDE from './projects/new'; -import PROJECTS_ID_GUIDE from './projects/[pid]'; - -export default { - '/projects': PROJECTS_GUIDE, - '/projects/new': PROJECTS_NEW_GUIDE, - '/projects/[pid]': PROJECTS_ID_GUIDE, -}; diff --git a/app/layout/help/guides/projects/[pid]/index.ts b/app/layout/help/guides/projects/[pid]/index.ts deleted file mode 100644 index 4245a056a7..0000000000 --- a/app/layout/help/guides/projects/[pid]/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -export const STEPS = [ - { - title: 'Project detail', - subtitle: 'Quick search & filtering', - target: '#scenarios-search', - content: 'This is my awesome feature!', - disableBeacon: true, - }, - { - title: 'Project detail', - subtitle: 'Scenarios list', - target: '#scenarios-list', - content: 'This another awesome feature!', - disableBeacon: true, - }, - { - title: 'Project detail', - subtitle: 'Upload scenario', - target: '#scenarios-upload', - content: 'This another awesome feature!', - disableBeacon: true, - }, - { - title: 'Project detail', - subtitle: 'Download project', - target: '#scenarios-download', - content: 'This another awesome feature!', - disableBeacon: true, - }, -]; - -export default { - STEPS, -}; diff --git a/app/layout/help/guides/projects/index.ts b/app/layout/help/guides/projects/index.ts deleted file mode 100644 index 59ac97675f..0000000000 --- a/app/layout/help/guides/projects/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const STEPS = [ - { - title: 'Project dashboard', - subtitle: 'Quick search', - target: '#projects-search', - content: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt...', - disableBeacon: true, - }, - { - title: 'Project dashboard', - subtitle: 'Create project', - target: '#projects-new', - content: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt...', - disableBeacon: true, - }, - { - title: 'Project dashboard', - subtitle: 'Project list', - target: '#projects-list', - content: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt...', - disableBeacon: true, - }, -]; - -export default { - STEPS, -}; diff --git a/app/layout/help/guides/projects/new.ts b/app/layout/help/guides/projects/new.ts deleted file mode 100644 index 6bdeec891e..0000000000 --- a/app/layout/help/guides/projects/new.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const STEPS = [ - { - title: 'Title1', - subtitle: 'SubTitle1', - target: '#project-new-form', - content: 'This is my awesome feature!', - disableBeacon: true, - placement: 'auto', - }, - { - title: 'Title2', - subtitle: 'SubTitle2', - target: '#project-new-map', - content: 'This another awesome feature!', - disableBeacon: true, - placement: 'auto', - }, -]; - -export default { - STEPS, -}; diff --git a/app/layout/help/spotlight/component.tsx b/app/layout/help/spotlight/component.tsx new file mode 100644 index 0000000000..13afb429f7 --- /dev/null +++ b/app/layout/help/spotlight/component.tsx @@ -0,0 +1,108 @@ +import React, { + MutableRefObject, useEffect, useRef, useState, + useCallback, +} from 'react'; + +interface HelpSpotlightProps { + childrenRef: MutableRefObject; +} + +export const HelpSpotlight = ({ + childrenRef, +}: HelpSpotlightProps) => { + const [canvasSize, setCanvasSize] = useState({ + width: 0, + height: 0, + }); + + const canvasRef = useRef(null); + + const getCanvasSize = () => { + const { width, height } = document.body.getBoundingClientRect(); + + setCanvasSize({ + width, height, + }); + }; + + const drawBackground = useCallback((CTX, reference) => { + const { width: canvaswidth, height: canvasheight } = canvasSize; + + if (reference.current) { + const { + top, left, width, height, + } = reference.current.getBoundingClientRect(); + + const h = height < canvasheight / 2 ? canvasheight / 2 : height * 1.5; + + const gradient = CTX.createRadialGradient( + left + width / 2, + top + height / 2, + h, + left + width / 2, + top + height / 2, + h / 2, + ); + + // Add three color stops + gradient.addColorStop(0, 'rgba(0,0,0,1)'); + gradient.addColorStop(0.75, 'rgba(0,0,0,0.75)'); + gradient.addColorStop(1, 'rgba(0,0,0,0)'); + CTX.clearRect(0, 0, canvaswidth, canvasheight); + + CTX.beginPath(); + CTX.rect(0, 0, canvaswidth, canvasheight); + CTX.fillStyle = gradient; + CTX.fill(); + } + }, [canvasSize]); + + const drawHighlight = useCallback((CTX, reference) => { + if (reference.current) { + const { + top, left, width, height, + } = reference.current.getBoundingClientRect(); + + CTX.globalCompositeOperation = 'destination-out'; + CTX.beginPath(); + CTX.rect(left, top, width, height); + CTX.fillStyle = 'white'; + CTX.fill(); + } + }, []); + + const updateCanvas = useCallback(() => { + const CTX = canvasRef.current.getContext('2d'); + CTX.save(); + + drawBackground(CTX, childrenRef); + drawHighlight(CTX, childrenRef); + + CTX.restore(); + }, [childrenRef, drawBackground, drawHighlight]); + + useEffect(() => { + getCanvasSize(); + + window.addEventListener('resize', getCanvasSize); + + return () => { + window.removeEventListener('resize', getCanvasSize); + }; + }, []); + + useEffect(() => { + updateCanvas(); + }, [updateCanvas]); + + return ( + + ); +}; + +export default HelpSpotlight; diff --git a/app/layout/help/spotlight/index.ts b/app/layout/help/spotlight/index.ts new file mode 100644 index 0000000000..b404d7fd44 --- /dev/null +++ b/app/layout/help/spotlight/index.ts @@ -0,0 +1 @@ +export { default } from './component'; From 27edda8de3d9358cccb6c4810a9cc66a1dfd4a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Barrenechea=20S=C3=A1nchez?= Date: Fri, 25 Jun 2021 08:42:20 +0200 Subject: [PATCH 8/9] Help: spotlight fixes --- app/hooks/help/constants.ts | 8 -------- app/hooks/help/index.tsx | 1 + app/layout/help/beacon/component.tsx | 6 ++---- app/layout/help/spotlight/component.tsx | 10 ++++------ app/layout/projects/all/toolbar/component.tsx | 1 + 5 files changed, 8 insertions(+), 18 deletions(-) delete mode 100644 app/hooks/help/constants.ts diff --git a/app/hooks/help/constants.ts b/app/hooks/help/constants.ts deleted file mode 100644 index e457991800..0000000000 --- a/app/hooks/help/constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const PLACEMENTS = { - 'top-left': { top: 0, left: 0 }, - 'top-right': { top: 0, right: 0 }, - 'top-center': { top: 0, left: '50%', transform: 'translateX(-50%)' }, - 'bottom-left': { bottom: 0, left: 0 }, - 'bottom-right': { bottom: 0, right: 0 }, - 'bottom-center': { bottom: 0, left: '50%', transform: 'translateX(-50%)' }, -}; diff --git a/app/hooks/help/index.tsx b/app/hooks/help/index.tsx index 34bc8d74cd..3c851561ab 100644 --- a/app/hooks/help/index.tsx +++ b/app/hooks/help/index.tsx @@ -1,6 +1,7 @@ import React, { createContext, useCallback, useContext, useState, } from 'react'; + import { HelpContextProps, HelpProviderProps } from './types'; const HelpContext = createContext({ diff --git a/app/layout/help/beacon/component.tsx b/app/layout/help/beacon/component.tsx index 02b30a171a..005956a70b 100644 --- a/app/layout/help/beacon/component.tsx +++ b/app/layout/help/beacon/component.tsx @@ -84,11 +84,9 @@ export const HelpBeacon: React.FC = ({ >
, - document.body, + document?.body, )} {typeof window !== 'undefined' && active && visible && createPortal( , - document.body, + document?.body, )} ); diff --git a/app/layout/help/spotlight/component.tsx b/app/layout/help/spotlight/component.tsx index 13afb429f7..b76efc5324 100644 --- a/app/layout/help/spotlight/component.tsx +++ b/app/layout/help/spotlight/component.tsx @@ -33,25 +33,23 @@ export const HelpSpotlight = ({ top, left, width, height, } = reference.current.getBoundingClientRect(); - const h = height < canvasheight / 2 ? canvasheight / 2 : height * 1.5; - const gradient = CTX.createRadialGradient( left + width / 2, top + height / 2, - h, + width, left + width / 2, top + height / 2, - h / 2, + height, ); // Add three color stops - gradient.addColorStop(0, 'rgba(0,0,0,1)'); - gradient.addColorStop(0.75, 'rgba(0,0,0,0.75)'); + gradient.addColorStop(0, 'rgba(0,0,0,0.75)'); gradient.addColorStop(1, 'rgba(0,0,0,0)'); CTX.clearRect(0, 0, canvaswidth, canvasheight); CTX.beginPath(); CTX.rect(0, 0, canvaswidth, canvasheight); + // CTX.fillStyle = 'rgba(0,0,0,0.75)'; CTX.fillStyle = gradient; CTX.fill(); } diff --git a/app/layout/projects/all/toolbar/component.tsx b/app/layout/projects/all/toolbar/component.tsx index b2da435210..d81a59f7bb 100644 --- a/app/layout/projects/all/toolbar/component.tsx +++ b/app/layout/projects/all/toolbar/component.tsx @@ -39,6 +39,7 @@ export const ProjectsToolbar: React.FC = () => { >
Date: Fri, 25 Jun 2021 13:04:04 +0200 Subject: [PATCH 9/9] Help: resize observer --- app/hooks/help/index.tsx | 30 +++++++- app/hooks/help/types.ts | 9 +++ app/layout/help/beacon/component.tsx | 68 ++++++++++++++----- app/layout/help/spotlight/component.tsx | 7 +- app/layout/projects/all/list/component.tsx | 1 + app/layout/projects/all/toolbar/component.tsx | 3 + .../projects/show/scenarios/component.tsx | 44 ++++++++---- app/package.json | 1 + app/yarn.lock | 15 ++++ 9 files changed, 147 insertions(+), 31 deletions(-) diff --git a/app/hooks/help/index.tsx b/app/hooks/help/index.tsx index 3c851561ab..036aefc9a0 100644 --- a/app/hooks/help/index.tsx +++ b/app/hooks/help/index.tsx @@ -2,11 +2,14 @@ import React, { createContext, useCallback, useContext, useState, } from 'react'; -import { HelpContextProps, HelpProviderProps } from './types'; +import { BeaconProps, HelpContextProps, HelpProviderProps } from './types'; const HelpContext = createContext({ active: false, onActive: (active) => { console.info(active); }, + beacons: {}, + addBeacon: (beacon) => { console.info(beacon); }, + removeBeacon: (beacon) => { console.info(beacon); }, }); // Hook for child components to get the toast object ... @@ -23,6 +26,9 @@ export const useHelp = () => { return { active: ctx.active, onActive: ctx.onActive, + beacons: ctx.beacons, + addBeacon: ctx.addBeacon, + removeBeacon: ctx.removeBeacon, }; }; @@ -32,16 +38,38 @@ export function HelpProvider({ children, }: HelpProviderProps) { const [active, setActive] = useState(false); + const [beacons, setBeacons] = useState>({}); const onActive = useCallback((a: boolean) => { return setActive(a); }, [setActive]); + const addBeacon = useCallback(({ id, state, update }) => { + setBeacons((prevBeacons) => { + return { + ...prevBeacons, + [id]: { + id, + state, + update, + }, + }; + }); + }, []); + + const removeBeacon = useCallback((id: string) => { + const { [id]: omitted, ...rest } = beacons; + setBeacons(rest); + }, [beacons]); + return ( {children} diff --git a/app/hooks/help/types.ts b/app/hooks/help/types.ts index 559f3823c8..27b7796443 100644 --- a/app/hooks/help/types.ts +++ b/app/hooks/help/types.ts @@ -1,8 +1,17 @@ import { ReactNode } from 'react'; +export interface BeaconProps { + id: string; + update: () => void; + state: any; +} + export interface HelpContextProps { active: boolean; onActive: (active: boolean) => void; + beacons: Record, + addBeacon: (beacon: Record) => void, + removeBeacon: (beaconId: string) => void, } export interface HelpProviderProps { diff --git a/app/layout/help/beacon/component.tsx b/app/layout/help/beacon/component.tsx index 005956a70b..8deacb9153 100644 --- a/app/layout/help/beacon/component.tsx +++ b/app/layout/help/beacon/component.tsx @@ -1,5 +1,8 @@ import React, { - ReactNode, ReactElement, useRef, cloneElement, useEffect, useState, + ReactNode, ReactElement, cloneElement, useState, + useEffect, + useCallback, + useRef, } from 'react'; import { createPortal } from 'react-dom'; @@ -7,12 +10,25 @@ import cx from 'classnames'; import { useHelp } from 'hooks/help'; import { usePopper } from 'react-popper'; +import { useResizeDetector } from 'react-resize-detector'; + +import { AnimatePresence } from 'framer-motion'; import Tooltip from 'components/tooltip'; import HelpTooltip from 'layout/help/tooltip'; import HelpSpotlight from 'layout/help/spotlight'; +const flipModifier = { + name: 'flip', + enabled: false, +}; + +const hideModifier = { + name: 'hide', + enabled: true, +}; export interface HelpBeaconProps { + id: string; title: string; subtitle: string; content: ReactNode; @@ -20,12 +36,13 @@ export interface HelpBeaconProps { } export const HelpBeacon: React.FC = ({ + id, title, subtitle, content, children, }: HelpBeaconProps) => { - const { active } = useHelp(); + const { active, beacons, addBeacon } = useHelp(); const [visible, setVisible] = useState(false); const childrenRef = useRef(null); const [beaconRef, setBeaconRef] = useState(null); @@ -34,22 +51,36 @@ export const HelpBeacon: React.FC = ({ ref: childrenRef, }); - // 'usePopper' - const flipModifier = { - name: 'flip', - enabled: false, - }; + const onResize = useCallback(() => { + Object.keys(beacons).forEach((k) => { + const b = beacons[k]; + if (b.update) b.update(); + }); + }, [beacons]); - const { styles, attributes, update } = usePopper(childrenRef.current, beaconRef, { + // 'usePopper' + const { + styles, attributes, state, update, + } = usePopper(childrenRef.current, beaconRef, { placement: 'top-start', modifiers: [ flipModifier, + hideModifier, ], }); + useResizeDetector({ + targetRef: childrenRef, + onResize, + }); + useEffect(() => { - if (update) update(); - }, [update]); + addBeacon({ + id, + state, + update, + }); + }, [active, addBeacon, id, state, update, childrenRef, beaconRef]); return ( <> @@ -76,8 +107,9 @@ export const HelpBeacon: React.FC = ({
setBeaconRef(el))} className={cx({ + 'z-50': true, 'visible pointer-events-auto': active, - 'invisible pointer-events-none': !active, + 'invisible pointer-events-none': !active || attributes?.popper?.['data-popper-reference-hidden'] || attributes?.popper?.['data-popper-escaped'], })} style={styles.popper} {...attributes.popper} @@ -85,7 +117,7 @@ export const HelpBeacon: React.FC = ({