Redo all of explore together in React (#617)
* unify explore in react * no more need for manual scroll reseting * we're not opening/closing the search anymore
This commit is contained in:
parent
c89a6771ea
commit
d7759c8c07
15 changed files with 268 additions and 275 deletions
|
@ -43,5 +43,4 @@
|
|||
//= require ./src/Metamaps.Mobile
|
||||
//= require ./src/Metamaps.Admin
|
||||
//= require ./src/Metamaps.Import
|
||||
//= require ./src/Metamaps.Header
|
||||
//= require ./src/Metamaps.JIT
|
||||
|
|
|
@ -121,36 +121,6 @@ Metamaps.Backbone.Map = Backbone.Model.extend({
|
|||
}
|
||||
return this.get('mappers')
|
||||
},
|
||||
attrForCards: function () {
|
||||
function capitalize (string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||
}
|
||||
|
||||
var n = this.get('name')
|
||||
var d = this.get('desc')
|
||||
|
||||
var maxNameLength = 32
|
||||
var maxDescLength = 118
|
||||
var truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + '...' : n) : ''
|
||||
var truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + '...' : d) : ''
|
||||
|
||||
var obj = {
|
||||
id: this.id,
|
||||
name: truncatedName,
|
||||
fullName: n,
|
||||
desc: truncatedDesc,
|
||||
permission: this.get('permission') ? capitalize(this.get('permission')) : 'Commons',
|
||||
editPermission: this.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEdit' : 'cannotEdit',
|
||||
contributor_count_number: '<span class="cCountColor">' + this.get('contributor_count') + '</span>',
|
||||
contributor_count_string: this.get('contributor_count') === 1 ? ' contributor' : ' contributors',
|
||||
topic_count_number: '<span class="tCountColor">' + this.get('topic_count') + '</span>',
|
||||
topic_count_string: this.get('topic_count') === 1 ? ' topic' : ' topics',
|
||||
synapse_count_number: '<span class="sCountColor">' + this.get('synapse_count') + '</span>',
|
||||
synapse_count_string: this.get('synapse_count') === 1 ? ' synapse' : ' synapses',
|
||||
screenshot: '<img src="' + this.get('screenshot_url') + '" />'
|
||||
}
|
||||
return obj
|
||||
},
|
||||
updateView: function () {
|
||||
var map = Metamaps.Active.Map
|
||||
var isActiveMap = this.id === map.id
|
||||
|
|
|
@ -51,31 +51,26 @@ $(document).ready(function () {
|
|||
Metamaps[prop].hasOwnProperty('init') &&
|
||||
typeof (Metamaps[prop].init) == 'function'
|
||||
) {
|
||||
Metamaps[prop].init();
|
||||
Metamaps[prop].init()
|
||||
}
|
||||
}
|
||||
// load whichever page you are on
|
||||
if (Metamaps.currentSection === "explore") {
|
||||
var capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1);
|
||||
var capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1)
|
||||
|
||||
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] );
|
||||
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] )
|
||||
if (Metamaps.currentPage === "mapper") {
|
||||
Metamaps.Views.exploreMaps.fetchUserThenRender();
|
||||
Metamaps.Header.fetchUserThenChangeSection(!!Metamaps.Active.Mapper, Metamaps.Maps.Mapper.mapperId)
|
||||
Metamaps.Views.exploreMaps.fetchUserThenRender()
|
||||
}
|
||||
else {
|
||||
Metamaps.Views.exploreMaps.render();
|
||||
Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, Metamaps.currentPage)
|
||||
Metamaps.Views.exploreMaps.render()
|
||||
}
|
||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
}
|
||||
else if (Metamaps.currentSection === "" && Metamaps.Active.Mapper) {
|
||||
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps.Active );
|
||||
Metamaps.Views.exploreMaps.render();
|
||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
||||
Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, 'active')
|
||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
||||
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps.Active)
|
||||
Metamaps.Views.exploreMaps.render()
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
}
|
||||
else if (Metamaps.Active.Map || Metamaps.Active.Topic) {
|
||||
Metamaps.Loading.show()
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
Metamaps.Header = {
|
||||
init: function () {
|
||||
|
||||
},
|
||||
fetchUserThenChangeSection: function (signedIn, mapperId) {
|
||||
$.ajax({
|
||||
url: '/users/' + mapperId + '.json',
|
||||
success: function (response) {
|
||||
Metamaps.Header.changeSection(signedIn, 'mapper', response.image, response.name)
|
||||
},
|
||||
error: function () {}
|
||||
});
|
||||
},
|
||||
changeSection: function (signedIn, section, userAvatar, userName) {
|
||||
ReactDOM.render(
|
||||
React.createElement(Metamaps.ReactComponents.Header, { signedIn: signedIn, section: section, userAvatar: userAvatar, userName: userName }),
|
||||
document.getElementById('exploreMapsHeader')
|
||||
);
|
||||
}
|
||||
}
|
|
@ -46,13 +46,7 @@
|
|||
if (Metamaps.Active.Mapper) {
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
|
||||
Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, 'active')
|
||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
||||
$('#exploreMaps').scrollTop(0)
|
||||
|
||||
Metamaps.GlobalUI.Search.open()
|
||||
Metamaps.GlobalUI.Search.lock()
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
|
||||
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps.Active)
|
||||
if (Metamaps.Maps.Active.length === 0) {
|
||||
|
@ -62,11 +56,8 @@
|
|||
}
|
||||
} else {
|
||||
// logged out home page
|
||||
Metamaps.GlobalUI.hideDiv('#exploreMapsHeader')
|
||||
Metamaps.GlobalUI.hideDiv('#exploreMaps')
|
||||
Metamaps.GlobalUI.hideDiv('#explore')
|
||||
Metamaps.GlobalUI.showDiv('#yield')
|
||||
Metamaps.GlobalUI.Search.unlock()
|
||||
//Metamaps.GlobalUI.Search.close(0, true)
|
||||
Metamaps.Router.timeoutId = setTimeout(navigate, 500)
|
||||
}
|
||||
|
||||
|
@ -143,15 +134,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
Metamaps.GlobalUI.Search.open()
|
||||
Metamaps.GlobalUI.Search.lock()
|
||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
||||
$('#exploreMaps').scrollTop(0)
|
||||
if (id) {
|
||||
Metamaps.Header.fetchUserThenChangeSection(!!Metamaps.Active.Mapper, id)
|
||||
}
|
||||
else Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, section)
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
Metamaps.GlobalUI.hideDiv('#infovis')
|
||||
Metamaps.GlobalUI.hideDiv('#instructions')
|
||||
|
@ -174,8 +157,7 @@
|
|||
// can edit this map '.canEditMap'
|
||||
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
Metamaps.GlobalUI.hideDiv('#exploreMaps')
|
||||
Metamaps.GlobalUI.hideDiv('#exploreMapsHeader')
|
||||
Metamaps.GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Metamaps.Visualize.mGraph) {
|
||||
|
@ -187,9 +169,6 @@
|
|||
Metamaps.Topic.end()
|
||||
Metamaps.Active.Topic = null
|
||||
|
||||
//Metamaps.GlobalUI.Search.unlock()
|
||||
//Metamaps.GlobalUI.Search.close(0, true)
|
||||
|
||||
Metamaps.Loading.show()
|
||||
Metamaps.Map.end()
|
||||
Metamaps.Map.launch(id)
|
||||
|
@ -206,8 +185,7 @@
|
|||
$('.wrapper').addClass('topicPage')
|
||||
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
Metamaps.GlobalUI.hideDiv('#exploreMaps')
|
||||
Metamaps.GlobalUI.hideDiv('#exploreMapsHeader')
|
||||
Metamaps.GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Metamaps.Visualize.mGraph) {
|
||||
|
@ -219,9 +197,6 @@
|
|||
Metamaps.Map.end()
|
||||
Metamaps.Active.Map = null
|
||||
|
||||
//Metamaps.GlobalUI.Search.unlock()
|
||||
//Metamaps.GlobalUI.Search.close(0, true)
|
||||
|
||||
Metamaps.Topic.end()
|
||||
Metamaps.Topic.launch(id)
|
||||
}
|
||||
|
|
|
@ -1,128 +1,87 @@
|
|||
/* global Metamaps, $, Hogan, Backbone */
|
||||
/* global Metamaps, $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Views.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Famous
|
||||
* - Metamaps.Loading
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.ReactComponents
|
||||
*/
|
||||
|
||||
Metamaps.Views = {
|
||||
initialized: false
|
||||
}
|
||||
|
||||
Metamaps.Views.init = function () {
|
||||
Metamaps.Views.MapperCard = Backbone.View.extend({
|
||||
template: Hogan.compile($('#mapperCardTemplate').html()),
|
||||
|
||||
tagName: 'div',
|
||||
|
||||
className: 'mapper',
|
||||
|
||||
render: function () {
|
||||
this.$el.html(this.template.render(this.model))
|
||||
return this
|
||||
}
|
||||
})
|
||||
|
||||
Metamaps.Views.MapCard = Backbone.View.extend({
|
||||
template: Hogan.compile($('#mapCardTemplate').html()),
|
||||
|
||||
tagName: 'div',
|
||||
|
||||
className: 'map',
|
||||
|
||||
id: function () {
|
||||
return this.model.id
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
this.listenTo(this.model, 'change', this.render)
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(this.template.render(this.model.attrForCards()))
|
||||
return this
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
var MapsWrapper = Backbone.View.extend({
|
||||
initialize: function (opts) {},
|
||||
exploreMaps: {
|
||||
setCollection: function (collection) {
|
||||
if (this.collection) this.stopListening(this.collection)
|
||||
this.collection = collection
|
||||
this.listenTo(this.collection, 'add', this.render)
|
||||
this.listenTo(this.collection, 'successOnFetch', this.handleSuccess)
|
||||
this.listenTo(this.collection, 'errorOnFetch', this.handleError)
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (self.collection) {
|
||||
self.collection.off('add', self.render)
|
||||
self.collection.off('successOnFetch', self.handleSuccess)
|
||||
self.collection.off('errorOnFetch', self.handleError)
|
||||
}
|
||||
self.collection = collection
|
||||
self.collection.on('add', self.render)
|
||||
self.collection.on('successOnFetch', self.handleSuccess)
|
||||
self.collection.on('errorOnFetch', self.handleError)
|
||||
},
|
||||
render: function (mapperObj, cb) {
|
||||
var that = this
|
||||
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (typeof mapperObj === 'function') {
|
||||
cb = mapperObj
|
||||
mapperObj = null
|
||||
}
|
||||
|
||||
this.el.innerHTML = ''
|
||||
|
||||
// in case it is a page where we have to display the mapper card
|
||||
if (mapperObj) {
|
||||
var view = new Metamaps.Views.MapperCard({ model: mapperObj })
|
||||
|
||||
that.el.appendChild(view.render().el)
|
||||
}
|
||||
|
||||
this.collection.each(function (map) {
|
||||
var view = new Metamaps.Views.MapCard({ model: map })
|
||||
|
||||
that.el.appendChild(view.render().el)
|
||||
})
|
||||
this.$el.append('<div class="clearfloat"></div>')
|
||||
|
||||
if (this.collection.length >= 20 && this.collection.page != "loadedAll") {
|
||||
this.$el.append('<button class="button loadMore">load more</button>')
|
||||
this.$el.append('<div class="clearfloat"></div>')
|
||||
var exploreObj = {
|
||||
currentUser: Metamaps.Active.Mapper,
|
||||
section: self.collection.id,
|
||||
displayStyle: 'grid',
|
||||
maps: self.collection,
|
||||
moreToLoad: self.collection.page != 'loadedAll',
|
||||
user: mapperObj,
|
||||
loadMore: self.loadMore
|
||||
}
|
||||
ReactDOM.render(
|
||||
React.createElement(Metamaps.ReactComponents.Maps, exploreObj),
|
||||
document.getElementById('explore')
|
||||
)
|
||||
|
||||
$('#exploreMaps').empty().html(this.el)
|
||||
this.$el.find('.loadMore').click(that.loadMore.bind(that))
|
||||
if (cb) cb()
|
||||
Metamaps.Loading.hide()
|
||||
},
|
||||
loadMore: function () {
|
||||
if (this.collection.page != "loadedAll") {
|
||||
this.collection.getMaps();
|
||||
}
|
||||
else {
|
||||
this.$el.find('.loadMore').hide()
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (self.collection.page != "loadedAll") {
|
||||
self.collection.getMaps()
|
||||
}
|
||||
else self.render()
|
||||
},
|
||||
handleSuccess: function (cb) {
|
||||
if (this.collection && this.collection.id === 'mapper') {
|
||||
this.fetchUserThenRender(cb)
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (self.collection && self.collection.id === 'mapper') {
|
||||
self.fetchUserThenRender(cb)
|
||||
} else {
|
||||
this.render(cb)
|
||||
self.render(cb)
|
||||
}
|
||||
},
|
||||
handleError: function () {
|
||||
console.log('error loading maps!') // TODO
|
||||
},
|
||||
fetchUserThenRender: function (cb) {
|
||||
var that = this
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
// first load the mapper object and then call the render function
|
||||
$.ajax({
|
||||
url: '/users/' + this.collection.mapperId + '/details.json',
|
||||
url: '/users/' + self.collection.mapperId + '/details.json',
|
||||
success: function (response) {
|
||||
that.render(response, cb)
|
||||
self.render(response, cb)
|
||||
},
|
||||
error: function () {
|
||||
that.render(cb)
|
||||
self.render(cb)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Metamaps.Views.exploreMaps = new MapsWrapper()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -590,8 +590,11 @@
|
|||
|
||||
/* explore maps */
|
||||
|
||||
#exploreMaps {
|
||||
#explore {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#exploreMaps {
|
||||
padding: 0 5%;
|
||||
position: absolute;
|
||||
width: 90%;
|
||||
|
@ -613,7 +616,6 @@
|
|||
}
|
||||
|
||||
#exploreMapsHeader {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -45,55 +45,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="mapCardTemplate">
|
||||
<a href="/maps/{{id}}" data-router="true">
|
||||
<div class="permission {{editPermission}}"> <!-- must be canEdit or cannotEdit -->
|
||||
<div class="mapCard">
|
||||
<span class="title" title="{{fullName}}">
|
||||
{{name}}
|
||||
</span>
|
||||
<div class="mapScreenshot">
|
||||
{{{screenshot}}}
|
||||
</div>
|
||||
<div class="scroll">
|
||||
<div class="desc">
|
||||
{{desc}}
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mapMetadata">
|
||||
<div class="metadataSection">{{{contributor_count_number}}}{{contributor_count_string}}</div>
|
||||
<div class="metadataSection">{{{topic_count_number}}}{{topic_count_string}}</div>
|
||||
<div class="metadataSection mapPermission">{{permission}}</div>
|
||||
<div class="metadataSection">{{{synapse_count_number}}}{{synapse_count_string}}</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="mapperCardTemplate">
|
||||
<div class="mapperCard">
|
||||
<div class="mapperImage">
|
||||
<img src="{{image}}" width="96" height="96" />
|
||||
</div>
|
||||
<div class="mapperName" title="{{name}}">
|
||||
{{name}}
|
||||
</div>
|
||||
<div class="mapperInfo">
|
||||
<div class="mapperCreatedAt">Mapper since: {{created_at}}</div>
|
||||
<div class="mapperGeneration">Generation: {{generation}}</div>
|
||||
</div>
|
||||
<div class="mapperMetadata">
|
||||
<div class="metadataSection metadataMaps"><div>{{numMaps}}</div>maps</div>
|
||||
<div class="metadataSection metadataTopics"><div>{{numTopics}}</div>topics</div>
|
||||
<div class="metadataSection metadataSynapses"><div>{{numSynapses}}</div>synapses</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="topicSearchTemplate">
|
||||
<div class="result{{rtype}}">
|
||||
|
|
|
@ -44,8 +44,7 @@
|
|||
<% end %>
|
||||
<%= render :partial => 'layouts/lowermapelements' %>
|
||||
|
||||
<div id="exploreMaps"></div>
|
||||
<div id="exploreMapsHeader"></div>
|
||||
<div id="explore"></div>
|
||||
|
||||
<div id="instructions">
|
||||
<div class="addTopic">
|
||||
|
|
|
@ -32,41 +32,43 @@ class Header extends Component {
|
|||
const mapper = section == "mapper"
|
||||
|
||||
return (
|
||||
<div className="exploreMapsBar exploreElement">
|
||||
<div className="exploreMapsMenu">
|
||||
<div className="exploreMapsCenter">
|
||||
<MapLink show={signedIn && explore}
|
||||
href="/explore/mine"
|
||||
linkClass={activeClass("my")}
|
||||
data-router="true"
|
||||
text="My Maps"
|
||||
/>
|
||||
<MapLink show={signedIn && explore}
|
||||
href="/explore/shared"
|
||||
linkClass={activeClass("shared")}
|
||||
data-router="true"
|
||||
text="Shared With Me"
|
||||
/>
|
||||
<MapLink show={explore}
|
||||
href={signedIn ? "/" : "/explore/active"}
|
||||
linkClass={activeClass("active")}
|
||||
data-router="true"
|
||||
text="Recently Active"
|
||||
/>
|
||||
<MapLink show={!signedIn && explore}
|
||||
href="/explore/featured"
|
||||
linkClass={activeClass("featured")}
|
||||
data-router="true"
|
||||
text="Featured Maps"
|
||||
/>
|
||||
|
||||
{mapper ? (
|
||||
<div className='exploreMapsButton active mapperButton'>
|
||||
<img className='exploreMapperImage' width='24' height='24' src={this.props.userAvatar} />
|
||||
<div className='exploreMapperName'>{this.props.userName}’s Maps</div>
|
||||
<div className='clearfloat'></div>
|
||||
</div>
|
||||
) : null }
|
||||
<div id="exploreMapsHeader">
|
||||
<div className="exploreMapsBar exploreElement">
|
||||
<div className="exploreMapsMenu">
|
||||
<div className="exploreMapsCenter">
|
||||
<MapLink show={signedIn && explore}
|
||||
href="/explore/mine"
|
||||
linkClass={activeClass("my")}
|
||||
data-router="true"
|
||||
text="My Maps"
|
||||
/>
|
||||
<MapLink show={signedIn && explore}
|
||||
href="/explore/shared"
|
||||
linkClass={activeClass("shared")}
|
||||
data-router="true"
|
||||
text="Shared With Me"
|
||||
/>
|
||||
<MapLink show={explore}
|
||||
href={signedIn ? "/" : "/explore/active"}
|
||||
linkClass={activeClass("active")}
|
||||
data-router="true"
|
||||
text="Recently Active"
|
||||
/>
|
||||
<MapLink show={!signedIn && explore}
|
||||
href="/explore/featured"
|
||||
linkClass={activeClass("featured")}
|
||||
data-router="true"
|
||||
text="Featured Maps"
|
||||
/>
|
||||
|
||||
{mapper ? (
|
||||
<div className='exploreMapsButton active mapperButton'>
|
||||
<img className='exploreMapperImage' width='24' height='24' src={this.props.user.image} />
|
||||
<div className='exploreMapperName'>{this.props.user.name}’s Maps</div>
|
||||
<div className='clearfloat'></div>
|
||||
</div>
|
||||
) : null }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -77,8 +79,7 @@ class Header extends Component {
|
|||
Header.propTypes = {
|
||||
signedIn: PropTypes.bool.isRequired,
|
||||
section: PropTypes.string.isRequired,
|
||||
userAvatar: PropTypes.string,
|
||||
userName: PropTypes.string
|
||||
user: PropTypes.object
|
||||
}
|
||||
|
||||
export default Header
|
||||
|
|
74
frontend/src/components/MapCard.js
Normal file
74
frontend/src/components/MapCard.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
class MapCard extends Component {
|
||||
render = () => {
|
||||
const { map, currentUser } = this.props
|
||||
|
||||
function capitalize (string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||
}
|
||||
|
||||
const n = map.get('name')
|
||||
const d = map.get('desc')
|
||||
|
||||
const maxNameLength = 32
|
||||
const maxDescLength = 118
|
||||
const truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + '...' : n) : ''
|
||||
const truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + '...' : d) : ''
|
||||
const editPermission = map.authorizeToEdit(currentUser) ? 'canEdit' : 'cannotEdit'
|
||||
|
||||
return (
|
||||
<div className="map" id={ map.id }>
|
||||
<a href={ '/maps/' + map.id } data-router="true">
|
||||
<div className={ 'permission ' + editPermission }>
|
||||
<div className="mapCard">
|
||||
<span className="title" title={ map.get('name') }>
|
||||
{ truncatedName }
|
||||
</span>
|
||||
<div className="mapScreenshot">
|
||||
<img src={ map.get('screenshot_url') } />
|
||||
</div>
|
||||
<div className="scroll">
|
||||
<div className="desc">
|
||||
{ truncatedDesc }
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mapMetadata">
|
||||
<div className="metadataSection">
|
||||
<span className="cCountColor">
|
||||
{ map.get('contributor_count') }
|
||||
</span>
|
||||
{ map.get('contributor_count') === 1 ? ' contributor' : ' contributors' }
|
||||
</div>
|
||||
<div className="metadataSection">
|
||||
<span className="tCountColor">
|
||||
{ map.get('topic_count') }
|
||||
</span>
|
||||
{ map.get('topic_count') === 1 ? ' topic' : ' topics' }
|
||||
</div>
|
||||
<div className="metadataSection mapPermission">
|
||||
{ map.get('permission') ? capitalize(map.get('permission')) : 'Commons' }
|
||||
</div>
|
||||
<div className="metadataSection">
|
||||
<span className="sCountColor">
|
||||
{ map.get('synapse_count') }
|
||||
</span>
|
||||
{ map.get('synapse_count') === 1 ? ' synapse' : ' synapses' }
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MapCard.propTypes = {
|
||||
map: PropTypes.object.isRequired,
|
||||
currentUser: PropTypes.object
|
||||
}
|
||||
|
||||
export default MapCard
|
0
frontend/src/components/MapListItem.js
Normal file
0
frontend/src/components/MapListItem.js
Normal file
36
frontend/src/components/MapperCard.js
Normal file
36
frontend/src/components/MapperCard.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
class MapperCard extends Component {
|
||||
render = () => {
|
||||
const { user } = this.props
|
||||
|
||||
return (
|
||||
<div className="mapper">
|
||||
<div className="mapperCard">
|
||||
<div className="mapperImage">
|
||||
<img src={ user.image } width="96" height="96" />
|
||||
</div>
|
||||
<div className="mapperName" title={ user.name }>
|
||||
{ user.name }
|
||||
</div>
|
||||
<div className="mapperInfo">
|
||||
<div className="mapperCreatedAt">Mapper since: { user.created_at }</div>
|
||||
<div className="mapperGeneration">Generation: { user.generation }</div>
|
||||
</div>
|
||||
<div className="mapperMetadata">
|
||||
<div className="metadataSection metadataMaps"><div>{ user.numMaps }</div>maps</div>
|
||||
<div className="metadataSection metadataTopics"><div>{ user.numTopics }</div>topics</div>
|
||||
<div className="metadataSection metadataSynapses"><div>{ user.numSynapses }</div>synapses</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MapperCard.propTypes = {
|
||||
user: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default MapperCard
|
54
frontend/src/components/Maps.js
Normal file
54
frontend/src/components/Maps.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
import Header from './Header.js'
|
||||
import MapperCard from './MapperCard.js'
|
||||
import MapCard from './MapCard.js'
|
||||
import MapListItem from './MapListItem.js'
|
||||
|
||||
class Maps extends Component {
|
||||
render = () => {
|
||||
const { maps, currentUser, section, displayStyle, user, moreToLoad, loadMore } = this.props
|
||||
let mapElements
|
||||
|
||||
if (displayStyle == 'grid') {
|
||||
mapElements = maps.models.map(function (map) {
|
||||
return <MapCard key={ map.id } map={ map } currentUser={ currentUser } />
|
||||
})
|
||||
}
|
||||
else if (displayStyle == 'list') {
|
||||
mapElements = maps.models.map(function (map) {
|
||||
return <MapListItem key={ map.id } map={ map } />
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id='exploreMaps'>
|
||||
<div>
|
||||
{ user ? <MapperCard user={ user } /> : null }
|
||||
{ mapElements }
|
||||
<div className='clearfloat'></div>
|
||||
{ moreToLoad ?
|
||||
[<button className="button loadMore" onClick={ loadMore }>load more</button>, <div className='clearfloat'></div>]
|
||||
: null }
|
||||
</div>
|
||||
</div>
|
||||
<Header signedIn={ !!currentUser }
|
||||
section={ section }
|
||||
user={ user }
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Maps.propTypes = {
|
||||
section: PropTypes.string.isRequired,
|
||||
maps: PropTypes.object.isRequired,
|
||||
moreToLoad: PropTypes.bool.isRequired,
|
||||
displayStyle: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
currentUser: PropTypes.object,
|
||||
loadMore: PropTypes.func
|
||||
}
|
||||
|
||||
export default Maps
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||
import ReactDOM from 'react-dom'
|
||||
import Backbone from 'backbone'
|
||||
import _ from 'underscore'
|
||||
import Header from './components/Header.js'
|
||||
import Maps from './components/Maps.js'
|
||||
|
||||
// this is optional really, if we import components directly React will be
|
||||
// in the bundle, so we won't need a global reference
|
||||
|
@ -14,5 +14,5 @@ window._ = _
|
|||
|
||||
window.Metamaps = window.Metamaps || {}
|
||||
window.Metamaps.ReactComponents = {
|
||||
Header
|
||||
Maps
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue