Skip to content

Commit 79889c2

Browse files
committed
First hacking in of Craft Clips for Redactor 😮
1 parent 98d79cf commit 79889c2

File tree

10 files changed

+1286
-23
lines changed

10 files changed

+1286
-23
lines changed

_craftclips/craftclips-component-list.json

Lines changed: 18 additions & 0 deletions
Large diffs are not rendered by default.

build-craftclips.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const chalk = require('chalk');
2+
const co = require('co');
3+
const prettyHrtime = require('pretty-hrtime');
4+
5+
const startTime = process.hrtime();
6+
7+
// require('./src/header-build')()
8+
// require('./src/gallery-build')()
9+
// require('./src/resources-build')()
10+
// console.log('header build complete')
11+
// require('./src/table-of-styles-build')()
12+
// console.log('table of styles build complete')
13+
// require('./src/table-of-properties-build')()
14+
// console.log('table of properties build complete')
15+
// require('./src/home-build')()
16+
// console.log('home build complete')
17+
18+
const componentsBuildCraftClips = require('./src/components-build-craftclips');
19+
// const componentsBuildIndex = require('./src/components-build-index');
20+
// const componentsBuildRSS = require('./src/components-build-rss');
21+
// const componentsBuildPages = require('./src/components-build-pages');
22+
// const componentsBuildScreenshots = require('./src/components-build-screenshots');
23+
24+
// See src/components-build-defaults for list of options that can be overriden
25+
const options = {
26+
components: {
27+
globPattern: 'src/components/pages**/*.html',
28+
// frontMatter: {
29+
// bodyClass: 'bg-red',
30+
// screenshot: {
31+
// autocrop: false,
32+
// },
33+
// },
34+
},
35+
// screenshot: {
36+
// aspectRatio: '16x9',
37+
// },
38+
};
39+
40+
// Note that componentsBuildList() generates a temporary components list (saved as JSON),
41+
// which is re-used by later steps (for performance).
42+
// If you are working on one component, uncomment and set components.GlobPattern
43+
// in the options above to only (re-)generate the list, index, pages, and screenshots for the
44+
// corresponding category. Once you are done, comment components.GlobPattern back, comment
45+
// the line below that generate the screenshots, then run the script -- this will
46+
// re-create the full index pages for all components, re-generate all the pages (since they need
47+
// to cross-reference the new component), and use the previously generated screenshots as well
48+
// as the new one (i.e. no need to re-generate *all* the screenshots unless you made
49+
// modifications to the screenshots script itself).
50+
co(function* generator() {
51+
yield componentsBuildCraftClips(options); // <- builds config file for the Redactor Clips plugin for Craft CMS
52+
}).then(() => {
53+
const elapsed = process.hrtime(startTime);
54+
console.log(chalk.green('All done'), chalk.dim(prettyHrtime(elapsed)));
55+
}).catch((err) => {
56+
console.log(err);
57+
});

