Skip to content

Commit 0e13462

Browse files
author
mrmrs
committed
Merge branch 'master' of github.com:tachyons-css/tachyons-css.github.io
2 parents 9afcd94 + 3c1b445 commit 0e13462

8 files changed

+117
-85
lines changed

build.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,18 @@ const componentsBuildScreenshots = require('./src/components-build-screenshots')
2121

2222
// See src/components-build-defaults for list of options that can be overriden
2323
const options = {
24-
// componentsGlobPattern: 'src/components/buttons/*.html',
24+
components: {
25+
globPattern: 'src/components/banners/*.html',
26+
// frontMatter: {
27+
// bodyClass: 'bg-red',
28+
// screenshot: {
29+
// autocrop: false,
30+
// },
31+
// },
32+
},
33+
// screenshot: {
34+
// aspectRatio: '16x9',
35+
// },
2536
};
2637

2738
// Note that componentsBuildIndex() generates the index *and* the JSON

src/components-build-defaults.js

+39-22
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,46 @@
11
module.exports = {
22
// Components
3-
componentsForNavPath: 'tmp/componentsForNav.json', // temporary file built by the index
4-
componentsGlobPattern: 'src/components/**/*.html', // source components to process
5-
componentsIndexPath: 'components/index.html', // target location of components index
6-
componentsBuildPages: true, // false to skip building pages
7-
componentsBuildScreenshots: true, // false to skip building screenshots
8-
// Screenshots
9-
screenshotName: 'screenshot.jpg', // name JPEG screenshot in each component dir
10-
screenshotAspectRatio: '4x3', // Tachyon aspect ratio of screenshot in index
11-
screenshotViewportWidth: 1024, // viewport width used for capture
12-
screenshotViewportHeight: 768, // viewport height used for capture
13-
screenshotTargetMinWidth: 400, // min width of target, resized screenshot
14-
screenshotTargetMinHeight: 160, // min height of target, resized screenshot
15-
mozjpegQuality: 90, // mozjpeg optimizer quality (default 75)
16-
screenshotSelector: '[data-name="component-container"]', // DOM element to capture
3+
components: {
4+
globPattern: 'src/components/**/*.html', // source components to process
5+
forNavPath: 'tmp/componentsForNav.json', // temporary file built by the index
6+
indexPath: 'components/index.html', // target location of components index
7+
buildPages: true, // false to skip building pages
8+
buildScreenshots: true, // false to skip building screenshots
9+
frontMatter: { // font matter defaults (i.e. optional)
10+
name: undefined, // undefined to infer component name
11+
title: undefined, // undefined to infer component title
12+
bodyClass: 'bg-white', // class to apply on <body>
13+
screenshot: { // per-component screenshot options
14+
selector: '[data-name="component"]', // DOM element to capture
15+
autocrop: true, // autocrop the capture
16+
'background-position': 'center center', // CSS background position
17+
'background-size': 'cover', // CSS background size ('cover', 'contain', 'auto')
18+
},
19+
},
20+
},
21+
// Screenshot options
22+
// (components only for now, but could apply to other areas for consistency)
23+
screenshot: {
24+
basename: 'screenshot.jpg', // name of *JPEG* screenshot
25+
aspectRatio: '4x3', // Tachyons aspect ratio of screenshots
26+
viewportWidth: 1024, // viewport width used for capture
27+
viewportHeight: 768, // viewport height used for capture
28+
targetMinWidth: 400, // min width of target (final) screenshot
29+
targetMinHeight: 160, // min height of target (final) screenshot
30+
mozjpegQuality: 90, // mozjpeg optimizer quality (default 75)
31+
},
1732
// Misc
1833
tachyonsCssPath: 'src/css/tachyons.css',
1934
serverPort: 3333,
2035
// Templates
21-
analyticsTemplatePath: 'src/templates/ga.html',
22-
componentsIndexTemplatePath: 'src/templates/components-index.html',
23-
componentsTemplatePath: 'src/templates/components.html',
24-
footerTemplatePath: 'src/templates/footer.html',
25-
headerTemplatePath: 'src/templates/header.html',
26-
headTemplatePath: 'src/templates/head.html',
27-
highlightTemplatePath: 'src/templates/highlight.html',
28-
lazysizesTemplate: 'src/templates/lazysizes.html',
36+
templates: {
37+
analyticsPath: 'src/templates/ga.html',
38+
componentsIndexPath: 'src/templates/components-index.html',
39+
componentPath: 'src/templates/component.html',
40+
footerPath: 'src/templates/footer.html',
41+
headerPath: 'src/templates/header.html',
42+
headPath: 'src/templates/head.html',
43+
highlightPath: 'src/templates/highlight.html',
44+
lazysizesPath: 'src/templates/lazysizes.html',
45+
},
2946
};

