redo the mobile menu in react
This commit is contained in:
parent
780217490b
commit
871c491097
9 changed files with 107 additions and 105 deletions
|
@ -1,7 +1,3 @@
|
||||||
#mobile_header {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width : 752px) and (min-width : 504px) {
|
@media only screen and (max-width : 752px) and (min-width : 504px) {
|
||||||
.sidebarSearch .tt-hint, .sidebarSearch .sidebarSearchField {
|
.sidebarSearch .tt-hint, .sidebarSearch .sidebarSearchField {
|
||||||
width: 160px !important;
|
width: 160px !important;
|
||||||
|
@ -51,10 +47,6 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile_header {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.homeWrapper {
|
.homeWrapper {
|
||||||
width: 96%;
|
width: 96%;
|
||||||
padding: 0 2%;
|
padding: 0 2%;
|
||||||
|
@ -116,7 +108,7 @@
|
||||||
#exploreMaps > div {
|
#exploreMaps > div {
|
||||||
margin-top: 70px;
|
margin-top: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapper {
|
.mapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 0 30px 0;
|
margin: 0 0 30px 0;
|
||||||
|
@ -217,6 +209,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#menu_icon {
|
#menu_icon {
|
||||||
|
@ -249,7 +242,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile_menu {
|
#mobile_menu {
|
||||||
display: none;
|
|
||||||
background: #EEE;
|
background: #EEE;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
|
@ -257,6 +249,7 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
box-shadow: 3px 3px 3px rgba(0,0,0,0.23), 3px 3px 3px rgba(0,0,0,0.16);
|
box-shadow: 3px 3px 3px rgba(0,0,0,0.23), 3px 3px 3px rgba(0,0,0,0.16);
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
@ -274,16 +267,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* the mobile menu, even if it's been opened by a user, should
|
|
||||||
* not show up if they resize their browser back to full size
|
|
||||||
*/
|
|
||||||
@media only screen and (max-width : 504px) {
|
|
||||||
#mobile_menu.visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
li.mobileMenuUser {
|
li.mobileMenuUser {
|
||||||
border-bottom: 1px solid #BBB;
|
border-bottom: 1px solid #BBB;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
<div id="mobile_header">
|
|
||||||
<div id="header_content">
|
|
||||||
<%= yield(:mobile_title) %>
|
|
||||||
</div>
|
|
||||||
<div id="menu_icon">
|
|
||||||
<% if user_unread_notification_count > 0 %>
|
|
||||||
<div class="unread-notifications-dot"></div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="mobile_menu">
|
|
||||||
<ul>
|
|
||||||
<% if not current_user %>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Home", root_path %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
<% if current_user %>
|
|
||||||
<li class="mobileMenuUser">
|
|
||||||
<%= image_tag current_user.image.url(:sixtyfour), :size => "32x32" %>
|
|
||||||
<span><%= current_user.name %></span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<%= link_to "New Map", new_map_path %>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<%= link_to "My Maps", explore_mine_path, :data => { :router => 'true'} %>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Shared With Me", explore_shared_path, :data => { :router => 'true'} %>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Starred By Me", explore_starred_path, :data => { :router => 'true'} %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
<li>
|
|
||||||
<%= link_to "All Maps", explore_active_path, :data => { :router => 'true'} %>
|
|
||||||
</li>
|
|
||||||
<% if not current_user %>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Featured Maps", explore_featured_path, :data => { :router => 'true'} %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
<% if not current_user %>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Request Invite", request_path %>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Login", sign_in_path %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
<% if current_user %>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Account", edit_user_url(current_user) %>
|
|
||||||
</li>
|
|
||||||
<li class="notifications">
|
|
||||||
<%= link_to "Notifications", notifications_path %>
|
|
||||||
<% if user_unread_notification_count > 0 %>
|
|
||||||
<div class="unread-notifications-dot"></div>
|
|
||||||
<% end %>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<%= link_to "Sign Out", "/logout", id: "Logout" %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
|
@ -9,7 +9,6 @@
|
||||||
<body class="<%= authenticated? ? "authenticated" : "unauthenticated" %> controller-<%= controller_name %> action-<%= action_name %>">
|
<body class="<%= authenticated? ? "authenticated" : "unauthenticated" %> controller-<%= controller_name %> action-<%= action_name %>">
|
||||||
<%= content_tag :div, class: "main", id: "react-app" do %>
|
<%= content_tag :div, class: "main", id: "react-app" do %>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
<%= render :partial => 'layouts/mobilemenu' %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if devise_error_messages? %>
|
<% if devise_error_messages? %>
|
||||||
<%= devise_error_messages! %>
|
<%= devise_error_messages! %>
|
||||||
|
@ -35,6 +34,9 @@
|
||||||
Metamaps.ServerData.mapIsStarred = <%= @map && current_user.starred_map?(@map) ? true : false %>
|
Metamaps.ServerData.mapIsStarred = <%= @map && current_user.starred_map?(@map) ? true : false %>
|
||||||
</script>
|
</script>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<script type="text/javascript">
|
||||||
|
Metamaps.ServerData.mobileTitle = "<%= yield(:mobile_title) %>"
|
||||||
|
</script>
|
||||||
<div class="hidden"><%= render :partial => 'shared/filterBox' %></div>
|
<div class="hidden"><%= render :partial => 'shared/filterBox' %></div>
|
||||||
<div id="loading"></div>
|
<div id="loading"></div>
|
||||||
<%= render :partial => 'layouts/foot' %>
|
<%= render :partial => 'layouts/foot' %>
|
||||||
|
|
|
@ -30,14 +30,15 @@ const ReactApp = {
|
||||||
unreadNotificationsCount: 0,
|
unreadNotificationsCount: 0,
|
||||||
mapsWidth: 0,
|
mapsWidth: 0,
|
||||||
mobile: false,
|
mobile: false,
|
||||||
|
mobileTitle: '',
|
||||||
|
mobileTitleWidth: 0,
|
||||||
init: function(serverData, openLightbox) {
|
init: function(serverData, openLightbox) {
|
||||||
const self = ReactApp
|
const self = ReactApp
|
||||||
self.unreadNotificationsCount = serverData.unreadNotificationsCount
|
self.unreadNotificationsCount = serverData.unreadNotificationsCount
|
||||||
|
self.mobileTitle = serverData.mobileTitle
|
||||||
self.openLightbox = openLightbox
|
self.openLightbox = openLightbox
|
||||||
routes = makeRoutes()
|
routes = makeRoutes()
|
||||||
self.resize()
|
self.resize()
|
||||||
self.setMobile()
|
|
||||||
self.render()
|
|
||||||
window && window.addEventListener('resize', self.resize)
|
window && window.addEventListener('resize', self.resize)
|
||||||
},
|
},
|
||||||
handleUpdate: function(location) {
|
handleUpdate: function(location) {
|
||||||
|
@ -72,7 +73,10 @@ const ReactApp = {
|
||||||
return merge({
|
return merge({
|
||||||
unreadNotificationsCount: self.unreadNotificationsCount,
|
unreadNotificationsCount: self.unreadNotificationsCount,
|
||||||
currentUser: Active.Mapper,
|
currentUser: Active.Mapper,
|
||||||
mobile: self.mobile
|
mobile: self.mobile,
|
||||||
|
mobileTitle: self.mobileTitle,
|
||||||
|
mobileTitleWidth: self.mobileTitleWidth,
|
||||||
|
mobileTitleClick: (e) => Active.Map && InfoBox.toggleBox(e)
|
||||||
},
|
},
|
||||||
self.getMapProps(),
|
self.getMapProps(),
|
||||||
self.getTopicProps(),
|
self.getTopicProps(),
|
||||||
|
@ -155,11 +159,6 @@ const ReactApp = {
|
||||||
handleInputMessage: ChatView.handleInputMessage
|
handleInputMessage: ChatView.handleInputMessage
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setMobile: function() {
|
|
||||||
const self = ReactApp
|
|
||||||
self.mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
|
||||||
self.render()
|
|
||||||
},
|
|
||||||
resize: function() {
|
resize: function() {
|
||||||
const self = ReactApp
|
const self = ReactApp
|
||||||
const maps = ExploreMaps.collection
|
const maps = ExploreMaps.collection
|
||||||
|
@ -170,7 +169,10 @@ const ReactApp = {
|
||||||
const mapsWidth = document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
const mapsWidth = document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||||
? document.body.clientWidth - MOBILE_VIEW_PADDING
|
? document.body.clientWidth - MOBILE_VIEW_PADDING
|
||||||
: Math.min(MAX_COLUMNS, Math.min(numCards, mapSpaces)) * MAP_WIDTH
|
: Math.min(MAX_COLUMNS, Math.min(numCards, mapSpaces)) * MAP_WIDTH
|
||||||
|
|
||||||
self.mapsWidth = mapsWidth
|
self.mapsWidth = mapsWidth
|
||||||
|
self.mobileTitleWidth = document ? document.body.clientWidth - 70 : 0
|
||||||
|
self.mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||||
self.render()
|
self.render()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ const Listeners = {
|
||||||
if (!(Active.Map || Active.Topic)) return
|
if (!(Active.Map || Active.Topic)) return
|
||||||
|
|
||||||
const onCanvas = e.target.tagName === 'BODY'
|
const onCanvas = e.target.tagName === 'BODY'
|
||||||
|
|
||||||
switch (e.which) {
|
switch (e.which) {
|
||||||
case 13: // if enter key is pressed
|
case 13: // if enter key is pressed
|
||||||
// prevent topic creation if sending a message
|
// prevent topic creation if sending a message
|
||||||
|
@ -141,7 +141,6 @@ const Listeners = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Active.Map && Realtime.inConversation) Realtime.positionVideos()
|
if (Active.Map && Realtime.inConversation) Realtime.positionVideos()
|
||||||
Mobile.resizeTitle()
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
centerAndReveal: function(nodes, opts) {
|
centerAndReveal: function(nodes, opts) {
|
||||||
|
|
|
@ -17,7 +17,6 @@ import Listeners from './Listeners'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import Map, { CheatSheet, InfoBox } from './Map'
|
import Map, { CheatSheet, InfoBox } from './Map'
|
||||||
import Mapper from './Mapper'
|
import Mapper from './Mapper'
|
||||||
import Mobile from './Mobile'
|
|
||||||
import Mouse from './Mouse'
|
import Mouse from './Mouse'
|
||||||
import Organize from './Organize'
|
import Organize from './Organize'
|
||||||
import PasteInput from './PasteInput'
|
import PasteInput from './PasteInput'
|
||||||
|
@ -57,7 +56,6 @@ Metamaps.Map.CheatSheet = CheatSheet
|
||||||
Metamaps.Map.InfoBox = InfoBox
|
Metamaps.Map.InfoBox = InfoBox
|
||||||
Metamaps.Maps = {}
|
Metamaps.Maps = {}
|
||||||
Metamaps.Mapper = Mapper
|
Metamaps.Mapper = Mapper
|
||||||
Metamaps.Mobile = Mobile
|
|
||||||
Metamaps.Mouse = Mouse
|
Metamaps.Mouse = Mouse
|
||||||
Metamaps.Organize = Organize
|
Metamaps.Organize = Organize
|
||||||
Metamaps.PasteInput = PasteInput
|
Metamaps.PasteInput = PasteInput
|
||||||
|
|
66
frontend/src/components/App/MobileHeader.js
Normal file
66
frontend/src/components/App/MobileHeader.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import React, { Component, PropTypes } from 'react'
|
||||||
|
import { Link } from 'react-router'
|
||||||
|
|
||||||
|
class MobileHeader extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
unreadNotificationsCount: PropTypes.number,
|
||||||
|
currentUser: PropTypes.object,
|
||||||
|
mobileTitle: PropTypes.string,
|
||||||
|
mobileTitleWidth: PropTypes.number,
|
||||||
|
onTitleClick: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {open: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle = () => {
|
||||||
|
this.setState({open: !this.state.open})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { unreadNotificationsCount, currentUser, mobileTitle, mobileTitleWidth, onTitleClick } = this.props
|
||||||
|
const { open } = this.state
|
||||||
|
return <div>
|
||||||
|
<div id="mobile_header">
|
||||||
|
<div id="header_content" style={{width: `${mobileTitleWidth}px`}} onClick={onTitleClick}>
|
||||||
|
{mobileTitle}
|
||||||
|
</div>
|
||||||
|
<div id="menu_icon" onClick={this.toggle}>
|
||||||
|
{unreadNotificationsCount > 0 && <div className="unread-notifications-dot"></div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{open && <div id="mobile_menu">
|
||||||
|
{currentUser && <ul onClick={this.toggle}>
|
||||||
|
<li className="mobileMenuUser">
|
||||||
|
<Link to={`/explore/mapper/${currentUser.id}`}>
|
||||||
|
<img src={currentUser.get('image')} width="32" height="32" />
|
||||||
|
<span>{currentUser.get('name')}</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li><a href="/maps/new">New Map</a></li>
|
||||||
|
<li><Link to="/explore/mine">My Maps</Link></li>
|
||||||
|
<li><Link to="/explore/shared">Shared With Me</Link></li>
|
||||||
|
<li><Link to="/explore/starred">Starred By Me</Link></li>
|
||||||
|
<li><Link to="/explore/active">All Maps</Link></li>
|
||||||
|
<li><a href={`/users/${currentUser.id}/edit`}>Account</a></li>
|
||||||
|
<li className="notifications">
|
||||||
|
<a href="/notifications">Notifications</a>
|
||||||
|
{unreadNotificationsCount > 0 && <div className="unread-notifications-dot"></div>}
|
||||||
|
</li>
|
||||||
|
<li><a id="Logout" href="/logout">Sign Out</a></li>
|
||||||
|
</ul>}
|
||||||
|
{!currentUser && <ul onClick={this.toggle}>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
<li><Link to="/explore/active">All Maps</Link></li>
|
||||||
|
<li><Link to="/explore/featured">Featured Maps</Link></li>
|
||||||
|
<li><a href="/request">Request Invite</a></li>
|
||||||
|
<li><a href="/login">Login</a></li>
|
||||||
|
</ul>}
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MobileHeader
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { Component, PropTypes } from 'react'
|
import React, { Component, PropTypes } from 'react'
|
||||||
|
|
||||||
|
import MobileHeader from './MobileHeader'
|
||||||
import Toast from './Toast'
|
import Toast from './Toast'
|
||||||
import UpperLeftUI from './UpperLeftUI'
|
import UpperLeftUI from './UpperLeftUI'
|
||||||
import UpperRightUI from './UpperRightUI'
|
import UpperRightUI from './UpperRightUI'
|
||||||
|
@ -9,7 +10,11 @@ class App extends Component {
|
||||||
children: PropTypes.object,
|
children: PropTypes.object,
|
||||||
toast: PropTypes.string,
|
toast: PropTypes.string,
|
||||||
unreadNotificationsCount: PropTypes.number,
|
unreadNotificationsCount: PropTypes.number,
|
||||||
location: PropTypes.object
|
location: PropTypes.object,
|
||||||
|
mobile: PropTypes.bool,
|
||||||
|
mobileTitle: PropTypes.string,
|
||||||
|
mobileTitleWidth: PropTypes.number,
|
||||||
|
mobileTitleClick: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
static childContextTypes = {
|
static childContextTypes = {
|
||||||
|
@ -23,12 +28,18 @@ class App extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { children, toast, currentUser, unreadNotificationsCount } = this.props
|
const { children, toast, currentUser, unreadNotificationsCount,
|
||||||
|
mobile, mobileTitle, mobileTitleWidth, mobileTitleClick } = this.props
|
||||||
return <div className="wrapper" id="wrapper">
|
return <div className="wrapper" id="wrapper">
|
||||||
|
{mobile && <MobileHeader currentUser={currentUser}
|
||||||
|
unreadNotificationsCount={unreadNotificationsCount}
|
||||||
|
mobileTitle={mobileTitle}
|
||||||
|
mobileTitleWidth={mobileTitleWidth}
|
||||||
|
onTitleClick={mobileTitleClick} />}
|
||||||
<UpperLeftUI currentUser={currentUser} />
|
<UpperLeftUI currentUser={currentUser} />
|
||||||
<UpperRightUI currentUser={currentUser} unreadNotificationsCount={unreadNotificationsCount} />
|
{!mobile && <UpperRightUI currentUser={currentUser} unreadNotificationsCount={unreadNotificationsCount} />}
|
||||||
<Toast message={toast} />
|
<Toast message={toast} />
|
||||||
{currentUser && <a className='feedback-icon' target='_blank' href='https://hylo.com/c/metamaps'></a>}
|
{!mobile && currentUser && <a className='feedback-icon' target='_blank' href='https://hylo.com/c/metamaps'></a>}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,12 @@ import TopicCard from '../TopicCard'
|
||||||
class MapView extends Component {
|
class MapView extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
mobile: PropTypes.bool,
|
||||||
mapId: PropTypes.string,
|
mapId: PropTypes.string,
|
||||||
map: PropTypes.object,
|
map: PropTypes.object,
|
||||||
mapIsStarred: PropTypes.bool,
|
mapIsStarred: PropTypes.bool,
|
||||||
|
onMapStar: PropTypes.func,
|
||||||
|
onMapUnstar: PropTypes.func,
|
||||||
toggleFilterBox: PropTypes.func,
|
toggleFilterBox: PropTypes.func,
|
||||||
filterBoxHtml: PropTypes.string,
|
filterBoxHtml: PropTypes.string,
|
||||||
toggleMapInfoBox: PropTypes.func,
|
toggleMapInfoBox: PropTypes.func,
|
||||||
|
@ -20,6 +23,12 @@ class MapView extends Component {
|
||||||
currentUser: PropTypes.object,
|
currentUser: PropTypes.object,
|
||||||
endActiveMap: PropTypes.func,
|
endActiveMap: PropTypes.func,
|
||||||
launchNewMap: PropTypes.func,
|
launchNewMap: PropTypes.func,
|
||||||
|
openImportLightbox: PropTypes.func,
|
||||||
|
forkMap: PropTypes.func,
|
||||||
|
openHelpLightbox: PropTypes.func,
|
||||||
|
onZoomExtents: PropTypes.func,
|
||||||
|
onZoomIn: PropTypes.func,
|
||||||
|
onZoomOut: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -31,7 +40,6 @@ class MapView extends Component {
|
||||||
|
|
||||||
endMap() {
|
endMap() {
|
||||||
this.setState({
|
this.setState({
|
||||||
filterBoxOpen: false,
|
|
||||||
chatOpen: false
|
chatOpen: false
|
||||||
})
|
})
|
||||||
this.props.endActiveMap()
|
this.props.endActiveMap()
|
||||||
|
|
Loading…
Add table
Reference in a new issue