Update Semantic

Fixes #40,#24
This commit is contained in:
Tim Schumacher 2015-03-29 19:33:23 +02:00
parent 1715f27f44
commit 2027b94179
621 changed files with 172488 additions and 15939 deletions

View file

@ -0,0 +1,17 @@
## Tasks
* Watch - Compile only changed files from source
* Build - Build all files from source
* Version - Output version number
* Install - Run Installer to Set-up Paths
## How to use
These tasks can be imported into your own gulpfile allowing you to avoid using Semantic's build tools
```javascript
var
watch = require('path/to/semantic/tasks/watch')
;
gulp.task('watch ui', 'Watch Semantic UI', watch));
```

View file

@ -0,0 +1,332 @@
/*******************************
Create Component Repos
*******************************/
/*
This will create individual component repositories for each SUI component
* copy component files from release
* create commonjs files as index.js for NPM release
* create release notes that filter only items related to component
* custom package.json file from template
* create bower.json from template
* create README from template
* create meteor.js file
*/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
del = require('del'),
fs = require('fs'),
path = require('path'),
runSequence = require('run-sequence'),
// admin dependencies
concatFileNames = require('gulp-concat-filenames'),
debug = require('gulp-debug'),
flatten = require('gulp-flatten'),
git = require('gulp-git'),
jsonEditor = require('gulp-json-editor'),
plumber = require('gulp-plumber'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
tap = require('gulp-tap'),
util = require('gulp-util'),
// config
config = require('../../config/user'),
release = require('../../config/admin/release'),
project = require('../../config/project/release'),
// shorthand
version = project.version,
output = config.paths.output
;
module.exports = function(callback) {
var
stream,
index,
tasks = []
;
for(index in release.components) {
var
component = release.components[index]
;
// streams... designed to save time and make coding fun...
(function(component) {
var
outputDirectory = path.join(release.outputRoot, component),
isJavascript = fs.existsSync(output.compressed + component + '.js'),
isCSS = fs.existsSync(output.compressed + component + '.css'),
capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
packageName = release.packageRoot + component,
repoName = release.componentRepoRoot + capitalizedComponent,
gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
concatSettings = {
newline : '',
root : outputDirectory,
prepend : " '",
append : "',"
},
regExp = {
match : {
// templated values
name : '{component}',
titleName : '{Component}',
version : '{version}',
files : '{files}',
// release notes
spacedVersions : /(###.*\n)\n+(?=###)/gm,
spacedLists : /(^- .*\n)\n+(?=^-)/gm,
trim : /^\s+|\s+$/g,
unrelatedNotes : new RegExp('^((?!(^.*(' + component + ').*$|###.*)).)*$', 'gmi'),
whitespace : /\n\s*\n\s*\n/gm,
// npm
export : /\$\.fn\.\w+\s*=\s*function\(parameters\)\s*{/g,
formExport : /\$\.fn\.\w+\s*=\s*function\(fields, parameters\)\s*{/g,
settingsExport : /\$\.fn\.\w+\.settings\s*=/g,
settingsReference : /\$\.fn\.\w+\.settings/g,
trailingComma : /,(?=[^,]*$)/,
jQuery : /jQuery/g,
},
replace : {
// readme
name : component,
titleName : capitalizedComponent,
// release notes
spacedVersions : '',
spacedLists : '$1',
trim : '',
unrelatedNotes : '',
whitespace : '\n\n',
// npm
export : 'module.exports = function(parameters) {\n var _module = module;\n',
formExport : 'module.exports = function(fields, parameters) {\n var _module = module;\n',
settingsExport : 'module.exports.settings =',
settingsReference : '_module.exports.settings',
jQuery : 'require("jquery")'
}
},
task = {
all : component + ' creating',
repo : component + ' create repo',
bower : component + ' create bower.json',
readme : component + ' create README',
npm : component + ' create NPM Module',
notes : component + ' create release notes',
composer : component + ' create composer.json',
package : component + ' create package.json',
meteor : component + ' create meteor package.js',
},
// paths to includable assets
manifest = {
assets : outputDirectory + '/assets/**/' + component + '?(s).*',
component : outputDirectory + '/' + component + '+(.js|.css)'
}
;
// copy dist files into output folder adjusting asset paths
gulp.task(task.repo, false, function() {
return gulp.src(release.source + component + '.*')
.pipe(plumber())
.pipe(flatten())
.pipe(replace(release.paths.source, release.paths.output))
.pipe(gulp.dest(outputDirectory))
;
});
// create npm module
gulp.task(task.npm, false, function() {
return gulp.src(release.source + component + '!(*.min|*.map).js')
.pipe(plumber())
.pipe(flatten())
.pipe(replace(regExp.match.export, regExp.replace.export))
.pipe(replace(regExp.match.formExport, regExp.replace.formExport))
.pipe(replace(regExp.match.settingsExport, regExp.replace.settingsExport))
.pipe(replace(regExp.match.settingsReference, regExp.replace.settingsReference))
.pipe(replace(regExp.match.jQuery, regExp.replace.jQuery))
.pipe(rename('index.js'))
.pipe(gulp.dest(outputDirectory))
;
});
// create readme
gulp.task(task.readme, false, function() {
return gulp.src(release.templates.readme)
.pipe(plumber())
.pipe(flatten())
.pipe(replace(regExp.match.name, regExp.replace.name))
.pipe(replace(regExp.match.titleName, regExp.replace.titleName))
.pipe(gulp.dest(outputDirectory))
;
});
// extend bower.json
gulp.task(task.bower, false, function() {
return gulp.src(release.templates.bower)
.pipe(plumber())
.pipe(flatten())
.pipe(jsonEditor(function(bower) {
bower.name = packageName;
bower.description = capitalizedComponent + ' - Semantic UI';
if(isJavascript) {
if(isCSS) {
bower.main = [
component + '.js',
component + '.css'
];
}
else {
bower.main = [
component + '.js'
];
}
bower.dependencies = {
jquery: '>=1.8'
};
}
else {
bower.main = [
component + '.css'
];
}
return bower;
}))
.pipe(gulp.dest(outputDirectory))
;
});
// extend package.json
gulp.task(task.package, false, function() {
return gulp.src(release.templates.package)
.pipe(plumber())
.pipe(flatten())
.pipe(jsonEditor(function(package) {
if(isJavascript) {
package.dependencies = {
jquery: 'x.x.x'
};
package.main = 'index.js';
}
package.name = packageName;
if(version) {
package.version = version;
}
package.title = 'Semantic UI - ' + capitalizedComponent;
package.description = 'Single component release of ' + component;
package.repository = {
type : 'git',
url : gitURL
};
return package;
}))
.pipe(gulp.dest(outputDirectory))
;
});
// extend composer.json
gulp.task(task.composer, false, function() {
return gulp.src(release.templates.composer)
.pipe(plumber())
.pipe(flatten())
.pipe(jsonEditor(function(composer) {
if(isJavascript) {
composer.dependencies = {
jquery: 'x.x.x'
};
composer.main = component + '.js';
}
composer.name = 'semantic/' + component;
if(version) {
composer.version = version;
}
composer.description = 'Single component release of ' + component;
return composer;
}))
.pipe(gulp.dest(outputDirectory))
;
});
// create release notes
gulp.task(task.notes, false, function() {
return gulp.src(release.templates.notes)
.pipe(plumber())
.pipe(flatten())
// Remove release notes for lines not mentioning component
.pipe(replace(regExp.match.unrelatedNotes, regExp.replace.unrelatedNotes))
.pipe(replace(regExp.match.whitespace, regExp.replace.whitespace))
.pipe(replace(regExp.match.spacedVersions, regExp.replace.spacedVersions))
.pipe(replace(regExp.match.spacedLists, regExp.replace.spacedLists))
.pipe(replace(regExp.match.trim, regExp.replace.trim))
.pipe(gulp.dest(outputDirectory))
;
});
// Creates meteor package.js
gulp.task(task.meteor, function() {
var
filenames = ''
;
return gulp.src(manifest.component)
.pipe(concatFileNames('empty.txt', concatSettings))
.pipe(tap(function(file) {
filenames += file.contents;
}))
.on('end', function() {
gulp.src(manifest.assets)
.pipe(concatFileNames('empty.txt', concatSettings))
.pipe(tap(function(file) {
filenames += file.contents;
}))
.on('end', function() {
// remove trailing slash
filenames = filenames.replace(regExp.match.trailingComma, '').trim();
gulp.src(release.templates.meteor.component)
.pipe(plumber())
.pipe(flatten())
.pipe(replace(regExp.match.name, regExp.replace.name))
.pipe(replace(regExp.match.titleName, regExp.replace.titleName))
.pipe(replace(regExp.match.version, version))
.pipe(replace(regExp.match.files, filenames))
.pipe(rename(release.files.meteor))
.pipe(gulp.dest(outputDirectory))
;
})
;
})
;
});
// synchronous tasks in orchestrator? I think not
gulp.task(task.all, false, function(callback) {
runSequence([
task.repo,
task.npm,
task.bower,
task.readme,
task.package,
task.composer,
task.notes,
task.meteor
], callback);
});
tasks.push(task.all);
})(component);
}
runSequence(tasks, callback);
};

View file

@ -0,0 +1,170 @@
/*******************************
Init Repos
*******************************/
/*
This task pulls the latest version of each component from GitHub
* Creates new repo if doesnt exist (locally & GitHub)
* Adds remote it doesnt exists
* Pulls latest changes from repo
*/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
del = require('del'),
fs = require('fs'),
path = require('path'),
git = require('gulp-git'),
githubAPI = require('github'),
mkdirp = require('mkdirp'),
// admin files
github = require('../../config/admin/github.js'),
release = require('../../config/admin/release'),
project = require('../../config/project/release'),
// oAuth configuration for GitHub
oAuth = fs.existsSync(__dirname + '/../../config/admin/oauth.js')
? require('../../config/admin/oauth')
: false,
// shorthand
version = project.version
;
module.exports = function(callback) {
var
index = -1,
total = release.components.length,
timer,
stream,
stepRepo
;
if(!oAuth) {
console.error('Must add oauth token for GitHub in tasks/config/admin/oauth.js');
return;
}
// Do Git commands synchronously per component, to avoid issues
stepRepo = function() {
index = index + 1;
if(index >= total) {
callback();
return;
}
var
component = release.components[index]
outputDirectory = path.resolve(release.outputRoot + component),
capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
repoName = release.componentRepoRoot + capitalizedComponent,
gitOptions = { cwd: outputDirectory },
pullOptions = { args: '-q', cwd: outputDirectory, quiet: true },
resetOptions = { args: '-q --hard', cwd: outputDirectory, quiet: true },
gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
localRepoSetup = fs.existsSync(path.join(outputDirectory, '.git'))
;
console.log('Processing repository: ' + outputDirectory);
// create folder if doesn't exist
if( !fs.existsSync(outputDirectory) ) {
mkdirp.sync(outputDirectory);
}
// clean folder
if(release.outputRoot.search('../repos') == 0) {
console.info('Cleaning dir', outputDirectory);
del.sync([outputDirectory + '**/*'], {silent: true, force: true});
}
// set-up local repo
function setupRepo() {
if(localRepoSetup) {
addRemote();
}
else {
initRepo();
}
}
function initRepo() {
console.info('Initializing repository for ' + component);
git.init(gitOptions, function(error) {
if(error) {
console.error('Error initializing repo', error);
}
addRemote();
});
}
function createRepo() {
console.info('Creating GitHub repo ' + repoURL);
github.repos.createFromOrg({
org : release.org,
name : repoName,
homepage : release.homepage
}, function() {
setupRepo();
});
}
function addRemote() {
console.info('Adding remote origin as ' + gitURL);
git.addRemote('origin', gitURL, gitOptions, function(){
pullFiles();
});
}
function pullFiles() {
console.info('Pulling ' + component + ' files');
git.pull('origin', 'master', pullOptions, function(error) {
resetFiles();
});
}
function resetFiles() {
console.info('Resetting files to head');
git.reset('HEAD', resetOptions, function(error) {
nextRepo();
});
}
function nextRepo() {
//console.log('Sleeping for 1 second...');
// avoid rate throttling
global.clearTimeout(timer);
timer = global.setTimeout(function() {
stepRepo()
}, 0);
}
if(localRepoSetup) {
pullFiles();
}
else {
setupRepo();
// createRepo() only use to create remote repo (easier to do manually)
}
};
stepRepo();
};

View file

@ -0,0 +1,184 @@
/*******************************
Update Repos
*******************************/
/*
This task update all SUI individual component repos with new versions of components
* Commits changes from create repo
* Pushes changes to GitHub
* Tag new releases if version changed in main repo
*/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
fs = require('fs'),
path = require('path'),
git = require('gulp-git'),
githubAPI = require('github'),
requireDotFile = require('require-dot-file'),
// admin files
github = require('../../config/admin/github.js'),
release = require('../../config/admin/release'),
project = require('../../config/project/release'),
// oAuth configuration for GitHub
oAuth = fs.existsSync(__dirname + '/../../config/admin/oauth.js')
? require('../../config/admin/oauth')
: false,
// shorthand
version = project.version
;
module.exports = function(callback) {
var
index = -1,
total = release.components.length,
timer,
stream,
stepRepo
;
if(!oAuth) {
console.error('Must add oauth token for GitHub in tasks/config/admin/oauth.js');
return;
}
// Do Git commands synchronously per component, to avoid issues
stepRepo = function() {
index = index + 1;
if(index >= total) {
callback();
return;
}
var
component = release.components[index],
outputDirectory = path.resolve(path.join(release.outputRoot, component)),
capitalizedComponent = component.charAt(0).toUpperCase() + component.slice(1),
repoName = release.componentRepoRoot + capitalizedComponent,
gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
commitArgs = (oAuth.name !== undefined && oAuth.email !== undefined)
? '--author "' + oAuth.name + ' <' + oAuth.email + '>"'
: '',
componentPackage = fs.existsSync(outputDirectory + 'package.json' )
? require(outputDirectory + 'package.json')
: false,
isNewVersion = (version && componentPackage.version != version),
commitMessage = (isNewVersion)
? 'Updated component to version ' + version
: 'Updated files from main repo',
gitOptions = { cwd: outputDirectory },
commitOptions = { args: commitArgs, cwd: outputDirectory },
releaseOptions = { tag_name: version, owner: release.org, repo: repoName },
fileModeOptions = { args : 'config core.fileMode false', cwd: outputDirectory },
usernameOptions = { args : 'config user.name "' + oAuth.name + '"', cwd: outputDirectory },
emailOptions = { args : 'config user.email "' + oAuth.email + '"', cwd: outputDirectory },
versionOptions = { args : 'rev-parse --verify HEAD', cwd: outputDirectory },
localRepoSetup = fs.existsSync(path.join(outputDirectory, '.git')),
canProceed = true
;
console.info('Processing repository:' + outputDirectory);
function setConfig() {
git.exec(fileModeOptions, function() {
git.exec(usernameOptions, function () {
git.exec(emailOptions, function () {
commitFiles();
});
});
});
}
// standard path
function commitFiles() {
// commit files
console.info('Committing ' + component + ' files', commitArgs);
gulp.src('**/*', gitOptions)
.pipe(git.add(gitOptions))
.pipe(git.commit(commitMessage, commitOptions))
.on('error', function(error) {
// canProceed = false; bug in git commit <https://github.com/stevelacy/gulp-git/issues/49>
})
.on('finish', function(callback) {
if(canProceed) {
pushFiles();
}
else {
console.info('Nothing new to commit');
nextRepo();
}
})
;
}
// push changes to remote
function pushFiles() {
console.info('Pushing files for ' + component);
git.push('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
console.info('Push completed successfully');
getSHA();
});
}
// gets SHA of last commit
function getSHA() {
git.exec(versionOptions, function(error, version) {
version = version.trim();
createRelease(version);
});
}
// create release on GitHub.com
function createRelease(version) {
if(version) {
releaseOptions.target_commitish = version;
}
github.releases.createRelease(releaseOptions, function() {
nextRepo();
});
}
// Steps to next repository
function nextRepo() {
console.log('Sleeping for 1 second...');
// avoid rate throttling
global.clearTimeout(timer);
timer = global.setTimeout(stepRepo, 1000);
}
if(localRepoSetup) {
setConfig();
}
else {
console.error('Repository must be setup before running update components');
}
};
stepRepo();
};

View file

@ -0,0 +1,216 @@
/*******************************
Create Distributions
*******************************/
/*
This will create individual distribution repositories for each SUI distribution
* copy distribution files to release
* update package.json file
*/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
del = require('del'),
fs = require('fs'),
path = require('path'),
runSequence = require('run-sequence'),
mergeStream = require('merge-stream'),
// admin dependencies
concatFileNames = require('gulp-concat-filenames'),
debug = require('gulp-debug'),
flatten = require('gulp-flatten'),
git = require('gulp-git'),
jsonEditor = require('gulp-json-editor'),
plumber = require('gulp-plumber'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
tap = require('gulp-tap'),
// config
config = require('../../config/user'),
release = require('../../config/admin/release'),
project = require('../../config/project/release'),
// shorthand
version = project.version,
output = config.paths.output
;
module.exports = function(callback) {
var
stream,
index,
tasks = []
;
for(index in release.distributions) {
var
distribution = release.distributions[index]
;
// streams... designed to save time and make coding fun...
(function(distribution) {
var
distLowerCase = distribution.toLowerCase(),
outputDirectory = path.join(release.outputRoot, distLowerCase),
packageFile = path.join(outputDirectory, release.files.npm),
repoName = release.distRepoRoot + distribution,
regExp = {
match : {
files : '{files}',
version : '{version}'
}
},
task = {
all : distribution + ' copying files',
repo : distribution + ' create repo',
meteor : distribution + ' create meteor package.js',
package : distribution + ' create package.json'
},
gatherFiles,
createList
;
// get files for meteor
gatherFiles = function(dir) {
var
dir = dir || path.resolve('.'),
list = fs.readdirSync(dir),
omitted = [
'.git',
'node_modules',
'package.js',
'LICENSE',
'README.md',
'package.json',
'bower.json',
'.gitignore'
]
files = []
;
list.forEach(function(file) {
var
isOmitted = (omitted.indexOf(file) > -1),
filePath = path.join(dir, file),
stat = fs.statSync(filePath)
;
if(!isOmitted) {
if(stat && stat.isDirectory()) {
files = files.concat(gatherFiles(filePath));
}
else {
files.push(filePath.replace(outputDirectory + path.sep, ''));
}
}
})
return files
};
// spaces out list correctly
createList = function(files) {
var filenames = '';
for(file in files) {
if(file == (files.length - 1) ) {
filenames += "'" + files[file] + "'";
}
else {
filenames += "'" + files[file] + "',\n ";
}
}
return filenames;
};
gulp.task(task.meteor, function() {
var
files = gatherFiles(outputDirectory)
filenames = createList(files)
;
gulp.src(release.templates.meteor[distLowerCase])
.pipe(plumber())
.pipe(flatten())
.pipe(replace(regExp.match.version, version))
.pipe(replace(regExp.match.files, filenames))
.pipe(rename(release.files.meteor))
.pipe(gulp.dest(outputDirectory))
;
});
if(distribution == 'CSS') {
gulp.task(task.repo, function() {
var
themes,
component,
releases
;
themes = gulp.src('dist/themes/default/**/*', { base: 'dist/' })
.pipe(gulp.dest(outputDirectory))
;
components = gulp.src('dist/components/*', { base: 'dist/' })
.pipe(gulp.dest(outputDirectory))
;
releases = gulp.src('dist/*', { base: 'dist/' })
.pipe(gulp.dest(outputDirectory))
;
return mergeStream(themes, components, releases);
});
}
else if(distribution == 'LESS') {
gulp.task(task.repo, function() {
var
definitions,
themeImport,
themeConfig,
siteTheme,
themes
;
definitions = gulp.src('src/definitions/**/*', { base: 'src/' })
.pipe(gulp.dest(outputDirectory))
;
themeImport = gulp.src('src/theme.less', { base: 'src/' })
.pipe(gulp.dest(outputDirectory))
;
themeConfig = gulp.src('src/theme.config.example', { base: 'src/' })
.pipe(gulp.dest(outputDirectory))
;
siteTheme = gulp.src('src/_site/**/*', { base: 'src/' })
.pipe(gulp.dest(outputDirectory))
;
themes = gulp.src('src/themes/**/*', { base: 'src/' })
.pipe(gulp.dest(outputDirectory))
;
return mergeStream(definitions, themeImport, themeConfig, siteTheme, themes);
});
}
// extend package.json
gulp.task(task.package, function() {
return gulp.src(packageFile)
.pipe(plumber())
.pipe(jsonEditor(function(package) {
if(version) {
package.version = version;
}
return package;
}))
.pipe(gulp.dest(outputDirectory))
;
});
tasks.push(task.meteor);
tasks.push(task.repo);
tasks.push(task.package);
})(distribution);
}
runSequence(tasks, callback);
};

View file

@ -0,0 +1,170 @@
/*******************************
Init Dist Repos
*******************************/
/*
This task pulls the latest version of distribution from GitHub
* Creates new repo if doesnt exist (locally & GitHub)
* Adds remote it doesnt exists
* Pulls latest changes from repo
*/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
del = require('del'),
fs = require('fs'),
path = require('path'),
git = require('gulp-git'),
githubAPI = require('github'),
mkdirp = require('mkdirp'),
// admin files
github = require('../../config/admin/github.js'),
release = require('../../config/admin/release'),
project = require('../../config/project/release'),
// oAuth configuration for GitHub
oAuth = fs.existsSync(__dirname + '/../../config/admin/oauth.js')
? require('../../config/admin/oauth')
: false,
// shorthand
version = project.version
;
module.exports = function(callback) {
var
index = -1,
total = release.distributions.length,
timer,
stream,
stepRepo
;
if(!oAuth) {
console.error('Must add oauth token for GitHub in tasks/config/admin/oauth.js');
return;
}
// Do Git commands synchronously per component, to avoid issues
stepRepo = function() {
index = index + 1;
if(index >= total) {
callback();
return;
}
var
component = release.distributions[index],
lowerCaseComponent = component.toLowerCase(),
outputDirectory = path.resolve(release.outputRoot + lowerCaseComponent),
repoName = release.distRepoRoot + component,
gitOptions = { cwd: outputDirectory },
pullOptions = { args: '-q', cwd: outputDirectory, quiet: true },
resetOptions = { args: '-q --hard', cwd: outputDirectory, quiet: true },
gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
localRepoSetup = fs.existsSync(path.join(outputDirectory, '.git'))
;
console.log('Processing repository: ' + outputDirectory);
// create folder if doesn't exist
if( !fs.existsSync(outputDirectory) ) {
mkdirp.sync(outputDirectory);
}
// clean folder
if(release.outputRoot.search('../repos') == 0) {
console.info('Cleaning dir', outputDirectory);
del.sync([outputDirectory + '**/*'], {silent: true, force: true});
}
// set-up local repo
function setupRepo() {
if(localRepoSetup) {
addRemote();
}
else {
initRepo();
}
}
function initRepo() {
console.info('Initializing repository for ' + component);
git.init(gitOptions, function(error) {
if(error) {
console.error('Error initializing repo', error);
}
addRemote();
});
}
function createRepo() {
console.info('Creating GitHub repo ' + repoURL);
github.repos.createFromOrg({
org : release.org,
name : repoName,
homepage : release.homepage
}, function() {
setupRepo();
});
}
function addRemote() {
console.info('Adding remote origin as ' + gitURL);
git.addRemote('origin', gitURL, gitOptions, function(){
pullFiles();
});
}
function pullFiles() {
console.info('Pulling ' + component + ' files');
git.pull('origin', 'master', pullOptions, function(error) {
resetFiles();
});
}
function resetFiles() {
console.info('Resetting files to head');
git.reset('HEAD', resetOptions, function(error) {
nextRepo();
});
}
function nextRepo() {
//console.log('Sleeping for 1 second...');
// avoid rate throttling
global.clearTimeout(timer);
timer = global.setTimeout(function() {
stepRepo()
}, 0);
}
if(localRepoSetup) {
pullFiles();
}
else {
setupRepo();
// createRepo() only use to create remote repo (easier to do manually)
}
};
stepRepo();
};

View file

@ -0,0 +1,182 @@
/*******************************
Update Repos
*******************************/
/*
This task update all SUI individual distribution repos with new versions of distributions
* Commits changes from create repo
* Pushes changes to GitHub
* Tag new releases if version changed in main repo
*/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
fs = require('fs'),
path = require('path'),
git = require('gulp-git'),
githubAPI = require('github'),
requireDotFile = require('require-dot-file'),
// admin files
github = require('../../config/admin/github.js'),
release = require('../../config/admin/release'),
project = require('../../config/project/release'),
// oAuth configuration for GitHub
oAuth = fs.existsSync(__dirname + '/../../config/admin/oauth.js')
? require('../../config/admin/oauth')
: false,
// shorthand
version = project.version
;
module.exports = function(callback) {
var
index = -1,
total = release.distributions.length,
timer,
stream,
stepRepo
;
if(!oAuth) {
console.error('Must add oauth token for GitHub in tasks/config/admin/oauth.js');
return;
}
// Do Git commands synchronously per distribution, to avoid issues
stepRepo = function() {
index = index + 1;
if(index >= total) {
callback();
return;
}
var
distribution = release.distributions[index],
outputDirectory = path.resolve(path.join(release.outputRoot, distribution.toLowerCase() )),
repoName = release.distRepoRoot + distribution,
gitURL = 'https://github.com/' + release.org + '/' + repoName + '.git',
repoURL = 'https://github.com/' + release.org + '/' + repoName + '/',
commitArgs = (oAuth.name !== undefined && oAuth.email !== undefined)
? '--author "' + oAuth.name + ' <' + oAuth.email + '>"'
: '',
distributionPackage = fs.existsSync(outputDirectory + 'package.json' )
? require(outputDirectory + 'package.json')
: false,
isNewVersion = (version && distributionPackage.version != version),
commitMessage = (isNewVersion)
? 'Updated distribution to version ' + version
: 'Updated files from main repo',
gitOptions = { cwd: outputDirectory },
commitOptions = { args: commitArgs, cwd: outputDirectory },
releaseOptions = { tag_name: version, owner: release.org, repo: repoName },
fileModeOptions = { args : 'config core.fileMode false', cwd: outputDirectory },
usernameOptions = { args : 'config user.name "' + oAuth.name + '"', cwd: outputDirectory },
emailOptions = { args : 'config user.email "' + oAuth.email + '"', cwd: outputDirectory },
versionOptions = { args : 'rev-parse --verify HEAD', cwd: outputDirectory },
localRepoSetup = fs.existsSync(path.join(outputDirectory, '.git')),
canProceed = true
;
console.info('Processing repository:' + outputDirectory);
function setConfig() {
git.exec(fileModeOptions, function() {
git.exec(usernameOptions, function () {
git.exec(emailOptions, function () {
commitFiles();
});
});
});
}
// standard path
function commitFiles() {
// commit files
console.info('Committing ' + distribution + ' files', commitArgs);
gulp.src('**/*', gitOptions)
.pipe(git.add(gitOptions))
.pipe(git.commit(commitMessage, commitOptions))
.on('error', function(error) {
// canProceed = false; bug in git commit <https://github.com/stevelacy/gulp-git/issues/49>
})
.on('finish', function(callback) {
if(canProceed) {
pushFiles();
}
else {
console.info('Nothing new to commit');
nextRepo();
}
})
;
}
// push changes to remote
function pushFiles() {
console.info('Pushing files for ' + distribution);
git.push('origin', 'master', { args: '', cwd: outputDirectory }, function(error) {
console.info('Push completed successfully');
getSHA();
});
}
// gets SHA of last commit
function getSHA() {
git.exec(versionOptions, function(error, version) {
version = version.trim();
createRelease(version);
});
}
// create release on GitHub.com
function createRelease(version) {
if(version) {
releaseOptions.target_commitish = version;
}
github.releases.createRelease(releaseOptions, function() {
nextRepo();
});
}
// Steps to next repository
function nextRepo() {
console.log('Sleeping for 1 second...');
// avoid rate throttling
global.clearTimeout(timer);
timer = global.setTimeout(stepRepo, 500);
}
if(localRepoSetup) {
setConfig();
}
else {
console.error('Repository must be setup before running update distributions');
}
};
stepRepo();
};

View file

@ -0,0 +1,25 @@
/*******************************
Release All
*******************************/
/*
This task update all SUI individual component repos with new versions of components
* Commits changes from create components to GitHub and Tags
*/
var
runSequence = require('run-sequence')
;
/* Release All */
module.exports = function(callback) {
runSequence(
'update distributions', // commit less/css versions to github
'update components', // commit components to github
callback
);
};

View file

@ -0,0 +1,55 @@
/*******************************
Register PM
*******************************/
/*
Task to register component repos with Package Managers
* Registers component with bower
* Registers component with NPM
*/
var
// node dependencies
process = require('child_process'),
// config
release = require('../config/admin/release'),
// register components and distributions
repos = release.distributions.concat(release.components),
total = repos.length,
index = -1,
stream,
stepRepo
;
module.exports = function(callback) {
console.log('Registering repos with package managers');
// Do Git commands synchronously per component, to avoid issues
stepRepo = function() {
index = index + 1;
if(index >= total) {
callback();
return;
}
var
repo = repos[index].toLowerCase(),
outputDirectory = release.outputRoot + repo + '/',
exec = process.exec,
execSettings = {cwd: outputDirectory},
updateNPM = 'npm publish'
;
/* Register with NPM */
exec(updateNPM, execSettings, function(err, stdout, stderr) {
console.log(err, stdout, stderr);
stepRepo();
});
};
stepRepo();
};

View file

@ -0,0 +1,29 @@
/*******************************
Release
*******************************/
/*
This task update all SUI individual component repos with new versions of components
* Initializes repositories with current versions
* Creates local files at ../distributions/ with each repo for release
*/
var
runSequence = require('run-sequence')
;
/* Release All */
module.exports = function(callback) {
runSequence(
//'build', // build Semantic
'init distributions', // sync with current github version
'create distributions', // update each repo with changes from master repo
'init components', // sync with current github version
'create components', // update each repo
callback
);
};

137
web/semantic/tasks/build.js Normal file
View file

@ -0,0 +1,137 @@
/*******************************
Build Task
*******************************/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
fs = require('fs'),
// gulp dependencies
autoprefixer = require('gulp-autoprefixer'),
chmod = require('gulp-chmod'),
clone = require('gulp-clone'),
flatten = require('gulp-flatten'),
gulpif = require('gulp-if'),
less = require('gulp-less'),
minifyCSS = require('gulp-minify-css'),
plumber = require('gulp-plumber'),
print = require('gulp-print'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
uglify = require('gulp-uglify'),
// config
config = require('./config/user'),
tasks = require('./config/project/tasks'),
install = require('./config/project/install'),
// shorthand
globs = config.globs,
assets = config.paths.assets,
output = config.paths.output,
source = config.paths.source,
banner = tasks.banner,
comments = tasks.regExp.comments,
log = tasks.log,
settings = tasks.settings
;
// add internal tasks (concat release)
require('./collections/internal')(gulp);
module.exports = function(callback) {
var
stream,
compressedStream,
uncompressedStream
;
console.info('Building Semantic');
if( !install.isSetup() ) {
console.error('Cannot build files. Run "gulp install" to set-up Semantic');
return;
}
// check for right-to-left language
if(config.rtl === true || config.rtl === 'Yes') {
gulp.start('build-rtl');
return;
}
// unified css stream
stream = gulp.src(source.definitions + '/**/' + globs.components + '.less')
.pipe(plumber())
.pipe(less(settings.less))
.pipe(autoprefixer(settings.prefix))
.pipe(replace(comments.variables.in, comments.variables.out))
.pipe(replace(comments.license.in, comments.license.out))
.pipe(replace(comments.large.in, comments.large.out))
.pipe(replace(comments.small.in, comments.small.out))
.pipe(replace(comments.tiny.in, comments.tiny.out))
.pipe(flatten())
;
// two concurrent streams from same source to concat release
uncompressedStream = stream.pipe(clone());
compressedStream = stream.pipe(clone());
// uncompressed component css
uncompressedStream
.pipe(plumber())
.pipe(replace(assets.source, assets.uncompressed))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package uncompressed css');
})
;
// compressed component css
compressedStream = stream
.pipe(plumber())
.pipe(clone())
.pipe(replace(assets.source, assets.compressed))
.pipe(minifyCSS(settings.minify))
.pipe(rename(settings.rename.minCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
callback();
gulp.start('package compressed css');
})
;
// copy assets
gulp.src(source.themes + '/**/assets/**/' + globs.components + '?(s).*')
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.themes))
;
// copy source javascript
gulp.src(source.definitions + '/**/' + globs.components + '.js')
.pipe(plumber())
.pipe(flatten())
.pipe(replace(comments.license.in, comments.license.out))
.pipe(gulp.dest(output.uncompressed))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(print(log.created))
.pipe(uglify(settings.uglify))
.pipe(rename(settings.rename.minJS))
.pipe(gulp.dest(output.compressed))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed js');
gulp.start('package uncompressed js');
})
;
};