src/components-build-index.js

+22-18
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ const getTitle = (component) => {
2020
const getName = component => titleize(getTitle(component.split('/')[3]));
2121

2222
module.exports = _options => new Promise((resolve, reject) => {
23-
const options = _.assign({}, defaults, _options);
23+
const options = _.merge({}, defaults, _options);
2424
const startTime = process.hrtime();
25-
glob(options.componentsGlobPattern, {}, (err, components) => {
25+
glob(options.components.globPattern, {}, (err, components) => {
2626
console.log(chalk.magenta('Working on components index...'));
2727
if (err) {
2828
reject(err);
@@ -38,7 +38,8 @@ module.exports = _options => new Promise((resolve, reject) => {
3838

3939
const componentHtml = fs.readFileSync(component, 'utf8');
4040
const fmParsed = fm.parse(componentHtml);
41-
const frontMatter = fmParsed.attributes || {};
41+
const srcFrontMatter = fmParsed.attributes || {};
42+
const frontMatter = _.merge({}, options.components.frontMatter, srcFrontMatter);
4243
const dir = component.replace('src/', '').replace('.html', '');
4344

4445
// Compute component signature based on the Tachyons version and the contents of the
@@ -56,11 +57,14 @@ module.exports = _options => new Promise((resolve, reject) => {
5657
path: `${dir}/index.html`,
5758
href: `/${dir}/index.html`,
5859
screenshot: {
59-
path: `${dir}/${options.screenshotName}`,
60-
href: `/${dir}/${options.screenshotName}?version=${signature}`,
60+
path: `${dir}/${options.screenshot.basename}`,
61+
href: `/${dir}/${options.screenshot.basename}?version=${signature}`,
6162
},
6263
signature,
63-
frontMatter,
64+
// This is the raw front matter, as found in the component source, NOT merged
65+
// with any defaults, so that it is easier to spot the overrides.
66+
// It is up to build scripts to merge with options.components.frontMatter down the road.
67+
frontMatter: srcFrontMatter,
6468
});
6569
});
6670

@@ -70,16 +74,16 @@ module.exports = _options => new Promise((resolve, reject) => {
7074
'in', categories.length, categories.length > 1 ? 'categories' : 'category'
7175
);
7276

73-
mkdirp.sync(path.dirname(options.componentsForNavPath));
74-
fs.writeFileSync(options.componentsForNavPath, JSON.stringify(componentsForNav, undefined, 2));
75-
console.log('- Created navigation JSON:', options.componentsForNavPath);
77+
mkdirp.sync(path.dirname(options.components.forNavPath));
78+
fs.writeFileSync(options.components.forNavPath, JSON.stringify(componentsForNav, undefined, 2));
79+
console.log('- Created navigation JSON:', options.components.forNavPath);
7680

77-
const analytics = fs.readFileSync(options.analyticsTemplatePath, 'utf8');
78-
const footer = fs.readFileSync(options.footerTemplatePath, 'utf8');
79-
const head = fs.readFileSync(options.headTemplatePath, 'utf8');
80-
const header = fs.readFileSync(options.headerTemplatePath, 'utf8');
81-
const componentsIndexTemplate = fs.readFileSync(options.componentsIndexTemplatePath, 'utf8');
82-
const lazysizesTemplate = fs.readFileSync(options.lazysizesTemplate, 'utf8');
81+
const analytics = fs.readFileSync(options.templates.analyticsPath, 'utf8');
82+
const footer = fs.readFileSync(options.templates.footerPath, 'utf8');
83+
const head = fs.readFileSync(options.templates.headPath, 'utf8');
84+
const header = fs.readFileSync(options.templates.headerPath, 'utf8');
85+
const componentsIndexTemplate = fs.readFileSync(options.templates.componentsIndexPath, 'utf8');
86+
const lazysizesTemplate = fs.readFileSync(options.templates.lazysizesPath, 'utf8');
8387

8488
const compiledPage = _.template(componentsIndexTemplate)({
8589
componentsForNav,
@@ -91,9 +95,9 @@ module.exports = _options => new Promise((resolve, reject) => {
9195
lazysizesTemplate,
9296
options,
9397
});
94-
mkdirp.sync(path.dirname(options.componentsIndexPath));
95-
fs.writeFileSync(options.componentsIndexPath, compiledPage);
96-
console.log('- Created index:', options.componentsIndexPath);
98+
mkdirp.sync(path.dirname(options.components.indexPath));
99+
fs.writeFileSync(options.components.indexPath, compiledPage);
100+
console.log('- Created index:', options.components.indexPath);
97101

98102
const elapsed = process.hrtime(startTime);
99103
console.log(chalk.magenta('Done with components index!'), chalk.dim(prettyHrtime(elapsed)));

src/components-build-pages.js

+10-11
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,25 @@ const select = require('postcss-select');
2323
const defaults = require('./components-build-defaults');
2424

2525
module.exports = _options => new Promise((resolve, reject) => {
26-
const options = _.assign({}, defaults, _options);
26+
const options = _.merge({}, defaults, _options);
2727
const startTime = process.hrtime();
2828
console.log(chalk.magenta('Working on components pages...'));
29-
if (options.componentsForNavPath === undefined || !fs.existsSync(options.componentsForNavPath)) {
29+
if (options.components.forNavPath === undefined || !fs.existsSync(options.components.forNavPath)) {
3030
reject('Can not find components nav JSON file');
3131
return;
3232
}
33-
if (!options.componentsBuildPages) {
33+
if (!options.components.buildPages) {
3434
console.log(chalk.dim('Skipped by request.'));
3535
resolve();
3636
return;
3737
}
38-
const componentsForNav = JSON.parse(fs.readFileSync(options.componentsForNavPath, 'utf8'));
38+
const componentsForNav = JSON.parse(fs.readFileSync(options.components.forNavPath, 'utf8'));
3939

40-
const componentTemplate = fs.readFileSync(options.componentsTemplatePath, 'utf8');
41-
const analytics = fs.readFileSync(options.analyticsTemplatePath, 'utf8');
42-
const footer = fs.readFileSync(options.footerTemplatePath, 'utf8');
43-
const head = fs.readFileSync(options.headTemplatePath, 'utf8');
44-
const highlight = fs.readFileSync(options.highlightTemplatePath, 'utf8');
40+
const componentTemplate = fs.readFileSync(options.templates.componentPath, 'utf8');
41+
const analytics = fs.readFileSync(options.templates.analyticsPath, 'utf8');
42+
const footer = fs.readFileSync(options.templates.footerPath, 'utf8');
43+
const head = fs.readFileSync(options.templates.headPath, 'utf8');
44+
const highlight = fs.readFileSync(options.templates.highlightPath, 'utf8');
4545

4646
const tachyonsCss = fs.readFileSync(options.tachyonsCssPath, 'utf8');
4747

@@ -57,10 +57,9 @@ module.exports = _options => new Promise((resolve, reject) => {
5757
const componentHtml = fs.readFileSync(component.src, 'utf8');
5858
const fmParsed = fm.parse(componentHtml);
5959

60-
const frontMatter = _.assign({}, component.frontMatter);
60+
const frontMatter = _.merge({}, options.components.frontMatter, component.frontMatter);
6161
frontMatter.title = component.title;
6262
frontMatter.name = component.name;
63-
frontMatter.bodyClass = frontMatter.bodyClass || '';
6463
frontMatter.classes = getClasses(fmParsed.body).map(klass => `.${klass}`);
6564
frontMatter.componentHtml = componentHtml;
6665
frontMatter.content = fmParsed.body;

src/components-build-screenshots.js

+17-21
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,19 @@ const initNightmare = () => Nightmare({ // eslint-disable-line
4040
const formatFromSizeToSize = (from, to) => `(${filesize(from)} => ${filesize(to)})`;
4141

4242
module.exports = _options => new Promise((resolve, reject) => {
43-
const options = _.assign({}, defaults, _options);
43+
const options = _.merge({}, defaults, _options);
4444
const startTime = process.hrtime();
4545
console.log(chalk.magenta('Working on components screenshots...'));
46-
if (options.componentsForNavPath === undefined || !fs.existsSync(options.componentsForNavPath)) {
46+
if (options.components.forNavPath === undefined || !fs.existsSync(options.components.forNavPath)) {
4747
reject('Can not find components nav JSON file');
4848
return;
4949
}
50-
if (!options.componentsBuildScreenshots) {
50+
if (!options.components.buildScreenshots) {
5151
console.log(chalk.dim('Skipped by request.'));
5252
resolve();
5353
return;
5454
}
55-
const componentsForNav = JSON.parse(fs.readFileSync(options.componentsForNavPath, 'utf8'));
55+
const componentsForNav = JSON.parse(fs.readFileSync(options.components.forNavPath, 'utf8'));
5656

5757
const nightmare = initNightmare();
5858

@@ -70,18 +70,15 @@ module.exports = _options => new Promise((resolve, reject) => {
7070

7171
for (let comp_idx = 0; comp_idx < componentsForNav[category].length; comp_idx += 1) {
7272
const component = componentsForNav[category][comp_idx];
73-
let selector = options.screenshotSelector;
74-
if (component.frontMatter.screenshot && component.frontMatter.screenshot.selector) {
75-
selector = `${selector} ${component.frontMatter.screenshot.selector}`;
76-
}
73+
const frontMatter = _.merge({}, options.components.frontMatter, component.frontMatter);
7774

7875
// Grab the size of the component enclosing rectangle
7976
// https://github.com/segmentio/nightmare/issues/498#issuecomment-189156529
8077
const componentRect = yield nightmare
81-
.viewport(options.screenshotViewportWidth, options.screenshotViewportHeight)
78+
.viewport(options.screenshot.viewportWidth, options.screenshot.viewportHeight)
8279
// .wait(1000)
8380
.goto(`http://localhost:${options.serverPort}${component.href}`)
84-
.wait(selector)
81+
.wait(frontMatter.screenshot.selector)
8582
.evaluate((_selector) => {
8683
// Hide scrollbar that could pop up due to .scrollTo
8784
const sheet = document.styleSheets[0];
@@ -97,7 +94,7 @@ module.exports = _options => new Promise((resolve, reject) => {
9794
};
9895
}
9996
return false;
100-
}, selector);
97+
}, frontMatter.screenshot.selector);
10198

10299
// Capture the component
103100
if (componentRect === false) {
@@ -107,12 +104,12 @@ module.exports = _options => new Promise((resolve, reject) => {
107104

108105
const screenshotDir = path.dirname(component.screenshot.path);
109106
const tmpPngObj = tmp.fileSync({ dir: screenshotDir });
110-
componentRect.height = Math.min(componentRect.height, options.screenshotViewportHeight);
107+
componentRect.height = Math.min(componentRect.height, options.screenshot.viewportHeight);
111108
yield nightmare
112109
// we can not use .screenshot() with componentRect, so constrain the viewport instead
113110
.viewport(
114-
componentRect.width || options.screenshotViewportWidth,
115-
componentRect.height || options.screenshotViewportHeight
111+
componentRect.width || options.screenshot.viewportWidth,
112+
componentRect.height || options.screenshot.viewportHeight
116113
).scrollTo(componentRect.y, componentRect.x)
117114
// .wait(1000)
118115
.screenshot(tmpPngObj.name); // do *not* use componentRect here or risk distortions
@@ -122,15 +119,14 @@ module.exports = _options => new Promise((resolve, reject) => {
122119
const tmpJpegPath = path.join(tmpJpegDirObj.name, path.basename(component.screenshot.path));
123120
const screenshot = yield Jimp.read(tmpPngObj.name);
124121
yield new Promise((write_resolve, write_reject) => {
125-
if (component.frontMatter.screenshot === undefined ||
126-
component.frontMatter.screenshot.autocrop !== false) {
122+
if (frontMatter.screenshot.autocrop) {
127123
screenshot.autocrop(false);
128124
}
129125
// Allow shrinking, up to a point
130-
const scaleHeight = screenshot.bitmap.height <= options.screenshotTargetMinHeight
131-
? 0.0 : options.screenshotTargetMinHeight / screenshot.bitmap.height;
132-
const scaleWidth = screenshot.bitmap.width <= options.screenshotTargetMinWidth
133-
? 0.0 : options.screenshotTargetMinWidth / screenshot.bitmap.width;
126+
const scaleHeight = screenshot.bitmap.height <= options.screenshot.targetMinHeight
127+
? 0.0 : options.screenshot.targetMinHeight / screenshot.bitmap.height;
128+
const scaleWidth = screenshot.bitmap.width <= options.screenshot.targetMinWidth
129+
? 0.0 : options.screenshot.targetMinWidth / screenshot.bitmap.width;
134130
const scale = Math.max(scaleHeight, scaleWidth);
135131
screenshot
136132
.scale(scale > 0 ? scale : 1.0)
@@ -142,7 +138,7 @@ module.exports = _options => new Promise((resolve, reject) => {
142138
// Optimize
143139
imagemin([tmpJpegPath], screenshotDir, {
144140
plugins: [
145-
imageminMozjpeg({ quality: options.mozjpegQuality }),
141+
imageminMozjpeg({ quality: options.screenshot.mozjpegQuality }),
146142
// imageminJpegRecompress(), // this guy is useless
147143
// imageminJpegtran(), // this guy is useless
148144
],

src/templates/components.html renamed to src/templates/component.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</head>
88
<body class="w-100 sans-serif <%= bodyClass %>">
99
<main>
10-
<div data-name="component-container">
10+
<div data-name="component">
1111
<%= content %>
1212
</div>
1313
<section data-name="component-info" class="pa3 pa5-ns bt b--black-10 black-70 bg-white">
@@ -64,8 +64,8 @@ <h1 class="f6 b ttu">Other Components</h1>
6464
<% Object.keys(componentsForNav).map(function(category) { %>
6565
<div>
6666
<h2 class="f6 fw6 mb2 ttc black-70"><%= category %></h2>
67-
<% componentsForNav[category].map(function(componentForNav) { %>
68-
<a class="f6 f5-ns fw4 dib mr3 mb2 black-70 link hover-blue" href="<%= componentForNav.href %>"><%= componentForNav.name %></a>
67+
<% componentsForNav[category].map(function(component) { %>
68+
<a class="f6 f5-ns fw4 dib mr3 mb2 black-70 link hover-blue" href="<%= component.href %>"><%= component.name %></a>
6969
<% }) %>
7070
</div>
7171
<% }) %>

src/templates/components-index.html

+12-7
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,22 @@ <h3 class="f5 fw6 pb2 bb b--black-10 black-70 ttc"><%= category %></h3>
3030
</div>
3131
<div class="ph3 ph5-ns mb5">
3232
<div class="mw9 center cf">
33-
<% componentsForNav[category].map(function(componentForNav) { %>
33+
<% componentsForNav[category].map(function(component) {
34+
const frontMatter = _.merge({}, options.components.frontMatter, component.frontMatter);
35+
%>
3436
<a class="db pointer link underline-hover black-70 fl w-50 w-third-m w-25-l pb2 pr2 border-box"
35-
href="<%= componentForNav.href %>"
36-
title="<%= componentForNav.name %>">
37-
<div class="ba b--black-20 aspect-ratio aspect-ratio--<%= options.screenshotAspectRatio %>">
37+
href="<%= component.href %>"
38+
title="<%= component.name %>">
39+
<div class="ba b--black-20 aspect-ratio aspect-ratio--<%= options.screenshot.aspectRatio %>">
3840
<div class="aspect-ratio--object lazyload"
39-
data-bg="<%= componentForNav.screenshot.href %>"
40-
style="background-repeat: no-repeat; background-position: <%= componentForNav.frontMatter.screenshot && componentForNav.frontMatter.screenshot['background-position'] || 'center center' %>; background-size: <%= componentForNav.frontMatter.screenshot && componentForNav.frontMatter.screenshot['background-size'] || 'cover' %>;"></div>
41+
data-bg="<%= component.screenshot.href %>"
42+
style="background-repeat: no-repeat;
43+
background-position: <%= frontMatter.screenshot['background-position'] %>;
44+
background-size: <%= frontMatter.screenshot['background-size'] %>;">
45+
</div>
4146
</div>
4247
<p class="f6 truncate">
43-
<%= componentForNav.name %>
48+
<%= component.name %>
4449
</p>
4550
</a>
4651
<% }) %>

0 commit comments

Comments
 (0)