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

Entry flow UX changes - Part 2 #177

Merged
merged 11 commits into from
Apr 16, 2018
13 changes: 10 additions & 3 deletions src/assets/stylesheets/audio.scss
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
@extend %top-subtitle;
}

&__icon {
&__button-container {
flex: 10;
display: flex;
justify-content: center;
Expand All @@ -114,9 +114,16 @@
height: 111px;
}

&__button {
background: none;
border: none;
cursor: pointer;
}

&__next {
@extend %bottom-button;
margin: auto;
flex: 1 1 20px;
padding-top: 0;
padding-bottom: 0;
flex: 1 1;
}
}
32 changes: 13 additions & 19 deletions src/assets/stylesheets/entry.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,18 @@
justify-content: center;

&__screen-sharing {
font-size: 1.4em;
margin-left: 2.95em;
margin-top: 0.6em;
}
font-size: 1.4em;
margin-left: 2.95em;
margin-top: 0.6em;

&__screen-sharing-checkbox {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
width: 2em;
height: 2em;
border: 3px solid white;
border-radius: 9px;
vertical-align: sub;
margin: 0 0.6em
&__checkbox {
@extend %checkbox;
}
&__checkbox:checked {
@extend %checkbox-checked;
}
}

&__screen-sharing-checkbox:checked {
border: 9px double white;
outline: 9px solid white;
outline-offset: -18px;
}