View file

@ -0,0 +1,28 @@
/*******************************
Check Install
*******************************/
var
// node dependencies
gulp = require('gulp'),
fs = require('fs'),
console = require('better-console'),
install = require('./config/project/install')
;
// export task
module.exports = function() {
setTimeout(function() {
if( !install.isSetup() ) {
console.log('Starting install...');
gulp.start('install');
return;
}
else {
gulp.start('watch');
}
}, 50); // Delay to allow console.clear to remove messages from check event
};

View file

@ -0,0 +1,14 @@
/*******************************
Clean Task
*******************************/
var
del = require('del'),
config = require('./config/user'),
tasks = require('./config/project/tasks')
;
// cleans distribution files
module.exports = function(callback) {
return del([config.paths.clean], tasks.settings.del, callback);
};

View file

@ -0,0 +1,16 @@
## How to use
These are collections of tasks that are imported together.
To import them into gulp:
```javascript
var
gulp = require('gulp'),
// modified to point to semantic folder
install = require('tasks/collections/install')
;
gulp = install(gulp);
// tasks are now injected and ready to be used
gulp.start('install');
```

View file

@ -0,0 +1,49 @@
/*******************************
Admin Task Collection
*******************************/
/*
This are tasks to be run by project maintainers
- Creating Component Repos
- Syncing with GitHub via APIs
- Modifying package files
*/
/*******************************
Tasks
*******************************/
module.exports = function(gulp) {
var
// less/css distributions
initComponents = require('../admin/components/init'),
createComponents = require('../admin/components/create'),
updateComponents = require('../admin/components/update'),
// single component releases
initDistributions = require('../admin/distributions/init'),
createDistributions = require('../admin/distributions/create'),
updateDistributions = require('../admin/distributions/update'),
release = require('../admin/release'),
publish = require('../admin/publish'),
register = require('../admin/register')
;
/* Release */
gulp.task('init distributions', 'Grabs each component from GitHub', initDistributions);
gulp.task('create distributions', 'Updates files in each repo', createDistributions);
gulp.task('init components', 'Grabs each component from GitHub', initComponents);
gulp.task('create components', 'Updates files in each repo', createComponents);
/* Publish */
gulp.task('update distributions', 'Commits component updates from create to GitHub', updateDistributions);
gulp.task('update components', 'Commits component updates from create to GitHub', updateComponents);
/* Tasks */
gulp.task('release', 'Stages changes in GitHub repos for all distributions', release);
gulp.task('publish', 'Publishes all releases (components, package)', publish);
gulp.task('register', 'Registers all packages with NPM', register);
};

View file

@ -0,0 +1,214 @@
/*******************************
Internal Task Collection
*******************************/
/* These tasks create packaged files from **dist** components
Not intended to be called directly by a user because
these do not build fresh from **src**
*/
module.exports = function(gulp) {
var
// node dependencies
fs = require('fs'),
chmod = require('gulp-chmod'),
concat = require('gulp-concat'),
concatCSS = require('gulp-concat-css'),
clone = require('gulp-clone'),
gulpif = require('gulp-if'),
header = require('gulp-header'),
less = require('gulp-less'),
minifyCSS = require('gulp-minify-css'),
plumber = require('gulp-plumber'),
print = require('gulp-print'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
uglify = require('gulp-uglify'),
// user config
config = require('./../config/user'),
docsConfig = require('./../config/docs'),
// install config
tasks = require('./../config/project/tasks'),
release = require('./../config/project/release'),
// shorthand
globs = config.globs,
assets = config.paths.assets,
output = config.paths.output,
banner = tasks.banner,
filenames = tasks.filenames,
log = tasks.log,
settings = tasks.settings
;
/*--------------
Packaged
---------------*/
gulp.task('package uncompressed css', function() {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignored + '.css')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(header(banner, settings.header))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
gulp.task('package compressed css', function() {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignored + '.css')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedMinifiedCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(minifyCSS(settings.concatMinify))
.pipe(header(banner, settings.header))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
gulp.task('package uncompressed js', function() {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignored + '.js')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concat(filenames.concatenatedJS))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
gulp.task('package compressed js', function() {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignored + '.js')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concat(filenames.concatenatedMinifiedJS))
.pipe(uglify(settings.concatUglify))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
/*--------------
RTL
---------------*/
if(config.rtl) {
gulp.task('package uncompressed rtl css', function () {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignoredRTL + '.rtl.css')
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedRTLCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(header(banner, settings.header))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
gulp.task('package compressed rtl css', function () {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignoredRTL + '.rtl.css')
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedMinifiedRTLCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(minifyCSS(settings.concatMinify))
.pipe(header(banner, settings.header))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
gulp.task('package uncompressed docs css', function() {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignored + '.css')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
gulp.task('package compressed docs css', function() {
return gulp.src(output.uncompressed + '/**/' + globs.components + globs.ignored + '.css')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedMinifiedCSS))
.pipe(minifyCSS(settings.concatMinify))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.packaged))
.pipe(print(log.created))
;
});
}
/*--------------
Docs
---------------*/
var
docsOutput = docsConfig.paths.output
;
gulp.task('package uncompressed docs css', function() {
return gulp.src(docsOutput.uncompressed + '/**/' + globs.components + globs.ignored + '.css')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(docsOutput.packaged))
.pipe(print(log.created))
;
});
gulp.task('package compressed docs css', function() {
return gulp.src(docsOutput.uncompressed + '/**/' + globs.components + globs.ignored + '.css')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concatCSS(filenames.concatenatedMinifiedCSS))
.pipe(minifyCSS(settings.concatMinify))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(docsOutput.packaged))
.pipe(print(log.created))
;
});
gulp.task('package uncompressed docs js', function() {
return gulp.src(docsOutput.uncompressed + '/**/' + globs.components + globs.ignored + '.js')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concat(filenames.concatenatedJS))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(docsOutput.packaged))
.pipe(print(log.created))
;
});
gulp.task('package compressed docs js', function() {
return gulp.src(docsOutput.uncompressed + '/**/' + globs.components + globs.ignored + '.js')
.pipe(plumber())
.pipe(replace(assets.uncompressed, assets.packaged))
.pipe(concat(filenames.concatenatedMinifiedJS))
.pipe(uglify(settings.concatUglify))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(docsOutput.packaged))
.pipe(print(log.created))
;
});
};

