diff --git a/src/assets/stylesheets/footer.scss b/src/assets/stylesheets/footer.scss index d80edef080344fbdeac63c0e23c31b1b73e6b2c6..8bb69d11631c3a794c13691cc093207096f63a4b 100644 --- a/src/assets/stylesheets/footer.scss +++ b/src/assets/stylesheets/footer.scss @@ -1,39 +1,80 @@ +@import 'shared'; + :local(.container) { position: absolute; width: 100%; - background-color: rgba(0, 0, 0, 0.35); bottom: 0; - display: flex; font-size: 1.3em; - height: 48px; + display: flex; + flex-direction: column; + // Position above virtual gamepad controls on mobile + z-index: 1; + +} +:local(.floatingButton) { + display: flex; + justify-content: center; +} +:local(.header) { + display: flex; + border-bottom: 2px solid #333; + background-color: rgba(0, 0, 0, 0.65); } :local(.hub-info) { flex: 1; margin: 8px; + display: flex; + align-items: center; } :local(.menu) { - margin: 8px; + padding: 5px 0; + background-color: rgba(0, 0, 0, 0.65); + display: flex; + flex-direction: column; + border-top: 3px solid white; +} +:local(.menu-buttons) { + margin: 0 auto; } :local(.menu-button) { + @extend %default-font; + margin: 8px 0; + padding: 0; + display: block; background: none; - border: 3px solid white; - border-radius: 16px; + border: none; color: white; - margin: 0 8px; pointer-events: auto; cursor: pointer; - width: 33px; - height: 33px; + font-size: 0.8em; } :local(.menu-button__icon) { - margin-left: -1px; - margin-bottom: 1px; + background: black; + width: 39px !important; + height: 39px; + border: 3px solid white; + border-radius: 39px; + display: inline-block; + font-size: 1.5em; + vertical-align: sub; + svg { + margin-top: 7px; + margin-left: 0px; + } +} +:local(.menu-button__text) { + margin-left: 16px; } :local(.hub-stats) { - flex: 1; text-align: right; margin: 8px; + display: flex; + align-items: center; + justify-content: flex-end; + @media (min-width: 768px) { + flex: 1; + } } :local(.hub-participant-count) { - margin: 0 8px; + margin: 0 5px; } diff --git a/src/react-components/footer.js b/src/react-components/footer.js index c6d87c757d9a587ce56bc99d5744a648efb77adc..3b852c4b103ee63fb3e2333e98e81db29e475b6a 100644 --- a/src/react-components/footer.js +++ b/src/react-components/footer.js @@ -1,32 +1,90 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; +import MobileDetect from "mobile-detect"; import FontAwesomeIcon from "@fortawesome/react-fontawesome"; +import faUsers from "@fortawesome/fontawesome-free-solid/faUsers"; import faEllipsisH from "@fortawesome/fontawesome-free-solid/faEllipsisH"; import faShareAlt from "@fortawesome/fontawesome-free-solid/faShareAlt"; -import faUsers from "@fortawesome/fontawesome-free-solid/faUsers"; +import faExclamation from "@fortawesome/fontawesome-free-solid/faExclamation"; +import faTimes from "@fortawesome/fontawesome-free-solid/faTimes"; import styles from "../assets/stylesheets/footer.scss"; +const mobiledetect = new MobileDetect(navigator.userAgent); + export default class Footer extends Component { static propTypes = { hubName: PropTypes.string, participantCount: PropTypes.number }; + static defaultProps = { + hubName: "Bobo's Super Test House", + participantCount: 10 + }; + state = { + menuVisible: false + }; render() { + const menuVisible = this.state.menuVisible; return ( <div className={styles.container}> - <div className={styles.hubInfo}> - <span className={styles.hubName}>{this.props.hubName}</span> - </div> - <div className={styles.menu}> - <button className={styles.menuButton}> - <FontAwesomeIcon icon={faEllipsisH} className={styles.menuButtonIcon} /> - </button> - </div> - <div className={styles.hubStats}> - <FontAwesomeIcon icon={faUsers} /> - <span className={styles.hubParticipantCount}>{this.props.participantCount}</span> - </div> + {mobiledetect.mobile() ? ( + <div className={styles.floatingButton}> + <button className={styles.menuButton} onClick={() => this.setState({ menuVisible: !menuVisible })}> + <i className={styles.menuButtonIcon}> + <FontAwesomeIcon icon={menuVisible ? faTimes : faEllipsisH} /> + </i> + </button> + </div> + ) : ( + <div className={styles.header}> + <div className={styles.hubInfo}> + <span className={styles.hubName}>{this.props.hubName}</span> + </div> + <button className={styles.menuButton} onClick={() => this.setState({ menuVisible: !menuVisible })}> + <i className={styles.menuButtonIcon}> + <FontAwesomeIcon icon={menuVisible ? faTimes : faEllipsisH} /> + </i> + </button> + <div className={styles.hubStats}> + <FontAwesomeIcon icon={faUsers} /> + <span className={styles.hubParticipantCount}>{this.props.participantCount}</span> + </div> + </div> + )} + {menuVisible && ( + <div className={styles.menu}> + {mobiledetect.mobile() && ( + <div className={styles.header}> + <div className={styles.hubInfo}> + <span className={styles.hubName}>{this.props.hubName}</span> + </div> + <div className={styles.hubStats}> + <FontAwesomeIcon icon={faUsers} /> + <span className={styles.hubParticipantCount}>{this.props.participantCount}</span> + </div> + </div> + )} + <div className={styles.menuButtons}> + <button className={styles.menuButton}> + <i className={styles.menuButtonIcon}> + <FontAwesomeIcon icon={faShareAlt} /> + </i> + <span className={styles.menuButtonText}> + <strong>Invite</strong> Others + </span> + </button> + <button className={styles.menuButton}> + <i className={styles.menuButtonIcon}> + <FontAwesomeIcon icon={faExclamation} /> + </i> + <span className={styles.menuButtonText}> + <strong>Report</strong> an Issue + </span> + </button> + </div> + </div> + )} </div> ); } diff --git a/webpack.config.js b/webpack.config.js index 3f5bf9001ac96086c8a3b43099b692b8566ce30d..3a70b848d2f763d1ff8b37d8a698fc682f7a54d4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -142,6 +142,7 @@ const config = { options: { name: "[path][name]-[hash].[ext]", minimize: process.env.NODE_ENV === "production", + localIdentName: "[name]__[local]__[hash:base64:5]", camelCase: true } }, @@ -158,6 +159,7 @@ const config = { options: { name: "[path][name]-[hash].[ext]", minimize: process.env.NODE_ENV === "production", + localIdentName: "[name]__[local]__[hash:base64:5]", camelCase: true } }