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;
|
||||
background-image: url("<%= asset_data_uri('newmap_sprite.png') %>");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
background-position: 0 0;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -36px;
|
||||
|
@ -96,7 +96,7 @@
|
|||
|
||||
.mapperList {
|
||||
display: none;
|
||||
padding: 8px;
|
||||
padding: 8px;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
|
@ -117,7 +117,7 @@
|
|||
padding-left: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.mapHasMapper {
|
||||
|
@ -149,7 +149,7 @@
|
|||
&:hover .circle {
|
||||
background-color: #222;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menuItems {
|
||||
position: absolute;
|
||||
|
@ -167,8 +167,8 @@
|
|||
&:hover {
|
||||
background-color: #DDD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mapScreenshot {
|
||||
|
@ -253,6 +253,25 @@
|
|||
float: left;
|
||||
font-family: 'din-medium', sans-serif;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Smartphones (portrait and landscape) ----------- */
|
||||
@media only screen and (max-device-width : 480px) {
|
||||
.upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .uv-icon, .chat-box, #exploreMapsHeader {
|
||||
@media only screen and (max-device-width : 720px) and (min-device-width : 504px) {
|
||||
.sidebarSearch .tt-hint, .sidebarSearch .sidebarSearchField {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#mobile_header {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.homeWrapper {
|
||||
width: 96%;
|
||||
padding: 0 2%;
|
||||
|
@ -38,11 +55,11 @@
|
|||
.learnMoreCTA {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
#yield {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.new_session, .new_user, .edit_user, .login, .forgotPassword {
|
||||
position: relative;
|
||||
top: auto;
|
||||
|
@ -51,11 +68,11 @@
|
|||
padding: 16px 10%;
|
||||
margin: 50px auto 0 auto;
|
||||
}
|
||||
|
||||
|
||||
.centerGreyForm input[type="text"], .centerGreyForm input[type="email"], .centerGreyForm input[type="password"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.wrapper .mapInfoBox {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
|
@ -64,12 +81,12 @@
|
|||
width: 100%;
|
||||
max-width: 360px;
|
||||
}
|
||||
|
||||
|
||||
#wrapper .requestInvite {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
#exploreMaps > div {
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
@ -94,35 +111,73 @@
|
|||
span {
|
||||
vertical-align: middle;
|
||||
padding: 16px;
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.map.newMap:hover .newMapImage {
|
||||
background-position: 0 -40px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Smartphones (portrait) ----------- */
|
||||
@media only screen and (max-width : 400px) {
|
||||
|
||||
.map {
|
||||
width: 100%;
|
||||
margin: 0 0 30px 0;
|
||||
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 {
|
||||
|
|
|
@ -24,17 +24,17 @@ class Menu extends Component {
|
|||
|
||||
render = () => {
|
||||
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'>
|
||||
<div className='menuToggle' onClick={ this.toggle }>
|
||||
<div className='circle'></div>
|
||||
<div className='circle'></div>
|
||||
<div className='circle'></div>
|
||||
</div>
|
||||
</div>
|
||||
<ul className='menuItems' style={ style }>
|
||||
<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> }
|
||||
<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> }
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
@ -43,16 +43,47 @@ Menu.propTypes = {
|
|||
currentUser: PropTypes.object.isRequired,
|
||||
map: PropTypes.object.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 {
|
||||
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 hasConversation = hasMap && find(values(hasMap), v => v === IN_CONVERSATION)
|
||||
const hasConversation = hasMap && find(values(hasMap), v => v === IN_CONVERSATION)
|
||||
const hasMapper = hasMap && !hasConversation
|
||||
const mapperList = hasMap && Object.keys(hasMap).map(id => juntoState.connectedPeople[id])
|
||||
|
||||
|
@ -71,51 +102,41 @@ class MapCard extends Component {
|
|||
|
||||
return (
|
||||
<div className="map" id={ map.id }>
|
||||
<div className={ 'permission ' + editPermission }>
|
||||
<div className='mapCard'>
|
||||
<div className='mainContent'>
|
||||
<div className='mapScreenshot'>
|
||||
<img src={ map.get('screenshot_url') } />
|
||||
</div>
|
||||
<div className='title' title={ map.get('name') }>
|
||||
<div className='innerTitle'>{ truncatedName }</div>
|
||||
</div>
|
||||
<div className='creatorAndPerm'>
|
||||
<img className='creatorImage' src={ map.get('user_image') } />
|
||||
<span className='creatorName'>{ map.get('user_name') }</span>
|
||||
{ !map.authorizeToEdit(currentUser) && <div className='cardViewOnly'>View Only</div> }
|
||||
</div>
|
||||
</div>
|
||||
<a className='mapMetadata' href={ '/maps/' + map.id } data-router="true">
|
||||
<div className="metadataSection numContributors">
|
||||
{ map.get('contributor_count') }<br/>
|
||||
{ map.get('contributor_count') === 1 ? 'contributor' : 'contributors' }
|
||||
</div>
|
||||
<div className="metadataSection numTopics">
|
||||
{ map.get('topic_count') }<br/>
|
||||
{ map.get('topic_count') === 1 ? 'topic' : 'topics' }
|
||||
</div>
|
||||
<div className="metadataSection numStars">
|
||||
{ map.get('star_count') }<br/>
|
||||
{ map.get('star_count') === 1 ? 'star' : 'stars' }
|
||||
</div>
|
||||
<div className="metadataSection numSynapses">
|
||||
{ map.get('synapse_count') }<br/>
|
||||
{ map.get('synapse_count') === 1 ? 'synapse' : 'synapses' }
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
<div className="scroll">
|
||||
<div className="desc">
|
||||
{ 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>
|
||||
{ checkAndWrapInA(mobile, '', map.id,
|
||||
<div className={ 'permission ' + editPermission }>
|
||||
<div className='mapCard'>
|
||||
<div className='mainContent'>
|
||||
{ !mobile && <div className='mapScreenshot'>
|
||||
<img src={ map.get('screenshot_url') } />
|
||||
</div> }
|
||||
<div className='title' title={ map.get('name') }>
|
||||
<div className='innerTitle'>{ truncatedName }</div>
|
||||
</div>
|
||||
{ mobile && hasMapper && <div className='mobileHasMapper'><MapperList mappers={ mapperList } /></div> }
|
||||
{ mobile && hasConversation && <div className='mobileHasConversation'><MapperList mappers={ mapperList } /></div> }
|
||||
{ mobile && d && <div className="desc">{ d }</div> }
|
||||
{ mobile && <div className='mobileMetadata'><Metadata map={ map } /></div> }
|
||||
<div className='creatorAndPerm'>
|
||||
<img className='creatorImage' src={ map.get('user_image') } />
|
||||
<span className='creatorName'>{ map.get('user_name') }</span>
|
||||
{ !map.authorizeToEdit(currentUser) && <div className='cardViewOnly'>View Only</div> }
|
||||
</div>
|
||||
</div>
|
||||
{ !mobile && checkAndWrapInA(true, 'mapMetadata', map.id,
|
||||
<div>
|
||||
<Metadata map={ map } />
|
||||
<div className="scroll">
|
||||
<div className="desc">
|
||||
{ truncatedDesc }
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>) }
|
||||
{ !mobile && hasMapper && <div className='mapHasMapper'><MapperList mappers={ mapperList } /></div> }
|
||||
{ !mobile && hasConversation && <div className='mapHasConversation'><MapperList mappers={ mapperList } /></div> }
|
||||
{ !mobile && currentUser && <Menu currentUser={ currentUser } map={ map } onStar= { onStar } onRequest={ onRequest } /> }
|
||||
</div>
|
||||
</div>) }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -123,6 +144,7 @@ class MapCard extends Component {
|
|||
|
||||
MapCard.propTypes = {
|
||||
map: PropTypes.object.isRequired,
|
||||
mobile: PropTypes.bool.isRequired,
|
||||
juntoState: PropTypes.object,
|
||||
currentUser: PropTypes.object,
|
||||
onStar: PropTypes.func.isRequired,
|
||||
|
|
|
@ -5,6 +5,8 @@ import MapperCard from './MapperCard'
|
|||
import MapCard from './MapCard'
|
||||
|
||||
const MAP_WIDTH = 252
|
||||
const MOBILE_VIEW_BREAKPOINT = 504
|
||||
const MOBILE_VIEW_PADDING = 20
|
||||
const MAX_COLUMNS = 4
|
||||
|
||||
class Maps extends Component {
|
||||
|
@ -28,7 +30,9 @@ class Maps extends Component {
|
|||
const { maps, user, currentUser } = this.props
|
||||
const numCards = maps.length + (user || currentUser ? 1 : 0)
|
||||
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 })
|
||||
}
|
||||
|
||||
|
@ -43,6 +47,7 @@ class Maps extends Component {
|
|||
render = () => {
|
||||
const { maps, currentUser, juntoState, pending, section, user, moreToLoad, loadMore, onStar, onRequest } = this.props
|
||||
const style = { width: this.state.mapsWidth + 'px' }
|
||||
const mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -50,7 +55,7 @@ class Maps extends Component {
|
|||
<div style={ style }>
|
||||
{ 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 }
|
||||
{ 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>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue