Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New tooltips #5805

Merged
merged 25 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dd76921
New tooltips styling
keianhzo Nov 16, 2022
435da8b
Better steps handling
keianhzo Nov 17, 2022
412645b
Animations and refactor
keianhzo Nov 17, 2022
4cf5cf2
refactor
keianhzo Nov 18, 2022
48c8be5
Hiding delay
keianhzo Nov 18, 2022
04128f7
fix linter issues
keianhzo Nov 18, 2022
8afa72a
Mobile support
keianhzo Nov 18, 2022
03fe786
Refactor some code
keianhzo Nov 22, 2022
4f9d776
Refactor tips rendering to not render the component at all if not nec…
keianhzo Nov 22, 2022
29a4733
Fix turning step to accept camera based looking
keianhzo Nov 23, 2022
dad9f1e
Increase tips text font size
keianhzo Nov 23, 2022
ab7e862
Break the invite message
keianhzo Nov 23, 2022
30a2ef2
Revert prettier changes
keianhzo Nov 29, 2022
9788474
Merge branch 'master' into new-tooltips
keianhzo Nov 30, 2022
34e7da8
Hide the notifications container when in UI hide mode
keianhzo Nov 30, 2022
a733f93
Add missing PropTypes
keianhzo Nov 30, 2022
af13155
Fix console prop type error
keianhzo Nov 30, 2022
5ed642a
Improve tooltips visibility after record mode
keianhzo Nov 30, 2022
371cae9
Improve string styling to avoid broken localized string
keianhzo Dec 5, 2022
dde2fb1
Update new localized tooltip string keys
keianhzo Dec 5, 2022
7caeede
Update isStep to only take a string as param
keianhzo Dec 5, 2022
3462621
Rename numStep -> currentStep
keianhzo Dec 5, 2022
7c7a592
Remove leftArrow/rightArrow step params
keianhzo Dec 5, 2022
4e370ba
Remome some stat handling complexity
keianhzo Dec 5, 2022
50dc8bd
Skip tips if there is a tour started or completed for old tips
keianhzo Dec 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/react-components/input/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export const presets = [
"accent5",
"accent6",
"landing",
"signin"
"signin",
"text"
];

/* eslint-disable-next-line react/display-name */
Expand Down
31 changes: 20 additions & 11 deletions src/react-components/input/Button.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@use '../styles/theme';
@use "../styles/theme";

:local(.button) {
height: 48px;
Expand All @@ -23,7 +23,8 @@
}
}

