From 4125f306be9b052c63b4f0c6660397990bb807d5 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 11 Feb 2021 10:40:50 +1000 Subject: [PATCH 1/8] interface: update tutorial location --- pkg/interface/config/webpack.dev.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/interface/config/webpack.dev.js b/pkg/interface/config/webpack.dev.js index b23edf5b2..1e6c52764 100644 --- a/pkg/interface/config/webpack.dev.js +++ b/pkg/interface/config/webpack.dev.js @@ -122,9 +122,9 @@ module.exports = { new webpack.DefinePlugin({ 'process.env.TUTORIAL_HOST': JSON.stringify('~hastuc-dibtux'), 'process.env.TUTORIAL_GROUP': JSON.stringify('beginner-island'), - 'process.env.TUTORIAL_CHAT': JSON.stringify('chat-8401'), - 'process.env.TUTORIAL_BOOK': JSON.stringify('notebook-9148'), - 'process.env.TUTORIAL_LINKS': JSON.stringify('link-4353'), + 'process.env.TUTORIAL_CHAT': JSON.stringify('chat-1704'), + 'process.env.TUTORIAL_BOOK': JSON.stringify('book-9695'), + 'process.env.TUTORIAL_LINKS': JSON.stringify('link-2827'), }) // new CleanWebpackPlugin(), From 4c4667c0d96ae96da9884ee709257eef582f6807 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 11 Feb 2021 10:41:16 +1000 Subject: [PATCH 2/8] tutorial: fix desktop positioning --- .../src/views/landscape/components/TutorialModal.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/interface/src/views/landscape/components/TutorialModal.tsx b/pkg/interface/src/views/landscape/components/TutorialModal.tsx index e53151c45..4d2f97d0a 100644 --- a/pkg/interface/src/views/landscape/components/TutorialModal.tsx +++ b/pkg/interface/src/views/landscape/components/TutorialModal.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useCallback } from "react"; +import _ from 'lodash'; import { Box, Col, Row, Button, Text, Icon, Action } from "@tlon/indigo-react"; import { useHistory } from "react-router-dom"; import { TutorialProgress, tutorialProgress as progress } from "~/types"; @@ -75,13 +76,13 @@ export function TutorialModal(props: { api: GlobalApi }) { if(key === 'bottom' || key === 'left') { return ['0px', ...value]; } - return [null, ...value]; + return ['unset', ...value]; }); if(!('bottom' in withMobile)) { - withMobile.bottom = ['0px', null]; + withMobile.bottom = ['0px', 'unset']; } if(!('left' in withMobile)) { - withMobile.left = ['0px', null]; + withMobile.left = ['0px', 'unset']; } if (newCoords) { From 7568ecc2b4b788cf8bc569d31a3ebbe3318c5a6b Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 11 Feb 2021 10:42:11 +1000 Subject: [PATCH 3/8] tutorial: launch from omnibox --- pkg/interface/src/logic/lib/omnibox.js | 1 + pkg/interface/src/views/apps/launch/app.js | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/pkg/interface/src/logic/lib/omnibox.js b/pkg/interface/src/logic/lib/omnibox.js index 4185d57b7..0a9d3d22d 100644 --- a/pkg/interface/src/logic/lib/omnibox.js +++ b/pkg/interface/src/logic/lib/omnibox.js @@ -34,6 +34,7 @@ const commandIndex = function (currentGroup) { commands.push(result(`Groups: Create`, `/~landscape/new`, 'Groups', null)); commands.push(result(`Groups: Join`, `/~landscape/join`, 'Groups', null)); commands.push(result(`Channel: Create`, `/~landscape${workspace}/new`, 'Groups', null)); + commands.push(result(`Tutorial`, '/?tutorial=true', 'Null', null)); return commands; }; diff --git a/pkg/interface/src/views/apps/launch/app.js b/pkg/interface/src/views/apps/launch/app.js index 7abc1f4c2..045959e93 100644 --- a/pkg/interface/src/views/apps/launch/app.js +++ b/pkg/interface/src/views/apps/launch/app.js @@ -20,6 +20,7 @@ import { JoinGroup } from "~/views/landscape/components/JoinGroup"; import { Helmet } from 'react-helmet'; import useLocalState from "~/logic/state/local"; import { useWaitForProps } from '~/logic/lib/useWaitForProps'; +import { useQuery } from "~/logic/lib/useQuery"; import { hasTutorialGroup, TUTORIAL_GROUP, @@ -69,6 +70,15 @@ export default function LaunchApp(props) { ); + const { query } = useQuery(); + + useEffect(() => { + if(query.tutorial) { + props.api.settings.putEntry('tutorial', 'seen', false); + } + + }, [query]); + const { tutorialProgress, nextTutStep } = useLocalState(tutSelector); const waiter = useWaitForProps(props); From 76de225b4a20ada45780284d2617b52e7b223140 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 11 Feb 2021 16:08:40 +1000 Subject: [PATCH 4/8] interface: untangle event propagation in modals --- pkg/interface/src/logic/lib/useModal.tsx | 22 +++--- .../src/logic/lib/useOutsideClick.ts | 3 +- .../src/views/components/ModalOverlay.tsx | 69 ++++++++++++------- .../ChannelPopoverRoutes/Notifications.tsx | 2 - .../components/ChannelPopoverRoutes/index.tsx | 7 +- .../landscape/components/GroupSwitcher.tsx | 1 - .../landscape/components/PopoverRoutes.tsx | 5 +- 7 files changed, 65 insertions(+), 44 deletions(-) diff --git a/pkg/interface/src/logic/lib/useModal.tsx b/pkg/interface/src/logic/lib/useModal.tsx index e2a10c143..c7cb9be7d 100644 --- a/pkg/interface/src/logic/lib/useModal.tsx +++ b/pkg/interface/src/logic/lib/useModal.tsx @@ -12,6 +12,8 @@ import { Box } from "@tlon/indigo-react"; import { useOutsideClick } from "./useOutsideClick"; import { ModalOverlay } from "~/views/components/ModalOverlay"; import {Portal} from "~/views/components/Portal"; +import {ModalPortal} from "~/views/components/ModalPortal"; +import {PropFunc} from "~/types"; type ModalFunc = (dismiss: () => void) => JSX.Element; interface UseModalProps { @@ -23,7 +25,8 @@ interface UseModalResult { showModal: () => void; } -export function useModal(props: UseModalProps): UseModalResult { +export function useModal(props: UseModalProps & PropFunc): UseModalResult { + const { modal, ...rest } = props; const innerRef = useRef(); const [modalShown, setModalShown] = useState(false); @@ -39,15 +42,13 @@ export function useModal(props: UseModalProps): UseModalResult { () => !modalShown ? null - : typeof props.modal === "function" - ? props.modal(dismiss) - : props.modal, - [modalShown, props.modal, dismiss] + : typeof modal === "function" + ? modal(dismiss) + : modal, + [modalShown, modal, dismiss] ); - useOutsideClick(innerRef, dismiss); - - const modal = useMemo( + const modalComponent = useMemo( () => !inner ? null : ( @@ -63,7 +64,8 @@ export function useModal(props: UseModalProps): UseModalResult { alignItems="stretch" flexDirection="column" spacing="2" - + dismiss={dismiss} + {...rest} > {inner} @@ -74,6 +76,6 @@ export function useModal(props: UseModalProps): UseModalResult { return { showModal, - modal, + modal: modalComponent, }; } diff --git a/pkg/interface/src/logic/lib/useOutsideClick.ts b/pkg/interface/src/logic/lib/useOutsideClick.ts index d43636967..4d4f95ca6 100644 --- a/pkg/interface/src/logic/lib/useOutsideClick.ts +++ b/pkg/interface/src/logic/lib/useOutsideClick.ts @@ -9,8 +9,7 @@ export function useOutsideClick( const portalRoot = document.querySelector('#portal-root')!; if ( ref.current && - !ref.current.contains(event.target as any) && - (!portalRoot.contains(ref.current) || portalRoot.contains(event.target as any)) + !ref.current.contains(event.target as any) ) { onClick(); } diff --git a/pkg/interface/src/views/components/ModalOverlay.tsx b/pkg/interface/src/views/components/ModalOverlay.tsx index ad41cd2f0..fee8c578e 100644 --- a/pkg/interface/src/views/components/ModalOverlay.tsx +++ b/pkg/interface/src/views/components/ModalOverlay.tsx @@ -1,29 +1,52 @@ -import React from "react"; +import React, { useCallback, UIEvent, MouseEvent, useRef } from "react"; import { Box } from "@tlon/indigo-react"; import { PropFunc } from "~/types/util"; interface ModalOverlayProps { spacing: PropFunc["m"]; + dismiss: () => void; +} +type Props = ModalOverlayProps & PropFunc; +export const ModalOverlay = (props: Props) => { + const { spacing, ...rest } = props; + const ref = useRef(null); + const onClick = useCallback( + (e: any) => { + if (!(ref as any).current.contains(e.target)) { + props.dismiss(); + } + e.stopPropagation(); + }, + [props.dismiss, ref] + ); + + const onKeyDown = useCallback( + (e: any) => { + if (e.key === "Escape") { + props.dismiss(); + e.stopPropagation(); + } + }, + [props.dismiss, ref] + ); + + return ( + + + + ); } -export const ModalOverlay = React.forwardRef( - (props: ModalOverlayProps & PropFunc, ref) => { - const { spacing, ...rest } = props; - return ( - - - - ); - } -); diff --git a/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/Notifications.tsx b/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/Notifications.tsx index 5cebda2f7..da0f6963e 100644 --- a/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/Notifications.tsx +++ b/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/Notifications.tsx @@ -3,7 +3,6 @@ import { Col, Text, BaseLabel, Label } from "@tlon/indigo-react"; import GlobalApi from "~/logic/api/global"; import { Association, NotificationGraphConfig } from "~/types"; import { StatelessAsyncToggle } from "~/views/components/StatelessAsyncToggle"; -import {useTutorialModal} from "~/views/components/useTutorialModal"; interface ChannelNotificationsProps { api: GlobalApi; @@ -27,7 +26,6 @@ export function ChannelNotifications(props: ChannelNotificationsProps) { const anchorRef = useRef(null) - useTutorialModal('notifications', true, anchorRef.current); return ( diff --git a/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/index.tsx b/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/index.tsx index 2056e110b..3f0b39287 100644 --- a/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/index.tsx +++ b/pkg/interface/src/views/landscape/components/ChannelPopoverRoutes/index.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from "react"; +import React, { useRef, useCallback } from "react"; import { ModalOverlay } from "~/views/components/ModalOverlay"; import { Col, Box, Text, Row } from "@tlon/indigo-react"; import { ChannelPopoverRoutesSidebar } from "./Sidebar"; @@ -36,9 +36,9 @@ export function ChannelPopoverRoutes(props: ChannelPopoverRoutesProps) { const overlayRef = useRef(); const history = useHistory(); - useOutsideClick(overlayRef, () => { + const onDismiss = useCallback(() => { history.push(props.baseUrl); - }); + }, [history, props.baseUrl]); const handleUnsubscribe = async () => { const [,,ship,name] = association.resource.split('/'); @@ -62,6 +62,7 @@ export function ChannelPopoverRoutes(props: ChannelPopoverRoutesProps) { width="100%" spacing={[3, 5, 7]} ref={overlayRef} + dismiss={onDismiss} > `${props.baseUrl}/popover${url}`; const innerRef = useRef(null); - const onOutsideClick = useCallback(() => { + const onDismiss = useCallback(() => { props.history.push(props.baseUrl); }, [props.history.push, props.baseUrl]); - useOutsideClick(innerRef, onOutsideClick); useHashLink(); @@ -62,6 +60,7 @@ export function PopoverRoutes( width="100%" height="100%" bg="white" + dismiss={onDismiss} > Date: Thu, 11 Feb 2021 16:12:04 +1000 Subject: [PATCH 5/8] launch: bring tutorial prompt to spec --- pkg/interface/src/views/apps/launch/app.js | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/pkg/interface/src/views/apps/launch/app.js b/pkg/interface/src/views/apps/launch/app.js index 045959e93..1e0c937e1 100644 --- a/pkg/interface/src/views/apps/launch/app.js +++ b/pkg/interface/src/views/apps/launch/app.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useMemo, useEffect } from 'react'; import styled from 'styled-components'; import { useHistory } from 'react-router-dom'; import f from 'lodash/fp'; @@ -73,10 +73,13 @@ export default function LaunchApp(props) { const { query } = useQuery(); useEffect(() => { - if(query.tutorial) { - props.api.settings.putEntry('tutorial', 'seen', false); + if(query.get('tutorial')) { + if(hasTutorialGroup(props)) { + nextTutStep(); + } else { + showModal(); + } } - }, [query]); const { tutorialProgress, nextTutStep } = useLocalState(tutSelector); @@ -84,6 +87,8 @@ export default function LaunchApp(props) { const waiter = useWaitForProps(props); const { modal, showModal } = useModal({ + position: 'relative', + maxWidth: '350px', modal: (dismiss) => { const onDismiss = (e) => { e.stopPropagation(); @@ -97,7 +102,7 @@ export default function LaunchApp(props) { await waiter(hasTutorialGroup); await Promise.all( [TUTORIAL_BOOK, TUTORIAL_CHAT, TUTORIAL_LINKS].map(graph => - api.graph.join(TUTORIAL_HOST, graph))); + props.api.graph.join(TUTORIAL_HOST, graph))); await waiter(p => { return `/ship/${TUTORIAL_HOST}/${TUTORIAL_CHAT}` in p.associations.graph && @@ -109,7 +114,10 @@ export default function LaunchApp(props) { dismiss(); } return ( - + + + + Welcome You have been invited to use Landscape, an interface to chat @@ -118,7 +126,7 @@ export default function LaunchApp(props) { Would you like a tour of Landscape? - + Yes @@ -126,12 +134,14 @@ export default function LaunchApp(props) { )} }); + const hasLoaded = useMemo(() => Object.keys(props.contacts).length > 0, [props.contacts]); + useEffect(() => { const seenTutorial = _.get(props.settings, ['tutorial', 'seen'], true); - if(!seenTutorial && tutorialProgress === 'hidden') { + if(hasLoaded && !seenTutorial && tutorialProgress === 'hidden') { showModal(); } - }, [props.settings]); + }, [props.settings, hasLoaded]); return ( <> From fe22d33696ee7c05501e407119c05577e80cafba Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 11 Feb 2021 16:13:23 +1000 Subject: [PATCH 6/8] Tutorial: bring into line with designs --- pkg/interface/src/logic/lib/tutorialModal.ts | 78 ++++++--- pkg/interface/src/types/local-update.ts | 2 +- .../apps/notifications/notifications.tsx | 22 ++- .../views/apps/profile/components/Profile.tsx | 3 +- .../landscape/components/TutorialModal.tsx | 159 +++++++++++++----- 5 files changed, 192 insertions(+), 72 deletions(-) diff --git a/pkg/interface/src/logic/lib/tutorialModal.ts b/pkg/interface/src/logic/lib/tutorialModal.ts index cc7aacd2c..ef1d753b1 100644 --- a/pkg/interface/src/logic/lib/tutorialModal.ts +++ b/pkg/interface/src/logic/lib/tutorialModal.ts @@ -1,8 +1,9 @@ import { TutorialProgress, Associations } from "~/types"; import { AlignX, AlignY } from "~/logic/lib/relativePosition"; +import { Direction } from "~/views/components/Triangle"; export const MODAL_WIDTH = 256; -export const MODAL_HEIGHT = 180; +export const MODAL_HEIGHT = 256; export const MODAL_WIDTH_PX = `${MODAL_WIDTH}px`; export const MODAL_HEIGHT_PX = `${MODAL_HEIGHT}px`; @@ -20,6 +21,7 @@ interface StepDetail { alignY: AlignY | AlignY[]; offsetX: number; offsetY: number; + arrow: Direction; } export function hasTutorialGroup(props: { associations: Associations }) { @@ -28,8 +30,36 @@ export function hasTutorialGroup(props: { associations: Associations }) { ); } +export const getTrianglePosition = (dir: Direction) => { + const midY = `${MODAL_HEIGHT / 2 - 8}px`; + const midX = `${MODAL_WIDTH / 2 - 8}px`; + switch(dir) { + case 'East': + return { + top: midY, + right: '-32px' + }; + case 'West': + return { + top: midY, + left: '-32px' + } + case 'North': + return { + top: '-32px', + left: midX + }; + case 'South': + return { + bottom: '-32px', + left: midX + }; + } +} + export const progressDetails: Record = { hidden: {} as any, + exit: {} as any, done: { title: "End", description: @@ -41,14 +71,15 @@ export const progressDetails: Record = { offsetY: 0, }, start: { - title: "New group added", + title: "New Group added", description: "We just added you to the Beginner island group to show you around. This group is public, but other groups can be private", url: "/", alignX: "right", alignY: "top", - offsetX: MODAL_WIDTH + 8, - offsetY: 0, + arrow: "West", + offsetX: MODAL_WIDTH + 24, + offsetY: 64, }, "group-desc": { title: "What's a group", @@ -57,7 +88,8 @@ export const progressDetails: Record = { url: `/~landscape/ship/${TUTORIAL_HOST}/${TUTORIAL_GROUP}`, alignX: "left", alignY: "top", - offsetX: MODAL_WIDTH + 8, + arrow: "East", + offsetX: MODAL_WIDTH + 24, offsetY: MODAL_HEIGHT / 2 - 8, }, channels: { @@ -67,7 +99,8 @@ export const progressDetails: Record = { url: `/~landscape/ship/${TUTORIAL_HOST}/${TUTORIAL_GROUP}`, alignY: "top", alignX: "right", - offsetX: MODAL_WIDTH + 8, + arrow: "West", + offsetX: MODAL_WIDTH + 24, offsetY: -8, }, chat: { @@ -76,9 +109,10 @@ export const progressDetails: Record = { "Chat channels are for messaging within your group. Direct Messages are also supported, and are accessible from the “DMs” tile on the homescreen", url: `/~landscape/ship/${TUTORIAL_HOST}/${TUTORIAL_GROUP}/resource/chat/ship/${TUTORIAL_HOST}/${TUTORIAL_CHAT}`, alignY: "top", + arrow: "North", alignX: "right", - offsetX: 0, - offsetY: -32, + offsetY: -56, + offsetX: -8, }, link: { title: "Collection", @@ -87,8 +121,9 @@ export const progressDetails: Record = { url: `/~landscape/ship/${TUTORIAL_HOST}/${TUTORIAL_GROUP}/resource/link/ship/${TUTORIAL_HOST}/${TUTORIAL_LINKS}`, alignY: "top", alignX: "right", - offsetX: 0, - offsetY: -32, + arrow: "North", + offsetX: -8, + offsetY: -56, }, publish: { title: "Notebook", @@ -97,18 +132,19 @@ export const progressDetails: Record = { url: `/~landscape/ship/${TUTORIAL_HOST}/${TUTORIAL_GROUP}/resource/publish/ship/${TUTORIAL_HOST}/${TUTORIAL_BOOK}`, alignY: "top", alignX: "right", - offsetX: 0, - offsetY: -32, + arrow: "North", + offsetX: -8, + offsetY: -56, }, notifications: { title: "Notifications", - description: - "Subscribing to a channel will send you notifications when there are new updates. You will also receive a notification when someone mentions your name in a channel.", - url: `/~landscape/ship/${TUTORIAL_HOST}/${TUTORIAL_GROUP}/resource/publish/ship/${TUTORIAL_HOST}/${TUTORIAL_BOOK}/settings#notifications`, + description: "You will get updates from subscribed channels and mentions here. You can access Notifications through Leap.", + url: '/~notifications', alignY: "top", - alignX: "right", - offsetX: 0, - offsetY: -32, + alignX: "left", + arrow: "North", + offsetX: (MODAL_WIDTH / 2) - 16, + offsetY: -48, }, profile: { title: "Profile", @@ -117,6 +153,7 @@ export const progressDetails: Record = { url: `/~profile/~${window.ship}`, alignY: "top", alignX: "right", + arrow: "South", offsetX: -300 + MODAL_WIDTH / 2, offsetY: -120 + MODAL_HEIGHT / 2, }, @@ -127,7 +164,8 @@ export const progressDetails: Record = { url: `/~profile/~${window.ship}`, alignY: "top", alignX: "left", - offsetX: 0, - offsetY: -32, + arrow: "North", + offsetX: 0.3 *MODAL_HEIGHT, + offsetY: -48, }, }; diff --git a/pkg/interface/src/types/local-update.ts b/pkg/interface/src/types/local-update.ts index 814832e96..5849931fe 100644 --- a/pkg/interface/src/types/local-update.ts +++ b/pkg/interface/src/types/local-update.ts @@ -1,4 +1,4 @@ -export const tutorialProgress = ['hidden', 'start', 'group-desc', 'channels', 'chat', 'link', 'publish', 'notifications', 'profile', 'leap', 'done'] as const; +export const tutorialProgress = ['hidden', 'start', 'group-desc', 'channels', 'chat', 'link', 'publish', 'profile', 'leap', 'notifications', 'done', 'exit'] as const; export type TutorialProgress = typeof tutorialProgress[number]; interface LocalUpdateSetDark { diff --git a/pkg/interface/src/views/apps/notifications/notifications.tsx b/pkg/interface/src/views/apps/notifications/notifications.tsx index 16f2658b2..42f35862e 100644 --- a/pkg/interface/src/views/apps/notifications/notifications.tsx +++ b/pkg/interface/src/views/apps/notifications/notifications.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from "react"; +import React, { useCallback, useState, useRef } from "react"; import _ from 'lodash'; import { Box, Col, Text, Row } from "@tlon/indigo-react"; import { Link, Switch, Route } from "react-router-dom"; @@ -12,11 +12,13 @@ import { Dropdown } from "~/views/components/Dropdown"; import { Formik } from "formik"; import { FormikOnBlur } from "~/views/components/FormikOnBlur"; import GroupSearch from "~/views/components/GroupSearch"; +import {useTutorialModal} from "~/views/components/useTutorialModal"; const baseUrl = "/~notifications"; -const HeaderLink = ( - props: PropFunc & { view?: string; current: string } +const HeaderLink = React.forwardRef(( + props: PropFunc & { view?: string; current: string }, + ref ) => { const { current, view, ...textProps } = props; const to = view ? `${baseUrl}/${view}` : baseUrl; @@ -24,10 +26,10 @@ const HeaderLink = ( return ( - + ); -}; +}); interface NotificationFilter { groups: string[]; @@ -37,15 +39,17 @@ export default function NotificationsScreen(props: any) { const relativePath = (p: string) => baseUrl + p; const [filter, setFilter] = useState({ groups: [] }); - const onSubmit = async (values: { groups: string }) => { - setFilter({ groups: values.groups ? [values.groups] : [] }); + const onSubmit = async ({ groups } : NotificationFilter) => { + setFilter({ groups }); }; const groupFilterDesc = filter.groups.length === 0 ? "All" : filter.groups .map((g) => props.associations?.groups?.[g]?.metadata?.title) - .join(", "); + .join(", "); + const anchorRef = useRef(null); + useTutorialModal('notifications', true, anchorRef.current); return ( Updates - + Inbox diff --git a/pkg/interface/src/views/apps/profile/components/Profile.tsx b/pkg/interface/src/views/apps/profile/components/Profile.tsx index 0676d7248..53115b973 100644 --- a/pkg/interface/src/views/apps/profile/components/Profile.tsx +++ b/pkg/interface/src/views/apps/profile/components/Profile.tsx @@ -54,13 +54,14 @@ export function Profile(props: any) { height="100%" width="100%"> { ship === `~${window.ship}` ? ( ) : null } - + {cover} ) => { - e.stopPropagation(); + const next = useCallback( () => { const idx = progress.findIndex((p) => p === tutorialProgress); const { url } = progressDetails[progress[idx + 1]]; - history.push(url); nextTutStep(); + history.push(url); }, [nextTutStep, history, tutorialProgress, setCoords] ); const prev = useCallback(() => { const idx = progress.findIndex((p) => p === tutorialProgress); - history.push(progressDetails[progress[idx - 1]].url); prevTutStep(); + history.push(progressDetails[progress[idx - 1]].url); }, [prevTutStep, history, tutorialProgress]); const updatePos = useCallback(() => { @@ -87,14 +92,25 @@ export function TutorialModal(props: { api: GlobalApi }) { if (newCoords) { setCoords(withMobile); + } else { + setCoords({}); + } }, [tutorialRef]); - const dismiss = useCallback(() => { + const dismiss = useCallback(async () => { hideTutorial(); - props.api.settings.putEntry("tutorial", "seen", true); + await props.api.settings.putEntry('tutorial', 'seen', true); }, [hideTutorial, props.api]); + const bailExit = useCallback(() => { + setPaused(false); + }, []); + + const tryExit = useCallback(() => { + setPaused(true); + }, []); + const leaveGroup = useCallback(async () => { await props.api.groups.leaveGroup(TUTORIAL_HOST, TUTORIAL_GROUP); }, [props.api]); @@ -109,27 +125,81 @@ export function TutorialModal(props: { api: GlobalApi }) { ) { const interval = setInterval(updatePos, 100); return () => { + setCoords({}); clearInterval(interval); }; } return () => {}; }, [tutorialRef, tutorialProgress, updatePos]); - // manually center final window - useEffect(() => { - if (tutorialProgress === "done") { - const { innerWidth, innerHeight } = window; - const left = ["0px", `${(innerWidth - MODAL_WIDTH) / 2}px`]; - const top = [null, `${(innerHeight - MODAL_HEIGHT) / 2}px`]; - const bottom = ["0px", null]; - setCoords({ top, left, bottom }); - } - }, [tutorialProgress]); + const triPos = getTrianglePosition(arrow); + + if (tutorialProgress === 'done') { + return ( + + + + + + Tutorial Finished + + + {progressIdx} of {progress.length - 1} + + + + This tutorial is finished. Would you like to leave Beginner Island? + + + + + Leave Group + + + + + + ); + } if (tutorialProgress === "hidden") { return null; } + if(paused) { + return ( + + + + + End Tutorial Now? + + + + You can always restart the tutorial by typing "tutorial" in Leap. + + + + + End Tutorial + + + + + + ) + + } + + + if(Object.keys(coords).length === 0) { + return null; + } + return ( + + - - {title} - + + + {title} + + + {progressIdx} of {progress.length - 2} + + + {description} - {tutorialProgress !== "done" ? ( - - - - - - {progressIdx}/{progress.length - 1} - - - - - - ) : ( - - - Leave Group - - - - )} + + { progressIdx > 1 && ( + + )} + + From 15ac328c1ff969ee45cd100cbd9cf1e0ca6a6a30 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 11 Feb 2021 16:14:17 +1000 Subject: [PATCH 7/8] StatusBar: float leap above on mobile tutorial --- pkg/interface/src/logic/api/settings.ts | 2 +- pkg/interface/src/logic/reducers/group-update.ts | 1 - pkg/interface/src/views/components/StatusBar.js | 6 ++++-- pkg/interface/src/views/components/StatusBarItem.tsx | 8 ++++++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/interface/src/logic/api/settings.ts b/pkg/interface/src/logic/api/settings.ts index 7365c434c..cd0cd736f 100644 --- a/pkg/interface/src/logic/api/settings.ts +++ b/pkg/interface/src/logic/api/settings.ts @@ -32,7 +32,7 @@ export default class SettingsApi extends BaseApi { } putEntry(buc: Key, key: Key, val: Value) { - this.storeAction({ + return this.storeAction({ "put-entry": { "bucket-key": buc, "entry-key": key, diff --git a/pkg/interface/src/logic/reducers/group-update.ts b/pkg/interface/src/logic/reducers/group-update.ts index 8de063f89..169b30d56 100644 --- a/pkg/interface/src/logic/reducers/group-update.ts +++ b/pkg/interface/src/logic/reducers/group-update.ts @@ -41,7 +41,6 @@ function decodePolicy(policy: Enc): GroupPolicy { } function decodeTags(tags: Enc): Tags { - console.log(tags); return _.reduce( tags, (acc, ships, key): Tags => { diff --git a/pkg/interface/src/views/components/StatusBar.js b/pkg/interface/src/views/components/StatusBar.js index ce15d3854..a76259b79 100644 --- a/pkg/interface/src/views/components/StatusBar.js +++ b/pkg/interface/src/views/components/StatusBar.js @@ -47,7 +47,9 @@ const StatusBar = (props) => { const anchorRef = useRef(null); - useTutorialModal('leap', true, anchorRef.current); + const leapHighlight = useTutorialModal('leap', true, anchorRef.current); + + const floatLeap = leapHighlight && window.matchMedia('(max-width: 550px)').matches; return ( { - toggleOmnibox()}> + toggleOmnibox()}> { !props.doNotDisturb && (props.notificationsCount > 0 || invites.length > 0) && ( diff --git a/pkg/interface/src/views/components/StatusBarItem.tsx b/pkg/interface/src/views/components/StatusBarItem.tsx index 49fe634aa..5577b0285 100644 --- a/pkg/interface/src/views/components/StatusBarItem.tsx +++ b/pkg/interface/src/views/components/StatusBarItem.tsx @@ -6,21 +6,25 @@ const Row = styled(_Row)` cursor: pointer; `; -type StatusBarItemProps = Parameters[0] & { badge?: boolean }; +type StatusBarItemProps = Parameters[0] & { badge?: boolean; float?: boolean; }; export function StatusBarItem({ badge, children, + float, ...props }: StatusBarItemProps) { + const floatPos = float ? { zIndex: 10, boxShadow: 'rgba(0,0,0,0.2) 0px 0px 0px 999px' } : {}; return (