diff --git a/app/assets/images/delete_mapinfo.png b/app/assets/images/delete_mapinfo.png deleted file mode 100644 index e6316c2e..00000000 Binary files a/app/assets/images/delete_mapinfo.png and /dev/null differ diff --git a/app/assets/images/profile_card_sprite.png b/app/assets/images/profile_card_sprite.png new file mode 100644 index 00000000..2b6eb216 Binary files /dev/null and b/app/assets/images/profile_card_sprite.png differ diff --git a/app/assets/images/remove_mapinfo_sprite.png b/app/assets/images/remove_mapinfo_sprite.png new file mode 100644 index 00000000..ba7f4b81 Binary files /dev/null and b/app/assets/images/remove_mapinfo_sprite.png differ diff --git a/app/assets/images/video-screen.png b/app/assets/images/video-screen.png new file mode 100644 index 00000000..751df9a9 Binary files /dev/null and b/app/assets/images/video-screen.png differ diff --git a/app/assets/javascripts/src/Metamaps.Backbone.js b/app/assets/javascripts/src/Metamaps.Backbone.js index 7ed0adfe..0eec6e61 100644 --- a/app/assets/javascripts/src/Metamaps.Backbone.js +++ b/app/assets/javascripts/src/Metamaps.Backbone.js @@ -131,11 +131,20 @@ Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({ this.id = options.id; this.sortBy = options.sortBy; + if (options.mapperId) { + this.mapperId = options.mapperId; + } + // this.page represents the NEXT page to fetch this.page = models.length > 0 ? (models.length < 20 ? "loadedAll" : 2) : 1; }, url: function() { - return '/explore/' + this.id + '.json'; + if (!this.mapperId) { + return '/explore/' + this.id + '.json'; + } + else { + return '/explore/mapper/' + this.mapperId + '.json'; + } }, comparator: function (a, b) { a = a.get(this.sortBy); diff --git a/app/assets/javascripts/src/Metamaps.GlobalUI.js b/app/assets/javascripts/src/Metamaps.GlobalUI.js index b93c6ab4..ce83ae80 100644 --- a/app/assets/javascripts/src/Metamaps.GlobalUI.js +++ b/app/assets/javascripts/src/Metamaps.GlobalUI.js @@ -90,9 +90,17 @@ Metamaps.GlobalUI = { if (Metamaps.Active.Mapper) Metamaps.Active.Mapper = new Metamaps.Backbone.Mapper(Metamaps.Active.Mapper); var myCollection = Metamaps.Maps.Mine ? Metamaps.Maps.Mine : []; + var mapperCollection = []; + var mapperOptionsObj = {id: 'mapper', sortBy: 'name' }; + if (Metamaps.Maps.Mapper) { + mapperCollection = Metamaps.Maps.Mapper.models; + mapperOptionsObj.mapperId = Metamaps.Maps.Mapper.id; + } var featuredCollection = Metamaps.Maps.Featured ? Metamaps.Maps.Featured : []; var activeCollection = Metamaps.Maps.Active ? Metamaps.Maps.Active : []; Metamaps.Maps.Mine = new Metamaps.Backbone.MapsCollection(myCollection, {id: 'mine', sortBy: 'name' }); + // 'Mapper' refers to another mapper + Metamaps.Maps.Mapper = new Metamaps.Backbone.MapsCollection(mapperCollection, mapperOptionsObj); Metamaps.Maps.Featured = new Metamaps.Backbone.MapsCollection(featuredCollection, {id: 'featured', sortBy: 'name' }); Metamaps.Maps.Active = new Metamaps.Backbone.MapsCollection(activeCollection, {id: 'active', sortBy: 'updated_at' }); }, @@ -600,8 +608,7 @@ Metamaps.GlobalUI.Search = { } else if (dataset == "maps") { Metamaps.Router.maps(datum.id); } else if (dataset == "mappers") { - win = window.open('/maps/mappers/' + datum.id, '_blank'); - win.focus(); + Metamaps.Router.explore("mapper", datum.id); } } }, diff --git a/app/assets/javascripts/src/Metamaps.Router.js b/app/assets/javascripts/src/Metamaps.Router.js index 466326d2..fae8f38e 100644 --- a/app/assets/javascripts/src/Metamaps.Router.js +++ b/app/assets/javascripts/src/Metamaps.Router.js @@ -6,6 +6,7 @@ routes: { "": "home", // #home "explore/:section": "explore", // #explore/active + "explore/:section/:id": "explore", // #explore/mapper/1234 "maps/:id": "maps" // #maps/7 }, home: function () { @@ -64,13 +65,18 @@ Metamaps.Active.Map = null; Metamaps.Active.Topic = null; }, - explore: function (section) { + explore: function (section, id) { // just capitalize the variable section - // either 'mine', 'featured', or 'active' + // either 'featured', 'mapper', or 'active' var capitalize = section.charAt(0).toUpperCase() + section.slice(1); - document.title = 'Explore ' + capitalize + ' Maps | Metamaps'; + if (capitalize === "featured" || capitalize === "active") { + document.title = 'Explore ' + capitalize + ' Maps | Metamaps'; + } + else if (capitalize === "mapper") { + document.title = 'Explore Maps | Metamaps'; + } $('.wrapper').removeClass('homePage mapPage topicPage'); $('.wrapper').addClass('explorePage'); @@ -78,6 +84,17 @@ Metamaps.currentSection = "explore"; Metamaps.currentPage = section; + // this will mean it's a mapper page being loaded + if (id) { + if (Metamaps.Maps.Mapper.mapperId !== id) { + // empty the collection if we are trying to load the maps + // collection of a different mapper than we had previously + Metamaps.Maps.Mapper.reset(); + Metamaps.Maps.Mapper.page = 1; + } + Metamaps.Maps.Mapper.mapperId = id; + } + Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] ); if (Metamaps.Maps[capitalize].length === 0) { Metamaps.Loading.show(); @@ -86,7 +103,12 @@ }, 300); // wait 300 milliseconds till the other animations are done to do the fetch } else { - Metamaps.Views.exploreMaps.render(); + if (id) { + Metamaps.Views.exploreMaps.fetchUserThenRender(); + } + else { + Metamaps.Views.exploreMaps.render(); + } } Metamaps.GlobalUI.Search.open(); @@ -96,7 +118,7 @@ Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top Metamaps.Famous.maps.show(); - Metamaps.Famous.explore.set(section); + Metamaps.Famous.explore.set(section, id); Metamaps.Famous.explore.show(); Metamaps.Famous.viz.hide(); diff --git a/app/assets/javascripts/src/Metamaps.Views.js b/app/assets/javascripts/src/Metamaps.Views.js index 3d00991e..eab536ba 100644 --- a/app/assets/javascripts/src/Metamaps.Views.js +++ b/app/assets/javascripts/src/Metamaps.Views.js @@ -5,6 +5,20 @@ 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() ), @@ -40,12 +54,20 @@ Metamaps.Views.init = function () { this.listenTo(this.collection, 'successOnFetch', this.handleSuccess); this.listenTo(this.collection, 'errorOnFetch', this.handleError); }, - render: function () { + render: function (mapperObj) { var that = this; 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 }); @@ -70,15 +92,41 @@ Metamaps.Views.init = function () { Metamaps.Loading.hide(); setTimeout(function(){ - var path = Metamaps.currentSection == "" ? "" : "/explore/" + Metamaps.currentPage; + var path = Metamaps.currentSection == "" ? "" : "/explore/" + Metamaps.currentPage; + + // alter url if for mapper profile page + if (that.collection && that.collection.mapperId) { + path += "/" + that.collection.mapperId; + } + Metamaps.Router.navigate(path); }, 500); }, handleSuccess: function () { - this.render(); + var that = this; + + if (this.collection && this.collection.id === "mapper") { + this.fetchUserThenRender(); + } + else { + this.render(); + } }, handleError: function () { console.log('error loading maps!'); //TODO + }, + fetchUserThenRender: function () { + var that = this; + // first load the mapper object and then call the render function + $.ajax({ + url: "/users/" + this.collection.mapperId + "/details.json", + success: function (response) { + that.render(response); + }, + error: function () { + + } + }); } }); diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 893c67d3..8cd71a74 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -70,9 +70,6 @@ body, .wrapper { height: 100%; } -.homePage .famousYield { - background: url(homepage-bg.png) no-repeat -515px -40px; -} .wrapper.mapPage { overflow: hidden; } @@ -1884,9 +1881,21 @@ and it won't be important on password protected instances */ display: none; } .mapInfoDelete { - background-image: url(delete_mapinfo.png); + color: #E0E0E0; +} +.mapInfoDelete .deleteMap { + width: 16px; + height: 16px; + margin: 8px auto 0; + background-image: url(remove_mapinfo_sprite.png); background-repeat: no-repeat; - background-position: center 8px; + background-position: -16px 0; +} +.mapInfoDelete:hover { + color: #F5F5F5; +} +.mapInfoDelete:hover .deleteMap { + background-position: 0 0; } /* only display delete button if it's a map you created */ .yourMap .mapInfoDelete { diff --git a/app/assets/stylesheets/base.css b/app/assets/stylesheets/base.css index 92809fbf..1b5ac8fc 100644 --- a/app/assets/stylesheets/base.css +++ b/app/assets/stylesheets/base.css @@ -980,4 +980,79 @@ font-family: 'din-regular', helvetica, sans-serif; .sCountColor { font-family: 'din-medium', sans-serif; color: #DAB539; +} + + +/* mapper card */ + +.mapper { + float: left; + width:220px; + height:340px; + font-size: 12px; + text-align: left; + overflow: visible; + background: #E0E0E0; + border-radius:2px; + margin:16px 16px 16px 19px; + box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16); +} + +.mapperCard { + width:100%; + height:308px; + padding: 16px 0; + color:#424242; +} + +.mapperImage { + margin: 16px auto 0; + width: 96px; +} +.mapperImage img { + border-radius: 48px; + box-shadow: 0px 3px 3px rgba(0,0,0,0.23); +} + +.mapperName { + font-size: 24px; + text-align: center; + margin-top: 24px; + padding: 0 16px; + white-space: nowrap; + text-overflow: ellipsis; + width: 189px; + overflow: hidden; +} + +.mapperInfo { + color: #DB5D5D; + text-align:center; + margin-top: 16px; +} + +.mapperMetadata { + background: url(profile_card_sprite.png) no-repeat center 0; + height: 64px; + width: 160px; + margin: 16px auto 0; +} +.mapperMetadata .metadataSection { + width: 32%; + display: inline-block; + text-align: center; +} +.mapperMetadata .metadataSection div { + font-size: 16px; + color: #424242; + margin: 14px 0; +} +.mapperMetadata .metadataMaps { + color: #DB5D5D; +} +.mapperMetadata .metadataTopics { + color: #4FC059; +} +.mapperMetadata .metadataSynapses { + color: #DAB539; } \ No newline at end of file diff --git a/app/assets/stylesheets/clean.css b/app/assets/stylesheets/clean.css index 28d3aac0..24a659fc 100644 --- a/app/assets/stylesheets/clean.css +++ b/app/assets/stylesheets/clean.css @@ -711,14 +711,26 @@ /* homepage */ +.homeWrapper.homeText { + margin-top: 10%; +} + +.fullWidthWrapper { + width: 100%; +} +.fullWidthWrapper.withVideo { + height: 350px; + background: #757575; +} + .homeWrapper { - width: 560px; - margin: 56px auto 72px; + width: 880px; + margin: 0 auto; color: #424242; } .homeTitle { - font-size: 48px; + font-size: 69px; line-height: 48px; text-align: center; margin-bottom: 20px; @@ -728,18 +740,40 @@ font-size: 23px; line-height: 26px; text-align: justify; - margin-bottom: 20px; + margin: 32px 0 20px; + font-family: 'din-regular', helvetica, sans-serif; } .homeWrapper .green { color: #4fc059; } -.homeVideo { - margin-bottom: 20px; +.homeWrapper .din-medium { + font-family: 'din-medium', helvetica, sans-serif; } -.callToAction a { +.homeVideo { + margin-bottom: 20px; + float: left; +} + +.homeWrapper .callToAction { + float: left; + width: 220px; + padding: 24px 0 24px 24px; + color: #F5F5F5; +} +.callToAction h3 { + font-size: 24px; +} +.callToAction p { + margin: 16px 0; + font-size: 14px; + line-height: 16px; + font-family: 'din-regular', helvetica, sans-serif; + text-align: justify; +} +.callToAction a, .callToAction button { display: block; width: 220px; height: 12px; @@ -750,20 +784,38 @@ box-shadow: 0px 1px 1.5px rgba(0,0,0,0.12), 0 1px 1px rgba(0,0,0,0.24); margin: 0 auto; color: #FFFFFF; + box-sizing: content-box; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; } .callToAction .requestInviteCTA { background-color: #4fc059; - margin-bottom: 15px; + margin-bottom: 16px; } .callToAction .requestInviteCTA:hover { background-color: #49ad4e; } .callToAction .exploreFeaturedCTA { background-color: #a354cd; + margin-bottom: 16px; } .callToAction .exploreFeaturedCTA:hover { background-color: #9150bc; } +.callToAction .learnMoreCTA { + background-color: #4fb5c0; +} +.callToAction .learnMoreCTA:hover { + background-color: #9150bc; +} + +.fullWidthWrapper.withPartners { + background: url(homepage-bg.png) no-repeat center -300px; +} +.homeWrapper.homePartners { + padding-bottom: 100px; + height: 200px; +} .github-fork-ribbon-wrapper { display:none; @@ -1074,6 +1126,23 @@ border-bottom: 2px solid #00BCD4; } +.exploreMapsButton.mapperButton { + height: 40px; + padding: 0; +} +.mapperButton img.exploreMapperImage { + float: left; + border-radius: 12px; + margin-top: 8px; + margin-right: 8px; +} +.exploreMapperName { + white-space: nowrap; + float: left; + margin-top: 12px; +} + + .exploreMapsButton .exploreMapsIcon { background-repeat: no-repeat; width:32px; diff --git a/app/controllers/maps_controller.rb b/app/controllers/maps_controller.rb index 58f778d9..268093f1 100644 --- a/app/controllers/maps_controller.rb +++ b/app/controllers/maps_controller.rb @@ -6,10 +6,9 @@ class MapsController < ApplicationController autocomplete :map, :name, :full => true, :extra_data => [:user_id] - # GET /maps/recent - # GET /maps/featured - # GET /maps/new - # GET /maps/mappers/:id + # GET /explore/active + # GET /explore/featured + # GET /explore/mapper/:id def index if request.path == "/explore" @@ -19,6 +18,7 @@ class MapsController < ApplicationController @current = current_user @user = nil @maps = [] + @mapperId = nil if !params[:page] page = 1 @@ -39,21 +39,12 @@ class MapsController < ApplicationController redirect_to activemaps_url and return end # don't need to exclude private maps because they all belong to you - @maps = Map.where("maps.user_id = ?", @current.id).order("name ASC").page(page).per(20) @request = "you" - elsif request.path.index('/explore/mappers/') != nil # looking for maps by a mapper + elsif request.path.index('/explore/mapper/') != nil # looking for maps by a mapper @user = User.find(params[:id]) @maps = Map.where("maps.user_id = ? AND maps.permission != ?", @user.id, "private").order("name ASC").page(page).per(20) - @request = "other" - - elsif request.path.index('/explore/topics/') != nil # looking for maps by a certain topic they include - @topic = Topic.find(params[:id]).authorize_to_show(@current) - if !@topic - redirect_to featuredmaps_url, notice: "Access denied." and return - end - @maps = @topic.maps.delete_if {|m| m.permission == "private" && (!authenticated? || (authenticated? && @current.id != m.user_id)) } - @request = "topic" + @request = "mapper" end respond_to do |format| diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index a8989bc6..58ef2d96 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -67,6 +67,23 @@ class UsersController < ApplicationController end end + # GET /users/:id/details [.json] + def details + @user = User.find(params[:id]) + + @details = Hash.new + + @details['name'] = @user.name + @details['created_at'] = @user.created_at.strftime("%m/%d/%Y") + @details['image'] = @user.image.url(:ninetysix) + @details['generation'] = @user.generation + @details['numSynapses'] = @user.synapses.count + @details['numTopics'] = @user.topics.count + @details['numMaps'] = @user.maps.count + + render json: @details + end + # PUT /user/updatemetacodes def updatemetacodes @user = current_user diff --git a/app/helpers/maps_helper.rb b/app/helpers/maps_helper.rb index de514252..0c9b3a08 100644 --- a/app/helpers/maps_helper.rb +++ b/app/helpers/maps_helper.rb @@ -18,9 +18,9 @@ module MapsHelper contributorTip = '' firstContributorImage = '/assets/user.png' if m.contributors.count > 0 - firstContributorImage = m.contributors[0].image.url(:square) + firstContributorImage = m.contributors[0].image.url(:thirtytwo) m.contributors.each_with_index do |c, index| - userImage = c.image.url(:square) + userImage = c.image.url(:thirtytwo) name = c.name contributorTip += '
  • ' + '' + name + '
  • ' end diff --git a/app/helpers/synapses_helper.rb b/app/helpers/synapses_helper.rb index a13a1be2..19286bcd 100644 --- a/app/helpers/synapses_helper.rb +++ b/app/helpers/synapses_helper.rb @@ -25,7 +25,7 @@ module SynapsesHelper synapse['permission'] = s.permission synapse['mapCount'] = s.maps.count synapse['originator'] = s.user.name - synapse['originatorImage'] = s.user.image.url(:square) + synapse['originatorImage'] = s.user.image.url(:thirtytwo) synapse['rtype'] = "synapse" temp.push synapse diff --git a/app/helpers/topics_helper.rb b/app/helpers/topics_helper.rb index 864493b7..e75a7397 100644 --- a/app/helpers/topics_helper.rb +++ b/app/helpers/topics_helper.rb @@ -15,7 +15,7 @@ module TopicsHelper topic['mapCount'] = t.maps.count topic['synapseCount'] = t.synapses.count topic['originator'] = t.user.name - topic['originatorImage'] = t.user.image.url(:square) + topic['originatorImage'] = t.user.image.url(:thirtytwo) topic['rtype'] = "topic" topic['inmaps'] = t.inmaps diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index a390eb83..977e5709 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -8,7 +8,7 @@ module UsersHelper user['id'] = u.id user['label'] = u.name user['value'] = u.name - user['profile'] = u.image.url(:square) + user['profile'] = u.image.url(:sixtyfour) user['mapCount'] = u.maps.count user['generation'] = u.generation user['created_at'] = u.created_at.strftime("%m/%d/%Y") diff --git a/app/models/user.rb b/app/models/user.rb index 8596a771..11062046 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -32,7 +32,10 @@ class User < ActiveRecord::Base # This method associates the attribute ":image" with a file attachment has_attached_file :image, :styles => { - :square => ['84x84#', :png] + :thirtytwo => ['32x32#', :png], + :sixtyfour => ['64x64#', :png], + :ninetysix => ['96x96#', :png], + :onetwentyeight => ['128x128#', :png] }, :default_url => "/assets/user.png" @@ -42,7 +45,7 @@ class User < ActiveRecord::Base def as_json(options={}) { :id => self.id, :name => self.name, - :image => self.image.url(:square) + :image => self.image.url(:sixtyfour) } end diff --git a/app/views/layouts/_account.html.erb b/app/views/layouts/_account.html.erb index b48cde3d..6150eebf 100644 --- a/app/views/layouts/_account.html.erb +++ b/app/views/layouts/_account.html.erb @@ -5,7 +5,7 @@ <% if authenticated? %> <% account = current_user %> - <%= image_tag user.image.url(:square), :size => "48x48", :class => "sidebarAccountImage" %> + <%= image_tag user.image.url(:sixtyfour), :size => "48x48", :class => "sidebarAccountImage" %>

    <%= account.name.split[0...1][0] %>