View file

@ -0,0 +1,38 @@
/*******************************
GitHub Login
*******************************/
/*
Logs into GitHub using OAuth
*/
var
fs = require('fs'),
path = require('path'),
githubAPI = require('github'),
// stores oauth info for GitHub API
oAuthConfig = path.join(__dirname, 'oauth.js'),
oAuth = fs.existsSync(oAuthConfig)
? require(oAuthConfig)
: false,
github
;
if(!oAuth) {
console.log('here');
console.error('Must add oauth token for GitHub in tasks/config/admin/oauth.js');
}
github = new githubAPI({
version : '3.0.0',
debug : true,
protocol : 'https',
timeout : 5000
});
github.authenticate({
type: 'oauth',
token: oAuth.token
});
module.exports = github;

View file

@ -0,0 +1,10 @@
/*
Used to import GitHub Auth Token
To Automate GitHub Updates
*/
module.exports = {
token : 'AN-OAUTH2-TOKEN',
name : 'Your Name',
email : 'user@email.com'
};

View file

@ -0,0 +1,110 @@
/*******************************
Release Settings
*******************************/
// release settings
module.exports = {
// path to components for repos
source : './dist/components/',
// modified asset paths for component repos
paths: {
source : '../themes/default/assets/',
output : 'assets/'
},
templates: {
bower : './tasks/config/admin/templates/bower.json',
composer : './tasks/config/admin/templates/composer.json',
package : './tasks/config/admin/templates/package.json',
meteor : {
css : './tasks/config/admin/templates/css-package.js',
component : './tasks/config/admin/templates/component-package.js',
less : './tasks/config/admin/templates/less-package.js',
},
readme : './tasks/config/admin/templates/README.md',
notes : './RELEASE-NOTES.md'
},
org : 'Semantic-Org',
repo : 'Semantic-UI',
// files created for package managers
files: {
composer : 'composer.json',
config : 'semantic.json',
npm : 'package.json',
meteor : 'package.js'
},
// root name for distribution repos
distRepoRoot : 'Semantic-UI-',
// root name for single component repos
componentRepoRoot : 'UI-',
// root name for package managers
packageRoot : 'semantic-ui-',
// root path to repos
outputRoot : '../repos/',
homepage : 'http://www.semantic-ui.com',
// distributions that get separate repos
distributions: [
'LESS',
'CSS'
],
// components that get separate repositories for bower/npm
components : [
'accordion',
'ad',
'api',
'breadcrumb',
'button',
'card',
'checkbox',
'comment',
'dimmer',
'divider',
'dropdown',
'feed',
'flag',
'form',
'grid',
'header',
'icon',
'image',
'input',
'item',
'label',
'list',
'loader',
'menu',
'message',
'modal',
'nag',
'popup',
'progress',
'rail',
'rating',
'reset',
'reveal',
'search',
'segment',
'shape',
'sidebar',
'site',
'statistic',
'step',
'sticky',
'tab',
'table',
'transition',
'video',
'visibility'
]
};

View file

