diff --git a/app/assets/images/pages/front/play_web.jpg b/app/assets/images/pages/front/play_web.jpg deleted file mode 100644 index 6ef8412da..000000000 Binary files a/app/assets/images/pages/front/play_web.jpg and /dev/null differ diff --git a/app/locale/en.coffee b/app/locale/en.coffee index c02762a02..0a89b3c1e 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -340,6 +340,14 @@ multiplayer_caption: "Play with friends!" auth_caption: "Save your progress." + leaderboard: + leaderboard: "Leaderboard" + view_other_solutions: "View Other Solutions" + top_solutions: "Top Solutions" + day_tab: "Today" + week_tab: "This Week" + all_tab: "All-Time" + inventory: choose_inventory: "Equip Items" equipped_item: "Equipped" diff --git a/app/models/User.coffee b/app/models/User.coffee index ee537e1ae..2dcc1dcc6 100644 --- a/app/models/User.coffee +++ b/app/models/User.coffee @@ -133,6 +133,21 @@ module.exports = class User extends CocoModel application.tracker.identify foreshadowsLevels: @foreshadowsLevels unless me.isAdmin() @foreshadowsLevels + getLeaderboardsGroup: -> + return @leaderboardsGroup if @leaderboardsGroup? + group = me.get('testGroupNumber') % 64 + if group < 16 + @leaderboardsGroup = 'always' + else if group < 32 + @leaderboardsGroup = 'early' + else if group < 48 + @leaderboardsGroup = 'late' + else + @leaderboardsGroup = 'never' + @leaderboardsGroup = 'always' if me.isAdmin() + application.tracker.identify leaderboardsGroup: @leaderboardsGroup unless me.isAdmin() + @leaderboardsGroup + getVideoTutorialStylesIndex: (numVideos=0)-> # A/B Testing video tutorial styles # Not a constant number of videos available (e.g. could be 0, 1, 3, or 4 currently) diff --git a/app/styles/play/level/modal/hero-victory-modal.sass b/app/styles/play/level/modal/hero-victory-modal.sass index c881afa9f..5fa59faa9 100644 --- a/app/styles/play/level/modal/hero-victory-modal.sass +++ b/app/styles/play/level/modal/hero-victory-modal.sass @@ -320,6 +320,11 @@ margin: 0 float: left + .leaderboard-button + height: 60px + line-height: 30px + margin: 0 10px + float: left .next-level-buttons float: right diff --git a/app/styles/game-menu/game-menu-modal.sass b/app/styles/play/menu/game-menu-modal.sass similarity index 100% rename from app/styles/game-menu/game-menu-modal.sass rename to app/styles/play/menu/game-menu-modal.sass diff --git a/app/styles/game-menu/guide-view.sass b/app/styles/play/menu/guide-view.sass similarity index 100% rename from app/styles/game-menu/guide-view.sass rename to app/styles/play/menu/guide-view.sass diff --git a/app/styles/game-menu/inventory-modal.sass b/app/styles/play/menu/inventory-modal.sass similarity index 100% rename from app/styles/game-menu/inventory-modal.sass rename to app/styles/play/menu/inventory-modal.sass diff --git a/app/styles/game-menu/item-view.sass b/app/styles/play/menu/item-view.sass similarity index 100% rename from app/styles/game-menu/item-view.sass rename to app/styles/play/menu/item-view.sass diff --git a/app/styles/game-menu/multiplayer-view.sass b/app/styles/play/menu/multiplayer-view.sass similarity index 100% rename from app/styles/game-menu/multiplayer-view.sass rename to app/styles/play/menu/multiplayer-view.sass diff --git a/app/styles/game-menu/options-view.sass b/app/styles/play/menu/options-view.sass similarity index 100% rename from app/styles/game-menu/options-view.sass rename to app/styles/play/menu/options-view.sass diff --git a/app/styles/game-menu/save-load-view.sass b/app/styles/play/menu/save-load-view.sass similarity index 100% rename from app/styles/game-menu/save-load-view.sass rename to app/styles/play/menu/save-load-view.sass diff --git a/app/styles/play/modal/leaderboard-modal.sass b/app/styles/play/modal/leaderboard-modal.sass new file mode 100644 index 000000000..b2320cba9 --- /dev/null +++ b/app/styles/play/modal/leaderboard-modal.sass @@ -0,0 +1,93 @@ +@import "app/styles/bootstrap/variables" +@import "app/styles/mixins" + +#leaderboard-modal + + //- Clear modal defaults + + .modal-dialog + width: 820px + height: 570px + padding: 0 + background: none + position: relative + top: 40px + + + //- Background + + #leaderboard-background + position: absolute + top: -146px + left: -3px + + + //- Close modal button + + #close-modal + position: absolute + left: 769px + top: -5px + width: 60px + height: 60px + color: white + text-align: center + font-size: 30px + padding-top: 17px + cursor: pointer + z-index: 2 + @include rotate(-3deg) + + &:hover + color: yellow + + + //- Nav bar + + #leaderboard-nav + position: absolute + top: 53px + left: 42px + width: 178px + + li + background: url(/images/pages/play/modal/menu-tab.png) + padding: 5px + margin: -5px 0 + height: 80px + padding: 0 + + &.active + background: url(/images/pages/play/modal/menu-tab-selected.png) + width: 197px + + a + font-size: 18px + line-height: 50px + background: none + color: rgb(195,153,124) + font-weight: bold + padding: 14px 20px + font-family: $headings-font-family + text-transform: uppercase + + .glyphicon + margin-right: 6px + + + //- Tab panels + + .leaderboard-tab-content + position: absolute + left: 219px + top: 21px + width: 571px + height: 514px + padding: 50px + overflow-y: scroll + + ::-webkit-scrollbar + // So that the scrollbar doesn't go on top of the close button. + // Wish we could easily do this for Firefox. + display: none + diff --git a/app/styles/play/modal/leaderboard-tab-view.sass b/app/styles/play/modal/leaderboard-tab-view.sass new file mode 100644 index 000000000..d2691932d --- /dev/null +++ b/app/styles/play/modal/leaderboard-tab-view.sass @@ -0,0 +1,2 @@ +.leaderboard-tab-view + color: black diff --git a/app/templates/play/level/modal/hero-victory-modal.jade b/app/templates/play/level/modal/hero-victory-modal.jade index 22fe126a1..2c13d42ba 100644 --- a/app/templates/play/level/modal/hero-victory-modal.jade +++ b/app/templates/play/level/modal/hero-victory-modal.jade @@ -68,6 +68,9 @@ block modal-footer-content .sign-up-blurb(data-i18n="play_level.victory_sign_up_poke") Want to save your code? Create a free account! button.btn.btn-illustrated.btn-warning.sign-up-button.btn-lg(data-dismiss="modal", data-i18n="play_level.victory_sign_up") Sign Up to Save Progress + else if !showHourOfCodeDoneButton && showLeaderboard + button.btn.btn-illustrated.btn-warning.leaderboard-button.btn-lg(data-dismiss="modal", data-i18n="leaderboard.view_other_solutions") View Other Solutions + button.btn.btn-illustrated.btn-lg.btn-warning.hide#saving-progress-label(disabled, data-i18n="play_level.victory_saving_progress") Saving Progress .next-level-buttons diff --git a/app/templates/play/modal/leaderboard-modal.jade b/app/templates/play/modal/leaderboard-modal.jade new file mode 100644 index 000000000..68fe487f8 --- /dev/null +++ b/app/templates/play/modal/leaderboard-modal.jade @@ -0,0 +1,17 @@ +.modal-dialog + .modal-content + img(src="/images/pages/play/modal/game-menu-background.png", draggable="false")#leaderboard-background + + div#close-modal + span.glyphicon.glyphicon-remove + + ul#leaderboard-nav.nav.nav-pills.nav-stacked + for submenu, index in submenus + li(class=submenu === showTab ? "active" : "") + a(href='#' + submenu + '-view', data-toggle='tab') + span(data-i18n='leaderboard.' + submenu + '_tab') + + .tab-content.leaderboard-tab-content + for submenu, index in submenus + .tab-pane(id=submenu + '-view') + .leaderboard-tab-view \ No newline at end of file diff --git a/app/templates/play/modal/leaderboard-tab-view.jade b/app/templates/play/modal/leaderboard-tab-view.jade new file mode 100644 index 000000000..22234e73d --- /dev/null +++ b/app/templates/play/modal/leaderboard-tab-view.jade @@ -0,0 +1,2 @@ +div dis be da tab view for #{timespan} +span= Math.random() diff --git a/app/views/common/SearchView.coffee b/app/views/common/SearchView.coffee index e0b24a533..93ffa26ba 100644 --- a/app/views/common/SearchView.coffee +++ b/app/views/common/SearchView.coffee @@ -10,7 +10,7 @@ class SearchCollection extends Backbone.Collection @url += 'created,permissions' @url += ',' + projected for projected in projection else @url += 'true' - @url += "&term=#{term}" if @term + @url += "&term=#{@term}" if @term comparator: (a, b) -> score = 0 diff --git a/app/views/editor/modal/VersionsModal.coffee b/app/views/editor/modal/VersionsModal.coffee index d3e174947..8be2ca97c 100755 --- a/app/views/editor/modal/VersionsModal.coffee +++ b/app/views/editor/modal/VersionsModal.coffee @@ -12,7 +12,7 @@ class VersionsViewCollection extends CocoCollection initialize: (@url, @levelID, @model) -> super() - @url = url + @levelID + '/versions' + @url = @url + @levelID + '/versions' module.exports = class VersionsModal extends ModalView template: template diff --git a/app/views/play/CampaignView.coffee b/app/views/play/CampaignView.coffee index 5866e59b7..06697df26 100644 --- a/app/views/play/CampaignView.coffee +++ b/app/views/play/CampaignView.coffee @@ -11,6 +11,7 @@ MusicPlayer = require 'lib/surface/MusicPlayer' storage = require 'core/storage' AuthModal = require 'views/core/AuthModal' SubscribeModal = require 'views/core/SubscribeModal' +LeaderboardModal = require 'views/play/modal/LeaderboardModal' Level = require 'models/Level' utils = require 'core/utils' require 'vendor/three' @@ -205,6 +206,7 @@ module.exports = class CampaignView extends RootView for nextLevelOriginal in level.nextLevels ? [] if nextLevel = _.find(@campaign.renderedLevels, original: nextLevelOriginal) @createLine level.position, nextLevel.position + @showLeaderboard @options.justBeatLevel?.get('original') if (@options.showLeaderboard or true) @applyCampaignStyles() @testParticles() @@ -217,6 +219,12 @@ module.exports = class CampaignView extends RootView authModal.mode = 'signup' @openModalView authModal + showLeaderboard: (levelOriginal) -> + #levelOriginal ?= '5411cb3769152f1707be029c' # Testing: show Dungeons of Kithgard + levelOriginal ?= '541c9a30c6362edfb0f34479' # Testing: show Kithgard Gates + leaderboardModal = new LeaderboardModal supermodel: @supermodel, levelOriginal: levelOriginal + @openModalView leaderboardModal + determineNextLevel: (levels) -> foundNext = false for level in levels diff --git a/app/views/play/level/modal/HeroVictoryModal.coffee b/app/views/play/level/modal/HeroVictoryModal.coffee index d88760dae..ec4eec156 100644 --- a/app/views/play/level/modal/HeroVictoryModal.coffee +++ b/app/views/play/level/modal/HeroVictoryModal.coffee @@ -23,6 +23,7 @@ module.exports = class HeroVictoryModal extends ModalView events: 'click #continue-button': 'onClickContinue' + 'click .leaderboard-button': 'onClickLeaderboard' 'click .return-to-ladder-button': 'onClickReturnToLadder' 'click .sign-up-button': 'onClickSignupButton' @@ -145,6 +146,11 @@ module.exports = class HeroVictoryModal extends ModalView # Show the "I'm done" button between 30 - 120 minutes if they definitely came from Hour of Code c.showHourOfCodeDoneButton = me.get('hourOfCode') and showDone + lg = me.getLeaderboardsGroup() + c.showLeaderboard = lg is 'always' + c.showLeaderboard = true if me.level() >= 3 and lg.group is 'early' + c.showLeaderboard = true if me.level() >= 5 and lg.group is 'late' + return c afterRender: -> @@ -322,11 +328,18 @@ module.exports = class HeroVictoryModal extends ModalView link += '/' + nextCampaign unless nextCampaign is 'dungeon' link - onClickContinue: (e) -> + onClickContinue: (e, extraOptions=null) -> @playSound 'menu-button-click' nextLevelLink = @getNextLevelLink() # Preserve the supermodel as we navigate back to the world map. - Backbone.Mediator.publish 'router:navigate', route: nextLevelLink, viewClass: require('views/play/CampaignView'), viewArgs: [{supermodel: if @options.hasReceivedMemoryWarning then null else @supermodel}, @getNextLevelCampaign()] + options = + justBeatLevel: @level + supermodel: if @options.hasReceivedMemoryWarning then null else @supermodel + _.merge options, extraOptions if extraOptions + Backbone.Mediator.publish 'router:navigate', route: nextLevelLink, viewClass: require('views/play/CampaignView'), viewArgs: [options, @getNextLevelCampaign()] + + onClickLeaderboard: (e) -> + @onClickContinue e, showLeaderboard: true onClickReturnToLadder: (e) -> @playSound 'menu-button-click' diff --git a/app/views/play/modal/LeaderboardModal.coffee b/app/views/play/modal/LeaderboardModal.coffee new file mode 100644 index 000000000..b5e25f848 --- /dev/null +++ b/app/views/play/modal/LeaderboardModal.coffee @@ -0,0 +1,49 @@ +ModalView = require 'views/core/ModalView' +template = require 'templates/play/modal/leaderboard-modal' +LeaderboardTabView = require 'views/play/modal/LeaderboardTabView' + +module.exports = class LeaderboardModal extends ModalView + id: 'leaderboard-modal' + template: template + instant: true + timespans: ['day', 'week', 'all'] + + subscriptions: {} + + events: + 'shown.bs.tab #leaderboard-nav a': 'onTabShown' + 'click #close-modal': 'hide' + + constructor: (options) -> + super options + @levelOriginal = @options.levelOriginal + + + getRenderData: (c) -> + c = super c + c.submenus = @timespans + c.showTab = c.submenus[0] + c + + afterRender: -> + super() + for timespan, index in @timespans + submenuView = new LeaderboardTabView timespan: timespan, levelOriginal: @levelOriginal + @insertSubView submenuView, @$el.find "##{timespan}-view .leaderboard-tab-view" + if index is 0 + submenuView.$el.parent().addClass 'active' + submenuView.onShown?() + @playSound 'game-menu-open' + @$el.find('.nano:visible').nanoScroller() + + onTabShown: (e) -> + @playSound 'game-menu-tab-switch' + timespan = e.target.hash.substring(1).replace(/-view/g, '') + subview = _.find @subviews, timespan: timespan + subview.onShown?() + otherSubview.onHidden?() for subviewKey, otherSubview of @subviews when otherSubview isnt subview + + onHidden: -> + super() + subview.onHidden?() for subviewKey, subview of @subviews + @playSound 'game-menu-close' diff --git a/app/views/play/modal/LeaderboardTabView.coffee b/app/views/play/modal/LeaderboardTabView.coffee new file mode 100644 index 000000000..161a1280b --- /dev/null +++ b/app/views/play/modal/LeaderboardTabView.coffee @@ -0,0 +1,27 @@ +CocoView = require 'views/core/CocoView' +template = require 'templates/play/modal/leaderboard-tab-view' + +module.exports = class LeaderboardTabView extends CocoView + template: template + className: 'leaderboard-tab-view' + helpVideoHeight: '295' + helpVideoWidth: '471' + + events: + 'click .start-subscription-button': "clickSubscribe" + + constructor: (options) -> + super options + @timespan = @options.timespan + @levelOriginal = @options.levelOriginal + + destroy: -> + super() + + getRenderData: -> + c = super() + c.timespan = @timespan + c + + afterRender: -> + super()