Move the builder page to the main branch.

master
Artem Sapegin 2016-01-10 19:11:24 +01:00
parent 378bc28ea3
commit 1e3cb062ee
102 changed files with 17289 additions and 20 deletions

5
.gitignore vendored
View File

@ -1 +1,6 @@
node_modules
gh-pages/public/social-likes
gh-pages/public/build
gh-pages/public/src
gh-pages/public/index.html
gh-pages/public/ru/index.html

File diff suppressed because one or more lines are too long

23
gh-pages/.jshintrc Normal file
View File

@ -0,0 +1,23 @@
{
"browser": true,
"jquery": true,
"white": false,
"smarttabs": true,
"eqeqeq": true,
"immed": true,
"latedef": false,
"newcap": true,
"undef": true,
"trailing": true,
"esnext": true,
"camelcase": true,
"bitwise": true,
"noempty": true,
"unused": "vars",
"strict": true,
"globals": {
"Modernizr": false,
"tamia": false,
"Component": false
}
}

182
gh-pages/Gruntfile.js Normal file
View File

@ -0,0 +1,182 @@
module.exports = function(grunt) {
'use strict';
grunt.file.expand('../node_modules/grunt-*/tasks').forEach(grunt.loadTasks);
var debug = !!grunt.option('debug');
var prefix = debug ? '' : '/social-likes/';
grunt.initConfig({
pkg: grunt.file.readJSON('../package.json'),
banner: '/* Author: Artem Sapegin, http://sapegin.me, <%= grunt.template.today("yyyy") %> */\n',
modernizr: {
main: {
devFile: 'vendor/modernizr.js',
outputFile: 'public/build/modernizr.js',
dest: 'public/build/modernizr.js',
extra: {
load: false
},
files: {
src: ['public/build/scripts.js', 'public/build/styles.css']
}
}
},
jshint: {
all: ['js/main.js']
},
concat: {
main: {
src: [
'js/mylibs/htmlhl.js',
'js/libs/doT.min.js',
'js/libs/jszip.js',
'js/libs/jszip-deflate.js',
'js/libs/store+json2.min.js',
'tamia/vendor/*.js',
'tamia/tamia/tamia.js',
'js/main.js'
],
dest: 'public/build/scripts.js'
}
},
uglify: {
main: {
options: {
banner: '<%= banner %>',
compress: {
global_defs: {
DEBUG: debug
}
}
},
files: {
'<%= concat.main.dest %>': '<%= concat.main.dest %>'
}
}
},
stylus: {
options: {
'include css': true,
urlfunc: 'embedurl',
banner: '<%= banner %>',
define: {
DEBUG: debug
},
paths: ['tamia'],
use: [
function() {
return (require('autoprefixer-stylus'))({browsers: ['last 2 versions', 'ie 8', 'ie 9']});
}, debug || (require('csso-stylus'))
]
},
compile: {
files: {
'public/build/styles.css': 'styles/index.styl'
}
}
},
sweet: {
content_dir: 'content',
publish_dir: 'public',
templates_dir: 'templates',
default_template_id: 'template',
langs: ['ru', 'en'],
root_lang: 'en',
url_prefixes: {
ru: prefix + 'ru/',
en: prefix
},
uri_prefixes: {
ru: prefix + 'ru/',
en: prefix
},
files: {
modernizr: {
path: 'public/build/modernizr.js',
href: prefix + 'build/modernizr.js?{version}'
},
css: {
path: 'public/build/styles.css',
href: prefix + 'build/styles.css?{version}'
},
js: {
path: '<%= concat.main.dest %>',
href: prefix + 'build/scripts.js?{version}'
},
sljs: {
path: 'public/src/social-likes.min.js',
href: prefix + 'src/social-likes.min.js?{version}'
},
slcss_classic: {
path: 'public/src/social-likes_classic.css',
href: prefix + 'src/social-likes_classic.css?{version}'
},
slcss_flat: {
path: 'public/src/social-likes_flat.css',
href: prefix + 'src/social-likes_flat.css?{version}'
},
slcss_birman: {
path: 'public/src/social-likes_birman.css',
href: prefix + 'src/social-likes_birman.css?{version}'
}
}
},
replace: {
version: {
files: {
'public/index.html': 'public/index.html',
'public/ru/index.html': 'public/ru/index.html'
},
options: {
patterns: [
{
match: /(<!\-\-VERSION\-\->).*?(<!\-\-\/VERSION\-\->)/,
replacement: '$1<%= pkg.version %>$2'
}
]
}
}
},
connect: {
server: {
options: {
port: 9000,
base: '.'
}
}
},
watch: {
livereload: {
options: {
livereload: true
},
files: ['<%= concat.main.dest %>', 'public/build/styles.css']
},
concat: {
options: {
atBegin: true
},
files: '<%= concat.main.src %>',
tasks: 'concat'
},
stylus: {
options: {
atBegin: true
},
files: 'styles/**',
tasks: 'stylus'
},
sweet: {
options: {
atBegin: true
},
files: ['content/**', 'templates/**'],
tasks: 'sweet'
}
}
}
);
return grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'stylus', 'modernizr', 'sweet', 'replace']);
};

View File

@ -0,0 +1,41 @@
{
"sites": [
{
"id": "facebook",
"name": "Facebook",
"checked": true
},
{
"id": "twitter",
"name": "Twitter",
"checked": true
},
{
"id": "plusone",
"name": "Google+",
"checked": true
},
{
"id": "mailru",
"name": "Мой мир",
"checked": true,
"langs": ["ru"]
},
{
"id": "vkontakte",
"name": "Вконтакте",
"checked": true,
"langs": ["ru"]
},
{
"id": "odnoklassniki",
"checked": true,
"name": "Одноклассники",
"langs": ["ru"]
},
{
"id": "pinterest",
"name": "Pinterest"
}
]
}

View File

@ -0,0 +1,40 @@
name: Social Likes
title: Social Likes: beautiful social like buttons with jQuery
description: Single style social like buttons with counters for jQuery: Facebook, Twitter, Google+, Pinterest and also popular <a href="/social-likes/ru/">Russian social networks</a>.
descriptionHead: Single style buttons with like counters: Facebook, Twitter, Google+, Pinterest and also popular Russian social networks.
translationLink: /social-likes/ru/
translationTitle: По-русски
builderSkin: Skin
builderSkinClassic: Classic
builderSkinFlat: Flat β
builderSkinBirman: Birman β
builderType: Look
builderTypeHorizontal: Horizontal
builderTypeVertical: Vertical
builderTypeSingle: Single button
builderCounters: Show counters
builderLight: Light style
builderSites: Websites
builderUrl: URL
builderUrlHelp: When buttons used on different page
builderTitle: Title
builderTitleHelp: When differs from current pages title
builderTwitterVia: Twitter Via
builderTwitterViaHelp: Username
builderTwitterRelated: Twitter Related
builderTwitterRelatedHelp: Username:Description
builderPinterestMedia: Image URL
builderPinterestMediaHelp: Image URL for Pinterest (required)
titleFacebook: Share link on Facebook
titleTwitter: Share link on Twitter
titlePlusone: Share link on Google+
titlePinterest: Share image on Pinterest
singleTitle: Share
downloadArchive: Download the Buttons
or: or
browseCode: view source
onGitHub: on GitHub
archiveContains: Version <a href="https://github.com/sapegin/social-likes/blob/master/Changelog.md"><!--VERSION--><!--/VERSION--></a>. Archive contains all you need to use like buttons with chosen options.
archiveFooter: <a href="http://sapegin.github.com/social-likes/">Social Likes</a> — <a href="https://github.com/sapegin/social-likes/Readme.md">documentation</a>
docs: <a href="https://github.com/sapegin/social-likes/blob/master/Readme.md">Documentation</a> and advanced customization examples.<br>Report bugs <a href="https://github.com/sapegin/social-likes/issues">on GitHub</a>.
footer: © 2014 <a href="https://github.com/sapegin">Artem Sapegin</a> and contributors. Flat skin: <a href="http://genn.org/">Genn Osypenko</a>, Birman skin: <a href="http://ilyabirman.net/">Ilya Birman</a>

View File

@ -0,0 +1,39 @@
name: Social Likes
title: Social Likes — красивые кнопки «лайков» социальных сетей с использованием jQuery
description: Красивые кнопки «лайков» со счётчиками в едином стиле для социальных сетей: Facebook, Twitter, Вконтакте, Одноклассники, Мой мир, Google+ и Pinterest. Кнопки уже используют <a href="http://www.snob.ru/">Сноб</a>, <a href="http://sberbank.ru/">Сбербанк</a>, <a href="http://blogengine.ru/blogs/">блоги на Эгее</a> и&nbsp;многие другие.
translationLink: /social-likes/
translationTitle: In English
builderSkin: Скин
builderSkinClassic: Классический
builderSkinFlat: Плоский β
builderSkinBirman: Бирман β
builderType: Вид
builderTypeHorizontal: Горизонтальный
builderTypeVertical: Вертикальный
builderTypeSingle: Одной кнопкой
builderCounters: Счётчики
builderLight: Лёгкий стиль
builderSites: Сайты
builderUrl: Адрес страницы
builderUrlHelp: Если отличается от адреса страницы, где размещены кнопки
builderTitle: Название
builderTitleHelp: Если отличается от заголовка страницы, где размещены кнопки
builderTwitterVia: Twitter Via
builderTwitterViaHelp: Имя в Твиттере
builderTwitterRelated: Twitter Related
builderTwitterRelatedHelp: Имя:Описание
builderPinterestMedia: URL картинки
builderPinterestMediaHelp: URL картинки для Пинтереста (обязательно)
titleFacebook: Поделиться ссылкой на Фейсбуке
titleTwitter: Поделиться ссылкой в Твиттере
titlePlusone: Поделиться ссылкой в Гугл-плюсе
titlePinterest: Поделиться картинкой на Пинтересте
singleTitle: Поделиться
downloadArchive: Скачать кнопки
or: или
browseCode: посмотреть код
onGitHub: на Гитхабе
archiveContains: Версия <a href="https://github.com/sapegin/social-likes/blob/master/Changelog.md"><!--VERSION--><!--/VERSION--></a>. В архиве есть всё необходимое для подключения кнопок с выбранными параметрами.
archiveFooter: <a href="http://sapegin.github.com/social-likes/">Social Likes</a> — <a href="https://github.com/sapegin/social-likes/Readme.md">документация</a>
docs: <a href="https://github.com/sapegin/social-likes/blob/master/Readme.md">Документация</a>, примеры настройки и расширения.<br>Об ошибках пишите <a href="https://github.com/sapegin/social-likes/issues">на Гитхаб</a>.
footer: © 2014 <a href="https://github.com/sapegin">Артём Сапегин</a> и другие. Плоский скин: <a href="http://genn.org/">Гена Осипенко</a>, скин Бирмана: <a href="http://ilyabirman.ru/">Илья Бирман</a>

BIN
gh-pages/img/noise.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

7
gh-pages/js/libs/doT.min.js vendored Normal file
View File

@ -0,0 +1,7 @@
// Laura Doktorova https://github.com/olado/doT
(function(){function o(){var b={"&":"&#38;","<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","/":"&#47;"},a=/&(?!#?\w+;)|<|>|"|'|\//g;return function(f){return f?f.toString().replace(a,function(g){return b[g]||g}):f}}function p(b,a,f){return(typeof a==="string"?a:a.toString()).replace(b.define||h,function(g,e,c,i){if(e.indexOf("def.")===0)e=e.substring(4);if(!(e in f))if(c===":")f[e]=i;else eval("def['"+e+"']="+i);return""}).replace(b.use||h,function(g,e){var c=eval(e);return c?p(b,c,f):c})}function l(b){return b.replace(/\\('|\\)/g,
"$1").replace(/[\r\t\n]/g," ")}var j={version:"0.2.0",templateSettings:{evaluate:/\{\{([\s\S]+?)\}\}/g,interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:true,append:true,selfcontained:false},template:undefined,compile:undefined},m=function(){return this||(0,eval)("this")}();
if(typeof module!=="undefined"&&module.exports)module.exports=j;else if(typeof define==="function"&&define.amd)define(function(){return j});else m.doT=j;m.encodeHTML=o();var q={append:{start:"'+(",end:")+'",startencode:"'+encodeHTML("},split:{start:"';out+=(",end:");out+='",startencode:"';out+=encodeHTML("}},h=/$^/;j.template=function(b,a,f){a=a||j.templateSettings;var g=a.append?q.append:q.split,e,c=0,i;if(a.use||a.define){var r=m.def;m.def=f||{};b=p(a,b,m.def);m.def=r}b=("var out='"+(a.strip?b.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,
" ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):b).replace(/'|\\/g,"\\$&").replace(a.interpolate||h,function(n,d){return g.start+l(d)+g.end}).replace(a.encode||h,function(n,d){e=true;return g.startencode+l(d)+g.end}).replace(a.conditional||h,function(n,d,k){return d?k?"';}else if("+l(k)+"){out+='":"';}else{out+='":k?"';if("+l(k)+"){out+='":"';}out+='"}).replace(a.iterate||h,function(n,d,k,s){if(!d)return"';} } out+='";c+=1;i=s||"i"+c;d=l(d);return"';var arr"+c+"="+d+";if(arr"+c+"){var "+k+","+i+"=-1,l"+
c+"=arr"+c+".length-1;while("+i+"<l"+c+"){"+k+"=arr"+c+"["+i+"+=1];out+='"}).replace(a.evaluate||h,function(n,d){return"';"+l(d)+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|}|^|{)out\+='';/g,"$1").replace(/\+''/g,"").replace(/(\s|;|}|^|{)out\+=''\+/g,"$1out+=");if(e&&a.selfcontained)b="var encodeHTML=("+o.toString()+"());"+b;try{return new Function(a.varname,b)}catch(t){typeof console!=="undefined"&&console.log("Could not create a template function: "+
b);throw t;}};j.compile=function(b,a){return j.template(b,null,a)}})();

2
gh-pages/js/libs/jquery-1.8.2.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

735
gh-pages/js/libs/jszip.js Normal file
View File

