extjs-theme 0.1.0
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.
- data/LICENSE +20 -0
- data/README +0 -0
- data/README.rdoc +75 -0
- data/Rakefile +63 -0
- data/bin/xtheme +14 -0
- data/lib/extjs-theme.rb +13 -0
- data/lib/extjs-theme/command.rb +81 -0
- data/lib/extjs-theme/commands/base.rb +74 -0
- data/lib/extjs-theme/commands/conifg.rb +56 -0
- data/lib/extjs-theme/commands/effects.rb +17 -0
- data/lib/extjs-theme/commands/help.rb +83 -0
- data/lib/extjs-theme/commands/theme.rb +49 -0
- data/lib/extjs-theme/dependencies.rb +16 -0
- data/lib/extjs-theme/effects.rb +57 -0
- data/lib/extjs-theme/generator.rb +116 -0
- data/lib/extjs-theme/template/defines.sass +7 -0
- data/test/extjs-xtheme_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +104 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Christocracy
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
= extjs-theme
|
2
|
+
|
3
|
+
Generates a Sass version of Ext theme. Includes methods for colorizing images.
|
4
|
+
|
5
|
+
This Gem depends upon RMagick[http://gemcutter.org/gems/rmagick] and haml-edge[http://gemcutter.org/gems/haml-edge]
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
The Gem is hosted at Gemcutter[http://gemcutter.com]. Install the gem with:
|
10
|
+
|
11
|
+
sudo gem install extjs-theme
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
|
15
|
+
In the root of your Rails app, first execute the following in your console:
|
16
|
+
|
17
|
+
$ xtheme init <path/to/ext> <path/to/stylesheets>
|
18
|
+
|
19
|
+
This creates a YAML config file named .xthemeconfig in the application root.
|
20
|
+
|
21
|
+
---
|
22
|
+
theme_dir: public/stylesheets/sass
|
23
|
+
ext_dir: public/javascripts/ext-3.1.0
|
24
|
+
|
25
|
+
Example
|
26
|
+
|
27
|
+
$ xtheme init public/javascripts/ext-3.1.0 public/stylesheets
|
28
|
+
|
29
|
+
To generate a new Sass theme:
|
30
|
+
|
31
|
+
$ xtheme create my-theme
|
32
|
+
|
33
|
+
In Rails, this will have created a new directory <code>public/stylesheets/sass/my-theme</code>
|
34
|
+
|
35
|
+
The generator creates a main include file called <code>my-theme/init.sass</code> (TODO: change to <code>my-theme/all.sass</code>) which contains <code>@include</code> directives for each individual Ext stylesheet. You *no longer need* to include the ext-all.css file from the Ext library -- <code>my-theme/init.sass</code> contains all it needs. In a Rails view, you would include this file in the standard Haml/Sass[http://sass-lang.com/] manner.
|
36
|
+
|
37
|
+
=stylesheet_link_tag "my-theme/init"
|
38
|
+
|
39
|
+
or in an <code>erb</code> template:
|
40
|
+
|
41
|
+
<%= stylesheet_link_tag "my-theme/init"
|
42
|
+
|
43
|
+
The generator also creates a copy of all the Ext theme images in <code>my-theme/images</code>
|
44
|
+
|
45
|
+
Another important sass file created is <code>my-theme/defines.sass</code>. This file contains Sass variable declarations added to each Ext sass file.
|
46
|
+
|
47
|
+
!img_path = ../sass/my-theme/images
|
48
|
+
!font = tahoma,arial,verdana,sans-serif
|
49
|
+
!hue = -90.0
|
50
|
+
|
51
|
+
Form more on Haml and Sass, consult the HAML documentation[http://haml-lang.com/] to learn about including Sass[http://sass-lang.com/] stylesheets.
|
52
|
+
|
53
|
+
== Effects
|
54
|
+
|
55
|
+
The Gem includes commands for theme colorization, including image-processing through RMagick.
|
56
|
+
|
57
|
+
Currently, the only effect available is <code>effects:modulate</code>, for modifying the _hue_, _saturation_ and _lightness_ of a theme according to RMagick[http://www.imagemagick.org/RMagick/doc/image2.html#modulate]:
|
58
|
+
|
59
|
+
$ xtheme effects:modulate <theme-name> <hue> <saturation> <lightness>
|
60
|
+
|
61
|
+
The parameters _hue_, _saturation_ and _lightness_ are defined as {"Float numbers, for example, 0.25 means "25%". All three arguments may be omitted. The default value of each argument is 1.0, that is, 100%"}[http://www.imagemagick.org/RMagick/doc/image2.html#modulate]
|
62
|
+
|
63
|
+
Based upon the default blue Ext theme, the following will generate a pink theme:
|
64
|
+
|
65
|
+
$ xtheme effects:modulate my-theme 0.5 1.0 1.0
|
66
|
+
|
67
|
+
A green theme:
|
68
|
+
|
69
|
+
$ xtheme effects:modulate my-theme 1.5 1.0 1.0
|
70
|
+
|
71
|
+
*Only hue works currently, saturation and lightness are under development*
|
72
|
+
|
73
|
+
== Copyright
|
74
|
+
|
75
|
+
Copyright (c) 2010 Christocracy. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "extjs-theme"
|
8
|
+
gem.summary = %Q{Ext theme-generator and colorizer}
|
9
|
+
gem.description = %Q{Generates Sass-based Ext themes. Includes methods for colorizing themes.}
|
10
|
+
gem.email = "christocracy@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/extjs/extjs-theme"
|
12
|
+
gem.authors = ["Christopher Scott"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda"
|
14
|
+
gem.add_dependency "rmagick"
|
15
|
+
gem.add_dependency "haml-edge", ">=2.3"
|
16
|
+
gem.files = %w(Rakefile) +
|
17
|
+
Dir.glob("{bin,lib,test}/**/*")
|
18
|
+
|
19
|
+
|
20
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
21
|
+
end
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/*_test.rb'
|
39
|
+
test.verbose = true
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
task :rcov do
|
43
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
task :test => :check_dependencies
|
48
|
+
|
49
|
+
task :default => :test
|
50
|
+
|
51
|
+
require 'rake/rdoctask'
|
52
|
+
Rake::RDocTask.new do |rdoc|
|
53
|
+
if File.exist?('VERSION')
|
54
|
+
version = File.read('VERSION')
|
55
|
+
else
|
56
|
+
version = ""
|
57
|
+
end
|
58
|
+
|
59
|
+
rdoc.rdoc_dir = 'rdoc'
|
60
|
+
rdoc.title = "extjs-xtheme #{version}"
|
61
|
+
rdoc.rdoc_files.include('README*')
|
62
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
63
|
+
end
|
data/bin/xtheme
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
6
|
+
|
7
|
+
require 'extjs-theme'
|
8
|
+
require 'extjs-theme/command'
|
9
|
+
|
10
|
+
args = ARGV.dup
|
11
|
+
ARGV.clear
|
12
|
+
command = args.shift.strip rescue 'help'
|
13
|
+
|
14
|
+
ExtJS::Theme::Command.run(command, args)
|
data/lib/extjs-theme.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
##
|
2
|
+
# XTheme
|
3
|
+
# A module for generating and colorizing ExtJS themes.
|
4
|
+
#
|
5
|
+
module ExtJS
|
6
|
+
module Theme
|
7
|
+
end
|
8
|
+
end
|
9
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/extjs-theme')
|
10
|
+
|
11
|
+
['dependencies', 'generator', 'effects'].each do |file|
|
12
|
+
require file
|
13
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'commands/base'
|
2
|
+
|
3
|
+
Dir["#{File.dirname(__FILE__)}/commands/*"].each { |c| require c }
|
4
|
+
|
5
|
+
module ExtJS::Theme
|
6
|
+
module Command
|
7
|
+
class InvalidCommand < RuntimeError; end
|
8
|
+
class CommandFailed < RuntimeError; end
|
9
|
+
class InvalidConfig < RuntimeError; end
|
10
|
+
class ConfigNotFound < RuntimeError; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def run(command, args, retries=0)
|
14
|
+
begin
|
15
|
+
run_internal(command, args.dup)
|
16
|
+
rescue InvalidCommand
|
17
|
+
error "Unknown command. Run 'xtheme help' for usage information."
|
18
|
+
rescue CommandFailed => e
|
19
|
+
error e.message
|
20
|
+
rescue InvalidConfig => e
|
21
|
+
error e.message
|
22
|
+
rescue ConfigNotFound => e
|
23
|
+
error e.message
|
24
|
+
rescue Interrupt => e
|
25
|
+
error "\n[canceled]"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def run_internal(command, args, heroku=nil)
|
30
|
+
config = load_config
|
31
|
+
|
32
|
+
klass, method = parse(command)
|
33
|
+
|
34
|
+
unless method == "init"
|
35
|
+
unless config
|
36
|
+
raise ConfigNotFound.new("Could not locate config file .xthemeconfig.\nAre you in your application root? Have you run xtheme init?")
|
37
|
+
end
|
38
|
+
unless config && File.exists?(config[:ext_dir])
|
39
|
+
raise InvalidConfig.new("Could not locate ext_dir #{config[:ext_dir]}.\nAre you in your application root?")
|
40
|
+
end
|
41
|
+
unless config && File.exists?(config[:theme_dir])
|
42
|
+
raise InvalidConig.new("Could not locate theme_dir #{config[:theme_dir]}.\nAre you in your application root?")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
runner = klass.new(args, config)
|
47
|
+
raise InvalidCommand unless runner.respond_to?(method)
|
48
|
+
runner.send(method)
|
49
|
+
end
|
50
|
+
|
51
|
+
def error(msg)
|
52
|
+
STDERR.puts(msg)
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse(command)
|
57
|
+
parts = command.split(':')
|
58
|
+
case parts.size
|
59
|
+
when 1
|
60
|
+
begin
|
61
|
+
return eval("ExtJS::Theme::Command::#{command.capitalize}"), :index
|
62
|
+
rescue NameError, NoMethodError
|
63
|
+
return ExtJS::Theme::Command::Theme, command
|
64
|
+
end
|
65
|
+
when 2
|
66
|
+
begin
|
67
|
+
return ExtJS::Theme::Command.const_get(parts[0].capitalize), parts[1]
|
68
|
+
rescue NameError
|
69
|
+
raise InvalidCommand
|
70
|
+
end
|
71
|
+
else
|
72
|
+
raise InvalidCommand
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def load_config
|
77
|
+
File.exists?('.xthemeconfig') ? YAML::load(File.open('.xthemeconfig')) : nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module ExtJS::Theme::Command
|
4
|
+
class Base
|
5
|
+
#include Heroku::Helpers
|
6
|
+
|
7
|
+
attr_accessor :args
|
8
|
+
attr_reader :config
|
9
|
+
|
10
|
+
def initialize(args, config)
|
11
|
+
@args = args
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def display(msg, newline=true)
|
16
|
+
if newline
|
17
|
+
puts(msg)
|
18
|
+
else
|
19
|
+
print(msg)
|
20
|
+
STDOUT.flush
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def error(msg)
|
25
|
+
ExtJS::Theme::Command.error(msg)
|
26
|
+
end
|
27
|
+
|
28
|
+
def ask
|
29
|
+
gets.strip
|
30
|
+
end
|
31
|
+
|
32
|
+
def shell(cmd)
|
33
|
+
FileUtils.cd(Dir.pwd) {|d| return `#{cmd}`}
|
34
|
+
end
|
35
|
+
|
36
|
+
def heroku
|
37
|
+
#@heroku ||= Heroku::Command.run_internal('auth:client', args)
|
38
|
+
end
|
39
|
+
|
40
|
+
def extract_app(force=true)
|
41
|
+
app = extract_option('--app')
|
42
|
+
unless app
|
43
|
+
app = extract_app_in_dir(Dir.pwd) ||
|
44
|
+
raise(CommandFailed, "No app specified.\nRun this command from app folder or set it adding --app <app name>") if force
|
45
|
+
@autodetected_app = true
|
46
|
+
end
|
47
|
+
app
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_app_in_dir(dir)
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def extract_option(options, default=true)
|
55
|
+
values = options.is_a?(Array) ? options : [options]
|
56
|
+
return unless opt_index = args.select { |a| values.include? a }.first
|
57
|
+
opt_position = args.index(opt_index) + 1
|
58
|
+
if args.size > opt_position && opt_value = args[opt_position]
|
59
|
+
if opt_value.include?('--')
|
60
|
+
opt_value = nil
|
61
|
+
else
|
62
|
+
args.delete_at(opt_position)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
opt_value ||= default
|
66
|
+
args.delete(opt_index)
|
67
|
+
block_given? ? yield(opt_value) : opt_value
|
68
|
+
end
|
69
|
+
|
70
|
+
def escape(value)
|
71
|
+
heroku.escape(value)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ExtJS::Theme::Command
|
2
|
+
class Config < Base
|
3
|
+
def index
|
4
|
+
#long = args.delete('--long')
|
5
|
+
#vars = heroku.config_vars(app)
|
6
|
+
#display_vars(vars, :long => long)
|
7
|
+
display "index"
|
8
|
+
end
|
9
|
+
|
10
|
+
def add
|
11
|
+
unless args.size > 0 and args.all? { |a| a.include?('=') }
|
12
|
+
raise CommandFailed, "Usage: xtheme config:add <key>=<value> [<key2>=<value2> ...]"
|
13
|
+
end
|
14
|
+
|
15
|
+
#vars = args.inject({}) do |vars, arg|
|
16
|
+
# key, value = arg.split('=', 2)
|
17
|
+
# vars[key] = value
|
18
|
+
# vars
|
19
|
+
#end
|
20
|
+
|
21
|
+
display "Adding config vars:"
|
22
|
+
#display_vars(vars, :indent => 2)
|
23
|
+
|
24
|
+
#display "Restarting app...", false
|
25
|
+
#heroku.add_config_vars(app, vars)
|
26
|
+
#display "done."
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove
|
30
|
+
display "Removing #{args.first} and restarting app...", false
|
31
|
+
#heroku.remove_config_var(app, args.first)
|
32
|
+
display "done."
|
33
|
+
end
|
34
|
+
alias :rm :remove
|
35
|
+
|
36
|
+
def clear
|
37
|
+
display "Clearing all config vars and restarting app...", false
|
38
|
+
#heroku.clear_config_vars(app)
|
39
|
+
display "done."
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
def display_vars(vars, options={})
|
44
|
+
max_length = vars.map { |v| v[0].size }.max
|
45
|
+
vars.keys.sort.each do |key|
|
46
|
+
spaces = ' ' * (max_length - key.size)
|
47
|
+
display "#{' ' * (options[:indent] || 0)}#{key}#{spaces} => #{format(vars[key], options)}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def format(value, options)
|
52
|
+
return value if options[:long] || value.size < 36
|
53
|
+
value[0, 16] + '...' + value[-16, 16]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'launchy'
|
2
|
+
|
3
|
+
module ExtJS::Theme::Command
|
4
|
+
class Effects < Base
|
5
|
+
|
6
|
+
def modulate
|
7
|
+
unless @args.length == 4
|
8
|
+
display "Usage: xtheme effects:modulate <theme-name> <hue> <saturation> <lightness>"
|
9
|
+
display " Specify <hue>, <saturation> and <lightness> as Floats, for example,"
|
10
|
+
display " 0.25 means 25%. The default value of each argument is 1.0, that is, 100%"
|
11
|
+
return
|
12
|
+
end
|
13
|
+
display "Modulating theme images"
|
14
|
+
ExtJS::Theme::Effects.modulate(@config[:ext_dir], "#{@config[:theme_dir]}/#{@args[0]}", @args[1].to_f, @args[2].to_f, @args[3].to_f)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module ExtJS::Theme::Command
|
2
|
+
class Help < Base
|
3
|
+
class HelpGroup < Array
|
4
|
+
attr_reader :title
|
5
|
+
|
6
|
+
def initialize(title)
|
7
|
+
@title = title
|
8
|
+
end
|
9
|
+
|
10
|
+
def command(name, description)
|
11
|
+
self << [name, description]
|
12
|
+
end
|
13
|
+
|
14
|
+
def space
|
15
|
+
self << ['', '']
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.groups
|
20
|
+
@groups ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.group(title, &block)
|
24
|
+
groups << begin
|
25
|
+
group = HelpGroup.new(title)
|
26
|
+
group.instance_eval(&block)
|
27
|
+
group
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.create_default_groups!
|
32
|
+
group('General Commands') do
|
33
|
+
command 'help', 'show this usage'
|
34
|
+
#command 'version', 'show the gem version'
|
35
|
+
space
|
36
|
+
#command 'list', 'list your themes'
|
37
|
+
command 'create [<name>]', 'create a new theme'
|
38
|
+
space
|
39
|
+
#command 'config', 'display the theme\'s config vars (environment)'
|
40
|
+
#command 'config:add key=val [...]', 'add one or more config vars'
|
41
|
+
#space
|
42
|
+
#command 'destroy [<name>]', 'destroy a theme permanently'
|
43
|
+
end
|
44
|
+
|
45
|
+
group('Effects') do
|
46
|
+
command 'effects:modulate [<theme> <hue> <saturation> <lightness>]', 'Apply hue, saturation, lightness to a themes\'s images. Specify as Floats, where 1.0 means 100%'
|
47
|
+
space
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def index
|
52
|
+
display usage
|
53
|
+
end
|
54
|
+
|
55
|
+
def version
|
56
|
+
#display ExtJS::Theme.version
|
57
|
+
end
|
58
|
+
|
59
|
+
def usage
|
60
|
+
longest_command_length = self.class.groups.map do |group|
|
61
|
+
group.map { |g| g.first.length }
|
62
|
+
end.flatten.max
|
63
|
+
|
64
|
+
self.class.groups.inject(StringIO.new) do |output, group|
|
65
|
+
output.puts "=== %s" % group.title
|
66
|
+
output.puts
|
67
|
+
|
68
|
+
group.each do |command, description|
|
69
|
+
if command.empty?
|
70
|
+
output.puts
|
71
|
+
else
|
72
|
+
output.puts "%-*s # %s" % [longest_command_length, command, description]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
output.puts
|
77
|
+
output
|
78
|
+
end.string
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
ExtJS::Theme::Command::Help.create_default_groups!
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'launchy'
|
2
|
+
|
3
|
+
module ExtJS::Theme::Command
|
4
|
+
class Theme < Base
|
5
|
+
|
6
|
+
def init
|
7
|
+
|
8
|
+
unless args.length == 2
|
9
|
+
display "Usage: xtheme init <path/to/ext> <path/to/stylesheets>"
|
10
|
+
display " - Eg: xtheme init public/javascripts/ext-3.1.0 public/stylesheets"
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
14
|
+
unless File.directory?(args[0])
|
15
|
+
return display "Error: invalid path/to/ext #{args[0]}"
|
16
|
+
end
|
17
|
+
unless File.directory?(args[1])
|
18
|
+
return display "Error: invalid path/to/stylesheets #{args[1]}"
|
19
|
+
end
|
20
|
+
|
21
|
+
display "Initializing xtheme configuration file .xthemeconfig"
|
22
|
+
|
23
|
+
File.open(".xthemeconfig", "w+") {|f|
|
24
|
+
f << {
|
25
|
+
:ext_dir => args[0],
|
26
|
+
:theme_dir => "#{args[1]}/sass"
|
27
|
+
}.to_yaml
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def list
|
32
|
+
display "Not implemented"
|
33
|
+
end
|
34
|
+
|
35
|
+
def create
|
36
|
+
name = args.shift.downcase.strip rescue nil
|
37
|
+
if !name
|
38
|
+
return display "Usage: xtheme create <name>"
|
39
|
+
end
|
40
|
+
ExtJS::Theme::Generator.create(name, @config[:ext_dir], @config[:theme_dir])
|
41
|
+
display "Created #{name}"
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def destroy
|
46
|
+
display "Not implemented"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ExtJS::Theme
|
2
|
+
module Effects
|
3
|
+
|
4
|
+
##
|
5
|
+
# performs hsv transformation on Ext theme images and save to Sass theme dir.
|
6
|
+
# @param {String} name Theme name
|
7
|
+
# @param {String} ext_dir path to Ext directory relative to public/javascripts
|
8
|
+
# @param {Float} hue
|
9
|
+
# @param {Float} saturation
|
10
|
+
# @param {Float} lightneess
|
11
|
+
#
|
12
|
+
def self.modulate(ext_dir, theme_dir, hue=1.0, saturation=1.0, lightness=1.0)
|
13
|
+
each_image("#{ext_dir}/resources/images/default") {|img|
|
14
|
+
write_image(img.modulate(lightness, saturation, hue), theme_dir)
|
15
|
+
}
|
16
|
+
# update hue in defines.sass
|
17
|
+
defines = File.read("#{theme_dir}/defines.sass")
|
18
|
+
File.open("#{theme_dir}/defines.sass", "w+") {|f| f << defines.gsub(/hue\s?=.*/, "hue = #{(hue-1)*180}") }
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
##
|
24
|
+
# Iterate all theme images
|
25
|
+
# @param {String} path
|
26
|
+
#
|
27
|
+
def self.each_image(path)
|
28
|
+
Dir["#{path}/*/"].each do |dir|
|
29
|
+
Dir[dir+'/*.gif'].each do |filename|
|
30
|
+
yield(Magick::ImageList.new(filename))
|
31
|
+
end
|
32
|
+
Dir[dir+'/*.png'].each do |filename|
|
33
|
+
yield(Magick::ImageList.new(filename))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
# Now transform any images left in the base /images/default directory (excluding s.gif)
|
37
|
+
Dir["#{path}/*.*"].reject {|f| f.match('s.gif')}.each do |filename|
|
38
|
+
yield(Magick::ImageList.new(filename))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Write transformed RMagick::Image to theme directory
|
44
|
+
# @param {RMagick::Image} img
|
45
|
+
# @param {String} dest Theme directory
|
46
|
+
#
|
47
|
+
def self.write_image(img, dest)
|
48
|
+
# Get filename and directory
|
49
|
+
m = /\/default\/(.*)\/(.*)\.(.*)$/.match(img.filename) || /\/default\/(.*)\.(.*)$/.match(img.filename)
|
50
|
+
#m = /\/(.*)\/(.*)\.(.*)$/.match(img.filename) || /\/(.*)\.(.*)$/.match(img.filename)
|
51
|
+
outfile = (m.captures.length == 3) ? "#{dest}/images/#{m[1]}#{m[2]}.#{m[3]}" : "#{dest}/images/#{m[1]}.#{m[2]}"
|
52
|
+
|
53
|
+
puts " - #{outfile}"
|
54
|
+
img.write(outfile)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module ExtJS
|
2
|
+
module Theme
|
3
|
+
module Generator
|
4
|
+
##
|
5
|
+
# creates a new Sass theme
|
6
|
+
# @param {String} name
|
7
|
+
# @param {String} ext_dir path to Ext directory relative to public/javascripts
|
8
|
+
# @param {String} theme_dir Path to theme output dir (eg: stylesheets/sass)
|
9
|
+
#
|
10
|
+
def self.create(name, ext_dir, theme_dir)
|
11
|
+
ext_css_path = "#{ext_dir}/resources/css"
|
12
|
+
theme_path = "#{theme_dir}/#{name}"
|
13
|
+
|
14
|
+
# Create theme directory in /stylesheets/sass
|
15
|
+
FileUtils.mkdir_p ["#{theme_path}/visual", "#{theme_path}/structure"]
|
16
|
+
|
17
|
+
# Create the defines.sass file, set img_path variable.
|
18
|
+
FileUtils.copy("#{File.dirname(__FILE__)}/template/defines.sass", "#{theme_path}/defines.sass")
|
19
|
+
defines = File.read("#{theme_path}/defines.sass")
|
20
|
+
File.open("#{theme_path}/defines.sass", "w+") {|f| f << defines.gsub(/\{\{img_path\}\}/, "../sass/#{name}/images") }
|
21
|
+
puts " - created #{theme_path}/defines.sass"
|
22
|
+
|
23
|
+
sass_files = []
|
24
|
+
# Iterate each Ext css file and convert to Sass.
|
25
|
+
["structure", "visual"].each do |subdir|
|
26
|
+
puts " Converting #{subdir} styles to Sass"
|
27
|
+
Dir["#{ext_css_path}/#{subdir}/*.css"].each do |file|
|
28
|
+
m = /^.*\/(.*)\.css$/.match(file)
|
29
|
+
sass_file = "#{theme_path}/#{subdir}/#{m.captures[0]}.sass"
|
30
|
+
puts " - css2sass #{m.captures[0]}.css -> #{sass_file}"
|
31
|
+
sass_files << "@import #{subdir}/#{m.captures[0]}.sass"
|
32
|
+
`css2sass #{file} #{sass_file}`
|
33
|
+
write_sass_vars(sass_file)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Create master sass file, which includes @imports for all other files in theme.
|
38
|
+
puts " - Writing init.sass"
|
39
|
+
f = File.new("#{theme_path}/init.sass", "w")
|
40
|
+
f.puts sass_files.join("\n")
|
41
|
+
|
42
|
+
# Copy Ext theme images to new Sass theme dir.
|
43
|
+
FileUtils.cp_r("#{ext_dir}/resources/images/default", "#{theme_path}/images")
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# performs hsv transformation on Ext theme images and save to Sass theme dir.
|
48
|
+
# @param {String} name Theme name
|
49
|
+
# @param {String} ext_dir path to Ext directory relative to public/javascripts
|
50
|
+
# @param {Float} hue
|
51
|
+
# @param {Float} saturation
|
52
|
+
# @param {Float} lightneess
|
53
|
+
#
|
54
|
+
def self.hsv_transform(name, ext_dir, theme_dir, hue=1.0, saturation=1.0, lightness=1.0)
|
55
|
+
theme_path = "#{theme_dir}/#{name}"
|
56
|
+
|
57
|
+
each_image(ext_path) {|img|
|
58
|
+
write_image(img.modulate(lightness, saturation, hue), theme_path(name))
|
59
|
+
}
|
60
|
+
# update hue in defines.sass
|
61
|
+
defines = File.read("#{theme_path}/defines.sass")
|
62
|
+
File.open("#{theme_path}/defines.sass", "w+") {|f| f << defines.gsub(/hue\s?=.*/, "hue = #{(hue-1)*180}") }
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
##
|
68
|
+
# Iterate all theme images
|
69
|
+
# @param {String} path
|
70
|
+
#
|
71
|
+
def self.each_image(path)
|
72
|
+
Dir["#{path}/*/"].each do |dir|
|
73
|
+
Dir[dir+'/*.gif'].each do |filename|
|
74
|
+
yield(Magick::ImageList.new(filename))
|
75
|
+
end
|
76
|
+
Dir[dir+'/*.png'].each do |filename|
|
77
|
+
yield(Magick::ImageList.new(filename))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
# Now transform any images left in the base /images/default directory (excluding s.gif)
|
81
|
+
Dir["#{path}/*.*"].reject {|f| f.match('s.gif')}.each do |filename|
|
82
|
+
yield(Magick::ImageList.new(filename))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Searches .sass file for HEX colors and wraps in Sass adjust_hue function.
|
88
|
+
# Also substitutes urls with !img_path Sass var
|
89
|
+
# @param {String} filename of .sass file to write !vars to
|
90
|
+
#
|
91
|
+
def self.write_sass_vars(file)
|
92
|
+
sass = File.read(file)
|
93
|
+
sass.gsub!(/background-image: url\(\.\.\/images\/default/, 'background-image = url(!img_path')
|
94
|
+
sass.gsub!(/\b(.*):\s?#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/, '\1 = adjust_hue(#\2, !hue)')
|
95
|
+
|
96
|
+
# append @import "defines.sass" at start of each .sass file in order to use defined variables
|
97
|
+
File.open(file, "w") {|f| f << "@import ../defines.sass\n#{sass}" }
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Write transformed RMagick::Image to theme directory
|
102
|
+
# @param {RMagick::Image} img
|
103
|
+
# @param {String} dest Theme directory
|
104
|
+
#
|
105
|
+
def self.write_image(img, dest)
|
106
|
+
# Get filename and directory
|
107
|
+
m = /\/default\/(.*)\/(.*)\.(.*)$/.match(img.filename) || /\/default\/(.*)\.(.*)$/.match(img.filename)
|
108
|
+
#m = /\/(.*)\/(.*)\.(.*)$/.match(img.filename) || /\/(.*)\.(.*)$/.match(img.filename)
|
109
|
+
outfile = (m.captures.length == 3) ? "#{dest}/images/#{m[1]}#{m[2]}.#{m[3]}" : "#{dest}/images/#{m[1]}.#{m[2]}"
|
110
|
+
|
111
|
+
puts " - #{outfile}"
|
112
|
+
img.write(outfile)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: extjs-theme
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Scott
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-12 00:00:00 -05:00
|
13
|
+
default_executable: xtheme
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thoughtbot-shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rmagick
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: haml-edge
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "2.3"
|
44
|
+
version:
|
45
|
+
description: Generates Sass-based Ext themes. Includes methods for colorizing themes.
|
46
|
+
email: christocracy@gmail.com
|
47
|
+
executables:
|
48
|
+
- xtheme
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- LICENSE
|
53
|
+
- README
|
54
|
+
- README.rdoc
|
55
|
+
files:
|
56
|
+
- Rakefile
|
57
|
+
- bin/xtheme
|
58
|
+
- lib/extjs-theme.rb
|
59
|
+
- lib/extjs-theme/command.rb
|
60
|
+
- lib/extjs-theme/commands/base.rb
|
61
|
+
- lib/extjs-theme/commands/conifg.rb
|
62
|
+
- lib/extjs-theme/commands/effects.rb
|
63
|
+
- lib/extjs-theme/commands/help.rb
|
64
|
+
- lib/extjs-theme/commands/theme.rb
|
65
|
+
- lib/extjs-theme/dependencies.rb
|
66
|
+
- lib/extjs-theme/effects.rb
|
67
|
+
- lib/extjs-theme/generator.rb
|
68
|
+
- lib/extjs-theme/template/defines.sass
|
69
|
+
- test/extjs-xtheme_test.rb
|
70
|
+
- test/test_helper.rb
|
71
|
+
- LICENSE
|
72
|
+
- README
|
73
|
+
- README.rdoc
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: http://github.com/extjs/extjs-theme
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options:
|
80
|
+
- --charset=UTF-8
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
version:
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: "0"
|
94
|
+
version:
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.3.5
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Ext theme-generator and colorizer
|
102
|
+
test_files:
|
103
|
+
- test/extjs-xtheme_test.rb
|
104
|
+
- test/test_helper.rb
|