diff --git a/.gitignore b/.gitignore
index e034826124..867eaccf94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,7 +64,9 @@ config.js
# Built asset files
/core/built
/core/client/assets/css
+/core/client/assets/img/contributors/
/core/client/docs/dist/css
+/core/client/templates/-contributors.hbs
# Coverage reports
coverage.html
diff --git a/Gruntfile.js b/Gruntfile.js
index 22b1293ddd..98f1365ce4 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -5,10 +5,14 @@
// **Usage instructions:** can be found in the [Custom Tasks](#custom%20tasks) section or by running `grunt --help`.
//
// **Debug tip:** If you have any problems with any Grunt tasks, try running them with the `--verbose` command
-var path = require('path'),
+var _ = require('lodash'),
colors = require('colors'),
- fs = require('fs'),
- _ = require('lodash'),
+ fs = require('fs-extra'),
+ getTopContribs = require('top-gh-contribs'),
+ path = require('path'),
+ Promise = require('bluebird'),
+ request = require('request'),
+
escapeChar = process.platform.match(/^win/) ? '^' : '\\',
cwd = process.cwd().replace(/( |\(|\))/g, escapeChar + '$1'),
buildDirectory = path.resolve(cwd, '.build'),
@@ -852,18 +856,67 @@ var path = require('path'),
// ### Ember Build *(Utility Task)*
// All tasks related to building the Ember client code including transpiling ES6 modules and building templates
grunt.registerTask('emberBuildDev', 'Build Ember JS & templates for development',
- ['clean:tmp', 'emberTemplates:dev', 'transpile', 'concat_sourcemap:dev']);
+ ['clean:tmp', 'buildAboutPage', 'emberTemplates:dev', 'transpile', 'concat_sourcemap:dev']);
// ### Ember Build *(Utility Task)*
// All tasks related to building the Ember client code including transpiling ES6 modules and building templates
grunt.registerTask('emberBuildProd', 'Build Ember JS & templates for production',
- ['clean:tmp', 'emberTemplates:prod', 'transpile', 'concat_sourcemap:prod']);
+ ['clean:tmp', 'buildAboutPage', 'emberTemplates:prod', 'transpile', 'concat_sourcemap:prod']);
// ### CSS Build *(Utility Task)*
// Build the CSS files from the SCSS files
grunt.registerTask('css', 'Build Client CSS',
['sass', 'autoprefixer']);
+ // ### Build About Page *(Utility Task)*
+ // Builds the github contributors partial template used on the Settings/About page,
+ // and downloads the avatar for each of the users.
+ // Run by any task that compiles the ember assets (emberBuildDev, emberBuildProd)
+ // or manually via `grunt buildAboutPage`.
+ // Change which version you're working against by setting the "releaseTag" below.
+ grunt.registerTask('buildAboutPage', 'Compile assets for the About Ghost page', function () {
+ var done = this.async();
+
+ grunt.verbose.writeln('Downloading release and contributor information from GitHub');
+ getTopContribs({
+ user: 'tryghost',
+ repo: 'ghost',
+ releaseTag: '0.4.2',
+ count: 20
+ }).then(function makeContributorTemplate(contributors) {
+ var contributorTemplate = '
\n\t\n' +
+ '\t\t\n' +
+ '\t\n';
+
+ grunt.verbose.writeln('Creating contributors template.');
+ grunt.file.write('core/client/templates/-contributors.hbs',
+ //Map contributors to the template.
+ _.map(contributors, function (contributor) {
+ return contributorTemplate
+ .replace(/<%githubUrl%>/g, contributor.githubUrl)
+ .replace(/<%name%>/g, contributor.name);
+ }).join('\n')
+ );
+ grunt.verbose.writeln('Downloading images for top contributors');
+ return Promise.promisify(fs.mkdirs)('core/client/assets/img/contributors').then(function () {
+ return contributors;
+ });
+ }).then(function downloadContributorImages(contributors) {
+ var downloadImagePromise = function (url, name) {
+ return new Promise(function (resolve, reject) {
+ request(url)
+ .pipe(fs.createWriteStream('core/client/assets/img/contributors/' + name))
+ .on('close', resolve)
+ .on('error', reject);
+ });
+ };
+ return Promise.all(_.map(contributors, function (contributor) {
+ return downloadImagePromise(contributor.avatarUrl, contributor.name);
+ }));
+ }).catch(function (error) {
+ grunt.log.error(error);
+ }).finally(done);
+ });
// ### Init assets
// `grunt init` - will run an initial asset build for you
//
diff --git a/core/client/router.js b/core/client/router.js
index f4ad652c00..741a263843 100644
--- a/core/client/router.js
+++ b/core/client/router.js
@@ -33,6 +33,7 @@ Router.map(function () {
this.resource('settings.users', { path: '/users' }, function () {
this.route('user', { path: '/:slug' });
});
+ this.route('about');
});
this.route('debug');
//Redirect legacy content to posts
diff --git a/core/client/routes/settings/about.js b/core/client/routes/settings/about.js
new file mode 100644
index 0000000000..64222d0bb6
--- /dev/null
+++ b/core/client/routes/settings/about.js
@@ -0,0 +1,25 @@
+import loadingIndicator from 'ghost/mixins/loading-indicator';
+
+var SettingsAboutRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, loadingIndicator, {
+ cachedConfig: false,
+ model: function () {
+ var cachedConfig = this.get('cachedConfig'),
+ self = this;
+ if (cachedConfig) {
+ return cachedConfig;
+ }
+
+ return ic.ajax.request(this.get('ghostPaths.url').api('configuration'))
+ .then(function (configurationResponse) {
+ var configKeyValues = configurationResponse.configuration;
+ cachedConfig = {};
+ configKeyValues.forEach(function (configKeyValue) {
+ cachedConfig[configKeyValue.key] = configKeyValue.value;
+ });
+ self.set('cachedConfig', cachedConfig);
+ return cachedConfig;
+ });
+ }
+});
+
+export default SettingsAboutRoute;
diff --git a/core/client/templates/settings.hbs b/core/client/templates/settings.hbs
index 238a7095cb..562d692ca5 100644
--- a/core/client/templates/settings.hbs
+++ b/core/client/templates/settings.hbs
@@ -14,6 +14,8 @@
{{gh-activating-list-item route="settings.users" title="Users" classNames="settings-menu-users"}}
{{/unless}}
+
+ {{gh-activating-list-item route="settings.about" title="About" classNames="settings-menu-about"}}
diff --git a/core/client/templates/settings/about.hbs b/core/client/templates/settings/about.hbs
new file mode 100644
index 0000000000..50578f6f24
--- /dev/null
+++ b/core/client/templates/settings/about.hbs
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+ Ghost
+
+ v{{version}}
+
+ A free, open, simple publishing platform
+
+
+
+
+ - Version:
+ - {{version}}
+ - Environment:
+ - {{environment}}
+ - Database:
+ - {{database}}
+ - Mail:
+ - {{#if mail}}{{mail}}{{else}}Native{{/if}}
+
+
+
+
+
+
+
+ The People Who Made it Possible
+
+
+ {{partial "contributors"}}
+
+
+ Ghost is built by an incredible group of contributors from all over the world. Here are just a few of the people who helped create the version you’re using right now.
+
+ Find out how you can get involved
+
+
+ Copyright 2013 - 2014 Ghost Foundation, released under the MIT license.
+
+ Ghost is a trademark of the Ghost Foundation.
+
+
+
diff --git a/core/client/utils/ghost-paths.js b/core/client/utils/ghost-paths.js
index 0271dfb0a0..2d03c1bf6b 100644
--- a/core/client/utils/ghost-paths.js
+++ b/core/client/utils/ghost-paths.js
@@ -25,7 +25,7 @@ function ghostPaths() {
blogRoot: subdir + '/',
adminRoot: adminRoot,
apiRoot: apiRoot,
- userImage: assetUrl('/assets/img/user-image.png'),
+ contributorsDir: assetUrl('/ghost/img/contributors'),
errorImageSrc: assetUrl('/ghost/img/404-ghost@2x.png'),
errorImageSrcSet: assetUrl('/ghost/img/404-ghost.png') + ' 1x, ' +
assetUrl('/ghost/img/404-ghost@2x.png') + ' 2x',
diff --git a/core/client/views/settings/about.js b/core/client/views/settings/about.js
new file mode 100644
index 0000000000..032be3076e
--- /dev/null
+++ b/core/client/views/settings/about.js
@@ -0,0 +1,5 @@
+import BaseView from 'ghost/views/settings/content-base';
+
+var SettingsAboutView = BaseView.extend();
+
+export default SettingsAboutView;
diff --git a/package.json b/package.json
index 8223f057e1..2ab21679c2 100644
--- a/package.json
+++ b/package.json
@@ -99,6 +99,7 @@
"require-dir": "~0.1.0",
"should": "~2.1.1",
"sinon": "~1.7.3",
- "supertest": "~0.8.2"
+ "supertest": "~0.8.2",
+ "top-gh-contribs": "0.0.1"
}
}