diff --git a/README.md b/README.md index 01a04e3..f27ea7a 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ -A [Yeoman](http://yeoman.io) generator to scaffold a development environment for building Politico interactives. +A [Yeoman](http://yeoman.io) generator to scaffold a development environment for building POLITICO interactives. ### What it does: -- Scaffolds your project's development directory, either for an embeddable feature or a complete interactive page. +- Scaffolds your project's development directory. - Compiles SCSS and bundles JS written in either ES5 or ES2015 using your choice of browserify or webpack. - Creates responsive image sets optimized for mobile devices. - Publishes your project to an Amazon S3 bucket. @@ -102,6 +102,34 @@ There is also an extra filter specifically for rendering [Markdown](https://gith

{{sectionTitle|markdown(strip=true)}}

``` +#### UnCSS + +When building for production, this app uses [UnCSS](https://github.com/giakki/uncss) to remove unused styles. If you have rules that apply to classes set with JavaScript, you must explicitly tell UnCSS not to remove them with a special comment. By default, we also tell UnCSS to ignore any rules set inside a graphics section or with a class of `dataviz`. + +```CSS +/* These rules will all be preserved by UnCSS */ + +/* uncss:ignore */ +.myClass { + /* ... */ +} + +section.graphic{ + /*...*/ + .myClass { + /*...*/ + } +} + +.dataviz { + /*...*/ + .myClass { + /*...*/ + } +} + +``` + #### ArchieML Optionally, there is a gulp task available which allows you to use [ArchieML](http://archieml.org/#demo) and Google Docs to render content into your templates. @@ -162,16 +190,15 @@ To change styles, simply update the scss files in the following directory within If you need to add a new SCSS file, ask a developer to help you write the line that loads your new file into a user's development directory. -If you need to make changes to HTML templates, they are split between these folder, depending on what kind of project you're updating: +If you need to make changes to HTML templates, they are here: -- `generators/templates-embeddable/src/templates` -- `generators/templates-interactive/src/templates` +- `generators/templates/src/templates` Again, if you need to add a new HTML file, rather than simply change an old one, talk to a developer. #### Publishing -Once you're satisfied with your changes, publish your updates through the following steps: +Once you're satisfied with your changes and have tested your update, publish your updates through the following steps: 1. Increment the version number in `package.json`, e.g., `0.0.3` --> `0.0.4` 2. Commit your changes to github 3. Run: diff --git a/generators/app/index.js b/generators/app/index.js index f36f1fc..d24fe72 100644 --- a/generators/app/index.js +++ b/generators/app/index.js @@ -1,165 +1,30 @@ const Generator = require('yeoman-generator'); -const S = require('string'); module.exports = class extends Generator { - constructor(args, opts) { - super(args, opts); - // Bundler options - this.BROWSERIFY = 'browserify'; - this.WEBPACK = 'webpack'; - // Project type options - this.EMBED = 'embed'; - this.PAGE = 'page'; - } - initializing() { this.composeWith(require.resolve('../linters')); this.composeWith(require.resolve('../gulp')); this.composeWith(require.resolve('../styles')); + this.composeWith(require.resolve('../aws')); } prompting() { const questions = [{ - type: 'list', - name: 'projectType', - message: 'Yo Politico! What do you want to make today?', - choices: [ - { - name: 'embeddable', - value: this.EMBED, - }, - { - name: 'interactive page', - value: this.PAGE, - }, - ], - }, { type: 'input', - name: 'projectTitle', - message: 'OK, what do we call it?', - }, { - type: 'list', - name: 'projectBundler', - message: 'Which module bundler would you like to use?', - default: this.BROWSERIFY, - choices: [ - { - name: 'Browserify (default)', - value: this.BROWSERIFY, - }, - { - name: 'Webpack (ES2015 + SCSS)', - value: this.WEBPACK, - }, - ], - }, { - type: 'confirm', - name: 'archieML', - message: 'Would like to include an ArchieML configuration?', - default: false, - }, { - name: 'awsAccessKey', - message: 'What\'s your AWS access key?', - store: true, - }, { - name: 'awsSecretKey', - message: 'What\'s your AWS secret key?', - store: true, + name: 'title', + message: 'Welcome to your new interactive. What will we call it?', }]; return this.prompt(questions).then((answers) => { - this.projectType = answers.projectType; - this.projectTitle = answers.projectTitle; - this.projectSlug = S(answers.projectTitle).slugify().s; - this.projectBundler = answers.projectBundler; - this.archieML = answers.archieML; - this.awsAccessKey = answers.awsAccessKey; - this.awsSecretKey = answers.awsSecretKey; + this.title = answers.title; }); } template() { - switch (this.projectType) { - case 'embed': - this.composeWith(require.resolve('../templates-embeddable'), { - title: this.projectTitle, - webpack: this.projectBundler === this.WEBPACK, - archie: this.archieML, - }); - break; - default: - this.composeWith(require.resolve('../templates-page'), { - title: this.projectTitle, - webpack: this.projectBundler === this.WEBPACK, - archie: this.archieML, - }); - } - } - writing() { - this.fs.copy( - this.templatePath('aws.json.example'), - this.destinationPath('aws.json.example')); - - this.fs.copy( - this.templatePath('gitignore'), - this.destinationPath('./.gitignore')); - - this.fs.copyTpl( - this.templatePath('package.json'), - this.destinationPath('package.json'), { - slug: this.projectSlug, - userName: this.user.git.name(), - userEmail: this.user.git.email(), - }); - - const awsJSON = { - accessKeyId: this.awsAccessKey, - secretAccessKey: this.awsSecretKey, - params: { - Bucket: 'com.politico.interactives.politico.com', - CloudFront: 'E3V6OHE700RHMR', - }, - }; - - const timestamp = new Date(); - const publishPath = this.projectType === 'embed' ? - `${timestamp.getFullYear()}/embed/${this.projectSlug}/` : - `${timestamp.getFullYear()}/${this.projectSlug}/`; - - const metaJSON = { - id: (Math.floor(Math.random() * 100000000000) + 1).toString(), - publishPath, - url: `http://www.politico.com/interactives/${publishPath}`, - share: { - fbook: { - card_title: this.projectTitle, - card_description: '', - author: 'politico', - }, - twitter: { - card_title: this.projectTitle, - card_description: '', - author: '@politico', - }, - image: { - url: `http://www.politico.com/interactives/${publishPath}images/share.jpg`, - alt: '', - type: 'image/jpeg', - width: '600', - height: '315', - }, - keywords: 'Politico, News, Washington D.C.', - }, - telium: { - free_paid_content: 'free', - site_section: 'white house', - ad_unit_section: 'whitehouse', - content_author: 'Polly Politico|Peter Politico', - content_byline: 'By Polly Politico and Peter Politico', - page_name: `${this.projectTitle} — POLITICO`, - }, - }; - - this.fs.writeJSON('aws.json', awsJSON); - this.fs.writeJSON('meta.json', metaJSON); + this.composeWith(require.resolve('../meta'), { + title: this.title, + }); + this.composeWith(require.resolve('../templates'), { + title: this.title, + }); } }; diff --git a/generators/aws/index.js b/generators/aws/index.js new file mode 100644 index 0000000..a3d935b --- /dev/null +++ b/generators/aws/index.js @@ -0,0 +1,37 @@ +const Generator = require('yeoman-generator'); + +module.exports = class extends Generator { + prompting() { + const questions = [{ + name: 'awsAccessKey', + message: 'What\'s your AWS access key?', + store: true, + }, { + name: 'awsSecretKey', + message: 'What\'s your AWS secret key?', + store: true, + }]; + + return this.prompt(questions).then((answers) => { + this.awsAccessKey = answers.awsAccessKey; + this.awsSecretKey = answers.awsSecretKey; + }); + } + + writing() { + this.fs.copy( + this.templatePath('aws.json.example'), + this.destinationPath('aws.json.example')); + + const awsJSON = { + accessKeyId: this.awsAccessKey, + secretAccessKey: this.awsSecretKey, + params: { + Bucket: 'com.politico.interactives.politico.com', + CloudFront: 'E3V6OHE700RHMR', + }, + }; + + this.fs.writeJSON('aws.json', awsJSON); + } +}; diff --git a/generators/app/templates/aws.json.example b/generators/aws/templates/aws.json.example similarity index 100% rename from generators/app/templates/aws.json.example rename to generators/aws/templates/aws.json.example diff --git a/generators/bundler-browserify/index.js b/generators/bundler-browserify/index.js index 63817be..5eb3f35 100644 --- a/generators/bundler-browserify/index.js +++ b/generators/bundler-browserify/index.js @@ -4,12 +4,6 @@ module.exports = class extends Generator { constructor(args, opts) { super(args, opts); - this.option('embed', { - type: Boolean, - required: false, - default: false, - desc: 'Whether building an embeddable', - }); this.option('archie', { type: Boolean, required: false, @@ -19,16 +13,6 @@ module.exports = class extends Generator { } writing() { - if (this.options.embed) { - this.fs.copy( - this.templatePath('src/js/main-embed.js'), - this.destinationPath('src/js/main.js')); - } else { - this.fs.copy( - this.templatePath('src/js/main.js'), - this.destinationPath('src/js/main.js')); - } - this.fs.copyTpl( this.templatePath('gulpfile.js'), this.destinationPath('gulpfile.js'), { @@ -66,9 +50,13 @@ module.exports = class extends Generator { 'fs-extra', 'gulp', 'gulp-babili', + 'gulp-cssnano', + 'gulp-env', + 'gulp-if', 'gulp-nunjucks-render', 'gulp-sass', 'gulp-sourcemaps', + 'gulp-uncss', 'gulp-util', 'marked', 'nunjucks', @@ -78,9 +66,7 @@ module.exports = class extends Generator { 'vinyl-source-stream', 'watchify', ]; - if (this.options.embed) { - dependencies.push('pym.js'); - } + this.yarnInstall(dependencies, { save: true }); } }; diff --git a/generators/bundler-browserify/templates/gulp/tasks/nunjucks.js b/generators/bundler-browserify/templates/gulp/tasks/nunjucks.js index 4b6f0f9..b5d6fc8 100644 --- a/generators/bundler-browserify/templates/gulp/tasks/nunjucks.js +++ b/generators/bundler-browserify/templates/gulp/tasks/nunjucks.js @@ -10,7 +10,8 @@ marked.setOptions({ smartypants: true }); const manageEnvironment = (environment) => { environment.addFilter('markdown', (str, kwargs) => { // strip outer

tags? - const strip = kwargs.strip || false; + const strip = typeof kwargs === 'undefined' ? + false : kwargs.strip || false; return !strip ? safe(marked(str)) : safe(marked(str).trim().replace(/^

|<\/p>$/g, '')); }); diff --git a/generators/bundler-browserify/templates/gulp/tasks/scss.js b/generators/bundler-browserify/templates/gulp/tasks/scss.js index f062f7e..f62e417 100644 --- a/generators/bundler-browserify/templates/gulp/tasks/scss.js +++ b/generators/bundler-browserify/templates/gulp/tasks/scss.js @@ -1,14 +1,26 @@ const gulp = require('gulp'); +const gulpif = require('gulp-if'); +const nano = require('gulp-cssnano'); const rename = require('gulp-rename'); const sass = require('gulp-sass'); const sourcemaps = require('gulp-sourcemaps'); +const uncss = require('gulp-uncss'); +const production = task => gulpif(process.env.NODE_ENV === 'production', task); module.exports = () => - gulp.src(['./src/scss/**/*.scss', './src/scss/**/*.css']) - // eslint-disable-next-line no-param-reassign - .pipe(rename((filePath) => { filePath.basename += '.bundle'; })) - .pipe(sourcemaps.init()) - .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError)) - .pipe(sourcemaps.write()) - .pipe(gulp.dest('./dist/css')); + gulp.src(['./src/scss/**/*.scss', './src/scss/**/*.css']) + // eslint-disable-next-line no-param-reassign + .pipe(rename((filePath) => { filePath.basename += '.bundle'; })) + .pipe(sourcemaps.init()) + .pipe(sass().on('error', sass.logError)) + .pipe(production(uncss({ + html: ['**/*.html'], + ignore: [ + /section\.graphic.*/, + /\.dataviz.*/, + ], + }))) + .pipe(production(nano())) + .pipe(sourcemaps.write()) + .pipe(gulp.dest('./dist/css')); diff --git a/generators/bundler-browserify/templates/gulpfile.js b/generators/bundler-browserify/templates/gulpfile.js index 6b1dc39..c3e07c1 100644 --- a/generators/bundler-browserify/templates/gulpfile.js +++ b/generators/bundler-browserify/templates/gulpfile.js @@ -1,22 +1,26 @@ +const env = require('gulp-env'); +const runSequence = require('run-sequence'); const gulp = require('./gulp')([ 'aws', - <% if (archie) { %>'archie',<% } %> // eslint-disable-line + <% if (archie) { %>'archie',<% } %> 'browserify', 'js-build', 'js-watch', 'nunjucks', 'scss', 'server', - 'img-copy', // from gulp generator ↓ ↓ ↓ ↓ + 'img-copy', 'img-optimize', 'img-resize', 'nunjucks-watch', ]); -const runSequence = require('run-sequence'); gulp.task('build', ['scss', 'js-build', 'nunjucks']); -gulp.task('publish', (cb) => { runSequence('build', 'aws', cb); }); +gulp.task('publish', (cb) => { + env.set({ NODE_ENV: 'production' }); + runSequence('build', 'aws', cb); +}); gulp.task('default', ['nunjucks-watch', 'scss', 'js-watch', 'server']); gulp.task('img', (cb) => { diff --git a/generators/bundler-browserify/templates/src/js/main-embed.js b/generators/bundler-browserify/templates/src/js/main-embed.js deleted file mode 100644 index dc28af2..0000000 --- a/generators/bundler-browserify/templates/src/js/main-embed.js +++ /dev/null @@ -1,4 +0,0 @@ -import pym from 'pym.js'; - -const pymChild = new pym.Child(); -pymChild.sendHeight(); diff --git a/generators/bundler-browserify/templates/src/js/main.js b/generators/bundler-browserify/templates/src/js/main.js deleted file mode 100644 index e69de29..0000000 diff --git a/generators/bundler-webpack/index.js b/generators/bundler-webpack/index.js index fedb893..98bee0a 100644 --- a/generators/bundler-webpack/index.js +++ b/generators/bundler-webpack/index.js @@ -5,12 +5,6 @@ module.exports = class extends Generator { constructor(args, opts) { super(args, opts); - this.option('embed', { - type: Boolean, - required: false, - default: false, - desc: 'Whether building an embeddable', - }); this.option('archie', { type: Boolean, required: false, @@ -22,10 +16,6 @@ module.exports = class extends Generator { writing() { mkdirp('./dist/js'); mkdirp('./dist/css'); - // JS files - this.fs.copy( - this.templatePath('src/js/main.js'), - this.destinationPath('src/js/main.js')); // Config files this.fs.copy( this.templatePath('webpack.config.js'), diff --git a/generators/bundler-webpack/templates/gulp/tasks/nunjucks.js b/generators/bundler-webpack/templates/gulp/tasks/nunjucks.js index 8e64ba7..dda5b95 100644 --- a/generators/bundler-webpack/templates/gulp/tasks/nunjucks.js +++ b/generators/bundler-webpack/templates/gulp/tasks/nunjucks.js @@ -10,7 +10,8 @@ marked.setOptions({ smartypants: true }); const manageEnvironment = (environment) => { environment.addFilter('markdown', (str, kwargs) => { // strip outer

