diff --git a/.gitignore b/.gitignore index d25210f28..ec2b069a7 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ Thumbs.db nbproject *.sublime-project *.sublime-workspace +.build* diff --git a/README.md b/README.md index 496e7eddc..c97d6f521 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,14 @@ gulp help // list all commands For more detail into how work with Semantic when building a site please [read out customization guide](http://learnsemantic.com/developing/customizing.html) on [LearnSemantic.com](http://learnsemantic.com/) +## Meteor + +To use Semantic with the [Meteor.js](https://www.meteor.com) framework, run + +$ meteor add semantic:ui + +Learn more by reading the [Meteor integration README](https://github.com/Semantic-Org/Semantic-UI/blob/master/meteor/README.md). + ## Browser Support @@ -97,4 +105,3 @@ When adding pull requests be sure to merge into [next](https://github.com/Semant If you'd like to start a conversation about Semantic feel free to reach out by e-mail [jack@semantic-ui.com](mailto:jack@semantic-ui.com) [![Flattr This](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=jlukic&url=https%3A%2F%2Fgithub.com%2Fjlukic%2FSemantic-UI) - diff --git a/gulpfile.js b/gulpfile.js index ba3f33b45..10a968a9f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -26,6 +26,7 @@ var clone = require('gulp-clone'), concat = require('gulp-concat'), concatCSS = require('gulp-concat-css'), + concatFnames = require('gulp-concat-filenames'), copy = require('gulp-copy'), debug = require('gulp-debug'), flatten = require('gulp-flatten'), @@ -42,6 +43,7 @@ var replace = require('gulp-replace'), rtlcss = require('gulp-rtlcss'), sourcemaps = require('gulp-sourcemaps'), + tap = require('gulp-tap'), uglify = require('gulp-uglify'), util = require('gulp-util'), watch = require('gulp-watch'), @@ -424,6 +426,32 @@ gulp.task('build', 'Builds all files from source', function(callback) { }) ; + // updates package.js + console.info('Updating package.js (Meteor)'); + var + assetPath = output.themes + 'default/assets/', + fnames = + ' \'' + output.packaged + 'semantic.css\',\n' + + ' \'' + output.packaged + 'semantic.js\',\n' + ; + gulp.src(assetPath + '**', {base: assetPath}) + .pipe(concatFnames("dummy.txt", { + newline: '', + root: './', + prepend: ' \'', + append: '\',' + })) + .pipe(tap(function(file) { fnames += file.contents; })) + .on('end', function() { + gulp.src(release.templates.meteor) + .pipe(plumber()) + .pipe(flatten()) + .pipe(replace('{package-version}', version)) + .pipe(replace('{package-files}', fnames)) + .pipe(gulp.dest('./')) + ; + }) + ; }); // cleans distribution files @@ -846,7 +874,6 @@ gulp.task('install', 'Set-up project for first time', function () { ; } - // determine semantic.json config if(answers.components) { json.components = answers.components; @@ -900,6 +927,35 @@ gulp.task('install', 'Set-up project for first time', function () { .pipe(gulp.dest('./')) ; } + + // writes package.js + console.info('Creating package.js (Meteor)'); + var + packagedFolder = json.paths.output.packaged || output.packaged, + themesFolder = json.paths.output.themes || output.themes, + fnames = + ' \'' + packagedFolder + 'semantic.css\',\n' + + ' \'' + packagedFolder + 'semantic.js\',\n' + ; + gulp.src(themesFolder + 'default/assets/**') + .pipe(concatFnames("dummy.txt", { + newline: '', + root: './', + prepend: ' \'', + append: '\',' + })) + .pipe(tap(function(file) { fnames += file.contents; })) + .on('end', function() { + gulp.src(release.templates.meteor) + .pipe(plumber()) + .pipe(flatten()) + .pipe(replace('{package-version}', version)) + .pipe(replace('{package-files}', fnames)) + .pipe(gulp.dest('./')) + ; + }) + ; + console.log(''); console.log(''); })) @@ -1050,7 +1106,10 @@ gulp.task('create repos', false, function(callback) { formExport : /\$\.fn\.\w+\s*=\s*function\(fields, parameters\)\s*{/g, settingsExport : /\$\.fn\.\w+\.settings\s*=/g, settingsReference : /\$\.fn\.\w+\.settings/g, - jQuery : /jQuery/g + jQuery : /jQuery/g, + // meteor + mversion : '{package-version}', + mfiles : '{package-files}', }, replace : { // readme @@ -1067,7 +1126,9 @@ gulp.task('create repos', false, function(callback) { formExport : 'module.exports = function(fields, parameters) {\n var _module = module;\n', settingsExport : 'module.exports.settings =', settingsReference : '_module.exports.settings', - jQuery : 'require("jquery")' + jQuery : 'require("jquery")', + // meteor + mversion : version } }, task = { @@ -1075,11 +1136,11 @@ gulp.task('create repos', false, function(callback) { repo : component + ' create repo', bower : component + ' create bower.json', readme : component + ' create README', - readme : component + ' create README', npm : component + ' create NPM Module', notes : component + ' create release notes', composer : component + ' create composer.json', - package : component + ' create package.json' + package : component + ' create package.json', + meteor : component + ' create package.js', } ; @@ -1227,6 +1288,41 @@ gulp.task('create repos', false, function(callback) { ; }); + // Meteor stuff + + // Creates Meteor package.js + // Tries to list assets to be added among the files list + // inside the package.js file for Meteor + gulp.task(task.meteor, function() { + var fnames = ''; + if(isJavascript) + fnames += ' \'' + component + '.js\',\n'; + if(isCSS) + fnames += ' \'' + component + '.css\',\n'; + return gulp.src(outputDirectory + '/assets/**', { base: outputDirectory}) + .pipe(concatFnames("dummy.txt", { + newline: '', + root: outputDirectory, + prepend: ' \'', + append: '\',' + })) + .pipe(tap(function(file) { fnames += file.contents;})) + .on('end', function(){ + gulp.src(release.templates.meteorComponent) + .pipe(plumber()) + .pipe(flatten()) + .pipe(replace(regExp.match.name, regExp.replace.name)) + .pipe(replace(regExp.match.titleName, regExp.replace.titleName)) + .pipe(replace(regExp.match.mversion, regExp.replace.mversion)) + .pipe(replace(regExp.match.mfiles, fnames)) + .pipe(rename(defaults.files.npm)) + .pipe(gulp.dest(outputDirectory)) + ; + }) + ; + }); + + // synchronous tasks in orchestrator? I think not gulp.task(task.all, false, function(callback) { runSequence([ @@ -1236,7 +1332,8 @@ gulp.task('create repos', false, function(callback) { task.readme, task.package, task.composer, - task.notes + task.notes, + task.meteor ], callback); }); @@ -1246,8 +1343,8 @@ gulp.task('create repos', false, function(callback) { } runSequence(tasks, callback); - }); + gulp.task('register repos', false, function(callback) { var index = -1, @@ -1288,7 +1385,7 @@ gulp.task('register repos', false, function(callback) { stepRepo(); }); */ - } + }; stepRepo(); }); @@ -1318,7 +1415,7 @@ gulp.task('update git', false, function() { repoURL = 'https://github.com/' + release.org + '/' + repoName + '/', gitOptions = { cwd: outputDirectory }, quietOptions = { args: '-q', cwd: outputDirectory }, - isRepository = fs.existsSync(outputDirectory + '.git/') + isRepository = fs.existsSync(outputDirectory + '.git/'), componentPackage = fs.existsSync(outputDirectory + 'package.json' ) ? require(outputDirectory + 'package.json') : false, @@ -1368,7 +1465,7 @@ gulp.task('update git', false, function() { mergeCommit(); } }); - }; + } function mergeCommit() { // commit files console.log('Adding merge commit', commitArgs); @@ -1403,7 +1500,7 @@ gulp.task('update git', false, function() { console.log('Push completed successfully'); stepRepo(); }); - }; + } // set-up path function createRepo() { @@ -1447,8 +1544,7 @@ gulp.task('update git', false, function() { stepRepo(); } }); - }; - + } }; return stepRepo(); diff --git a/meteor/README.md b/meteor/README.md new file mode 100644 index 000000000..c4f742e73 --- /dev/null +++ b/meteor/README.md @@ -0,0 +1,38 @@ +[Semantic-UI](http://semantic-ui.com/) packaged for [Meteor.js](http://meteor.com). + +# Usage + +```sh +meteor add semantic:ui +``` + +# Theming + +In case you wish to build your own theme you should follow the +[Recommended Usage (Themed)](https://github.com/Semantic-Org/Semantic-UI#recommended-usage-themed) +guide. + +After having build the project you'll get a ready to use meteor package +shipping your newly created theme. +Simply move the whole folder (or otherwise simlink it...) under your Meteor +app's `packages` folder run + +```sh +meteor add semantic:ui +``` + +from your app's main folder and that's it! + + +# Issues + +If you encounter a Meteor-related issue while using this package, +please CC @Semantic-Org/meteor when you +[file it](https://github.com/Semantic-Org/Semantic-UI/issues). + + +# Meteor + +If you're new to Meteor, here's what the excitement is all about - [watch the first two minutes](https://www.youtube.com/watch?v=fsi0aJ9yr2o); you'll be hooked by 1:28. + +That screencast is from 2012. In the meantime, Meteor has become a mature JavaScript-everywhere web development framework with numerous [advantages](http://www.meteorpedia.com/read/Why_Meteor) over all other single-page application frameworks. diff --git a/meteor/tests/test_fonts.js b/meteor/tests/test_fonts.js new file mode 100644 index 000000000..40c208162 --- /dev/null +++ b/meteor/tests/test_fonts.js @@ -0,0 +1,14 @@ +// Check that the font files are downloadable. Meteor places assets at /packages//. +['eot', 'otf', 'svg', 'ttf', 'woff'].forEach(function (ext) { + Tinytest.addAsync(ext + ' fonts are shipped', function (test, done) { + HTTP.get('/packages/semantic_ui/dist/themes/default/assets/fonts/icons.' + ext, function callback(error, result) { + if (error) { + test.fail({message: 'Font failed to load'}); + } else { + test.isTrue(result.content.length > 10000, ext + ' font could not be downloaded'); + } + + done(); + }); + }); +}); \ No newline at end of file diff --git a/meteor/tests/test_images.js b/meteor/tests/test_images.js new file mode 100644 index 000000000..0b87a8e5f --- /dev/null +++ b/meteor/tests/test_images.js @@ -0,0 +1,20 @@ +var images = [ + 'dist/themes/default/assets/images/flags.png', +]; + +// Check that the font files are downloadable. Meteor places assets at /packages//. +images.forEach(function (path) { + Tinytest.addAsync('image ' + path + ' is shipped', function (test, done) { + HTTP.get('/packages/semantic_ui/' + path, function callback(error, result) { + if (error) { + test.fail({message: 'Image failed to load'}); + } else { + test.isTrue(result.content.length > 10000, 'Image ' + path + ' could not be downloaded'); + } + + done(); + }); + }); +}); + + diff --git a/package.js b/package.js new file mode 100644 index 000000000..4aaf8c407 --- /dev/null +++ b/package.js @@ -0,0 +1,37 @@ +Package.describe({ + name: 'semantic:ui', + summary: 'Semantic (official): a UI component framework based around useful principles from natural language.', + version: '1.7.0', + git: 'git://github.com/Semantic-Org/Semantic-UI.git', + readme: 'https://github.com/Semantic-Org/Semantic-UI/blob/master/meteor/README.md' +}); + +var where = 'client'; // Adds files only to the client + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.addFiles([ + 'dist/semantic.css', + 'dist/semantic.js', + 'dist/themes/default/assets/fonts/icons.eot', + 'dist/themes/default/assets/fonts/icons.otf', + 'dist/themes/default/assets/fonts/icons.svg', + 'dist/themes/default/assets/fonts/icons.ttf', + 'dist/themes/default/assets/fonts/icons.woff', + 'dist/themes/default/assets/images/flags.png', + ], where); +}); + +Package.onTest(function(api) { + api.use([ + 'tinytest', + 'http', + 'semantic:ui' + ], where); + + api.addFiles([ + 'meteor/tests/test_fonts.js', + 'meteor/tests/test_images.js', + ], where); +}); diff --git a/package.json b/package.json index d2ff68a73..50d043795 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "gulp-clone": "^1.0.0", "gulp-concat": "^2.4.2", "gulp-concat-css": "^1.1.1", + "gulp-concat-filenames": "^0.0.3", "gulp-copy": "0.0.2", "gulp-csscomb": "^3.0.3", "gulp-debug": "^1.0.1", @@ -50,6 +51,7 @@ "gulp-replace": "^0.5.0", "gulp-rtlcss": "^0.1.2", "gulp-sourcemaps": "^1.2.8", + "gulp-tap": "^0.1.3", "gulp-uglify": "^1.0.1", "gulp-util": "^3.0.1", "gulp-watch": "^2.0.0", diff --git a/tasks/admin/release.js b/tasks/admin/release.js index 35446c5be..4d685e09e 100644 --- a/tasks/admin/release.js +++ b/tasks/admin/release.js @@ -15,11 +15,13 @@ module.exports = { }, templates: { - bower : './tasks/admin/templates/bower.json', - composer : './tasks/admin/templates/composer.json', - package : './tasks/admin/templates/package.json', - readme : './tasks/admin/templates/README.md', - notes : './RELEASE-NOTES.md' + bower : './tasks/admin/templates/bower.json', + composer : './tasks/admin/templates/composer.json', + package : './tasks/admin/templates/package.json', + meteor : './tasks/admin/templates/package.js', + meteorComponent : './tasks/admin/templates/package-component.js', + readme : './tasks/admin/templates/README.md', + notes : './RELEASE-NOTES.md' }, org : 'Semantic-Org', @@ -82,4 +84,3 @@ module.exports = { 'video' ] }; - diff --git a/tasks/admin/templates/README.md b/tasks/admin/templates/README.md index 38bcaf439..c3ee5b308 100644 --- a/tasks/admin/templates/README.md +++ b/tasks/admin/templates/README.md @@ -16,6 +16,12 @@ bower install semantic-ui-{component} npm install semantic-ui-{component} ``` +#### To install with Meteor +``` +meteor add semantic:ui-{component} +``` + + ## Addendum This element's definitions (required class names, html structures) are available in the [UI Docs](http://www.semantic-ui.com) diff --git a/tasks/admin/templates/package-component.js b/tasks/admin/templates/package-component.js new file mode 100644 index 000000000..63911e850 --- /dev/null +++ b/tasks/admin/templates/package-component.js @@ -0,0 +1,15 @@ +Package.describe({ + name: 'semantic:ui-{component}', + summary: 'Semantic UI - {Component} (official): Single component release of {component}', + version: '{package-version}', + git: 'git://github.com/Semantic-Org/UI-{Component}.git', +}); + +var where = 'client'; // Adds files only to the client + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.addFiles([ +{package-files} ], where); +}); diff --git a/tasks/admin/templates/package.js b/tasks/admin/templates/package.js new file mode 100644 index 000000000..23d20d9e0 --- /dev/null +++ b/tasks/admin/templates/package.js @@ -0,0 +1,29 @@ +Package.describe({ + name: 'semantic:ui', + summary: 'Semantic (official): a UI component framework based around useful principles from natural language.', + version: '{package-version}', + git: 'git://github.com/Semantic-Org/Semantic-UI.git', + readme: 'https://github.com/Semantic-Org/Semantic-UI/blob/master/meteor/README.md' +}); + +var where = 'client'; // Adds files only to the client + +Package.onUse(function(api) { + api.versionsFrom('1.0'); + + api.addFiles([ +{package-files} ], where); +}); + +Package.onTest(function(api) { + api.use([ + 'tinytest', + 'http', + 'semantic:ui' + ], where); + + api.addFiles([ + 'meteor/tests/test_fonts.js', + 'meteor/tests/test_images.js', + ], where); +}); diff --git a/tasks/defaults.js b/tasks/defaults.js index 000b835ef..300ce4be1 100644 --- a/tasks/defaults.js +++ b/tasks/defaults.js @@ -109,6 +109,7 @@ module.exports = { composer : 'composer.json', config : './semantic.json', npm : './package.json', + meteor : './package.js', site : './src/site', theme : './src/theme.config' }, @@ -129,4 +130,4 @@ module.exports = { }, clean : 'dist/' } -}; \ No newline at end of file +};