fontcustom 0.1.4 → 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/CHANGELOG.md +14 -0
  2. data/CONTRIBUTING.md +15 -8
  3. data/Rakefile +4 -6
  4. data/bin/fontcustom +1 -1
  5. data/fontcustom.gemspec +2 -7
  6. data/lib/fontcustom.rb +6 -21
  7. data/lib/fontcustom/cli.rb +46 -18
  8. data/lib/fontcustom/error.rb +4 -0
  9. data/lib/fontcustom/generator/font.rb +101 -0
  10. data/lib/fontcustom/generator/template.rb +80 -0
  11. data/lib/fontcustom/options.rb +20 -0
  12. data/lib/fontcustom/scripts/generate.py +22 -6
  13. data/lib/fontcustom/templates/_fontcustom.scss +72 -0
  14. data/lib/fontcustom/templates/fontcustom-ie7.css +10 -10
  15. data/lib/fontcustom/templates/fontcustom.css +19 -19
  16. data/lib/fontcustom/templates/fontcustom.html +119 -0
  17. data/lib/fontcustom/templates/fontcustom.yml +23 -0
  18. data/lib/fontcustom/util.rb +89 -0
  19. data/lib/fontcustom/version.rb +1 -1
  20. data/lib/fontcustom/watcher.rb +50 -25
  21. data/spec/fixtures/empty-data/.fontcustom-data +0 -0
  22. data/spec/fixtures/fontcustom.yml +1 -0
  23. data/spec/fixtures/mixed-output/.fontcustom-data +17 -0
  24. data/spec/fixtures/mixed-output/another-font.ttf +0 -0
  25. data/spec/fixtures/mixed-output/dont-delete-me.bro +0 -0
  26. data/spec/fixtures/mixed-output/fontcustom-cc5ce52f2ae4f9ce2e7ee8131bbfee1e.eot +0 -0
  27. data/spec/fixtures/mixed-output/fontcustom-cc5ce52f2ae4f9ce2e7ee8131bbfee1e.svg +102 -0
  28. data/spec/fixtures/mixed-output/fontcustom-cc5ce52f2ae4f9ce2e7ee8131bbfee1e.ttf +0 -0
  29. data/spec/fixtures/mixed-output/fontcustom-cc5ce52f2ae4f9ce2e7ee8131bbfee1e.woff +0 -0
  30. data/spec/fixtures/mixed-output/fontcustom.css +108 -0
  31. data/spec/fixtures/not-a-dir +0 -0
  32. data/spec/fontcustom/generator/font_spec.rb +183 -0
  33. data/spec/fontcustom/generator/template_spec.rb +106 -0
  34. data/spec/fontcustom/util_spec.rb +109 -0
  35. data/spec/fontcustom/watcher_spec.rb +68 -0
  36. data/spec/spec_helper.rb +32 -22
  37. metadata +47 -100
  38. data/lib/fontcustom/generator.rb +0 -105
  39. data/lib/fontcustom/templates/test.html +0 -100
  40. data/spec/fontcustom/fontcustom_spec.rb +0 -42
  41. data/spec/fontcustom/generator_spec.rb +0 -75
  42. data/spec/fontcustom/watcher_spec.rb.off +0 -34