@ -0,0 +1,29 @@
# Semantic {Component}
This repository contains pre-compiled {component} files using the default themes. This is intended for use in projects that do not need all the bells and whistles of Semantic UI, and want to keep file size to a minimum.
For the latest changes please see the [Release Notes](https://github.com/Semantic-Org/UI-{Component}/blob/master/RELEASE-NOTES.md)
If you're looking for the full version of Semantic including all components and build tools [check out the main project repository](https://github.com/Semantic-Org/Semantic-UI/tree/1.0)
#### To install with Bower
```
bower install semantic-ui-{component}
```
#### To install with NPM
```
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)
Please consider checking out [all the benefits to theming](http://www.learnsemantic.com/guide/expert.html) before using these stand-alone releases.

View file

@ -0,0 +1,29 @@
{
"name" : "Component",
"description" : "Component distribution",
"homepage" : "http://www.semantic-ui.com",
"author": {
"name" : "Jack Lukic",
"web" : "http://www.jacklukic.com"
},
"ignore": [
"./index.js"
],
"keywords": [
"semantic",
"ui",
"css3",
"framework"
],
"license" : [
"http://semantic-ui.mit-license.org/"
],
"ignore": [
"docs",
"node",
"server",
"spec",
"src",
"test"
]
}

View file

@ -0,0 +1,14 @@
Package.describe({
name : 'semantic:ui-{component}',
summary : 'Semantic UI - {Component}: Single component release',
version : '{version}',
git : 'git://github.com/Semantic-Org/UI-{Component}.git',
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.addFiles([
{files}
], 'client');
});

View file

@ -0,0 +1,20 @@
{
"name" : "semantic/ui",
"description" : "Semantic empowers designers and developers by creating a shared vocabulary for UI.",
"homepage" : "http://www.semantic-ui.com",
"authors": [
{
"name" : "Jack Lukic",
"email": "jacklukic@gmail.com",
"web" : "http://www.jacklukic.com",
"role" : "Creator"
}
],
"keywords": [
"semantic",
"ui",
"css",
"framework"
],
"license" : "MIT"
}

View file

@ -0,0 +1,33 @@
var
where = 'client' // Adds files only to the client
;
Package.describe({
name : 'semantic:ui-css',
summary : 'Semantic UI - CSS Release of Semantic UI',
version : '{version}',
git : 'git://github.com/Semantic-Org/Semantic-UI-CSS.git',
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.addFiles([
// icons
'themes/default/assets/fonts/icons.eot',
'themes/default/assets/fonts/icons.otf',
'themes/default/assets/fonts/icons.svg',
'themes/default/assets/fonts/icons.ttf',
'themes/default/assets/fonts/icons.woff',
'themes/default/assets/fonts/icons.woff2',
// flags
'themes/default/assets/images/flags.png',
// release
'semantic.css',
'semantic.js'
], 'client');
});

View file

@ -0,0 +1,21 @@
var
where = 'client' // Adds files only to the client
;
Package.describe({
name : 'semantic:ui',
summary : 'Semantic UI - LESS Release of Semantic UI',
version : '{version}',
git : 'git://github.com/Semantic-Org/Semantic-UI-LESS.git',
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use('less', 'client');
api.addFiles([
{files}
], 'client');
});

View file

@ -0,0 +1,17 @@
{
"name": "semantic",
"version": "1.0.0",
"title": "Semantic UI",
"description": "Semantic empowers designers and developers by creating a shared vocabulary for UI.",
"homepage": "http://www.semantic-ui.com",
"author": "Jack Lukic <jack@semantic-ui.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/Semantic-Org/Semantic-UI.git"
},
"bugs": {
"url": "https://github.com/Semantic-Org/Semantic-UI/issues"
},
"devDependencies": {}
}

View file

@ -0,0 +1,116 @@
/*******************************
Default Paths
*******************************/
module.exports = {
// base path added to all other paths
base : '',
// base path when installed with npm
pmRoot: 'semantic/',
// octal permission for output files, i.e. 644 (false does not adjust)
permission : 744,
// whether to generate rtl files
rtl : false,
// file paths
files: {
config : 'semantic.json',
site : 'src/site',
theme : 'src/theme.config'
},
// folder paths
paths: {
source: {
config : 'src/theme.config',
definitions : 'src/definitions/',
site : 'src/site/',
themes : 'src/themes/'
},
output: {
packaged : 'dist/',
uncompressed : 'dist/components/',
compressed : 'dist/components/',
themes : 'dist/themes/'
},
clean : 'dist/'
},
// components to include in package
components: [
// global
'reset',
'site',
// elements
'button',
'divider',
'flag',
'header',
'icon',
'image',
'input',
'label',
'list',
'loader',
'rail',
'reveal',
'segment',
'step',
// collections
'breadcrumb',
'form',
'grid',
'menu',
'message',
'table',
// views
'ad',
'card',
'comment',
'feed',
'item',
'statistic',
// modules
'accordion',
'checkbox',
'dimmer',
'dropdown',
'modal',
'nag',
'popup',
'progress',
'rating',
'search',
'shape',
'sidebar',
'sticky',
'tab',
'transition',
'video',
// behaviors
'api',
'form',
'state',
'visibility'
],
// whether to load admin tasks
admin: false,
// globs used for matching file patterns
globs : {
ignored : '!(*.min|*.map|*.rtl)',
ignoredRTL : '!(*.min|*.map)'
}
};

View file

@ -0,0 +1,24 @@
/*******************************
Docs
*******************************/
/* Paths used for "serve-docs" and "build-docs" tasks */
module.exports = {
base: '',
paths: {
source: {
config : 'src/theme.config',
definitions : 'src/definitions/',
site : 'src/site/',
themes : 'src/themes/'
},
output: {
less : '../docs/out/src/',
packaged : '../docs/out/dist/',
uncompressed : '../docs/out/dist/components/',
compressed : '../docs/out/dist/components/',
themes : '../docs/out/dist/themes/'
},
clean: '../docs/out/dist/'
}
};

View file

@ -0,0 +1,59 @@
/*******************************
Set-up
*******************************/
var
gulp = require('gulp-help')(require('gulp')),
// read user config to know what task to load
config = require('./tasks/config/user'),
// import tasks
build = require('./tasks/build'),
clean = require('./tasks/clean'),
version = require('./tasks/version'),
watch = require('./tasks/watch'),
// docs tasks
serveDocs = require('./tasks/docs/serve'),
buildDocs = require('./tasks/docs/build'),
// rtl
buildRTL = require('./tasks/rtl/build'),
watchRTL = require('./tasks/rtl/watch')
;
/*--------------
Common
---------------*/
gulp.task('default', false, [
'watch'
]);
gulp.task('watch', 'Watch for site/theme changes', watch);
gulp.task('build', 'Builds all files from source', build);
gulp.task('clean', 'Clean dist folder', clean);
gulp.task('version', 'Displays current version of Semantic', version);
/*--------------
Docs
---------------*/
/*
See usage instruction in Docs Readme
https://github.com/Semantic-Org/Semantic-UI-Docs/
*/
gulp.task('serve-docs', 'Serve file changes to SUI Docs', serveDocs);
gulp.task('build-docs', 'Build all files and add to SUI Docs', buildDocs);
/*--------------
RTL
---------------*/
if(config.rtl) {
gulp.task('watch-rtl', 'Build all files as RTL', watchRTL);
gulp.task('build-rtl', 'Watch files as RTL ', buildRTL);
}

View file

@ -0,0 +1,135 @@
/*******************************
Set-up
*******************************/
var
extend = require('extend'),
fs = require('fs'),
path = require('path'),
defaults = require('../defaults')
;
/*******************************
Exports
*******************************/
module.exports = {
getPath: function(file, directory) {
var
configPath,
walk = function(directory) {
var
nextDirectory = path.resolve( path.join(directory, path.sep, '..') ),
currentPath = path.normalize( path.join(directory, file) )
;
if( fs.existsSync(currentPath) ) {
// found file
configPath = path.normalize(directory);
return;
}
else {
// reached file system root, let's stop
if(nextDirectory == directory) {
return;
}
// otherwise recurse
walk(nextDirectory, file);
}
}
;
// start walk from outside require-dot-files directory
file = file || defaults.files.config;
directory = directory || path.join(__dirname, path.sep, '..');
walk(directory);
return configPath || '';
},
// adds additional derived values to a config object
addDerivedValues: function(config) {
config = config || extend(false, {}, defaults);
/*--------------
File Paths
---------------*/
var
configPath = this.getPath(),
sourcePaths = {},
outputPaths = {},
folder
;
// resolve paths (config location + base + path)
for(folder in config.paths.source) {
if(config.paths.source.hasOwnProperty(folder)) {
sourcePaths[folder] = path.resolve(path.join(configPath, config.base, config.paths.source[folder]));
}
}
for(folder in config.paths.output) {
if(config.paths.output.hasOwnProperty(folder)) {
outputPaths[folder] = path.resolve(path.join(configPath, config.base, config.paths.output[folder]));
}
}
// set config paths to full paths
config.paths.source = sourcePaths;
config.paths.output = outputPaths;
// resolve "clean" command path
config.paths.clean = path.resolve( path.join(configPath, config.base, config.paths.clean) );
/*--------------
CSS URLs
---------------*/
// determine asset paths in css by finding relative path between themes and output
// force forward slashes
config.paths.assets = {
source : '../../themes', // source asset path is always the same
uncompressed : path.relative(config.paths.output.uncompressed, config.paths.output.themes).replace(/\\/g,'/'),
compressed : path.relative(config.paths.output.compressed, config.paths.output.themes).replace(/\\/g,'/'),
packaged : path.relative(config.paths.output.packaged, config.paths.output.themes).replace(/\\/g,'/')
};
/*--------------
Permission
---------------*/
if(config.permission) {
config.hasPermissions = true;
}
else {
// pass blank object to avoid causing errors
config.permission = {};
config.hasPermissions = false;
}
/*--------------
Globs
---------------*/
if(!config.globs) {
config.globs = {};
}
// takes component object and creates file glob matching selected components
config.globs.components = (typeof config.components == 'object')
? (config.components.length > 1)
? '{' + config.components.join(',') + '}'
: config.components[0]
: '{' + defaults.components.join(',') + '}'
;
return config;
}
};

View file

@ -0,0 +1,762 @@
/*******************************
Set-up
*******************************/
var
fs = require('fs'),
path = require('path'),
defaults = require('../defaults'),
release = require('./release'),
requireDotFile = require('require-dot-file')
;
/*******************************
When to Ask
*******************************/
/* Preconditions for install questions */
var when = {
// path
changeRoot: function(questions) {
return (questions.useRoot !== undefined && questions.useRoot !== true);
},
// permissions
changePermissions: function(questions) {
return (questions.changePermissions && questions.changePermissions === true);
},
// install
hasConfig: function() {
return requireDotFile('semantic.json');
},
allowOverwrite: function(questions) {
return (questions.overwrite === undefined || questions.overwrite == 'yes');
},
notAuto: function(questions) {
return (questions.install !== 'auto' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
},
custom: function(questions) {
return (questions.install === 'custom' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
},
express: function(questions) {
return (questions.install === 'express' && (questions.overwrite === undefined || questions.overwrite == 'yes'));
},
// customize
customize: function(questions) {
return (questions.customize === true);
},
primaryColor: function(questions) {
return (questions.primaryColor);
},
secondaryColor: function(questions) {
return (questions.secondaryColor);
}
};
/*******************************
Response Filters
*******************************/
/* Filters to user input from install questions */
var filter = {
removeTrailingSlash: function(path) {
return path.replace(/(\/$|\\$)+/mg, '');
}
};
/*******************************
Configuration
*******************************/
module.exports = {
// check whether install is setup
isSetup: function() {
return when.hasConfig();
},
// checks if files are in a PM directory
getPackageManager: function(directory) {
var
// returns last matching result (avoid sub-module detection)
walk = function(directory) {
var
pathArray = directory.split(path.sep),
folder = pathArray[pathArray.length - 1],
nextDirectory = path.join(directory, path.sep, '..')
;
console.log(folder, nextDirectory);
if( folder == 'bower_components') {
return {
name: 'Bower',
root: nextDirectory
};
}
else if(folder == 'node_modules') {
return {
name: 'NPM',
root: nextDirectory
};
}
else if(folder == 'composer') {
return {
name: 'Composer',
root: nextDirectory
};
}
if(path.resolve(directory) == path.resolve(nextDirectory)) {
return false;
}
// recurse downward
return walk(nextDirectory);
}
;
// start walk from current directory if none specified
directory = directory || (__dirname + path.sep);
return walk(directory);
},
// checks if files is PMed submodule
isSubModule: function(directory) {
var
moduleFolders = 0,
walk = function(directory) {
var
pathArray = directory.split(path.sep),
folder = pathArray[pathArray.length - 2],
nextDirectory = path.join(directory, path.sep, '..')
;
if( folder == 'bower_components') {
moduleFolders++;
}
else if(folder == 'node_modules') {
moduleFolders++;
}
else if(folder == 'composer') {
moduleFolders++;
}
if(path.resolve(directory) == path.resolve(nextDirectory)) {
return (moduleFolders > 1);
}
// recurse downward
return walk(nextDirectory);
}
;
// start walk from current directory if none specified
directory = directory || (__dirname + path.sep);
return walk(directory);
},
createJSON: function(answers) {
var
json = {
paths: {
source: {},
output: {}
}
}
;
// add components
if(answers.components) {
json.components = answers.components;
}
// add rtl choice
if(answers.rtl) {
json.rtl = answers.rtl;
}
// add permissions
if(answers.permission) {
json.permission = answers.permission;
}
// add path to semantic
if(answers.semanticRoot) {
json.base = path.normalize(answers.semanticRoot);
}
// record version number to avoid re-installing on same version
json.version = release.version;
// add dist folder paths
if(answers.dist) {
answers.dist = path.normalize(answers.dist);
json.paths.output = {
packaged : path.normalize(answers.dist + '/'),
uncompressed : path.normalize(answers.dist + '/components/'),
compressed : path.normalize(answers.dist + '/components/'),
themes : path.normalize(answers.dist + '/themes/')
};
}
// add site path
if(answers.site) {
json.paths.source.site = path.normalize(answers.site + '/');
}
if(answers.packaged) {
json.paths.output.packaged = path.normalize(answers.packaged + '/');
}
if(answers.compressed) {
json.paths.output.compressed = path.normalize(answers.compressed + '/');
}
if(answers.uncompressed) {
json.paths.output.uncompressed = path.normalize(answers.uncompressed + '/');
}
return json;
},
// files cleaned up after install
setupFiles: [
'./src/theme.config.example',
'./semantic.json.example',
'./src/_site'
],
regExp: {
// used to match siteFolder variable in theme.less
siteVariable: /@siteFolder .*\'(.*)/mg
},
// source paths (relative to tasks/install.js )
source: {
config : './semantic.json.example',
definitions : './src/definitions',
gulpFile : './gulpfile.js',
lessImport : './src/semantic.less',
site : './src/_site',
tasks : './tasks',
themeConfig : './src/theme.config.example',
themeImport : './src/theme.less',
themes : './src/themes',
userGulpFile : './tasks/config/npm/gulpfile.js'
},
// expected final filenames
files: {
config : 'semantic.json',
lessImport : 'src/semantic.less',
site : 'src/site',
themeConfig : 'src/theme.config',
themeImport : 'src/theme.less'
},
// folder paths to files relative to root
folders: {
config : './',
definitions : 'src/definitions/',
lessImport : 'src/',
modules : 'node_modules/',
site : 'src/site/',
tasks : 'tasks/',
themeConfig : 'src/',
themeImport : 'src/',
themes : 'src/themes/'
},
// questions asked during install
questions: {
root: [
{
type : 'list',
name : 'useRoot',
message :
' \n' +
' {packageMessage} \n' +
' \n' +
' Is this your project folder?\n' +
' \033[92m{root}\033[0m \n' +
' \n ' +
'\n',
choices: [
{
name : 'Yes',
value : true
},
{
name : 'No, let me specify',
value : false
}
]
},
{
type : 'input',
name : 'customRoot',
message : 'Please enter the absolute path to your project root',
default : '/my/project/path',
when : when.changeRoot
},
{
type : 'input',
name : 'semanticRoot',
message : 'Where should we put Semantic UI inside your project?',
default : 'semantic/'
}
],
setup: [
{
type: 'list',
name: 'overwrite',
message: 'It looks like you have a semantic.json file already.',
when: when.hasConfig,
choices: [
{
name: 'Yes, extend my current settings.',
value: 'yes'
},
{
name: 'Skip install',
value: 'no'
}
]
},
{
type: 'list',
name: 'install',
message: 'Set-up Semantic UI',
when: when.allowOverwrite,
choices: [
{
name: 'Automatic (Use defaults locations and all components)',
value: 'auto'
},
{
name: 'Express (Set components and output folder)',
value: 'express'
},
{
name: 'Custom (Customize all src/dist values)',
value: 'custom'
}
]
},
{
type: 'checkbox',
name: 'components',
message: 'What components should we include in the package?',
// duplicated manually from tasks/defaults.js with additional property
choices: [
{ name: "reset", checked: true },
{ name: "site", checked: true },
{ name: "button", checked: true },
{ name: "divider", checked: true },
{ name: "flag", checked: true },
{ name: "header", checked: true },
{ name: "icon", checked: true },
{ name: "image", checked: true },
{ name: "input", checked: true },
{ name: "label", checked: true },
{ name: "list", checked: true },
{ name: "loader", checked: true },
{ name: "rail", checked: true },
{ name: "reveal", checked: true },
{ name: "segment", checked: true },
{ name: "step", checked: true },
{ name: "breadcrumb", checked: true },
{ name: "form", checked: true },
{ name: "grid", checked: true },
{ name: "menu", checked: true },
{ name: "message", checked: true },
{ name: "table", checked: true },
{ name: "ad", checked: true },
{ name: "card", checked: true },
{ name: "comment", checked: true },
{ name: "feed", checked: true },
{ name: "item", checked: true },
{ name: "statistic", checked: true },
{ name: "accordion", checked: true },
{ name: "checkbox", checked: true },
{ name: "dimmer", checked: true },
{ name: "dropdown", checked: true },
{ name: "modal", checked: true },
{ name: "nag", checked: true },
{ name: "popup", checked: true },
{ name: "progress", checked: true },
{ name: "rating", checked: true },
{ name: "search", checked: true },
{ name: "shape", checked: true },
{ name: "sidebar", checked: true },
{ name: "sticky", checked: true },
{ name: "tab", checked: true },
{ name: "transition", checked: true },
{ name: "video", checked: true },
{ name: "api", checked: true },
{ name: "form", checked: true },
{ name: "state", checked: true },
{ name: "visibility", checked: true }
],
when: when.notAuto
},
{
type: 'list',
name: 'changePermisions',
when: when.notAuto,
message: 'Should we set permissions on outputted files?',
choices: [
{
name: 'No',
value: false
},
{
name: 'Yes',
value: true
},
]
},
{
type: 'input',
name: 'permission',
message: 'What octal file permission should outputted files receive?',
default: defaults.permission,
when: when.changePermissions
},
{
type: 'list',
name: 'rtl',
message: 'Do you use a RTL (Right-To-Left) language?',
when: when.notAuto,
choices: [
{
name: 'No',
value: false
},
{
name: 'Yes',
value: true
},
]
},
{
type: 'input',
name: 'dist',
message: 'Where should we output Semantic UI?',
default: defaults.paths.output.packaged,
filter: filter.removeTrailingSlash,
when: when.express
},
{
type: 'input',
name: 'site',
message: 'Where should we put your site folder?',
default: defaults.paths.source.site,
filter: filter.removeTrailingSlash,
when: when.custom
},
{
type: 'input',
name: 'packaged',
message: 'Where should we output a packaged version?',
default: defaults.paths.output.packaged,
filter: filter.removeTrailingSlash,
when: when.custom
},
{
type: 'input',
name: 'compressed',
message: 'Where should we output compressed components?',
default: defaults.paths.output.compressed,
filter: filter.removeTrailingSlash,
when: when.custom
},
{
type: 'input',
name: 'uncompressed',
message: 'Where should we output uncompressed components?',
default: defaults.paths.output.uncompressed,
filter: filter.removeTrailingSlash,
when: when.custom
}
],
cleanup: [
{
type: 'list',
name: 'cleanup',
message: 'Should we remove set-up files?',
choices: [
{
name: 'Yes (re-install will require redownloading semantic).',
value: 'yes'
},
{
name: 'No Thanks',
value: 'no'
}
]
},
{
type: 'list',
name: 'build',
message: 'Do you want to build Semantic now?',
choices: [
{
name: 'Yes',
value: 'yes'
},
{
name: 'No',
value: 'no'
}
]
},
],
site: [
{
type: 'list',
name: 'customize',
message: 'You have not yet customized your site, can we help you do that?',
choices: [
{
name: 'Yes, ask me a few questions',
value: true
},
{
name: 'No I\'ll do it myself',
value: false
}
]
},
{
type: 'list',
name: 'headerFont',
message: 'Select your header font',
choices: [
{
name: 'Helvetica Neue, Arial, sans-serif',
value: 'Helvetica Neue, Arial, sans-serif;'
},
{
name: 'Lato (Google Fonts)',
value: 'Lato'
},
{
name: 'Open Sans (Google Fonts)',
value: 'Open Sans'
},
{
name: 'Source Sans Pro (Google Fonts)',
value: 'Source Sans Pro'
},
{
name: 'Droid (Google Fonts)',
value: 'Droid'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'list',
name: 'pageFont',
message: 'Select your page font',
choices: [
{
name: 'Helvetica Neue, Arial, sans-serif',
value: 'Helvetica Neue, Arial, sans-serif;'
},
{
name: 'Lato (Import from Google Fonts)',
value: 'Lato'
},
{
name: 'Open Sans (Import from Google Fonts)',
value: 'Open Sans'
},
{
name: 'Source Sans Pro (Import from Google Fonts)',
value: 'Source Sans Pro'
},
{
name: 'Droid (Google Fonts)',
value: 'Droid'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'list',
name: 'fontSize',
message: 'Select your base font size',
default: '14px',
choices: [
{
name: '12px',
},
{
name: '13px',
},
{
name: '14px (Recommended)',
value: '14px'
},
{
name: '15px',
},
{
name: '16px',
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'list',
name: 'primaryColor',
message: 'Select the closest name for your primary brand color',
default: '14px',
choices: [
{
name: 'Blue'
},
{
name: 'Green'
},
{
name: 'Orange'
},
{
name: 'Pink'
},
{
name: 'Purple'
},
{
name: 'Red'
},
{
name: 'Teal'
},
{
name: 'Yellow'
},
{
name: 'Black'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'input',
name: 'PrimaryHex',
message: 'Enter a hexcode for your primary brand color',
when: when.primaryColor
},
{
type: 'list',
name: 'secondaryColor',
message: 'Select the closest name for your secondary brand color',
default: '14px',
choices: [
{
name: 'Blue'
},
{
name: 'Green'
},
{
name: 'Orange'
},
{
name: 'Pink'
},
{
name: 'Purple'
},
{
name: 'Red'
},
{
name: 'Teal'
},
{
name: 'Yellow'
},
{
name: 'Black'
},
{
name: 'I\'ll choose on my own',
value: false
}
],
when: when.customize
},
{
type: 'input',
name: 'secondaryHex',
message: 'Enter a hexcode for your secondary brand color',
when: when.secondaryColor
}
]
},
settings: {
/* Rename Files */
rename: {
json : { extname : '.json' },
},
/* Copy Install Folders */
wrench: {
// copy during npm update (default theme / definition)
update: {
forceDelete : true,
excludeHiddenUnix : true,
preserveFiles : false
},
// copy during first npm install
install: {
forceDelete : true,
excludeHiddenUnix : true,
preserveFiles : false
},
// copy for node_modules
modules: {
forceDelete : true,
excludeHiddenUnix : true,
preserveFiles : false
},
// copy for site theme
site: {
forceDelete : false,
excludeHiddenUnix : true,
preserveFiles : true
}
}
}
};

View file

@ -0,0 +1,61 @@
/*******************************
Release Config
*******************************/
var
requireDotFile = require('require-dot-file'),
config,
package,
version
;
/*******************************
Derived Values
*******************************/
try {
config = requireDotFile('semantic.json');
package = require('../../../package.json');
// looks for version in config or package.json (whichever is available)
version = (config && config.version !== undefined)
? config.version
: package.version
;
}
catch(error) {
// generate fake package
package = {
version: 'x.x'
};
}
/*******************************
Export
*******************************/
module.exports = {
title : 'Semantic UI',
repository : 'https://github.com/Semantic-Org/Semantic-UI',
url : 'http://www.semantic-ui.com/',
banner: ''
+ ' /*' + '\n'
+ ' * # <%= title %> - <%= version %>' + '\n'
+ ' * <%= repository %>' + '\n'
+ ' * <%= url %>' + '\n'
+ ' *' + '\n'
+ ' * Copyright 2014 Contributors' + '\n'
+ ' * Released under the MIT license' + '\n'
+ ' * http://opensource.org/licenses/MIT' + '\n'
+ ' *' + '\n'
+ ' */' + '\n',
version : package.version
};

View file

@ -0,0 +1,127 @@
var
config = require('../user'),
release = require('./release')
;
module.exports = {
banner : release.banner,
log: {
created: function(file) {
return 'Created: ' + file;
},
modified: function(file) {
return 'Modified: ' + file;
}
},
filenames: {
concatenatedCSS : 'semantic.css',
concatenatedJS : 'semantic.js',
concatenatedMinifiedCSS : 'semantic.min.css',
concatenatedMinifiedJS : 'semantic.min.js',
concatenatedRTLCSS : 'semantic.rtl.css',
concatenatedMinifiedRTLCSS : 'semantic.rtl.min.css'
},
regExp: {
comments: {
// remove all comments from config files (.variable)
variables : {
in : /(\/\*[\s\S]+?\*\/+)[\s\S]+?\/\* End Config \*\//,
out : '$1',
},
// add version to first comment
license: {
in : /(^\/\*[\s\S]+)(# Semantic UI )([\s\S]+?\*\/)/,
out : '$1$2' + release.version + ' $3'
},
// adds uniform spacing around comments
large: {
in : /(\/\*\*\*\*[\s\S]+?\*\/)/mg,
out : '\n\n$1\n'
},
small: {
in : /(\/\*---[\s\S]+?\*\/)/mg,
out : '\n$1\n'
},
tiny: {
in : /(\/\* [\s\S]+? \*\/)/mg,
out : '\n$1'
}
},
theme: /.*\/themes\/.*?(?=\/)/mg
},
settings: {
/* Remove Files in Clean */
del: {
silent : true
},
/* Comment Banners */
header: {
title : release.title,
version : release.version,
repository : release.repository,
url : release.url
},
/* What Browsers to Prefix */
prefix: {
browsers: [
'last 2 version',
'> 1%',
'opera 12.1',
'safari 6',
'ie 9',
'bb 10',
'android 4'
]
},
/* File Renames */
rename: {
minJS : { extname : '.min.js' },
minCSS : { extname : '.min.css' },
rtlCSS : { extname : '.rtl.css' },
rtlMinCSS : { extname : '.rtl.min.css' }
},
/* Minified CSS Concat */
minify: {
processImport : false,
restructuring : false,
keepSpecialComments : 1
},
/* Minified JS Settings */
uglify: {
mangle : true,
preserveComments : 'some'
},
/* Minified Concat CSS Settings */
concatMinify: {
processImport : false,
restructuring : false,
keepSpecialComments : false
},
/* Minified Concat JS */
concatUglify: {
mangle : true,
preserveComments : false
}
}
};

View file

@ -0,0 +1,58 @@
/*******************************
Set-up
*******************************/
var
// npm dependencies
extend = require('extend'),
fs = require('fs'),
path = require('path'),
requireDotFile = require('require-dot-file'),
// semantic.json defaults
defaults = require('./defaults'),
config = require('./project/config'),
// Final config object
gulpConfig = {},
// semantic.json settings
userConfig
;
/*******************************
User Config
*******************************/
try {
// looks for config file across all parent directories
userConfig = requireDotFile('semantic.json');
}
catch(error) {
if(error.code === 'MODULE_NOT_FOUND') {
console.error('No semantic.json config found');
}
}
// extend user config with defaults
gulpConfig = (!userConfig)
? extend(true, {}, defaults)
: extend(false, {}, defaults, userConfig)
;
/*******************************
Add Derived Values
*******************************/
// adds calculated values
config.addDerivedValues(gulpConfig);
/*******************************
Export
*******************************/
module.exports = gulpConfig;

View file

@ -0,0 +1,158 @@
/*******************************
Build Docs
*******************************/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
fs = require('fs'),
// gulp dependencies
autoprefixer = require('gulp-autoprefixer'),
chmod = require('gulp-chmod'),
clone = require('gulp-clone'),
flatten = require('gulp-flatten'),
gulpif = require('gulp-if'),
header = require('gulp-header'),
less = require('gulp-less'),
minifyCSS = require('gulp-minify-css'),
plumber = require('gulp-plumber'),
print = require('gulp-print'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
uglify = require('gulp-uglify'),
// user config
config = require('../config/docs'),
// install config
configSetup = require('../config/project/config'),
tasks = require('../config/project/tasks'),
install = require('../config/project/install'),
// shorthand
globs,
assets,
output,
source,
banner = tasks.banner,
comments = tasks.regExp.comments,
log = tasks.log,
settings = tasks.settings
;
// add internal tasks (concat release)
require('../collections/internal')(gulp);
module.exports = function(callback) {
var
stream,
compressedStream,
uncompressedStream
;
// use a different config
config = configSetup.addDerivedValues(config);
// shorthand
globs = config.globs;
assets = config.paths.assets;
output = config.paths.output;
source = config.paths.source;
/*--------------
Copy Source
---------------*/
// copy src/ to server
gulp.src('src/**/*.*')
.pipe(gulp.dest(output.less))
.pipe(print(log.created))
;
/*--------------
Build
---------------*/
console.info('Building Semantic for docs');
if( !install.isSetup() ) {
console.error('Cannot build files. Run "gulp install" to set-up Semantic');
return;
}
// unified css stream
stream = gulp.src(source.definitions + '/**/' + globs.components + '.less')
.pipe(plumber())
.pipe(less(settings.less))
.pipe(autoprefixer(settings.prefix))
.pipe(flatten())
;
// two concurrent streams from same source to concat release
uncompressedStream = stream.pipe(clone());
compressedStream = stream.pipe(clone());
uncompressedStream
.pipe(plumber())
.pipe(replace(comments.variables.in, comments.variables.out))
.pipe(replace(comments.large.in, comments.large.out))
.pipe(replace(comments.small.in, comments.small.out))
.pipe(replace(comments.tiny.in, comments.tiny.out))
.pipe(replace(assets.source, assets.uncompressed))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package uncompressed docs css');
})
;
compressedStream = stream
.pipe(plumber())
.pipe(clone())
.pipe(replace(assets.source, assets.compressed))
.pipe(minifyCSS(settings.minify))
.pipe(rename(settings.rename.minCSS))
.pipe(header(banner, settings.header))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
callback();
gulp.start('package compressed docs css');
})
;
// copy assets
gulp.src(source.themes + '/**/assets/**/' + globs.components + '?(s).*')
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.themes))
;
// copy source javascript
gulp.src(source.definitions + '/**/' + globs.components + '.js')
.pipe(plumber())
.pipe(flatten())
.pipe(gulp.dest(output.uncompressed))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(print(log.created))
.pipe(uglify(settings.uglify))
.pipe(rename(settings.rename.minJS))
.pipe(header(banner, settings.header))
.pipe(gulp.dest(output.compressed))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed docs js');
gulp.start('package uncompressed docs js');
})
;
};

View file

@ -0,0 +1,236 @@
/*******************************
Serve Docs
*******************************/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
fs = require('fs'),
// gulp dependencies
autoprefixer = require('gulp-autoprefixer'),
chmod = require('gulp-chmod'),
clone = require('gulp-clone'),
gulpif = require('gulp-if'),
header = require('gulp-header'),
less = require('gulp-less'),
minifyCSS = require('gulp-minify-css'),
plumber = require('gulp-plumber'),
print = require('gulp-print'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
uglify = require('gulp-uglify'),
util = require('gulp-util'),
watch = require('gulp-watch'),
// user config
config = require('../config/docs'),
// task config
configSetup = require('../config/project/config'),
tasks = require('../config/project/tasks'),
install = require('../config/project/install'),
// shorthand
banner = tasks.banner,
comments = tasks.regExp.comments,
log = tasks.log,
settings = tasks.settings,
globs,
assets,
output,
source
;
require('../collections/internal')(gulp);
module.exports = function () {
// use a different config
config = configSetup.addDerivedValues(config);
// shorthand
globs = config.globs;
assets = config.paths.assets;
output = config.paths.output;
source = config.paths.source;
/*--------------
Copy Source
---------------*/
gulp
.watch([
'src/**/*.*'
], function(file) {
console.clear();
return gulp.src(file.path, {
base: 'src/'
})
.pipe(gulp.dest(output.less))
.pipe(print(log.created))
;
})
;
/*--------------
Watch CSS
---------------*/
gulp
.watch([
source.config,
source.definitions + '/**/*.less',
source.site + '/**/*.{overrides,variables}',
source.themes + '/**/*.{overrides,variables}'
], function(file) {
var
lessPath,
stream,
compressedStream,
uncompressedStream,
isDefinition,
isPackagedTheme,
isSiteTheme,
isConfig
;
// log modified file
gulp.src(file.path)
.pipe(print(log.modified))
;
/*--------------
Find Source
---------------*/
// recompile on *.override , *.variable change
isConfig = (file.path.indexOf('theme.config') !== -1);
isPackagedTheme = (file.path.indexOf(source.themes) !== -1);
isSiteTheme = (file.path.indexOf(source.site) !== -1);
isDefinition = (file.path.indexOf(source.definitions) !== -1);
if(isConfig) {
console.info('Change detected in theme config, rebuild docs with `build-docs`');
// impossible to tell which file was updated in theme.config
return;
}
else if(isPackagedTheme) {
console.log('Change detected in packaged theme');
lessPath = util.replaceExtension(file.path, '.less');
lessPath = lessPath.replace(tasks.regExp.theme, source.definitions);
}
else if(isSiteTheme) {
console.log('Change detected in site theme');
lessPath = util.replaceExtension(file.path, '.less');
lessPath = lessPath.replace(source.site, source.definitions);
}
else {
console.log('Change detected in definition');
lessPath = file.path;
}
/*--------------
Create CSS
---------------*/
if( fs.existsSync(lessPath) ) {
// unified css stream
stream = gulp.src(lessPath)
.pipe(plumber())
.pipe(less(settings.less))
.pipe(replace(comments.variables.in, comments.variables.out))
.pipe(replace(comments.large.in, comments.large.out))
.pipe(replace(comments.small.in, comments.small.out))
.pipe(replace(comments.tiny.in, comments.tiny.out))
.pipe(autoprefixer(settings.prefix))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
;
// use 2 concurrent streams from same pipe
uncompressedStream = stream.pipe(clone());
compressedStream = stream.pipe(clone());
uncompressedStream
.pipe(plumber())
.pipe(replace(assets.source, assets.uncompressed))
.pipe(header(banner, settings.header))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package uncompressed docs css');
})
;
compressedStream = stream
.pipe(plumber())
.pipe(replace(assets.source, assets.compressed))
.pipe(minifyCSS(settings.minify))
.pipe(rename(settings.rename.minCSS))
.pipe(header(banner, settings.header))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed docs css');
})
;
}
else {
console.log('Cannot find UI definition at path', lessPath);
}
})
;
/*--------------
Watch JS
---------------*/
gulp
.watch([
source.definitions + '/**/*.js'
], function(file) {
gulp.src(file.path)
.pipe(plumber())
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.pipe(uglify(settings.uglify))
.pipe(rename(settings.rename.minJS))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed docs js');
gulp.start('package uncompressed docs js');
})
;
})
;
/*--------------
Watch Assets
---------------*/
// only copy assets that match component names (or their plural)
gulp
.watch([
source.themes + '/**/assets/**/' + globs.components + '?(s).*'
], function(file) {
// copy assets
gulp.src(file.path, { base: source.themes })
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.themes))
.pipe(print(log.created))
;
})
;
};

View file

@ -0,0 +1,391 @@
/*******************************
Install Task
*******************************/
/*
Install tasks
For more notes
* Runs automatically after npm update (hooks)
* (NPM) Install - Will ask for where to put semantic (outside pm folder)
* (NPM) Upgrade - Will look for semantic install, copy over files and update if new version
* Standard installer runs asking for paths to site files etc
*/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
extend = require('extend'),
fs = require('fs'),
mkdirp = require('mkdirp'),
path = require('path'),
// gulp dependencies
chmod = require('gulp-chmod'),
del = require('del'),
jsonEditor = require('gulp-json-editor'),
plumber = require('gulp-plumber'),
prompt = require('gulp-prompt'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
requireDotFile = require('require-dot-file'),
wrench = require('wrench'),
// install config
install = require('./config/project/install'),
// user config
config = require('./config/user'),
// release config (name/title/etc)
release = require('./config/project/release'),
// shorthand
questions = install.questions,
files = install.files,
folders = install.folders,
regExp = install.regExp,
settings = install.settings,
source = install.source
;
// Export install task
module.exports = function () {
var
currentConfig = requireDotFile('semantic.json'),
manager = install.getPackageManager(),
rootQuestions = questions.root
;
console.clear();
/* Test NPM
manager = {
name : 'NPM',
root : path.normalize(__dirname + '/../')
};
*/
/*--------------
PM Config
---------------*/
/* Don't do end user config if SUI is a sub-module */
if( install.isSubModule() ) {
console.info('SUI is a sub-module, skipping end-user install');
return;
}
// run update scripts if semantic.json exists
if(currentConfig && manager.name === 'NPM') {
var
updateFolder = path.join(manager.root, currentConfig.base),
updatePaths = {
config : path.join(manager.root, files.config),
tasks : path.join(updateFolder, folders.tasks),
themeImport : path.join(updateFolder, folders.themeImport),
definition : path.join(currentConfig.paths.source.definitions),
site : path.join(currentConfig.paths.source.site),
theme : path.join(currentConfig.paths.source.themes)
}
;
// duck-type if there is a project installed
if( fs.existsSync(updatePaths.definition) ) {
// perform update if new version
if(currentConfig.version !== release.version) {
console.log('Updating Semantic UI from ' + currentConfig.version + ' to ' + release.version);
console.info('Updating ui definitions...');
wrench.copyDirSyncRecursive(source.definitions, updatePaths.definition, settings.wrench.update);
console.info('Updating default theme...');
wrench.copyDirSyncRecursive(source.themes, updatePaths.theme, settings.wrench.update);
console.info('Updating tasks...');
wrench.copyDirSyncRecursive(source.tasks, updatePaths.tasks, settings.wrench.update);
console.info('Updating gulpfile.js');
gulp.src(source.userGulpFile)
.pipe(plumber())
.pipe(gulp.dest(updateFolder))
;
// copy theme import
console.info('Updating theme import file');
gulp.src(source.themeImport)
.pipe(plumber())
.pipe(gulp.dest(updatePaths.themeImport))
;
console.info('Adding new site theme files...');
wrench.copyDirSyncRecursive(source.site, updatePaths.site, settings.wrench.site);
console.info('Updating version...');
// update version number in semantic.json
gulp.src(updatePaths.config)
.pipe(plumber())
.pipe(rename(settings.rename.json)) // preserve file extension
.pipe(jsonEditor({
version: release.version
}))
.pipe(gulp.dest(manager.root))
;
console.info('Update complete! Run "\033[92mgulp build\033[0m" to rebuild dist/ files.');
return;
}
else {
console.log('Current version of Semantic UI already installed');
return;
}
}
else {
console.error('Cannot locate files to update at path: ', updatePaths.definition);
console.log('Running installer');
}
}
/*--------------
Determine Root
---------------*/
// PM that supports Build Tools (NPM Only Now)
if(manager.name == 'NPM') {
rootQuestions[0].message = rootQuestions[0].message
.replace('{packageMessage}', 'We detected you are using \033[92m' + manager.name + '\033[0m. Nice! ')
.replace('{root}', manager.root)
;
// set default path to detected PM root
rootQuestions[0].default = manager.root;
rootQuestions[1].default = manager.root;
// insert PM questions after "Install Type" question
Array.prototype.splice.apply(questions.setup, [2, 0].concat(rootQuestions));
// omit cleanup questions for managed install
questions.cleanup = [];
}
/*--------------
Set-up
---------------*/
return gulp
.src('gulpfile.js')
.pipe(prompt.prompt(questions.setup, function(answers) {
/*--------------
Exit Conditions
---------------*/
// if config exists and user specifies not to proceed
if(answers.overwrite !== undefined && answers.overwrite == 'no') {
return;
}
console.clear();
console.log('Installing');
console.log('------------------------------');
/*--------------
Paths
---------------*/
var
installPaths = {
config : files.config,
configFolder : folders.config,
site : answers.site || folders.site,
themeConfig : files.themeConfig,
themeConfigFolder : folders.themeConfig
},
installFolder = false
;
/*--------------
PM Install
---------------*/
// Check if PM install
if(answers.useRoot || answers.customRoot) {
// Set root to custom root path if set
if(answers.customRoot) {
if(answers.customRoot === '') {
console.log('Unable to proceed, invalid project root');
return;
}
manager.root = answers.customRoot;
}
// special install paths only for PM install
installPaths = extend(false, {}, installPaths, {
definition : folders.definitions,
lessImport : folders.lessImport,
tasks : folders.tasks,
theme : folders.themes,
themeImport : folders.themeImport
});
// add project root to semantic root
installFolder = path.join(manager.root, answers.semanticRoot);
// add install folder to all output paths
for(var destination in installPaths) {
if( installPaths.hasOwnProperty(destination) ) {
// config goes in project root, rest in install folder
installPaths[destination] = (destination == 'config' || destination == 'configFolder')
? path.normalize( path.join(manager.root, installPaths[destination]) )
: path.normalize( path.join(installFolder, installPaths[destination]) )
;
}
}
// create project folders
try {
mkdirp.sync(installFolder);
mkdirp.sync(installPaths.definition);
mkdirp.sync(installPaths.theme);
mkdirp.sync(installPaths.tasks);
}
catch(error) {
console.error('NPM does not have permissions to create folders at your specified path. Adjust your folders permissions and run "npm install" again');
}
console.log('Installing to \033[92m' + answers.semanticRoot + '\033[0m');
console.info('Copying UI definitions');
wrench.copyDirSyncRecursive(source.definitions, installPaths.definition, settings.wrench.install);
wrench.copyDirSyncRecursive(source.themes, installPaths.theme, settings.wrench.install);
console.info('Copying gulp tasks');
wrench.copyDirSyncRecursive(source.tasks, installPaths.tasks, settings.wrench.install);
// copy theme import
console.info('Adding theme files');
gulp.src(source.themeImport)
.pipe(plumber())
.pipe(gulp.dest(installPaths.themeImport))
;
gulp.src(source.lessImport)
.pipe(plumber())
.pipe(gulp.dest(installPaths.lessImport))
;
// create gulp file
console.info('Creating gulpfile.js');
gulp.src(source.userGulpFile)
.pipe(plumber())
.pipe(gulp.dest(installFolder))
;
}
/*--------------
Site Theme
---------------*/
// Copy _site templates folder to destination
if( fs.existsSync(installPaths.site) ) {
console.info('Site folder exists, merging files (no overwrite)', installPaths.site);
}
else {
console.info('Creating site theme folder', installPaths.site);
}
wrench.copyDirSyncRecursive(source.site, installPaths.site, settings.wrench.site);
/*--------------
Theme Config
---------------*/
var
// determine path to site theme folder from theme config
// force CSS path variable to use forward slashes for paths
pathToSite = path.relative(path.resolve(installPaths.themeConfigFolder), path.resolve(installPaths.site)).replace(/\\/g,'/'),
siteVariable = "@siteFolder : '" + pathToSite + "/';"
;
// rewrite site variable in theme.less
console.info('Adjusting @siteFolder to: ', pathToSite + '/');
if(fs.existsSync(installPaths.themeConfig)) {
console.info('Modifying src/theme.config (LESS config)', installPaths.themeConfig);
gulp.src(installPaths.themeConfig)
.pipe(plumber())
.pipe(replace(regExp.siteVariable, siteVariable))
.pipe(gulp.dest(installPaths.themeConfigFolder))
;
}
else {
console.info('Creating src/theme.config (LESS config)', installPaths.themeConfig);
gulp.src(source.themeConfig)
.pipe(plumber())
.pipe(rename({ extname : '' }))
.pipe(replace(regExp.siteVariable, siteVariable))
.pipe(gulp.dest(installPaths.themeConfigFolder))
;
}
/*--------------
Semantic.json
---------------*/
var
jsonConfig = install.createJSON(answers)
;
// adjust variables in theme.less
if( fs.existsSync(files.config) ) {
console.info('Extending config file (semantic.json)', installPaths.config);
gulp.src(installPaths.config)
.pipe(plumber())
.pipe(rename(settings.rename.json)) // preserve file extension
.pipe(jsonEditor(jsonConfig))
.pipe(gulp.dest(installPaths.configFolder))
;
}
else {
console.info('Creating config file (semantic.json)', installPaths.config);
gulp.src(source.config)
.pipe(plumber())
.pipe(rename({ extname : '' })) // remove .template from ext
.pipe(jsonEditor(jsonConfig))
.pipe(gulp.dest(installPaths.configFolder))
;
}
// Completion Message
if(installFolder) {
console.log('Install complete! Navigate to \033[92m' + answers.semanticRoot + '\033[0m and run "\033[92mgulp build\033[0m" to build');
}
else {
console.log('');
console.log('');
}
}))
.pipe(prompt.prompt(questions.cleanup, function(answers) {
if(answers.cleanup == 'yes') {
del(install.setupFiles);
}
if(answers.build == 'yes') {
gulp.start('build');
}
}))
;
};

View file

@ -0,0 +1,132 @@
/*******************************
Build Task
*******************************/
var
gulp = require('gulp'),
// node dependencies
fs = require('fs'),
// gulp dependencies
autoprefixer = require('gulp-autoprefixer'),
chmod = require('gulp-chmod'),
clone = require('gulp-clone'),
flatten = require('gulp-flatten'),
gulpif = require('gulp-if'),
less = require('gulp-less'),
minifyCSS = require('gulp-minify-css'),
plumber = require('gulp-plumber'),
print = require('gulp-print'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
rtlcss = require('gulp-rtlcss'),
uglify = require('gulp-uglify'),
// user config
config = require('../config/user'),
// install config
tasks = require('../config/project/tasks'),
install = require('../config/project/install'),
// shorthand
globs = config.globs,
assets = config.paths.assets,
output = config.paths.output,
source = config.paths.source,
banner = tasks.banner,
comments = tasks.regExp.comments,
log = tasks.log,
settings = tasks.settings
;
// add internal tasks (concat release)
require('../collections/internal')(gulp);
module.exports = function(callback) {
var
stream,
compressedStream,
uncompressedStream
;
console.info('Building Semantic');
if( !install.isSetup() ) {
console.error('Cannot build files. Run "gulp install" to set-up Semantic');
return;
}
// unified css stream
stream = gulp.src(source.definitions + '/**/' + globs.components + '.less')
.pipe(plumber())
.pipe(less(settings.less))
.pipe(autoprefixer(settings.prefix))
.pipe(rtlcss())
.pipe(replace(comments.variables.in, comments.variables.out))
.pipe(replace(comments.license.in, comments.license.out))
.pipe(replace(comments.large.in, comments.large.out))
.pipe(replace(comments.small.in, comments.small.out))
.pipe(replace(comments.tiny.in, comments.tiny.out))
.pipe(flatten())
;
// two concurrent streams from same source to concat release
uncompressedStream = stream.pipe(clone());
compressedStream = stream.pipe(clone());
uncompressedStream
.pipe(plumber())
.pipe(replace(assets.source, assets.uncompressed))
.pipe(rename(settings.rename.rtlCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package uncompressed rtl css');
})
;
compressedStream = stream
.pipe(plumber())
.pipe(clone())
.pipe(replace(assets.source, assets.compressed))
.pipe(minifyCSS(settings.minify))
.pipe(rename(settings.rename.rtlMinCSS))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
callback();
gulp.start('package compressed rtl css');
})
;
// copy assets
gulp.src(source.themes + '/**/assets/**/' + globs.components + '?(s).*')
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.themes))
;
// copy source javascript
gulp.src(source.definitions + '/**/' + globs.components + '.js')
.pipe(plumber())
.pipe(flatten())
.pipe(replace(comments.license.in, comments.license.out))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.pipe(uglify(settings.uglify))
.pipe(rename(settings.rename.minJS))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed js');
gulp.start('package uncompressed js');
})
;
};

View file

@ -0,0 +1,221 @@
/*******************************
Watch Task
*******************************/
var
gulp = require('gulp'),
// node deps
console = require('better-console'),
fs = require('fs'),
// gulp deps
autoprefixer = require('gulp-autoprefixer'),
chmod = require('gulp-chmod'),
clone = require('gulp-clone'),
gulpif = require('gulp-if'),
less = require('gulp-less'),
minifyCSS = require('gulp-minify-css'),
plumber = require('gulp-plumber'),
print = require('gulp-print'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
rtlcss = require('gulp-rtlcss'),
uglify = require('gulp-uglify'),
util = require('gulp-util'),
watch = require('gulp-watch'),
// user config
config = require('../config/user'),
// task config
tasks = require('../config/project/tasks'),
install = require('../config/project/install'),
// shorthand
globs = config.globs,
assets = config.paths.assets,
output = config.paths.output,
source = config.paths.source,
banner = tasks.banner,
comments = tasks.regExp.comments,
log = tasks.log,
settings = tasks.settings
;
// add internal tasks (concat release)
require('../collections/internal')(gulp);
module.exports = function(callback) {
if( !install.isSetup() ) {
console.error('Cannot watch files. Run "gulp install" to set-up Semantic');
return;
}
console.clear();
console.log('Watching source files for changes');
/*--------------
Watch CSS
---------------*/
gulp
.watch([
source.config,
source.definitions + '/**/*.less',
source.site + '/**/*.{overrides,variables}',
source.themes + '/**/*.{overrides,variables}'
], function(file) {
var
lessPath,
stream,
compressedStream,
uncompressedStream,
isDefinition,
isPackagedTheme,
isSiteTheme,
isConfig
;
// log modified file
gulp.src(file.path)
.pipe(print(log.modified))
;
/*--------------
Find Source
---------------*/
// recompile on *.override , *.variable change
isConfig = (file.path.indexOf('.config') !== -1);
isPackagedTheme = (file.path.indexOf(source.themes) !== -1);
isSiteTheme = (file.path.indexOf(source.site) !== -1);
isDefinition = (file.path.indexOf(source.definitions) !== -1);
if(isConfig) {
console.log('Change detected in theme config');
// cant tell which theme was changed in theme.config, rebuild all
gulp.start('build');
}
else if(isPackagedTheme) {
console.log('Change detected in packaged theme');
lessPath = lessPath.replace(tasks.regExp.theme, source.definitions);
lessPath = util.replaceExtension(file.path, '.less');
}
else if(isSiteTheme) {
console.log('Change detected in site theme');
lessPath = lessPath.replace(source.site, source.definitions);
lessPath = util.replaceExtension(file.path, '.less');
}
else if(isDefinition) {
console.log('Change detected in definition');
lessPath = util.replaceExtension(file.path, '.less');
}
/*--------------
Create CSS
---------------*/
if( fs.existsSync(lessPath) ) {
// unified css stream
stream = gulp.src(lessPath)
.pipe(plumber())
.pipe(less(settings.less))
.pipe(replace(comments.variables.in, comments.variables.out))
.pipe(replace(comments.license.in, comments.license.out))
.pipe(replace(comments.large.in, comments.large.out))
.pipe(replace(comments.small.in, comments.small.out))
.pipe(replace(comments.tiny.in, comments.tiny.out))
.pipe(autoprefixer(settings.prefix))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(rtlcss())
;
// use 2 concurrent streams from same pipe
uncompressedStream = stream.pipe(clone());
compressedStream = stream.pipe(clone());
uncompressedStream
.pipe(plumber())
.pipe(replace(assets.source, assets.uncompressed))
.pipe(rename(settings.rename.rtlCSS))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package uncompressed rtl css');
})
;
compressedStream = stream
.pipe(plumber())
.pipe(replace(assets.source, assets.compressed))
.pipe(minifyCSS(settings.minify))
.pipe(rename(settings.rename.minCSS))
.pipe(rename(settings.rename.rtlMinCSS))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed rtl css');
})
;
}
else {
console.log('Cannot find UI definition at path', lessPath);
}
})
;
/*--------------
Watch JS
---------------*/
gulp
.watch([
source.definitions + '/**/*.js'
], function(file) {
gulp.src(file.path)
.pipe(plumber())
.pipe(replace(comments.license.in, comments.license.out))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.pipe(uglify(settings.uglify))
.pipe(rename(settings.rename.minJS))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed js');
gulp.start('package uncompressed js');
})
;
})
;
/*--------------
Watch Assets
---------------*/
// only copy assets that match component names (or their plural)
gulp
.watch([
source.themes + '/**/assets/**/' + globs.components + '?(s).*'
], function(file) {
// copy assets
gulp.src(file.path, { base: source.themes })
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.themes))
.pipe(print(log.created))
;
})
;
};

View file

@ -0,0 +1,11 @@
/*******************************
Version Task
*******************************/
var
release = require('./config/project/release')
;
module.exports = function(callback) {
console.log(release.title + ' ' + release.version);
};

225
web/semantic/tasks/watch.js Normal file
View file

@ -0,0 +1,225 @@
/*******************************
Watch Task
*******************************/
var
gulp = require('gulp'),
// node dependencies
console = require('better-console'),
fs = require('fs'),
// gulp dependencies
autoprefixer = require('gulp-autoprefixer'),
chmod = require('gulp-chmod'),
clone = require('gulp-clone'),
gulpif = require('gulp-if'),
less = require('gulp-less'),
minifyCSS = require('gulp-minify-css'),
plumber = require('gulp-plumber'),
print = require('gulp-print'),
rename = require('gulp-rename'),
replace = require('gulp-replace'),
uglify = require('gulp-uglify'),
util = require('gulp-util'),
watch = require('gulp-watch'),
// user config
config = require('./config/user'),
// task config
tasks = require('./config/project/tasks'),
install = require('./config/project/install'),
// shorthand
globs = config.globs,
assets = config.paths.assets,
output = config.paths.output,
source = config.paths.source,
banner = tasks.banner,
comments = tasks.regExp.comments,
log = tasks.log,
settings = tasks.settings
;
// add tasks that shouldn't be exposed to end-user
require('./collections/internal')(gulp);
// export task
module.exports = function(callback) {
if( !install.isSetup() ) {
console.error('Cannot watch files. Run "gulp install" to set-up Semantic');
return;
}
// check for right-to-left language
if(config.rtl === true || config.rtl === 'Yes') {
gulp.start('watch-rtl');
return;
}
//console.clear();
console.log('Watching source files for changes');
/*--------------
Watch CSS
---------------*/
gulp
.watch([
source.config,
source.definitions + '/**/*.less',
source.site + '/**/*.{overrides,variables}',
source.themes + '/**/*.{overrides,variables}'
], function(file) {
var
lessPath,
stream,
compressedStream,
uncompressedStream,
isDefinition,
isPackagedTheme,
isSiteTheme,
isConfig
;
// log modified file
gulp.src(file.path)
.pipe(print(log.modified))
;
/*--------------
Find Source
---------------*/
// recompile on *.override , *.variable change
isConfig = (file.path.indexOf('theme.config') !== -1);
isPackagedTheme = (file.path.indexOf(source.themes) !== -1);
isSiteTheme = (file.path.indexOf(source.site) !== -1);
isDefinition = (file.path.indexOf(source.definitions) !== -1);
if(isConfig) {
console.info('Change detected in theme config');
// impossible to tell which file was updated in theme.config, rebuild all
gulp.start('build');
return;
}
else if(isPackagedTheme) {
console.log('Change detected in packaged theme');
lessPath = util.replaceExtension(file.path, '.less');
lessPath = lessPath.replace(tasks.regExp.theme, source.definitions);
}
else if(isSiteTheme) {
console.log('Change detected in site theme');
lessPath = util.replaceExtension(file.path, '.less');
lessPath = lessPath.replace(source.site, source.definitions);
}
else {
console.log('Change detected in definition');
lessPath = file.path;
}
/*--------------
Create CSS
---------------*/
if( fs.existsSync(lessPath) ) {
// unified css stream
stream = gulp.src(lessPath)
.pipe(plumber())
.pipe(less(settings.less))
.pipe(replace(comments.variables.in, comments.variables.out))
.pipe(replace(comments.license.in, comments.license.out))
.pipe(replace(comments.large.in, comments.large.out))
.pipe(replace(comments.small.in, comments.small.out))
.pipe(replace(comments.tiny.in, comments.tiny.out))
.pipe(autoprefixer(settings.prefix))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
;
// use 2 concurrent streams from same pipe
uncompressedStream = stream.pipe(clone());
compressedStream = stream.pipe(clone());
uncompressedStream
.pipe(plumber())
.pipe(replace(assets.source, assets.uncompressed))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package uncompressed css');
})
;
compressedStream = stream
.pipe(plumber())
.pipe(replace(assets.source, assets.compressed))
.pipe(minifyCSS(settings.minify))
.pipe(rename(settings.rename.minCSS))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed css');
})
;
}
else {
console.log('Cannot find UI definition at path', lessPath);
}
})
;
/*--------------
Watch JS
---------------*/
gulp
.watch([
source.definitions + '/**/*.js'
], function(file) {
gulp.src(file.path)
.pipe(plumber())
.pipe(replace(comments.license.in, comments.license.out))
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.uncompressed))
.pipe(print(log.created))
.pipe(uglify(settings.uglify))
.pipe(rename(settings.rename.minJS))
.pipe(gulp.dest(output.compressed))
.pipe(print(log.created))
.on('end', function() {
gulp.start('package compressed js');
gulp.start('package uncompressed js');
})
;
})
;
/*--------------
Watch Assets
---------------*/
// only copy assets that match component names (or their plural)
gulp
.watch([
source.themes + '/**/assets/**/' + globs.components + '?(s).*'
], function(file) {
// copy assets
gulp.src(file.path, { base: source.themes })
.pipe(gulpif(config.hasPermission, chmod(config.permission)))
.pipe(gulp.dest(output.themes))
.pipe(print(log.created))
;
})
;
};