diff --git a/design/pages.graffle b/design/pages.graffle index 47e89f39c..52d8de4d3 100644 Binary files a/design/pages.graffle and b/design/pages.graffle differ diff --git a/src/coffee/constants.coffee b/src/coffee/constants.coffee index eee1bdd3b..a61a8ddbe 100644 --- a/src/coffee/constants.coffee +++ b/src/coffee/constants.coffee @@ -37,32 +37,45 @@ Duration.fast = 200 Duration.normal = 400 Duration.slow = 1200 -exports.Event = Event = {} -Event.add = 'add' # collection, item... -Event.change = 'change' # model -Event.click = 'click' # event -Event.load = {} -Event.load.started = 'load:started' # controller, url -Event.load.succeeded = 'load:succeeded' # controller, book -Event.load.failed = 'load:failed' # controller, error message -Event.load.finished = 'load:finished' # controller -Event.remove = 'remove' # collection, item... -Event.request = 'request' # model -Event.route = 'route' -Event.sort = 'sort' -Event.sync = 'sync' # model, response -Event.transitionEnd = (-> +exports.Event = Event = {} +Event.add = 'add' # collection, item... +Event.animate = {} +Event.animate.hide = {} +Event.animate.hide.start = 'animate:hide:start' # controller, selector +Event.animate.hide.finish = 'animate:hide:finish' # controller, selector +Event.animate.show = {} +Event.animate.show.start = 'animate:show:start' # controller, selector +Event.animate.show.finish = 'animate:show:finish' # controller, selector +Event.button = {} +Event.button.complete = 'button:complete' # controller +Event.button.first = 'button:first' # controller, buttonType +Event.button.second = 'button:second' # controller, buttonType +Event.change = 'change' # model +Event.click = 'click' # event +Event.load = {} +Event.load.started = 'load:started' # controller, url +Event.load.succeeded = 'load:succeeded' # controller, book +Event.load.failed = 'load:failed' # controller, error message +Event.load.finished = 'load:finished' # controller +Event.remove = 'remove' # collection, item... +Event.request = 'request' # model +Event.route = 'route' +Event.sort = 'sort' +Event.sync = 'sync' # model, response +Event.transitionEnd = (-> return unless document? transitions = - 'transition': 'transitionend', - 'OTransition': 'oTransitionEnd', - 'MSTransition': 'msTransitionEnd', - 'MozTransition': 'transitionend', 'WebkitTransition': 'webkitTransitionEnd' + 'MozTransition': 'transitionend' + 'MSTransition': 'msTransitionEnd' + 'OTransition': 'oTransitionEnd' + 'transition': 'transitionend' el = document.createElement 'fakeelement' for styleName, eventName of transitions return eventName if el.style[styleName]? + + throw new Error 'cannot determine transitionEnd event' )() exports.Key = Key = {} diff --git a/src/coffee/controllers/base_controller.coffee b/src/coffee/controllers/base_controller.coffee index 2aa43fbec..52b22a748 100644 --- a/src/coffee/controllers/base_controller.coffee +++ b/src/coffee/controllers/base_controller.coffee @@ -5,22 +5,22 @@ Copyright (c) 2014-2015 by Redwood Labs All rights reserved. ### -views = require '../views' -{Event} = require '../constants' +views = require '../views' +{Duration} = require '../constants' +{Event} = require '../constants' ######################################################################################################################## module.exports = class BaseController extends Backbone.View constructor: (options={})-> - options.useAnimations ?= true @tryRefresh = _.debounce @_tryRefresh, 100 - @_model = null - @_rendered = false - @_parent = options.parent @_children = [] - @_useAnimations = options.useAnimations + @_model = null + @_parent = options.parent + @_rendered = false + @_useAnimations = options.useAnimations ?= true @_loadTemplate options.templateName super options @@ -36,33 +36,39 @@ module.exports = class BaseController extends Backbone.View @_children.push child return child - hide: (args...)-> - {$el, callback} = @_resolveShowHideArgs args + hide: ($el)-> + $el ?= @$el - $el.addClass 'hideable' unless $el.hasClass 'hideable' + if not $el.hasClass 'hideable' + $el.addClass 'hideable' + _.defer => @hide $el + return - logger.verbose => "#{this} is hiding #{$el.selector}" - if $el.hasClass('hiding') or $el.hasClass('hidden') - _.defer => callback this - else - $el.off Event.transitionEnd - $el.one Event.transitionEnd, => + if not ($el.hasClass('hiding') or $el.hasClass('hidden')) + logger.verbose => "#{this} is hiding \"#{$el.selector}\"" + @_onAnimationComplete $el, Duration.normal, => $el.addClass 'hidden' $el.removeClass 'hiding' - callback this + logger.verbose => "#{this} is finished hiding #{$el.selector}" + @trigger Event.animate.hide.finish, this, $el $el.addClass 'hiding' + @trigger Event.animate.hide.start, this, $el refresh: -> logger.verbose => "#{this} refreshing" remove: -> if @_useAnimations - @hide => + logger.verbose => "#{this} is hiding element before removing it" + @once Event.animate.hide.finish, => logger.verbose => "#{this} is removing its element from the DOM" @$el.remove() + @off() + @hide() else @$el.remove() + @off() routeLinkClick: (event)-> event.preventDefault() @@ -75,19 +81,22 @@ module.exports = class BaseController extends Backbone.View else router.navigate href, trigger:true - show: (args...)-> - {$el, callback} = @_resolveShowHideArgs args + show: ($el)-> + $el ?= @$el + $el.addClass 'hideable' - $el.addClass 'hideable' unless $el.hasClass 'hideable' + if $el.hasClass('hidden') or $el.hasClass('hiding') + logger.verbose => "#{this} is showing \"#{$el.selector}\"" - logger.verbose => "#{this} is showing #{$el.selector}" - if $el.hasClass('hiding') or $el.hasClass('hidden') - $el.off Event.transitionEnd - $el.one Event.transitionEnd, => callback this - $el.removeClass 'hiding' + @_onAnimationComplete $el, Duration.normal, => + logger.verbose => "#{this} is finished showing #{$el.selector}" + @trigger Event.animate.show.finish, this, $el + + $el.addClass 'hiding' $el.removeClass 'hidden' - else - _.defer => callback this + _.defer => + $el.removeClass 'hiding' + @trigger Event.animate.show.start, this, $el unrender: -> @undelegateEvents() @@ -164,14 +173,12 @@ module.exports = class BaseController extends Backbone.View $renderedEl = $($(@_template(data))[0]) @onWillRender() - @hide() if @_useAnimations - @unrender() + @$el.append $renderedEl.children() @$el.addClass $renderedEl.attr 'class' @$el.data $renderedEl.data() @delegateEvents() - @show() if options.show and @_useAnimations @_rendered = true @onDidRender() @@ -189,19 +196,20 @@ module.exports = class BaseController extends Backbone.View if templateName? @_template = views[templateName] - _resolveShowHideArgs: (args)-> - if args.length is 0 - return $el:@$el, callback:-> - else if args.length is 1 - if _.isFunction args[0] - return $el:@$el, callback:args[0] - else - return $el:args[0], callback:-> - else if args.length is 2 - return $el:args[0], callback:args[1] - else - throw new Error "expected to get 0, 1, or 2 args" - _tryRefresh: -> return unless @_rendered @refresh() + + _onAnimationComplete: ($el, maxDuration, callback)-> + $el ?= @$el + maxDuration ?= Duration.slow + callback ?= -> # do nothing + + $el.off Event.transitionEnd + $el.one Event.transitionEnd, callback + + # One would very much like this not to be necessary, but because of the way CSS transitions work, they are + # frequently not triggered. Rather than try to avoid the multitude of corner cases where this can happen, this + # simply sets a timer to ensure the event does eventually trigger. Since we're only listening for the first + # event, if the transition end event *did* happen, then this is a no-op. -- Andrew 2015-04-18 + setTimeout (-> $el.trigger Event.transitionEnd), maxDuration diff --git a/src/coffee/controllers/craft_page_controller.coffee b/src/coffee/controllers/craft_page_controller.coffee index 5e0b4e894..64df883b7 100644 --- a/src/coffee/controllers/craft_page_controller.coffee +++ b/src/coffee/controllers/craft_page_controller.coffee @@ -5,17 +5,13 @@ Copyright (c) 2014-2015 by Redwood Labs All rights reserved. ### -CraftingTableController = require './crafting_table_controller' -CraftPage = require '../models/craft_page' -{Event} = require '../constants' -ImageLoader = require './image_loader' -InventoryController = require './inventory_controller' -ModPackController = require './mod_pack_controller' -NameFinder = require '../models/name_finder' -PageController = require './page_controller' -Storage = require '../models/storage' -{Text} = require '../constants' -{Url} = require '../constants' +AdsenseController = require './adsense_controller' +CraftPage = require '../models/craft_page' +InventoryController = require './inventory_controller' +PageController = require './page_controller' +StepController = require './step_controller' +{Event} = require '../constants' +{Url} = require '../constants' ######################################################################################################################## @@ -24,20 +20,56 @@ module.exports = class CraftPageController extends PageController constructor: (options={})-> if not options.imageLoader? then throw new Error 'options.imageLoader is required' if not options.modPack? then throw new Error 'options.modPack is required' + if not options.storage? then throw new Error 'options.storage is required' - options.model ?= new CraftPage modPack:options.modPack - options.storage ?= new Storage storage:window.localStorage - options.templateName = 'craft_page' + options.model ?= new CraftPage modPack:options.modPack + options.templateName = 'craft_page' super options @imageLoader = options.imageLoader @modPack = options.modPack @storage = options.storage + @model.plan.on Event.change, => @refresh() + # Event Methods ################################################################################ - onToolsBoxToggled: -> - @model.plan.includingTools = @$('.includeTools:checked').length isnt 0 + onCraftTool: (itemSlug)-> + # TODO: implement this + + onHaveInventoryChanged: -> + @storage.store 'crafting-plan:have', @model.plan.have.unparse() + + onMoveNeedToHave: (itemSlug)-> + quantity = @model.plan.need.quantityOf itemSlug + @model.plan.have.add itemSlug, quantity + @_saveHaveInventory() + + onRemoveFromHaveInventory: (itemSlug)-> + @model.plan.have.remove itemSlug + @onHaveInventoryChanged() + + onRemoveFromWant: (itemSlug)-> + @model.plan.want.remove itemSlug + @onWantInventoryChange() + + onStopUsingTool: (itemSlug)-> + # TODO: implement this + + onStepComplete: (stepController)-> + step = stepController.model + for stack in step.recipe.output + @model.plan.have.add stack.itemSlug, stack.quantity * step.multiplier + @onHaveInventoryChanged() + + onWantInventoryChange: -> + text = @model.plan.want.unparse() + url = Url.crafting inventoryText:text + router.navigate url + + if @model.plan.want.isEmpty + @model.plan.have.clear() + @onHaveInventoryChanged() # PageController Overrides ##################################################################### @@ -46,69 +78,105 @@ module.exports = class CraftPageController extends PageController # BaseController Overrides ##################################################################### + onDidRender: -> + @adsenseController = @addChild AdsenseController, '.view__adsense', model:'sidebar_skyscraper' + + @wantInventoryController = @addChild InventoryController, '.want .view__inventory', + imageLoader: @imageLoader + isAcceptable: (item)=> item.isCraftable + model: @model.plan.want + modPack: @modPack + firstButtonType: 'remove' + @wantInventoryController.on Event.button.first, (c, s)=> @onRemoveFromWant(s) + @wantInventoryController.on Event.change, (c)=> @onWantInventoryChange() + + # @toolsInUseController = @addChild InventoryController, '.tools .view__inventory', + # imageLoader: @imageLoader + # model: @model.plan.toolsInUse + # modPack: @modPack + # firstButtonType: 'down' + # secondButtonType: 'up' + # @toolsInUseController.on Event.button.first, (c, s)=> @onStopUsingTool(s) + # @toolsInUseController.of Event.button.second, (c, s)=> @onCraftTool(s) + + @haveInventoryController = @addChild InventoryController, '.have .view__inventory', + imageLoader: @imageLoader + model: @model.plan.have + modPack: @modPack + firstButtonType: 'down' + @haveInventoryController.on Event.button.first, (c, s)=> + @onRemoveFromHaveInventory(s) + @haveInventoryController.on Event.change, (c)=> @onHaveInventoryChanged() + + @needInventoryController = @addChild InventoryController, '.need .view__inventory', + editable: false + imageLoader: @imageLoader + model: @model.plan.need + modPack: @modPack + firstButtonType: 'up' + @needInventoryController.on Event.button.first, (c, s)=> @onMoveNeedToHave(s) + + @$instructionsSection = @$('.instructions.section') + @$makeSection = @$('.make.section') + @$toolsSection = @$('.tools.section') + @$ingredientsSection = @$('.ingredients.section') + @$stepsSection = @$('.steps.section') + @$stepsContainer = @$('.steps.section .panel') + + super + onWillRender: -> - @storage.register 'crafting-plan', @model.plan, 'includingTools' @model.plan.have.clear() @model.plan.have.parse @storage.load('crafting-plan:have') super - onDidRender: -> - @wantController = @addChild InventoryController, '.want', - editable: true - icon: '/images/fishing_rod.png' - imageLoader: @imageLoader - isAcceptable: (item)-> item.isCraftable - model: @model.plan.want - modPack: @model.modPack - onChange: => @_updateLocation() - title: 'Items you want' - - @haveController = @addChild InventoryController, '.have', - editable: true, - imageLoader: @imageLoader - model: @model.plan.have - modPack: @model.modPack - onChange: => @_saveHaveInventory() - title: 'Items you have' - - @needController = @addChild InventoryController, '.need', - editable: false - icon: '/images/boots.png' - imageLoader: @imageLoader - model: @model.plan.need - modPack: @model.modPack - title: "Items you'll need" - - @craftingTableController = @addChild CraftingTableController, '.view__crafting_table', - imageLoader: @imageLoader - model: @model.table - modPack: @model.modPack - - @$('.want .toolbar').append '' - @$includeToolsBox = @$('.includeTools') - - super - refresh: -> - if @model.plan.includingTools - @$includeToolsBox.attr 'checked', 'checked' - else - @$includeToolsBox.removeAttr 'checked' - + @_refreshSectionVisibility() + @_refreshSteps() super - # Backbone.View Overrides ###################################################################### + # Backbone.View Overrides ######################################################################## events: -> return _.extend super, - 'change .includeTools': 'onToolsBoxToggled' + 'click .instructions a': 'routeLinkClick' - # Private Methods ############################################################################## + # Private Methods ################################################################################ - _saveHaveInventory: -> - @storage.store 'crafting-plan:have', @model.plan.have.unparse() + _isStepCompletable: (controller)-> + return not @model.plan.want.hasAtLeast controller.model.outputItemSlug - _updateLocation: -> - text = @model.plan.want.unparse() - url = Url.crafting inventoryText:text - router.navigate url + _refreshSectionVisibility: -> + if @model.plan.want.isEmpty + for $el in [@$toolsSection, @$ingredientsSection, @$stepsSection] + @hide $el + @show @$instructionsSection + else + for $el in [@$toolsSection, @$ingredientsSection, @$stepsSection] + @show $el + @hide @$instructionsSection + + _refreshSteps: -> + @_stepControllers ?= [] + index = 0 + + for step in @model.plan.steps + controller = @_stepControllers[index] + if not controller? + controller = new StepController + canComplete: (controller)=> @_isStepCompletable(controller) + imageLoader: @imageLoader + model: step + modPack: @modPack + controller.on Event.button.complete, (c)=> @onStepComplete(c) + controller.render() + + @$stepsContainer.append controller.$el + @_stepControllers.push controller + else + controller.model = step + + index += 1 + + while @_stepControllers.length > index + @_stepControllers.pop().remove() diff --git a/src/coffee/controllers/header_controller.coffee b/src/coffee/controllers/header_controller.coffee index 4eaf010e8..3507cced5 100644 --- a/src/coffee/controllers/header_controller.coffee +++ b/src/coffee/controllers/header_controller.coffee @@ -81,7 +81,7 @@ module.exports = class HeaderController extends BaseController addThisUrl = '//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-54f3c9717b2e530d' $('body').append "" - @_itemSelector = @addChild ItemSelectorController, '.view__item_selector', + @_itemSelector = @addChild ItemSelectorController, '.view__item_selector.search', modPack: @modPack onChoseItem: (itemSlug)=> @_goToItem(itemSlug) diff --git a/src/coffee/controllers/inventory_controller.coffee b/src/coffee/controllers/inventory_controller.coffee index 1d7c9ee92..af038f077 100644 --- a/src/coffee/controllers/inventory_controller.coffee +++ b/src/coffee/controllers/inventory_controller.coffee @@ -16,6 +16,14 @@ StackController = require './stack_controller' ######################################################################################################################## +### +Events: + clear(this) + change(this) + add(this, itemSlug) + button:first(this, itemSlug) + button:second(this, itemSlug) +### module.exports = class InventoryController extends BaseController @MAX_QUANTITY = 9999 @@ -27,13 +35,16 @@ module.exports = class InventoryController extends BaseController if not options.model? then throw new Error 'options.model is required' if not options.modPack? then throw new Error 'options.modPack is required' - @editable = options.editable ?= true - @icon = options.icon ?= '/images/chest_front.png' - @imageLoader = options.imageLoader - @isAcceptable = options.isAcceptable ?= null - @modPack = options.modPack - @onChange = options.onChange ?= -> # do nothing - @title = options.title ?= 'Inventory' + @imageLoader = options.imageLoader + @modPack = options.modPack + + @editable = options.editable ?= true + @icon = options.icon ?= '/images/chest_front.png' + @firstButtonType = options.firstButtonType ?= null + @isAcceptable = options.isAcceptable ?= null + @secondButtonType = options.secondButtonType ?= null + @shouldEnableButton = options.shouldEnableButton ?= (model, button)-> true + @title = options.title ?= 'Inventory' options.templateName = 'inventory' super options @@ -46,11 +57,19 @@ module.exports = class InventoryController extends BaseController onClearButtonClicked: -> @model.clear() - @onChange() + @trigger Event.clear, this + @trigger Event.change, this + + onFirstButtonClicked: (stackController)-> + @trigger Event.button.first, this, stackController?.model?.itemSlug onItemChosen: (itemSlug)-> @model.add itemSlug, 1 - @onChange() + @trigger Event.add, this, itemSlug + @trigger Event.change, this + + onSecondButtonClicked: (stackController)-> + @trigger Event.button.second, this, stackController?.model?.itemSlug # BaseController Overrides ##################################################################### @@ -60,32 +79,23 @@ module.exports = class InventoryController extends BaseController modPack: @modPack, onChoseItem: (itemSlug)=> @onItemChosen(itemSlug) - @$clearButton = @$('button[name="clear"]') + @$clearButton = @$('button.clear') @$icon = @$('.icon') - @$editPanel = @$('.edit') - @$scrollbox = @$('.scrollbox') - @$table = @$('table') - @$toolbar = @$('.toolbar') + @$itemContainer = @$('.item_container') @$title = @$('h2 p') super refresh: -> if @editable - @show @$editPanel - @show @$toolbar, => - @$scrollbox.css bottom:@$toolbar.height() + @selector.show() else - if not @$editPanel? then throw new Error "no edit panel" - if not @$toolbar? then throw new Error "no toolbar" - @hide @$editPanel - @hide @$toolbar - @$scrollbox.css bottom:0 + @selector.hide() @$icon.attr 'src', @icon @$title.html @title + @$clearButton.disabled = @model.isEmpty @_refreshStacks() - @_refreshButtonState() super @@ -93,38 +103,37 @@ module.exports = class InventoryController extends BaseController events: -> return _.extend super, - 'click button[name="clear"]': 'onClearButtonClicked' + 'click button.clear': 'onClearButtonClicked' + 'click button.first': 'onFirstButtonClicked' + 'click button.second': 'onSecondButtonClicked' # Private Methods ############################################################################## - _refreshButtonState: -> - if @model.isEmpty then @$clearButton.attr('disabled', 'disabled') else @$clearButton.removeAttr('disabled') - _refreshStacks: -> @_stackControllers ?= [] index = 0 - $lastRow = @$table.find 'tr:last-child' @model.each (stack)=> controller = @_stackControllers[index] if not controller? controller = new StackController - editable: @editable - imageLoader: @imageLoader - model: stack - modPack: @modPack - onChange: @onChange - onRemove: if not @editable then null else (stack)=> @_removeStack(stack) + editable: @editable + firstButtonType: @firstButtonType + imageLoader: @imageLoader + model: stack + modPack: @modPack + secondButtonType: @secondButtonType + shouldEnableButton: @shouldEnableButton + controller.on Event.change, => @trigger Event.change, this + controller.on Event.button.first, (c)=> @onFirstButtonClicked(c) + controller.on Event.button.second, (c)=> @onSecondButtonClicked(c) + controller.render() @_stackControllers.push controller - controller.$el.insertBefore $lastRow - controller.render() + @$itemContainer.append controller.$el else controller.model = stack index += 1 while @_stackControllers.length > index @_stackControllers.pop().remove() - - _removeStack: (stack)-> - @model.remove stack.itemSlug, stack.quantity diff --git a/src/coffee/controllers/item_group_controller.coffee b/src/coffee/controllers/item_group_controller.coffee index 2210c9872..be11c7238 100644 --- a/src/coffee/controllers/item_group_controller.coffee +++ b/src/coffee/controllers/item_group_controller.coffee @@ -65,7 +65,6 @@ module.exports = class ItemGroupController extends BaseController _refreshItems: -> @_itemControllers ?= [] controllerIndex = 0 - delay = 0 for item in @model controller = @_itemControllers[controllerIndex] diff --git a/src/coffee/controllers/minimal_recipe_controller.coffee b/src/coffee/controllers/minimal_recipe_controller.coffee index 7d7ab0c8f..b6067c608 100644 --- a/src/coffee/controllers/minimal_recipe_controller.coffee +++ b/src/coffee/controllers/minimal_recipe_controller.coffee @@ -24,6 +24,7 @@ module.exports = class MinimalRecipeController extends BaseController @imageLoader = options.imageLoader @modPack = options.modPack + @multiplier = options.multiplier ?= null # BaseController Overrides ##################################################################### @@ -36,6 +37,7 @@ module.exports = class MinimalRecipeController extends BaseController imageLoader: @imageLoader modPack: @modPack + @$multiplier = @$('.multiplier') @$outputImg = @$('.output img') @$outputLink = @$('.output a') @$outputQuantity = @$('.quantity') @@ -46,6 +48,8 @@ module.exports = class MinimalRecipeController extends BaseController @gridController.model = @model @outputSlotController.model = @model?.output?[0] @$el.tooltip show:{delay:Duration.snap, duration:Duration.fast} + + @_refreshMultiplier() @_refreshTools() super @@ -57,6 +61,12 @@ module.exports = class MinimalRecipeController extends BaseController # Private Methods ############################################################################## + _refreshMultiplier: -> + if @multiplier? and @multiplier > 1 + @$multiplier.html "x#{@multiplier}" + else + @$multiplier.html '' + _refreshTools: -> @$toolContainer.empty() return unless @model? diff --git a/src/coffee/controllers/mod_page_controller.coffee b/src/coffee/controllers/mod_page_controller.coffee index f036d78a9..68a7f5198 100644 --- a/src/coffee/controllers/mod_page_controller.coffee +++ b/src/coffee/controllers/mod_page_controller.coffee @@ -159,7 +159,7 @@ module.exports = class ModPageController extends PageController @$tutorialsContainer.append controller.$el controller.render() else - controller.model = model + controller.model = tutorial index += 1 diff --git a/src/coffee/controllers/stack_controller.coffee b/src/coffee/controllers/stack_controller.coffee index 81fd7d978..840c600a1 100644 --- a/src/coffee/controllers/stack_controller.coffee +++ b/src/coffee/controllers/stack_controller.coffee @@ -6,13 +6,20 @@ All rights reserved. ### BaseController = require './base_controller' +ImageLoader = require './image_loader' {Duration} = require '../constants' {Event} = require '../constants' -ImageLoader = require './image_loader' {Key} = require '../constants' ######################################################################################################################## +### +Events: + change(this) + change:quantity(this, oldQuantity, newQuantity) + button:first(this, type) + button:second(this, type) +### module.exports = class StackController extends BaseController @MAX_QUANTITY = 9999 @@ -22,60 +29,67 @@ module.exports = class StackController extends BaseController if not options.model? then throw new Error 'options.model is required' if not options.modPack? then throw new Error 'options.modPack is required' - options.editable ?= false - options.onChange ?= -> # do nothing - options.onRemove ?= (stack)-> # do nothing - options.tagName = 'tr' options.templateName = 'stack' super options - @editable = options.editable - @modPack = options.modPack - @onChange = options.onChange - @onRemove = options.onRemove - @_imageLoader = options.imageLoader + @editable = options.editable ?= false + @firstButtonType = options.firstButtonType ?= null + @imageLoader = options.imageLoader + @modPack = options.modPack + @secondButtonType = options.secondButtonType ?= null + @shouldEnableButton = options.shouldEnableButton ?= (model, button)-> true @modPack.on Event.change, => @tryRefresh() # Event Methods ################################################################################ + onFirstButtonClicked: (event)-> + @trigger Event.button.first, this, @firstButtonType + return false + onQuantityFieldBlur: -> return unless @editable + @$bubble.removeClass 'editing' + + oldQuantity = @_priorValue quantityText = @$quantityField.val().trim() if quantityText.length is 0 - quantity = @_priorValue + newQuantity = oldQuantity else if not quantityText.match /^[0-9]*$/ - quantity = 1 + newQuantity = 1 else - quantity = parseInt quantityText, 10 - if _.isNaN quantity then quantity = 1 + newQuantity = parseInt quantityText, 10 + if _.isNaN newQuantity then newQuantity = 1 - quantity = Math.min quantity, StackController.MAX_QUANTITY - quantity = Math.max 1, quantity + newQuantity = Math.min newQuantity, StackController.MAX_QUANTITY + newQuantity = Math.max 1, newQuantity - if quantity? - @$quantityField.val "#{quantity}" - @$quantityField.removeClass 'error', Duration.snap - @$quantityField.removeClass 'error-new', Duration.snap + if newQuantity? and newQuantity isnt oldQuantity + @$quantityField.val "#{newQuantity}" + @$bubble.removeClass 'error', Duration.snap + @$bubble.removeClass 'error-new', Duration.snap - @model.quantity = quantity - @onChange() + @model.quantity = newQuantity + @trigger Event.change + ':quantity', this, oldQuantity, newQuantity + @trigger Event.change, this onQuantityFieldChanged: -> return unless @editable quantityText = @$quantityField.val().trim() if not quantityText.match /^[0-9]*$/ - @$quantityField.addClass 'error', 0 - @$quantityField.addClass 'error-new', 0 - @$quantityField.removeClass 'error-new', Duration.fast + @$bubble.addClass 'error', 0 + @$bubble.addClass 'error-new', 0 + @$bubble.removeClass 'error-new', Duration.fast else - @$quantityField.removeClass 'error', Duration.snap - @$quantityField.removeClass 'error-new', Duration.snap + @$bubble.removeClass 'error', Duration.snap + @$bubble.removeClass 'error-new', Duration.snap onQuantityFieldFocused: -> + if @editable + @$bubble.addClass 'editing' @_priorValue = @model.quantity @$quantityField.val '' else @@ -87,18 +101,20 @@ module.exports = class StackController extends BaseController if event.which is Key.Return @$quantityField.blur() - onRemoveClicked: -> - @onRemove @model - @onChange() + onSecondButtonClicked: (event)-> + event.preventDefault() + @trigger Event.button.second, this, @secondButtonType # BaseController Overrides ##################################################################### onDidRender: -> @$action = @$('.action') + @$bubble = @$('.bubble') + @$firstButton = @$('button.first') @$image = @$('.icon img') @$nameLink = @$('.name a') @$quantityField = @$('.quantity input') - @$removeButton = @$('button.remove') + @$secondButton = @$('button.second') super refresh: -> @@ -106,19 +122,23 @@ module.exports = class StackController extends BaseController display = @modPack.findItemDisplay @model.itemSlug - @_imageLoader.load display.iconUrl, @$image + @imageLoader.load display.iconUrl, @$image @$nameLink.html display.itemName @$nameLink.attr 'href', display.itemUrl @$quantityField.val @model.quantity + @_updateButtonType @$firstButton, @firstButtonType + @_updateButtonType @$secondButton, @secondButtonType + + @$firstButton.prop('disabled', not @shouldEnableButton(@model, 1)) if @firstButtonType? + @$secondButton.prop('disabled', not @shouldEnableButton(@model, 2)) if @secondButtonType? + if @editable @$quantityField.removeAttr 'readonly' - @$quantityField.addClass 'editable' + @$bubble.addClass 'editable' else @$quantityField.attr 'readonly', 'readonly' - @$quantityField.removeClass 'editable' - - @$action.css display:(if @editable then 'table-cell' else 'none') + @$bubble.removeClass 'editable' super @@ -127,8 +147,21 @@ module.exports = class StackController extends BaseController events: -> return _.extend super, 'blur .quantity input': 'onQuantityFieldBlur' - 'click button.remove': 'onRemoveClicked' 'click .name a': 'routeLinkClick' + 'click button.first': 'onFirstButtonClicked' + 'click button.second': 'onSecondButtonClicked' 'focus .quantity input': 'onQuantityFieldFocused' 'input .quantity input': 'onQuantityFieldChanged' 'keyup .quantity input': 'onQuantityKeyUp' + + # Private Methods ############################################################################## + + _updateButtonType: ($button, type)-> + for currentType in ['check', 'down', 'remove', 'up'] + $button.removeClass currentType + + if type? + $button.css 'display', null + $button.addClass type + else + $button.css 'display', 'none' diff --git a/src/coffee/controllers/step_controller.coffee b/src/coffee/controllers/step_controller.coffee new file mode 100644 index 000000000..91fa73093 --- /dev/null +++ b/src/coffee/controllers/step_controller.coffee @@ -0,0 +1,75 @@ +### +Crafting Guide - step_controller.coffee + +Copyright (c) 2015 by Redwood Labs +All rights reserved. +### + +BaseController = require './base_controller' +InventoryController = require './inventory_controller' +MinimalRecipeController = require './minimal_recipe_controller' +{Event} = require '../constants' + +######################################################################################################################## + +module.exports = class StepController extends BaseController + + constructor: (options={})-> + if not options.model? then throw new Error 'options.model is required' + if not options.modPack? then throw new Error 'options.modPack is required' + if not options.imageLoader? then throw new Error 'options.imageLoader is required' + options.templateName = 'step' + super options + + @canComplete = options.canComplete or (controller)-> true + @imageLoader = options.imageLoader + @modPack = options.modPack + + # Event Methods ################################################################################ + + onCompleteButtonClicked: (event)-> + event.preventDefault() + @trigger Event.button.complete, this + + # BaseController Overrides ##################################################################### + + onDidRender: -> + @inventoryController = @addChild InventoryController, '.view__inventory', + editable: false + imageLoader: @imageLoader + model: @model.inventory + modPack: @modPack + + @recipeController = @addChild MinimalRecipeController, '.view__minimal_recipe', + imageLoader: @imageLoader + model: @model.recipe + modPack: @modPack + + @$header = @$('h3') + @$completeButton = @$('button.complete') + super + + onWillChangeModel: (oldModel, newModel)-> + if not newModel? then throw new Error 'model cannot be null' + return super + + refresh: -> + itemDisplay = @modPack.findItemDisplay @model.outputItemSlug + @$header.html "#{@model.number}. #{itemDisplay.itemName}" + + @inventoryController.model = @model.inventory + @recipeController.model = @model.recipe + @recipeController.multiplier = @model.multiplier + + if @canComplete(this) + @$completeButton.removeProp 'disabled' + else + @$completeButton.prop 'disabled', true + + super + + # Backbone.View Overrides ###################################################################### + + events: -> + return _.extend super, + 'click button.complete': 'onCompleteButtonClicked' diff --git a/src/coffee/crafting_guide_router.coffee b/src/coffee/crafting_guide_router.coffee index 9c61c4821..ba4770cca 100644 --- a/src/coffee/crafting_guide_router.coffee +++ b/src/coffee/crafting_guide_router.coffee @@ -224,9 +224,11 @@ module.exports = class CraftingGuideRouter extends Backbone.Router controller.onWillShow() controller.$el = $pageContent controller.render() + controller.show() if @_controller? - @_controller.hide -> switchToNextController() + @_controller.once Event.animate.hide.finish, switchToNextController + @_controller.hide() else switchToNextController() diff --git a/src/coffee/models/craft_page.coffee b/src/coffee/models/craft_page.coffee index 2fafb162d..403e58825 100644 --- a/src/coffee/models/craft_page.coffee +++ b/src/coffee/models/craft_page.coffee @@ -25,6 +25,7 @@ module.exports = class CraftPage extends BaseModel @modPack.on Event.change, => @_consumeParams() @on Event.change + ':params', => @_consumeParams() + @plan.on Event.change, => @trigger Event.change, this # Private Methods ############################################################################## diff --git a/src/coffee/models/crafting_plan.coffee b/src/coffee/models/crafting_plan.coffee index 693ead03f..5c6b49114 100644 --- a/src/coffee/models/crafting_plan.coffee +++ b/src/coffee/models/crafting_plan.coffee @@ -6,9 +6,10 @@ All rights reserved. ### BaseModel = require './base_model' -{Event} = require '../constants' Inventory = require './inventory' ItemSlug = require './item_slug' +Step = require './step' +{Event} = require '../constants' ######################################################################################################################## @@ -26,7 +27,7 @@ module.exports = class CraftingPlan extends BaseModel recraft = _.debounce (=> @craft()), 100 for inventory in [@have, @want] - inventory.on 'change', recraft + inventory.on Event.change, recraft @on Event.change + ':includingTools', recraft @@ -140,7 +141,7 @@ module.exports = class CraftingPlan extends BaseModel @_findSteps inputStack.itemSlug, parentSteps logger.verbose -> "adding step for: #{recipe.slug}" - @steps[recipe.slug] = recipe:recipe, itemSlug:item.slug + @steps[recipe.slug] = new Step outputItemSlug:item.slug, recipe:recipe foundValidRecipe = true break catch error @@ -166,16 +167,26 @@ module.exports = class CraftingPlan extends BaseModel return itemSlug _removeExtraSteps: -> - result = (step for step in @steps when step.multiplier > 0) + result = [] + + number = 1 + for step in @steps + if step.multiplier > 0 + result.push step + step.number = number + number += 1 + @steps = result _resolveNeeds: -> for i in [@steps.length-1..0] by -1 step = @steps[i] - recipe = step.recipe - outputQuantity = recipe.getQuantityProducedOf step.itemSlug + step.number = i + 1 - step.multiplier = Math.ceil(@need.quantityOf(step.itemSlug) / outputQuantity) + recipe = step.recipe + outputQuantity = recipe.getQuantityProducedOf step.outputItemSlug + + step.multiplier = Math.ceil(@need.quantityOf(step.outputItemSlug) / outputQuantity) if @includingTools recipe.eachToolStack (stack)=> diff --git a/src/coffee/models/inventory.coffee b/src/coffee/models/inventory.coffee index 720195b2d..b6cda2e9d 100644 --- a/src/coffee/models/inventory.coffee +++ b/src/coffee/models/inventory.coffee @@ -20,9 +20,6 @@ module.exports = class Inventory extends BaseModel attributes.modPack ?= null @clear() - Object.defineProperties this, - isEmpty: { get:-> @_itemSlugs.length is 0 } - # Class Methods ################################################################################ @Delimiters = @@ -161,6 +158,14 @@ module.exports = class Inventory extends BaseModel return parts.join Inventory.Delimiters.Stack + # Property Methods ############################################################################# + + getIsEmpty: -> + return @_itemSlugs.length is 0 + + Object.defineProperties @prototype, + isEmpty: { get:@prototype.getIsEmpty } + # Object Overrides ############################################################################# toString: -> @@ -185,7 +190,7 @@ module.exports = class Inventory extends BaseModel stack = @_stacks[itemSlug] if not stack? stack = new Stack itemSlug:itemSlug, quantity:quantity - @listenTo stack, Event.change, => @trigger Event.change, stack + @listenTo stack, Event.change, => @trigger Event.change, this @_stacks[itemSlug] = stack @_itemSlugs.push itemSlug @_sort() diff --git a/src/coffee/models/item_selector.coffee b/src/coffee/models/item_selector.coffee index 38da50ab0..daaa28601 100644 --- a/src/coffee/models/item_selector.coffee +++ b/src/coffee/models/item_selector.coffee @@ -14,7 +14,7 @@ module.exports = class ItemSelector extends BaseModel constructor: (attributes={}, options={})-> if not options.modPack? then throw new Error 'options.modPack is required' - options.isAcceptable ?= (itemSlug)-> return true # accept everything by default + options.isAcceptable ?= (item)-> return true # accept everything by default super attributes, options @_isAcceptable = options.isAcceptable diff --git a/src/coffee/models/step.coffee b/src/coffee/models/step.coffee new file mode 100644 index 000000000..087b6cac1 --- /dev/null +++ b/src/coffee/models/step.coffee @@ -0,0 +1,35 @@ +### +Crafting Guide - step.coffee + +Copyright (c) 2015 by Redwood Labs +All rights reserved. +### + +BaseModel = require './base_model' +Inventory = require './inventory' +{Event} = require '../constants' + +######################################################################################################################## + +module.exports = class Step extends BaseModel + + constructor: (attributes={}, options={})-> + if not attributes.outputItemSlug? then throw new Error 'attributes.outputItemSlug is required' + if not attributes.recipe? then throw new Error 'attributes.recipe is required' + + attributes.inventory = new Inventory + attributes.number ?= 1 + attributes.outputItemSlug ?= null + attributes.multiplier ?= 1 + attributes.recipe ?= null + super attributes, options + + @_computeInventory() + @on Event.change + ':multiplier', => @_computeInventory() + + # Private Methods ############################################################################## + + _computeInventory: -> + @inventory.clear() + @recipe.eachInputStack (stack)=> + @inventory.add stack.itemSlug, stack.quantity * @multiplier diff --git a/src/jade/includes/_header.jade b/src/jade/includes/_header.jade index cfac200e5..8f5b564e5 100644 --- a/src/jade/includes/_header.jade +++ b/src/jade/includes/_header.jade @@ -30,4 +30,4 @@ p Craft .dot - .view__item_selector: p.placeholder find an item... + .view__item_selector.search: p find an item... diff --git a/src/jade/templates/craft_page.jade b/src/jade/templates/craft_page.jade index 782e0e77a..9ca88db4c 100644 --- a/src/jade/templates/craft_page.jade +++ b/src/jade/templates/craft_page.jade @@ -6,8 +6,50 @@ //- .view__craft_page - .view__inventory.want - .view__inventory.have - .view__inventory.need + .sidebar + ins.view__adsense - .view__crafting_table + .mainBody + + .want.section + h2 Items to Make + .panel + .view__inventory.large.editable + + //- .tools.section.hideable.hidden + //- h2 Tools + //- .panel + //- .inUse + //- h3 In Use + //- .view__inventory.large + //- + //- .options + //- h3 More Options + //- .view__inventory.large + + .ingredients.section.hideable.hidden + h2 Ingredients + .panel + .have + h3 Already In Inventory + .view__inventory.large + + .need + h3 Need to Gather + .view__inventory.large + + .steps.section.hideable.hidden + h2 Steps + .panel + + .instructions.section + h2 Instructions + .panel + p. + Welcome to the Craft page. Here you can get detailed instructions for making any item in your + current mod pack (use the Configure page to change it). Making a crafting + plan is very simple: + ol + li Click the "add an item..." button to choose items to craft + li Use the button to mark any items you already possess + li Use the button to complete any step if you already have that item diff --git a/src/jade/templates/inventory.jade b/src/jade/templates/inventory.jade index 8f723066f..753d86150 100644 --- a/src/jade/templates/inventory.jade +++ b/src/jade/templates/inventory.jade @@ -6,13 +6,6 @@ //- .view__inventory - h2 - img.icon - p - .panel - .scrollbox - table - tr.edit.hideable.hidden - td.name(colspan="4", width="*"): .view__item_selector: p.button-label add an item... - .toolbar.hideable.hidden - button(name="clear") clear + .item_container + .empty_placeholder.hideable.hidden Empty + .view__item_selector.hideable.hidden.button: p add an item... diff --git a/src/jade/templates/item.jade b/src/jade/templates/item.jade index 5349f8c40..f210ca3c3 100644 --- a/src/jade/templates/item.jade +++ b/src/jade/templates/item.jade @@ -5,7 +5,7 @@ //- All rights reserved. //- -.view__item.hideable.hidden +.view__item a table tr diff --git a/src/jade/templates/item_selector.jade b/src/jade/templates/item_selector.jade index 9086bc62c..7fa9f1d6b 100644 --- a/src/jade/templates/item_selector.jade +++ b/src/jade/templates/item_selector.jade @@ -6,8 +6,6 @@ //- .view__item_selector - p.placeholder find items... - .view__item_selector_popup.hideable.hiding .search input diff --git a/src/jade/templates/minimal_recipe.jade b/src/jade/templates/minimal_recipe.jade index 56dcf94bf..63f010f22 100644 --- a/src/jade/templates/minimal_recipe.jade +++ b/src/jade/templates/minimal_recipe.jade @@ -7,6 +7,7 @@ .view__minimal_recipe .input - table.view__crafting_grid + .view__crafting_grid .tool .output.view__slot + .multiplier \ No newline at end of file diff --git a/src/jade/templates/stack.jade b/src/jade/templates/stack.jade index 8909aaa0f..3c8b64020 100644 --- a/src/jade/templates/stack.jade +++ b/src/jade/templates/stack.jade @@ -5,9 +5,10 @@ //- All rights reserved. //- -tr.view__stack - td.quantity: input - td.icon: img(src='') - td.name(width='*'): a - td.action - button.remove   +.view__stack + .quantity: .bubble: input + .icon: img(src='') + .name: a + .action + button.second   + button.first   diff --git a/src/jade/templates/step.jade b/src/jade/templates/step.jade new file mode 100644 index 000000000..00e9cb3a7 --- /dev/null +++ b/src/jade/templates/step.jade @@ -0,0 +1,12 @@ +//- +//- Crafting Guide - step.jade +//- +//- Copyright (c) 2015 by Redwood Labs +//- All rights reserved. +//- + +.view__step + h3 + .view__inventory + .view__minimal_recipe + button.complete diff --git a/src/scss/classes.scss b/src/scss/classes.scss index 455660243..88f21d5da 100644 --- a/src/scss/classes.scss +++ b/src/scss/classes.scss @@ -101,12 +101,20 @@ All rights reserved. font-family: $font-family-header; font-size: $font-size-large; margin-bottom: 0.5em; + + &:first-child { + margin-top: 0; + } } h3 { font-family: $font-family-header; font-size: $font-size-normal; margin: 2em 0 0 0.5em; + + &:first-child { + margin-top: 0; + } } .entry { @@ -118,6 +126,10 @@ All rights reserved. background: white; padding: 1em; } + + &:first-child { + margin-top: 0; + } } .slideable { diff --git a/src/scss/templates/craft_page.scss b/src/scss/templates/craft_page.scss index c0516e680..ac2464b3f 100644 --- a/src/scss/templates/craft_page.scss +++ b/src/scss/templates/craft_page.scss @@ -7,20 +7,44 @@ All rights reserved. .view__craft_page { - & > div { - display: inline-block; - margin-top: 2em; - padding: 0 2em; - position: relative; - vertical-align: top; + .want.section { + .view__inventory { + position: relative; width: 100%; + } } - .view__inventory { width: 50%; height: 30em; } + .tools.section { + .options { + margin-top: 4em; + } + } - .view__crafting_table { width: 50%; height: 30em; } + .ingredients.section { + .need { + margin-top: 4em; + } + } - .want label { - position: absolute; top: 50%; left: 0.5em; - @include transform(translateY(-50%)); + .instructions.section { + p { + font-size: $font-size-large; + margin-top: 1em; + + &:first-child { + margin-top: 0; + } + } + + ol { + margin: 2em 3em 0 3em; + + li { + font-family: $font-family-normal; + font-size: $font-size-large; + line-height: $font-size-normal + 0.15em; + list-style: decimal; + margin: 0.66em 0 0 2em; + } + } } } diff --git a/src/scss/templates/index.scss b/src/scss/templates/index.scss index a77181d75..2bd749953 100644 --- a/src/scss/templates/index.scss +++ b/src/scss/templates/index.scss @@ -27,5 +27,6 @@ All rights reserved. @import 'mod_selector'; @import 'stack'; @import 'slot'; +@import 'step'; @import 'tutorial'; @import 'video'; diff --git a/src/scss/templates/inventory.scss b/src/scss/templates/inventory.scss index cff7a1d0e..9521b4b0e 100644 --- a/src/scss/templates/inventory.scss +++ b/src/scss/templates/inventory.scss @@ -6,92 +6,72 @@ All rights reserved. */ .view__inventory { - min-height: 14em; - width: 100%; - .edit td { - padding-top: 1em; - } + .item_container { + position: relative; width: 100%; - .panel { - position: absolute; top: 3.6em; right: 2em; bottom: 0; left: 2em; - background: $color-background-panel; - text-align: right; - } + .view__stack > div { + height: 4.2em; + padding: 0 1em 0.5em 0; + vertical-align: middle; - .scrollbox { - position: absolute; top: 0em; right: 0em; bottom: 3em; left: 0em; - padding: 0.5em 1em; - overflow: auto; - } - - .toolbar { - position: absolute; right: 0; bottom: 0; left: 0; height: 3.5em; - background: $color-background-toolbar; - border-top: 1px solid $color-gray-light; - } - - .view__item_selector { - height: 2.5em; width: 80%; - background: $color-gray-faint; - margin: 0 auto; - - transition: background $animate-normal; - - &:hover { - background: $color-background-panel; + &:last-child { + padding: 0 0 0.5em 0; + } } - } - button[name="clear"] { - position: absolute; bottom: 0.5em; right: 0.5em; - } - - input { - border: 1px solid $color-gray-light; - } - - button:disabled { - background: white; - color: $color-gray-light; - } - - table { - width: 100%; - } - - td { - height: 2.4em; - vertical-align: middle; - } - - td.icon { - width: 4.8em; - padding: 0 1em; - - img { - width: 100%; height: auto; - max-height: 4.8em; + .icon { + img { + height: 3.6em; width: 3.6em; + } } - } - td.name { - text-align: left; - padding-right: 1em; - - input { + .name { width: 100%; - border: 0; - border-bottom: 1px dashed $color-gray-light; - outline: 0; + } - &:focus { - border: 1px solid $color-gray-light; + .action { + white-space: nowrap; + + button:first-child { + margin-right: 0.5em; } } } - td.action { - width: 4em; + .view__item_selector { + position: relative; width: 80%; + margin: 1em auto; + } + + &.large { + .item_container { + .view__stack > div { + height: 5em; + } + + .quantity { + .bubble { + border-radius: 3em; + + input { + font-size: $font-size-large; + } + } + } + + .icon { + img { + height: 4.8em; width: 4.8em; + } + } + + .name { + a { + font-size: $font-size-large; + font-weight: bold; + } + } + } } } diff --git a/src/scss/templates/item_selector.scss b/src/scss/templates/item_selector.scss index f8f9a4eb4..abd8c34f0 100644 --- a/src/scss/templates/item_selector.scss +++ b/src/scss/templates/item_selector.scss @@ -6,30 +6,42 @@ All rights reserved. */ .view__item_selector { - background: $color-background-panel; + position: relative; min-height: $font-size-normal * 2; min-width: 20em; + border: 0.1em solid $color-gray-medium; border-radius: 1.5em; cursor: pointer; padding: 0 0.75em; - p { - position: relative; top: 50%; width: 100%; - @include transform(translateY(-50%)); + &.search { + background: $color-background-panel; - &.placeholder { + p { color: $color-gray-medium; font-family: $font-family-input; - font-size: $font-size-normal; + } + } + + &.button { + background: $color-gray-faint; + + &:hover { + background: $color-background-panel; } - &.button-label { + p { color: $color-active; font-family: $font-family-normal; - font-size: $font-size-normal; font-weight: bold; text-align: center; } } + + p { + position: absolute; top: 50%; width: 100%; + @include transform(translateY(-50%)); + font-size: $font-size-normal; + } } .view__item_selector_popup { diff --git a/src/scss/templates/minimal_recipe.scss b/src/scss/templates/minimal_recipe.scss index a783e60c6..3a72470c8 100644 --- a/src/scss/templates/minimal_recipe.scss +++ b/src/scss/templates/minimal_recipe.scss @@ -44,13 +44,6 @@ All rights reserved. @include transform(translate(-50%, -50%)); } - .multiplier { - position: absolute; bottom: -2.0em; left: 0; right: 0; height: 1.5em; - font-family: $font-family-header; - font-size: $font-size-large; - text-align: center; - } - .quantity { position: absolute; right: 0.1em; bottom: 0; color: white; @@ -59,4 +52,12 @@ All rights reserved. text-shadow: -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 2px 0 #000; } } + + .multiplier { + position: absolute; top: 50%; right: 0; width: 2.7em; + @include transform(translateY(-50%) translateY(2.5em)); + font-family: $font-family-header; + font-size: $font-size-large; + text-align: center; + } } diff --git a/src/scss/templates/mod_page.scss b/src/scss/templates/mod_page.scss index baedf0f08..9550f6b5d 100644 --- a/src/scss/templates/mod_page.scss +++ b/src/scss/templates/mod_page.scss @@ -29,6 +29,10 @@ All rights reserved. font-size: $font-size-large; } } + + .itemGroups { + margin-top: 2em; + } } .view__item { diff --git a/src/scss/templates/stack.scss b/src/scss/templates/stack.scss index c608259a4..20e946562 100644 --- a/src/scss/templates/stack.scss +++ b/src/scss/templates/stack.scss @@ -7,38 +7,36 @@ All rights reserved. .view__stack { font-family: $font-family-normal; + display: table-row; - td { - padding: 0.2em 0; + & > div { + display: table-cell; + vertical-align: middle; } - td.quantity { - position: relative; - width: 5em; - - input { - position: absolute; top: 50%; height: $font-size-small; width: 100%; - @include transform(translateY(-50%)); - - border-radius: 0.75em; + .quantity { + .bubble { + border: 0.1em solid $color-gray-light; + border-radius: 1.5em; background: $color-ice; - color: $color-background-panel; - font-family: $font-family-normal; - font-size: $font-size-normal; - font-weight: bold; - text-align: center; - &.editable { - &:focus { - background: $color-background-panel; - color: $color-text; - font-family: $font-family-input; - font-weight: normal; - outline: none; - } + input { + width: 3em; + background: none; + border: none; + color: $color-background-panel; + font-family: $font-family-normal; + font-size: $font-size-normal; + font-weight: bold; + line-height: $font-size-normal; + outline: none; + text-align: center; + } - &:hover { - background: $color-background-panel; + &.editable:hover, &.editing { + background: $color-background-panel; + + input { color: $color-text; font-family: $font-family-input; font-weight: normal; @@ -47,10 +45,7 @@ All rights reserved. } } - td.icon { - width: 4.6em; - padding: 0.2em 0.5em; - + .icon { img { width: 100%; height: auto; max-height: 4.8em; @@ -58,37 +53,99 @@ All rights reserved. } } - td.name a { - color: $color-text; - display: inline; - font-size: $font-size-normal; - text-decoration: none; + .name { + a { + color: $color-text; + font-size: $font-size-normal; + text-decoration: none; - &:hover { - color: $color-active-hover; - text-decoration: underline; + &:hover { + color: $color-active-hover; + text-decoration: underline; + } } } - td.action { + .action { text-align: right; - } - button.remove { - opacity: 0; - position: relative; width: 1.8em; height: 1.8em; - background: url('/images/remove.png') no-repeat center; - border: 0; - outline: none; + button { + position: relative; width: 3.0em; height: 3.0em; + display: inline-block; - &:hover { - background: url('/images/remove-hover.png') no-repeat center; - } - } + border: 0; + font-size: $font-size-small; + margin: 0; + outline: none; + padding: 0; - &:hover { - button.remove { - opacity: 1; + &.check { + background: url('/images/check.png') no-repeat center; + + &:active { + background: url('/images/check_active.png') no-repeat center; + } + + &:disabled { + background: url('/images/check_disabled.png') no-repeat center !important; + cursor: inherit; + } + + &:hover { + background: url('/images/check_hover.png') no-repeat center; + } + } + + &.down { + background: url('/images/down.png') no-repeat center; + + &:active { + background: url('/images/down_active.png') no-repeat center; + } + + &:disabled { + background: url('/images/down_disabled.png') no-repeat center !important; + cursor: inherit; + } + + &:hover { + background: url('/images/down_hover.png') no-repeat center; + } + } + + &.remove { + background: url('/images/remove.png') no-repeat center; + + &:active { + background: url('/images/remove_active.png') no-repeat center; + } + + &:disabled { + background: url('/images/remove_disabled.png') no-repeat center !important; + cursor: inherit; + } + + &:hover { + background: url('/images/remove_hover.png') no-repeat center; + } + } + + &.up { + background: url('/images/up.png') no-repeat center; + + &:active { + background: url('/images/up_active.png') no-repeat center; + } + + &:disabled { + background: url('/images/up_disabled.png') no-repeat center !important; + cursor: inherit; + } + + &:hover { + background: url('/images/up_hover.png') no-repeat center; + } + } } } } diff --git a/src/scss/templates/step.scss b/src/scss/templates/step.scss new file mode 100644 index 000000000..d617d2279 --- /dev/null +++ b/src/scss/templates/step.scss @@ -0,0 +1,47 @@ +/* +Crafting Page - step.scss + +Copyright (C) 2015 by Redwood Labs +All rights reserved. +*/ + +.view__step { + position: relative; min-height: 24em; + + border-top: 0.1em solid $color-gray-medium; + padding: 1em 0; + + &:first-child { + border-top: 0; + } + + .view__inventory { + margin: 1em 0 0 3em; + } + + .view__minimal_recipe { + position: absolute; top: 2em; right: 4.8em; + } + + button.complete { + position: absolute; top: 1em; right: 0; height: 3em; width: 3em; + + background: url("/images/check.png") no-repeat center; + border: 0; + font-size: $font-size-small; + outline: none; + + &:active { + background: url('/images/check_active.png') no-repeat center; + } + + &:disabled { + background: url('/images/check_disabled.png') no-repeat center !important; + cursor: inherit; + } + + &:hover { + background: url('/images/check_hover.png') no-repeat center; + } + } +} \ No newline at end of file diff --git a/static/images/arrow-left-disabled.png b/static/images/arrow-left-disabled.png deleted file mode 100644 index 8ce5770fc..000000000 Binary files a/static/images/arrow-left-disabled.png and /dev/null differ diff --git a/static/images/arrow-left-hover.png b/static/images/arrow-left-hover.png deleted file mode 100644 index f635425a4..000000000 Binary files a/static/images/arrow-left-hover.png and /dev/null differ diff --git a/static/images/arrow-left.png b/static/images/arrow-left.png deleted file mode 100644 index 8088ee2ed..000000000 Binary files a/static/images/arrow-left.png and /dev/null differ diff --git a/static/images/arrow-right-disabled.png b/static/images/arrow-right-disabled.png deleted file mode 100644 index 764784a41..000000000 Binary files a/static/images/arrow-right-disabled.png and /dev/null differ diff --git a/static/images/arrow-right-hover.png b/static/images/arrow-right-hover.png deleted file mode 100644 index ace111db5..000000000 Binary files a/static/images/arrow-right-hover.png and /dev/null differ diff --git a/static/images/arrow-right.png b/static/images/arrow-right.png deleted file mode 100644 index c0ba334a6..000000000 Binary files a/static/images/arrow-right.png and /dev/null differ diff --git a/static/images/check.png b/static/images/check.png new file mode 100644 index 000000000..399c54fbd Binary files /dev/null and b/static/images/check.png differ diff --git a/static/images/check_active.png b/static/images/check_active.png new file mode 100644 index 000000000..76e31f674 Binary files /dev/null and b/static/images/check_active.png differ diff --git a/static/images/check_disabled.png b/static/images/check_disabled.png new file mode 100644 index 000000000..31727dfc9 Binary files /dev/null and b/static/images/check_disabled.png differ diff --git a/static/images/check_hover.png b/static/images/check_hover.png new file mode 100644 index 000000000..8911dc7c0 Binary files /dev/null and b/static/images/check_hover.png differ diff --git a/static/images/down.png b/static/images/down.png new file mode 100644 index 000000000..3c576c1ac Binary files /dev/null and b/static/images/down.png differ diff --git a/static/images/down_active.png b/static/images/down_active.png new file mode 100644 index 000000000..d12415468 Binary files /dev/null and b/static/images/down_active.png differ diff --git a/static/images/down_disabled.png b/static/images/down_disabled.png new file mode 100644 index 000000000..a9a82fad9 Binary files /dev/null and b/static/images/down_disabled.png differ diff --git a/static/images/down_hover.png b/static/images/down_hover.png new file mode 100644 index 000000000..99aadeb67 Binary files /dev/null and b/static/images/down_hover.png differ diff --git a/static/images/question.png b/static/images/question.png new file mode 100644 index 000000000..15481c2ab Binary files /dev/null and b/static/images/question.png differ diff --git a/static/images/question_disabled.png b/static/images/question_disabled.png new file mode 100644 index 000000000..6f8cf0da6 Binary files /dev/null and b/static/images/question_disabled.png differ diff --git a/static/images/question_hover.png b/static/images/question_hover.png new file mode 100644 index 000000000..f8e9db3d6 Binary files /dev/null and b/static/images/question_hover.png differ diff --git a/static/images/remove-hover.png b/static/images/remove-hover.png deleted file mode 100644 index 5cb7747b9..000000000 Binary files a/static/images/remove-hover.png and /dev/null differ diff --git a/static/images/remove.png b/static/images/remove.png index f982c6298..af5f9b970 100644 Binary files a/static/images/remove.png and b/static/images/remove.png differ diff --git a/static/images/remove_action.png b/static/images/remove_action.png new file mode 100644 index 000000000..ca0e6d17e Binary files /dev/null and b/static/images/remove_action.png differ diff --git a/static/images/remove_disabled.png b/static/images/remove_disabled.png new file mode 100644 index 000000000..94e4e8d4c Binary files /dev/null and b/static/images/remove_disabled.png differ diff --git a/static/images/remove_hover.png b/static/images/remove_hover.png new file mode 100644 index 000000000..a6284d4fe Binary files /dev/null and b/static/images/remove_hover.png differ diff --git a/static/images/up.png b/static/images/up.png new file mode 100644 index 000000000..9369cb5cc Binary files /dev/null and b/static/images/up.png differ diff --git a/static/images/up_active.png b/static/images/up_active.png new file mode 100644 index 000000000..f9d1e8dde Binary files /dev/null and b/static/images/up_active.png differ diff --git a/static/images/up_disabled.png b/static/images/up_disabled.png new file mode 100644 index 000000000..e2b782cf3 Binary files /dev/null and b/static/images/up_disabled.png differ diff --git a/static/images/up_hover.png b/static/images/up_hover.png new file mode 100644 index 000000000..6cbefc0c7 Binary files /dev/null and b/static/images/up_hover.png differ diff --git a/static/images/wordmark.png b/static/images/wordmark.png deleted file mode 100644 index e538238ed..000000000 Binary files a/static/images/wordmark.png and /dev/null differ