@@ -0,0 +1,72 @@
1
+ /*
2
+ Font Custom
3
+ */
4
+
5
+ @font-face {
6
+ font-family: "<%= @opts[:font_name] %>";
7
+ src: url("<%= @data[:file_name] %>.eot?#iefix") format("embedded-opentype"),
8
+ url("<%= @data[:file_name] %>.woff") format("woff"),
9
+ url("<%= @data[:file_name] %>.ttf") format("truetype"),
10
+ url("<%= @data[:file_name] %>.svg#<%= @opts[:font_name] %>") format("svg");
11
+ font-weight: normal;
12
+ font-style: normal;
13
+ }
14
+
15
+ /*
16
+ Bootstrap Overrides
17
+ */
18
+
19
+ [class^="<%= @opts[:css_prefix] %>"]:before, [class*=" <%= @opts[:css_prefix] %>"]:before {
20
+ font-family: "<%= @opts[:font_name] %>";
21
+ font-weight: normal;
22
+ font-style: normal;
23
+ display: inline-block;
24
+ text-decoration: inherit;
25
+ }
26
+
27
+ a [class^="<%= @opts[:css_prefix] %>"], a [class*=" <%= @opts[:css_prefix] %>"] {
28
+ display: inline-block;
29
+ text-decoration: inherit;
30
+ }
31
+
32
+ /* makes the font 33% larger relative to the icon container */
33
+ .<%= @opts[:css_prefix] %>large:before {
34
+ vertical-align: top;
35
+ font-size: 1.333em;
36
+ }
37
+
38
+ /* keeps button heights with and without icons the same */
39
+ .btn [class^="<%= @opts[:css_prefix] %>"], .btn [class*=" <%= @opts[:css_prefix] %>"] {
40
+ line-height: 0.9em;
41
+ }
42
+
43
+ li [class^="<%= @opts[:css_prefix] %>"], li [class*=" <%= @opts[:css_prefix] %>"] {
44
+ display: inline-block;
45
+ width: 1.25em;
46
+ text-align: center;
47
+ }
48
+
49
+ /* 1.5 increased font size for <%= @opts[:css_prefix] %>large * 1.25 width */
50
+ li .<%= @opts[:css_prefix] %>large[class^="<%= @opts[:css_prefix] %>"], li .<%= @opts[:css_prefix] %>large[class*=" <%= @opts[:css_prefix] %>"] {
51
+ width: 1.875em;
52
+ }
53
+
54
+ li[class^="<%= @opts[:css_prefix] %>"], li[class*=" <%= @opts[:css_prefix] %>"] {
55
+ margin-left: 0;
56
+ list-style-type: none;
57
+ }
58
+
59
+ li[class^="<%= @opts[:css_prefix] %>"]:before, li[class*=" <%= @opts[:css_prefix] %>"]:before {
60
+ text-indent: -2em;
61
+ text-align: center;
62
+ }
63
+
64
+ li[class^="<%= @opts[:css_prefix] %>"].<%= @opts[:css_prefix] %>large:before, li[class*=" <%= @opts[:css_prefix] %>"].<%= @opts[:css_prefix] %>large:before {
65
+ text-indent: -1.333em;
66
+ }
67
+
68
+ /*
69
+ Icon Classes
70
+ */
71
+ <% @data[:glyphs].each_with_index do |name, index| %>
72
+ .<%= @opts[:css_prefix] + name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
@@ -1,18 +1,18 @@
1
- [class^="icon-"],
2
- [class*=" icon-"] {
3
- font-family: "<%= @name %>";
1
+ [class^="<%= @opts[:css_prefix] %>"],
2
+ [class*=" <%= @opts[:css_prefix] %>"] {
3
+ font-family: "<%= @opts[:font_name] %>";
4
4
  font-style: normal;
5
5
  font-weight: normal;
6
6
  }
7
- .btn.dropdown-toggle [class^="icon-"],
8
- .btn.dropdown-toggle [class*=" icon-"] {
9
- /* keeps button heights with and without icons the same */
10
7
 
8
+ .btn.dropdown-toggle [class^="<%= @opts[:css_prefix] %>"],
9
+ .btn.dropdown-toggle [class*=" <%= @opts[:css_prefix] %>"] {
10
+ /* keeps button heights with and without icons the same */
11
11
  line-height: 1.4em;
12
12
  }
13
- .icon-large {
13
+
14
+ .<%= @opts[:css_prefix] %>large {
14
15
  font-size: 1.3333em;
15
16
  }
16
-
17
- <% @classes.each_with_index do |name, index| %>
18
- .icon-<%= name %> { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x<%= (61696+index).to_s(16) %>;&nbsp;');} <% end %>
17
+ <% @data[:glyphs].each_with_index do |name, index| %>
18
+ .<%= @opts[:css_prefix] + name %> { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x<%= (61696+index).to_s(16) %>;&nbsp;'); }<% end %>
@@ -1,13 +1,13 @@
1
1
  /*
2
- Font Custom - icon webfonts made simple
2
+ Font Custom
3
3
  */
4
4
 
5
5
  @font-face {
6
- font-family: "<%= @name %>";
7
- src: url("<%= @path %>.eot?#iefix") format("embedded-opentype"),
8
- url("<%= @path %>.woff") format("woff"),
9
- url("<%= @path %>.ttf") format("truetype"),
10
- url("<%= @path %>.svg#<%= @name %>") format("svg");
6
+ font-family: "<%= @opts[:font_name] %>";
7
+ src: url("<%= @data[:file_name] %>.eot?#iefix") format("embedded-opentype"),
8
+ url("<%= @data[:file_name] %>.woff") format("woff"),
9
+ url("<%= @data[:file_name] %>.ttf") format("truetype"),
10
+ url("<%= @data[:file_name] %>.svg#<%= @opts[:font_name] %>") format("svg");
11
11
  font-weight: normal;
12
12
  font-style: normal;
13
13
  }
@@ -16,57 +16,57 @@
16
16
  Bootstrap Overrides
17
17
  */
18
18
 
19
- [class^="icon-"]:before, [class*=" icon-"]:before {
20
- font-family: "<%= @name %>";
19
+ [class^="<%= @opts[:css_prefix] %>"]:before, [class*=" <%= @opts[:css_prefix] %>"]:before {
20
+ font-family: "<%= @opts[:font_name] %>";
21
21
  font-weight: normal;
22
22
  font-style: normal;
23
23
  display: inline-block;
24
24
  text-decoration: inherit;
25
25
  }
26
26
 
27
- a [class^="icon-"], a [class*=" icon-"] {
27
+ a [class^="<%= @opts[:css_prefix] %>"], a [class*=" <%= @opts[:css_prefix] %>"] {
28
28
  display: inline-block;
29
29
  text-decoration: inherit;
30
30
  }
31
31
 
32
32
  /* makes the font 33% larger relative to the icon container */
33
- .icon-large:before {
33
+ .<%= @opts[:css_prefix] %>large:before {
34
34
  vertical-align: top;
35
35
  font-size: 1.333em;
36
36
  }
37
37
 
38
38
  /* keeps button heights with and without icons the same */
39
- .btn [class^="icon-"], .btn [class*=" icon-"] {
39
+ .btn [class^="<%= @opts[:css_prefix] %>"], .btn [class*=" <%= @opts[:css_prefix] %>"] {
40
40
  line-height: 0.9em;
41
41
  }
42
42
 
43
- li [class^="icon-"], li [class*=" icon-"] {
43
+ li [class^="<%= @opts[:css_prefix] %>"], li [class*=" <%= @opts[:css_prefix] %>"] {
44
44
  display: inline-block;
45
45
  width: 1.25em;
46
46
  text-align: center;
47
47
  }
48
48
 
49
- /* 1.5 increased font size for icon-large * 1.25 width */
50
- li .icon-large[class^="icon-"], li .icon-large[class*=" icon-"] {
49
+ /* 1.5 increased font size for <%= @opts[:css_prefix] %>large * 1.25 width */
50
+ li .<%= @opts[:css_prefix] %>large[class^="<%= @opts[:css_prefix] %>"], li .<%= @opts[:css_prefix] %>large[class*=" <%= @opts[:css_prefix] %>"] {
51
51
  width: 1.875em;
52
52
  }
53
53
 
54
- li[class^="icon-"], li[class*=" icon-"] {
54
+ li[class^="<%= @opts[:css_prefix] %>"], li[class*=" <%= @opts[:css_prefix] %>"] {
55
55
  margin-left: 0;
56
56
  list-style-type: none;
57
57
  }
58
58
 
59
- li[class^="icon-"]:before, li[class*=" icon-"]:before {
59
+ li[class^="<%= @opts[:css_prefix] %>"]:before, li[class*=" <%= @opts[:css_prefix] %>"]:before {
60
60
  text-indent: -2em;
61
61
  text-align: center;
62
62
  }
63
63
 
64
- li[class^="icon-"].icon-large:before, li[class*=" icon-"].icon-large:before {
64
+ li[class^="<%= @opts[:css_prefix] %>"].<%= @opts[:css_prefix] %>large:before, li[class*=" <%= @opts[:css_prefix] %>"].<%= @opts[:css_prefix] %>large:before {
65
65
  text-indent: -1.333em;
66
66
  }
67
67
 
68
68
  /*
69
69
  Icon Classes
70
70
  */
71
- <% @classes.each_with_index do |name, index| %>
72
- .icon-<%= name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
71
+ <% @data[:glyphs].each_with_index do |name, index| %>
72
+ .<%= @opts[:css_prefix] + name %>:before { content: "\<%= (61696+index).to_s(16) %>"; }<% end %>
@@ -0,0 +1,119 @@
1
+ <% scale = %w|12 14 16 18 21 24 36 48 60 72| %>
2
+ <!DOCTYPE html>
3
+ <html>
4
+ <head>
5
+ <title><%= @opts[:font_name] %> glyphs preview</title>
6
+ <link rel="stylesheet" href="fontcustom.css" />
7
+ <!--[if lte IE 7]><link rel="stylesheet" href="fontcustom-ie7.css" /><![endif]-->
8
+
9
+ <style>
10
+ * {
11
+ -moz-box-sizing: border-box;
12
+ -webkit-box-sizing: border-box;
13
+ box-sizing: border-box;
14
+ margin: 0;
15
+ padding: 0;
16
+ }
17
+
18
+ body {
19
+ background: #fff;
20
+ color: #444;
21
+ font: 16px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
22
+ }
23
+
24
+ a,
25
+ a:visited {
26
+ color: #888;
27
+ text-decoration: underline;
28
+ }
29
+ a:hover,
30
+ a:focus { color: #000; }
31
+
32
+ h1 {
33
+ border-bottom: 2px solid #ddd;
34
+ color: #888;
35
+ font-size: 36px;
36
+ font-weight: 300;
37
+ margin-bottom: 20px;
38
+ padding: 20px 0;
39
+ }
40
+
41
+ .container {
42
+ margin: 0 auto;
43
+ min-width: 880px;
44
+ padding: 0 40px;
45
+ width: 80%;
46
+ }
47
+
48
+ .glyph {
49
+ border-bottom: 1px dotted #ccc;
50
+ padding: 10px 0 20px;
51
+ margin-bottom: 20px;
52
+ }
53
+
54
+ .preview-glyphs { vertical-align: bottom; }
55
+
56
+ .preview-scale {
57
+ color: #888;
58
+ font-size: 12px;
59
+ margin-top: 5px;
60
+ }
61
+
62
+ .step {
63
+ display: inline-block;
64
+ line-height: 1;
65
+ width: 10%;
66
+ }
67
+
68
+ <% scale.each do |n| %>
69
+ .size-<%= n %> { font-size: <%= n %>px; }
70
+ <% end %>
71
+
72
+ .usage { margin-top: 10px; }
73
+
74
+ .usage input {
75
+ font-family: monospace;
76
+ margin-right: 3px;
77
+ padding: 2px 5px;
78
+ text-align: center;
79
+ }
80
+
81
+ .usage .point { width: 150px; }
82
+
83
+ .usage .class { width: 250px; }
84
+
85
+ .footer {
86
+ color: #888;
87
+ font-size: 12px;
88
+ padding: 20px 0;
89
+ }
90
+ </style>
91
+
92
+ <!--[if lte IE 8]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
93
+ </head>
94
+
95
+ <body>
96
+ <div class="container">
97
+ <h1><%= @opts[:font_name] %> contains <%= @data[:glyphs].length %> glyphs:</h1>
98
+
99
+ <% @data[:glyphs].each_with_index do |name, index| %>
100
+ <div class="glyph">
101
+ <div class="preview-glyphs">
102
+ <% scale.each do |n| %><i class="step <%= @opts[:css_prefix] + name %> size-<%= n %>"></i><% end %>
103
+ </div>
104
+ <div class="preview-scale">
105
+ <% scale.each do |n| %><span class="step"><%= n %></span><% end %>
106
+ </div>
107
+ <div class="usage">
108
+ <input class="class" type="text" readonly="readonly" onClick="this.select();" value=".<%= @opts[:css_prefix] + name %>" />
109
+ <input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#x<%= (61696+index).to_s(16) %>;" />
110
+ </div>
111
+ </div>
112
+ <% end %>
113
+
114
+ <div class="footer">
115
+ Made with love using <a href="http://fontcustom.com">Font Custom</a>.
116
+ </div>
117
+ </div>
118
+ </body>
119
+ </html>
@@ -0,0 +1,23 @@
1
+ ##
2
+ # FONTCUSTOM CONFIG
3
+ #
4
+ # Include this file along with your vectors or pass it to any command with:
5
+ # --config=path/to/config.yml
6
+ # -c path/to/containing/dir/
7
+ #
8
+ # Run `fontcustom help` to learn about various options
9
+ ##
10
+
11
+ #output: /path/to/output
12
+
13
+ #templates: [ scss, preview, relative/path/from/INPUT, relative/path/from/PWD ]
14
+
15
+ #font_name: my-font
16
+
17
+ #file_hash: false
18
+
19
+ #css_prefix: glyph-
20
+
21
+ #debug: true
22
+
23
+ #verbose: false
@@ -0,0 +1,89 @@
1
+ require "yaml"
2
+
3
+ module Fontcustom
4
+ class Util
5
+ class << self
6
+ def check_fontforge
7
+ if `which fontforge` == ""
8
+ raise Fontcustom::Error, "Please install fontforge first. Visit http://fontcustom.com for more details."
9
+ end
10
+ end
11
+
12
+ # Converts all options into symbol-accessible hashes
13
+ # Priority: Passed args > config file > default
14
+ def collect_options(args = {})
15
+ options = Fontcustom::DEFAULT_OPTIONS.clone
16
+ args = args.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
17
+
18
+ options[:input] = args[:input] if args[:input]
19
+ options[:config] = args[:config] if args[:config]
20
+ args.delete :config # don't overwrite the return value of #get_config_path
21
+ options[:config] = get_config_path options
22
+
23
+ if options[:config]
24
+ config = YAML.load File.open(options[:config])
25
+ if config.is_a? Hash
26
+ config = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
27
+ options.merge! config
28
+ end
29
+ end
30
+
31
+ options.merge! args
32
+ options[:output] ||= File.join(options[:input], "fontcustom")
33
+ options[:templates] = get_template_paths options
34
+ options[:font_name] = options[:font_name].strip.downcase.gsub(/\W/, '-')
35
+ options
36
+ end
37
+
38
+ # passed path > input
39
+ def get_config_path(options)
40
+ if options[:config] && File.directory?(options[:config]) && File.exists?(File.join(options[:config], "fontcustom.yml"))
41
+ File.join options[:config], "fontcustom.yml"
42
+ elsif options[:config] && File.exists?(options[:config])
43
+ options[:config]
44
+ elsif File.exists? File.join(options[:input], "fontcustom.yml")
45
+ File.join options[:input], "fontcustom.yml"
46
+ else
47
+ false
48
+ end
49
+ end
50
+
51
+ # Translates shorthand to full path of packages templates, otherwise,
52
+ # it checks input and pwd for the template.
53
+ #
54
+ # Could arguably belong in Generator::Template, however, it's nice to
55
+ # be able to catch template errors before any generator runs.
56
+ def get_template_paths(options)
57
+ options[:templates] << "css" if options[:templates].include?("preview") && ! options[:templates].include?("css")
58
+ options[:templates].map do |template|
59
+ case template
60
+ when "preview"
61
+ File.join gem_lib_path, "templates", "fontcustom.html"
62
+ when "css"
63
+ File.join gem_lib_path, "templates", "fontcustom.css"
64
+ when "scss"
65
+ File.join gem_lib_path, "templates", "_fontcustom.scss"
66
+ when "css-ie7"
67
+ File.join gem_lib_path, "templates", "fontcustom-ie7.css"
68
+ else
69
+ if File.exists?(template)
70
+ template
71
+ elsif File.exists?(File.join(options[:input], template))
72
+ File.join options[:input], template
73
+ else
74
+ raise Fontcustom::Error, "We couldn't find your custom template #{template}. Double check and try again?"
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def clear_file(file)
81
+ File.open(file, "w") {}
82
+ end
83
+
84
+ def gem_lib_path
85
+ File.expand_path(File.join(File.dirname(__FILE__)))
86
+ end
87
+ end
88
+ end
89
+ end
@@ -1,3 +1,3 @@
1
1
  module Fontcustom
2
- VERSION = "0.1.4"
2
+ VERSION = "1.0.0.pre"
3
3
  end
@@ -1,37 +1,62 @@
1
- require 'listen'
1
+ require "fontcustom"
2
+ require "listen"
2
3
 
3
4
  module Fontcustom
4
5
  class Watcher
5
- def self.watch(*args)
6
- callback = Proc.new do |modified, added, removed|
7
- puts ' >> Changed: ' + modified.join(' ') unless modified.empty?
8
- puts ' >> Added: ' + added.join(' ') unless added.empty?
9
- puts ' >> Removed: ' + removed.join(' ') unless removed.empty?
10
-
11
- changed = modified + added + removed
12
- Fontcustom.compile(*args) unless changed.empty?
13
- end
6
+ def initialize(opts)
7
+ @opts = opts
8
+ @listener = Listen.to(@opts[:input])
9
+ .relative_paths(true)
10
+ .filter(/\.(eps|svg)$/)
11
+ .change(&callback)
12
+ @opts[:blocking] = @opts[:blocking] == false ? false : true
13
+ @listener = @listener.polling_fallback_message(false) unless @opts[:blocking]
14
+ end
14
15
 
15
- dir = args.first
16
- @listener = Listen.to(dir).filter(/\.(eps|svg)$/).change(&callback)
16
+ def watch
17
+ puts "Font Custom is watching your icons at #{@opts[:input]}. Press Ctrl + C to stop."
18
+ compile unless @opts[:skip_first]
19
+ @listener.start @opts[:blocking]
17
20
 
18
- begin
19
- puts 'Fontcustom is watching your icons at ' + dir
20
- puts 'Press Ctrl + C to stop.'
21
- Fontcustom.compile(*args)
22
- @listener.start()
21
+ rescue Fontcustom::Error => e
22
+ show_error e
23
23
 
24
- # Catches Ctrl + C
25
- # Does listen gem have a better way of handling this?
26
- rescue SignalException
27
- stop
28
- end
24
+ # Catches Ctrl + C
25
+ # TODO Does the listen gem have a better way of handling this?
26
+ rescue SignalException
27
+ stop
29
28
  end
30
29
 
31
- def self.stop
32
- # Newline exists so message is not prepended with ^C on SIGTERM
33
- puts "\nFontcustom is signing off. Goodnight and good luck."
30
+ def stop
31
+ # Adding a newline so message is not prepended with ^C on SIGTERM
32
+ puts "\nFont Custom is signing off. Good night and good luck."
34
33
  @listener.stop
35
34
  end
35
+
36
+ private
37
+
38
+ def callback
39
+ Proc.new do |modified, added, removed|
40
+ begin
41
+ puts " >> Changed: " + modified.join(", ") unless modified.empty?
42
+ puts " >> Added: " + added.join(", ") unless added.empty?
43
+ puts " >> Removed: " + removed.join(", ") unless removed.empty?
44
+
45
+ changed = modified + added + removed
46
+ compile unless changed.empty?
47
+ rescue Fontcustom::Error => e
48
+ show_error e
49
+ end
50
+ end
51
+ end
52
+
53
+ def compile
54
+ Fontcustom::Generator::Font.start [@opts]
55
+ Fontcustom::Generator::Template.start [@opts]
56
+ end
57
+
58
+ def show_error(err)
59
+ puts "ERROR: #{err.message}"
60
+ end
36
61
  end
37
62
  end