@ -0,0 +1,735 @@
/**
JSZip - A Javascript class for generating and reading zip files
<http://stuartk.com/jszip>
(c) 2009-2012 Stuart Knightley <stuart [at] stuartk.com>
Dual licenced under the MIT license or GPLv3. See LICENSE.markdown.
Usage:
zip = new JSZip();
zip.file("hello.txt", "Hello, World!").add("tempfile", "nothing");
zip.folder("images").file("smile.gif", base64Data, {base64: true});
zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")});
zip.remove("tempfile");
base64zip = zip.generate();
**/
/**
* Representation a of zip file in js
* @constructor
* @param {String=} data the data to load, if any (optional).
* @param {Object=} options the options for creating this objects (optional).
*/
var JSZip = function(data, options) {
// object containing the files :
// {
// "folder/" : {...},
// "folder/data.txt" : {...}
// }
this.files = {};
// Where we are in the hierarchy
this.root = "";
if(data) {
this.load(data, options);
}
};
JSZip.signature = {
LOCAL_FILE_HEADER : "\x50\x4b\x03\x04",
CENTRAL_FILE_HEADER : "\x50\x4b\x01\x02",
CENTRAL_DIRECTORY_END : "\x50\x4b\x05\x06",
ZIP64_CENTRAL_DIRECTORY_LOCATOR : "\x50\x4b\x06\x07",
ZIP64_CENTRAL_DIRECTORY_END : "\x50\x4b\x06\x06",
DATA_DESCRIPTOR : "\x50\x4b\x07\x08"
};
// Default properties for a new file
JSZip.defaults = {
base64: false,
binary: false,
dir: false,
date: null
};
JSZip.prototype = (function ()
{
/**
* A simple object representing a file in the zip file.
* @constructor
* @param {string} name the name of the file
* @param {string} data the data
* @param {Object} options the options of the file
*/
var ZipObject = function (name, data, options) {
this.name = name;
this.data = data;
this.options = options;
};
ZipObject.prototype = {
/**
* Return the content as UTF8 string.
* @return {string} the UTF8 string.
*/
asText : function ()
{
return this.options.binary ? JSZip.prototype.utf8decode(this.data) : this.data;
},
/**
* Returns the binary content.
* @return {string} the content as binary.
*/
asBinary : function ()
{
return this.options.binary ? this.data : JSZip.prototype.utf8encode(this.data);
}
};
/**
* Transform an integer into a string in hexadecimal.
* @private
* @param {number} dec the number to convert.
* @param {number} bytes the number of bytes to generate.
* @returns {string} the result.
*/
var decToHex = function(dec, bytes) {
var hex = "", i;
for(i = 0; i < bytes; i++)
{
hex += String.fromCharCode(dec&0xff);
dec=dec>>>8;
}
return hex;
};
/**
* Merge the objects passed as parameters into a new one.
* @private
* @param {...Object} var_args All objects to merge.
* @return {Object} a new object with the data of the others.
*/
var extend = function () {
var result = {}, i, attr;
for (i = 0; i < arguments.length; i++) // arguments is not enumerable in some browsers
{
for (attr in arguments[i])
{
if(typeof result[attr] === "undefined")
{
result[attr] = arguments[i][attr];
}
}
}
return result;
};
/**
* Transforms the (incomplete) options from the user into the complete
* set of options to create a file.
* @private
* @param {Object} o the options from the user.
* @return {Object} the complete set of options.
*/
var prepareFileAttrs = function (o) {
o = o || {};
if (o.base64 === true && o.binary == null) {
o.binary = true;
}
o = extend(o, JSZip.defaults);
o.date = o.date || new Date();
return o;
};
/**
* Add a file in the current folder.
* @private
* @param {string} name the name of the file
* @param {string} data the data of the file
* @param {Object} o the options of the file
* @return {Object} the new file.
*/
var fileAdd = function (name, data, o) {
// be sure sub folders exist
var parent = parentFolder(name);
if (parent) {
folderAdd.call(this, parent);
}
o = prepareFileAttrs(o);
return this.files[name] = {name: name, data: data, options:o};
};
/**
* Find the parent folder of the path.
* @private
* @param {string} path the path to use
* @return {string} the parent folder, or ""
*/
var parentFolder = function (path) {
if (path.slice(-1) == '/')
{
path = path.substring(0, path.length - 1);
}
var lastSlash = path.lastIndexOf('/');
return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
};
/**
* Add a (sub) folder in the current folder.
* @private
* @param {string} name the folder's name
* @return {Object} the new folder.
*/
var folderAdd = function (name) {
// Check the name ends with a /
if (name.slice(-1) != "/") {
name += "/"; // IE doesn't like substr(-1)
}
// Does this folder already exist?
if (!this.files[name])
{
// be sure sub folders exist
var parent = parentFolder(name);
if (parent) {
folderAdd.call(this, parent);
}
fileAdd.call(this, name, '', {dir:true});
}
return this.files[name];
};
/**
* Generate the data found in the local header of a zip file.
* Do not create it now, as some parts are re-used later.
* @private
* @param {Object} file the file to use.
* @param {string} utfEncodedFileName the file name, utf8 encoded.
* @param {string} compressionType the compression to use.
* @return {Object} an object containing header and compressedData.
*/
var prepareLocalHeaderData = function(file, utfEncodedFileName, compressionType) {
var useUTF8 = utfEncodedFileName !== file.name,
data = file.data,
o = file.options,
dosTime,
dosDate;
// date
// @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
// @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
// @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
dosTime = o.date.getHours();
dosTime = dosTime << 6;
dosTime = dosTime | o.date.getMinutes();
dosTime = dosTime << 5;
dosTime = dosTime | o.date.getSeconds() / 2;
dosDate = o.date.getFullYear() - 1980;
dosDate = dosDate << 4;
dosDate = dosDate | (o.date.getMonth() + 1);
dosDate = dosDate << 5;
dosDate = dosDate | o.date.getDate();
if (o.base64 === true) {
data = JSZipBase64.decode(data);
}
// decode UTF-8 strings if we are dealing with text data
if(o.binary === false) {
data = this.utf8encode(data);
}
var compression = JSZip.compressions[compressionType];
var compressedData = compression.compress(data);
var header = "";
// version needed to extract
header += "\x0A\x00";
// general purpose bit flag
// set bit 11 if utf8
header += useUTF8 ? "\x00\x08" : "\x00\x00";
// compression method
header += compression.magic;
// last mod file time
header += decToHex(dosTime, 2);
// last mod file date
header += decToHex(dosDate, 2);
// crc-32
header += decToHex(this.crc32(data), 4);
// compressed size
header += decToHex(compressedData.length, 4);
// uncompressed size
header += decToHex(data.length, 4);
// file name length
header += decToHex(utfEncodedFileName.length, 2);
// extra field length
header += "\x00\x00";
return {
header:header,
compressedData:compressedData
};
};
// return the actual prototype of JSZip
return {
/**
* Read an existing zip and merge the data in the current JSZip object.
* The implementation is in jszip-load.js, don't forget to include it.
* @param {string} stream The stream to load
* @param {Object} options Options for loading the stream.
* options.base64 : is the stream in base64 ? default : false
* @return {JSZip} the current JSZip object
*/
load : function (stream, options)
{
throw new Error("Load method is not defined. Is the file jszip-load.js included ?");
},
/**
* Filter nested files/folders with the specified function.
* @param {Function} search the predicate to use :
* function (relativePath, file) {...}
* It takes 2 arguments : the relative path and the file.
* @return {Array} An array of matching elements.
*/
filter : function (search)
{
var result = [], filename, relativePath, file, fileClone;
for (filename in this.files)
{
file = this.files[filename];
// return a new object, don't let the user mess with our internal objects :)
fileClone = new ZipObject(file.name, file.data, extend(file.options));
relativePath = filename.slice(this.root.length, filename.length);
if (filename.slice(0, this.root.length) === this.root && // the file is in the current root
search(relativePath, fileClone)) // and the file matches the function
{
result.push(fileClone);
}
}
return result;
},
/**
* Add a file to the zip file, or search a file.
* @param {string|RegExp} name The name of the file to add (if data is defined),
* the name of the file to find (if no data) or a regex to match files.
* @param {string} data The file data, either raw or base64 encoded
* @param {Object} o File options
* @return {JSZip|Object|Array} this JSZip object (when adding a file),
* a file (when searching by string) or an array of files (when searching by regex).
*/
file : function(name, data, o)
{
if (arguments.length === 1)
{
if (name instanceof RegExp)
{
var regexp = name;
return this.filter(function(relativePath, file) {
return !file.options.dir && regexp.test(relativePath);
});
}
else // text
{
return this.filter(function (relativePath, file) {
return !file.options.dir && relativePath === name;
})[0]||null;
}
}
else // more than one argument : we have data !
{
name = this.root+name;
fileAdd.call(this, name, data, o);
}
return this;
},
/**
* Add a directory to the zip file, or search.
* @param {String|RegExp} arg The name of the directory to add, or a regex to search folders.
* @return {JSZip} an object with the new directory as the root, or an array containing matching folders.
*/
folder : function(arg)
{
if (!arg)
{
throw new Error("folder : wrong argument");
}
if (arg instanceof RegExp)
{
return this.filter(function(relativePath, file) {
return file.options.dir && arg.test(relativePath);
});
}
// else, name is a new folder
var name = this.root + arg;
var newFolder = folderAdd.call(this, name);
// Allow chaining by returning a new object with this folder as the root
var ret = this.clone();
ret.root = newFolder.name;
return ret;
},
/**
* Delete a file, or a directory and all sub-files, from the zip
* @param {string} name the name of the file to delete
* @return {JSZip} this JSZip object
*/
remove : function(name)
{
name = this.root + name;
var file = this.files[name];
if (!file)
{
// Look for any folders
if (name.slice(-1) != "/") {
name += "/";
}
file = this.files[name];
}
if (file)
{
if (!file.options.dir)
{
// file
delete this.files[name];
}
else
{
// folder
var kids = this.filter(function (relativePath, file) {
return file.name.slice(0, name.length) === name;
});
for (var i = 0; i < kids.length; i++)
{
delete this.files[kids[i].name];
}
}
}
return this;
},
/**
* Generate the complete zip file
* @param {Object} options the options to generate the zip file :
* - base64, true to generate base64.
* - compression, "STORE" by default.
* @return {string} the zip file
*/
generate : function(options)
{
options = extend(options || {}, {
base64 : true,
compression : "STORE"
});
var compression = options.compression.toUpperCase();
// The central directory, and files data
var directory = [], files = [], fileOffset = 0;
if (!JSZip.compressions[compression]) {
throw compression + " is not a valid compression method !";
}
for (var name in this.files)
{
if( !this.files.hasOwnProperty(name) ) { continue; }
var file = this.files[name];
var utfEncodedFileName = this.utf8encode(file.name);
var fileRecord = "",
dirRecord = "",
data = prepareLocalHeaderData.call(this, file, utfEncodedFileName, compression);
fileRecord = JSZip.signature.LOCAL_FILE_HEADER + data.header + utfEncodedFileName + data.compressedData;
dirRecord = JSZip.signature.CENTRAL_FILE_HEADER +
// version made by (00: DOS)
"\x14\x00" +
// file header (common to file and central directory)
data.header +
// file comment length
"\x00\x00" +
// disk number start
"\x00\x00" +
// internal file attributes TODO
"\x00\x00" +
// external file attributes
(this.files[name].dir===true?"\x10\x00\x00\x00":"\x00\x00\x00\x00")+
// relative offset of local header
decToHex(fileOffset, 4) +
// file name
utfEncodedFileName;
fileOffset += fileRecord.length;
files.push(fileRecord);
directory.push(dirRecord);
}
var fileData = files.join("");
var dirData = directory.join("");
var dirEnd = "";
// end of central dir signature
dirEnd = JSZip.signature.CENTRAL_DIRECTORY_END +
// number of this disk
"\x00\x00" +
// number of the disk with the start of the central directory
"\x00\x00" +
// total number of entries in the central directory on this disk
decToHex(files.length, 2) +
// total number of entries in the central directory
decToHex(files.length, 2) +
// size of the central directory 4 bytes
decToHex(dirData.length, 4) +
// offset of start of central directory with respect to the starting disk number
decToHex(fileData.length, 4) +
// .ZIP file comment length
"\x00\x00";
var zip = fileData + dirData + dirEnd;
return (options.base64) ? JSZipBase64.encode(zip) : zip;
},
/**
*
* Javascript crc32
* http://www.webtoolkit.info/
*
*/
crc32 : function(str, crc)
{
if (str === "" || typeof str === "undefined") {
return 0;
}
var table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D";
if (typeof(crc) == "undefined") { crc = 0; }
var x = 0;
var y = 0;
crc = crc ^ (-1);
for( var i = 0, iTop = str.length; i < iTop; i++ ) {
y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
x = "0x" + table.substr( y * 9, 8 );
crc = ( crc >>> 8 ) ^ x;
}
return crc ^ (-1);
},
// Inspired by http://my.opera.com/GreyWyvern/blog/show.dml/1725165
clone : function()
{
var newObj = new JSZip();
for (var i in this)
{
if (typeof this[i] !== "function")
{
newObj[i] = this[i];
}
}
return newObj;
},
/**
* http://www.webtoolkit.info/javascript-utf8.html
*/
utf8encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
/**
* http://www.webtoolkit.info/javascript-utf8.html
*/
utf8decode : function (utftext) {
var string = "";
var i = 0;
var c = 0, c1 = 0, c2 = 0, c3 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
};
}());
/*
* Compression methods
* This object is filled in as follow :
* name : {
* magic // the 2 bytes indentifying the compression method
* compress // function, take the uncompressed content and return it compressed.
* uncompress // function, take the compressed content and return it uncompressed.
* }
*
* STORE is the default compression method, so it's included in this file.
* Other methods should go to separated files : the user wants modularity.
*/
JSZip.compressions = {
"STORE" : {
magic : "\x00\x00",
compress : function (content)
{
return content; // no compression
},
uncompress : function (content)
{
return content; // no compression
}
}
};
/**
*
* Base64 encode / decode
* http://www.webtoolkit.info/
*
* Hacked so that it doesn't utf8 en/decode everything
**/
var JSZipBase64 = (function() {
// private property
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
// public method for encoding
encode : function(input, utf8) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode : function(input, utf8) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
return output;
}
};
}());
// enforcing Stuk's coding style
// vim: set shiftwidth=3 softtabstop=3:

2
gh-pages/js/libs/store+json2.min.js vendored Normal file

File diff suppressed because one or more lines are too long

258
gh-pages/js/main.js Normal file
View File

