make it responsive (#820)
This commit is contained in:
parent
a44edbb17e
commit
cda0c21a0b
5 changed files with 190 additions and 89 deletions
BIN
app/assets/images/metadata.png
Normal file
BIN
app/assets/images/metadata.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -36,7 +36,7 @@
|
||||||
height: 72px;
|
height: 72px;
|
||||||
background-image: url("<%= asset_data_uri('newmap_sprite.png') %>");
|
background-image: url("<%= asset_data_uri('newmap_sprite.png') %>");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -36px;
|
margin-left: -36px;
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
|
|
||||||
.mapperList {
|
.mapperList {
|
||||||
display: none;
|
display: none;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mapHasMapper {
|
.mapHasMapper {
|
||||||
|
@ -149,7 +149,7 @@
|
||||||
&:hover .circle {
|
&:hover .circle {
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuItems {
|
.menuItems {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -167,8 +167,8 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #DDD;
|
background-color: #DDD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapScreenshot {
|
.mapScreenshot {
|
||||||
|
@ -253,6 +253,25 @@
|
||||||
float: left;
|
float: left;
|
||||||
font-family: 'din-medium', sans-serif;
|
font-family: 'din-medium', sans-serif;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
div {
|
||||||
|
background: url('<%= asset_path('metadata.png') %>') no-repeat;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.numTopicsIcon {
|
||||||
|
background-position: 0 -32px;
|
||||||
|
}
|
||||||
|
.numStarsIcon {
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
.numSynapsesIcon {
|
||||||
|
background-position: -32px -32px;
|
||||||
|
}
|
||||||
|
.numContributorsIcon {
|
||||||
|
background-position: -32px 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,33 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Smartphones (portrait and landscape) ----------- */
|
@media only screen and (max-device-width : 720px) and (min-device-width : 504px) {
|
||||||
@media only screen and (max-device-width : 480px) {
|
.sidebarSearch .tt-hint, .sidebarSearch .sidebarSearchField {
|
||||||
.upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .uv-icon, .chat-box, #exploreMapsHeader {
|
width: 160px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-device-width : 390px) {
|
||||||
|
.map .mapCard .mobileMetadata {
|
||||||
|
width: 190px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (min-device-width : 390px) {
|
||||||
|
.map .mapCard .mobileMetadata {
|
||||||
|
width: 390px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smartphones (portrait and landscape) ----------- the minimum space that two map cards can fit side by side */
|
||||||
|
@media only screen and (max-device-width : 504px) {
|
||||||
|
.upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .feedback-icon, .chat-box, #exploreMapsHeader {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile_header {
|
#mobile_header {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.homeWrapper {
|
.homeWrapper {
|
||||||
width: 96%;
|
width: 96%;
|
||||||
padding: 0 2%;
|
padding: 0 2%;
|
||||||
|
@ -38,11 +55,11 @@
|
||||||
.learnMoreCTA {
|
.learnMoreCTA {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#yield {
|
#yield {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new_session, .new_user, .edit_user, .login, .forgotPassword {
|
.new_session, .new_user, .edit_user, .login, .forgotPassword {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: auto;
|
top: auto;
|
||||||
|
@ -51,11 +68,11 @@
|
||||||
padding: 16px 10%;
|
padding: 16px 10%;
|
||||||
margin: 50px auto 0 auto;
|
margin: 50px auto 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.centerGreyForm input[type="text"], .centerGreyForm input[type="email"], .centerGreyForm input[type="password"] {
|
.centerGreyForm input[type="text"], .centerGreyForm input[type="email"], .centerGreyForm input[type="password"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper .mapInfoBox {
|
.wrapper .mapInfoBox {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
|
@ -64,12 +81,12 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 360px;
|
max-width: 360px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wrapper .requestInvite {
|
#wrapper .requestInvite {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#exploreMaps > div {
|
#exploreMaps > div {
|
||||||
margin-top: 70px;
|
margin-top: 70px;
|
||||||
}
|
}
|
||||||
|
@ -94,35 +111,73 @@
|
||||||
span {
|
span {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map.newMap:hover .newMapImage {
|
.map.newMap:hover .newMapImage {
|
||||||
background-position: 0 -40px;
|
background-position: 0 -40px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Smartphones (portrait) ----------- */
|
|
||||||
@media only screen and (max-width : 400px) {
|
|
||||||
|
|
||||||
.map {
|
.map {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 0 30px 0;
|
margin: 0 0 30px 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
|
||||||
|
|
||||||
.mapCard {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapCard .title {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapCard .mapScreenshot {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.mapCard {
|
||||||
|
height: auto;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.mainContent {
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mobileHasMapper, .mobileHasConversation {
|
||||||
|
.mapperList {
|
||||||
|
padding: 8px 16px;
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
&.live {
|
||||||
|
height: 32px;
|
||||||
|
padding-left: 32px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
padding-left: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mobileHasMapper {
|
||||||
|
background: url('<%= asset_path('junto.png') %>') no-repeat 12px 0;
|
||||||
|
}
|
||||||
|
.mobileHasConversation {
|
||||||
|
background: url('<%= asset_path('junto.gif') %>') no-repeat 12px 0;
|
||||||
|
}
|
||||||
|
.mobileMetadata {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
text-align: left;
|
||||||
|
display: block;
|
||||||
|
height: auto;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile_header {
|
#mobile_header {
|
||||||
|
|
|
@ -24,17 +24,17 @@ class Menu extends Component {
|
||||||
|
|
||||||
render = () => {
|
render = () => {
|
||||||
const { currentUser, map, onStar, onRequest } = this.props
|
const { currentUser, map, onStar, onRequest } = this.props
|
||||||
const style = { display: this.state.open ? 'block' : 'none' }
|
const style = { display: this.state.open ? 'block' : 'none' }
|
||||||
|
|
||||||
return <div className='dropdownMenu'>
|
return <div className='dropdownMenu'>
|
||||||
<div className='menuToggle' onClick={ this.toggle }>
|
<div className='menuToggle' onClick={ this.toggle }>
|
||||||
<div className='circle'></div>
|
<div className='circle'></div>
|
||||||
<div className='circle'></div>
|
<div className='circle'></div>
|
||||||
<div className='circle'></div>
|
<div className='circle'></div>
|
||||||
</div>
|
</div>
|
||||||
<ul className='menuItems' style={ style }>
|
<ul className='menuItems' style={ style }>
|
||||||
<li className='star' onClick={ () => { this.toggle() && onStar(map) }}>Star Map</li>
|
<li className='star' onClick={ () => { this.toggle() && onStar(map) }}>Star Map</li>
|
||||||
{ !map.authorizeToEdit(currentUser) && <li className='request' onClick={ () => { this.toggle() && onRequest(map) }}>Request Access</li> }
|
{ !map.authorizeToEdit(currentUser) && <li className='request' onClick={ () => { this.toggle() && onRequest(map) }}>Request Access</li> }
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -43,16 +43,47 @@ Menu.propTypes = {
|
||||||
currentUser: PropTypes.object.isRequired,
|
currentUser: PropTypes.object.isRequired,
|
||||||
map: PropTypes.object.isRequired,
|
map: PropTypes.object.isRequired,
|
||||||
onStar: PropTypes.func.isRequired,
|
onStar: PropTypes.func.isRequired,
|
||||||
onRequest: PropTypes.func.isRequired
|
onRequest: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Metadata = (props) => {
|
||||||
|
const { map } = props
|
||||||
|
return (<div>
|
||||||
|
<div className="metadataSection numTopics">
|
||||||
|
<div className="numTopicsIcon"></div>
|
||||||
|
{ map.get('topic_count') }<br/>
|
||||||
|
{ map.get('topic_count') === 1 ? 'topic' : 'topics' }
|
||||||
|
</div>
|
||||||
|
<div className="metadataSection numStars">
|
||||||
|
<div className="numStarsIcon"></div>
|
||||||
|
{ map.get('star_count') }<br/>
|
||||||
|
{ map.get('star_count') === 1 ? 'star' : 'stars' }
|
||||||
|
</div>
|
||||||
|
<div className="metadataSection numSynapses">
|
||||||
|
<div className="numSynapsesIcon"></div>
|
||||||
|
{ map.get('synapse_count') }<br/>
|
||||||
|
{ map.get('synapse_count') === 1 ? 'synapse' : 'synapses' }
|
||||||
|
</div>
|
||||||
|
<div className="metadataSection numContributors">
|
||||||
|
<div className="numContributorsIcon"></div>
|
||||||
|
{ map.get('contributor_count') }<br/>
|
||||||
|
{ map.get('contributor_count') === 1 ? 'contributor' : 'contributors' }
|
||||||
|
</div>
|
||||||
|
<div className="clearfloat"></div>
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkAndWrapInA = (shouldWrap, classString, mapId, element) => {
|
||||||
|
if (shouldWrap) return <a className={ classString } href={ `/maps/${mapId}` } data-router="true">{ element }</a>
|
||||||
|
else return element
|
||||||
|
}
|
||||||
|
|
||||||
class MapCard extends Component {
|
class MapCard extends Component {
|
||||||
render = () => {
|
render = () => {
|
||||||
const { map, juntoState, currentUser, onRequest, onStar } = this.props
|
const { map, mobile, juntoState, currentUser, onRequest, onStar } = this.props
|
||||||
|
|
||||||
const hasMap = juntoState.liveMaps[map.id]
|
const hasMap = juntoState.liveMaps[map.id]
|
||||||
const hasConversation = hasMap && find(values(hasMap), v => v === IN_CONVERSATION)
|
const hasConversation = hasMap && find(values(hasMap), v => v === IN_CONVERSATION)
|
||||||
const hasMapper = hasMap && !hasConversation
|
const hasMapper = hasMap && !hasConversation
|
||||||
const mapperList = hasMap && Object.keys(hasMap).map(id => juntoState.connectedPeople[id])
|
const mapperList = hasMap && Object.keys(hasMap).map(id => juntoState.connectedPeople[id])
|
||||||
|
|
||||||
|
@ -71,51 +102,41 @@ class MapCard extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="map" id={ map.id }>
|
<div className="map" id={ map.id }>
|
||||||
<div className={ 'permission ' + editPermission }>
|
{ checkAndWrapInA(mobile, '', map.id,
|
||||||
<div className='mapCard'>
|
<div className={ 'permission ' + editPermission }>
|
||||||
<div className='mainContent'>
|
<div className='mapCard'>
|
||||||
<div className='mapScreenshot'>
|
<div className='mainContent'>
|
||||||
<img src={ map.get('screenshot_url') } />
|
{ !mobile && <div className='mapScreenshot'>
|
||||||
</div>
|
<img src={ map.get('screenshot_url') } />
|
||||||
<div className='title' title={ map.get('name') }>
|
</div> }
|
||||||
<div className='innerTitle'>{ truncatedName }</div>
|
<div className='title' title={ map.get('name') }>
|
||||||
</div>
|
<div className='innerTitle'>{ truncatedName }</div>
|
||||||
<div className='creatorAndPerm'>
|
</div>
|
||||||
<img className='creatorImage' src={ map.get('user_image') } />
|
{ mobile && hasMapper && <div className='mobileHasMapper'><MapperList mappers={ mapperList } /></div> }
|
||||||
<span className='creatorName'>{ map.get('user_name') }</span>
|
{ mobile && hasConversation && <div className='mobileHasConversation'><MapperList mappers={ mapperList } /></div> }
|
||||||
{ !map.authorizeToEdit(currentUser) && <div className='cardViewOnly'>View Only</div> }
|
{ mobile && d && <div className="desc">{ d }</div> }
|
||||||
</div>
|
{ mobile && <div className='mobileMetadata'><Metadata map={ map } /></div> }
|
||||||
</div>
|
<div className='creatorAndPerm'>
|
||||||
<a className='mapMetadata' href={ '/maps/' + map.id } data-router="true">
|
<img className='creatorImage' src={ map.get('user_image') } />
|
||||||
<div className="metadataSection numContributors">
|
<span className='creatorName'>{ map.get('user_name') }</span>
|
||||||
{ map.get('contributor_count') }<br/>
|
{ !map.authorizeToEdit(currentUser) && <div className='cardViewOnly'>View Only</div> }
|
||||||
{ map.get('contributor_count') === 1 ? 'contributor' : 'contributors' }
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="metadataSection numTopics">
|
{ !mobile && checkAndWrapInA(true, 'mapMetadata', map.id,
|
||||||
{ map.get('topic_count') }<br/>
|
<div>
|
||||||
{ map.get('topic_count') === 1 ? 'topic' : 'topics' }
|
<Metadata map={ map } />
|
||||||
</div>
|
<div className="scroll">
|
||||||
<div className="metadataSection numStars">
|
<div className="desc">
|
||||||
{ map.get('star_count') }<br/>
|
{ truncatedDesc }
|
||||||
{ map.get('star_count') === 1 ? 'star' : 'stars' }
|
<div className="clearfloat"></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="metadataSection numSynapses">
|
</div>
|
||||||
{ map.get('synapse_count') }<br/>
|
</div>) }
|
||||||
{ map.get('synapse_count') === 1 ? 'synapse' : 'synapses' }
|
{ !mobile && hasMapper && <div className='mapHasMapper'><MapperList mappers={ mapperList } /></div> }
|
||||||
</div>
|
{ !mobile && hasConversation && <div className='mapHasConversation'><MapperList mappers={ mapperList } /></div> }
|
||||||
<div className="clearfloat"></div>
|
{ !mobile && currentUser && <Menu currentUser={ currentUser } map={ map } onStar= { onStar } onRequest={ onRequest } /> }
|
||||||
<div className="scroll">
|
</div>
|
||||||
<div className="desc">
|
</div>) }
|
||||||
{ truncatedDesc }
|
|
||||||
<div className="clearfloat"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{ hasMapper && <div className='mapHasMapper'><MapperList mappers={ mapperList } /></div> }
|
|
||||||
{ hasConversation && <div className='mapHasConversation'><MapperList mappers={ mapperList } /></div> }
|
|
||||||
{ currentUser && <Menu currentUser={ currentUser } map={ map } onStar= { onStar } onRequest={ onRequest } /> }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -123,6 +144,7 @@ class MapCard extends Component {
|
||||||
|
|
||||||
MapCard.propTypes = {
|
MapCard.propTypes = {
|
||||||
map: PropTypes.object.isRequired,
|
map: PropTypes.object.isRequired,
|
||||||
|
mobile: PropTypes.bool.isRequired,
|
||||||
juntoState: PropTypes.object,
|
juntoState: PropTypes.object,
|
||||||
currentUser: PropTypes.object,
|
currentUser: PropTypes.object,
|
||||||
onStar: PropTypes.func.isRequired,
|
onStar: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -5,6 +5,8 @@ import MapperCard from './MapperCard'
|
||||||
import MapCard from './MapCard'
|
import MapCard from './MapCard'
|
||||||
|
|
||||||
const MAP_WIDTH = 252
|
const MAP_WIDTH = 252
|
||||||
|
const MOBILE_VIEW_BREAKPOINT = 504
|
||||||
|
const MOBILE_VIEW_PADDING = 20
|
||||||
const MAX_COLUMNS = 4
|
const MAX_COLUMNS = 4
|
||||||
|
|
||||||
class Maps extends Component {
|
class Maps extends Component {
|
||||||
|
@ -28,7 +30,9 @@ class Maps extends Component {
|
||||||
const { maps, user, currentUser } = this.props
|
const { maps, user, currentUser } = this.props
|
||||||
const numCards = maps.length + (user || currentUser ? 1 : 0)
|
const numCards = maps.length + (user || currentUser ? 1 : 0)
|
||||||
const mapSpaces = Math.floor(document.body.clientWidth / MAP_WIDTH)
|
const mapSpaces = Math.floor(document.body.clientWidth / MAP_WIDTH)
|
||||||
const mapsWidth = Math.min(MAX_COLUMNS, Math.min(numCards, mapSpaces)) * MAP_WIDTH
|
const mapsWidth = document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT ?
|
||||||
|
document.body.clientWidth - MOBILE_VIEW_PADDING :
|
||||||
|
Math.min(MAX_COLUMNS, Math.min(numCards, mapSpaces)) * MAP_WIDTH
|
||||||
this.setState({ mapsWidth })
|
this.setState({ mapsWidth })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +47,7 @@ class Maps extends Component {
|
||||||
render = () => {
|
render = () => {
|
||||||
const { maps, currentUser, juntoState, pending, section, user, moreToLoad, loadMore, onStar, onRequest } = this.props
|
const { maps, currentUser, juntoState, pending, section, user, moreToLoad, loadMore, onStar, onRequest } = this.props
|
||||||
const style = { width: this.state.mapsWidth + 'px' }
|
const style = { width: this.state.mapsWidth + 'px' }
|
||||||
|
const mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -50,7 +55,7 @@ class Maps extends Component {
|
||||||
<div style={ style }>
|
<div style={ style }>
|
||||||
{ user ? <MapperCard user={ user } /> : null }
|
{ user ? <MapperCard user={ user } /> : null }
|
||||||
{ currentUser && !user && !(pending && maps.length === 0) ? <div className="map newMap"><a href="/maps/new"><div className="newMapImage"></div><span>Create new map...</span></a></div> : null }
|
{ currentUser && !user && !(pending && maps.length === 0) ? <div className="map newMap"><a href="/maps/new"><div className="newMapImage"></div><span>Create new map...</span></a></div> : null }
|
||||||
{ maps.models.map(map => <MapCard key={ map.id } map={ map } juntoState={ juntoState } currentUser={ currentUser } onStar={ onStar } onRequest={ onRequest } />) }
|
{ maps.models.map(map => <MapCard key={ map.id } map={ map } mobile={ mobile } juntoState={ juntoState } currentUser={ currentUser } onStar={ onStar } onRequest={ onRequest } />) }
|
||||||
<div className='clearfloat'></div>
|
<div className='clearfloat'></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue