├── .gitignore
├── .npmignore
├── LICENSE.md
├── README.md
├── index.js
├── lib
├── addPasswordProtection.js
└── createSections.js
├── package-lock.json
├── package.json
├── templates
├── .babelrc
├── .gitkeep
├── backend
│ └── php
│ │ └── static
│ │ ├── index.php
│ │ ├── json
│ │ └── share.json
│ │ └── lib
│ │ └── Meta.php
├── base
│ ├── .editorconfig
│ ├── .eslintrc
│ ├── .gitattributes
│ ├── .jshintrc
│ ├── COMPONENTS.md
│ ├── README.md
│ ├── SCRIPTS.md
│ ├── STANDARDS.md
│ ├── TESTS.md
│ ├── config-preloader.json
│ ├── config.json
│ ├── gitignore
│ ├── package.json
│ ├── raw-assets
│ │ ├── fonts
│ │ │ └── .gitkeep
│ │ ├── json
│ │ │ ├── .gitkeep
│ │ │ └── test.json
│ │ ├── sounds
│ │ │ ├── .gitkeep
│ │ │ ├── button-click.mp3
│ │ │ ├── button-rollover.mp3
│ │ │ └── button-sprite.mp3
│ │ ├── svg
│ │ │ ├── captions-off.svg
│ │ │ ├── captions-on.svg
│ │ │ ├── close.svg
│ │ │ ├── enter-fullscreen.svg
│ │ │ ├── exit-fullscreen.svg
│ │ │ ├── loader.svg
│ │ │ ├── muted.svg
│ │ │ ├── pause.svg
│ │ │ ├── play.svg
│ │ │ ├── rotate.svg
│ │ │ └── unmuted.svg
│ │ └── videos
│ │ │ ├── .gitkeep
│ │ │ └── captions-test.vtt
│ ├── src
│ │ ├── data
│ │ │ └── sounds.js
│ │ └── util
│ │ │ ├── audio.js
│ │ │ ├── detect.js
│ │ │ ├── seconds-to-minutes.js
│ │ │ └── stats.js
│ └── static
│ │ ├── .htaccess
│ │ ├── humans.txt
│ │ ├── index.html
│ │ └── robots.txt
├── bigwheel
│ └── src
│ │ ├── framework
│ │ ├── index.js
│ │ └── routes.js
│ │ ├── index.js
│ │ └── model
│ │ └── index.js
├── react
│ └── src
│ │ ├── components
│ │ ├── HamburgerButton
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ ├── MobileFullscreenVideo
│ │ │ └── index.js
│ │ ├── Preloader
│ │ │ ├── Preloader.js
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ ├── Rotate
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ └── VideoPlayer
│ │ │ ├── VideoPoster
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ │ ├── VideoTimeline
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ ├── decorators
│ │ └── connectTransitionWrapper.js
│ │ ├── framework
│ │ └── index.js
│ │ ├── index.js
│ │ ├── routes
│ │ └── index.js
│ │ ├── sections
│ │ ├── App
│ │ │ ├── App.js
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ └── Landing
│ │ │ ├── Landing.js
│ │ │ ├── index.js
│ │ │ └── style.{{css}}
│ │ ├── store
│ │ ├── actions
│ │ │ ├── app.js
│ │ │ └── preloader.js
│ │ ├── index.js
│ │ ├── keys.js
│ │ └── reducers
│ │ │ ├── app.js
│ │ │ └── preloader.js
│ │ └── test
│ │ ├── components
│ │ ├── HamburgerButton
│ │ │ └── index.js
│ │ ├── MobileFullscreenVideo
│ │ │ └── index.js
│ │ ├── Preloader
│ │ │ └── index.js
│ │ ├── SoundTest.js
│ │ └── TestPage
│ │ │ └── index.js
│ │ └── index.js
├── scripts
│ ├── clean.js
│ ├── config.js
│ ├── copy.js
│ ├── dev.js
│ ├── facebook.js
│ ├── favicons
│ │ ├── faviconDescription.json
│ │ ├── favicon_template.png
│ │ └── favicons.js
│ ├── gzip.js
│ ├── less
│ │ └── style.js
│ ├── live.js
│ ├── lowercase.js
│ ├── preloader.js
│ ├── release.js
│ ├── scss
│ │ └── style.js
│ ├── template.js
│ └── timestamp.js
├── sections
│ └── bigwheel
│ │ ├── normal
│ │ ├── index.js
│ │ ├── style.css
│ │ └── template.hbs
│ │ └── preloader
│ │ ├── index.js
│ │ ├── style.css
│ │ └── template.hbs
├── style
│ ├── fonts.{{css}}
│ ├── global.{{css}}
│ ├── main.{{css}}
│ ├── normalize.{{css}}
│ └── vars.{{css}}
└── unsupported
│ ├── default
│ ├── src
│ │ └── util
│ │ │ └── warning.js
│ └── static
│ │ ├── device-matrix.json
│ │ └── unsupported.html
│ ├── none
│ └── src
│ │ └── unsupported.js
│ └── php
│ └── static
│ ├── index.php
│ ├── lib
│ └── whichbrowser.phar
│ └── main.php
└── test
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 | /output
7 | /test/output
8 | .idea
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 | /test
7 | test.js
8 | demo/
9 | .npmignore
10 | LICENSE.md
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2015 Jam3
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
20 | OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nyg-jam3
2 |
3 | [](http://github.com/badges/stability-badges)
4 |
5 | Jam3 project scaffold based on [nyg](https://www.npmjs.com/package/nyg). Used to create the basic files needed for a Jam3 project.
6 |
7 | ## Usage
8 |
9 | [](https://www.npmjs.com/package/nyg-jam3)
10 |
11 | The nyg generator is designed to function similar to yeoman. To get it running, simply follow these steps:
12 |
13 | ```bash
14 | npm i nyg -g
15 | npm i nyg-jam3 -g
16 | cd your-project-directory
17 | nyg nyg-jam3
18 | ```
19 |
20 | You will then be prompted with a number of questions, which will define the project. The appropriate files will then be copied to the current directory and it will install all your needed dependencies. Congratulations, you are now setup with the basis of a Jam3 project.
21 |
22 | ## Prompts
23 |
24 | `What is your name? (Author)`
25 | Default: (empty string)
26 | A name used in the README.md, package.json and humans.txt.
27 |
28 | `What is your email? (Author Email)`
29 | Default: (empty string)
30 | An email used in the package.json and humans.txt.
31 |
32 | `Describe the project:`
33 | Default: (empty string)
34 | A brief description of the project that is used at the top of the README.md.
35 |
36 | `What is your git repository? (GitHub Repository)`
37 | Default: (empty string)
38 | The git repository used for the project, used within the package.json.
39 |
40 | `What framework will your project use?"`
41 | Default: React
42 | The framework that this project will be based on, all necessary files and modules will be downloaded to get you up and running with the selected framework. Currently supports React, Bigwheel, or None. In the case of None, source files won't be created, but all the common development scripts will still be setup.
43 |
44 | `Would you perfer ComponentName/ComponentName.js over ComponentName/index.js?`
45 | Default: false
46 | Whether file names will follow the convention of [folder name]/[folder name].js or [folder name]/index.js.
47 |
48 | `Would you like to use ES6?`
49 | Default: true
50 | Whether to use ES6 and babel transpilation. Sets up a .babelrc file and all necessary dependencies.
51 |
52 | `What css preprocessor will your project use?`
53 | Default: SCSS
54 | Which css preprocessor should be setup on the project, defaults to SASS, but LESS is also an option.
55 |
56 | `Separate common npm modules into vendor.js?`
57 | Default: true
58 | Whether to separate all npm modules into a separate vender.js file, limiting the bundle.js file to just custom code.
59 |
60 | `What backend language would you like to use?`
61 | Default: PHP
62 | Whether to copy over backend libraries that aid development such as automatic meta tag generation.
63 |
64 | `Would you like to include an unsupported page?`
65 | Default: true
66 | Whether to include automatic unsupported page redirection.
67 |
68 | `Choose the password to use for password protection. (leave blank to disable)`
69 | Default: (empty string)
70 | If you want to enable password protection via .htaccess, simply type the password you would like to use and the .htaccess and .htpasswd files will be created.
71 |
72 | `Where on the server will your .htpasswd be located?`
73 | Default: /var/www
74 | If you opted to add password protection, this will need to be set to the location of the .htpasswd file in your production environment.
75 |
76 | ### [Generated Project Documentation](templates/base/README.md)
77 |
78 | ## License
79 |
80 | MIT, see [LICENSE.md](http://github.com/Jam3/generator-jam3/blob/master/LICENSE.md) for details.
81 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var nyg = require('nyg');
4 | var spawn = require('cross-spawn');
5 |
6 | var createSections = require('./lib/createSections');
7 | var Favicon = require('./templates/scripts/favicons/favicons.js');
8 | var addPasswordProtection = require('./lib/addPasswordProtection.js');
9 |
10 | var prompts = [{
11 | type: "input",
12 | name: "author",
13 | message: "What is your name? (Author)",
14 | default: ""
15 | }, {
16 | type: "input",
17 | name: "email",
18 | message: "What is your email? (Author Email)",
19 | default: ""
20 | }, {
21 | type: "input",
22 | name: "description",
23 | message: "Describe the project:",
24 | default: ""
25 | }, {
26 | type: "input",
27 | name: "repo",
28 | message: "What is your git repository? (GitHub Repository)",
29 | default: ""
30 | }, {
31 | type: "list",
32 | message: "What framework will your project use?",
33 | name: "framework",
34 | choices: [{
35 | name: "React",
36 | value: "react"
37 | },{
38 | name: "Bigwheel / Handlebars",
39 | value: "bigwheel",
40 | checked: true
41 | },
42 | {
43 | name: "None",
44 | value: "none"
45 | }]
46 | },{
47 | type: "confirm",
48 | name: "sectionNames",
49 | message: "Would you prefer ComponentName/ComponentName.js over ComponentName/index.js?",
50 | default: false,
51 | when: function(answers) { return answers.framework!=='none'; }
52 | },{
53 | type: "confirm",
54 | name: "useES6",
55 | message: "Would you like to use ES6?",
56 | default: true,
57 | when: function(answers) { return answers.framework==='bigwheel' || answers.framework==='none'; }
58 | },{
59 | type: "list",
60 | message: "What css preprocessor will your project use?",
61 | name: "css",
62 | choices: [{
63 | name: "SCSS",
64 | value: "scss",
65 | checked: true
66 | },{
67 | name: "LESS",
68 | value: "less"
69 | }]
70 | },{
71 | type: "confirm",
72 | name: "vendor",
73 | message: "Separate common npm modules into vendor.js?",
74 | default: true
75 | },{
76 | type: "list",
77 | message: "What backend language would you like to use?",
78 | name: "backend",
79 | choices: [{
80 | name: "PHP",
81 | value: "php"
82 | }, {
83 | name: "None",
84 | value: "none"
85 | }]
86 | },{
87 | type: "confirm",
88 | name: "unsupported",
89 | message: "Would you like to include an unsupported page?",
90 | default: true
91 | },{
92 | type: "input",
93 | name: "password",
94 | message: "Choose the password to use for password protection. (leave blank to disable)",
95 | default: ""
96 | },{
97 | type: "input",
98 | name: "passLocation",
99 | message: "Where on the server will your .htpasswd be located?",
100 | default: "/var/www",
101 | when: function(answers) { return answers.password!==''; }
102 | }];
103 | var globs = [
104 | { base: 'templates/{{framework}}/' },
105 | { base: 'templates/', glob: 'scripts/*' },
106 | { base: 'templates/base/' },
107 | { base: 'templates/style/', output: 'src/style/' },
108 | { base: 'templates/scripts/{{css}}/', glob: '*', output: 'scripts/' },
109 | { base: 'templates/scripts/favicons/', glob: '*', output: 'scripts/favicons/' },
110 | { base: 'templates/backend/{{backend}}/'},
111 | { base: 'templates/unsupported/default/', when: function(answers) { return answers.unsupported; }},
112 | { base: 'templates/unsupported/{{backend}}/', when: function(answers) { return answers.unsupported; } }
113 |
114 | ];
115 | var gen = nyg(prompts,globs,{ignore:[".phar"]})
116 | .on('postprompt', onPostPrompt)
117 | .on('postcopy', onPostCopy)
118 | .on('postinstall', onPostInstall)
119 | .run();
120 |
121 | //*************************** Event Handlers ***************************
122 |
123 | function onPostPrompt() {
124 | var repo = gen.config.get('repo').split('/');
125 | repo = repo[repo.length-1].toLowerCase().replace('.git','');
126 | gen.config.set('repoName', repo || '');
127 | if (gen.config.get('framework')!=='none' && gen.config.get('framework')!=='bigwheel') gen.config.set('useES6',true);
128 | }
129 |
130 | function onPostCopy() {
131 | var done = gen.async();
132 | fs.rename(path.join(gen.cwd,'gitignore'),path.join(gen.cwd,'.gitignore'),function() {
133 | if (gen.config.get('framework')!=='none') {
134 | if (gen.config.get('useES6')) {
135 | gen.copy('templates/.babelrc','.babelrc',function() {
136 | if (gen.config.get('sectionNames') && gen.config.get('framework')==='react') {
137 | var style = gen.config.get('css');
138 | var files = [
139 | [path.join(gen.cwd,'src/components/Preloader/style.'+style),path.join(gen.cwd,'src/components/Preloader/Preloader.'+style)],
140 | [path.join(gen.cwd,'src/components/Rotate/index.js'),path.join(gen.cwd,'src/components/Rotate/Rotate.js')],
141 | [path.join(gen.cwd,'src/components/Rotate/style.'+style),path.join(gen.cwd,'src/components/Rotate/Rotate.'+style)],
142 | [path.join(gen.cwd,'src/components/MobileFullscreenVideo/index.js'),path.join(gen.cwd,'src/components/MobileFullscreenVideo/MobileFullscreenVideo.js')],
143 | [path.join(gen.cwd,'src/components/MobileFullscreenVideo/style.'+style),path.join(gen.cwd,'src/components/MobileFullscreenVideo/MobileFullscreenVideo.'+style)],
144 | [path.join(gen.cwd,'src/components/VideoPlayer/index.js'),path.join(gen.cwd,'src/components/VideoPlayer/VideoPlayer.js')],
145 | [path.join(gen.cwd,'src/components/VideoPlayer/style.'+style),path.join(gen.cwd,'src/components/VideoPlayer/VideoPlayer.'+style)],
146 | [path.join(gen.cwd,'src/components/VideoPlayer/VideoPoster/index.js'),path.join(gen.cwd,'src/components/VideoPlayer/VideoPoster/VideoPoster.js')],
147 | [path.join(gen.cwd,'src/components/VideoPlayer/VideoPoster/style.'+style),path.join(gen.cwd,'src/components/VideoPlayer/VideoPoster/VideoPoster.'+style)],
148 | [path.join(gen.cwd,'src/components/VideoPlayer/VideoTimeline/index.js'),path.join(gen.cwd,'src/components/VideoPlayer/VideoTimeline/VideoTimeline.js')],
149 | [path.join(gen.cwd,'src/components/VideoPlayer/VideoTimeline/style.'+style),path.join(gen.cwd,'src/components/VideoPlayer/VideoTimeline/VideoTimeline.'+style)],
150 | [path.join(gen.cwd,'src/sections/App/style.'+style),path.join(gen.cwd,'src/sections/App/App.'+style)],
151 | [path.join(gen.cwd,'src/components/HamburgerButton/index.js'),path.join(gen.cwd,'src/components/HamburgerButton/HamburgerButton.js')],
152 | [path.join(gen.cwd,'src/components/HamburgerButton/style.'+style),path.join(gen.cwd,'src/components/HamburgerButton/HamburgerButton.'+style)]
153 | ];
154 | renameFiles(files,function() {
155 | createSections(gen,done);
156 | });
157 | } else {
158 | createSections(gen,done);
159 | }
160 | });
161 | } else {
162 | createSections(gen,done);
163 | }
164 | } else {
165 | fs.writeFile(path.join(gen.cwd,'src/index.js'),'',function() {
166 | if (gen.config.get('useES6')) {
167 | gen.copy('templates/.babelrc','.babelrc',done);
168 | } else {
169 | done();
170 | }
171 | });
172 | }
173 | if (gen.config.get('password') !== '') {
174 | addPasswordProtection(gen.cwd, gen.config.get('password'));
175 | }
176 | });
177 | }
178 |
179 | function renameFiles(arr,cb) {
180 | var total = arr.length;
181 | var count = 0;
182 | var done = function() {
183 | count++;
184 | if (count>=total) cb();
185 | };
186 | arr.forEach(function(cur) {
187 | fs.rename(cur[0],cur[1],done);
188 | });
189 | }
190 |
191 | function onPostInstall() {
192 | var done = gen.async();
193 | var npm = spawn('npm', ['run','favicons'], {cwd: gen.cwd, stdio: 'inherit'});
194 | npm.on('error',function() {
195 | console.log(arguments);
196 | });
197 | npm.on('close',function(code) {
198 | if (code!==0) console.log(new Error('npm run favicons exited with non-zero code ' + code + '. Please try running "npm run favicons" again as administrator.'));
199 | done();
200 | });
201 | }
202 |
--------------------------------------------------------------------------------
/lib/addPasswordProtection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 | var md5 = require('md5');
6 | var prependFile = require('prepend-file');
7 |
8 | module.exports = function(location, password) {
9 | createHtPasswd(location, password);
10 | modifyHtAccess(location);
11 | }
12 |
13 | function createHtPasswd(location, password) {
14 | var htpasswdData = "# This file should be located in a private place in the server\n";
15 | htpasswdData += "user:" + md5(password);
16 |
17 | fs.writeFile(path.join(location,'.htpasswd'), htpasswdData, function(err) {
18 | if (err) throw err;
19 | });
20 | }
21 |
22 | function modifyHtAccess(location) {
23 | var htaccessData = '' +
24 | 'AuthName "Restricted Area"\n' +
25 | 'AuthType Basic\n' +
26 | 'AuthUserFile ' + path.join('{{htpasswd}}', '.htpasswd').replace('\\','/') + '\n' +
27 | 'Require valid-user\n\n';
28 |
29 | prependFile(path.join(location, '/static/.htaccess'), htaccessData, function(err) {
30 | if (err) throw err;
31 | });
32 | }
--------------------------------------------------------------------------------
/lib/createSections.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var path = require('path');
3 | var fs = require('fs');
4 | module.exports = function(gen,cb) {
5 | var sections;
6 | if (gen.config.get('framework')==='bigwheel') {
7 | var model = require(path.join(process.cwd(),'src/model/index.js'));
8 | sections = ['Preloader'];
9 | Object.keys(model).forEach(function(key) {
10 | if (key.charAt(0)==="/") sections.push(key.substr(1) || 'Landing');
11 | });
12 | } else {
13 | sections = ['Landing'];
14 | }
15 | nextSection(sections,gen,cb);
16 | };
17 |
18 | function nextSection(arr,gen,cb) {
19 | if (arr.length>0) {
20 | createSection(arr.shift(),gen,function() {
21 | nextSection(arr,gen,cb);
22 | });
23 | } else {
24 | if (cb) cb();
25 | }
26 | }
27 |
28 | function createSection(cur,gen,cb) {
29 | var name = gen.config.get('sectionNames') ? '{{section}}.js' : 'index.js';
30 | var style = gen.config.get('sectionNames') ? '{{section}}.{{css}}' : 'style.{{css}}';
31 | var count = 0;
32 | var total = 0;
33 | var done = function() {
34 | count++;
35 | if (count>=total) cb();
36 | };
37 | fs.stat('src/sections/'+cur+'/',function(err,stat) {
38 | if (err) {
39 | gen.config.set('section',cur);
40 | if (gen.config.get('framework')==='bigwheel') {
41 | var type = cur==='Preloader' ? 'preloader' : 'normal';
42 | gen.copy('templates/sections/{{framework}}/'+type+'/index.js','src/sections/{{section}}/'+name,done);
43 | gen.copy('templates/sections/{{framework}}/'+type+'/style.css','src/sections/{{section}}/'+style,done);
44 | gen.copy('templates/sections/{{framework}}/'+type+'/template.hbs','src/sections/{{section}}/template.hbs',done);
45 | gen.copy('templates/.gitkeep','src/ui/{{section}}/.gitkeep',done);
46 | total += 4;
47 | } else if (gen.config.get('framework')==='react') {
48 | gen.copy('templates/sections/{{framework}}/index.js','src/sections/{{section}}/'+name,done);
49 | gen.copy('templates/sections/{{framework}}/style.css','src/sections/{{section}}/'+style,done);
50 | total += 2;
51 | }
52 | } else {
53 | done();
54 | }
55 | });
56 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nyg-jam3",
3 | "version": "3.0.0",
4 | "description": "Jam3 project scaffold generator based on nyg",
5 | "main": "index.js",
6 | "license": "MIT",
7 | "author": {
8 | "name": "Nick Poisson",
9 | "email": "nick@jam3.com",
10 | "url": "https://github.com/njam3"
11 | },
12 | "dependencies": {
13 | "cross-spawn": "^4.0.0",
14 | "md5": "^2.1.0",
15 | "nyg": "^2.7.0",
16 | "prepend-file": "^1.3.0",
17 | "rfg-api": "^0.1.7"
18 | },
19 | "devDependencies": {},
20 | "scripts": {
21 | "test": "node test/"
22 | },
23 | "keywords": [
24 | "jam3",
25 | "project",
26 | "scaffold",
27 | "generator",
28 | "nyg"
29 | ],
30 | "repository": {
31 | "type": "git",
32 | "url": "git://github.com/Jam3/generator-jam3.git"
33 | },
34 | "homepage": "https://github.com/Jam3/generator-jam3",
35 | "bugs": {
36 | "url": "https://github.com/Jam3/generator-jam3/issues"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/templates/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015"{{#is framework 'react'}},
4 | "react",
5 | "stage-1"{{/is}}
6 | ],
7 | "plugins": [
8 | {{#is framework 'react'}}"transform-decorators-legacy",
9 | "transform-object-assign"{{/is}}
10 | ],
11 | "env": {
12 | {{#is framework 'react'}}
13 | "production": {
14 | "presets": [
15 | "react-optimize"
16 | ]
17 | }{{/is}}
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/templates/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Experience-Monks/generator-jam3/c8c0f674245b4a2475de235e3cf2ddaa65b4c2f8/templates/.gitkeep
--------------------------------------------------------------------------------
/templates/backend/php/static/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | write();
8 | ?>
9 |
10 |
11 |
12 |
13 |
14 | \{{#if vendor}}
15 | \{{/if}}
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/templates/backend/php/static/json/share.json:
--------------------------------------------------------------------------------
1 | {
2 | "default": {
3 | "image": "",
4 | "title": "{{repoName}}",
5 | "description": "{{description}}",
6 | "og:site_name": "",
7 | "twitter:site": "",
8 | "twitter:creator": ""
9 | },
10 | "route/subroute": {
11 | "title": "",
12 | "description": "",
13 | "keywords": ""
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/templates/backend/php/static/lib/Meta.php:
--------------------------------------------------------------------------------
1 | '',
12 | 'description' => '',
13 | 'keywords' => '',
14 | 'og:title' => '',
15 | 'og:type' => 'website',
16 | 'og:image' => '',
17 | 'og:url' => '',
18 | 'og:description' => '',
19 | 'og:site_name' => '',
20 | 'twitter:card' => 'summary_large_image',
21 | 'twitter:title' => '',
22 | 'twitter:image' => '',
23 | 'twitter:description' => '',
24 | 'twitter:site' => '',
25 | 'twitter:creator' => ''
26 | );
27 | var $nonMeta = array(
28 | 'title'
29 | );
30 |
31 | function Meta($json=NULL,$path=NULL) {
32 | $this->ua = strtolower($_SERVER['HTTP_USER_AGENT']);
33 | if (array_key_exists('HTTP_X_FORWARDED_PROTO',$_SERVER)) {
34 | $protocol = htmlspecialchars($_SERVER['HTTP_X_FORWARDED_PROTO'], ENT_QUOTES);
35 | } else {
36 | $protocol = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') ? 'https' : 'http' );
37 | }
38 | $this->host = $protocol.'://'.htmlspecialchars($_SERVER['HTTP_HOST'], ENT_QUOTES);
39 | $this->path = htmlspecialchars(is_string($path) ? $path : $_SERVER['REQUEST_URI'], ENT_QUOTES);
40 | $this->url = $this->host."/".$this->path;
41 | $this->addTag('og:url',$this->url);
42 |
43 | if (!empty($json)) {
44 | $this->share = json_decode(file_get_contents($json),true);
45 | $this->setPath($this->path);
46 | }
47 | }
48 |
49 | function isBot() {
50 | $isBot = false;
51 | for ($i=0; $iuaList); $i++) {
52 | if (strpos($this->ua,$this->uaList[$i])!==false) $isBot = true;
53 | }
54 | return $isBot;
55 | }
56 |
57 | function setPath($path) {
58 | $this->path = $path;
59 | $data = $this->share["default"];
60 | if (@$this->share[$path]) $data = array_merge($data, $this->share[$path]);
61 | $this->addTags($data);
62 | }
63 |
64 | function addTag($tag, $content) {
65 | $this->tags[$tag] = $content;
66 | if ($tag==='title' || $tag==='description' || $tag==='image') {
67 | $this->tags['twitter:'.$tag] = $content;
68 | $this->tags['og:'.$tag] = $content;
69 | }
70 | }
71 |
72 | function addTags($data) {
73 | foreach ($data as $key => $value) {
74 | $this->addTag($key,$value);
75 | }
76 | }
77 |
78 | function write() {
79 | foreach ($this->tags as $key => $value) {
80 | if (in_array($key,$this->nonMeta)) {
81 | echo '<'.$key.'>'.$value.''.$key.'>';
82 | } else {
83 | $type = (strpos($key,'og:')!==false) ? 'property' : 'name';
84 | echo '';
85 | }
86 | }
87 | }
88 |
89 | }
90 |
91 | ?>
92 |
--------------------------------------------------------------------------------
/templates/base/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/templates/base/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "parserOptions": {
4 | "ecmaVersion": 6,
5 | "sourceType": "module",
6 | "ecmaFeatures": {
7 | "experimentalObjectRestSpread": true,
8 | "jsx": true
9 | }
10 | },
11 | "globals": {
12 | "ASSET_PATH": true,
13 | "_":true,
14 | "__":true,
15 | "THREE": false,
16 | "Int8Array": false,
17 | "Int16Array": false,
18 | "Int32Array": false,
19 | "Uint8Array": false,
20 | "Uint16Array": false,
21 | "Uint32Array": false,
22 | "Float32Array": false,
23 | "Float64Array": false,
24 | "Array": false,
25 | "Uint8ClampedArray": false,
26 | "google": false,
27 | "Promise": false,
28 | "document": false,
29 | "navigator": false,
30 | "window": false,
31 | "TimelineLite": false,
32 | "TimelineMax": false,
33 | "TweenLite": false,
34 | "TweenMax": false,
35 | "Back": false,
36 | "Bounce": false,
37 | "Circ": false,
38 | "Cubic": false,
39 | "Ease": false,
40 | "EaseLookup": false,
41 | "Elastic": false,
42 | "Expo": false,
43 | "Linear": false,
44 | "Power0": false,
45 | "Power1": false,
46 | "Power2": false,
47 | "Power3": false,
48 | "Power4": false,
49 | "Quad": false,
50 | "Quart": false,
51 | "Quint": false,
52 | "RoughEase": false,
53 | "Sine": false,
54 | "SlowMo": false,
55 | "SteppedEase": false,
56 | "Strong": false,
57 | "Draggable": false,
58 | "SplitText": false,
59 | "VelocityTracker": false,
60 | "CSSPlugin": false,
61 | "ThrowPropsPlugin": false,
62 | "BezierPlugin": false
63 | },
64 | "plugins": [
65 | "react",
66 | "standard",
67 | "promise"
68 | ],
69 | "extends": [
70 | ],
71 | "env": {
72 | "browser": true,
73 | "node": true
74 | },
75 | "rules": {
76 | "no-console": 0,
77 | "no-extra-semi": 2,
78 | "semi-spacing": 2,
79 | "semi": 2,
80 | "guard-for-in": 1,
81 | "no-trailing-spaces": 1,
82 | "react/jsx-uses-vars": 1,
83 | "react/jsx-uses-react": 1,
84 | "react/jsx-wrap-multilines": 1,
85 | "react/react-in-jsx-scope": 1,
86 | "react/prop-types": 0,
87 | "react/sort-comp": [1, {
88 | "order": [
89 | "static-methods",
90 | "lifecycle",
91 | "everything-else",
92 | "render"
93 | ],
94 | "groups": {
95 | "lifecycle": [
96 | "displayName",
97 | "propTypes",
98 | "contextTypes",
99 | "childContextTypes",
100 | "mixins",
101 | "statics",
102 | "defaultProps",
103 | "constructor",
104 | "getDefaultProps",
105 | "getInitialState",
106 | "state",
107 | "getChildContext",
108 | "componentWillMount",
109 | "componentDidMount",
110 | "componentWillReceiveProps",
111 | "shouldComponentUpdate",
112 | "componentWillUpdate",
113 | "componentDidUpdate",
114 | "componentWillUnmount",
115 | "componentWillAppear",
116 | "componentWillEnter",
117 | "componentWillLeave"
118 | ]
119 | }
120 | }
121 | ],
122 | "no-multi-spaces": 1,
123 | "no-use-before-define": 1,
124 | "arrow-spacing": [2, { "before": true, "after": true }],
125 | "block-spacing": [2, "always"],
126 | "brace-style": [2, "1tbs", { "allowSingleLine": true }],
127 | "camelcase": [2, { "properties": "never" }],
128 | "comma-spacing": [2, { "before": false, "after": true }],
129 | "comma-dangle": 0,
130 | "id-length": [1, {"min":1, "max": 50}],
131 | "space-before-function-paren": 0,
132 | "comma-style": [2, "last"],
133 | "curly": [2, "multi-line"],
134 | "dot-location": [2, "property"],
135 | "eqeqeq": [2, "always", {"null": "ignore"}],
136 | "func-call-spacing": [2, "never"],
137 | "handle-callback-err": [2, "^(err|error)$" ],
138 | "indent": [2, 2, { "SwitchCase": 1 }],
139 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
140 | "keyword-spacing": [2, { "before": true, "after": true }],
141 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
142 | "new-parens": 2,
143 | "no-array-constructor": 2,
144 | "no-caller": 2,
145 | "no-class-assign": 2,
146 | "no-cond-assign": 2,
147 | "no-const-assign": 2,
148 | "no-constant-condition": [2, { "checkLoops": false }],
149 | "no-control-regex": 2,
150 | "no-dupe-args": 2,
151 | "no-dupe-class-members": 2,
152 | "no-dupe-keys": 2,
153 | "no-duplicate-case": 2,
154 | "no-duplicate-imports": 2,
155 | "no-empty-character-class": 2,
156 | "no-empty-pattern": 2,
157 | "no-eval": 2,
158 | "no-ex-assign": 2,
159 | "no-extend-native": 2,
160 | "no-extra-bind": 2,
161 | "no-extra-boolean-cast": 2,
162 | "no-extra-parens": [2, "functions"],
163 | "no-fallthrough": 2,
164 | "no-floating-decimal": 2,
165 | "no-func-assign": 2,
166 | "no-global-assign": 2,
167 | "no-implied-eval": 2,
168 | "no-inner-declarations": [2, "functions"],
169 | "no-invalid-regexp": 2,
170 | "no-irregular-whitespace": 2,
171 | "no-iterator": 2,
172 | "no-label-var": 2,
173 | "no-labels": [2, { "allowLoop": false, "allowSwitch": false }],
174 | "no-lone-blocks": 2,
175 | "no-mixed-spaces-and-tabs": 2,
176 | "no-multi-str": 2,
177 | "no-negated-in-lhs": 2,
178 | "no-new": 2,
179 | "no-new-func": 2,
180 | "no-new-object": 2,
181 | "no-new-require": 2,
182 | "no-new-symbol": 2,
183 | "no-new-wrappers": 2,
184 | "no-obj-calls": 2,
185 | "no-octal": 2,
186 | "no-octal-escape": 2,
187 | "no-path-concat": 2,
188 | "no-proto": 2,
189 | "no-redeclare": 2,
190 | "no-regex-spaces": 2,
191 | "no-return-assign": [2, "except-parens"],
192 | "no-self-assign": 2,
193 | "no-self-compare": 2,
194 | "no-sequences": 2,
195 | "no-shadow-restricted-names": 2,
196 | "no-sparse-arrays": 2,
197 | "no-tabs": 2,
198 | "no-template-curly-in-string": 2,
199 | "no-this-before-super": 2,
200 | "no-throw-literal": 2,
201 | "no-undef": 2,
202 | "no-undef-init": 2,
203 | "no-unexpected-multiline": 2,
204 | "no-unmodified-loop-condition": 2,
205 | "no-unneeded-ternary": [2, { "defaultAssignment": false }],
206 | "no-unreachable": 2,
207 | "no-unsafe-finally": 2,
208 | "no-unsafe-negation": 2,
209 | "no-unused-vars": [2, { "vars": "all", "args": "none" }],
210 | "no-unused-expressions": 2,
211 | "no-useless-call": 2,
212 | "no-useless-computed-key": 2,
213 | "no-useless-escape": 1,
214 | "no-useless-rename": 2,
215 | "no-whitespace-before-property": 1,
216 | "no-with": 2,
217 | "object-property-newline": [2, { "allowMultiplePropertiesPerLine": true }],
218 | "one-var": [2, { "initialized": "never" }],
219 | "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }],
220 | "padded-blocks": [2, "never"],
221 | "quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
222 | "rest-spread-spacing": [2, "never"],
223 | "space-in-parens": [1, "never"],
224 | "space-infix-ops": 1,
225 | "space-unary-ops": [1, { "words": true, "nonwords": false }],
226 | "template-curly-spacing": [2, "never"],
227 | "unicode-bom": [2, "never"],
228 | "use-isnan": 2,
229 | "valid-typeof": 2,
230 | "wrap-iife": [2, "any", { "functionPrototypeMethods": true }],
231 | "yield-star-spacing": [2, "both"],
232 | "yoda": [2, "never"],
233 | "standard/object-curly-even-spacing": [2, "either"],
234 | "standard/array-bracket-even-spacing": [2, "either"],
235 | "standard/computed-property-even-spacing": [2, "even"],
236 | "promise/param-names": 2
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/templates/base/.gitattributes:
--------------------------------------------------------------------------------
1 | raw-assets/fonts/**/* filter=lfs diff=lfs merge=lfs -text
2 | raw-assets/images/**/* filter=lfs diff=lfs merge=lfs -text
3 | raw-assets/sounds/**/* filter=lfs diff=lfs merge=lfs -text
4 | raw-assets/videos/**/* filter=lfs diff=lfs merge=lfs -text
5 |
--------------------------------------------------------------------------------
/templates/base/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "esnext": true,
4 | "bitwise": true,
5 | "camelcase": true,
6 | "curly": true,
7 | "eqeqeq": true,
8 | "immed": true,
9 | "indent": 2,
10 | "latedef": true,
11 | "newcap": true,
12 | "noarg": true,
13 | "quotmark": "single",
14 | "undef": true,
15 | "unused": true,
16 | "strict": true
17 | }
18 |
--------------------------------------------------------------------------------
/templates/base/COMPONENTS.md:
--------------------------------------------------------------------------------
1 | [Back](README.md) | [Scripts](SCRIPTS.md)
2 | # Components
3 |
4 | ##### Table of Contents
5 | - [Preloader](#preloader)
6 | - [Rotate Screen](#rotate)
7 | - [Video Player](#video-player)
8 | - [Mobile Fullscreen Video](#mobile-fs-video)
9 | - [Hamburger Button](#hamburger-button)
10 | - [Device Detection](#device)
11 | - [Stats](#stats)
12 | - [Unsupported Page](#unsupported)
13 | - [Meta](#meta)
14 | - [Audio](#audio)
15 |
16 |
17 | ## Preloader (components/Preloader)
18 | The preloader component is built on the top of [preloader module](https://www.npmjs.com/package/preloader). Please refer to it for more information.
19 |
20 | #### Setup
21 | Specify files or folders (to be read recursively) using glob format in `config-preloader.json` in the root of the project.
22 | Example preloader json file:
23 | ```
24 | [
25 | "json/**/*"
26 | ]
27 | ```
28 |
29 | On `npm start` the preloader script will be executed and `preloader-list.json` will be created in `raw-assets` folder with the list of files to be loaded, excluding any junk files.
30 |
31 | **Important:**
32 | * Do not include `assets` folder in the paths of config file
33 | * Newly added assets won't affect the preloader list until node script restarted
34 |
35 | #### Props
36 | - `assetsList` (Required) - an array of assets to be loaded. It automatically determines the loader to be used based on file extension (json, mp4, etc.)
37 | - `minDisplayTime` - min time (in milliseconds) for the preloader to be shown
38 | - `options` - an object that contains the following properties:
39 |
40 | - `xhrImages` - loads images via XHR and converts to a Blob instead of the image tag. Default: `false`
41 | - `loadFullAudio` - specifies is audio should be loaded in full instead of just to the point where they can play. Default: `false`
42 | - `loadFillVideo` - specifies is video should be loaded in full instead of just to the point where they can play. Default: `false`
43 | - `onComplete` - function to attach to the complete event
44 | - `onProgress` - function to attach to the progress event
45 |
46 | #### API
47 | Follows [preloader](https://www.npmjs.com/package/preloader) API for the corresponding methods:
48 |
49 | - `add`
50 | - `get`
51 | - `load`
52 | - `stopLoad`
53 |
54 |
55 | ## Rotate Screen (components/Rotate)
56 |
57 | The rotate screen component simply needs to be included on the page. It determines the device orientation via the detect utility. It will determine if it needs to be shown based the boolean prop.
58 |
59 | #### Props
60 | - `portrait` - Boolean which determines if the site is locked to portrait or not. If `true`, the rotate screen will display if the device is in landscape mode, otherwise it will display if the device is in portrait mode. Default: true
61 |
62 |
63 | ## Video Player (components/VideoPlayer)
64 | This is basic video player that includes `VideoTimeline` and `VideoPoster` components.
65 | It is accessible and allows to be controlled using keyboard.
66 |
67 | #### Props
68 | - `src` - *String* (required) - video source
69 | - `poster` - *String* - poster image
70 | - `id` - - *String* or *Number* - video ID that will be sent back with `onPlay` hook
71 | - `preload` - *String* - determines whether video should automatically preload. Valid options are `auto`, `metadata` or `none`
72 | - `captions` - *Object* - track data refer to https://developer.mozilla.org/en/docs/Web/HTML/Element/track
73 | - `disableBackgroundCover`- *Boolean* - disable video cover effect
74 | - `allowKeyboardControl` - *Boolean* - allow/disallow toggle play state with space bar when video element is focused
75 | - `autoPlay` - *Boolean* - determines whether video should automatically play on load
76 | - `muted` - *Boolean* - determines whether video should play sound
77 | - `loop` - *Boolean* - determines whether video should loop
78 | - `togglePlayOnClick` - *Boolean* - allow/disallow toggle play state on video click
79 | - `showControlsOnLoad` - *Boolean* - determines whether to show video controls on load without mouse interaction
80 | - `hasCloseButton` - *Boolean* - render close button that is synced with controls
81 | - `hasPlayButton` - *Boolean* - render play button for video poster
82 | - `showPosterOnEnd` - *Boolean* - determines whether poster should show up after video has ended
83 | - `hasControls` - *Boolean* - render controls
84 | - `playsInline` - *Boolean* - determines if video plays inline on iPhone
85 | - `autoPlayDelay` - *Number* - auto play delay (in milliseconds). Only works with `autoPlay: true`
86 | - `controlsTimeout` - *Number* - time (in milliseconds) after which controls and close button hide if the user was inactive
87 | - `windowWidth` - *Number* - window width. It is required when for background cover videos - `disableBackgroundCover: false`
88 | - `windowHeight` - *Number* - window height. It is required when for background cover videos - `disableBackgroundCover: false`
89 | - `volume` - *Number* - values from 0 to 1
90 | - `startTime` - *Number* - video start time (in seconds)
91 | - `posterFadeDuration` - *Number* - poster fade out duration (in milliseconds)
92 | - `onPlay` - *Function* - on video play hook
93 | - `onPause` - *Function* - on video pause hook
94 | - `onEnd` - *Function* - on video end hook
95 | - `onClose` - *Function* - on close button click hook
96 |
97 | #### API
98 | - `showControls` - force controls to show
99 | - `hideControls`- force controls to hide
100 | - `getVideoElement` - access HTML video
101 | - `play`
102 | - `pause`
103 | - `mute`
104 | - `unmute`
105 | - `togglePlay`
106 | - `toggleMute`
107 | - `toggleFullScreen`
108 | - `toggleCaptions` - show/hide captions
109 |
110 |
111 | ## Mobile Fullscreen Video (components/MobilFsVideo)
112 | Component that triggers video to go fullscreen on Android and play in native browser on iOS
113 |
114 | #### Props
115 | - `src` - *String* - video source
116 | - `onOpen` *Function* - fullscreen enter (native player open) hook
117 | - `onClose` *Function* - fullscreen exit (native player close) hook
118 |
119 | #### API
120 | - `play`
121 | - `pause`
122 | - `getVideoElement` - access HTML video
123 |
124 |
125 |
126 | ## Hamburger Button (components/HamburgerButton)
127 |
128 | #### Props
129 | - `className` - *String* - additional class name
130 | - `style` - *Object* - additional styles
131 | - `tabIndex` - *Number* - container's tab index
132 | - `state` - *String* - one of the 3 available states: `idle`, `close` or `back`
133 | - `activeState` - *String* - the active state, `close` or `back`
134 | - `isMouseOver` - *Boolean* - force mouse over state
135 | - `onClick` - *Function* - `click` hook
136 | - `onMouseEnter` - *Function* - `mouseenter` hook
137 | - `onMouseLeave` - *Function* - `mouseleave` hook
138 |
139 |
140 | ## Device Detection (util/detect.js)
141 |
142 | The device detection utility is a javascript object with numerous properties to help you build conditionals based on the current browser / device. It includes the following properties.
143 | - `isBot` - Detect if is a crawler bot,
144 | - `isFacebook` - Detect if in-app Facebook browser,
145 | - `isTwitter` - Detect if in-app Twitter browser,
146 | - `isInstagram` - Detect if in-app Instagram browser,
147 | - `isPinterest` - Detect if in-app Pinterest browser,
148 | - `isInAppBrowser` - Detect if browser is in-app,
149 | - `inAppBrowserVersion` - in-app browser version,
150 | - `device` - returns either `phone`, `tablet`, or `desktop`
151 | - `vendor` - vendor name of the browser (i.e. "google inc.")
152 | - `os` - Returns the current operating system
153 | - `osVersion` - Returns the version of the current operating system
154 | - `browser` - Returns the current browser
155 | - `browserVersion` - Returns the version of the current browser
156 | - `manufacturer` - Returns the manufacturer of the current device
157 | - `devicePixelRatio` - Returns the current devicePixelRatio of the current screen
158 | - `classes` - Classes returns an array of classes to add to the body / html element to allow for easy conditional logic in css. These include device type, browser, and pixel ratio
159 | - `isMobile` - Boolean that describes if the device is a phone or a tablet
160 | - `isPhone` - Boolean that describes if the device is a phone
161 | - `isTablet` - Boolean that describes if the device is a tablet
162 | - `isDesktop` - Boolean that describes if the device is a desktop computer
163 | - `isChrome` - Boolean that describes if browser is Chrome
164 | - `isIE` - Boolean that describes if browser is Internet Explorer
165 | - `isEdge` - Boolean that describes if browser is Microsoft Edge
166 | - `isFirefox` - Boolean that describes if browser is Firefox
167 | - `isSafari` - Boolean that describes if browser is Safari
168 | - `isOpera` - Boolean that describes if browser is Opera
169 | - `md` - The [mobile-detect](npmjs.com/mobile-detect) object used in the device detection
170 | - `bowser` - The [bowser](npmjs.com/bowser) object used in the device detection
171 | - `orientation` - String that returns either `portrait` or `landscape`
172 |
173 |
174 | ## Stats (util/stats.js)
175 |
176 | A simple utility that tracks browser framerate. The script simply needs to be included and executed. This is already done for you in `index.js` and is currently setup to only display in the development environment.
177 |
178 |
179 | ## Unsupported Page
180 |
181 | The unsupported page is automatically redirected to via PHP. This is determined via `device-matrix.json` in the static folder of the project. Specify your minimum browser versions in the json. You can style your page by modifying `unsupported.html` also in the static folder of the project. Here is an example of the device-matrix.json:
182 |
183 | ```
184 | {
185 | "ie": 11,
186 | "safari": 8,
187 | "chrome": 47,
188 | "firefox": 42
189 | }
190 | ```
191 |
192 | This will ensure the browser is at a minimum, Internet Explorer 11, Safari 8, Chrome 47 or Firefox 42, otherwise it will redirect to the unsupported page.
193 |
194 |
195 | ## Meta
196 |
197 | Meta.php takes care of automatically populating Open Graph, Twitter Card data, and regular meta tags. Simply specify your routes with the accompanying title, description, and image in the share.json in the static folder and the rest will be taken care of. title, image, and description will automatically be spread across Open Graph, Twitter Card and regular meta tags. You can add any meta property into the json and it will be parsed and added as a meta tag. Here is an example share.json:
198 |
199 | ```
200 | {
201 | "default": {
202 | "image": "http://www.jam3.com/wp-content/uploads/2014/05/jam3_fb.jpg",
203 | "title": "Jam3 | Toronto Digital Design and Development Agency",
204 | "description": "Jam3 is one of the world’s top digital production and design agencies. We specialize in creating highly advanced, experiential works in both the advertising and entertainment industries.",
205 | "og:site_name": "Jam3.com",
206 | "twitter:site": "@Jam3",
207 | "twitter:creator": "@Jam3"
208 | },
209 | "about": {
210 | "title": "About - Jam3.com",
211 | "description": "“It’s not wise to violate rules until you know how to observe them.” Keep reading"
212 | }
213 | }
214 | ```
215 |
216 |
217 | ## Audio (util/audio.js)
218 |
219 | This is a Howler wrapper that reads sounds manifest - `data/sounds.js` and sets `Howl` instances for each manifest entry.
220 |
221 | Example manifest:
222 | ```
223 | {
224 | 'button-rollover': '{{path}}/rollover.mp3',
225 | 'button-click': ['{{path}}/click.wav', '{path}/click.mp3']
226 | 'sprite': {
227 | src: '{{path}}/sprite.mp3',
228 | sprite: {
229 | 'chunk-1': [0, 3000],
230 | 'chunk-1': [3000, 2000]
231 | }
232 | },
233 | 'ambient': {
234 | src: '{{path}}/ambient.mp3',
235 | loop: true,
236 | autoplay: true
237 | }
238 | }
239 | ```
240 |
241 | if manifest item is type of `String` or `Array`, then it will be used as source(s) and a `Howl` will be set up with it's default options.
242 | If manifest entry in type of `Object`, its property will be merged with Howler defaults.
243 |
244 | This utility is using Singleton pattern, so it will be initialized once upon first `import/require`.
245 | Thus, be careful with `preload` and `autoplay` options combination because if both are set to true for a sound, it will start playing on app initialization.
246 |
247 | **NOTE**: `preload` option is set to `false` for all sounds by default but can overridden via in manifest for specific sounds.
248 | You can also use `load` function for dynamic loading control. Refer to [Howler API](https://github.com/goldfire/howler.js#documentation).
249 |
250 | #### API
251 | - `sounds` (getter) - Get specific sound from the map by ID e.g. `audio.sounds['some-sound'].play()`
252 | - `extraData` (setter) - Update sound model. It won't replace the original data unless you overwrite existing in manifest keys e.g. `audio.extraData = {noise: '{path}noise.wav'}`
253 | - `play` - play sound or sprite by `ID` e.g. ```audio.play('button-click')``` or ```audio.play('chunk-1')```
254 |
255 | #### Example
256 | Take a look at code example `test/components/SoundTest.js`
257 |
258 | See in action in your browser http://localhost:9966/test/SoundTest
259 |
--------------------------------------------------------------------------------
/templates/base/README.md:
--------------------------------------------------------------------------------
1 | # {{repoName}}
2 |
3 | {{description}}
4 |
5 | ## Developers
6 | {{author}}
7 |
8 | ## Dependencies list
9 | [http://jam3-license.herokuapp.com/projects/{{repoName}}/licenses](http://jam3-license.herokuapp.com/projects/{{repoName}}/licenses)
10 |
11 | Note: If the link is broken use http://jam3-license.herokuapp.com/projects/[repo name]/licenses ?
12 |
13 | ## PROJECT DOCUMENTATION
14 |
15 | #### [Components](COMPONENTS.md)
16 | #### [Scripts](SCRIPTS.md)
17 | #### [Tests](TESTS.md)
18 |
19 | ## GIT
20 |
21 | ```
22 | git checkout {{repo}}
23 | ```
24 |
25 | ## Setup
26 |
27 | ```bash
28 | $ npm install
29 | ```
30 |
31 | Folder Structure
32 | ```bash
33 | raw-assets/json/ // Any static json files
34 | raw-assets/images/ // Images that should not be texture packed
35 | raw-assets/videos/
36 | raw-assets/sounds/
37 | raw-assets/fonts/
38 | raw-assets/tp/ // Folder for the .tps files
39 | raw-assets/tp/common/ // Folder containing images to be texture packed,
40 | // folder name should share the name of the tps file
41 | ```
42 |
43 | ## Run
44 |
45 | ```bash
46 | $ npm start
47 | ```
48 |
49 | ## Development
50 |
51 | Javascript Style Guide: https://github.com/Jam3/Javascript-Code-Conventions
52 |
53 | CSS Style Guide: https://github.com/Jam3/CSS-Style-Guide
54 |
55 | ### IMAGES
56 |
57 | Name images using dashes:
58 | - large-pixel-image.png
59 | - cute-yellow-pepper.png
60 |
61 | ### GLOBAL VARIABLES
62 |
63 | Always make the root path to assets (image/videos..) a variable, store it in your global settings file, in both Javascript code and CSS
64 |
65 | Because when the site goes live, those assets will come from a CDN and going in and changing all the paths the day before the site goes live is very annoying.
66 |
67 | ```less
68 | @{ASSET_PATH}: 'images/'; // This variable will be changed by a script when pushing to production or other environments
69 | .background {
70 | background: url('@{ASSET_PATH}/images/background.png')
71 | }
72 | ```
73 |
74 | ```scss
75 | $ASSET_PATH: 'images/'; // This variable will be changed by a script when pushing to production or other environments
76 | .background {
77 | background: url('#{$ASSET_PATH}/images/background.png')
78 | }
79 | ```
80 |
81 | ```javascript
82 | var filePath = settings.ASSET_PATH + 'fancy/fancy-graphic.png';
83 | ```
84 | {{#is framework 'react'}}
85 | To debug Redux, use this browser extension: http://zalmoxisus.github.io/redux-devtools-extension/ {{/is}}
86 |
87 | ## DEPLOYMENT
88 |
89 | ```bash
90 | $ npm run release
91 | ```
92 |
93 | ## BROWSER SUPPORT
94 |
95 | [Browserify](https://www.npmjs.com/package/browserify) recently reduced support for older IE browsers (IE10 and below). This is due to the updated `Buffer` module. If you wish to support these browsers and are planning to use the `Buffer` module or use a seperate module that uses it, consider installing this [browser polyfill](https://github.com/inexorabletash/polyfill/blob/master/typedarray.js).
96 |
97 | Optionally you can install version 4 of the `Buffer` module by running this command.
98 |
99 | `npm install buffer@^4 --save-dev`
100 |
101 | You will also have to update the browserify bundle options using the require flag:
102 |
103 | `-r buffer/:buffer`
104 |
105 | This will require editing the `release.js` and `dev.js` scripts.
106 |
107 | For more information, check out: [https://github.com/substack/node-browserify/pull/1678](https://github.com/substack/node-browserify/pull/1678)
108 |
109 | ## RUN TESTS
110 |
111 | Use [Budo](http://npmjs.com/budo/) to develop and test your modules independently before integrating into the framework.
112 |
113 | ```bash
114 | $ cd {{repoName}}
115 | $ budo test/thingtotest/index.js [PORT] [-- browserify args]
116 | ```
117 |
118 | ## NPM MODULES
119 |
120 | When installing modules be sure to use `npm install --save` for dependencies that will be used in the actual application deployed to the server.
121 |
122 | And `npm install --save-dev` for modules that are only used on your system for workflow and development, like automated tasks etc.
123 |
124 | [List of Jam3 Node modules](https://docs.google.com/a/jam3.com/spreadsheets/d/1bPImGwGLjqbOnBxMNmqGVz2mdfVb_R2FKaaoOw1IyP8/edit#gid=0)
125 |
--------------------------------------------------------------------------------
/templates/base/SCRIPTS.md:
--------------------------------------------------------------------------------
1 | [Back](README.md) | [Components](COMPONENTS.md)
2 | # Scripts
3 |
4 | ##### Table of Contents
5 | [config.json](#config)
6 | [Favicons](#favicons)
7 | [Lowercase](#lowercase)
8 | [Facebook Open Graph](#facebook)
9 |
10 |
11 | ## config.json
12 |
13 | The config.json in the root of the project controls how all the scripts function. Here is the default setup for the config.json:
14 |
15 | ```
16 | {
17 | "defaults": {
18 | "entry": "./src/index.js",
19 | "vendor": "vendor.js",
20 | "bundle": "bundle.js",
21 | "static": "./static/",
22 | "raw": "./raw-assets/",
23 | "style": "./src/style/main.scss",
24 | "ASSET_PATH": "./assets/",
25 | "BASENAME": "/",
26 | "JPEG_QUALITY": 80,
27 | "templateBlacklist": [],
28 | "htpasswd": false,
29 | "env": {}
30 | },
31 | "development": {
32 | "output": "./build/"
33 | },
34 | "production": {
35 | "timestamp": true,
36 | "output": "./release/",
37 | "minify": true,
38 | "removeLogs": true
39 | }
40 | }
41 | ```
42 |
43 | All variables are able to be overridden, as you can see via the development and production properties. These properties relate to the NODE_ENV variable. By default `npm start` sets NODE_ENV=development and `npm run release` sets NODE_ENV=production.
44 |
45 | Here is a breakdown of what each properties controls.
46 |
47 | `entry` - The entry point for your app
48 | `vendor` - The name of your vendor.js file, all npm modules will be bundled into this file, setting it to `false` will put everything into the bundle.js
49 | `bundle` - The name of the bundle.js
50 | `static` - The folder containing static html / server files
51 | `raw` - The folder container raw-assets, such as images, asset related json files and 3d assets
52 | `style` - The entry point for your less / scss files
53 | `ASSET_PATH` - Where raw-assets will live in the end, useful to edit this if assets will live on a CDN
54 | `BASENAME` - If your project will live in a subfolder, specify that here, with a trailing slash
55 | `JPEG_QUALITY` - The quality to compress JPEG's in the raw-assets folder to, set to `false` to disable JPEG compression
56 | `templateBlacklist` - Files in the static folder to skip handlebars template compilation, this is only needed if a file breaks handlebars compilation
57 | `htpasswd` - Where the .htpasswd will live on your production environment
58 | `env` - Any custom variables to use via envify, allows you to access them via `process.env.MY_CUSTOM_VAR`
59 | `output` - The folder to place all processed files in
60 | `minify` - Whether to minify the released javascript files, useful for debugging
61 | `removeLogs` - Whether to remove console commands from the final build
62 | `timestamp` - Whether to add a build signature to assets and compiled javascript / css files. `true` will add a timestamp to the path, a string will simply append that string to the path, and false will not add a build signature
63 |
64 | To add a new environment, simply specify it in the config.json and then create a new entry for the script in the package.json. Here is an example adding a staging environment.
65 |
66 | config.json
67 | ```
68 | {
69 | "defaults": {...},
70 | "development": {...},
71 | "production": {...},
72 | "staging": {
73 | "timestamp": false,
74 | "minify": true,
75 | "removeLogs": true
76 | }
77 | }
78 | ```
79 |
80 | package.json
81 | ```
82 | "staging": "npm run preloader-release && npm run release-clean && node scripts/style.js --env=staging && node scripts/release.js --env=staging && npm run release-copy && npm run release-gzip"
83 | ```
84 |
85 |
86 | ## Favicons `npm run favicons`
87 |
88 | #### Default setup
89 | After generating the scaffolding, you will have favicons setup for all the common devices (iOS, Android, Windows Phone and Desktop)
90 |
91 | #### Customize
92 | You can change the default configuration by modifying the file `/scripts/favicons/faviconDescription.json`. All the available option are described in (here)[http://realfavicongenerator.net/api/non_interactive_api](http://realfavicongenerator.net/api/non_interactive_api).
93 | If you want to change the image, you can replace the image located in `/scripts/favicons/favicon_template.png` for your new favicon image. The recommended size for this master image is `500x500`.
94 | After changing all the things you want, just run `npm run update-favicons` and you will get your new favicons ready.
95 |
96 |
97 | ## Lowercase `npm run lowercase`
98 |
99 | The lowercase script is a simple utility that will lowercase and replace spaces with dashes for all files within the raw-assets folder. This is useful if you have been handed assets from external sources with inconsistent naming conventions.
100 |
101 |
102 | ## Facebook Open Graph `npm run facebook`
103 |
104 | `npm run facebook -- --url=[YOUR URL]`
105 |
106 | The Facebook script will clear the Facebook sharing cache for all URL's in your share.json, as well as the base URL you specify in the script. Simply provide your base URL to the script and it will begin clearing the cache for that domain. Here is an example:
107 |
108 | share.json
109 | ```
110 | {
111 | "default": {...},
112 | "gallery: {...},
113 | "gallery/grid": {...}
114 | }
115 | ```
116 |
117 | `npm run facebook -- --url=http://my-page-url.com/`
118 |
119 | Running this command with this share.json will clear the following URLs from the facebook cache:
120 |
121 | ```
122 | http://my-page-url.com/
123 | http://my-page-url.com/gallery
124 | http://my-page-url.com/gallery/grid
125 | ```
--------------------------------------------------------------------------------
/templates/base/STANDARDS.md:
--------------------------------------------------------------------------------
1 | # Standards
2 |
3 | ##### Table of Contents
4 | [ESLint](#eslint)
5 |
6 |
7 | ## ESlint (.eslintrc)
8 |
9 | #### Required plugins (global or local)
10 | * eslint-plugin-react
11 | * eslint-plugin-standard
12 | * eslint-plugin-promise
13 | * babel-eslint
14 |
--------------------------------------------------------------------------------
/templates/base/TESTS.md:
--------------------------------------------------------------------------------
1 | [Back](README.md)
2 | # Tests
3 |
4 | Tests are set up for dev environment and you can access the list of test components in your browser at `http://localhost:9966/test`.
5 | Each component will be available on it's own page like `http://localhost:9966/test/{componentName}`.
6 |
7 | To add a new item to the list, add a component to the `src/tests/manifest.js` and a create a wrapper component if necessary.
8 | Refer to existing test examples `src/tests/`;
--------------------------------------------------------------------------------
/templates/base/config-preloader.json:
--------------------------------------------------------------------------------
1 | [
2 | "json/**/*"
3 | ]
--------------------------------------------------------------------------------
/templates/base/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaults": {
3 | "entry": "./src/index.js",
4 | "vendor": {{#if vendor}}"vendor.js"{{else}}false{{/if}},
5 | "bundle": "bundle.js",
6 | "static": "./static/",
7 | "raw": "./raw-assets/",
8 | "style": "./src/style/main.{{css}}",
9 | "ASSET_PATH": "./assets/",
10 | "BASENAME": "/",
11 | "JPEG_QUALITY": 90,
12 | "templateBlacklist": [{{#if unsupported}}{{#is backend 'php'}}".phar"{{/is}}{{/if}}],
13 | "liveReloadClient": true,
14 | "htpasswd": {{#if password}}"{{passLocation}}"{{else}}false{{/if}},
15 | "env": {}
16 | },
17 | "development": {
18 | "vendor": false,
19 | "output": "./build/"
20 | },
21 | "production": {
22 | "timestamp": false,
23 | "output": "./release/",
24 | "minify": true,
25 | "removeLogs": true
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/templates/base/gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.log
3 |
4 | node_modules
5 |
6 | build
7 | release
8 |
--------------------------------------------------------------------------------
/templates/base/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{repoName}}",
3 | "version": "0.0.0",
4 | "description": "{{description}}",
5 | "author": {
6 | "name": "{{author}}",
7 | "email": "{{email}}",
8 | "url": "https://github.com/Jam3"
9 | },
10 | "scripts": {
11 | "start": "npm-run-all preloader copy style {{#if unsupported}}{{#is backend "none"}}unsupported {{/is}}{{/if}}dev",
12 | "build": "node scripts/timestamp.js && npm-run-all preloader clean style browserify {{#if unsupported}}{{#is backend "none"}}unsupported {{/is}}{{/if}}copy gzip && node scripts/timestamp.js --delete",
13 | "release": "cross-env NODE_ENV=production npm run build",
14 | "copy": "node scripts/copy.js",
15 | "style": "node scripts/style.js",
16 | "preloader": "node scripts/preloader.js",
17 | "dev": "node scripts/dev.js",
18 | "browserify": "node scripts/release.js",{{#if unsupported}}{{#is backend "none"}}
19 | "unsupported": "node scripts/release.js --unsupported",{{/is}}{{/if}}
20 | "gzip": "node scripts/gzip.js",
21 | "clean": "node scripts/clean.js",
22 | "lowercase": "node scripts/lowercase.js",
23 | "favicons": "node scripts/favicons/favicons.js",
24 | "facebook": "node scripts/facebook.js"
25 | },
26 | "license": "ISC",
27 | "repository": "{{repo}}",
28 | "dependencies": {
29 | "gsap": "^1.19.1",
30 | "howler": "^2.0.4"{{#is framework 'bigwheel'}},
31 | "bigwheel": "^3.0.0",
32 | "domready": "^1.0.8",
33 | "bw-analytics": "^1.1.1",
34 | "handlebars": "^2.0.0",
35 | "domify": "^1.4.0"{{/is}}{{#is framework 'react'}},
36 | "babel-polyfill": "^6.23.0",
37 | "bowser": "^1.7.0",
38 | "domready": "^1.0.8",
39 | "fullscreen-handler": "^0.0.2",
40 | "mobile-detect": "^1.3.6",
41 | "preloader": "^4.0.1",
42 | "prop-types": "^15.5.10",
43 | "react": "^16.1.1",
44 | "react-dom": "^16.1.1",
45 | "react-redux": "^5.0.6",
46 | "react-router": "^4.2.0",
47 | "react-router-dom": "^4.2.2",
48 | "react-router-redux": "^5.0.0-alpha.8",
49 | "react-background-video-player": "^0.3.0",
50 | "react-svg-inline": "^2.0.0",
51 | "react-transition-group-plus": "^0.5.2",
52 | "redux": "^3.4.0",
53 | "stats.js": "0.17.0"{{/is}}
54 | },
55 | "devDependencies": {
56 | "budo": "^10.0.3",
57 | "rimraf": "^2.5.2",
58 | "envify": "^3.4.0",
59 | "concat-stream": "^1.5.1",
60 | "graceful-fs": "^4.1.3",
61 | "handlebars": "^4.0.5",
62 | "glob": "^6.0.1",
63 | "junk": "^2.0.0",
64 | "merge": "^1.2.0",
65 | "isbinaryfile": "^3.0.0",
66 | "npm-run-all": "^4.0.0",
67 | "cross-env": "^5.0.0",{{#is css 'less'}}
68 | "less": "^2.5.3",
69 | "less-plugin-autoprefix": "^1.5.1",
70 | "less-plugin-glob": "^1.1.1",{{/is}}{{#is css 'scss'}}
71 | "autoprefixer": "^6.2.3",
72 | "node-sass": "^3.4.2",
73 | "postcss": "^5.0.14",
74 | "node-sass-glob": "^1.0.4",{{/is}}
75 | "minimist": "^1.2.0",
76 | "mkdirp": "^0.5.1",
77 | "rfg-api": "^0.2.0",
78 | "mozjpeg": "^4.1.1",
79 | "pngquant-bin": "^3.0.0",
80 | "uglify-js": "^2.6.1",
81 | "brfs": "^1.2.0",{{#is framework 'bigwheel'}}
82 | "browserify-shim": "^3.8.0",{{/is}}
83 | "browserify": "^14.1.0"{{#if useES6}},
84 | "babelify": "^7.2.0",
85 | "babel-runtime": "^5.8.34",
86 | "babel-preset-es2015": "^6.3.13"{{#is framework 'react'}},
87 | "babel-plugin-transform-decorators-legacy": "^1.3.4",
88 | "babel-plugin-transform-object-assign": "^6.22.0",
89 | "babel-preset-react": "^6.5.0",
90 | "babel-preset-react-optimize": "^1.0.1",
91 | "babel-preset-stage-1": "^6.5.0",
92 | "stringify": "3.2.0"{{/is}}{{/if}}
93 | },
94 | "browserify": {
95 | "transform": [{{#is framework 'bigwheel'}}
96 | "browserify-shim",
97 | "brfs",{{/is}}{{#if useES6}}
98 | "babelify",{{/if}}
99 | "envify"{{#is framework 'react'}},
100 | ["stringify", {"extensions": [".svg"], "minify": true}]{{/is}}
101 | ]
102 | }{{#is framework 'bigwheel'}},
103 | "browserify-shim": {
104 |
105 | },
106 | "browser": {}{{/is}}
107 | }
108 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/fonts/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Experience-Monks/generator-jam3/c8c0f674245b4a2475de235e3cf2ddaa65b4c2f8/templates/base/raw-assets/fonts/.gitkeep
--------------------------------------------------------------------------------
/templates/base/raw-assets/json/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Experience-Monks/generator-jam3/c8c0f674245b4a2475de235e3cf2ddaa65b4c2f8/templates/base/raw-assets/json/.gitkeep
--------------------------------------------------------------------------------
/templates/base/raw-assets/json/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "glossary": {
3 | "title": "example glossary",
4 | "GlossDiv": {
5 | "title": "S",
6 | "GlossList": {
7 | "GlossEntry": {
8 | "ID": "SGML",
9 | "SortAs": "SGML",
10 | "GlossTerm": "Standard Generalized Markup Language",
11 | "Acronym": "SGML",
12 | "Abbrev": "ISO 8879:1986",
13 | "GlossDef": {
14 | "para": "A meta-markup language, used to create markup languages such as DocBook.",
15 | "GlossSeeAlso": [
16 | "GML",
17 | "XML"
18 | ]
19 | },
20 | "GlossSee": "markup"
21 | }
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/templates/base/raw-assets/sounds/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Experience-Monks/generator-jam3/c8c0f674245b4a2475de235e3cf2ddaa65b4c2f8/templates/base/raw-assets/sounds/.gitkeep
--------------------------------------------------------------------------------
/templates/base/raw-assets/sounds/button-click.mp3:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:faf7241be50cec4c30b657b004b15829c5cbbe48db6f8fe881132e81efec7ae3
3 | size 1024
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/sounds/button-rollover.mp3:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:450cedff59402d82873eb2e80a24a0db7392fb5a1f0ebd4c96c6c30d34742f60
3 | size 1024
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/sounds/button-sprite.mp3:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e0544ca263dafe313ba6058a3c2116d78b46d9b39c411c815499724a5ef477bf
3 | size 1024
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/captions-off.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/captions-on.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/close.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/enter-fullscreen.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/exit-fullscreen.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/loader.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/muted.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/pause.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/play.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/rotate.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/svg/unmuted.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/templates/base/raw-assets/videos/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Experience-Monks/generator-jam3/c8c0f674245b4a2475de235e3cf2ddaa65b4c2f8/templates/base/raw-assets/videos/.gitkeep
--------------------------------------------------------------------------------
/templates/base/raw-assets/videos/captions-test.vtt:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f6182866c9eeb4f353eb6155588d98ab0fced3a6892a628fd3db267a18a052cc
3 | size 1024
4 |
--------------------------------------------------------------------------------
/templates/base/src/data/sounds.js:
--------------------------------------------------------------------------------
1 | const path = process.env.ASSET_PATH + 'sounds/';
2 |
3 | export default {
4 | 'button-rollover': `${path}button-rollover.mp3`,
5 | 'button-click': `${path}button-click.mp3`,
6 | };
7 |
--------------------------------------------------------------------------------
/templates/base/src/util/audio.js:
--------------------------------------------------------------------------------
1 | import Howl from 'howler';
2 | import soundModel from '../data/sounds';
3 |
4 | let soundMap = {};
5 |
6 | function isObject(val) {
7 | return (typeof val === 'object') && !Array.isArray(val) && val !== null;
8 | }
9 |
10 | function parseData(val) {
11 | if (typeof val === 'string' || val instanceof String) {
12 | return [val];
13 | } else if (Array.isArray(val)) {
14 | return val;
15 | } else if (isObject(val)) {
16 | if (val.src) {
17 | return parseData(val.src);
18 | } else {
19 | console.error('"soundModel" item missing field "src"', val);
20 | return [''];
21 | }
22 | } else {
23 | console.error('Unrecognized type for "soundModel" item', val);
24 | return [''];
25 | }
26 | }
27 |
28 | function getSprite(val) {
29 | let sprite;
30 | Object.keys(soundMap).forEach(key => {
31 | if (soundMap[key]._sprite[val]) {
32 | sprite = soundMap[key];
33 | }
34 | });
35 | return sprite;
36 | }
37 |
38 | function setMap(model) {
39 | Object.keys(model).forEach(item => {
40 | let data = model[item];
41 | const defaults = {
42 | preload: false,
43 | };
44 | const opts = Object.assign(defaults, isObject(data) ? data : {}, {src: parseData(data)});
45 | soundMap[item] = new Howl.Howl(opts);
46 | });
47 | }
48 |
49 | class AudioStore {
50 | constructor() {
51 | setMap(soundModel);
52 | }
53 |
54 | play = (id) => {
55 | if (Object.keys(soundMap).length === 0) {
56 | console.error('Can\'t play any sounds as "soundMap" is empty', soundMap);
57 | return;
58 | }
59 |
60 | let curr = soundMap[id];
61 | let isSprite;
62 |
63 | if (!curr) {
64 | curr = getSprite(id);
65 | isSprite = true;
66 | }
67 |
68 | if (curr) {
69 | (curr.state() === 'unloaded') && curr.load();
70 | isSprite ? curr.play(id) : curr.play();
71 | } else {
72 | console.error(`"${id}" doesn't exist in sound map.`, soundMap);
73 | }
74 | };
75 |
76 | set extraData(data) {
77 | setMap(data);
78 | }
79 |
80 | get sounds() {
81 | return soundMap;
82 | }
83 | }
84 |
85 | const instance = new AudioStore();
86 | Object.freeze(instance);
87 |
88 | export default instance;
89 |
--------------------------------------------------------------------------------
/templates/base/src/util/detect.js:
--------------------------------------------------------------------------------
1 | import browser from 'bowser';
2 | import MobileDetect from 'mobile-detect';
3 |
4 | const ua = navigator.userAgent.toLowerCase();
5 | const md = new MobileDetect(ua);
6 | const bots = ['facebookexternalhit', 'linkedinbot', 'google (+https://developers.google.com/+/web/snippet/)', 'facebot', 'https://developers.google.com/+/web/snippet/', 'twitterbot', 'tumblr', 'googlebot'];
7 |
8 | function checkBot() {
9 | let isBot = false;
10 | bots.map(function(cur) {
11 | if (ua.toLowerCase().indexOf(cur) > -1) isBot = true;
12 | });
13 | return isBot;
14 | }
15 |
16 | function checkFacebook() {
17 | return (ua.indexOf('fban') > -1) || (ua.indexOf('fbav') > -1);
18 | }
19 |
20 | function checkTwitter() {
21 | return (ua.indexOf('twitter') > -1);
22 | }
23 |
24 | function checkInstagram() {
25 | return (ua.indexOf('instagram') > -1);
26 | }
27 |
28 | function checkPinterest() {
29 | return (ua.indexOf('pinterest') > -1);
30 | }
31 |
32 | function checkInAppBrowser() {
33 | return checkFacebook() || checkTwitter() || checkInstagram() || checkPinterest();
34 | }
35 |
36 | function checkInAppBrowserVersion() {
37 | // take iOS version for Apple
38 | if (browser.ios) {
39 | const OSApp = ua.match(/OS \s*(\d+)/i);
40 | return OSApp[1];
41 | }
42 |
43 | // take Chrome version for Android
44 | const FBApp = ua.match(/(chrome)\/?\s*(\d+)/i);
45 | if (FBApp && FBApp[1] === 'chrome') {
46 | return FBApp[2];
47 | }
48 |
49 | return 9999;
50 | }
51 |
52 | function checkOS() {
53 | if (browser.mac) return 'mac';
54 | if (browser.windows) return 'windows';
55 | if (browser.windowsphone) return 'windowsphone';
56 | if (browser.linux) return 'linux';
57 | if (browser.chromeos) return 'chromeos';
58 | if (browser.android) return 'android';
59 | if (browser.ios) return 'ios';
60 | if (browser.blackberry) return 'blackberry';
61 | if (browser.firefoxos) return 'firefoxos';
62 | }
63 |
64 | const checkDevice = function() {
65 | let device;
66 | if (browser.mobile) {
67 | device = 'phone';
68 | } else if (browser.tablet) {
69 | device = 'tablet';
70 | } else {
71 | device = 'desktop';
72 | }
73 | return device;
74 | };
75 |
76 | const checkVendor = function() {
77 | return (navigator.vendor) ? navigator.vendor.toLowerCase() : '';
78 | };
79 |
80 | const checkDevicePixelRatio = function() {
81 | return window.devicePixelRatio;
82 | };
83 |
84 | const checkManufacturer = function() {
85 | let man = 'unknown';
86 | if (md.phone()) {
87 | man = md.phone();
88 | } else if (md.tablet()) {
89 | man = md.tablet();
90 | }
91 | return man.toLowerCase();
92 | };
93 |
94 | const getClasses = function() {
95 | const classes = [
96 | browser.mobile || browser.tablet ? 'mobile' : '',
97 | checkDevice(),
98 | 'x' + checkDevicePixelRatio(),
99 | browser.name.toLocaleLowerCase(),
100 | 'v' + browser.version,
101 | ];
102 | if (md.mobile()) classes.push(checkManufacturer());
103 | return classes.filter(cur => Boolean(cur));
104 | };
105 |
106 | module.exports = {
107 | isBot: checkBot(),
108 | isFacebook: checkFacebook(),
109 | isTwitter: checkTwitter(),
110 | isInstagram: checkInstagram(),
111 | isPinterest: checkPinterest(),
112 | isInAppBrowser: checkInAppBrowser(),
113 | inAppBrowserVersion: checkInAppBrowserVersion(),
114 | device: checkDevice(),
115 | vendor: checkVendor(),
116 | os: checkOS(),
117 | osVersion: browser.osversion,
118 | browser: browser.name.toLocaleLowerCase(),
119 | browserVersion: browser.version,
120 | devicePixelRatio: checkDevicePixelRatio(),
121 | classes: getClasses(),
122 | isMobile: browser.mobile || browser.tablet,
123 | isPhone: browser.mobile,
124 | isTablet: browser.tablet,
125 | isDesktop: !browser.mobile && !browser.tablet,
126 | isChrome: browser.chrome,
127 | isIE: browser.msie,
128 | isEdge: browser.msedge,
129 | isFirefox: browser.firefox,
130 | isSafari: browser.safari,
131 | isOpera: browser.opera,
132 | md: md,
133 | bowser: browser,
134 | get orientation() {
135 | if (window.screen) {
136 | const orientation = window.screen.orientation || window.screen.mozOrientation || window.screen.msOrientation;
137 | if (orientation && orientation.type) {
138 | return orientation.type.split('-', 1)[0];
139 | }
140 | }
141 | const w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
142 | const h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
143 | if (w < h) {
144 | return 'portrait';
145 | } else {
146 | return 'landscape';
147 | }
148 | }
149 | };
150 |
--------------------------------------------------------------------------------
/templates/base/src/util/seconds-to-minutes.js:
--------------------------------------------------------------------------------
1 | export default function(totalSeconds) {
2 | const totalSecondsFloat = parseFloat(totalSeconds);
3 | let minutes = Math.floor(totalSecondsFloat / 60);
4 | let seconds = Math.round(totalSecondsFloat - (minutes * 60));
5 |
6 | if (minutes < 10) {
7 | minutes = `0${minutes}`;
8 | }
9 |
10 | if (seconds < 10) {
11 | seconds = `0${seconds}`;
12 | }
13 |
14 | return `${minutes}:${seconds}`;
15 | }
16 |
--------------------------------------------------------------------------------
/templates/base/src/util/stats.js:
--------------------------------------------------------------------------------
1 | var Stats = require('stats.js');
2 | module.exports = function() {
3 | var stats = new Stats();
4 | stats.domElement.style.cssText = 'position:fixed;right:0;bottom:100px;z-index:10000';
5 | document.body.appendChild(stats.domElement);
6 | var loop = function() {
7 | stats.update();
8 | requestAnimationFrame(loop);
9 | };
10 | requestAnimationFrame(loop);
11 | };
--------------------------------------------------------------------------------
/templates/base/static/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | RewriteEngine On
3 |
4 | # Force HTTPS
5 | # RewriteCond %{HTTP:X-Forwarded-Proto} =http [OR]
6 | # RewriteCond %{HTTP:X-Forwarded-Proto} =""
7 | # RewriteCond %{HTTPS} !=on
8 | # RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
9 |
10 | #Serve gzip compressed CSS files if they exist and the client accepts gzip.
11 | RewriteCond %{HTTP:Accept-encoding} gzip
12 | RewriteCond %{REQUEST_FILENAME}\.gz -s
13 | RewriteRule ^(.*)\.css $1\.css\.gz [QSA]
14 |
15 | # Serve gzip compressed JS files if they exist and the client accepts gzip.
16 | RewriteCond %{HTTP:Accept-encoding} gzip
17 | RewriteCond %{REQUEST_FILENAME}\.gz -s
18 | RewriteRule ^(.*)\.js $1\.js\.gz [QSA]
19 |
20 |
21 | # Serve correct content types, and prevent mod_deflate double gzip.
22 | RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=is_gzip:1]
23 | RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=is_gzip:1]
24 | Header set Content-Encoding "gzip" env=is_gzip
25 |
26 |
27 | # Push state support
28 | RewriteCond %{REQUEST_FILENAME} !-f
29 | RewriteCond %{REQUEST_FILENAME} !-d
30 | RewriteCond %{REQUEST_URI} !index
31 | RewriteRule (.*) index.{{#is backend 'php'}}php?u=$1{{else}}html{{/is}} [L,QSA]
32 |
33 |
34 | Header append X-FRAME-OPTIONS "SAMEORIGIN"
35 |
36 | DirectoryIndex index.php index.html
37 |
--------------------------------------------------------------------------------
/templates/base/static/humans.txt:
--------------------------------------------------------------------------------
1 | # humanstxt.org/
2 | # The humans responsible & technology colophon
3 |
4 | # TEAM
5 |
6 | {{author}} - {{email}}
7 |
8 | # THANKS
9 |
10 |
11 |
12 | # TECHNOLOGY COLOPHON
13 |
14 | HTML5, CSS3
15 |
--------------------------------------------------------------------------------
/templates/base/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#is backend "none"}}{{#if unsupported}}
4 | {{/if}}{{/is}}
7 | {{repoName}}
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | {{#is backend "none"}}{{#if unsupported}}
35 |
36 | {{/if}}{{/is}}
37 |
38 |
39 | \{{#if vendor}}
40 | \{{/if}}
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/templates/base/static/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /cgi-bin/
3 | Disallow: /tmp/
--------------------------------------------------------------------------------
/templates/bigwheel/src/framework/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var bigwheel = require('bigwheel');
3 | var analytics = require('bw-analytics');
4 | var model = require('../model');
5 | module.exports = analytics(model.settings.UA, bigwheel(function(done) {
6 | done({
7 | initSection: require('../sections/Preloader/{{#if sectionNames}}Preloader{{else}}index{{/if}}.js'),
8 | routes: require('./routes')
9 | });
10 | }));
11 |
--------------------------------------------------------------------------------
/templates/bigwheel/src/framework/routes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | 'pushState': true,
4 | '/': require('../sections/Landing/{{#if sectionNames}}Landing{{else}}index{{/if}}.js'),
5 | '404': '/'
6 | };
7 |
--------------------------------------------------------------------------------
/templates/bigwheel/src/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var domready = require('domready');
3 | var framework = require('./framework');
4 |
5 | domready(function() {
6 | framework.init();
7 | });
8 |
--------------------------------------------------------------------------------
/templates/bigwheel/src/model/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | module.exports = {
3 | settings: {
4 | UA: '',
5 | ASSET_PATH: process.env.ASSET_PATH,
6 | NODE_ENV: process.env.NODE_ENV
7 | },
8 | '/': {}
9 | };
10 |
--------------------------------------------------------------------------------
/templates/react/src/components/HamburgerButton/index.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import PropTypes from 'prop-types';
3 | import animate from 'gsap';
4 |
5 | const STATES = {
6 | idle: 'idle',
7 | close: 'close',
8 | back: 'back',
9 | };
10 |
11 | export default class HamburgerButton extends PureComponent {
12 | constructor(props) {
13 | super(props);
14 | this.state = {
15 | buttonState: props.state,
16 | isMouseOver: props.isMouseOver,
17 | };
18 | }
19 |
20 | componentDidMount() {
21 | this.bars = [...this.container.querySelectorAll('.bar')];
22 | }
23 |
24 | componentWillReceiveProps(nextProps) {
25 | if (nextProps.buttonState !== this.props.buttonState) {
26 | this.setState({buttonState: nextProps.buttonState});
27 | }
28 |
29 | if (nextProps.isMouseOver !== this.props.isMouseOver) {
30 | this.setState({isMouseOver: nextProps.isMouseOver});
31 | }
32 | }
33 |
34 | componentDidUpdate(prevProps, prevState) {
35 | if (prevState.buttonState !== this.state.buttonState) {
36 | if (this.state.buttonState === STATES.close) {
37 | this.goToCloseState();
38 | } else if (this.state.buttonState === STATES.back) {
39 | this.goToBackState();
40 | } else {
41 | this.goToIdleState();
42 | }
43 | }
44 | }
45 |
46 | checkIsIdleState = () => {
47 | return (this.state.buttonState !== STATES.close && this.state.buttonState !== STATES.back);
48 | };
49 |
50 | goToCloseState = () => {
51 | const duration = 0.2;
52 | animate.killTweensOf(this.bars);
53 | animate.to(this.bars[0], duration, {rotation: 45, x: 1, y: 0});
54 | animate.to(this.bars[1], duration, {scaleX: 0, autoAlpha: 0});
55 | animate.to(this.bars[2], duration, {rotation: -45, y: 0});
56 | };
57 |
58 | goToBackState = () => {
59 | const duration = 0.2;
60 | animate.killTweensOf(this.bars);
61 | animate.to(this.bars[0], duration, {x: -1, y: 10, rotation: -45, scaleX: 0.8});
62 | animate.to(this.bars[1], duration, {scaleX: 0, autoAlpha: 0});
63 | animate.to(this.bars[2], duration, {x: 1, y: -9, rotation: 45, scaleX: 0.8});
64 | };
65 |
66 | goToIdleState = () => {
67 | animate.killTweensOf(this.bars);
68 | animate.to(this.bars, 0.2, {x: 0, y: 0, rotation: 0, scaleX: 1, autoAlpha: 1});
69 | };
70 |
71 | handleClick = (e) => {
72 | const buttonState = this.state.buttonState === STATES.idle ? this.props.activeState : STATES.idle;
73 | this.setState({buttonState});
74 | this.props.onClick(buttonState);
75 | };
76 |
77 | handleMouseEnter = (e) => {
78 | if (this.checkIsIdleState()) {
79 | animate.killTweensOf(this.bars);
80 | animate.to([this.bars[1], this.bars[3]], 0.2, {scaleX: 0.8});
81 | }
82 | this.setState({isMouseOver: true});
83 | this.props.onMouseEnter();
84 | };
85 |
86 | handleMouseLeave = (e) => {
87 | this.checkIsIdleState() && this.goToIdleState();
88 | this.setState({isMouseOver: false});
89 | this.props.onMouseLeave();
90 | };
91 |
92 | render() {
93 | const props = this.props;
94 | const state = this.state;
95 |
96 | const style = Object.assign({}, this.props.style);
97 | const buttonClass = `HamburgerButton ${props.className}`;
98 |
99 | return (
100 |
115 | );
116 | }
117 | }
118 |
119 | HamburgerButton.propTypes = {
120 | className: PropTypes.string,
121 | style: PropTypes.object,
122 | tabIndex: PropTypes.number,
123 | state: PropTypes.string,
124 | activeState: PropTypes.string,
125 | isMouseOver: PropTypes.bool,
126 | onClick: PropTypes.func,
127 | onMouseEnter: PropTypes.func,
128 | onMouseLeave: PropTypes.func,
129 | };
130 |
131 | HamburgerButton.defaultProps = {
132 | className: '',
133 | style: {},
134 | tabIndex: 0,
135 | state: STATES.idle,
136 | activeState: STATES.close,
137 | isMouseOver: false,
138 | onClick: () => f => f,
139 | onMouseEnter: f => f,
140 | onMouseLeave: f => f,
141 | };
142 |
--------------------------------------------------------------------------------
/templates/react/src/components/HamburgerButton/style.{{css}}:
--------------------------------------------------------------------------------
1 | .HamburgerButton {
2 | cursor: pointer;
3 |
4 | .bars-container {
5 | display: flex;
6 | flex-direction: column;
7 | justify-content: space-between;
8 | position: relative;
9 | width: 25px;
10 | height: 20px;
11 |
12 | > .bar {
13 | width: 100%;
14 | height: 2px;
15 | background: #000;
16 | transform-origin: top left;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/templates/react/src/components/MobileFullscreenVideo/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import fullScreen from 'fullscreen-handler';
4 |
5 | import detect from '../../util/detect';
6 |
7 | const isIOS = detect.isIOS;
8 |
9 | class MobileFullscreenVideo extends React.PureComponent {
10 | constructor(props) {
11 | super(props);
12 | }
13 |
14 | componentDidMount() {
15 | this.fullScreen = fullScreen(this.video,
16 | this.handleFsEnter,
17 | this.handleFsExit,
18 | );
19 | }
20 |
21 | componentWillUnmount() {
22 | this.fullScreen.destroy();
23 | }
24 |
25 | play = () => {
26 | process.nextTick(() => {
27 | isIOS && this.props.onOpen();
28 | this.fullScreen.enter();
29 | this.video.play();
30 | });
31 | };
32 |
33 | pause = () => {
34 | this.video.pause();
35 | };
36 |
37 | getVideoElement = () => {
38 | return this.video;
39 | };
40 |
41 | handleFsEnter = () => {
42 | !isIOS && this.props.onOpen();
43 | };
44 |
45 | handleFsExit = () => {
46 | this.pause();
47 | this.props.onClose();
48 | };
49 |
50 | handleEnded = () => {
51 | this.fullScreen.exit();
52 | };
53 |
54 | render() {
55 | const style = Object.assign({}, {
56 | position: 'fixed',
57 | width: 0,
58 | height: 0,
59 | top: window.innerHeight / 2,
60 | left: window.innerWidth / 2,
61 | }, this.props.style);
62 |
63 | return (
64 |