:local(.basic), :local(.transparent) {
:local(.basic),
:local(.transparent) {
color: theme.$text4-color;
border: 2px solid theme.$basic-border-color;
background-color: theme.$basic-color;
Expand Down Expand Up @@ -71,7 +72,7 @@
color: theme.$text5-color;
background-color: theme.$accept-color;
border: 2px solid theme.$accept-border-color;

svg {
color: theme.$text5-color;
}
Expand Down Expand Up @@ -138,7 +139,7 @@
&:hover {
color: theme.$text5-color-hover;
background-color: theme.$accent2-color-hover;
border: 2px solid theme.$accent2-border-color
border: 2px solid theme.$accent2-border-color;
}

&:active {
Expand Down Expand Up @@ -208,7 +209,6 @@
}
}


:local(.accent6) {
color: theme.$text5-color;
background-color: theme.$accent6-color;
Expand Down Expand Up @@ -247,7 +247,8 @@
padding: 0 8px;
}

:local(.lg), :local(.xl) {
:local(.lg),
:local(.xl) {
border-radius: 32px;
padding: 0 48px;
font-size: 16px;
Expand All @@ -274,23 +275,31 @@
}

:local(.signin) {
border: 2px solid #007AB8;
border: 2px solid #007ab8;
background-color: transparent;
color: #007AB8;
color: #007ab8;
box-sizing: border-box;
border-radius: 13px;
}

:local(.landing) {
border: 2px solid #007AB8;
background-color: #007AB8;
border: 2px solid #007ab8;
background-color: #007ab8;
color: theme.$text5-color;
box-sizing: border-box;
border-radius: 13px;
&:hover {
background-color: #008bd1;
}
&:active {
background-color: #00699E;
background-color: #00699e;
}
}

:local(.text) {
border: none;
background-color: theme.$transparent;
color: theme.$primary-color;
padding: 0px;
box-sizing: border-box;
}
2 changes: 1 addition & 1 deletion src/react-components/input/InputField.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const InputField = memo(
InputField.propTypes = {
id: PropTypes.string,
htmlFor: PropTypes.string,
label: PropTypes.string,
label: PropTypes.node,
className: PropTypes.string,
children: PropTypes.node,
error: PropTypes.node,
Expand Down
7 changes: 5 additions & 2 deletions src/react-components/room/NotificationsContainer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
bottom: 8px;
margin-bottom: 8px;

@media(max-width: theme.$breakpoint-md) {
@media (max-width: theme.$breakpoint-md) {
max-width: min(100% - 8px, 320px);
min-width: 320px;
bottom: auto;
height: 100%;
justify-content: flex-end;
}
}
}
6 changes: 3 additions & 3 deletions src/react-components/room/Tip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
color: theme.$tip-text-color;
align-items: center;

@media(min-width: theme.$breakpoint-lg) and (min-height: theme.$breakpoint-vr) {
@media (min-width: theme.$breakpoint-lg) and (min-height: theme.$breakpoint-vr) {
bottom: 24px;
max-width: 360px;
}
}

:local(.content) {
margin: 16px;
font-size: theme.$font-size-sm;
font-size: theme.$font-size-md;
font-weight: theme.$font-weight-bold;
padding: 0 8px;
line-height: 1.25;
Expand All @@ -35,7 +35,7 @@
margin-right: 8px;
margin-bottom: 8px;
min-width: 48px;
font-size: theme.$font-size-xs;
font-size: theme.$font-size-md;
font-weight: theme.$font-weight-bold;
align-self: flex-end;

Expand Down
42 changes: 40 additions & 2 deletions src/react-components/room/Tip.stories.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
import { RoomLayout } from "../layout/RoomLayout";
import { Tip } from "./Tip";
import { Tooltip } from "./Tooltip";
import PropTypes from "prop-types";

export default {
title: "Room/Tip",
Expand All @@ -9,12 +11,48 @@ export default {
}
};

export const Base = () => (
export const Tips = ({ step }) => (
<RoomLayout
viewport={
<Tip onDismiss={() => {}} dismissLabel="Skip">
<Tip onDismiss={() => {}} dismissLabel="Skip" step={step}>
{"Welcome to Mozilla Hubs! Let's take a quick tour. 👋 Click and drag to look around."}
</Tip>
}
/>
);

Tips.propTypes = {
step: PropTypes.string
};

const TOOLTIP_STEPS = {
"tips.desktop.welcome": "Desktop Welcome Message",
"tips.desktop.locomotion": "Desktop Locomotion",
"tips.desktop.turning": "Desktop Turning",
"tips.desktop.invite": "Desktop Invite",
"tips.desktop.end": "Desktop End",
"tips.desktop.menu": "Desktop Menu",
"tips.mobile.welcome": "Mobile Welcome Message",
"tips.mobile.locomotion": "Mobile Locomotion",
"tips.mobile.turning": "Mobile Turning",
"tips.mobile.end": "Mobile End",
"tips.mobile.menu": "Mobile Menu"
};

export const Tooltips = ({ step }) => <RoomLayout viewport={<Tooltip step={step} />} />;

Tooltips.argTypes = {
step: {
name: "Onboarding tips step",
options: Object.keys(TOOLTIP_STEPS),
control: {
type: "select",
labels: TOOLTIP_STEPS
},
defaultValue: Object.keys(TOOLTIP_STEPS)[0]
}
};

Tooltips.propTypes = {
step: PropTypes.string
};
100 changes: 29 additions & 71 deletions src/react-components/room/TipContainer.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,19 @@
import React, { useCallback, useState } from "react";
import React, { useCallback, useRef, useState } from "react";
import PropTypes from "prop-types";
import { FormattedMessage, useIntl, defineMessages } from "react-intl";
import { FormattedMessage } from "react-intl";
import { Tip } from "./Tip";
import { ToastTip } from "./ToastTip";
import { useEffect } from "react";
import { discordBridgesForPresences, hasEmbedPresences } from "../../utils/phoenix-utils";
import configs from "../../utils/configs";

// These keys are hardcoded in the input system to be based on the physical location on the keyboard rather than character
let moveKeys = "W A S D";
let turnLeftKey = "Q";
let turnRightKey = "E";

// TODO The API to map from physical key to character is experimental. Depending on prospects of this getting wider
// implimentation we may want to cook up our own polyfill based on observing key inputs
if (window.navigator.keyboard !== undefined && window.navigator.keyboard.getLayoutMap) {
window.navigator.keyboard
.getLayoutMap()
.then(function (map) {
moveKeys = `${map.get("KeyW") || "W"} ${map.get("KeyA") || "A"} ${map.get("KeyS") || "S"} ${
map.get("KeyD") || "D"
}`.toUpperCase();
turnLeftKey = map.get("KeyQ")?.toUpperCase();
turnRightKey = map.get("KeyE")?.toUpperCase();
})
.catch(function (e) {
// This occurs on Chrome 93 when the Hubs page is in an iframe
console.warn(`Unable to remap keyboard: ${e}`);
});
}
import { Tooltip } from "./Tooltip";

const onboardingMessages = defineMessages({
"tips.mobile.look": {
id: "tips.mobile.look",
defaultMessage: "Welcome! 👋 Tap and drag to look around."
},
"tips.mobile.locomotion": {
id: "tips.mobile.locomotion",
defaultMessage: "Great! To move, pinch with two fingers."
},
"tips.mobile.invite": {
id: "tips.mobile.invite",
defaultMessage: "Use the Invite button in the bottom left to share this room."
},
"tips.desktop.look": {
id: "tips.desktop.look",
defaultMessage: "Welcome to {appName}! Let's take a quick tour. 👋 Click and drag to look around."
},
"tips.desktop.locomotion": {
id: "tips.desktop.locomotion",
defaultMessage: "Use the {moveKeys} keys to move. Hold shift to boost."
},
"tips.desktop.turning": {
id: "tips.desktop.turning",
defaultMessage: "Perfect. Use the {turnLeftKey} and {turnRightKey} keys to rotate."
},
"tips.desktop.invite": {
id: "tips.desktop.invite",
defaultMessage: "Nobody else is here. Use the invite button in the bottom left to share this room."
}
});
const isEndTooltipStep = step =>
["tips.desktop.end", "tips.mobile.end", "tips.desktop.menu", "tips.mobile.menu"].includes(step);

function OkDismissLabel() {
return <FormattedMessage id="tips.dismiss.ok" defaultMessage="Ok" />;
}

function SkipDismissLabel() {
return <FormattedMessage id="tips.dismiss.skip" defaultMessage="Skip" />;
}

export function FullscreenTip(props) {
return (
<Tip {...props} dismissLabel={<OkDismissLabel />}>
Expand All @@ -86,27 +31,49 @@ export function RecordModeTip() {
}

export function TipContainer({ hide, inLobby, inRoom, isStreaming, isEmbedded, scene, store, hubId, presences }) {
const intl = useIntl();
const [lobbyTipDismissed, setLobbyTipDismissed] = useState(false);
const [broadcastTipDismissed, setBroadcastTipDismissed] = useState(() =>
store.state.confirmedBroadcastedRooms.includes(hubId)
);
const [streamingTipDismissed, setStreamingTipDismissed] = useState(false);
const [embeddedTipDismissed, setEmbeddedTipDismissed] = useState(false);
const [onboardingTipId, setOnboardingTipId] = useState(null);
const timeoutRef = useRef(null);

const onSkipOnboarding = useCallback(() => {
scene.systems.tips.skipTips();
}, [scene]);

const onNextTip = useCallback(() => {
scene.systems.tips.nextTip();
}, [scene]);

const onPrevTip = useCallback(() => {
scene.systems.tips.prevTip();
}, [scene]);

useEffect(() => {
if (isEndTooltipStep(onboardingTipId)) {
timeoutRef.current = setTimeout(() => {
scene.systems.tips.nextTip();
keianhzo marked this conversation as resolved.
Show resolved Hide resolved
}, 2500);
keianhzo marked this conversation as resolved.
Show resolved Hide resolved
}
}, [scene, timeoutRef, onboardingTipId]);

useEffect(() => {
function onSceneTipChanged({ detail: tipId }) {
setOnboardingTipId(null);
setOnboardingTipId(tipId);
}

scene.addEventListener("tip-changed", onSceneTipChanged);

setOnboardingTipId(scene.systems.tips.activeTip);

return () => {
scene.removeEventListener("tip-changed", onSceneTipChanged);
clearTimeout(timeoutRef.current);
};
}, [scene]);

const discordBridges = presences ? discordBridgesForPresences(presences) : [];
Expand All @@ -130,16 +97,7 @@ export function TipContainer({ hide, inLobby, inRoom, isStreaming, isEmbedded, s
);
} else if (inRoom) {
if (onboardingTipId) {
return (
<Tip onDismiss={onSkipOnboarding} dismissLabel={<SkipDismissLabel />}>
{intl.formatMessage(onboardingMessages[onboardingTipId], {
appName: configs.translation("app-name"),
moveKeys,
turnLeftKey,
turnRightKey
})}
</Tip>
);
return <Tooltip onPrev={onPrevTip} onNext={onNextTip} onDismiss={onSkipOnboarding} step={onboardingTipId} />;
}

if (isStreaming && !streamingTipDismissed) {
Expand Down
Loading