build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const componentsBuildScreenshots = require('./src/components-build-screenshots')
2424
// See src/components-build-defaults for list of options that can be overriden
2525
const options = {
2626
components: {
27-
// globPattern: 'src/components/article**/*.html',
27+
globPattern: 'src/components/pages**/*.html',
2828
// frontMatter: {
2929
// bodyClass: 'bg-red',
3030
// screenshot: {

css/tachyons.css

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -918,11 +918,11 @@ code, .code { font-family: Consolas, monaco, monospace; }
918918
Docs: http://tachyons.io/docs/elements/links/
919919
920920
*/
921-
.link { text-decoration: none; -webkit-transition: color .15s ease-in; transition: color .15s ease-in; }
922-
.link:link, .link:visited { -webkit-transition: color .15s ease-in; transition: color .15s ease-in; }
923-
.link:hover { -webkit-transition: color .15s ease-in; transition: color .15s ease-in; }
924-
.link:active { -webkit-transition: color .15s ease-in; transition: color .15s ease-in; }
925-
.link:focus { -webkit-transition: color .15s ease-in; transition: color .15s ease-in; outline: 1px dotted currentColor; }
921+
.link { text-decoration: none; transition: color .15s ease-in; }
922+
.link:link, .link:visited { transition: color .15s ease-in; }
923+
.link:hover { transition: color .15s ease-in; }
924+
.link:active { transition: color .15s ease-in; }
925+
.link:focus { transition: color .15s ease-in; outline: 1px dotted currentColor; }
926926
/*
927927
928928
LISTS
@@ -1881,16 +1881,16 @@ code, .code { font-family: Consolas, monaco, monospace; }
18811881
Dim element on hover by adding the dim class.
18821882
18831883
*/
1884-
.dim { opacity: 1; -webkit-transition: opacity .15s ease-in; transition: opacity .15s ease-in; }
1885-
.dim:hover, .dim:focus { opacity: .5; -webkit-transition: opacity .15s ease-in; transition: opacity .15s ease-in; }
1886-
.dim:active { opacity: .8; -webkit-transition: opacity .15s ease-out; transition: opacity .15s ease-out; }
1884+
.dim { opacity: 1; transition: opacity .15s ease-in; }
1885+
.dim:hover, .dim:focus { opacity: .5; transition: opacity .15s ease-in; }
1886+
.dim:active { opacity: .8; transition: opacity .15s ease-out; }
18871887
/*
18881888
18891889
Animate opacity to 100% on hover by adding the glow class.
18901890
18911891
*/
1892-
.glow { -webkit-transition: opacity .15s ease-in; transition: opacity .15s ease-in; }
1893-
.glow:hover, .glow:focus { opacity: 1; -webkit-transition: opacity .15s ease-in; transition: opacity .15s ease-in; }
1892+
.glow { transition: opacity .15s ease-in; }
1893+
.glow:hover, .glow:focus { opacity: 1; transition: opacity .15s ease-in; }
18941894
/*
18951895
18961896
Hide child & reveal on hover:
@@ -1905,15 +1905,15 @@ code, .code { font-family: Consolas, monaco, monospace; }
19051905
<div class="child"> Hidden until hover or focus </div>
19061906
</div>
19071907
*/
1908-
.hide-child .child { opacity: 0; -webkit-transition: opacity .15s ease-in; transition: opacity .15s ease-in; }
1909-
.hide-child:hover .child, .hide-child:focus .child, .hide-child:active .child { opacity: 1; -webkit-transition: opacity .15s ease-in; transition: opacity .15s ease-in; }
1908+
.hide-child .child { opacity: 0; transition: opacity .15s ease-in; }
1909+
.hide-child:hover .child, .hide-child:focus .child, .hide-child:active .child { opacity: 1; transition: opacity .15s ease-in; }
19101910
.underline-hover:hover, .underline-hover:focus { text-decoration: underline; }
19111911
/* Can combine this with overflow-hidden to make background images grow on hover
19121912
* even if you are using background-size: cover */
1913-
.grow { -moz-osx-font-smoothing: grayscale; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateZ( 0 ); transform: translateZ( 0 ); -webkit-transition: -webkit-transform .25s ease-out; transition: -webkit-transform .25s ease-out; transition: transform .25s ease-out; transition: transform .25s ease-out, -webkit-transform .25s ease-out; }
1913+
.grow { -moz-osx-font-smoothing: grayscale; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateZ( 0 ); transform: translateZ( 0 ); transition: -webkit-transform .25s ease-out; transition: transform .25s ease-out; transition: transform .25s ease-out, -webkit-transform .25s ease-out; }
19141914
.grow:hover, .grow:focus { -webkit-transform: scale( 1.05 ); transform: scale( 1.05 ); }
19151915
.grow:active { -webkit-transform: scale( .90 ); transform: scale( .90 ); }
1916-
.grow-large { -moz-osx-font-smoothing: grayscale; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateZ( 0 ); transform: translateZ( 0 ); -webkit-transition: -webkit-transform .25s ease-in-out; transition: -webkit-transform .25s ease-in-out; transition: transform .25s ease-in-out; transition: transform .25s ease-in-out, -webkit-transform .25s ease-in-out; }
1916+
.grow-large { -moz-osx-font-smoothing: grayscale; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateZ( 0 ); transform: translateZ( 0 ); transition: -webkit-transform .25s ease-in-out; transition: transform .25s ease-in-out; transition: transform .25s ease-in-out, -webkit-transform .25s ease-in-out; }
19171917
.grow-large:hover, .grow-large:focus { -webkit-transform: scale( 1.2 ); transform: scale( 1.2 ); }
19181918
.grow-large:active { -webkit-transform: scale( .95 ); transform: scale( .95 ); }
19191919
/* Add pointer on hover */
@@ -1924,12 +1924,12 @@ code, .code { font-family: Consolas, monaco, monospace; }
19241924
Performant box-shadow animation pattern from
19251925
http://tobiasahlin.com/blog/how-to-animate-box-shadow/
19261926
*/
1927-
.shadow-hover { cursor: pointer; position: relative; -webkit-transition: all .5s cubic-bezier( .165, .84, .44, 1 ); transition: all .5s cubic-bezier( .165, .84, .44, 1 ); }
1928-
.shadow-hover::after { content: ''; box-shadow: 0 0 16px 2px rgba( 0, 0, 0, .2 ); border-radius: inherit; opacity: 0; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; -webkit-transition: opacity .5s cubic-bezier( .165, .84, .44, 1 ); transition: opacity .5s cubic-bezier( .165, .84, .44, 1 ); }
1927+
.shadow-hover { cursor: pointer; position: relative; transition: all .5s cubic-bezier( .165, .84, .44, 1 ); }
1928+
.shadow-hover::after { content: ''; box-shadow: 0 0 16px 2px rgba( 0, 0, 0, .2 ); border-radius: inherit; opacity: 0; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; transition: opacity .5s cubic-bezier( .165, .84, .44, 1 ); }
19291929
.shadow-hover:hover::after, .shadow-hover:focus::after { opacity: 1; }
19301930
/* Combine with classes in skins and skins-pseudo for
19311931
* many different transition possibilities. */
1932-
.bg-animate, .bg-animate:hover, .bg-animate:focus { -webkit-transition: background-color .15s ease-in-out; transition: background-color .15s ease-in-out; }
1932+
.bg-animate, .bg-animate:hover, .bg-animate:focus { transition: background-color .15s ease-in-out; }
19331933
/*
19341934
19351935
Z-INDEX
@@ -1992,9 +1992,9 @@ code, .code { font-family: Consolas, monaco, monospace; }
19921992
.nested-copy-indent p+p { text-indent: 1em; margin-top: 0; margin-bottom: 0; }
19931993
.nested-copy-seperator p+p { margin-top: 1.5em; }
19941994
.nested-img img { width: 100%; max-width: 100%; display: block; }
1995-
.nested-links a { color: #408bc9; -webkit-transition: color .15s ease-in; transition: color .15s ease-in; }
1996-
.nested-links a:hover { color: #76c4e2; -webkit-transition: color .15s ease-in; transition: color .15s ease-in; }
1997-
.nested-links a:focus { color: #76c4e2; -webkit-transition: color .15s ease-in; transition: color .15s ease-in; }
1995+
.nested-links a { color: #408bc9; transition: color .15s ease-in; }
1996+
.nested-links a:hover { color: #76c4e2; transition: color .15s ease-in; }
1997+
.nested-links a:focus { color: #76c4e2; transition: color .15s ease-in; }
19981998
/*
19991999
20002000
STYLES

css/tachyons.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"start": "npm run css && node build.js",
88
"css": "tachyons src/css/tachyons.css > css/tachyons.css && tachyons src/css/tachyons.css --minify > css/tachyons.min.css",
99
"components:watch": "watch 'node build.js' src/components/*",
10+
"components:craftclips": "watch 'node build-craftclips.js' src/components/*",
1011
"home:watch": "watch 'node build-home.js' src/templates/",
1112
"gallery:watch": "watch 'node build' src/templates/",
1213
"build:watch": "watch 'node build.js' src/templates/",

src/components-build-craftclips.js

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
const _ = require('lodash');
2+
const chalk = require('chalk');
3+
const co = require('co');
4+
const crypto = require('crypto');
5+
const fm = require('json-front-matter');
6+
const fs = require('fs');
7+
const glob = require('glob');
8+
const mkdirp = require('mkdirp');
9+
const nodegit = require('nodegit');
10+
const path = require('path');
11+
const prettyHrtime = require('pretty-hrtime');
12+
const rmHtmlExt = require('remove-html-extension');
13+
14+
const defaults = require('./components-build-defaults');
15+
16+
/*
17+
* Return the first commit that even introduced a component, given its path
18+
*/
19+
const getComponentFirstCommit = (repo, componentPath) =>
20+
co(function* generator() {
21+
const headCommit = yield repo.getHeadCommit();
22+
const walker = repo.createRevWalk();
23+
walker.push(headCommit.id());
24+
walker.sorting(nodegit.Revwalk.SORT.TIME);
25+
// Not happy about that hard-coded constant here, but this is the only way to
26+
// tell the walker to go as far back in time as possible. No amount of asking
27+
// on nodegit's Slack or Gitter gave me a better way to do it.
28+
const historyCommits = yield walker.fileHistoryWalk(componentPath, 30000);
29+
return historyCommits[historyCommits.length - 1].commit;
30+
});
31+
32+
/*
33+
* Return the list of components
34+
*/
35+
const getComponents = options => new Promise((resolve, reject) => {
36+
glob(options.components.globPattern, {}, (err, componentPaths) => {
37+
if (err) {
38+
reject(err);
39+
return;
40+
}
41+
const npmPackage = JSON.parse(fs.readFileSync('package.json', 'utf8'));
42+
co(function* generator() {
43+
const repo = yield nodegit.Repository.open(path.resolve('.'));
44+
45+
const components = [];
46+
for (let comp_idx = 0; comp_idx < componentPaths.length; comp_idx += 1) {
47+
const componentPath = componentPaths[comp_idx];
48+
49+
const firstCommit = yield getComponentFirstCommit(repo, componentPath);
50+
51+
const componentHtml = fs.readFileSync(componentPath, 'utf8');
52+
const fmParsed = fm.parse(componentHtml);
53+
const srcFrontMatter = fmParsed.attributes || {};
54+
const frontMatter = _.merge({}, options.components.frontMatter, srcFrontMatter);
55+
56+
const targetDir = componentPath.replace('src/', '').replace('.html', '');
57+
58+
const tokens = rmHtmlExt(componentPath).replace('src/components/', '').split('/');
59+
const category = tokens[0];
60+
const id = tokens[1];
61+
62+
// Compute component signature based on the Tachyons version and the contents of the
63+
// component itself. This can be used to bust the browser cache of screenshots.
64+
const md5sum = crypto.createHash('md5');
65+
md5sum.update(npmPackage.version);
66+
md5sum.update(componentHtml);
67+
const signature = md5sum.digest('hex');
68+
69+
const page = {
70+
path: `${targetDir}/index.html`,
71+
href: `/${targetDir}/index.html`,
72+
name: frontMatter.name ||
73+
(options.components.prettify.id ? options.components.prettify.id(id) : id),
74+
category: options.components.prettify.category
75+
? options.components.prettify.category(category) : category,
76+
};
77+
page.title = frontMatter.title ||
78+
options.components.page.composeTitle(page.category, page.name);
79+
80+
81+
page.href
82+
83+
// const screenshot = {
84+
// path: `${targetDir}/${options.screenshot.basename}`,
85+
// href: `/${targetDir}/${options.screenshot.basename}?version=${signature}`,
86+
// };
87+
88+
components.push({
89+
id,
90+
// category,
91+
src: componentHtml,
92+
// creationTime: firstCommit.date().getTime(),
93+
// author: firstCommit.author().toString(),
94+
// signature,
95+
// page,
96+
// screenshot,
97+
// This is the raw front matter, as found in the component source, NOT merged
98+
// with any defaults, so that it is easier to spot the overrides.
99+
// It is up to build scripts to merge with options.components.frontMatter down the road.
100+
// frontMatter: srcFrontMatter,
101+
});
102+
}
103+
resolve(components);
104+
}); // generator
105+
}); // glob
106+
});
107+
108+
module.exports = _options => new Promise((resolve, reject) => {
109+
const options = _.merge({}, defaults, _options);
110+
const startTime = process.hrtime();
111+
console.log(chalk.magenta('Working on components config for Craft CMS / Redactor Clips plugin...'));
112+
getComponents(options).then((components) => {
113+
mkdirp.sync(path.dirname(options.components.tempListPath));
114+
fs.writeFileSync(options.components.tempListPath, JSON.stringify(components, undefined, 2));
115+
console.log('- Working on components config for Craft CMS / Redactor Clips plugin:', options.components.tempListPath);
116+
const elapsed = process.hrtime(startTime);
117+
console.log(chalk.magenta('Done with Redactor Clips component config file!'), chalk.dim(prettyHrtime(elapsed)));
118+
}).then(resolve).catch(reject);
119+
}); // return promise

src/components-build-defaults.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module.exports = {
1010
// Components
1111
components: {
1212
globPattern: 'src/components/**/*.html', // source components to process
13-
tempListPath: 'tmp/components.json', // temporary JSON file built by the index
13+
tempListPath: '_craftclips/craftclips-component-list.json', // temporary JSON file built by the index
1414
build: {
1515
pages: true, // false to skip building pages
1616
screenshots: true, // false to skip building screenshots

src/modules/nodegit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit beaa78d09798332984c729f001990a82670178fb

0 commit comments

Comments
 (0)