@ -0,0 +1,258 @@
/* Author: Artem Sapegin, http://sapegin.me, 2012 */
/*global tamia:false, doT:true, htmlhl:false, JSZip:false, store:false */
;(function ($) {
'use strict';
$.extend(doT.templateSettings, {
strip: false,
varname: '$'
});
var lang = $('html').attr('lang'),
skins = ['flat', 'classic', 'birman'],
skin = 'classic',
downloadData = {
lang: lang,
jquery_ver: jQuery.fn.jquery,
footer: $('#index_footer_tmpl').html(),
html: '',
skin: skin
},
prefix = location.hostname === '127.0.0.1' ? '' : '/social-likes/',
sourceFiles = {
'social-likes.min.js': {url: prefix + 'src/social-likes.min.js'},
'social-likes_{skin}.css': {url: prefix + 'src/social-likes_{skin}.css'}
},
templateIndex = doT.template($('#index_tmpl').html().replace(/\\\//g, '/')),
experimental = location.hash === '#ponies',
// simple = !('download' in document.createElement('a'));
simple = true; // Because of bug in Chrome 35: https://code.google.com/p/chromium/issues/detail?id=377860
// stackoverflow.com/questions/1184624/convert-form-data-to-js-object-with-jquery
$.fn.serializeObject = function() {
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
// jasonwyatt.tumblr.com/post/10481498815/how-to-correctly-debounce-a-javascript-function
function debounce(fn, debounceDuration){
// summary:
// Returns a debounced function that will make sure the given
// function is not triggered too much.
// fn: Function
// Function to debounce.
// debounceDuration: Number
// OPTIONAL. The amount of time in milliseconds for which we
// will debounce the function. (defaults to 100ms)
debounceDuration = debounceDuration || 100;
return function(){
if (!fn.debouncing) {
fn.debouncing = true;
}
clearTimeout(fn.debounceTimeout);
var args = Array.prototype.slice.apply(arguments);
fn.debounceTimeout = setTimeout(function() {
fn.lastReturnVal = fn.apply(window, args);
fn.debouncing = false;
}, debounceDuration);
return fn.lastReturnVal;
};
}
function escapeValue(value) {
return value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
;
}
function escapeFormData(data) {
var fields = ['url', 'title', 'twitter_via', 'twitter_related', 'pinterest_media'];
for (var fieldIdx = 0; fieldIdx < fields.length; fieldIdx++) {
var field = fields[fieldIdx];
data[field] = escapeValue(data[field]);
}
return data;
}
function fillForm(form, data) {
jQuery.each(data, function(name, value) {
var field = form.find('[name="' + name + '"]'),
type = field.attr('type');
switch (type) {
case 'checkbox':
field.prop('checked', !!value);
break;
case 'radio':
field.filter('[value="' + value + '"]').prop('checked', true);
break;
default:
field.val(value);
break;
}
});
}
function cleanHtml(code) {
return code
.replace(/\n[\n\t]*\n/g, '\n') // Remove empty lines
.replace(/ {2,}/g, ' ') // Remove extra spaces
;
}
function highlight(code) {
return htmlhl(code.replace(/\\\//g, '/'));
}
function download(e) {
var files = getFiles();
var zip = new JSZip();
zip.file('index.html', templateIndex(downloadData));
for (var fileName in files) {
zip.file(fileName, files[fileName]);
}
var content = zip.generate();
if (simple) {
var form = $('#download-proxy'),
field = form.find('[name="content"]');
field.val(content);
form.submit();
return false;
}
else {
$(e.target).attr('href', 'data:application/zip;base64,' + content);
}
}
function getFiles() {
var files = {};
for (var fileName in sourceFiles) {
files[getFilenameForSkin(fileName)] = getFile(fileName);
}
return files;
}
function getFile(fileName) {
var file = sourceFiles[fileName];
var url = getFilenameForSkin(file.url);
if (!file.files) file.files = {};
if (!file.files[url]) {
$.ajax(url, { async: false, dataType: 'html' }).then(function(data) {
file.files[url] = data;
});
}
return file.files[url];
}
function getFilenameForSkin(fileName) {
return fileName.replace('{skin}', skin);
}
tamia.initComponents({
builder: function(elem) {
var form = $(elem),
preview = $('.js-preview'),
code = $('.js-code'),
twitterExtra = form.find('.js-twitter-extra'),
pinterestExtra = form.find('.js-pinterest-extra'),
lightStyle = form.find('.js-light'),
prepend = doT.template($('#prepend_tmpl').html()),
template = doT.template($('#build_tmpl').html()),
previous;
var delayedUpdate = debounce(function(html, data) {
// Switch skin
skin = data.skin;
$.each(skins, function(i, s) {
$('#styles_' + s).prop('disabled', s !== skin);
});
// Render preview
preview.attr('class', preview.attr('class').replace(/(preview_)\w+/, '$1' + data.type));
preview.html(html);
preview.find('.social-likes').socialLikes();
form.find('.js-experimental').toggleClass('is-hidden', !experimental);
store.set(lang, {
skin: skin,
type: data.type,
counters: !!data.counters,
light: !!data.light,
title: data.title,
url: data.url,
site_facebook: !!data.site_facebook,
site_mailru: !!data.site_mailru,
site_odnoklassniki: !!data.site_odnoklassniki,
site_plusone: !!data.site_plusone,
site_twitter: !!data.site_twitter,
site_pinterest: !!data.site_pinterest,
site_vkontakte: !!data.site_vkontakte,
twitter_related: data.twitter_related,
twitter_via: data.twitter_via,
pinterest_media: data.pinterest_media
});
});
var loadOptions = function() {
var data = store.get(lang);
if (data) fillForm(form, data);
};
function update() {
var dataString = form.serialize();
if (dataString !== previous) {
var data = escapeFormData(form.serializeObject());
data.experimental = experimental;
twitterExtra.toggleClass('is-hidden', data.site_twitter !== '1');
pinterestExtra.toggleClass('is-hidden', data.site_pinterest !== '1');
lightStyle.toggleClass('is-hidden', data.skin !== 'flat');
var html = cleanHtml(template(data));
code.html(highlight(prepend(data) + html));
delayedUpdate(html, data);
downloadData.html = html;
downloadData.skin = data.skin;
previous = dataString;
}
}
loadOptions();
form.on('change input', 'input', update);
update();
form.submit(function() {
return false;
});
$('.js-download').click(download);
}
});
}(jQuery));

View File

@ -0,0 +1,72 @@
/* Author: Artem Sapegin, http://sapegin.me, 2012 */
/*jshint browser:true, jquery:true, white:false, smarttabs:true, eqeqeq:true,
immed:true, latedef:true, newcap:true, undef:true */
/*global jQuery:false, define:false*/
(function (factory) { // Try to register as an anonymous AMD module
if (typeof define === 'function' && define.amd) {
define([], factory);
} else {
factory();
}
}(function () {
'use strict';
var regexps = [
[/<(\/?)([\w]+)([^>]*)>/g, '←<$1→←tag:$2→$3←>→'], // Tag
[/ ([\-\w]+)/g, ' ←attr:$1→'] // Attribute
],
saveStringsRe = [
/"([^"]+)"/mg
],
restoreStringsRe = /↑(\d+)↓/g,
savedStrings,
savedStringsNum;
function save_strings(code) {
function save(s) {
savedStrings[savedStringsNum] = s;
return '↑' + savedStringsNum++ + '↓';
}
savedStringsNum = 0;
savedStrings = [];
for (var reIdx = 0; reIdx < saveStringsRe.length; reIdx++) {
code = code.replace(saveStringsRe[reIdx], save);
}
return code;
}
function restore_strings(code) {
code = code.replace(restoreStringsRe, function(s, num) {
return savedStrings[num];
});
savedStringsNum = 0;
savedStrings = [];
return code;
}
function highlight(code) {
code = save_strings(code);
for (var regexpIdx = 0; regexpIdx < regexps.length; regexpIdx++) {
var re = regexps[regexpIdx];
code = code.replace(re[0], re[1]);
}
code = restore_strings(code);
code = code.replace(/\=("[^\"]*")/g, '←=→←str:$1→'); // Attribute values
return code;
}
function htmlize(code) {
return code
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/←([^:→]+)→/g, '←gray:$1→')
.replace(/←(\w+):([^→]+)→/g, '<span class="hl-$1">$2</span>')
;
}
return (window.htmlhl = function(code) {
return htmlize(highlight(code));
});
}));

15
gh-pages/proxy/proxy.php Normal file
View File

@ -0,0 +1,15 @@
<?php
try {
$content = base64_decode($_POST['content']);
if (empty($content)) throw new Exception();
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="social-likes.zip"');
echo $content;
}
catch (Exception $e) {
header('HTTP/1.0 400 Bad request');
echo 'Bad request.';
}
?>

View File

@ -0,0 +1,166 @@
/* Author: Artem Sapegin, http://sapegin.me, 2012 */
link-color = #cf6c0a;
visited-color = #7c579e;
hover-color = #ff6900;
noise = url('../img/noise.png');
body {
background:#fff;
color:#111;
font-size:18px;
line-height:1.4;
min-width:1024px;
}
.wrapper {
position:relative;
max-width:1100px;
margin:0 auto;
padding:2*spacer;
}
// Fonts
* { font-family:"Helvetica Neue", Tahoma, sans-serif; }
pre, code, pre span { font-family:Consolas, "Lucida Console", Monaco, "Courier New", Courier, monospace; }
// Links
a {
text-decoration:underline;
transition:border .1s ease-in-out, color .2s ease-in-out, background .2s ease-in-out;
}
a.fake {
text-decoration:none;
border-bottom:1px dotted;
}
a:link, nav a:visited, a.fake:visited {
color:link-color;
}
a:visited {
color:visited-color;
}
a:hover, a:active, a:focus, nav a:hover, nav a:active, nav a:focus, a.fake:hover, a.fake:active, a.fake:focus {
color:hover-color;
}
// Text selection
text-selection(#000, #faedb1);
// iOS tap highlighting: j.mp/webkit-tap-highlight-color
a:link {
-webkit-tap-highlight-color:#ff5e99;
}
// Page elements
h1 {
font-size:64px;
margin:0 0 16px;
line-height:1;
font-weight:normal;
letter-spacing:-.2px;
}
h2, h3 {
line-height:40px;
margin:16px 0 0;
font-weight:normal;
letter-spacing:-.2px;
}
h2 {
font-size:24px;
}
h3 {
font-size:22px;
font-style:italic;
text-align:center;
}
// Code
.code {
display: block
white-space: pre-wrap
-moz-tab-size: 4
-o-tab-size: 4
tab-size: 4
code {
display: block
font-size: 15px
line-height: 1.3
}
.indent {
display: inline-block
width: 2.2em
}
}
pre code::-webkit-scrollbar {
width:9px;
height:9px;
}
pre code::-webkit-scrollbar-track-piece {
background:white(.2);
}
pre code::-webkit-scrollbar-thumb {
background:white(.6);
border-radius:8px;
}
// GitHub page elements
.forkme {
position:fixed;
top:0;
right:0;
width:149px;
height:149px;
z-index:999;
&-i {
+link-all-states() {
color:#fff;
}
position:relative;
right:-37px;
top:-22px;
display:block;
width:190px;
padding:5px 15px;
text-align:center;
font-size:14px;
background:#f9970d;
text-decoration:none;
text-shadow:0 -1px 0 black(.15);
transform-origin:0 0;
transform:rotate(45deg);
}
}
@media (max-width:1150px) {
.forkme {
display:none;
}
}
.download {
float:right;
}
.subtitle {
font-size:19px;
margin:5px 0 1em 0;
font-style:italic;
display:none;
}
.footer {
padding:spacer;
text-align:center;
font-size:14px;
}

View File

@ -0,0 +1,11 @@
/* Author: Artem Sapegin, http://sapegin.me, 2013 */
sticky_footer_height = 40px;
form_focus_color = #f59300;
@import "tamia";
@import "modules/form";
@import "modules/checkbox";
@import "modules/switcher";
@import "gh-page";
@import "styles";

144
gh-pages/styles/styles.styl Normal file
View File

@ -0,0 +1,144 @@
// Author: Artem Sapegin, http://sapegin.me, 2013
.language-switcher {
position:absolute;
top:15px;
right:2*spacer;
}
.description {
space(2);
}
// Forms
.builder {
space(3);
&__row {
clearfix();
margin-top:.5em;
}
&__label {
float:left;
width:15%;
line-height:28px;
}
&__widget {
float:right;
width:85%;
}
&__checkbox {
float:left;
width:20%;
}
.l-half &__label {
width:30.67%;
}
.l-half &__widget {
width:69.33%;
}
}
.checkbox__input:checked + .checkbox__label .checkbox__button,
.radio__input:checked + .radio__label .radio__button,
.checkbox__input:not(:checked) + .checkbox__label .checkbox__button,
.radio__input:not(:checked) + .radio__label .radio__button {
margin-top:0;
}
.preview {
space(2);
min-height:150px;
padding:6*spacer 0 0;
text-align:center;
&_vertical {
padding-top:0;
overflow:auto;
}
}
.code {
space(4);
padding:spacer;
background:#f5f2f0;
border-radius:3px
border:1px solid #ccc
border-color:black(.2)
}
// Syntax highlighting
.hl-gray {
color:#999;
}
.hl-tag {
color:#905;
}
.hl-attr {
color:#690;
}
.hl-str {
color:#07a;
}
// Download row
.download-row {
margin-bottom:2*spacer;
&__links {
margin-bottom:1.5*spacer;
.big-button {
margin-right:.2em;
}
}
&__button {
display:inline-block;
font-size:36px;
// position:relative;
}
&__descr {
font-size:14px;
}
}
.docs {
margin-bottom:spacer;
}
// Download button
.big-button,
.big-button:link,
.big-button:visited {
tweak-inverted-text();
display:inline-block;
padding:10px 20px;
background:#ff6d00;
background:linear-gradient(to bottom, #ffb300, #ff6d00);
border-radius:5px;
color:#fff;
font-size:36px;
text-decoration:none;
text-shadow:0 -1px 0 black(.15);
outline:0;
}
.big-button:hover,
.big-button:focus {
background:#ff7c1a;
background:linear-gradient(to bottom, #fbbd00, #ff750d);
}
.big-button:active {
position:relative;
top:1px;
margin-top:-1px;
margin-bottom:1px;
padding:11px 20px 9px;
background:#faa643;
background:linear-gradient(to bottom, #ff7c1a, #faa643);
box-shadow:inset 0 2px 2px black(.2);
}

View File

@ -0,0 +1,31 @@
# Checkbox and radio button
Checkbox and radio button with custom design.
## Markup
Checkbox:
<div class="checkbox">
<input class="checkbox__input" id="my_checkbox" type="checkbox" name="my_checkbox" value="yes" checked="checked">
<label class="checkbox__label" for="my_checkbox">
<span class="checkbox__button"></span>
<span class="checkbox__text">My checkbox</span>
</label>
</div>
Radio button:
<div class="radiobutton">
<input class="radiobutton__input" id="my_radio" type="checkbox" name="my_radio" value="dog" checked="checked">
<label class="radiobutton__label" for="my_radio">
<span class="radiobutton__button"></span>
<span class="radiobutton__text">My radio button</span>
</label>
</div>
## Skin
Set `checkbox_default_skin` or `modules_default_skin` to `true` to enable default skin.

View File

@ -0,0 +1 @@
<svg width="12" height="11" xmlns="http://www.w3.org/2000/svg"><path d="M0 5.899l2.136-2.432 2.342 2.668 5.387-6.135 2.136 2.432-7.522 8.568-4.478-5.101zm0 0" fill="#444"/></svg>

After

Width:  |  Height:  |  Size: 179 B

View File

@ -0,0 +1,43 @@
<div class="checkbox">
<input class="checkbox__input" id="check1" type="checkbox" name="check" value="yes" checked>
<label class="checkbox__label" for="check1">
<span class="checkbox__button"></span>
<span class="checkbox__text fixie"></span>
</label>
</div>
<div class="checkbox">
<input class="checkbox__input" id="check2" type="checkbox" name="check2" value="yes">
<label class="checkbox__label" for="check2">
<span class="checkbox__button"></span>
<span class="checkbox__text fixie"></span>
</label>
</div>
<div class="checkbox is-disabled">
<input class="checkbox__input" id="check3" type="checkbox" name="check3" value="yes" checked disabled>
<label class="checkbox__label" for="check3">
<span class="checkbox__button"></span>
<span class="checkbox__text fixie"></span>
</label>
</div>
<div class="radio">
<input class="radio__input" id="radio1" type="radio" name="radio" value="dog" checked>
<label class="radio__label" for="radio1">
<span class="radio__button"></span>
<span class="radio__text fixie"></span>
</label>
</div>
<div class="radio">
<input class="radio__input" id="radio2" type="radio" name="radio" value="hamster">
<label class="radio__label" for="radio2">
<span class="radio__button"></span>
<span class="radio__text fixie"></span>
</label>
</div>
<div class="radio is-disabled">
<input class="radio__input" id="radio3" type="radio" name="radio" value="cat" disabled>
<label class="radio__label" for="radio3">
<span class="radio__button"></span>
<span class="radio__text fixie"></span>
</label>
</div>

View File

@ -0,0 +1,108 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Checkbox and radio button
// Requires Modernizr.svg
// Dependencies: form
// Bones
.checkbox,
.radio
white-space: nowrap
&__button
// For prehistoric browsers
display: none
&__text
display: inline-block
white-space: normal
&__button,
&__text
vertical-align: middle
&__input:checked,
&__input:not(:checked)
// Input should be hidden but focusable
// display:none and width=height=0 dont work here
position: absolute
opacity: 0
overflow: hidden
height: 1px
width: 1px
padding: 0
border: 0
&__input:checked + &__label &__button,
&__input:not(:checked) + &__label &__button
display: inline-block
&__input:checked + &__label &__button
position: relative
&:before
content: ""
position: absolute
line-height: 1
&.is-disabled &__input + &__label
opacity: .4
// Default skin
modules_default_skin ?= true
checkbox_default_skin ?= false
if modules_default_skin or checkbox_default_skin
.checkbox,
.radio
&__button,
&__text
line-height: 1.8
font-size: 1em
&__input:checked + &__label &__button,
&__input:not(:checked) + &__label &__button
width: size = 1em
height: size
margin-top: -.15em
margin-right: .15em
border: 1px solid #bbb
border-radius: form_border_radius
box-shadow: inset 0 .1em .2em black(.1)
&__input:checked + &__label &__button
&:before
background-size: 100% 100%
background-repeat: no-repeat
&__input:enabled:active + &__label &__button,
&__input:focus + &__label &__button
background: #f4f4f4
.checkbox
&__input:checked + &__label &__button
&:before
center(.8em, .65em)
background-image: embedurl("check.svg")
.no-svg &:before
margin-top:-.5em;
font-size: 0.8em
font-weight:bold;
color: #444
content: ""
.radio
&__input:checked + &__label &__button,
&__input:not(:checked) + &__label &__button
border-radius: 50%
&__input:checked + &__label &__button
&:before
center(.5em)
background-image: embedurl("radio.svg")
.no-svg &:before
background: #444
border-radius: 50%

View File

@ -0,0 +1 @@
<svg width="10" height="10" xmlns="http://www.w3.org/2000/svg"><circle fill="#444" cx="5" cy="5" r="5"/></svg>

After

Width:  |  Height:  |  Size: 111 B

View File

@ -0,0 +1,18 @@
# Code blocks
Nice code examples with highlighting.
## Markup
<pre class="code"><code class="language-coffescript">alert 'Hello world!'</code></pre>
<div class="text">
<pre><code class="language-coffescript">alert 'Hello world!'</code></pre>
</div>
## Tools
* [highlight.js](http://softwaremaniacs.org/soft/highlight/en/).
* [docpad-plugin-highlightjs](https://github.com/docpad/docpad-plugin-highlightjs) for DocPad.

View File

@ -0,0 +1 @@
<pre class="code"><code class="language-javascript">alert('Hello world!');</code></pre>

View File

@ -0,0 +1,44 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Code blocks
modules_default_skin ?= true
code_default_skin ?= false
.code,
.text code,
.text kbd,
.text pre,
.text pre *
font-family: Consolas, "Lucida Console", Monaco, "DejaVu Sans Mono", monospace
.code
display: block
white-space: pre-wrap
-moz-tab-size: 4
-o-tab-size: 4
tab-size: 4
code
display: block
font-size: 14px
line-height: 1.3
.indent
display: inline-block
width: 2.2em
if modules_default_skin or code_default_skin
@import 'tomorrow'
code
padding: spacer
background: #fff
background: white(.7)
border-radius: 3px
border: 1px solid #ccc
border-color: black(.2)
// Enable code in .text blocks
.text pre
@extend .code

View File

@ -0,0 +1,67 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Tomorrow theme
// Theme from: http://jmblog.github.com/color-themes-for-google-code-highlightjs
.tomorrow-comment,
.comment,
.title
color: #8e908c
.tomorrow-red,
.variable,
.attribute,
.tag,
.regexp,
.ruby .constant,
.xml .tag .title,
.xml .pi,
.xml .doctype,
.html .doctype,
.css .id,
.css .class,
.css .pseudo
color: #c82829
.tomorrow-orange,
.number,
.codeprocessor,
.built_in,
.literal,
.params,
.constant
color: #f5871f
.tomorrow-yellow,
.class,
.ruby .class .title,
.css .rules .attribute
color: #eab700
.tomorrow-green,
.string,
.value,
.inheritance,
.header,
.ruby .symbol,
.xml .cdata
color: #718c00
.tomorrow-aqua,
.css .hexcolor
color: #3e999f
.tomorrow-blue,
.function,
.python .decorator,
.python .title,
.ruby .function .title,
.ruby .title .keyword,
.perl .sub,
.javascript .title,
.coffeescript .title
color: #4271ae
.tomorrow-purple,
.keyword,
.javascript .function
color: #8959a8

View File

@ -0,0 +1,14 @@
# Fade
Fading text.
## Markup
<div class="fade" title="Very long text">Very long text</div>
## Caveats
Works best in Webkits (via `mask-image`). Works acceptable in Firefox (via SVG mask): fade width is fixed. Fades with ellipsis in any IE.

View File

@ -0,0 +1 @@
<p class="fade fixie" style="width:300px"></p>

View File

@ -0,0 +1,11 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Fading text
// Based on http://mir.aculo.us/2012/09/16/masking-html-elements-with-gradient-based-fadeouts/ + thanks to @kizu
.fade
display: block
overflow: hidden
white-space: nowrap
-webkit-mask-image: -webkit-linear-gradient(right, transparent 0, #000 3em) // Webkit
mask: embedurl("mask.svg#fade-mask") // Firefox
-ms-text-overflow: ellipsis // IE

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg"><mask maskContentUnits="objectBoundingBox"><linearGradient id="a"><stop stop-color="#fff" offset=".7"/><stop stop-color="#fff" stop-opacity="0" offset="1"/></linearGradient><rect width="1" height="1" fill="url(#a)"/></mask></svg>

After

Width:  |  Height:  |  Size: 269 B

View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg">
<mask id="fade-mask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<linearGradient id="g">
<stop stop-color="#fff" stop-opacity="1" offset=".7"></stop>
<stop stop-color="#fff" stop-opacity="0" offset="1"></stop>
</linearGradient>
<rect x="0" y="0" width="1" height="1" fill="url(#g)"></rect>
</mask>
</svg>

After

Width:  |  Height:  |  Size: 384 B

View File

@ -0,0 +1,39 @@
# Flippable pane
Vertical or horizontal flippable pane. With 3D animation.
# Markup
<div class="flippable js-flip" data-component="flippable">
<div class="flippable__front">Front</div>
<div class="flippable__back">Back</div>
</div>
## Modifiers
### .flippable.flippable_vertical
Vertical rotation (horizontal by default).
## States
### .flippable.is-flipped
Back side is visible.
## Events
### flipped.tamia
Fires on every flip. Argument will be `true` if back side is visible.
## JS Hooks
### .js-flip
Element that flips pane when clicked.

View File

@ -0,0 +1,4 @@
<div class="flippable js-flip" data-component="flippable" style="width:200px; height:200px">
<div class="flippable__front fixie" style="padding:20px; background:#8FA1B3"></div>
<div class="flippable__back fixie" style="padding:20px; background:#EBCB8B"></div>
</div>

View File

@ -0,0 +1,36 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Flippable pane
.flippable
no-select()
position: relative
perspective: 600px
cursor: default
&__front,
&__back
position: absolute
top: 0
left: 0
width: inherit
height: inherit
transform-style: preserve-3d
backface-visibility: hidden
transition: all .4s ease-out-back
&__front
z-index: 900
transform: rotateY(0deg) rotateX(0deg)
&__back
z-index:800;
transform: rotateY(-180deg)
&_vertical &__back
transform: rotateX(-180deg)
&.is-flipped &__front
transform: rotateY(180deg)
&_vertical.is-flipped &__front
transform: rotateX(180deg)
.is-flipped &__back
transform: rotateY(0deg) rotateX(0deg)

View File

@ -0,0 +1,19 @@
# Tâmia © 2013 Artem Sapegin http://sapegin.me
# Flippable pane
'use strict'
$ = jQuery
class Flippable extends Component
init: ->
if @elem.hasClass('js-flip')
@on('click', @toggle)
else
@on('click', 'flip', @toggle)
toggle: ->
@toggleState('flipped')
@elem.trigger('flipped.tamia', @hasState('flipped'))
tamia.initComponents(flippable: Flippable)

View File

@ -0,0 +1,38 @@
(function() {
'use strict';
var $, Flippable, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
$ = jQuery;
Flippable = (function(_super) {
__extends(Flippable, _super);
function Flippable() {
_ref = Flippable.__super__.constructor.apply(this, arguments);
return _ref;
}
Flippable.prototype.init = function() {
if (this.elem.hasClass('js-flip')) {
return this.on('click', this.toggle);
} else {
return this.on('click', 'flip', this.toggle);
}
};
Flippable.prototype.toggle = function() {
this.toggleState('flipped');
return this.elem.trigger('flipped.tamia', this.hasState('flipped'));
};
return Flippable;
})(Component);
tamia.initComponents({
flippable: Flippable
});
}).call(this);

View File

@ -0,0 +1,33 @@
# Form
Basic form controls: inputs, textareas, buttons.
## Markup
Controls:
<input type="text" class="field" name="name">
<textarea type="text" class="field field_area" name="message"></textarea>
<input type="submit" class="button" value="Send!">
## Events
### enable.tamia / disable.tamia
Enables / disables all descendant form elements.
## Skin
Set `form_default_skin` or `modules_default_skin` to `true` to enable default skin.
## Configuration
### form_focus_color
Type: CSS color value.
Color of focus otline.

View File

@ -0,0 +1,13 @@
<div class="form form_full">
<div class="form__row">
<input type="text" class="field" placeholder="Name">
</div>
<div class="form__row">
<button class="button fixie"></button>
</div>
</div>
<div class="form form_inline">
<input type="text" class="field" placeholder="Name">
<button class="button fixie"></button>
</div>

View File

@ -0,0 +1,136 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Basic form controls: inputs, textareas, buttons
// Disabled form element
.is-disabled
cursor: default
pointer-events: none
text-shadow: none
// Bones
.field,
.button
display: block
vertical-align: middle
font-size: 1em
line-height: 1
outline: 0
transition: opacity .25 ease-out
&_inline
display: inline-block
&.is-disabled
opacity: .4
.field
// Hide IE10 clear button
&::-ms-clear
size: 0 // Not display:none because: http://bit.ly/1h3UlAH
.field_area
resize: vertical
.button
no-select()
position: relative // Fixes strange bugs in webkit
text-decoration: none
white-space: nowrap
cursor: pointer
// Fixing Mozilla's inner paddings
// https://github.com/nanoblocks/nanoblocks/blob/gh-pages/blocks/button/button.styl
&::-moz-focus-inner
padding: 0
border: none
.form
&_inline .field,
&_inline .button,
&_inline .select,
&_inline .password
display: inline-block
&_full .field,
&_full .button,
&_full .select,
&_full .password
width: 100%
&__group
space(2)
&__row
space()
&:last-child
space(0)
&__left
float: left
&__right
float: right
// Default skin
modules_default_skin ?= true
form_default_skin ?= false
if modules_default_skin or form_default_skin
.field,
.button
height: 2em
border-radius: form_border_radius
&:focus
outline: 0
border-color: form_focus_color
.field,
.button:active
transition: border-color .1s ease-in-out, box-shadow .1s ease-in-out
.field
padding: .3em .4em
background: #fff
border: 1px solid #bbb
box-shadow: inset 0 .1em .2em black(.1)
&:focus
box-shadow: inset 0 .1em .2em black(.1), 0 0 .4em rgba(form_focus_color, .75)
&_area
height: auto
.button
height: 2em
padding: .45em 1.5em .35em;
background: #dfdfdf
background: linear-gradient(to bottom, #fefefe, #eaeaea)
border: 1px solid #bbb
border-bottom-color: #aaa
color: #555
border-radius: form_border_radius
box-shadow: 0 .1em .1em black(.05)
text-shadow: 0 1px 0 white(.4)
&:focus
box-shadow: 0 0 .4em rgba(form_focus_color, .75)
&:not(.is-disabled):hover
background: linear-gradient(to bottom, #fff, #f0f0f0)
color: #333
&:not(.is-disabled):active
padding-top: .55em
padding-bottom: .25em
background: #cacaca
background: linear-gradient(to bottom, #aaa, #dfdfdf)
box-shadow: 0 0 .4em rgba(form_focus_color, .75), inset 0 .1em .2em black(.2), 0 .025em .05em black(.05)
border-color: form_focus_color
border-top-color: #888

View File

@ -0,0 +1,31 @@
# Tâmia © 2013 Artem Sapegin http://sapegin.me
# Basic form controls
'use strict'
$ = jQuery
_formElementsSelector = '.field,.button,.disablable'
_disabledClass = 'is-disabled'
_enableDisable = (elem, enable) ->
formElements = ($ elem).find(_formElementsSelector).addBack(_formElementsSelector)
formElements[if enable then 'removeClass' else 'addClass'](_disabledClass)
formElements.attr('disabled', !enable)
# Events
tamia.registerEvents(
###
Enables all descendant form elements.
###
enable: (elem) ->
_enableDisable elem, true
###
Disables all descendant form elements.
###
disable: (elem) ->
_enableDisable elem, false
)

View File

@ -0,0 +1,35 @@
(function() {
'use strict';
var $, _disabledClass, _enableDisable, _formElementsSelector;
$ = jQuery;
_formElementsSelector = '.field,.button,.disablable';
_disabledClass = 'is-disabled';
_enableDisable = function(elem, enable) {
var formElements;
formElements = ($(elem)).find(_formElementsSelector).addBack(_formElementsSelector);
formElements[enable ? 'removeClass' : 'addClass'](_disabledClass);
return formElements.attr('disabled', !enable);
};
tamia.registerEvents({
/*
Enables all descendant form elements.
*/
enable: function(elem) {
return _enableDisable(elem, true);
},
/*
Disables all descendant form elements.
*/
disable: function(elem) {
return _enableDisable(elem, false);
}
});
}).call(this);

View File

@ -0,0 +1,29 @@
# Unordered list
Unordered list with dashes (—) as bullets.
## Markup
<ul class="list">
<li>Dog</li>
<li>Cat</li>
<li>Mouse</li>
<li>Moose</li>
</ul>
## Configuration
### list_inside
Type: Boolean, default: `false`.
If `true` places bullets inside container (by default bullets are outside).
## Caveats
1. If `list_inside` is `false` (default) automatically places bullets inside container (like `list_inside = true` does) when window width is less than `max_width` global variable.
2. `UL`s inside `.text` class are treated as `.list`.

View File

@ -0,0 +1,6 @@
<ul class="list">
<li class="fixie"></li>
<li class="fixie"></li>
<li class="fixie"></li>
<li class="fixie"></li>
</ul>

View File

@ -0,0 +1,33 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Unordered list with dashes as bullets
// Place bullets inside container (by default bullets are outside).
list_inside ?= false
.list
> li
position: relative
padding-left: 1.3em
margin-left: -1.3em unless list_inside
> li:before
position: absolute
left: 0
content: "\2014\a0"
ul
margin-left: 1.3em
li > ul,
li > ol
margin-bottom: 0
.text
ul
@extend .list
if not list_inside and max_width
+below(max_width)
.list > li,
.text ul > li
margin-left: 0

View File

@ -0,0 +1,22 @@
# Media object
Media object from OOCSS.
## Markup
<div class="media">
<img src="http://placedog.com/200/200" alt="" class="media__img">
<p class="media__body">Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, “and what is the use of a book,” thought Alice “without pictures or conversation?”</p>
</div>
## Modifiers
### .media__img.media__img_rev
Reversed image location (right instead of left).
```html
<img src="http://placedog.com/200/200" alt="" class="media__img media__img_rev">
```

View File

@ -0,0 +1,4 @@
<div class="media">
<img class="media__img fixie" src="http://placedog.com/150/100">
<p class="media__body fixie"></p>
</div>

View File

@ -0,0 +1,18 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Media object
// Based on https://github.com/csswizardry/inuit.css/blob/master/objects/_media.scss
.media
clearfix()
display: block
&__img
float: left
margin-right: spacer
&__img_rev
float: right
margin-right: 0
margin-left: spacer
&__body
overflow: hidden

View File

@ -0,0 +1,32 @@
# Password field
Password field with toggle to show characters.
## Markup
<div class="password" data-component="password">
<span class="password__toggle js-toggle"></span>
<input type="password" class="password__field field js-field">
</div>
## States
### .password.is-ok
Browser is supported.
### .password.is-unlocked
Password characters are visible.
## Caveats
IE9+.
## Skin
Set `password_default_skin` or `modules_default_skin` to `true` to enable default skin.

View File

@ -0,0 +1,4 @@
<div class="password password_inline" data-component="password">
<span class="password__toggle js-toggle"></span>
<input type="password" class="password__field field js-field">
</div>

View File

@ -0,0 +1,60 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Password field with toggle to show characters
// Dependencies: form
// Bones
.password
position: relative
display: block
&_inline
display: inline-block
&__field
position:relative;
width: 100%
z-index: 90
&__toggle
display: none
&.is-ok &__toggle
position: absolute
display: block
top: 0
bottom: 0
right: 0
cursor: pointer
z-index: 100
&:before
content: ""
position: absolute
top: 50%
left: 50%
transform: translate(-50%,-50%)
&.is-disabled &__toggle
opacity: .4
// Hide IE10 password visibility toggle
&::-ms-reveal
size: 0 // Not display:none because: http://bit.ly/1h3UlAH
// Default skin
modules_default_skin ?= true
password_default_skin ?= false
if modules_default_skin or password_default_skin
.password
&.is-ok &__toggle
width: 1.8em
&:before
tweak-inverted-text()
content: "abc"
font-size: .75em
letter-spacing: .1ex
&.is-ok.is-unlocked &__toggle:before
content: ""
letter-spacing: 0

View File

@ -0,0 +1,45 @@
# Tâmia © 2013 Artem Sapegin http://sapegin.me
# Password field with toggle to show characters
'use strict'
$ = jQuery
supported = undefined
class Password extends Component
init: ->
@types =
locked: 'password'
unlocked: 'text'
@fieldElem = @find('field')
@toggleElem = @find('toggle')
# Mousedown instead of click to catch focused field
@on('mousedown', 'toggle', @toggle)
isSupported: ->
return supported unless supported is undefined
# IE8+
supported = $('<!--[if lte IE 8]><i></i><![endif]-->').find('i').length isnt 1
return supported
toggle: ->
focused = document.activeElement is @fieldElem[0]
locked = @hasState('unlocked')
fieldType = @fieldElem.attr('type')
@toggleState('unlocked')
if fieldType is @types.locked and not locked
@fieldElem.attr('type', @types.unlocked)
else if fieldType is @types.unlocked and locked
@fieldElem.attr('type', @types.locked)
if focused
setTimeout((=> @fieldElem.focus()), 0)
tamia.initComponents(password: Password)

View File

@ -0,0 +1,64 @@
(function() {
'use strict';
var $, Password, supported, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
$ = jQuery;
supported = void 0;
Password = (function(_super) {
__extends(Password, _super);
function Password() {
_ref = Password.__super__.constructor.apply(this, arguments);
return _ref;
}
Password.prototype.init = function() {
this.types = {
locked: 'password',
unlocked: 'text'
};
this.fieldElem = this.find('field');
this.toggleElem = this.find('toggle');
return this.on('mousedown', 'toggle', this.toggle);
};
Password.prototype.isSupported = function() {
if (supported !== void 0) {
return supported;
}
supported = $('<!--[if lte IE 8]><i></i><![endif]-->').find('i').length !== 1;
return supported;
};
Password.prototype.toggle = function() {
var fieldType, focused, locked,
_this = this;
focused = document.activeElement === this.fieldElem[0];
locked = this.hasState('unlocked');
fieldType = this.fieldElem.attr('type');
this.toggleState('unlocked');
if (fieldType === this.types.locked && !locked) {
this.fieldElem.attr('type', this.types.unlocked);
} else if (fieldType === this.types.unlocked && locked) {
this.fieldElem.attr('type', this.types.locked);
}
if (focused) {
return setTimeout((function() {
return _this.fieldElem.focus();
}), 0);
}
};
return Password;
})(Component);
tamia.initComponents({
password: Password
});
}).call(this);

View File

@ -0,0 +1,17 @@
# Print
Print stylesheet.
## Configuration
### site_domain
Type: String.
Site domain (for example, `example.com`) that will be printed.
## Caveats
Use `.no-print` class to hide elements in print version and `.print` to show (hidden on screen).

View File

@ -0,0 +1,103 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Print stylesheet
// Site domain (for example, `example.com`) that will be printed.
site_domain ?= false
@media print
@page
margin: .5cm
nav,
.social-likes,
.no-print
display: none
.print
display: block
*
font-family: Cambria, Georgia, serif
color: #000 !important
background: transparent !important
float: none !important
width: auto !important
margin-left: 0 !important
margin-right: 0 !important
padding-left: 0 !important
padding-right: 0 !important
text-shadow: none !important
body
padding-bottom: 0
a
border: none !important
h1,
h2,
h3,
h4,
h5,
h6
font-family: Corbel, 'Helvetica Neue', Arial, sans-serif
page-break-inside: avoid
page-break-after: avoid
a:link:after,
a:visited:after
content: " (" attr(href) ")"
font-size: .9em
if site_domain
a[href^="/"]:link:after,
a[href^="/"]:visited:after
content: (" (http://" + site_domain) attr(href) ")"
font-size: .9em
a[href^="javascript:"]:after,
a[href^="#"]:after,
.footer a:after
content: ""
.header
margin-bottom: 2*spacer
border-bottom: 1pt solid #000
height: auto
.footer
position: static
margin-top: 2*spacer
border-top: 1pt solid #000
height: auto
a
text-decoration: none
if site_domain
.logo:before
content: url(/favicon.ico)
padding-right: 2px
vertical-align: middle
.logo a:link:after,
.logo a:visited:after
content: "  " + site_domain
p,
blockquote,
ul,
ol,
dl,
tr,
img
page-break-inside: avoid
p,
h2,
h3
orphans: 3
widows: 3
ul
margin-left: 1.2em !important

View File

@ -0,0 +1,31 @@
# Rich typograhy
Classes and tweaks for better typography.
## Markup
### Abbreviations with spacing
<div class="text">
<p><abbr>PNG</abbr>, <abbr>GIF</abbr> (animated or not) and <abbr>JPEG</abbr> formats.</p>
</div>
### The best ampersand
Nuts <span class="amp">&amp;</span> Bolts.
### Hanging punctuation
Awesome Web Typography with <span class="slaquo"> </span> <span class="hlaquo"></span>Richtypo”'
## Caveats
* Enables ligatures in headings (h1—h6 inside .text and .alpha—.zeta).
## Tools
* [richtypo.js](https://github.com/sapegin/richtypo.js) for Node.js.
* [wp-typohelper](https://github.com/sapegin/wp-typohelper) for Wordpress.

View File

@ -0,0 +1,32 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Rich typograhy
// Abbreviations with spacing.
.abbr,
.text abbr
letter-spacing: 0.1em
margin-right: -0.1em
// The best ampersand.
.amp
font-family: Baskerville, Constantia, Palatino, "Palatino Linotype", "Book Antiqua", serif
font-style: italic
// Hanging punctuation.
.sbrace
margin-right: 0.3em
.hbrace
margin-left: -0.3em
.slaquo
margin-right: 0.42em
.hlaquo
margin-left: -0.42em
// Headings with ligatures.
.text h1, .alpha,
.text h2, .beta,
.text h3, .gamma,
.text h4, .delta,
.text h5, .epsilon,
.text h6, .zeta
enable-ligatures()

View File

@ -0,0 +1,22 @@
# Select
Select with custom design
## Markup
<div class="select" data-component="select">
<div class="select__box js-box"></div>
<select class="select__select js-select">
<option selected>Please select an option</option>
<option>Dog</option>
<option>Cat</option>
<option>Mouse</option>
<option>Moose</option>
</select>
</div>
## Skin
Set `select_default_skin` or `modules_default_skin` to `true` to enable default skin.

View File

@ -0,0 +1 @@
<svg width="10" height="10" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h10l-5 9-5-9z" fill="#444"/></svg>

After

Width:  |  Height:  |  Size: 111 B

View File

@ -0,0 +1,10 @@
<div class="select select_inline" data-component="select">
<div class="select__box js-box"></div>
<select class="select__select js-select">
<option selected>Please select an option</option>
<option class="fixie"></option>
<option class="fixie"></option>
<option class="fixie"></option>
<option class="fixie"></option>
</select>
</div>

View File

@ -0,0 +1,86 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Select with custom design
// Dependencies: form
// Bones
.select
no-select()
position: relative
display: block
overflow: hidden
font-size: 1em
&_inline
display: inline-block
&__select
position: absolute
bottom: 0
left: 0
width: 100%
opacity: 0
z-index: 2
cursor: default
transform: scaleY(2) // Select height could be smaller than box height
transform-origin: 0 100% // Fixes dropdown position on Windows
&__box
display: block
vertical-align: middle
line-height: 1
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
&:after
content: ""
position: absolute
top: 0
bottom: 0
right: 0
z-index: 1
&.is-disabled
opacity: .4
// Default skin
modules_default_skin ?= true
select_default_skin ?= false
if modules_default_skin or select_default_skin
.select
border: 1px solid #bbb
border-bottom-color: #aaa
border-radius: form_border_radius
transition: border-color .1s ease-in-out, box-shadow .1s ease-in-out
&__box
height: 2em
padding: .5em 1.5em .5em .5em
background: #f4f4f4
background: linear-gradient(to bottom, #fefefe, #f4f4f4)
line-height: 1
color: #555
&:after
top: 50%
right: .3em
width: .8em
height: .7em
margin-top: -.3em
background: embedurl("arrow.svg") no-repeat
background-size: 100% 100%
.no-svg &:after
content: ""
padding-right: .2em
text-align: center
vertical-align: middle
font-size: 1em
line-height: 2em
&.is-focused
border-color: form_focus_color
box-shadow: 0 0 .4em rgba(form_focus_color, .75)

View File

@ -0,0 +1,28 @@
# Tâmia © 2013 Artem Sapegin http://sapegin.me
# Select with custom design
'use strict'
$ = jQuery
class Select extends Component
init: ->
@selectElem = @find('select')
@boxElem = @find('box')
@on('focus', 'select', @focus)
@on('blur', 'select', @blur)
@on('change', 'select', @change)
@change()
focus: ->
@addState('focused')
blur: ->
@removeState('focused')
change: ->
@boxElem.text(@selectElem.find(':selected').text())
tamia.initComponents(select: Select)

View File

@ -0,0 +1,46 @@
(function() {
'use strict';
var $, Select, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
$ = jQuery;
Select = (function(_super) {
__extends(Select, _super);
function Select() {
_ref = Select.__super__.constructor.apply(this, arguments);
return _ref;
}
Select.prototype.init = function() {
this.selectElem = this.find('select');
this.boxElem = this.find('box');
this.on('focus', 'select', this.focus);
this.on('blur', 'select', this.blur);
this.on('change', 'select', this.change);
return this.change();
};
Select.prototype.focus = function() {
return this.addState('focused');
};
Select.prototype.blur = function() {
return this.removeState('focused');
};
Select.prototype.change = function() {
return this.boxElem.text(this.selectElem.find(':selected').text());
};
return Select;
})(Component);
tamia.initComponents({
select: Select
});
}).call(this);

View File

@ -0,0 +1,45 @@
# Spinner
Loading indicator (spinner) with animation.
## Markup
<div class="spinner"></div>
<div class="is-loading">
<div class="loader"></div>
</div>
`.loader` is the same as `.spinner` but its hidden by default. Its visible only when `.is-loading` state is set on ancestor element.
## Modifiers
### .spinner.spinner_big
Bigger size.
## More sizes
You can set any spinner size changing `font-size` property.
.spinner_huge
font-size: 64px
<div class="spinner spinner_huge"></div>
## Component loading indicator
$('.pony').trigger('loading-start.tamia'); // Show loader
$('.pony').trigger('loading-stop.tamia'); // Hide loader
That will blocks all containers content with a semi transparent layer and shows spinner in the middle.
To change shade layers color set `loader_shade_color` variable.
## IE 8—9 callback
Copy `spinner.gif` to your images folder and set `spinner_fallback_gif` variable to its URL.

View File

@ -0,0 +1 @@
<div class="spinner"></div>

View File

@ -0,0 +1,81 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Spinner
// Based on http://codepen.io/beben-koben/pen/JcGnK
spinner_fallback_gif ?= false
loader_shade_color ?= white(.8)
@keyframes spinner-rotate
0%
transform: rotate(0deg)
100%
transform: rotate(360deg)
// Regular spinner
.spinner,
.loader
display: inline-block
width: .25em
height: .25em
margin: .5em .2em
opacity: .7
border-radius: 50%
font-size: 16px
box-shadow: 0 -.4em 0 0 rgba(0,0,0,1), -.28em -.28em 0 0 rgba(0,0,0,.75), -.4em 0 0 0 rgba(0,0,0,.5), -.28em .28em 0 0 rgba(0,0,0,.25)
&_big
font-size: 32px
// Loader
.loader
visibility: hidden
opacity: 0
transition: visibility 0s .3s, opacity .3s ease-out
.is-loading &
visibility: visible
opacity: 1
transition: opacity .5s ease-out
// Enable animation only when spinner is visible to increase page performance
.spinner,
.is-loading .loader
animation: .85s spinner-rotate steps(9) infinite
.spinner.is-hidden,
.loader.is-hidden
animation: none
// Loader shade
.loader-wrapper
position: relative
.loader-shade
position: absolute
top: 0
left: 0
width: 100%
height: 100%
opacity: 0
background: loader_shade_color
border-radius: inherit
z-index: 99999
transition: opacity .15s ease-out
.is-loading &
opacity: 1
// Fallback GIF image for browsers that dont support CSS animations
if spinner_fallback_gif
.no-cssanimations .spinner
width: 16px
height: 16px
margin: 0
opacity: 1
background: url(spinner_fallback_gif)

View File

@ -0,0 +1,53 @@
# Tâmia © 2013 Artem Sapegin http://sapegin.me
# Spinner
'use strict'
$ = jQuery
_wrapperClass = 'loader-wrapper'
_shadeSelector = '.loader-shade'
_loaderTmpl = '''
<div class="loader-shade">
<div class="l-center">
<div class="l-center-i">
<div class="spinner spinner_big"></div>
</div>
</div>
</div>
'''
class Loader extends Component
init: ->
@initHtml()
setTimeout((=> @addState('loading')), 0)
destroy: ->
@removeState('loading')
@elem.find(_shadeSelector).afterTransition(=>
@elem.removeClass(_wrapperClass)
@loader.remove()
)
initHtml: ->
@elem.addClass(_wrapperClass)
@loader = $(_loaderTmpl)
@elem.append(@loader)
# Events
tamia.registerEvents(
'loading-start': (elem) ->
container = $(elem)
return if container.data('loader')
container.data('loader', new Loader(elem))
'loading-stop': (elem) ->
container = $(elem)
loader = container.data('loader')
return if not loader
loader.destroy()
container.removeData('loader')
)

View File

@ -0,0 +1,71 @@
(function() {
'use strict';
var $, Loader, _loaderTmpl, _ref, _shadeSelector, _wrapperClass,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
$ = jQuery;
_wrapperClass = 'loader-wrapper';
_shadeSelector = '.loader-shade';
_loaderTmpl = '<div class="loader-shade">\n <div class="l-center">\n <div class="l-center-i">\n <div class="spinner spinner_big"></div>\n </div>\n </div>\n</div>';
Loader = (function(_super) {
__extends(Loader, _super);
function Loader() {
_ref = Loader.__super__.constructor.apply(this, arguments);
return _ref;
}
Loader.prototype.init = function() {
var _this = this;
this.initHtml();
return setTimeout((function() {
return _this.addState('loading');
}), 0);
};
Loader.prototype.destroy = function() {
var _this = this;
this.removeState('loading');
return this.elem.find(_shadeSelector).afterTransition(function() {
_this.elem.removeClass(_wrapperClass);
return _this.loader.remove();
});
};
Loader.prototype.initHtml = function() {
this.elem.addClass(_wrapperClass);
this.loader = $(_loaderTmpl);
return this.elem.append(this.loader);
};
return Loader;
})(Component);
tamia.registerEvents({
'loading-start': function(elem) {
var container;
container = $(elem);
if (container.data('loader')) {
return;
}
return container.data('loader', new Loader(elem));
},
'loading-stop': function(elem) {
var container, loader;
container = $(elem);
loader = container.data('loader');
if (!loader) {
return;
}
loader.destroy();
return container.removeData('loader');
}
});
}).call(this);

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

View File

@ -0,0 +1,20 @@
# Switcher
Nice looking radio buttons group.
## Markup
<div class="switcher">
<input class="switcher__input" id="type_first" type="radio" name="type" value="first" checked="checked">
<label class="switcher__label" for="type_first">First</label>
<input class="switcher__input" id="type_second" type="radio" name="type" value="second">
<label class="switcher__label" for="type_second">Second</label>
<input class="switcher__input" id="type_third" type="radio" name="type" value="third">
<label class="switcher__label" for="type_third">Third</label>
</div>
## Skin
Set `switcher_default_skin` or `modules_default_skin` to `true` to enable default skin.

View File

@ -0,0 +1,8 @@
<div class="switcher">
<input class="switcher__input" id="type_first" type="radio" name="type" value="first" checked="checked">
<label class="switcher__label" for="type_first">Dog</label>
<input class="switcher__input" id="type_second" type="radio" name="type" value="second">
<label class="switcher__label" for="type_second">Cat</label>
<input class="switcher__input" id="type_third" type="radio" name="type" value="third">
<label class="switcher__label" for="type_third">Hamster</label>
</div>

View File

@ -0,0 +1,77 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Switcher
// Dependencies: form
// Bones
.switcher
clearfix()
no-select()
&__label,
&__input
// For prehistoric browsers
vertical-align: text-bottom
padding-right: .5em
font-size: 1em
&__input:checked,
&__input:not(:checked)
position: absolute
opacity: 0
&__input:checked + &__label,
&__input:not(:checked) + &__label
position: relative
float: left
box-sizing: border-box
vertical-align: top
cursor: pointer
z-index: 1
margin-left: -1px
user-select: none
&__label:nth-of-type(1)
margin-left: 0
&__input:checked + &__label
cursor: default
z-index: 2
&.is-disabled
opacity: .4
// Default skin
modules_default_skin ?= true
switcher_default_skin ?= false
if modules_default_skin or switcher_default_skin
.switcher
&__input:checked + &__label,
&__input:not(:checked) + &__label
height: 2em
padding: .5em 1em
background: #f4f4f4
background: linear-gradient(to bottom, #fefefe, #f4f4f4)
border: 1px solid #bbb
line-height: 1
color: #555
transition: border-color .1s ease-in-out, box-shadow .1s ease-in-out
&__label:nth-of-type(1)
border-radius: form_border_radius 0 0 form_border_radius
&__label:nth-last-of-type(1)
border-radius: 0 form_border_radius form_border_radius 0
&__input:checked + &__label
background: #ccc
background: linear-gradient(to bottom, #bbb, #eee)
border-color: #999
box-shadow: inset 0 .1em .2em black(.2)
text-shadow: 0 1px 0 black(.1)
&__input:focus + &__label
border-color: form_focus_color
box-shadow: 0 0 .4em rgba(form_focus_color, .75)

View File

@ -0,0 +1,12 @@
# Basic text styles
Headings, paragraphs, etc.
## Markup
<div class="text">
<h1>Down the Rabbit-Hole</h1>
<p>Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, “and what is the use of a book,” thought Alice “without pictures or conversation?”</p>
<p>So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her.</p>
</div>

View File

@ -0,0 +1,7 @@
<div class="text">
<h1 class="fixie"></h1>
<p class="fixie"></p>
<p class="fixie"></p>
<h2 class="fixie"></h2>
<p class="fixie"></p>
</div>

View File

@ -0,0 +1,68 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Basic text styles
.text
hyphens: auto
p,
ul,
ol,
li,
pre
margin-bottom: 2*spacer
.alpha,
.text h1,
.beta,
.text h2,
.gamma,
.text h3,
.delta,
.text h4,
.epsilon,
.text h5
margin-top: 3*spacer
margin-bottom: spacer
line-height: 1.2
font-weight: normal
.alpha,
.text h1
font-size: 44px
.beta,
.text h2
font-size: 34px
.gamma,
.text h3
font-size: 28px
.delta,
.text h4
font-size: 20px
.epsilon,
.text h5
font-size: 1em
font-weight: bold
// Collapse margin between headings and before first heading.
.text h1 + h2,
.text h2 + h3,
.text h3 + h4,
.text h4 + h5,
.alpha + .beta,
.beta + .gamma,
.gamma + .delta,
.delta + .epsilon,
h1:first-child,
h2:first-child,
h3:first-child,
h4:first-child,
h5:first-child,
.alpha:first-child,
.beta:first-child,
.gamma:first-child,
.delta:first-child
margin-top: 0

View File

@ -0,0 +1,15 @@
# Tooltip
Simple tooltips.
## Markup
<div class="tooltip">Im tooltip!</div>
<a href="#" class="has-tooltip" data-tooltip="Call us!">+7 495 212-85-06</a>
## Skin
Set `tooltip_default_skin` or `modules_default_skin` to `true` to enable default skin.

View File

@ -0,0 +1 @@
<span class="has-tooltip" data-tooltip="Call us!">+7 495 212-85-06</span>

View File

@ -0,0 +1,63 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Tooltip
// Bones
.tooltip,
.has-tooltip:before
position: relative
display: inline-block
text-decoration: none
white-space: nowrap
.tooltip:after,
.has-tooltip:before,
.has-tooltip:after
content: ""
position: absolute
left: 50%
transform: translateX(-50%)
.has-tooltip
position: relative
&:before
content: attr(data-tooltip);
&:before,
&:after
top: 100%
display: none
&:hover:before,
&:hover:after
display: block
// Default skin
modules_default_skin ?= true
tooltip_default_skin ?= false
if modules_default_skin or tooltip_default_skin
_tooltip_arrow = 5px
_tooltip_bg = black(0.9)
.tooltip,
.has-tooltip:before
padding: .2em .5em
background: _tooltip_bg
color: #fff
font-size: 14px
border-radius: form_border_radius
.tooltip:after,
.has-tooltip:after
triangle("up", _tooltip_arrow, _tooltip_bg)
.tooltip:after
top: (-(_tooltip_arrow))
.has-tooltip:before
margin-top: _tooltip_arrow

View File

@ -0,0 +1,138 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Base CSS
// Global reset.
*
padding: 0
margin: 0
box-sizing: border-box
article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary
display: block
sup, sub, small, code
line-height: 0
img
max-width: 100%
height: auto
img
vertical-align: middle
a img, a.img
border: none !important
background-image: none !important
abbr
border-bottom: none
ul
list-style: none
table
border-collapse: collapse
border-spacing: 0
html
// Force scrollbar in non IE
overflow-y: scroll
// Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g
-webkit-text-size-adjust: 100%
-ms-text-size-adjust: 100%
if sticky_footer_height
position: relative
min-height: 100%
// Sticky footer: mystrd.at/modern-clean-css-sticky-footer/.
if sticky_footer_height
body
padding-bottom: sticky_footer_height
.footer
sticky-footer(sticky_footer_height)
padding: 0 spacer
if max_width
&-i
max-width: max_width
margin-left: auto
margin-right: auto
// www.aestheticallyloyal.com/public/optimize-legibility/
h1, h2, h3
text-rendering: optimizeLegibility
// Hand cursor on clickable input elements
input[type="button"],
input[type="submit"],
input[type="image"],
button
cursor: pointer
button[disabled],
input[disabled]
cursor: default
// Forms: github.com/necolas/normalize.css/blob/master/normalize.css.
button,
input
line-height: normal
button,
input,
select,
textarea
font-family: inherit
font-size: 100%
button,
input[type="button"],
input[type="reset"],
input[type="submit"]
-webkit-appearance: button
input[type="search"]
-webkit-appearance: textfield
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button
-webkit-appearance: none
button::-moz-focus-inner,
input::-moz-focus-inner
border: 0
textarea
overflow: auto
vertical-align: top
resize: vertical
fieldset,
legend
border: 0
[hidden]
display: none
// Pre with wrapping.
pre
white-space: pre-wrap
// Addresses outline inconsistency between Chrome and other browsers.
a:focus
outline: thin dotted
// Improve readability when focused and also mouse hovered in all browsers.
a:hover,
a:active
outline: 0
// Text selection and iOS tap highlighting.
if light(bg_color)
_selection_color = rgba(darken(bg_color,60),.5)
else
_selection_color = rgba(lighten(bg_color,60),.5)
text-selection(base_color, _selection_color)
a:link
-webkit-tap-highlight-color: rgba(_selection_color,.25)
// Hide phone links from desktop browsers.
.no-touch a[href^="tel"]
&:link,
&:visited,
&:hover,
&:active,
&:focus
position: inherit
text-decoration: inherit
border: inherit
color: inherit
background-image: none
cursor: default
if content_max_width
.content
max-width: content_max_width
margin: 0 auto

View File

@ -0,0 +1,20 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Helper classes
// Element is hidden.
.is-hidden
display: none
// Element is invisible (but occupies place on page).
.is-invisible
visibility: hidden
/// Element is in transit between hidden (.is-hidden) and visible.
.is-transit
display: block
&.l-center
display: table
// Clearfix.
.group
clearfix()

View File

@ -0,0 +1,215 @@
# Tâmia © 2013 Artem Sapegin http://sapegin.me
# https://github.com/sapegin/tamia
# JS component base class
'use strict'
$ = jQuery
###
JS component base class.
Elements: any HTML element with class name that follow a pattern `.js-name` where `name` is an element name.
States: any class on component root HTML node that follow a pattern `.is-state` where `state` is a state name.
After initialization all components will have `ok` state.
Example:
class Pony extends Component
init: ->
@on('click', 'toggle', @toggle)
toggle: ->
@toggleState('pink')
tamia.initComponents(pony: Pony)
<div class="pink-pony is-pink" data-component="pony">
<button class="pink-pony__button js-toggle">To pink or not to pink?</div>
</div>
###
class Component
constructor: (elem) ->
if not elem or elem.nodeType isnt 1 then throw new ReferenceError('No DOM node passed to Component constructor.')
@elemNode = elem
@elem = $(elem)
@initializable = @isInitializable()
if not @initializable
return
@_fillStates()
if @isSupported()
@handlers = {}
@init()
@addState('ok')
else
@fallback()
@addState('unsupported')
###
Put all your initialization code in this method.
###
init: ->
# Should be implemented
###
You can implement this method to do destroy component.
###
destroy: ->
# Could be implemented
###
Implement this method if you want to check whether browser is good for your component or not.
@returns {Boolean}
###
isSupported: ->
return true
###
Implement this method if you want to check whether component could be initialized.
Example:
isInitializable: ->
# Do not initialize component if it's not visible
@isVisible()
@return {Boolean}
###
isInitializable: ->
return true
###
You can implement this method to do some fallbacks. It will be called if isSupported() returns false.
###
fallback: ->
# Could be implemented
###
Finds element.
@param {String} name Element ID.
@return {jQuery} Element with .js-name class.
###
find: (name) ->
return @elem.find(".js-#{name}").first()
###
Attaches event handler.
@param {String} events Event names (space separated).
@param {String} [element] Element id.
@param {Function} handler Handler function (scope will automatically sets to this).
###
on: (args...) ->
@_toggleEvent('on', args...)
###
Detaches event handler.
@param {String} events Event names (space separated).
@param {String} [element] Element id.
@param {Function} handler Handler function (scope will automatically sets to this).
###
off: (args...) ->
@_toggleEvent('off', args...)
###
Returns component state.
@param {String} [name] State name.
@return {Boolean} Sate value.
###
hasState: (name) ->
return !!@states[name]
###
Sets state to true.
@param {String} [name] State name.
###
addState: (name) ->
@toggleState(name, true)
###
Sets state to false.
@param {String} [name] State name.
###
removeState: (name) ->
@toggleState(name, false)
###
Toggles state value.
@param {String} [name] State name.
@param {Boolean} [value] State value.
###
toggleState: (name, value = not @states[name]) ->
@states[name] = value
@_updateStates()
###
Returns component visibility.
@return {Boolean}
###
isVisible: ->
return !!(@elemNode.offsetWidth or @elemNode.offsetHeight)
_toggleEvent: (action, args...) ->
if typeof args[1] is 'string'
# Selector passed
args[1] = ".js-#{args[1]}"
# Bind handler to this
funcArg = args.length - 1 # Last argument
func = args[funcArg]
handler
if @handlers[func]
handler = @handlers[func]
if action is 'on'
if handler
handler.counter++
else
@handlers[func] = handler =
counter: 1
func: func.bind(this)
return if not handler
args[funcArg] = handler.func
# Pass to jQuery
@elem[action](args...)
# Clean up
if action is 'off'
handler.counter--
if handler.counter <= 0
@handlers[func] = null
_fillStates: ->
states = {}
classes = @elemNode.className.split(' ')
for clsName of classes
cls = classes[clsName]
re = /^is-/
if re.test(cls)
states[cls.replace(re, '')] = true
@states = states
_updateStates: ->
classes = @elemNode.className
classes = $.trim(classes.replace(/\bis-[-\w]+/g, ''))
classes = classes.split(/\s+/)
for name of @states
if @states[name]
classes.push("is-#{name}")
@elemNode.className = classes.join(' ')
Component.__tamia_cmpnt__ = true
window.Component = Component

View File

@ -0,0 +1,278 @@
(function() {
'use strict';
var $, Component,
__slice = [].slice;
$ = jQuery;
/*
JS component base class.
Elements: any HTML element with class name that follow a pattern `.js-name` where `name` is an element name.
States: any class on component root HTML node that follow a pattern `.is-state` where `state` is a state name.
After initialization all components will have `ok` state.
Example:
class Pony extends Component
init: ->
@on('click', 'toggle', @toggle)
toggle: ->
@toggleState('pink')
tamia.initComponents(pony: Pony)
<div class="pink-pony is-pink" data-component="pony">
<button class="pink-pony__button js-toggle">To pink or not to pink?</div>
</div>
*/
Component = (function() {
function Component(elem) {
if (!elem || elem.nodeType !== 1) {
throw new ReferenceError('No DOM node passed to Component constructor.');
}
this.elemNode = elem;
this.elem = $(elem);
this.initializable = this.isInitializable();
if (!this.initializable) {
return;
}
this._fillStates();
if (this.isSupported()) {
this.handlers = {};
this.init();
this.addState('ok');
} else {
this.fallback();
this.addState('unsupported');
}
}
/*
Put all your initialization code in this method.
*/
Component.prototype.init = function() {};
/*
You can implement this method to do destroy component.
*/
Component.prototype.destroy = function() {};
/*
Implement this method if you want to check whether browser is good for your component or not.
@returns {Boolean}
*/
Component.prototype.isSupported = function() {
return true;
};
/*
Implement this method if you want to check whether component could be initialized.
Example:
isInitializable: ->
# Do not initialize component if it's not visible
@isVisible()
@return {Boolean}
*/
Component.prototype.isInitializable = function() {
return true;
};
/*
You can implement this method to do some fallbacks. It will be called if isSupported() returns false.
*/
Component.prototype.fallback = function() {};
/*
Finds element.
@param {String} name Element ID.
@return {jQuery} Element with .js-name class.
*/
Component.prototype.find = function(name) {
return this.elem.find(".js-" + name).first();
};
/*
Attaches event handler.
@param {String} events Event names (space separated).
@param {String} [element] Element id.
@param {Function} handler Handler function (scope will automatically sets to this).
*/
Component.prototype.on = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return this._toggleEvent.apply(this, ['on'].concat(__slice.call(args)));
};
/*
Detaches event handler.
@param {String} events Event names (space separated).
@param {String} [element] Element id.
@param {Function} handler Handler function (scope will automatically sets to this).
*/
Component.prototype.off = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return this._toggleEvent.apply(this, ['off'].concat(__slice.call(args)));
};
/*
Returns component state.
@param {String} [name] State name.
@return {Boolean} Sate value.
*/
Component.prototype.hasState = function(name) {
return !!this.states[name];
};
/*
Sets state to true.
@param {String} [name] State name.
*/
Component.prototype.addState = function(name) {
return this.toggleState(name, true);
};
/*
Sets state to false.
@param {String} [name] State name.
*/
Component.prototype.removeState = function(name) {
return this.toggleState(name, false);
};
/*
Toggles state value.
@param {String} [name] State name.
@param {Boolean} [value] State value.
*/
Component.prototype.toggleState = function(name, value) {
if (value == null) {
value = !this.states[name];
}
this.states[name] = value;
return this._updateStates();
};
/*
Returns component visibility.
@return {Boolean}
*/
Component.prototype.isVisible = function() {
return !!(this.elemNode.offsetWidth || this.elemNode.offsetHeight);
};
Component.prototype._toggleEvent = function() {
var action, args, func, funcArg, handler, _ref;
action = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
if (typeof args[1] === 'string') {
args[1] = ".js-" + args[1];
}
funcArg = args.length - 1;
func = args[funcArg];
handler;
if (this.handlers[func]) {
handler = this.handlers[func];
}
if (action === 'on') {
if (handler) {
handler.counter++;
} else {
this.handlers[func] = handler = {
counter: 1,
func: func.bind(this)
};
}
}
if (!handler) {
return;
}
args[funcArg] = handler.func;
(_ref = this.elem)[action].apply(_ref, args);
if (action === 'off') {
handler.counter--;
if (handler.counter <= 0) {
return this.handlers[func] = null;
}
}
};
Component.prototype._fillStates = function() {
var classes, cls, clsName, re, states;
states = {};
classes = this.elemNode.className.split(' ');
for (clsName in classes) {
cls = classes[clsName];
re = /^is-/;
if (re.test(cls)) {
states[cls.replace(re, '')] = true;
}
}
return this.states = states;
};
Component.prototype._updateStates = function() {
var classes, name;
classes = this.elemNode.className;
classes = $.trim(classes.replace(/\bis-[-\w]+/g, ''));
classes = classes.split(/\s+/);
for (name in this.states) {
if (this.states[name]) {
classes.push("is-" + name);
}
}
return this.elemNode.className = classes.join(' ');
};
return Component;
})();
Component.__tamia_cmpnt__ = true;
window.Component = Component;
}).call(this);

View File

@ -0,0 +1,18 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Functions
// White color with transparency.
//
// opacity - Opacity value (01).
//
// Returns color.
white(opacity)
rgba(255, 255, 255, opacity)
// Black color with transparency.
//
// opacity - Opacity value (01).
//
// Returns color.
black(opacity)
rgba(0, 0, 0, opacity)

View File

@ -0,0 +1,147 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Images, sprites, Retina support
//
// Configuration
//
// Enable Retina support (default: false).
retinafy ?= false
// Path to calculate file system image path based on CSS path (default: .).
images_relative_root ?= '.'
// Default sprite image file (default: ../build/sprite.png).
sprite_image ?= '../build/sprite.png';
sprite_image = sprite_image + '?' + sprite_fingerprint if sprite_fingerprint
// Sprite step size (default: 20px).
sprite_step ?= 20px;
//
// Functions
//
// background-image with Retina variant.
//
// path - Image file path.
// x - background-position x (default: 0).
// y - background-position y (default: 0).
//
// Retina image file should be named path@2x.png.
if retinafy
image(path, x=0, y=0)
background: url(path) x y
+retina()
ext = extname(path)
hdpath = dirname(path) + '/' + basename(path, ext) + '@2x' + ext
background: url(hdpath) x y
background-size: image-size(pathjoin(images_relative_root, path))
else
image(path, x=0, y=0)
background: url(path) x y
// Sprite (to use in pseudo element).
//
// Sprite generated by grunt-squirrelsprite:
// img - Sprite image variable.
//
// Manually created sprite:
// x - Horizontal position in sprite grid.
// y - Vertical position in sprite grid.
// w - Sprite width, pixels.
// h - sprite height, pixels.
//
// Example:
//
// .elem
// sprite(sprite_pony);
//
// .elem2
// sprite(5, 6, 36, 22);
sprite(img)
if not @content and match(":(before|after)", selector())
content: ""
if not @display
display: inline-block
if length(img) > 1
image(sprite_image, img[0], img[1])
width: img[2]
height: img[3]
else
image(sprite_image, sprite-x(arguments[0]), sprite-y(arguments[1]))
width: arguments[2]
height: arguments[3]
// Horizontal position of sprite image.
//
// x - Horizontal position in sprite grid.
//
// Returns pixels.
sprite-x(x)
(-((x - 1)*sprite_step+1));
// Vertical position of sprite image.
//
// y - Vertical position in sprite grid.
//
// Returns pixels.
sprite-y(y)
(-((y - 1)*sprite_step+1));
// background-position for sprite.
//
// x - Horizontal position in sprite grid.
// y - Vertical position in sprite grid.
//
// Example:
//
// .elem
// sprite-bg()
// sprite-pos(5,6)
// sprite-pos(sprite_pony-hover)
sprite-pos(img)
if length(img) > 1
background-position: img[0] img[1]
else
background-position: sprite-x(img[0]) sprite-y(img[1])
// background-image for sprite.
//
// Sprite generated by grunt-squirrelsprite:
// img - Sprite image variable.
//
// Manually created sprite:
// x - Horizontal position in sprite grid (default: 0).
// y - Vertical position in sprite grid (default: 0).
sprite-bg(x=0, y=0)
image(sprite_image, x, x)
// Element width for sprite.
//
// Returns pixels
sprite-width(img)
img[2]
// Element height for sprite.
//
// Returns pixels
sprite-height(img)
img[3]
// Element width/height for sprite.
//
// Example:
//
// .elem
// sprite-size(sprite_pony);
sprite-size(img)
width: sprite-width(img)
height: sprite-height(img)
// Shifts element half height to top
//
sprite-shift-top(img)
margin-top: (-(round(sprite-height(img)/2)))

View File

@ -0,0 +1,39 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Configuration
/// Debug mode.
DEBUG ?= false
// Default spacer (default: 10px).
spacer ?= 10px;
// Max page with.
max_width ?= null;
// Max content block (.content) with.
content_max_width ?= null;
// Sticky footer height (default: no sticky footer).
sticky_footer_height ?= null;
// Background color (default: white).
bg_color ?= #fff;
// Base text color (default: #111).
base_color ?= #111;
// Form focus outline color (default: hsl(204,68%,69%)).
form_focus_color ?= hsl(204, 68%, 69%)
// Form border radius (default: .15em).
form_border_radius ?= .15em
@import "./misc"
@import "./functions"
@import "./layout"
@import "./mediaqueries"
@import "./images"
@import "./bootstrap"
@import "./classes"
@import "./links"

View File

@ -0,0 +1,295 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Grids and layouts
//
// Configuration
//
// Grid gutter size, in pixels (default: 2×spacer).
grid_gutter ?= 2*spacer
// Number of columns in grid (default: 12).
grid_columns ?= 12
//
// Grid
//
/// Inspired by http://zengrids.com
// Columns wrapper.
grid-row()
clearfix()
grid-wrapper()
// Column (grid).
//
// position - Start column number (default: 1).
// span - Width, in culumns (default: 1).
// context - Width of parent column (default: null).
//
// Example:
//
// .row>.col1+.col2
//
// .row
// grid-row()
// .col1
// grid-col(1,2)
// .col2
// grid-col(3,10)
grid-col(position=1, span=1, context=null)
_grid-column(position, span, context)
_grid-float()
grid-padding()
// Single column.
//
// position - Start column number (default: 1).
// span - Width, in culumns (default: 1).
// context - Width of parent column (default: null).
grid-one(position=1, span=1, context=null)
_grid-column(position, span, context)
grid-padding()
// Single column (without padding, wrapper for child columns).
//
// position - Start column number (default: 1).
// span - Width, in culumns (default: 1).
// context - Width of parent column (default: null).
grid-one-container(position=1, span=1, context=null)
clearfix()
_grid-column(position, span, context)
// Gutter size negative margin to make column with different background.
// You should adjust padding depending on content.
grid-explode()
margin: (-(grid_gutter))
// Width of column, in percent.
//
// position - Start column number (default: 1).
// span - Width, in culumns (default: 1).
//
// Returns percent.
grid-width(span=1, context=null)
context = grid_columns if not context
unit-width = 100% / context
span * unit-width
// Column left/right padding.
//
// full - Padding on all sides if true, left/right otherwise (default: false).
grid-padding(full=false)
side-gutter = grid_gutter / 2;
if full
padding: side-gutter
else
padding-left: side-gutter
padding-right: side-gutter
// Column wrapper left/right negative margin.
grid-wrapper()
side-gutter = (-(grid_gutter / 2))
margin-left: side-gutter
margin-right: side-gutter
_grid-column(position=1, span=1, context=null)
context = grid_columns if not context
unit-width = 100% / context
width: span * unit-width
margin-left: (position - 1) * unit-width
_grid-float()
float: left
margin-right: -100%
//
// Layouts
//
// Layout wrapper.
layout-row()
grid-wrapper()
display: flex
flex-flow: row wrap
// flex-direction: row
/// IE8-9
.no-flexbox &
letter-spacing: -0.31em
// Column (simple layout).
//
// part - 1/Nth part of wrapper.
//
// Example:
//
// .row>.col+.col
//
// .row
// layout-row()
// .col
// layout-nth(2) // Half
layout-nth(part)
_layout-col()
_layout-part(part)
// Change number of columns.
//
// Use it to change number of columns (defined via layout-nth()) inside media queries.
//
// part - 1/Nth part of wrapper.
layout-change(part)
_layout-part(part)
// Disable columns.
//
// Alias for layout-change(1).
layout-stop()
_layout-part(1)
// Center element with specified width and hegith.
center(width, height=null)
size(width, height)
left: 50%
top: 50%
margin-left: (-(@width / 2))
margin-top: (-(@height / 2))
_layout-col()
grid-padding()
// IE8-9
.no-flexbox &
display: inline-block
vertical-align: top
letter-spacing: normal
_layout-part(part)
width: (100% / part)
//
// Classes
//
// Column wrapper.
.l-row
layout-row()
.l-sixth,
.l-quarter,
.l-third,
.l-half,
.l-three-quarters,
.l-two-thirds
_layout-col()
// Sixth (to use inside .l-row).
.l-sixth
_layout-part(6)
// Quarter (to use inside .l-row).
.l-quarter
_layout-part(4)
// Three quarters (to use inside .l-row).
.l-three-quarters
_layout-part(4/3)
// Third (to use inside .l-row).
.l-third
_layout-part(3)
// Two thirds (to use inside .l-row).
.l-two-thirds
_layout-part(3/2)
// Half (to use inside .l-row).
.l-half
_layout-part(2)
// Flexible columns with left (.l-left) and right (.l-right) text alignment (to use inside .l-row).
.l-left,
.l-right
flex: 1
.l-right
text-align: right
.no-flexbox
.l-left
float: left
.l-right
float: right
// Centered content (vertically and horizontally).
//
// Example:
//
// .l-center>.l-center-i>span
.l-center
display: table
width: 100%
height: 100%
&-i
display: table-cell
text-align: center
vertical-align: middle
//
// Spacing
//
// Space after block.
//
// rows - Number of rows (one row = default spacer).
space(rows=1)
margin-bottom: rows*spacer
// Standard bottom margin.
.l-space
space()
// Double bottom margin.
.l-double-space
space(2)
// Triple bottom margin.
.l-triple-space
space(3)
// Quadruple bottom margin.
.l-quad-space
space(4)
///
/// Debug stuff
///
if DEBUG
.g-debug-col
grid-padding()
float: left
width: grid-width()
.g-debug-helper
position: absolute
left: 0
right: 0
height: 100%
min-height: 3000px
z-index: 10000
overflow: hidden
pointer-events: none
*
height: 100%
[data-component="grid"]
grid-wrapper()
.g-debug-col:before
content: ""
display: block
height: inherit
background: hsla(220,40%,50%,.25)

View File

@ -0,0 +1,195 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Links
//
// Configuration
//
// Link style (default: underline).
//
// Values:
// - underline - text-decoration:underline.
// - border - border-bottom:1px solid.
// - gradient - Uses CSS gradients to position line under text (cannot change line color on hover).
link_style ?= "underline"
// Link color (default: #1978c8).
link_color ?= #1978c8
// Visited link color.
visited_color ?= link_color
// Hovered link color.
hover_color ?= link_color
// Link underline color.
link_underline_color ?= rgba(link_color,.4)
// Visited link underline color.
visited_underline_color ?= rgba(visited_color,.4)
// Hovered link underline color.
hover_underline_color ?= rgba(hover_color,.4)
// Link underline position (only when link_style == gradient, default: 80%)
link_underline_position ?= 80%
link_underline_position = 76.5% if link_style == "underline"
// Pressable links (shifts down by 1px, default: false).
link_pressable ?= false
//
// Mixins
//
// Adds link underline (adds nothing for "underline" and "border" types)
link-underline(color)
if link_style == "gradient"
background-image: linear-gradient(to right, color, color)
// Adds fake link underline (adds nothing for "underline" type)
link-fake-underline(color)
if link_style != "border"
background-image: linear-gradient(to right, color, color 50%, transparent 50%)
// :hover, :active and :focus states of the link.
//
// Example:
// +link-hovers()
// color: #bada55
link-hovers() {
&:hover,
&:active,
&:focus {
{block}
}
}
// All states of the link.
//
// Example:
// +link-all-states()
// color: @color
link-all-states() {
&,
&:link,
&:visited,
&:hover,
&:active,
&:focus {
{block}
}
}
//
// Classes
//
// Pressable element: pointer cursor + disable text selection.
.pressable-inset
no-select()
cursor: pointer
// Pressable element: shifts down by 1px on click.
.pressable
@extend .pressable-inset
&:active
position: relative if link_pressable
top: 1px if link_pressable
// Non-pressable element: cancels .pressable.
.no-pressable
&,
&:hover,
&:active
cursor: default
&:active
position: static if link_pressable
// Remove underline.
.no-underline
&,
&:link,
&:visited,
&:hover,
&:active,
&:focus
text-decoration: none
border-bottom: 0
background-image: none
// Link.
//
// .link_fake - Pseudo link with dashed underline.
// .link_quoted - Link in quotes (quotes should be colored but not underlined). Example: a.link.link_quoted>u.
.link
&,
& u
@extend .pressable
transition: border .1s ease-in-out, color .2s ease-in-out, background .2s ease-in-out
cursor: pointer
if link_style == "underline"
text-decoration: underline
else
text-decoration: none
if link_style == "border"
border-bottom-width: 1px
border-bottom-style: solid
if link_style == "gradient"
background-position: 0 link_underline_position
background-size: 5px 1px
background-repeat: repeat-x
&,
&:link,
& u,
&:link u
link-underline(link_underline_color)
color: link_color
&:visited,
&:visited u
link-underline(visited_underline_color)
color: visited_color
&:hover,
&:active,
&:focus,
&:hover u,
&:active u,
&:focus u
link-underline(hover_underline_color)
color: hover_color
&_fake
if link_style == "border"
border-bottom-style: dotted
if link_style != "gradient"
text-decoration: none
background-position: 0 link_underline_position
background-size: 5px 1px
background-repeat: repeat-x
&,
&:link,
&:visited
link-fake-underline(link_underline_color)
color: link_color
&:hover,
&:active,
&:focus
link-fake-underline(link_underline_color)
color: hover_color
&_quoted
@extend .no-underline
.no-cssgradients
.link
text-decoration: underline
.link_fake
text-decoration: none
border-bottom: 1px dotted

View File

@ -0,0 +1,41 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Media queries
/// Based on https://github.com/jenius/rupture
// Media query shortcut: viewport width is greater than or equal to specified value.
//
// Example:
//
// .pony
// color: #c0ffee
// +above(320px)
// color: #bada55
//
// min - Min width.
above(min)
condition = 'only screen and (min-width: %s)' % min
@media condition
{block}
// Media query shortcut: viewport width is less than or equal to specified value.
//
// max - Max width.
below(max)
condition = 'only screen and (max-width: %s)' % max
@media condition
{block}
// Media query shortcut: viewport width is in between specified values.
//
// min - Min width.
// max - Max width.
between(min, max)
condition = 'only screen and (min-width: %s) and (max-width: %s)' % (min max)
@media condition
{block}
// Media query shortcut: retina screen.
retina()
@media (min-resolution: 1.5dppx), (-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (min-resolution: 144dpi)
{block}

View File

@ -0,0 +1,174 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// Misc functions and mixins
/// Colors for debug() function.
_debug_colors = cyan magenta orange green blue red
//
// Easings
//
/// More here: https://github.com/thoughtbot/bourbon/blob/master/app/assets/stylesheets/addons/_timing-functions.scss
// Ease in sine.
ease-in-sine = cubic-bezier(0.47, 0, 0.745, 0.715)
// Ease out quint.
ease-out-quint = cubic-bezier(0.23,1,0.32,1)
// Ease out back.
ease-out-back = cubic-bezier(0.175,0.885,0.32,1.275)
//
// Typography and text
//
// Ellipsis text overflow.
ellipsis()
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
// Tweak inverted text (light on dark) for OS X.
tweak-inverted-text()
-webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale
// Enables ligatures in text.
enable-ligatures()
text-rendering: optimizeLegibility
-webkit-font-feature-settings: "liga", "dlig"
-moz-font-feature-settings: "liga=1, dlig=1"
font-feature-settings: "liga", "dlig"
// Text selection style.
//
// color - Text color.
// background - Background color.
text-selection(color, background)
::-moz-selection
color: color
background: background
text-shadow: none
::selection
color: color
background: background
text-shadow: none
// Input placeholder color.
//
// color - Placeholder color.
placeholder-color(color)
&::-webkit-input-placeholder
color: color
&::-moz-placeholder
color: color
&:-ms-input-placeholder
color: color
// Disables text selection.
no-select()
-webkit-touch-callout: none
user-select: none
//
// Misc.
//
// Clearfix.
clearfix()
&:before
&:after
content: ""
display: table
&:after
clear: both
// Set element width and height.
//
// width - Width.
// [height] - Height (the same as width if not passed).
size(width, height=null)
width: width
if height
height: height
else
height: width
// Disables columns.
no-cols()
position: static
display: block
float: none
width: auto
margin-left: 0
margin-right: 0
// Disables transitions.
//
// imp - Important? (default: false).
no-transition(imp=false)
/// It is the shortest crossbrowser way
if imp
transition 0s !important
else
transition 0s
// Draws triangle.
//
// direction - Triangle direction (up, down, left, right).
// size - Size (default: 10px).
// color - Color (default: black).
triangle(direction=up, size=10px, color=#000)
/// Borrowed from https://github.com/jenius/roots-css/blob/master/roots-css/utilities.styl.
width: 0
height: 0
if direction is up
border-left: size solid transparent
border-right: size solid transparent
border-bottom: size solid color
else if direction is down
border-left: size solid transparent
border-right: size solid transparent
border-top: size solid color
else if direction is left
border-top: size solid transparent
border-bottom: size solid transparent
border-right: size solid color
else if direction is right
border-top: size solid transparent
border-bottom: size solid transparent
border-left: size solid color
// Draws color outline around an element.
//
// Works only when DEBUG == true.
debug()
outline: 1px solid pop(_debug_colors) if DEBUG
///
/// Internal stuff
///
/// Sticky footer wrapper.
///
/// h - Footer height.
sticky-footer-wrapper(h)
position: relative
min-height: 100%
margin-bottom: h
/// Sticky footer.
///
/// h - Footer height.
sticky-footer(h)
position: absolute
left: 0
right: 0
bottom: 0
height: h

View File

@ -0,0 +1,363 @@
// Tâmia © 2013 Artem Sapegin http://sapegin.me
// https://github.com/sapegin/tamia
// JS core
// jQuery and Modernizr arent required but very useful
/*jshint newcap:false*/
/*global DEBUG:true, Modernizr:false, console:false*/
/**
* Debug mode.
*
* You can use DEBUG global variable in your scripts to hide some code from minified production version of JavaScript.
*
* To make it work add to your Gruntfile:
*
* uglify: {
* options: {
* compress: {
* global_defs: {
* DEBUG: !!grunt.option('debug')
* }
* }
* },
* ...
* }
*
* Then if you run `grunt --debug` DEBUG variable will be true and false if you run just `grunt`.
*/
if (typeof window.DEBUG === 'undefined') window.DEBUG = true;
;(function(window, jQuery, Modernizr, undefined) {
'use strict';
// IE8+
if (!document.querySelectorAll) return;
// Namespace
var tamia = window.tamia = {};
if (DEBUG) {
// Debug logger
var addBadge = function(args, name) {
// Color console badge
// Based on https://github.com/jbail/lumberjack
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('chrome') !== -1 || ua.indexOf('firefox') !== -1) {
var format = '%c %s %c ' + args.shift();
args.unshift(format, 'background:#aa759f; color:#fff', name, 'background:inherit; color:inherit');
}
else {
args[0] = name + ': ' + args[0];
}
return args;
};
var logger = function() {
var args = Array.prototype.slice.call(arguments);
var func = args.shift();
console[func].apply(console, addBadge(args, 'Tâmia'));
};
var log = tamia.log = logger.bind(null, 'log');
var warn = tamia.warn = logger.bind(null, 'warn');
// Check optional dependencies
if (!jQuery) warn('jQuery not found.');
if (!jQuery.Transitions) warn('jQuery Transition Events plugin (tamia/vendor/transition-events.js) not found.');
if (!Modernizr) warn('Modernizr not found.');
// Check required Modernizr features
$.each([
'csstransitions',
'cssgradients',
'flexbox',
'touch',
], function(idx, feature) {
if (!(feature in Modernizr)) warn('Modernizr should be built with "' + feature + '" feautre.');
});
}
var _containersCache;
var _components = {};
var _initializedAttribute = '_tamia-yep';
function _getContainers(parent) {
return (parent || document).querySelectorAll('[data-component]');
}
/**
* Initialize components.
*
* @param {Object} components Initializers for each component.
*
* Examples:
*
* <div data-component="pony"></div>
*
* tamia.initComponents({
* // New style component
* pony: Pony, // class Pony extends Component {...}
* // Plain initializer
* pony: function(elem) {
* // $(elem) === <div data-component="pony">
* },
* // Initialize jQuery plugins (plain initializer)
* jquerypony: function(elem) {
* $(elem).pluginmethod({option1: 'val1', options2: 'val2'});
* $(elem).pluginmethod2();
* },
* // Initialize jQuery plugins (shortcut)
* jquerypony: {
* pluginmethod: {option1: 'val1', options2: 'val2'},
* pluginmethod2: ['attr1', 'attr2', 'attr3'],
* pluginmethod3: null
* }
* }
*
* Caveats:
*
* 1. To initialize components inside container that was hidden or inside dynamically created container use
* init.tamia event: `$('.js-container').trigger('init.tamia');`
* 2. No components will be initialized twice. Its safe to trigger init.tamia event multiple times: only new nodes
* or nodes that was hidden before will be affected.
*/
tamia.initComponents = function(components, parent) {
var containers;
if (parent === undefined) {
containers = _containersCache || (_containersCache = _getContainers());
}
else {
// Init all components inside DOM node
containers = _getContainers(parent);
components = _components;
}
// Init components
for (var containerIdx = 0, containerCnt = containers.length; containerIdx < containerCnt; containerIdx++) {
var container = containers[containerIdx];
var componentName = container.getAttribute('data-component');
var component = components[componentName];
if (!component || container.hasAttribute(_initializedAttribute)) continue;
var initialized = true;
if ('__tamia_cmpnt__' in component) {
// New style component
initialized = (new component(container)).initializable;
}
else if (typeof component === 'function') {
// Old style component
initialized = component(container);
}
else if (jQuery) {
// jQuery plugins shortcut
for (var method in component) {
var params = component[method];
var elem = jQuery(container);
if (DEBUG && !jQuery.isFunction(elem[method])) warn('jQuery method "%s" not found (used in "%s" component).', method, componentName);
if (jQuery.isArray(params)) {
elem[method].apply(elem, params);
}
else {
elem[method](params);
}
}
}
if (initialized !== false) {
container.setAttribute(_initializedAttribute, 'yes');
}
}
// Add new components to all components array
for (var name in components) {
_components[name] = components[name];
}
};
if (jQuery) {
var _doc = jQuery(document);
var _hiddenClass = 'is-hidden';
var _transitionClass = 'is-transit';
var _appearedEvent = 'appeared.tamia';
var _disappearedEvent = 'disappeared.tamia';
var _fallbackTimeout = 1000;
/**
* Registers Tâmia events (eventname.tamia) on document.
*
* Example:
*
* // Registers enable.tamia event.
* tamia.registerEvents({
* enable: function(elem) {
* }
* });
*
* @param {Object} handlers Handlers list.
*/
tamia.registerEvents = function(handlers) {
var events = $.map(handlers, _tamiaze).join(' ');
_doc.on(events, function(event) {
if (DEBUG) log('Event "%s":', event.type, event.target);
handlers[event.type](event.target);
});
};
var _tamiaze = function (handler, name) {
return name + '.tamia';
};
/**
* Events
*/
var _handlers = {};
/**
* Init components inside any jQuery node.
*
* Examples:
*
* $(document).trigger('init.tamia');
* $('.js-container').trigger('init.tamia');
*/
_handlers.init = function(elem) {
tamia.initComponents(undefined, elem);
};
/**
* Show element with CSS transition.
*
* appeared.tamia event will be fired the moment transition ends.
*
* Example:
*
* .dialog
* transition: opacity .5s ease-in-out
* ...
* &.is-hidden
* opacity: 0
*
* <div class="dialog is-hidden js-dialog">...</div>
*
* $('.js-dialog').trigger('appear.tamia');
*/
_handlers.appear = function(elem) {
elem = $(elem);
if (Modernizr && Modernizr.csstransitions) {
if (elem.hasClass(_transitionClass) && !elem.hasClass(_hiddenClass)) return;
elem.addClass(_transitionClass);
setTimeout(function() {
elem.removeClass(_hiddenClass);
elem.afterTransition(function() {
elem.removeClass(_transitionClass);
elem.trigger(_appearedEvent);
});
}, 0);
}
else {
elem.removeClass(_hiddenClass);
elem.trigger(_appearedEvent);
}
};
/**
* Hide element with CSS transition.
*
* disappeared.tamia event will be fired the moment transition ends.
*
* Opposite of `appear.tamia` event.
*/
_handlers.disappear = function(elem) {
elem = $(elem);
if (Modernizr && Modernizr.csstransitions) {
if (elem.hasClass(_transitionClass) && elem.hasClass(_hiddenClass)) return;
elem.addClass(_transitionClass);
elem.addClass(_hiddenClass);
elem.afterTransition(function() {
elem.removeClass(_transitionClass);
elem.trigger(_disappearedEvent);
});
}
else {
elem.addClass(_hiddenClass);
elem.trigger(_disappearedEvent);
}
};
/**
* Toggles elements visibility with CSS transition.
*
* See `appear.tamia` event for details.
*/
_handlers.toggle = function(elem) {
elem = $(elem);
if (elem.hasClass(_hiddenClass)) {
_handlers.appear(elem);
}
else {
_handlers.disappear(elem);
}
};
tamia.registerEvents(_handlers);
/**
* Controls.
*
* Fires jQuery event to specified element on click at this element.
*
* @param data-fire Event name.
* @param [data-target] Target element selector.
* @param [data-closest] Target element selector: search only through element ancestors.
* @param [data-attrs] Comma separated attributes list.
*
* Either of data-target or data-closest is required.
*
* Example:
*
* <span data-fire="slider-next" data-target=".portfolio" data-attrs="1,2,3">Next</span>
* <!-- $('.portfolio').trigger('slider-next', [1, 2, 3]); -->
*/
_doc.on('click', '[data-fire]', function(event) {
var elem = jQuery(event.currentTarget);
var data = elem.data();
if (DEBUG) if (!data.target && !data.closest) return log('You should define either data-target or data-closest on', elem[0]);
var target = data.target && jQuery(data.target) || elem.closest(data.closest);
if (DEBUG) if (!target.length) return log('Target element %s not found for', data.target || data.closest, elem[0]);
var attrs = data.attrs;
if (DEBUG) log('Fire "%s" with attrs [%s] on', data.fire, attrs || '', target);
target.trigger(data.fire, attrs ? attrs.split(/[;, ]/) : undefined);
event.preventDefault();
});
/**
* Grid helper.
*
* Example:
*
* <div data-component="grid"></div>
*/
if (DEBUG) tamia.initComponents({
grid: function(elem) {
elem = $(elem);
elem
.addClass('g-row')
.html(
new Array((elem.data('columns') || 12) + 1).join('<b class="g-debug-col" style="height:'+document.documentElement.scrollHeight+'px"></b>')
)
;
}
});
}
}(window, window.jQuery, window.Modernizr));

View File

@ -0,0 +1,212 @@
/*
* Copyright 2012 Andrey A.I. Sitnik <andrey@sitnik.ru>,
* sponsored by Evil Martians.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
;(function($) {
"use strict";
// Common methods and properties for jQuery Transition Events plugin.
// Mostly for internal usage, but maybe helpful for some hack stuff:
//
// if ( $.Transitions.isSupported() ) {
// // CSS Transitions is supported
// }
$.Transitions = {
// Hash of property name to event name with vendor prefixes.
// It is used to detect prefix.
_names: {
// Webkit must be on bottom, because Opera try to use webkit
// prefix.
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend'
},
// Return array of milliseconds for CSS value of `transition-duration`.
// Its used in `$.fn.afterTransition`.
_parseTimes: function (string) {
var value, array = string.split(/,\s*/);
for (var i = 0; i < array.length; i++) {
value = array[i];
array[i] = parseFloat(value);
if ( value.match(/\ds/) ) {
array[i] = array[i] * 1000;
}
}
return array;
},
// Autodetect vendor prefix and return `transitionend` event name.
//
// If browser didnt support CSS Transitions it will return `false`.
getEvent: function () {
var finded = false;
for ( var prop in this._names ) {
if ( typeof(document.body.style[prop]) != 'undefined' ) {
finded = this._names[prop];
break;
}
}
this.getEvent = function () {
return finded;
};
return finded;
},
// Alias to vendor prefixed `requestAnimationFrame`. Will be replace
// by native function after first call.
animFrame: function (callback) {
var raf = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame;
if ( raf ) {
this.animFrame = function (callback) {
return raf.call(window, callback);
};
} else {
this.animFrame = function (callback) {
return setTimeout(callback, 10);
};
}
return this.animFrame(callback);
},
// Return `true` if browser support CSS Transitions.
isSupported: function () {
return this.getEvent() !== false;
}
}
// jQuery node methods.
$.extend($.fn, {
// Call `callback` after CSS Transition finish
// `delay + (durationPart * duration)`. It will call `callback` only
// once, in difference from `transitionEnd`.
//
// $('.show-video').click(function () {
// $('.slider').addClass('video-position').afterTransition(
// function () { autoPlayVideo(); });
// });
//
// You can set `durationPart` to call `callback` in the middle of
// transition:
//
// $('.fliper').addClass('rotate').afterTransition(0.5, function () {
// $(this).find('.backface').show();
// });
//
// Callback will get object with `propertyName` and `elapsedTime`
// properties. If transition is set to difference properties, it will
// be called on every property.
//
// This method doesnt check, that transition is really finished (it can
// be canceled in the middle).
afterTransition: function (durationPart, callback) {
if ( typeof(callback) == 'undefined' ) {
callback = durationPart;
durationPart = 1;
}
if ( !$.Transitions.isSupported() ) {
for (var i = 0; i < this.length; i++) {
callback.call(this[i], {
type: 'aftertransition',
elapsedTime: 0,
propertyName: '',
currentTarget: this[i]
});
}
return this;
}
for (var i = 0; i < this.length; i++) {
var el = $(this[i]);
var props = el.css('transition-property').split(/,\s*/);
var durations = el.css('transition-duration');
var delays = el.css('transition-delay');
durations = $.Transitions._parseTimes(durations);
delays = $.Transitions._parseTimes(delays);
var prop, duration, delay, after, elapsed;
for (var j = 0; j < props.length; j++) {
prop = props[j];
duration = durations[ durations.length == 1 ? 0 : j ];
delay = delays[ delays.length == 1 ? 0 : j ];
after = delay + (duration * durationPart);
elapsed = duration * durationPart / 1000;
(function (el, prop, after, elapsed) {
setTimeout(function () {
$.Transitions.animFrame(function () {
callback.call(el[0], {
type: 'aftertransition',
elapsedTime: elapsed,
propertyName: prop,
currentTarget: el[0]
});
});
}, after);
})(el, prop, after, elapsed);
}
}
return this;
},
// Set `callback` to listen every CSS Transition finish.
// It will call `callback` on every finished transition,
// in difference from `afterTransition`.
//
// It just bind to `transitionend` event, but detect vendor prefix.
//
// Callback will get event object with `propertyName` and `elapsedTime`
// properties. If transition is set to difference properties, it will
// be called on every property.
//
// Note, that `callback` will get original event object, not from
// jQuery.
//
// var slider = $('.slider').transitionEnd(function () {
// if ( slider.hasClass('video-position') ) {
// autoPlayVideo();
// }
// });
//
// $('.show-video').click(function () {
// slider.addClass('video-position');
// });
//
// If transition will be canceled before finish, event wont be fired.
transitionEnd: function (callback) {
for (var i = 0; i < this.length; i++) {
this[i].addEventListener($.Transitions.getEvent(), function (e) {
callback.call(this, e);
});
}
return this;
}
});
}).call(this, jQuery);

View File

@ -0,0 +1,17 @@
<div class="social-likes{{? $.type === 'vertical' }} social-likes_vertical{{?}}{{? $.type === 'single' }} social-likes_single{{?}}{{? $.light }} social-likes_light{{?}}"{{? !$.counters }} data-counters="no"{{?}}{{? $.url }} data-url="{{=$.url}}"{{?}}{{? $.title }} data-title="{{=$.title}}"{{?}}{{? $.type === 'single' }} data-single-title="{{=$.singleTitle}}"{{?}}>
{{? $.site_facebook }}<div class="facebook" title="{{=$.titleFacebook}}">Facebook</div>{{?}}
{{? $.site_twitter }}<div class="twitter" {{? $.twitter_via }} data-via="{{=$.twitter_via}}"{{?}} {{? $.twitter_related }} data-related="{{=$.twitter_related}}"{{?}} title="{{=$.titleTwitter}}">Twitter</div>{{?}}
{{? $.site_mailru }}<div class="mailru" title="Поделиться ссылкой в Моём мире">Мой мир</div>{{?}}
{{? $.site_vkontakte }}<div class="vkontakte" title="Поделиться ссылкой во Вконтакте">Вконтакте</div>{{?}}
{{? $.site_odnoklassniki }}<div class="odnoklassniki" title="Поделиться ссылкой в Одноклассниках">Одноклассники</div>{{?}}
{{? $.site_plusone }}<div class="plusone" title="{{=$.titlePlusone}}">Google+</div>{{?}}
{{? $.site_pinterest }}<div class="pinterest" title="{{=$.titlePinterest}}" data-media="{{=$.pinterest_media}}">Pinterest</div>{{?}}
</div>

View File

@ -0,0 +1,21 @@
$.tagsClasses = function(prefix, tags) {
var classes = [prefix];
for (var tagIdx = 0; tagIdx < tags.length; tagIdx++) {
classes.push(prefix + '_' + tags[tagIdx]);
}
return classes.join(' ');
};
$.getPage = function(page) {
return $.map[$.lang + '/' + page];
};
$.getBodyClasses = function() {
if (!$.bodyClasses) return '';
return $.bodyClasses.join(' ');
};
$.getTranslationUrl = function(lang) {
var translation = $.map[$.path.replace($.lang, lang)];
return translation ? translation.url : $.map[lang + '/index'].url;
};

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="{{=$.lang}}">
<head>
<meta charset="utf-8">
<title>Social Likes</title>
<meta name="generator" content="Social Likes: http://sapegin.github.com/social-likes/">
<link rel="stylesheet" href="social-likes_{{=$.skin}}.css">
</head>
<body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/{{=$.jquery_ver}}/jquery.min.js"><\/script>
<script src="social-likes.min.js"><\/script>
{{=$.html}}
<p><small>{{=$.footer}}</small></p>
</body>
</html>

View File

@ -0,0 +1,5 @@
<link rel="stylesheet" href="social-likes_{{=$.skin}}.css">
...
<script src="jquery.min.js"><\/script>
<script src="social-likes.min.js"><\/script>
...

View File

@ -0,0 +1,249 @@
<f:template xmlns:f="http://fest.mail.ru" context_name="$">
<f:doctype>html</f:doctype>
<f:script src="./functions.js"/>
<html lang="{$.lang}">
<head>
<meta charset="utf-8"/>
<title>
<f:value>$.pageTitle</f:value>
</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="width=1024px"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="description" content="{$.descriptionHead||$.description}"/>
<script src="{$.files.modernizr}"></script>
<link rel="stylesheet" href="{$.files.css}"/>
<link id="styles_classic" rel="stylesheet" href="{$.files.slcss_classic}"/>
<link id="styles_flat" rel="stylesheet" href="{$.files.slcss_flat}" disabled="disabled"/>
<link id="styles_birman" rel="stylesheet" href="{$.files.slcss_birman}" disabled="disabled"/>
<link rel="image_src" href="http://sapegin.github.com/social-likes/img/social-likes.png"/>
<meta property="og:image" content="http://sapegin.github.com/social-likes/img/social-likes.png"/>
</head>
<body>
<div class="forkme">
<a href="https://github.com/sapegin/social-likes" class="forkme-i">Fork me on GitHub</a>
</div>
<div class="wrapper">
<div class="language-switcher">
<a href="{$.translationLink}">
<f:value>$.translationTitle</f:value>
</a>
</div>
<h1>
<f:value>$.name</f:value>
</h1>
<div class="description">
<p>
<f:value output="text">$.description</f:value>
</p>
</div>
<div class="preview preview_horizontal js-preview"></div>
<form class="builder form form_full" data-component="builder">
<input type="hidden" name="lang" value="{$.lang}"/>
<input type="hidden" name="titleFacebook" value="{$.titleFacebook}"/>
<input type="hidden" name="titleTwitter" value="{$.titleTwitter}"/>
<input type="hidden" name="titlePlusone" value="{$.titlePlusone}"/>
<input type="hidden" name="titleLivejournal" value="{$.titleLivejournal}"/>
<input type="hidden" name="titlePinterest" value="{$.titlePinterest}"/>
<input type="hidden" name="singleTitle" value="{$.singleTitle}"/>
<!-- Skin -->
<div class="builder__row">
<div class="builder__label">
<f:value>$.builderSkin</f:value>
</div>
<div class="builder__widget">
<div class="switcher">
<input class="switcher__input" id="skin_classic" type="radio" name="skin" value="classic" checked="checked"/>
<label class="switcher__label" for="skin_classic"><f:value>$.builderSkinClassic</f:value></label>
<input class="switcher__input" id="skin_flat" type="radio" name="skin" value="flat"/>
<label class="switcher__label" for="skin_flat"><f:value>$.builderSkinFlat</f:value></label>
<input class="switcher__input" id="skin_birman" type="radio" name="skin" value="birman"/>
<label class="switcher__label" for="skin_birman"><f:value>$.builderSkinBirman</f:value></label>
</div>
</div>
</div>
<!-- Type (look) -->
<div class="builder__row">
<div class="builder__label">
<f:value>$.builderType</f:value>
</div>
<div class="builder__widget">
<div class="switcher">
<input class="switcher__input" id="type_horizontal" type="radio" name="type" value="horizontal" checked="checked"/>
<label class="switcher__label" for="type_horizontal"><f:value>$.builderTypeHorizontal</f:value></label>
<input class="switcher__input" id="type_vertical" type="radio" name="type" value="vertical"/>
<label class="switcher__label" for="type_vertical"><f:value>$.builderTypeVertical</f:value></label>
<input class="switcher__input" id="type_single" type="radio" name="type" value="single"/>
<label class="switcher__label" for="type_single"><f:value>$.builderTypeSingle</f:value></label>
</div>
</div>
</div>
<div class="builder__row">
<div class="builder__widget">
<div class="builder__checkbox checkbox">
<input class="checkbox__input" id="counters" type="checkbox" name="counters" value="1" checked="checked"/>
<label class="checkbox__label" for="counters">
<span class="checkbox__button"></span>
<f:space/>
<span class="checkbox__text"><f:value>$.builderCounters</f:value></span>
</label>
</div>
<div class="builder__checkbox checkbox js-light is-hidden">
<input class="checkbox__input" id="light" type="checkbox" name="light" value="1"/>
<label class="checkbox__label" for="light">
<span class="checkbox__button"></span>
<f:space/>
<span class="checkbox__text"><f:value>$.builderLight</f:value></span>
</label>
</div>
</div>
</div>
<div class="builder__row">
<div class="builder__label">
<f:value>$.builderSites</f:value>
</div>
<div class="builder__widget builder__sites group">
<f:for iterate="$.common.sites" index="i" value="site">
<f:if test="!site.langs || site.langs.indexOf($.lang) !== -1">
<div class="builder__checkbox checkbox">
<input class="checkbox__input" id="site_{site.id}" type="checkbox" name="site_{site.id}" value="1">
<f:attributes>
<f:if test="site.checked">
<f:attribute name="checked" value="checked"/>
</f:if>
</f:attributes>
</input>
<label class="checkbox__label" for="site_{site.id}">
<span class="checkbox__button"></span>
<f:space/>
<span class="checkbox__text">
<f:choose>
<f:when test="typeof site.name === 'string'">
<f:value>site.name</f:value>
</f:when>
<f:otherwise>
<f:value>site.name[$.lang]</f:value>
</f:otherwise>
</f:choose>
</span>
</label>
</div>
</f:if>
</f:for>
</div>
</div>
<div class="builder__row">
<label for="url" class="builder__label">
<f:value>$.builderUrl</f:value>
</label>
<div class="builder__widget">
<input type="text" name="url" value="" placeholder="{$.builderUrlHelp}" class="field"/>
</div>
</div>
<div class="builder__row">
<label for="title" class="builder__label">
<f:value>$.builderTitle</f:value>
</label>
<div class="builder__widget">
<input type="text" name="title" value="" placeholder="{$.builderTitleHelp}" class="field"/>
</div>
</div>
<div class="builder__row js-twitter-extra is-hidden">
<div class="l-row">
<div class="l-half">
<label for="twitter_via" class="builder__label">
<f:value>$.builderTwitterVia</f:value>
</label>
<div class="builder__widget">
<input type="text" name="twitter_via" value="" placeholder="{$.builderTwitterViaHelp}" class="field"/>
</div>
</div>
<div class="l-half">
<label for="twitter_related" class="builder__label">
<f:value>$.builderTwitterRelated</f:value>
</label>
<div class="builder__widget">
<input type="text" name="twitter_related" value="" placeholder="{$.builderTwitterRelatedHelp}" class="field"/>
</div>
</div>
</div>
</div>
<div class="builder__row js-pinterest-extra is-hidden">
<label for="pinterest_media" class="builder__label">
<f:value>$.builderPinterestMedia</f:value>
</label>
<div class="builder__widget">
<input type="text" name="pinterest_media" value="" placeholder="{$.builderPinterestMediaHelp}" class="field"/>
</div>
</div>
</form>
<div class="code">
<pre class="code-i"><code class="language-markup js-code"></code></pre>
</div>
<div class="download-row">
<div class="download-row__links">
<div class="download-row__button">
<a href="https://github.com/sapegin/social-likes/zipball/master" class="big-button js-download" download="social-likes.zip"><f:value>$.downloadArchive</f:value></a>
</div>
<f:space/>
<nobr>
<f:value>$.or</f:value>
<f:space/>
<a href="https://github.com/sapegin/social-likes"><f:value>$.browseCode</f:value></a>
<f:space/>
<f:value>$.onGitHub</f:value>
</nobr>
</div>
<div class="download-row__descr"><f:value output="text">$.archiveContains</f:value></div>
</div>
<form id="download-proxy" action="http://api.sapegin.me/social-likes-proxy/proxy.php" method="post">
<input type="hidden" name="content" value=""/>
</form>
<div class="docs">
<f:value output="text">$.docs</f:value>
</div>
</div>
<div class="footer">
<f:value output="text">$.footer</f:value>
</div>
<script type="text/plain" id="build_tmpl"><f:insert src="build.tmpl.html"/></script>
<script type="text/plain" id="prepend_tmpl"><f:insert src="prepend.tmpl.html"/></script>
<script type="text/plain" id="index_tmpl"><f:insert src="index.tmpl.html"/></script>
<script type="text/plain" id="index_footer_tmpl"><f:value output="text">$.archiveFooter</f:value></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="{$.files.js}"></script>
<f:choose>
<f:when test="$.debug">
<script src="src/social-likes.js"></script>
</f:when>
<f:otherwise>
<script src="{$.files.sljs}"></script>
</f:otherwise>
</f:choose>
<!-- Yandex.Metrika counter --><script>(function (d, w, c) { (w[c] = w[c] || []).push(function() { try { w.yaCounter6395488 = new Ya.Metrika({id:6395488, clickmap:true, trackLinks:true, webvisor:true}); } catch(e) { } }); var n = d.getElementsByTagName("script")[0], s = d.createElement("script"), f = function () { n.parentNode.insertBefore(s, n); }; s.type = "text/javascript"; s.async = true; s.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//mc.yandex.ru/metrika/watch.js"; if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f); } else { f(); } })(document, window, "yandex_metrika_callbacks");</script><noscript><div><img src="//mc.yandex.ru/watch/6395488" style="position:absolute; left:-9999px;" alt="" /></div></noscript><!-- /Yandex.Metrika counter -->
</body>
</html>
</f:template>

9442
gh-pages/vendor/modernizr.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -28,9 +28,13 @@
"jquery": ">=1.8"
},
"devDependencies": {
"autoprefixer-stylus": "0.3.0",
"autoprefixer-stylus": "~0.3.0",
"csso-stylus": "0.0.3",
"gh-pages": "~0.8.0",
"grunt": "~0.4.5",
"grunt-cli": "~0.1.13",
"grunt-contrib-concat": "~0.5.1",
"grunt-contrib-connect": "~0.11.2",
"grunt-contrib-imagemin": "~0.8.1",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-stylus": "~0.20.0",
@ -38,13 +42,19 @@
"grunt-contrib-watch": "~0.6.1",
"grunt-csso": "~0.6.3",
"grunt-jscs-checker": "~0.7.1",
"grunt-modernizr": "~1.0.1",
"grunt-replace": "~0.11.0",
"grunt-sweet": "~0.2.2",
"grunt-webfont": "~0.4.8",
"load-grunt-tasks": "~0.6.0"
},
"scripts": {
"build": "grunt",
"test": "grunt",
"replace-version": "grunt replace:version",
"build-gh-pages": "scripts/update-gh-pages.sh"
"publish": "npm run update-gh-pages && npm run build-gh-pages && npm run publish-gh-pages",
"update-gh-pages": "mkdir -p gh-pages/public/src && cp dist/* gh-pages/public/src/ && cp src/social-likes.js gh-pages/public/src/",
"build-gh-pages": "cd gh-pages && grunt && cd ..",
"publish-gh-pages": "gh-pages -d gh-pages/public",
"make-debug-symlinks": "ln -s . gh-pages/public/social-likes"
}
}

Some files were not shown because too many files have changed in this diff Show More