tags? - const strip = kwargs.strip || false; + const strip = typeof kwargs === 'undefined' ? + false : kwargs.strip || false; return !strip ? safe(marked(str)) : safe(marked(str).trim().replace(/^

|<\/p>$/g, '')); }); diff --git a/generators/bundler-webpack/templates/gulpfile.js b/generators/bundler-webpack/templates/gulpfile.js index a2af726..9de5575 100644 --- a/generators/bundler-webpack/templates/gulpfile.js +++ b/generators/bundler-webpack/templates/gulpfile.js @@ -2,10 +2,10 @@ const runSequence = require('run-sequence'); const gulp = require('./gulp')([ 'aws', - <% if (archie) { %>'archie',<% } %> // eslint-disable-line + <% if (archie) { %>'archie',<% } %> 'nunjucks', 'webpack', - 'img-copy', // from gulp generator ↓ ↓ ↓ ↓ + 'img-copy', 'img-optimize', 'img-resize', 'nunjucks-watch', diff --git a/generators/bundler-webpack/templates/src/js/main.js b/generators/bundler-webpack/templates/src/js/main.js deleted file mode 100644 index d7d8e94..0000000 --- a/generators/bundler-webpack/templates/src/js/main.js +++ /dev/null @@ -1 +0,0 @@ -import './../scss/main.scss'; diff --git a/generators/gulp/templates/gulp/tasks/img-copy.js b/generators/gulp/templates/gulp/tasks/img-copy.js index 643bcd2..48ddcad 100644 --- a/generators/gulp/templates/gulp/tasks/img-copy.js +++ b/generators/gulp/templates/gulp/tasks/img-copy.js @@ -1,20 +1,24 @@ const gulp = require('gulp'); const changed = require('gulp-changed'); const merge = require('merge-stream'); +const rename = require('gulp-rename'); module.exports = () => { // Copies over SVGs or other image files - const other = gulp.src([ - './src/images/**/*', - '!./src/images/**/*.{png,jpg,JPG}', - '!./src/images/opt/**/*', -], { nodir: true }) - .pipe(changed('./dist/images')) - .pipe(gulp.dest('./dist/images')); + const other = gulp.src([ + './src/images/**/*', + '!./src/images/**/*.{png,jpg,JPG}', + '!./src/images/opt/**/*', + ], { nodir: true }) + .pipe(changed('./dist/images')) + .pipe(gulp.dest('./dist/images')); // Copy imgs that weren't resized const copied = gulp.src('./src/images/opt/**/_*.{png,jpg,JPG}') - .pipe(changed('./dist/images')) - .pipe(gulp.dest('./dist/images')); + .pipe(rename((path) => { + path.basename = path.basename.slice(1); // eslint-disable-line no-param-reassign + })) + .pipe(changed('./dist/images')) + .pipe(gulp.dest('./dist/images')); return merge(other, copied); }; diff --git a/generators/gulp/templates/gulp/tasks/nunjucks-watch.js b/generators/gulp/templates/gulp/tasks/nunjucks-watch.js index 6c6f57a..28705cc 100644 --- a/generators/gulp/templates/gulp/tasks/nunjucks-watch.js +++ b/generators/gulp/templates/gulp/tasks/nunjucks-watch.js @@ -1,3 +1,3 @@ const gulp = require('gulp'); -module.exports = () => gulp.watch('./src/templates/**/*.html', ['nunjucks']); +module.exports = () => gulp.watch('./src/templates/**/*', ['nunjucks']); diff --git a/generators/meta/index.js b/generators/meta/index.js new file mode 100644 index 0000000..431aa09 --- /dev/null +++ b/generators/meta/index.js @@ -0,0 +1,81 @@ +const Generator = require('yeoman-generator'); +const S = require('string'); + +module.exports = class extends Generator { + constructor(args, opts) { + super(args, opts); + + this.option('title', { + type: String, + required: true, + desc: 'Project title', + }); + } + + writing() { + this.title = this.options.title; + this.slug = S(this.title).slugify().s; + + const timestamp = new Date(); + const publishPath = `http://www.politico.com/interactives/${timestamp.getFullYear()}/${this.slug}/`; + + this.fs.copy( + this.templatePath('gitignore'), + this.destinationPath('./.gitignore')); + + this.fs.copyTpl( + this.templatePath('package.json'), + this.destinationPath('package.json'), { + slug: this.slug, + userName: this.user.git.name(), + userEmail: this.user.git.email(), + }); + + this.fs.copyTpl( + this.templatePath('README.md'), + this.destinationPath('README.md'), { + slug: this.slug, + title: this.title, + userName: this.user.git.name(), + userEmail: this.user.git.email(), + url: publishPath, + }); + + const metaJSON = { + id: (Math.floor(Math.random() * 100000000000) + 1).toString(), + publishPath, + url: `${publishPath}`, + share: { + fbook: { + card_title: this.title, + card_description: 'The latest news from POLITICO.', + author: 'politico', + }, + twitter: { + card_title: this.title, + card_description: 'The latest news from POLITICO.', + author: '@politico', + }, + image: { + url: `${publishPath}images/share.jpg`, + alt: '', + type: 'image/jpeg', + width: '600', + height: '300', + }, + keywords: 'POLITICO, News, Washington D.C.', + }, + telium: { + free_paid_content: 'free', + site_section: 'white house', + ad_unit_section: 'whitehouse', + content_author: 'Polly Politico|Peter Politico', + content_byline: 'By Polly Politico and Peter Politico', + page_name: `${this.title} — POLITICO`, + }, + }; + + this.fs.writeJSON('meta.json', metaJSON); + } + +}; diff --git a/generators/meta/templates/README.md b/generators/meta/templates/README.md new file mode 100644 index 0000000..e506d5a --- /dev/null +++ b/generators/meta/templates/README.md @@ -0,0 +1,10 @@ +![POLITICO](https://rawgithub.com/The-Politico/src/master/images/logo/badge.png) + +![](dist/images/share.jpg) + +# interactive_<%= slug %> + +| Title | <%= title %> | +|-|-| +| Developer | [<%= userName %>](<%= userEmail %>) | +| Link | [<%= url %>](<%= url %>) | diff --git a/generators/app/templates/gitignore b/generators/meta/templates/gitignore similarity index 100% rename from generators/app/templates/gitignore rename to generators/meta/templates/gitignore diff --git a/generators/app/templates/package.json b/generators/meta/templates/package.json similarity index 100% rename from generators/app/templates/package.json rename to generators/meta/templates/package.json diff --git a/generators/styles/index.js b/generators/styles/index.js index 8af446b..f696ac9 100644 --- a/generators/styles/index.js +++ b/generators/styles/index.js @@ -11,12 +11,18 @@ module.exports = class extends Generator { this.fs.copy( this.templatePath('src/scss/_breakpoints.scss'), this.destinationPath('src/scss/_breakpoints.scss')); + this.fs.copy( + this.templatePath('src/scss/_buttons.scss'), + this.destinationPath('src/scss/_buttons.scss')); this.fs.copy( this.templatePath('src/scss/_colors.scss'), this.destinationPath('src/scss/_colors.scss')); this.fs.copy( this.templatePath('src/scss/_comments.scss'), this.destinationPath('src/scss/_comments.scss')); + this.fs.copy( + this.templatePath('src/scss/_credits.scss'), + this.destinationPath('src/scss/_credits.scss')); this.fs.copy( this.templatePath('src/scss/_elements.scss'), this.destinationPath('src/scss/_elements.scss')); @@ -26,6 +32,9 @@ module.exports = class extends Generator { this.fs.copy( this.templatePath('src/scss/_footer.scss'), this.destinationPath('src/scss/_footer.scss')); + this.fs.copy( + this.templatePath('src/scss/_graphics.scss'), + this.destinationPath('src/scss/_graphics.scss')); this.fs.copy( this.templatePath('src/scss/_header.scss'), this.destinationPath('src/scss/_header.scss')); @@ -41,6 +50,9 @@ module.exports = class extends Generator { this.fs.copy( this.templatePath('src/scss/_photos.scss'), this.destinationPath('src/scss/_photos.scss')); + this.fs.copy( + this.templatePath('src/scss/_share.scss'), + this.destinationPath('src/scss/_share.scss')); this.fs.copy( this.templatePath('src/scss/main.scss'), this.destinationPath('src/scss/main.scss')); diff --git a/generators/styles/templates/src/scss/_ads.scss b/generators/styles/templates/src/scss/_ads.scss index a2b1d8f..550add3 100644 --- a/generators/styles/templates/src/scss/_ads.scss +++ b/generators/styles/templates/src/scss/_ads.scss @@ -1,22 +1,22 @@ .content-group.ad { + text-align: center; + margin: 0px auto; + padding: 20px 0; + .ad-slot.flex{ text-align: center; - margin: 0px auto; - padding: 20px 0; - .ad-slot.flex{ - text-align: center; - } + } - p{ - text-transform: uppercase; - font-family: $proxima; - font-size: 12px; - color: $medium-gray; - margin: 5px auto 0; - } + p { + text-transform: uppercase; + font-family: $proxima; + font-size: 12px; + color: $medium-gray; + margin: 5px auto 0; + } } -.ad{ - &.supercube, &.cube{ +.ad { + &.supercube, &.cube { padding-top: 35px; padding-bottom: 35px; max-width: 600px; diff --git a/generators/styles/templates/src/scss/_bootstrap.scss b/generators/styles/templates/src/scss/_bootstrap.scss index b14a9d0..a62a592 100644 --- a/generators/styles/templates/src/scss/_bootstrap.scss +++ b/generators/styles/templates/src/scss/_bootstrap.scss @@ -1,6 +1,4 @@ -/*! - * Uncomment the parts of bootstrap you need! - */ +/* Uncomment the parts of bootstrap you need! */ // Core variables and mixins @import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/variables"; diff --git a/generators/styles/templates/src/scss/_buttons.scss b/generators/styles/templates/src/scss/_buttons.scss new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/generators/styles/templates/src/scss/_buttons.scss @@ -0,0 +1 @@ + diff --git a/generators/styles/templates/src/scss/_colors.scss b/generators/styles/templates/src/scss/_colors.scss index 558acfd..44fe20d 100644 --- a/generators/styles/templates/src/scss/_colors.scss +++ b/generators/styles/templates/src/scss/_colors.scss @@ -1,13 +1,26 @@ +// Brand colors $politico-red: #9e0000; -$dark-red: #6b0000; +$politico-dark-red: #6b0000; +$politico-gray: #22252c; + +// Monochromes $black: #000; $white: #fff; + $light-gray: #ddd; -$medium-gray: #bdbdbd; -$footer-gray: #22252c; -$dark-gray-text: #999; -$satan: #666; +$medium-gray: #999; +$dark-gray: #666; + +$light-grey: $light-gray; +$medium-grey: $medium-gray; +$dark-grey: $dark-gray; +$satan: $dark-gray; + +// Element colors $facebook: #3b5998; $twitter: #00aced; $mail: #a9a9a9; $link: #0a7cc4; +$button: #7aaaf4; +$highlighter-yellow: #fffAb7; +$highlighter-orange: #f9d289; diff --git a/generators/styles/templates/src/scss/_comments.scss b/generators/styles/templates/src/scss/_comments.scss index 6e814a8..679d46b 100644 --- a/generators/styles/templates/src/scss/_comments.scss +++ b/generators/styles/templates/src/scss/_comments.scss @@ -1,4 +1,4 @@ -#fb-comments{ +section.comments{ max-width: 600px; margin: 40px auto 0; } diff --git a/generators/styles/templates/src/scss/_credits.scss b/generators/styles/templates/src/scss/_credits.scss new file mode 100644 index 0000000..06570a3 --- /dev/null +++ b/generators/styles/templates/src/scss/_credits.scss @@ -0,0 +1,14 @@ +section.credits{ + p { + font-family: $proxima; + font-size: .9em; + margin-top: 3em; + padding-top: 1em; + border-top: 1px solid $light-gray; + color: $satan; + + a:hover{ + text-decoration: underline; + } + } +} diff --git a/generators/styles/templates/src/scss/_elements.scss b/generators/styles/templates/src/scss/_elements.scss index bc7e5f8..6b6250a 100644 --- a/generators/styles/templates/src/scss/_elements.scss +++ b/generators/styles/templates/src/scss/_elements.scss @@ -70,6 +70,18 @@ p { @media (max-width: $width-medium) { font-size: 1.2em; } + + span.dropcap { + float: left; + font-size: 90px; + line-height: 0.85em; + font-family: $tablet; + margin-right: 0.115em; + color: #000; + text-transform: uppercase; + margin-top: 0px; + } + } h2, @@ -103,16 +115,8 @@ h4 + p { } -.graphic h2, -.graphic h3, -.graphic h4, -.graphic h5 { - font-family: $proxima; -} - - // Sections - article section { +article section { margin: 0 auto; max-width: 600px; padding: 1.25em 0; @@ -140,17 +144,3 @@ h4 + p { max-width: 800px; } } - -//credits -p.credits{ - font-family: $proxima; - font-size: .9em; - margin-top: 3em; - padding-top: 1em; - border-top: 1px solid $light-gray; - color: $satan; -} - -p.credits a:hover{ - text-decoration: underline; -} diff --git a/generators/styles/templates/src/scss/_footer.scss b/generators/styles/templates/src/scss/_footer.scss index 4bd8f14..72a78f8 100644 --- a/generators/styles/templates/src/scss/_footer.scss +++ b/generators/styles/templates/src/scss/_footer.scss @@ -1,7 +1,7 @@ // Footer #global-footer { - background-color: $footer-gray; - color: $dark-gray-text; + background-color: $politico-gray; + color: $medium-gray; padding: 5px 10px; position: absolute; right: 0; @@ -10,12 +10,12 @@ .icon-politico { font-size: 1em; - color: $dark-gray-text; + color: $medium-gray; padding-bottom: 3px; } a{ - color: $dark-gray-text; + color: $medium-gray; } .footer-branding::after{ @@ -42,7 +42,7 @@ .copyright, .legal-links, .legal-links a{ font-size: 10px; font-family: $proxima; - color: $dark-gray-text; + color: $medium-gray; } ul{ diff --git a/generators/styles/templates/src/scss/_graphics.scss b/generators/styles/templates/src/scss/_graphics.scss new file mode 100644 index 0000000..69d42b8 --- /dev/null +++ b/generators/styles/templates/src/scss/_graphics.scss @@ -0,0 +1,8 @@ +section.graphic { + h2, h3, h4, h5 { + font-family: $proxima; + } +} + +// Prefix classes added to elements by javascript with the following: +/* uncss:ignore */ diff --git a/generators/styles/templates/src/scss/_navigation.scss b/generators/styles/templates/src/scss/_navigation.scss index 21e04ab..a3307f0 100644 --- a/generators/styles/templates/src/scss/_navigation.scss +++ b/generators/styles/templates/src/scss/_navigation.scss @@ -45,7 +45,7 @@ li > a { background: $politico-red; - border-left: 1px solid $dark-red; + border-left: 1px solid $politico-dark-red; display: block; font-family: $tablet; font-weight: 700; diff --git a/generators/styles/templates/src/scss/_photos.scss b/generators/styles/templates/src/scss/_photos.scss index 5dcc2cf..ecd97e5 100644 --- a/generators/styles/templates/src/scss/_photos.scss +++ b/generators/styles/templates/src/scss/_photos.scss @@ -41,7 +41,7 @@ figure { } figcaption { - color: $dark-gray-text; + color: $medium-gray; font-family: $proxima; font-size: .875em; line-height: 1.2em; diff --git a/generators/styles/templates/src/scss/_share.scss b/generators/styles/templates/src/scss/_share.scss new file mode 100644 index 0000000..d0dd661 --- /dev/null +++ b/generators/styles/templates/src/scss/_share.scss @@ -0,0 +1,27 @@ +section.share{ +text-align: center; +margin: 20px auto; + a { + color: white; + background-color: $light-gray; + padding: 4px; + margin: 0 2px; + display: inline-block; + border-radius: 4px; + font-size: 18px; + transition: all .2s; + &.icon-facebook{ + background-color: $facebook; + } + &.icon-twitter{ + background-color: $twitter; + } + &.icon-mail{ + background-color: $dark-gray; + } + cursor:pointer; + &:hover{ + text-decoration: none; + } + } +} diff --git a/generators/styles/templates/src/scss/main.scss b/generators/styles/templates/src/scss/main.scss index 662242b..0fda1a3 100644 --- a/generators/styles/templates/src/scss/main.scss +++ b/generators/styles/templates/src/scss/main.scss @@ -6,10 +6,14 @@ @import 'fonts'; @import 'icons'; +@import 'elements'; @import 'navigation'; @import 'header'; @import 'footer'; @import 'photos'; -@import 'elements'; +@import 'buttons'; @import 'ads'; @import 'comments'; +@import 'share'; +@import 'credits'; +@import 'graphics'; diff --git a/generators/templates-embeddable/index.js b/generators/templates-embeddable/index.js deleted file mode 100644 index ad5778d..0000000 --- a/generators/templates-embeddable/index.js +++ /dev/null @@ -1,101 +0,0 @@ -const Generator = require('yeoman-generator'); -const mkdirp = require('mkdirp'); -const fs = require('fs'); -const S = require('string'); - -module.exports = class extends Generator { - constructor(args, opts) { - super(args, opts); - - this.option('title', { - type: String, - required: true, - desc: 'Project title', - }); - - this.option('webpack', { - type: Boolean, - required: false, - default: false, - desc: 'Use webpack module bundler', - }); - this.option('archie', { - type: Boolean, - required: false, - default: false, - desc: 'Use ArchieML', - }); - } - - initializing() { - switch (this.options.webpack) { - case true: - this.composeWith(require.resolve('../bundler-webpack'), { - embed: true, - archie: this.options.archie, - }); - break; - default: - this.composeWith(require.resolve('../bundler-browserify'), { - embed: true, - archie: this.options.archie, - }); - } - if (this.options.archie) this.composeWith(require.resolve('../archie')); - } - - writing() { - const d = new Date(); - const slug = S(this.options.title).slugify().s; - // Skeleton - mkdirp('./src'); - mkdirp('./dist'); - this.fs.copyTpl( - this.templatePath('README.md'), - this.destinationPath('README.md'), { - title: this.options.title, - path: `${d.getFullYear()}/embed/${slug}/index.html`, - slug, - }); - // Nunjucks templates - this.fs.copyTpl( - this.templatePath('src/templates/index.html'), - this.destinationPath('src/templates/index.html'), - { title: this.options.title }); - this.fs.copyTpl( - this.templatePath('src/templates/base.html'), - this.destinationPath('src/templates/base.html'), - { - cssInclude: !this.options.webpack, // Don't include script tags for webpack - jsInclude: !this.options.webpack, // which injects them automatically. - }); - this.fs.writeJSON('src/templates/data.json', {}); - this.fs.copyTpl( - this.templatePath('dist/embed.html'), - this.destinationPath('dist/embed.html'), { - slug: S(this.options.title).slugify().s, - }); - // Images directory - mkdirp('./src/images'); - mkdirp('./src/images/opt'); - } - - end() { - const nunjucksTask = this.spawnCommand('gulp', ['nunjucks']); - nunjucksTask.on('close', () => { - // Copy the rendered template over initially - if (this.options.webpack) { - fs.createReadStream('./src/index.html').pipe(fs.createWriteStream('./dist/index.html')); - } - - const imgTask = this.spawnCommand('gulp', ['img']); - imgTask.on('close', () => { - // Need this for webpack. Investigating why... - const yarnTask = this.spawnCommand('yarn', ['install']); - yarnTask.on('close', () => { - this.spawnCommand('gulp'); - }); - }); - }); - } -}; diff --git a/generators/templates-embeddable/templates/README.md b/generators/templates-embeddable/templates/README.md deleted file mode 100644 index 82c276c..0000000 --- a/generators/templates-embeddable/templates/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# <%=title%> - -#### Embed code - -``` -

- - - -``` - -**NOTE:** If you change the `publishPath` in `meta.json`, you need to adjust the URL in this code, as well. - -#### Responsive iframes - -We use [pym.js](http://blog.apps.npr.org/pym.js/) to create responsive embeds. - -By default, your app has been setup to correctly adjust the height of your iframe on the parent page using the library. If, however, you have dynamic content that updates your embed's height, then you need to explicitly call pym's `sendHeight` method in the child page: - -```javascript -import pym from 'pym.js'; - -const pymChild = new pym.Child(); -pymChild.sendHeight(); // Sets initial height - -const functionThatChangesContentHeight = () =>{ - // Do stuff here that changes content height... - - // Call sendHeight to update iframe height on parent page - pymChild.sendHeight(); -}; - - -functionThatChangesContentHeight(); -``` - -Sometimes, if you have animations associated with your transitions, you may want to delay the `sendHeight` call. Simply add a timeout: - -```javascript -window.setTimeout(() => {pymChild.sendHeight();}, 500); -``` - -#### To publish - -Make sure you have the correct publish path set in `meta.json` and that you've correctly filled in you AWS access keys in `aws.json`. Then run: - -```bash -$ gulp publish -``` - -Unless you've changed your publishPath in meta.json, your project will be published at: - -**[http://www.politico.com/interactives/<%=path%>](http://www.politico.com/interactives/<%=path%>)** diff --git a/generators/templates-embeddable/templates/dist/embed.html b/generators/templates-embeddable/templates/dist/embed.html deleted file mode 100644 index fed9d4c..0000000 --- a/generators/templates-embeddable/templates/dist/embed.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - -
- - -
- - - diff --git a/generators/templates-embeddable/templates/src/templates/base.html b/generators/templates-embeddable/templates/src/templates/base.html deleted file mode 100644 index 7b657f9..0000000 --- a/generators/templates-embeddable/templates/src/templates/base.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - {%block title%}Politico Interactives{%endblock%} - <%# Skip if using webpack. #%> - <% if (cssInclude) { %> <% } %> - - - - - - - {%block content%}{%endblock%} - <%# Skip if using webpack. #%> - <% if (jsInclude) { %> <% } %> - - diff --git a/generators/templates-embeddable/templates/src/templates/index.html b/generators/templates-embeddable/templates/src/templates/index.html deleted file mode 100644 index aafa51c..0000000 --- a/generators/templates-embeddable/templates/src/templates/index.html +++ /dev/null @@ -1,9 +0,0 @@ -{%extends "base.html"%} - -{%block title%} -<%=title%> -{%endblock%} - -{%block content%} -

Politico

-{%endblock%} diff --git a/generators/templates-page/index.js b/generators/templates/index.js similarity index 67% rename from generators/templates-page/index.js rename to generators/templates/index.js index 73ad44e..e470a33 100644 --- a/generators/templates-page/index.js +++ b/generators/templates/index.js @@ -12,35 +12,50 @@ module.exports = class extends Generator { desc: 'Project title', }); - this.option('webpack', { - type: Boolean, - required: false, - default: false, - desc: 'Use webpack module bundler', - }); - this.option('archie', { - type: Boolean, - required: false, + this.BROWSERIFY = 'browserify'; + this.WEBPACK = 'webpack'; + } + + prompting() { + const questions = [{ + type: 'list', + name: 'bundler', + message: 'Which module bundler would you like to use?', + default: this.BROWSERIFY, + choices: [ + { + name: 'Browserify (default)', + value: this.BROWSERIFY, + }, + { + name: 'Webpack (ES2015 + SCSS)', + value: this.WEBPACK, + }, + ], + }, { + type: 'confirm', + name: 'archie', + message: 'Would you like to include an ArchieML configuration?', default: false, - desc: 'Use ArchieML', + }]; + + return this.prompt(questions).then((answers) => { + this.webpack = answers.bundler === this.WEBPACK; + this.archie = answers.archie; }); } - initializing() { - switch (this.options.webpack) { - case true: - this.composeWith(require.resolve('../bundler-webpack'), { - embed: false, - archie: this.options.archie, - }); - break; - default: - this.composeWith(require.resolve('../bundler-browserify'), { - embed: false, - archie: this.options.archie, - }); + template() { + if (this.webpack) { + this.composeWith(require.resolve('../bundler-webpack'), { + archie: this.archie, + }); + } else { + this.composeWith(require.resolve('../bundler-browserify'), { + archie: this.archie, + }); } - if (this.options.archie) this.composeWith(require.resolve('../archie')); + if (this.archie) this.composeWith(require.resolve('../archie')); } writing() { @@ -54,10 +69,7 @@ module.exports = class extends Generator { this.fs.copyTpl( this.templatePath('src/templates/base.html'), this.destinationPath('src/templates/base.html'), - { - cssInclude: !this.options.webpack, // Don't include script tags for webpack - jsInclude: !this.options.webpack, // which injects them automatically. - }); + { webpack: this.webpack }); // Meta this.fs.copy( this.templatePath('src/templates/meta/social.html'), @@ -93,15 +105,22 @@ module.exports = class extends Generator { // Template context this.fs.writeJSON('src/templates/data.json', {}); // Images directory - mkdirp('./src/images'); + this.fs.copy( + this.templatePath('src/images/_share.jpg'), + this.destinationPath('src/images/_share.jpg')); mkdirp('./src/images/opt'); + mkdirp('./dist/images'); + // Javascript + this.fs.copy( + this.templatePath('src/js/main.js'), + this.destinationPath('src/js/main.js')); } end() { const nunjucksTask = this.spawnCommand('gulp', ['nunjucks']); nunjucksTask.on('close', () => { // Copy the rendered template over initially - if (this.options.webpack) { + if (this.webpack) { fs.createReadStream('./src/index.html').pipe(fs.createWriteStream('./dist/index.html')); } diff --git a/generators/templates/templates/src/images/_share.jpg b/generators/templates/templates/src/images/_share.jpg new file mode 100644 index 0000000..260ddc7 Binary files /dev/null and b/generators/templates/templates/src/images/_share.jpg differ diff --git a/generators/templates/templates/src/js/main.js b/generators/templates/templates/src/js/main.js new file mode 100644 index 0000000..4eba1ce --- /dev/null +++ b/generators/templates/templates/src/js/main.js @@ -0,0 +1,14 @@ +window.$('.icon-facebook').click((e) => { + e.preventDefault(); + const uri = encodeURIComponent(window.location.href); + window.open(`https://www.facebook.com/sharer/sharer.php?u=${uri}`); +}); + + +window.$('.icon-twitter').click((e) => { + e.preventDefault(); + const uri = window.location.href; + const tweet = 'The latest news from POLITICO'; + const status = encodeURIComponent(`${tweet} ${uri}`); + window.open(`https://twitter.com/home?status=${status}`); +}); diff --git a/generators/templates-page/templates/src/templates/ads/banner1.html b/generators/templates/templates/src/templates/ads/banner1.html similarity index 100% rename from generators/templates-page/templates/src/templates/ads/banner1.html rename to generators/templates/templates/src/templates/ads/banner1.html diff --git a/generators/templates-page/templates/src/templates/ads/banner2.html b/generators/templates/templates/src/templates/ads/banner2.html similarity index 100% rename from generators/templates-page/templates/src/templates/ads/banner2.html rename to generators/templates/templates/src/templates/ads/banner2.html diff --git a/generators/templates-page/templates/src/templates/ads/cube.html b/generators/templates/templates/src/templates/ads/cube.html similarity index 100% rename from generators/templates-page/templates/src/templates/ads/cube.html rename to generators/templates/templates/src/templates/ads/cube.html diff --git a/generators/templates-page/templates/src/templates/ads/script.html b/generators/templates/templates/src/templates/ads/script.html similarity index 100% rename from generators/templates-page/templates/src/templates/ads/script.html rename to generators/templates/templates/src/templates/ads/script.html diff --git a/generators/templates-page/templates/src/templates/ads/supercube1.html b/generators/templates/templates/src/templates/ads/supercube1.html similarity index 100% rename from generators/templates-page/templates/src/templates/ads/supercube1.html rename to generators/templates/templates/src/templates/ads/supercube1.html diff --git a/generators/templates-page/templates/src/templates/ads/supercube2.html b/generators/templates/templates/src/templates/ads/supercube2.html similarity index 100% rename from generators/templates-page/templates/src/templates/ads/supercube2.html rename to generators/templates/templates/src/templates/ads/supercube2.html diff --git a/generators/templates-page/templates/src/templates/base.html b/generators/templates/templates/src/templates/base.html similarity index 91% rename from generators/templates-page/templates/src/templates/base.html rename to generators/templates/templates/src/templates/base.html index 8e07d3a..ac68655 100644 --- a/generators/templates-page/templates/src/templates/base.html +++ b/generators/templates/templates/src/templates/base.html @@ -7,8 +7,9 @@ {%block title%}Politico Interactives{%endblock%} {%include "meta/icons.html"%} {%include "meta/social.html"%} - - + + <%# Skip if using webpack. #%> + <% if (!webpack) { %><% } %> + + <%# Skip if using webpack. #%> + <% if (!webpack) { %><% } %> {% include "meta/telium.html" %} {% include "ads/script.html" %} diff --git a/generators/templates-page/templates/src/templates/index.html b/generators/templates/templates/src/templates/index.html similarity index 80% rename from generators/templates-page/templates/src/templates/index.html rename to generators/templates/templates/src/templates/index.html index 24f2d22..82cd2c2 100644 --- a/generators/templates-page/templates/src/templates/index.html +++ b/generators/templates/templates/src/templates/index.html @@ -10,8 +10,14 @@ {% include "ads/banner1.html" %}
+

- Category title

+ Category title +

Your pithy, compelling headline here

@@ -30,7 +36,7 @@

{%endblock%} {%block content%} -

George Washington (February 11, 1731) was an American politician and soldier who served as the first President of the United States from 1789 to 1797 and was one of the Founding Fathers of the United States. He served as Commander-in-Chief of the Continental Army during the American Revolutionary War, and later presided over the 1787 convention that drafted the United States Constitution. He is popularly considered the driving force behind the nation's establishment and came to be known as the "father of the country," both during his lifetime and to this day.

+

George Washington (February 11, 1731) was an American politician and soldier who served as the first President of the United States from 1789 to 1797 and was one of the Founding Fathers of the United States. He served as Commander-in-Chief of the Continental Army during the American Revolutionary War, and later presided over the 1787 convention that drafted the United States Constitution. He is popularly considered the driving force behind the nation's establishment and came to be known as the "father of the country," both during his lifetime and to this day.

After crossing the Delaware River in the middle of winter, he defeated the British in two battles (Trenton and Princeton), retook New Jersey, and restored momentum to the Patriot cause. His strategy enabled Continental forces to capture two major British armies at Saratoga in 1777 and Yorktown in 1781.

@@ -67,7 +73,10 @@

H2 header

The death of his father prevented Washington from an education at England's Appleby School such as his older brothers had received. He achieved the equivalent of an elementary school education from a variety of tutors, as well as from a school run by an Anglican clergyman in or near Fredericksburg.[17][18] There was talk of securing an appointment for him in the Royal Navy when he was 15, but it was dropped when his widowed mother objected.

-

Copy edited by Firstname Lastname. Produced by FirstName Last.

+
+

Copy edited by Firstname Lastname. Produced by FirstName Last.

+
+ {% include "meta/comments.html" %} diff --git a/generators/templates-page/templates/src/templates/meta/comments.html b/generators/templates/templates/src/templates/meta/comments.html similarity index 69% rename from generators/templates-page/templates/src/templates/meta/comments.html rename to generators/templates/templates/src/templates/meta/comments.html index 8ec5dea..99ad010 100644 --- a/generators/templates-page/templates/src/templates/meta/comments.html +++ b/generators/templates/templates/src/templates/meta/comments.html @@ -1,7 +1,7 @@ -
-
-
-
+
+
+
+