&__secondary {
width: 100%;
Expand All @@ -58,6 +48,10 @@
margin-top: 10px;
margin-bottom: 10px;
cursor: pointer;
background: none;
color: white;
border: none;
@extend %default-font;

&__icon {
flex: 1 1 90px;
Expand Down
2 changes: 2 additions & 0 deletions src/assets/stylesheets/exited.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.exited-panel {
position: absolute;
color: white;
background-color: black;
width: 100%;
height: 100%;
Expand Down
41 changes: 30 additions & 11 deletions src/assets/stylesheets/profile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
color: $grey-text;
}

&__display-name-label {
font-size: 1.2em;
margin-right: 0.5em;
}
&__form-field-text {
@extend %rounded-border;
@extend %default-font;
Expand All @@ -54,19 +58,34 @@
margin: 0.5em 0;
}

&__form-submit {
@extend %default-font;
border: none;
&__terms {
margin-bottom: 16px;

margin: 8px;
width: 100px;
line-height: 1.5em;
font-size: 1.0em;
&__checkbox {
@extend %checkbox;
vertical-align: unset;
}
&__checkbox:checked {
@extend %checkbox-checked;
}

background-color: transparent;
font-weight: bold;
color: white;
cursor: pointer;
&__text {
display: inline-block;
max-width: 20em;
}

&__link {
color: white;
}

&__link:visited {
color: grey;
}
}

&__form-submit {
@extend %bottom-button;
margin: 0;
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/assets/stylesheets/shared.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@ $darker-grey: rgba(64, 64, 64, 1.0);
}

%bottom-button {
@extend %default-font;
font-size: 1em;
font-weight: bold;
margin-top: auto;
margin-bottom: 30px;
cursor: pointer;
border: 3px solid white;
border-radius: 14px;
padding: 12px;
background: none;
color: white;
}

%top-title {
Expand All @@ -42,3 +48,21 @@ $darker-grey: rgba(64, 64, 64, 1.0);
border: none;
font-size: 64pt;
}

%checkbox {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
width: 2em;
height: 2em;
border: 3px solid white;
border-radius: 9px;
vertical-align: sub;
margin: 0 0.6em
}

%checkbox-checked {
border: 9px double white;
outline: 9px solid white;
outline-offset: -18px;
}
7 changes: 6 additions & 1 deletion src/assets/translations.data.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@
"entry.daydream-via-chrome": "Using Google Chrome",
"entry.enable-screen-sharing": "Share my desktop",
"profile.save": "SAVE",
"profile.display_name.label": "Display name:",
"profile.display_name.validation_warning": "Alphanumerics and hyphens. At least 3 characters, no more than 32",
"profile.header": "Your identity",
"profile.terms.prefix": "I confirm that I am over the age of 13 and agree to the",
"profile.terms.privacy": "privacy policy",
"profile.terms.conjunction": "and",
"profile.terms.tou": "terms of use",
"profile.terms.suffix": ".",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gfodor Terms copy needs your review.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we can send this to legal once they get things wrapped up

"profile.avatar-selector.loading": "Loading Avatars...",
"audio.title": "Test your audio",
"audio.subtitle-desktop": "Confirm HMD speaker output",
Expand All @@ -26,7 +32,6 @@
"audio.grant-subtitle": "Mic access needed to be heard by others",
"audio.granted-title": "Mic permissions granted",
"audio.granted-subtitle": "You can still mute yourself in-game",
"audio.grant-next": " ",
"audio.granted-next": "NEXT",
"exit.subtitle": "Your session has ended.",
"autoexit.title": "Auto-ending session in ",
Expand Down
5 changes: 3 additions & 2 deletions src/hub.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

<head>
<meta charset="utf-8">
<title>moz://a duck</title>

<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="origin-trial" data-feature="WebVR (For Chrome M62+)" data-expires="<%= ORIGIN_TRIAL_EXPIRES %>" content="<%= ORIGIN_TRIAL_TOKEN %>">
<title>moz://a duck</title>
<link href="https://fonts.googleapis.com/css?family=Zilla+Slab:300,300i,400,400i,700" rel="stylesheet">

<% if(NODE_ENV === "production") { %>
<script src="https://cdn.rawgit.com/brianpeiris/aframe/845825ae694449524c185c44a314d361eead4680/dist/aframe-master.min.js"></script>
<% } else { %>
Expand Down
29 changes: 15 additions & 14 deletions src/hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,14 @@ async function enterScene(mediaStream, enterInVR, janusRoomId) {
}
}

function mountUI(scene) {
function mountUI(scene, props = {}) {
const disableAutoExitOnConcurrentLoad = qsTruthy("allow_multi");
const forcedVREntryType = qs.vr_entry_type || null;
const enableScreenSharing = qsTruthy("enable_screen_sharing");
const htmlPrefix = document.body.dataset.htmlPrefix || "";
const showProfileEntry = !store.state.profile.has_changed_name;

// TODO: Refactor to avoid using return value
/* eslint-disable react/no-render-return-value */
const uiRoot = ReactDOM.render(
ReactDOM.render(
<UIRoot
{...{
scene,
Expand All @@ -247,14 +245,12 @@ function mountUI(scene) {
enableScreenSharing,
store,
htmlPrefix,
showProfileEntry
showProfileEntry,
...props
}}
/>,
document.getElementById("ui-root")
);
/* eslint-enable react/no-render-return-value */

return uiRoot;
}

const onReady = async () => {
Expand All @@ -264,26 +260,31 @@ const onReady = async () => {

registerNetworkSchemas();

const uiRoot = mountUI(scene);
mountUI(scene);

let modifiedProps = {};
const remountUI = props => {
modifiedProps = { ...modifiedProps, ...props };
mountUI(scene, modifiedProps);
};

getAvailableVREntryTypes().then(availableVREntryTypes => {
uiRoot.setState({ availableVREntryTypes });
uiRoot.handleForcedVREntryType();
remountUI({ availableVREntryTypes });
});

const environmentRoot = document.querySelector("#environment-root");

const initialEnvironmentEl = document.createElement("a-entity");
initialEnvironmentEl.addEventListener("bundleloaded", () => {
uiRoot.setState({ initialEnvironmentLoaded: true });
remountUI({ initialEnvironmentLoaded: true });
// Wait a tick plus some margin so that the environments actually render.
setTimeout(() => scene.renderer.animate(null), 100);
});
environmentRoot.appendChild(initialEnvironmentEl);

if (qs.room) {
// If ?room is set, this is `yarn start`, so just use a default environment and query string room.
uiRoot.setState({ janusRoomId: qs.room && !isNaN(parseInt(qs.room)) ? parseInt(qs.room) : 1 });
remountUI({ janusRoomId: qs.room && !isNaN(parseInt(qs.room)) ? parseInt(qs.room) : 1 });
initialEnvironmentEl.setAttribute("gltf-bundle", {
src: "https://asset-bundles-prod.reticulum.io/rooms/meetingroom/MeetingRoom.bundle.json"
// src: "https://asset-bundles-prod.reticulum.io/rooms/theater/TheaterMeshes.bundle.json"
Expand Down Expand Up @@ -314,7 +315,7 @@ const onReady = async () => {
const hub = data.hubs[0];
const defaultSpaceTopic = hub.topics[0];
const gltfBundleUrl = defaultSpaceTopic.assets.find(a => a.asset_type === "gltf_bundle").src;
uiRoot.setState({ janusRoomId: defaultSpaceTopic.janus_room_id });
remountUI({ janusRoomId: defaultSpaceTopic.janus_room_id });
initialEnvironmentEl.setAttribute("gltf-bundle", `src: ${gltfBundleUrl}`);
hubChannel.setPhoenixChannel(channel);
})
Expand Down
4 changes: 2 additions & 2 deletions src/react-components/entry-buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import DaydreamEntyImg from "../assets/images/daydream_entry.svg";
const mobiledetect = new MobileDetect(navigator.userAgent);

const EntryButton = props => (
<div className="entry-button" onClick={props.onClick}>
<button className="entry-button" onClick={props.onClick}>
<img src={props.iconSrc} className="entry-button__icon" />
<div className="entry-button__label">
<div className="entry-button__label__contents">
Expand All @@ -25,7 +25,7 @@ const EntryButton = props => (
{props.subtitle && <div className="entry-button__subtitle">{props.subtitle}</div>}
</div>
</div>
</div>
</button>
);

EntryButton.propTypes = {
Expand Down
48 changes: 39 additions & 9 deletions src/react-components/profile-entry-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ class ProfileEntryPanel extends Component {

saveStateAndFinish = e => {
e.preventDefault();
const has_agreed_to_terms = this.props.store.state.profile.has_agreed_to_terms || this.state.has_agreed_to_terms;
if (!has_agreed_to_terms) return;
const { has_changed_name, display_name } = this.props.store.state.profile;
const hasChangedName = has_changed_name || this.state.display_name !== display_name;
this.props.store.update({
profile: {
has_agreed_to_terms: true,
has_changed_name: hasChangedName,
...this.state
}
Expand Down Expand Up @@ -74,20 +77,47 @@ class ProfileEntryPanel extends Component {
<div className="profile-entry__subtitle">
<FormattedMessage id="profile.header" />
</div>
<input
className="profile-entry__form-field-text"
value={this.state.display_name}
onChange={e => this.setState({ display_name: e.target.value })}
required
pattern={SCHEMA.definitions.profile.properties.display_name.pattern}
title={formatMessage({ id: "profile.display_name.validation_warning" })}
ref={inp => (this.nameInput = inp)}
/>
<label>
<span className="profile-entry__display-name-label">
<FormattedMessage id="profile.display_name.label" />
</span>
<input
className="profile-entry__form-field-text"
value={this.state.display_name}
onChange={e => this.setState({ display_name: e.target.value })}
required
pattern={SCHEMA.definitions.profile.properties.display_name.pattern}
title={formatMessage({ id: "profile.display_name.validation_warning" })}
ref={inp => (this.nameInput = inp)}
/>
</label>
<iframe
className="profile-entry__avatar-selector"
src={`/${this.props.htmlPrefix}avatar-selector.html#avatar_id=${this.state.avatar_id}`}
ref={ifr => (this.avatarSelector = ifr)}
/>
{!this.props.store.state.profile.has_agreed_to_terms && (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gfodor does it make sense to hide the term checkbox after the user has agreed to it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think so

<label className="profile-entry__terms">
<input
className="profile-entry__terms__checkbox"
type="checkbox"
required
value={this.state.has_agreed_to_terms}
onChange={e => this.setState({ has_agreed_to_terms: e.target.checked })}
/>
<span className="profile-entry__terms__text">
<FormattedMessage id="profile.terms.prefix" />{" "}
<a className="profile-entry__terms__link" target="_blank" href="/privacy">
<FormattedMessage id="profile.terms.privacy" />
</a>{" "}
<FormattedMessage id="profile.terms.conjunction" />{" "}
<a className="profile-entry__terms__link" target="_blank" href="/terms">
<FormattedMessage id="profile.terms.tou" />
</a>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gfodor Linking to non-existent /privacy and /terms urls for now.

<FormattedMessage id="profile.terms.suffix" />
</span>
</label>
)}
<input className="profile-entry__form-submit" type="submit" value={formatMessage({ id: "profile.save" })} />
</div>
</form>
Expand Down
Loading