├── README.md
├── .gitignore
├── gulp
├── tasks
│ ├── default.js
│ ├── build.js
│ ├── setWatch.js
│ ├── markup.js
│ ├── browserSync.js
│ ├── images.js
│ ├── watch.js
│ ├── sass.js
│ └── browserify.js
├── index.js
└── util
│ ├── handleErrors.js
│ └── bundleLogger.js
├── Gemfile
├── src
├── images
│ └── gulp.png
├── sass
│ ├── _scss-mixins.scss
│ ├── _typography.sass
│ ├── app.sass
│ ├── app.css.scss
│ └── _famous.sass
├── javascript
│ ├── models
│ │ └── card.coffee
│ ├── templates
│ │ └── menu.hbs
│ ├── app.coffee
│ ├── views
│ │ ├── menu
│ │ │ ├── menu-button.coffee
│ │ │ └── menu-interior.coffee
│ │ ├── cards
│ │ │ ├── card-stack.coffee
│ │ │ ├── card-interior.coffee
│ │ │ └── card.coffee
│ │ ├── components
│ │ │ └── slideout.coffee
│ │ └── main-view.coffee
│ └── collections
│ │ └── cards.coffee
└── htdocs
│ └── index.html
├── config.rb
├── gulpfile.js
├── Gemfile.lock
├── LICENSE.md
└── package.json
/README.md:
--------------------------------------------------------------------------------
1 | Browser imgur using Famo.us.
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .sass-cache
3 | build
4 | Desktop.ini
5 | node_modules
6 | API_KEY.coffee
--------------------------------------------------------------------------------
/gulp/tasks/default.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | gulp.task('default', ['watch']);
4 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'sass', '>= 3.3'
4 | gem 'compass', '>= 1.0.0.rc.1'
--------------------------------------------------------------------------------
/src/images/gulp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StephenGrider/Famous-SlideTemplateApp/master/src/images/gulp.png
--------------------------------------------------------------------------------
/gulp/tasks/build.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | gulp.task('build', ['browserify', 'sass', 'images', 'markup']);
4 |
--------------------------------------------------------------------------------
/gulp/tasks/setWatch.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | gulp.task('setWatch', function() {
4 | global.isWatching = true;
5 | });
6 |
--------------------------------------------------------------------------------
/src/sass/_scss-mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin font-smoothing {
2 | -moz-osx-font-smoothing: grayscale;
3 | -webkit-font-smoothing: antialiased;
4 | }
5 |
--------------------------------------------------------------------------------
/src/sass/_typography.sass:
--------------------------------------------------------------------------------
1 | body
2 | +font-smoothing // <- _mixins.scss
3 | +translateZ(0) // <- Compass
4 | color: #555
5 | font-family: sans-serif
--------------------------------------------------------------------------------
/gulp/index.js:
--------------------------------------------------------------------------------
1 | var requireDir = require('require-dir');
2 |
3 | // Require all tasks in gulp/tasks, including subfolders
4 | requireDir('./tasks', { recurse: true });
5 |
--------------------------------------------------------------------------------
/gulp/tasks/markup.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | gulp.task('markup', function() {
4 | return gulp.src('src/htdocs/**')
5 | .pipe(gulp.dest('build'));
6 | });
7 |
--------------------------------------------------------------------------------
/src/javascript/models/card.coffee:
--------------------------------------------------------------------------------
1 | Backbone = require('Backbone')
2 |
3 | class Card extends Backbone.Model
4 | getImageSrc: ->
5 | @get('link').replace('.jpg', 'l.jpg').replace('.png', 'l.png')
6 |
7 |
8 | module.exports = Card
9 |
--------------------------------------------------------------------------------
/config.rb:
--------------------------------------------------------------------------------
1 | # Compass Config
2 | preferred_syntax = :sass
3 | http_path = '/'
4 | css_dir = 'build'
5 | sass_dir = 'src/sass'
6 | images_dir = 'build/images'
7 | fonts_dir = 'build/fonts'
8 | relative_assets = true
9 | line_comments = true
10 |
--------------------------------------------------------------------------------
/gulp/tasks/browserSync.js:
--------------------------------------------------------------------------------
1 | var browserSync = require('browser-sync');
2 | var gulp = require('gulp');
3 |
4 | gulp.task('browserSync', ['build'], function() {
5 | browserSync.init(['build/**'], {
6 | server: {
7 | baseDir: ['build', 'src']
8 | }
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/src/javascript/templates/menu.hbs:
--------------------------------------------------------------------------------
1 |
Filters
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/src/javascript/app.coffee:
--------------------------------------------------------------------------------
1 | $ = require('jquery')
2 | Backbone = require('backbone')
3 | Backbone.$ = $
4 | CardsCollection = require('./collections/cards')
5 | MainView = require('./views/main-view')
6 |
7 |
8 | context = require('famous/core/engine').createContext()
9 | collection = new CardsCollection
10 | mainView = new MainView(collection: collection)
11 | context.add(mainView)
12 |
--------------------------------------------------------------------------------
/src/javascript/views/menu/menu-button.coffee:
--------------------------------------------------------------------------------
1 | _ = require('underscore')
2 |
3 | class MenuButton extends require('famous/core/surface')
4 | constructor: (options) ->
5 | super
6 | @value = options.value
7 | @on('click', @onClick)
8 |
9 | spin: =>
10 |
11 | onClick: =>
12 | @emit('button:clicked', @value, this)
13 |
14 |
15 | module.exports = MenuButton
16 |
--------------------------------------------------------------------------------
/gulp/tasks/images.js:
--------------------------------------------------------------------------------
1 | var changed = require('gulp-changed');
2 | var gulp = require('gulp');
3 | var imagemin = require('gulp-imagemin');
4 |
5 | gulp.task('images', function() {
6 | var dest = './build/images';
7 |
8 | return gulp.src('./src/images/**')
9 | .pipe(changed(dest)) // Ignore unchanged files
10 | .pipe(imagemin()) // Optimize
11 | .pipe(gulp.dest(dest));
12 | });
13 |
--------------------------------------------------------------------------------
/gulp/util/handleErrors.js:
--------------------------------------------------------------------------------
1 | var notify = require("gulp-notify");
2 |
3 | module.exports = function() {
4 |
5 | var args = Array.prototype.slice.call(arguments);
6 |
7 | // Send error to notification center with gulp-notify
8 | notify.onError({
9 | title: "Compile Error",
10 | message: "<%= error.message %>"
11 | }).apply(this, args);
12 |
13 | // Keep gulp from hanging on this task
14 | this.emit('end');
15 | };
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | gulpfile.js
3 | ===========
4 | Rather than manage one giant configuration file responsible
5 | for creating multiple tasks, each task has been broken out into
6 | its own file in gulp/tasks. Any file in that folder gets automatically
7 | required by the loop in ./gulp/index.js (required below).
8 |
9 | To add a new task, simply add a new task file to gulp/tasks.
10 | */
11 |
12 | require('./gulp');
--------------------------------------------------------------------------------
/gulp/tasks/watch.js:
--------------------------------------------------------------------------------
1 | /* Notes:
2 | - gulp/tasks/browserify.js handles js recompiling with watchify
3 | - gulp/tasks/browserSync.js automatically reloads any files
4 | that change within the directory it's serving from
5 | */
6 |
7 | var gulp = require('gulp');
8 |
9 | gulp.task('watch', ['setWatch', 'browserSync'], function() {
10 | gulp.watch('src/sass/**', ['sass']);
11 | gulp.watch('src/images/**', ['images']);
12 | gulp.watch('src/htdocs/**', ['markup']);
13 | });
14 |
--------------------------------------------------------------------------------
/gulp/tasks/sass.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var sass = require('gulp-ruby-sass');
3 | var handleErrors = require('../util/handleErrors');
4 | var browserSync = require('browser-sync');
5 |
6 | gulp.task('sass', ['images'], function () {
7 | return gulp.src('src/sass/*.{sass, scss}')
8 | .pipe(sass({
9 | compass: true,
10 | bundleExec: true,
11 | sourcemap: true,
12 | sourcemapPath: '../sass'
13 | }))
14 | .on('error', handleErrors)
15 | .pipe(gulp.dest('build'));
16 | });
17 |
--------------------------------------------------------------------------------
/gulp/util/bundleLogger.js:
--------------------------------------------------------------------------------
1 | /* bundleLogger
2 | ------------
3 | Provides gulp style logs to the bundle method in browserify.js
4 | */
5 |
6 | var gutil = require('gulp-util');
7 | var prettyHrtime = require('pretty-hrtime');
8 | var startTime;
9 |
10 | module.exports = {
11 | start: function() {
12 | startTime = process.hrtime();
13 | gutil.log('Running', gutil.colors.green("'bundle'") + '...');
14 | },
15 |
16 | end: function() {
17 | var taskTime = process.hrtime(startTime);
18 | var prettyTime = prettyHrtime(taskTime);
19 | gutil.log('Finished', gutil.colors.green("'bundle'"), 'in', gutil.colors.magenta(prettyTime));
20 | }
21 | };
--------------------------------------------------------------------------------
/src/htdocs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Swipey App
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | chunky_png (1.3.1)
5 | compass (1.0.0.rc.1)
6 | chunky_png (~> 1.2)
7 | compass-core (~> 1.0.0.rc.1)
8 | compass-import-once (~> 1.0.5)
9 | rb-fsevent (>= 0.9.3)
10 | rb-inotify (>= 0.9)
11 | sass (>= 3.3.13, < 3.5)
12 | compass-core (1.0.0.rc.1)
13 | multi_json (~> 1.0)
14 | sass (>= 3.3.0, < 3.5)
15 | compass-import-once (1.0.5)
16 | sass (>= 3.2, < 3.5)
17 | ffi (1.9.3)
18 | multi_json (1.10.1)
19 | rb-fsevent (0.9.4)
20 | rb-inotify (0.9.5)
21 | ffi (>= 0.5.0)
22 | sass (3.3.14)
23 |
24 | PLATFORMS
25 | ruby
26 |
27 | DEPENDENCIES
28 | compass (>= 1.0.0.rc.1)
29 | sass (>= 3.3)
30 |
--------------------------------------------------------------------------------
/src/sass/app.sass:
--------------------------------------------------------------------------------
1 | @import compass
2 | @import scss-mixins
3 | @import typography
4 | @import famous
5 |
6 |
7 | .card
8 | border-radius: 8px
9 | box-shadow: 0 0 6px 8px rgba(0, 0, 0, 0.5)
10 |
11 | .card-description
12 | text-align: center
13 | font: 16px
14 | box-shadow: 0 0 6px 8px rgba(0, 0, 0, 0.5)
15 | background-color: rgba(0, 0, 0, .3)
16 | color: white
17 |
18 | .background-image
19 | -webkit-filter: blur(7px)
20 | z-index: -999
21 |
22 | body
23 | background-color: black
24 |
25 | .menu-bar
26 | background-color: blue
27 | z-index: 10
28 |
29 | .menu-button
30 | text-align: center
31 | font: 16px
32 | box-shadow: 0 0 6px 8px rgba(0, 0, 0, 0.5)
33 | background-color: rgba(150, 150, 150, .4)
34 | color: black
35 | line-height: 140px
36 |
37 | .selected
38 | background-color: rgba(250, 250, 250, .8)
39 |
40 | .settings
41 | color: white
42 | text-align: center
43 |
--------------------------------------------------------------------------------
/src/javascript/views/cards/card-stack.coffee:
--------------------------------------------------------------------------------
1 | RenderController = require('famous/views/rendercontroller')
2 | Card = require('./card')
3 | API_KEY = require('../../API_KEY')
4 |
5 | class CardStackView extends RenderController
6 |
7 | #
8 | # Init
9 |
10 | constructor: (options) ->
11 | super
12 | @collection = options.collection
13 |
14 | @loadData()
15 |
16 | #
17 | # Control
18 |
19 | loadData: ->
20 | @collection.fetch({ headers: {Authorization :"Client-ID #{API_KEY}"} })
21 | .done(@addCard)
22 | .fail(-> console.log 'card fetch fail')
23 |
24 | addCard: =>
25 | cardView = new Card(model: @collection.first())
26 | cardView.on('card:exit', @onCardExit)
27 | @_eventOutput.emit('card:enter', @collection.first())
28 | @show(cardView)
29 |
30 |
31 | #
32 | # Events
33 |
34 | onCardExit: (cardModel) =>
35 | @collection.remove(cardModel)
36 | @addCard()
37 |
38 |
39 | module.exports = CardStackView
40 |
--------------------------------------------------------------------------------
/src/sass/app.css.scss:
--------------------------------------------------------------------------------
1 | @import compass
2 | @import scss-mixins
3 | @import typography
4 | @import famous
5 |
6 |
7 | .card {
8 | border-radius: 8px;
9 | box-shadow: 0 0 6px 8px rgba(0, 0, 0, 0.5);
10 | }
11 |
12 | .card-description {
13 | text-align: center;
14 | font: 16px;
15 | box-shadow: 0 0 6px 8px rgba(0, 0, 0, 0.5);
16 | background-color: rgba(0, 0, 0, .3);
17 | color: white;
18 | }
19 |
20 | .background-image {
21 | -webkit-filter: blur(7px);
22 | z-index: -999;
23 | }
24 |
25 | body {
26 | background-color: black;
27 | }
28 | ;
29 | .menu-bar {
30 | background-color: blue;
31 | z-index: 10;
32 | }
33 | ;
34 | .menu-button {
35 | text-align: center;
36 | font: 16px;
37 | box-shadow: 0 0 6px 8px rgba(0, 0, 0, 0.5);
38 | background-color: rgba(150, 150, 150, .4);
39 | color: black;
40 | line-height: 140px;
41 | }
42 |
43 | .selected {
44 | background-color: rgba(250, 250, 250, .8);
45 | }
46 |
47 | .settings {
48 | color: white;
49 | text-align: center;
50 | }
51 |
--------------------------------------------------------------------------------
/src/javascript/views/components/slideout.coffee:
--------------------------------------------------------------------------------
1 | Draggable = require('famous/modifiers/draggable')
2 | StateModifier = require('famous/modifiers/statemodifier')
3 | Transform = require('famous/core/transform')
4 |
5 | class Slideout extends require('famous/core/view')
6 |
7 | #
8 | # Properties
9 |
10 | open: false
11 |
12 | #
13 | # Init
14 |
15 | constructor: ->
16 | super()
17 |
18 | @stateMod = new StateModifier
19 |
20 | @stateMod.setTransform(Transform.translate(0, -300, 0))
21 |
22 | this._eventInput.on('click', @onClick)
23 |
24 | closeSlideout: ->
25 | @open = false
26 | trans = curve: 'easeOutBounce', duration: 250
27 | @stateMod.setTransform(Transform.translate(0, -300, 0), trans)
28 |
29 | openSlideout: ->
30 | @open = true
31 | trans = curve: 'easeOutBounce', duration: 250
32 | @stateMod.setTransform(Transform.translate(0, 0, 10), trans)
33 |
34 | #
35 | # Events
36 |
37 | onClick: =>
38 | if @open then @closeSlideout() else @openSlideout()
39 |
40 |
41 | module.exports = Slideout
--------------------------------------------------------------------------------
/src/javascript/views/cards/card-interior.coffee:
--------------------------------------------------------------------------------
1 | ImageSurface = require('famous/surfaces/ImageSurface')
2 | Surface = require('famous/core/surface')
3 | StateModifier = require('famous/modifiers/statemodifier')
4 |
5 | class CardInteriorView extends require('famous/core/view')
6 |
7 | #
8 | # Init
9 |
10 | constructor: (options) ->
11 | super
12 | @model = options.model
13 |
14 | @showCardImage()
15 | @showCardAnnotation()
16 |
17 |
18 | #
19 | # Control
20 |
21 | showCardImage: ->
22 | surface = new ImageSurface
23 | content: @model.getImageSrc()
24 | origin: [0, .5]
25 | size: [undefined, 400]
26 | classes: ['card']
27 | textAlign: 'center'
28 |
29 | surface.pipe(@._eventOutput)
30 | @add(surface)
31 |
32 | showCardAnnotation: ->
33 | surface = new Surface
34 | content: @model.get('title')
35 | size: [undefined, 60]
36 | classes: ['card-description']
37 |
38 | state = new StateModifier
39 | align: [.5, .9]
40 | origin: [.5, .5]
41 |
42 | @add(state).add(surface)
43 |
44 |
45 | module.exports = CardInteriorView
46 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Daniel Tello
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-starter",
3 | "version": "0.1.1",
4 | "description": "Gulp starter with common tasks and scenarios",
5 | "repository": {
6 | "type": "git",
7 | "url": "git://github.com/greypants/gulp-starter.git"
8 | },
9 | "browser": {
10 | "underscore": "backbone/node_modules/underscore",
11 | "plugin": "./src/javascript/vendor/jquery-plugin.js"
12 | },
13 | "browserify": {
14 | "transform": [
15 | "browserify-shim",
16 | "coffeeify",
17 | "hbsfy"
18 | ]
19 | },
20 | "browserify-shim": {
21 | "plugin": {
22 | "exports": "plugin",
23 | "depends": [
24 | "jquery:$"
25 | ]
26 | }
27 | },
28 | "devDependencies": {
29 | "browser-sync": "~0.8.2",
30 | "browserify": "~3.36.0",
31 | "browserify-shim": "~3.4.1",
32 | "coffeeify": "~0.6.0",
33 | "gulp": "^3.8.0",
34 | "gulp-changed": "^0.4.1",
35 | "gulp-imagemin": "^0.6.2",
36 | "gulp-notify": "^1.4.2",
37 | "gulp-ruby-sass": "^0.7.1",
38 | "gulp-util": "^3.0.0",
39 | "handlebars": "^1.3.0",
40 | "hbsfy": "~1.3.2",
41 | "pretty-hrtime": "~0.2.1",
42 | "require-dir": "^0.1.0",
43 | "vinyl-source-stream": "~0.1.1",
44 | "watchify": "~0.10.1"
45 | },
46 | "dependencies": {
47 | "backbone": "^1.1.2",
48 | "famous": "^0.2.2",
49 | "jquery": "~2.1.0",
50 | "underscore": "^1.6.0",
51 | "handlebars": "~1.3.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/javascript/views/main-view.coffee:
--------------------------------------------------------------------------------
1 | CardStack = require('./cards/card-stack')
2 | ImageSurface = require('famous/surfaces/imagesurface')
3 | Modifier = require('famous/modifiers/statemodifier')
4 | MenuInterior = require('./menu/menu-interior')
5 | Slideout = require('./components/slideout')
6 |
7 | class MainView extends require('famous/core/view')
8 |
9 | #
10 | # Init
11 |
12 | constructor: (options) ->
13 | super
14 | @collection = options.collection
15 |
16 | @createSlideout()
17 | @createContent()
18 | @createBackground()
19 |
20 |
21 | #
22 | # Control
23 |
24 | createContent: ->
25 | content = new CardStack(collection: @collection)
26 |
27 | content.on('card:enter', @onCardEnter)
28 |
29 | @add(content)
30 |
31 | createSlideout: ->
32 | slideout = new Slideout
33 | @add(slideout.stateMod).add(slideout)
34 |
35 | interior = new MenuInterior(collection: @collection)
36 | interior._eventOutput.pipe(slideout._eventInput)
37 | slideout.add(interior)
38 |
39 | createBackground: (model) ->
40 | @background = new ImageSurface
41 | origin: [0, .5]
42 | size: [undefined, undefined]
43 | classes: ['background-image']
44 | textAlign: 'center'
45 |
46 | mod = new Modifier
47 | opacity: .9
48 |
49 | @add(mod).add(@background)
50 |
51 | setBackground: (model) ->
52 | @background.setContent(model.getImageSrc())
53 |
54 |
55 | #
56 | # Events
57 |
58 | onCardEnter: (model) =>
59 | @setBackground(model)
60 |
61 |
62 | module.exports = MainView
63 |
--------------------------------------------------------------------------------
/src/javascript/collections/cards.coffee:
--------------------------------------------------------------------------------
1 | Card = require('../models/card')
2 | Backbone = require('Backbone')
3 | API_KEY = require('../API_KEY')
4 | _ = require('underscore')
5 |
6 | class Cards extends Backbone.Collection
7 | model: Card
8 | urlRoot: "https://api.imgur.com/3/gallery/r/"
9 | url: "https://api.imgur.com/3/gallery/r/pics/time/day/"
10 | category: 'funny'
11 | page: 1
12 |
13 | initialize: ->
14 | @on('sync', @prefetchImages)
15 | @on('remove', @shouldGetNextPage)
16 | @on('change:category', @onCategoryChange)
17 |
18 | parse: (response) ->
19 | response.data
20 |
21 | filterModels: (image) ->
22 | aspectRatio = image.get('width') / image.get('height')
23 | true if aspectRatio > .5 and aspectRatio < 2
24 |
25 | prefetchImages: =>
26 | @set(@filter(@filterModels))
27 | for image,index in @models
28 | break unless image
29 |
30 | if image.get('is_album')
31 | @remove(image)
32 | else
33 | (new Image).src = image.getImageSrc()
34 |
35 | shouldGetNextPage: (options) =>
36 | if @length < 15 && !@fetching
37 | @getNextPage()
38 |
39 | onCategoryChange: =>
40 | @page = 1
41 | @getNextPage(reset: true)
42 |
43 | resetPageIndex: ->
44 | @page = 1
45 |
46 | getNextPage: (options = {}) =>
47 | @fetching = true
48 |
49 | @page++
50 |
51 | fetchOptions =
52 | headers: {Authorization :"Client-ID #{API_KEY}"}
53 | url: "#{@urlRoot}#{@category}/time/day/#{@page}"
54 |
55 | options = _.extend(options, fetchOptions)
56 |
57 | @fetch(options)
58 | .always( => @fetching = false)
59 |
60 |
61 | module.exports = Cards
62 |
--------------------------------------------------------------------------------
/gulp/tasks/browserify.js:
--------------------------------------------------------------------------------
1 | /* browserify task
2 | ---------------
3 | Bundle javascripty things with browserify!
4 |
5 | If the watch task is running, this uses watchify instead
6 | of browserify for faster bundling using caching.
7 | */
8 |
9 | var browserify = require('browserify');
10 | var watchify = require('watchify');
11 | var bundleLogger = require('../util/bundleLogger');
12 | var gulp = require('gulp');
13 | var handleErrors = require('../util/handleErrors');
14 | var source = require('vinyl-source-stream');
15 |
16 | gulp.task('browserify', function() {
17 |
18 | var bundleMethod = global.isWatching ? watchify : browserify;
19 |
20 | var bundler = bundleMethod({
21 | // Specify the entry point of your app
22 | entries: ['./src/javascript/app.coffee'],
23 | // Add file extentions to make optional in your requires
24 | extensions: ['.coffee', '.hbs'],
25 | // Enable source maps!
26 | debug: true
27 | });
28 |
29 | var bundle = function() {
30 | // Log when bundling starts
31 | bundleLogger.start();
32 |
33 | return bundler
34 | .bundle()
35 | // Report compile errors
36 | .on('error', handleErrors)
37 | // Use vinyl-source-stream to make the
38 | // stream gulp compatible. Specifiy the
39 | // desired output filename here.
40 | .pipe(source('app.js'))
41 | // Specify the output destination
42 | .pipe(gulp.dest('./build/'))
43 | // Log when bundling completes!
44 | .on('end', bundleLogger.end);
45 | };
46 |
47 | if(global.isWatching) {
48 | // Rebundle with watchify on changes.
49 | bundler.on('update', bundle);
50 | }
51 |
52 | return bundle();
53 | });
54 |
--------------------------------------------------------------------------------
/src/javascript/views/cards/card.coffee:
--------------------------------------------------------------------------------
1 | CardInterior = require('./card-interior')
2 | Draggable = require('famous/modifiers/draggable')
3 | StateModifier = require('famous/modifiers/statemodifier')
4 | Transform = require('famous/core/transform')
5 |
6 | class CardView extends require('famous/core/view')
7 |
8 | #
9 | # Init
10 |
11 | constructor: (options) ->
12 | super
13 | @model = options.model
14 | @showSurface()
15 |
16 |
17 | #
18 | # Control
19 |
20 | showSurface: ->
21 | cardInterior = new CardInterior
22 | model: @model
23 | dimensions: [1,2]
24 |
25 | @draggable = new Draggable
26 | xRange: [-200, 200]
27 | yRange: [-500, 500]
28 |
29 | @stateMod = new StateModifier
30 | transform: Transform.rotateZ(0)
31 | align: [.5, .075]
32 | origin: [.5, 0]
33 |
34 | cardInterior.pipe(@draggable)
35 |
36 | @draggable.on('end', @onDragEnd)
37 | @draggable.on('update', @onDragUpdate)
38 |
39 | @.add(@stateMod).add(@draggable).add(cardInterior)
40 |
41 | resetPosition: ->
42 | trans = {curve : 'easeOutBounce', duration : 500}
43 | @draggable.setPosition([0,0,0], trans)
44 | @stateMod.setTransform(Transform.identity, trans)
45 |
46 | cardExit: (direction) ->
47 | trans = {curve : 'easeOutBounce', duration : 1500}
48 |
49 | @_eventOutput.emit('card:exit', this.model)
50 | @draggable.setPosition([-600,0,0], trans) if direction == 'left'
51 | @draggable.setPosition([600,0,0], trans) if direction == 'right'
52 |
53 |
54 | #
55 | # Events
56 |
57 | onDragUpdate: =>
58 | @stateMod.setTransform(Transform.rotateZ(@draggable.getPosition()[0]/800))
59 |
60 | onDragEnd: =>
61 | distance = @draggable.getPosition()[0]
62 |
63 | if distance > 150
64 | @cardExit('right')
65 | else if distance < -150
66 | @cardExit('left')
67 | else
68 | @resetPosition()
69 |
70 |
71 | module.exports = CardView
72 |
73 |
--------------------------------------------------------------------------------
/src/sass/_famous.sass:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this
3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 | *
5 | * Owner: mark@famo.us
6 | * @license MPL 2.0
7 | * @copyright Famous Industries, Inc. 2014
8 | */
9 |
10 |
11 | html
12 | width: 100%
13 | height: 100%
14 | margin: 0px
15 | padding: 0px
16 | overflow: hidden
17 | -webkit-transform-style: preserve-3d
18 | transform-style: preserve-3d
19 |
20 |
21 | body
22 | position: absolute
23 | width: 100%
24 | height: 100%
25 | margin: 0px
26 | padding: 0px
27 | -webkit-transform-style: preserve-3d
28 | transform-style: preserve-3d
29 | -webkit-font-smoothing: antialiased
30 | -webkit-tap-highlight-color: transparent
31 | -webkit-perspective: 0
32 | perspective: none
33 | overflow: hidden
34 |
35 |
36 | .famous-container, .famous-group
37 | position: absolute
38 | top: 0px
39 | left: 0px
40 | bottom: 0px
41 | right: 0px
42 | overflow: visible
43 | -webkit-transform-style: preserve-3d
44 | transform-style: preserve-3d
45 | -webkit-backface-visibility: visible
46 | backface-visibility: visible
47 | pointer-events: none
48 |
49 |
50 | .famous-group
51 | width: 0px
52 | height: 0px
53 | margin: 0px
54 | padding: 0px
55 | -webkit-transform-style: preserve-3d
56 | transform-style: preserve-3d
57 |
58 |
59 | .famous-surface
60 | position: absolute
61 | -webkit-transform-origin: center center
62 | transform-origin: center center
63 | -webkit-backface-visibility: hidden
64 | backface-visibility: hidden
65 | -webkit-transform-style: flat
66 | transform-style: preserve-3d
67 | -webkit-box-sizing: border-box
68 | -moz-box-sizing: border-box
69 | -webkit-tap-highlight-color: transparent
70 | pointer-events: auto
71 |
72 |
73 | .famous-container-group
74 | position: relative
75 | width: 100%
76 | height: 100%
77 |
--------------------------------------------------------------------------------
/src/javascript/views/menu/menu-interior.coffee:
--------------------------------------------------------------------------------
1 | _ = require('underscore')
2 | Surface = require('famous/core/surface')
3 | GridLayout = require('famous/views/gridlayout')
4 | StateModifier = require('famous/modifiers/statemodifier')
5 | MenuButton = require('./menu-button')
6 | Transform = require('famous/core/transform')
7 |
8 | class MenuInterior extends require('famous/core/view')
9 |
10 | #
11 | # Properties
12 |
13 | filters:
14 | [
15 | {
16 | name: 'Everything'
17 | value: 'pics'
18 | },
19 | {
20 | name: 'Funny'
21 | value: 'funny'
22 | },
23 | {
24 | name: 'Mildly Interesting'
25 | value: 'mildlyinteresting'
26 | },
27 | {
28 | name: 'Gifs'
29 | value: 'gifs'
30 | }
31 | ]
32 |
33 | #
34 | # Init
35 |
36 | constructor: (options) ->
37 | super
38 | @collection = options.collection
39 |
40 | @createMenu()
41 | @createClose()
42 |
43 |
44 | #
45 | # Control
46 |
47 | createMenu: ->
48 | stateMod = new StateModifier
49 | size: [undefined, 300]
50 |
51 | grid = new GridLayout
52 | dimensions: [2,2]
53 |
54 | @surfaces = []
55 | grid.sequenceFrom(@surfaces)
56 |
57 | for filter in @filters
58 | surface = new MenuButton
59 | value: filter.value
60 | content: filter.name
61 | classes: ['menu-button']
62 |
63 |
64 | surface.on('button:clicked', @onCategoryClick)
65 | surface.filter = filter
66 | @surfaces.push surface
67 |
68 | _.findWhere(@surfaces, content: 'Everything').addClass('selected')
69 |
70 | @add(stateMod).add(grid)
71 |
72 | createClose: ->
73 | stateMod = new StateModifier
74 | transform: Transform.translate(0, 300, 0)
75 |
76 | surface = new Surface
77 | size: [undefined, 200]
78 | content: 'Settings'
79 | classes: ['settings']
80 |
81 | surface.on('click', @onCloseClick)
82 |
83 | @add(stateMod).add(surface)
84 |
85 |
86 | #
87 | # Events
88 |
89 | onCloseClick: =>
90 | @_eventOutput.trigger('click')
91 |
92 | onCategoryClick: (category) =>
93 | _.each(@surfaces, (surface) -> surface.removeClass('selected'))
94 | _.findWhere(@surfaces, value: category).addClass('selected')
95 |
96 | @collection.category = category
97 | @collection.resetPageIndex()
98 | @collection.getNextPage()
99 |
100 | module.exports = MenuInterior
--------------------------------------------------------------------------------