fontcustom 0.1.4 → 1.0.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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