maglove 0.3.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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +137 -0
- data/README.md +26 -0
- data/bin/maglove +21 -0
- data/data/maglove/scaffold/base/base.coffee +1 -0
- data/data/maglove/scaffold/base/base.less +26 -0
- data/data/maglove/scaffold/base/images/base/loading-bars.svg +17 -0
- data/data/maglove/scaffold/base/less/base/animations.less +301 -0
- data/data/maglove/scaffold/base/less/base/blockquotes.less +23 -0
- data/data/maglove/scaffold/base/less/base/buttons.less +76 -0
- data/data/maglove/scaffold/base/less/base/code.less +19 -0
- data/data/maglove/scaffold/base/less/base/forms.less +115 -0
- data/data/maglove/scaffold/base/less/base/global.less +142 -0
- data/data/maglove/scaffold/base/less/base/grid-minimal.less +146 -0
- data/data/maglove/scaffold/base/less/base/grid-non-responsive.less +63 -0
- data/data/maglove/scaffold/base/less/base/grid.less +267 -0
- data/data/maglove/scaffold/base/less/base/helpers.less +146 -0
- data/data/maglove/scaffold/base/less/base/images.less +8 -0
- data/data/maglove/scaffold/base/less/base/lists.less +23 -0
- data/data/maglove/scaffold/base/less/base/mixins.less +107 -0
- data/data/maglove/scaffold/base/less/base/print.less +35 -0
- data/data/maglove/scaffold/base/less/base/resets.less +27 -0
- data/data/maglove/scaffold/base/less/base/tables.less +29 -0
- data/data/maglove/scaffold/base/less/core/alignments.less +17 -0
- data/data/maglove/scaffold/base/less/core/cleanup.less +8 -0
- data/data/maglove/scaffold/base/less/core/editor.less +23 -0
- data/data/maglove/scaffold/base/less/core/typography.less +74 -0
- data/data/maglove/scaffold/base/less/vendor/flex-video.less +22 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/animated.less +34 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/bordered-pulled.less +16 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/core.less +13 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/fixed-width.less +6 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/font-awesome.less +17 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/icons.less +596 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/larger.less +13 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/list.less +19 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/mixins.less +27 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/rotated-flipped.less +20 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/stacked.less +20 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome/variables.less +606 -0
- data/data/maglove/scaffold/base/less/vendor/font-awesome.less +16 -0
- data/data/maglove/scaffold/base/less/vendor/image-loader.less +15 -0
- data/data/maglove/scaffold/base/less/vendor/magnific-popup.less +363 -0
- data/data/maglove/scaffold/base/less/widgets/banner.less +3 -0
- data/data/maglove/scaffold/base/less/widgets/button.less +26 -0
- data/data/maglove/scaffold/base/less/widgets/callout.less +3 -0
- data/data/maglove/scaffold/base/less/widgets/columns.less +25 -0
- data/data/maglove/scaffold/base/less/widgets/container.less +114 -0
- data/data/maglove/scaffold/base/less/widgets/feedback.less +11 -0
- data/data/maglove/scaffold/base/less/widgets/heading.less +8 -0
- data/data/maglove/scaffold/base/less/widgets/horizontal_rule.less +113 -0
- data/data/maglove/scaffold/base/less/widgets/image.less +85 -0
- data/data/maglove/scaffold/base/less/widgets/paragraph.less +3 -0
- data/data/maglove/scaffold/base/variables.less +75 -0
- data/data/maglove/scaffold/base/vendor/jquery.js +4 -0
- data/data/maglove/scaffold/theme/images/logo.png +0 -0
- data/data/maglove/scaffold/theme/images/pattern/symphony.png +0 -0
- data/data/maglove/scaffold/theme/less/base/variables.less +25 -0
- data/data/maglove/scaffold/theme/templates/article-01.haml +41 -0
- data/data/maglove/scaffold/theme/templates/cover.haml +27 -0
- data/data/maglove/scaffold/theme/templates/toc.haml +34 -0
- data/data/maglove/scaffold/theme/templates/toc.yml +12 -0
- data/data/maglove/scaffold/theme/theme.coffee +1 -0
- data/data/maglove/scaffold/theme/theme.less +4 -0
- data/data/maglove/sdk.coffee +22 -0
- data/data/maglove/sdk.haml +18 -0
- data/data/maglove/sdk.less +60 -0
- data/data/maglove/thumbnail.haml +11 -0
- data/data/maglove/thumbnail.js +160 -0
- data/data/maglove/vendor.js +4 -0
- data/lib/ext/commander/command.rb +32 -0
- data/lib/ext/commander/methods.rb +8 -0
- data/lib/maglove/application.rb +46 -0
- data/lib/maglove/asset/base_theme.rb +17 -0
- data/lib/maglove/asset/theme.rb +83 -0
- data/lib/maglove/command/compile.rb +40 -0
- data/lib/maglove/command/compress.rb +36 -0
- data/lib/maglove/command/copy.rb +35 -0
- data/lib/maglove/command/core.rb +23 -0
- data/lib/maglove/command/font.rb +80 -0
- data/lib/maglove/command/server.rb +16 -0
- data/lib/maglove/command/sync.rb +17 -0
- data/lib/maglove/command/theme.rb +132 -0
- data/lib/maglove/command/util.rb +45 -0
- data/lib/maglove/helper/asset_helper.rb +24 -0
- data/lib/maglove/helper/command_helper.rb +67 -0
- data/lib/maglove/helper/log_helper.rb +42 -0
- data/lib/maglove/helper/theme_helper.rb +101 -0
- data/lib/maglove/phantom_script.rb +45 -0
- data/lib/maglove/server.rb +80 -0
- data/lib/maglove/template/tumblr.rb +81 -0
- data/lib/maglove/tilt/coffee_template.rb +47 -0
- data/lib/maglove/tilt/haml_template.rb +20 -0
- data/lib/maglove/tilt/js_template.rb +38 -0
- data/lib/maglove/tilt/less_template.rb +18 -0
- data/lib/maglove/tilt/twig_template.rb +49 -0
- data/lib/maglove/tilt/yaml_template.rb +19 -0
- data/lib/maglove/version.rb +3 -0
- data/lib/maglove.rb +46 -0
- data/maglove.gemspec +39 -0
- metadata +427 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Asset
|
|
3
|
+
class Theme
|
|
4
|
+
include MagLove::Helper::AssetHelper
|
|
5
|
+
include MagLove::Helper::LogHelper
|
|
6
|
+
include MagLove::Helper::ThemeHelper
|
|
7
|
+
attr_reader :mtime, :path, :theme, :valid, :locals, :contents
|
|
8
|
+
|
|
9
|
+
OUTPUT_MAPPING = {
|
|
10
|
+
"haml" => "html",
|
|
11
|
+
"twig" => "html",
|
|
12
|
+
"less" => "css",
|
|
13
|
+
"coffee" => "js",
|
|
14
|
+
"yml" => "json"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def initialize(path, theme, locals={})
|
|
18
|
+
@path = path
|
|
19
|
+
@theme = theme
|
|
20
|
+
@locals = locals
|
|
21
|
+
@mtime = File.mtime(absolute_path)
|
|
22
|
+
begin
|
|
23
|
+
if ::Tilt[input_type]
|
|
24
|
+
template = ::Tilt.new(absolute_path)
|
|
25
|
+
locals[:base_path] = theme_base_path(nil, theme)
|
|
26
|
+
@contents = template.render(nil, locals)
|
|
27
|
+
else
|
|
28
|
+
@contents = File.read(absolute_path)
|
|
29
|
+
end
|
|
30
|
+
rescue Exception => e
|
|
31
|
+
error("▸ #{e.message}")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def input_type
|
|
36
|
+
File.extname(path).gsub("\.", "")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def output_type
|
|
40
|
+
OUTPUT_MAPPING[input_type] or input_type
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def valid?
|
|
44
|
+
!contents.nil?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def write!
|
|
48
|
+
return false if not valid?
|
|
49
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
50
|
+
|
|
51
|
+
File.open("#{output_path}+", 'wb') do |f|
|
|
52
|
+
f.write @contents
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Atomic write
|
|
56
|
+
FileUtils.mv("#{output_path}+", output_path)
|
|
57
|
+
|
|
58
|
+
# Set mtime correctly
|
|
59
|
+
File.utime(mtime, mtime, output_path)
|
|
60
|
+
|
|
61
|
+
true
|
|
62
|
+
ensure
|
|
63
|
+
# Ensure tmp file gets cleaned up
|
|
64
|
+
FileUtils.rm("#{output_path}+") if File.exist?("#{output_path}+")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def absolute_path
|
|
68
|
+
File.absolute_path("src/themes/#{theme}/#{path}")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def logical_path
|
|
72
|
+
return false if not valid?
|
|
73
|
+
"#{File.dirname(path)}/#{File.basename(path,'.*')}.#{output_type}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def output_path
|
|
77
|
+
return false if not valid?
|
|
78
|
+
"dist/themes/#{theme}/#{logical_path}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Compile
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :coffee, theme: "!" do |args, options|
|
|
9
|
+
asset = theme_asset("theme.coffee", options.theme)
|
|
10
|
+
debug("▸ created #{asset.logical_path}") if asset.write!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
task :less, theme: "!" do |args, options|
|
|
14
|
+
asset = theme_asset("theme.less", options.theme)
|
|
15
|
+
debug("▸ created #{asset.logical_path}") if asset.write!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
task :yaml, theme: "!" do |args, options|
|
|
19
|
+
asset = theme_asset("theme.yml", options.theme)
|
|
20
|
+
debug("▸ created #{asset.logical_path}") if asset.write!
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
task :templates, theme: "!", bucket: "!" do |args, options|
|
|
24
|
+
Hamloft::Options.defaults[:asset_uri] = "http://#{options.bucket}"
|
|
25
|
+
theme_glob("templates/*.{html,haml,twig}", options.theme).each do |file|
|
|
26
|
+
# check if yaml file exists
|
|
27
|
+
locals = {}
|
|
28
|
+
locals_contents = theme_contents(file.sub(/\.[^.]+\z/, ".yml"), options.theme)
|
|
29
|
+
if locals_contents
|
|
30
|
+
locals = YAML.load(locals_contents).with_indifferent_access
|
|
31
|
+
end
|
|
32
|
+
asset = theme_asset(file, options.theme, locals)
|
|
33
|
+
debug("▸ created #{asset.logical_path}") if asset.write!
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Compress
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :theme, theme: "!" do |args, options|
|
|
9
|
+
# archive_path("dist/themes/#{options.theme}", "**/*", "#{options.theme}.tar.gz")
|
|
10
|
+
target = "themes/#{options.theme}/#{options.theme}.tar.gz"
|
|
11
|
+
Dir.chdir("dist") do
|
|
12
|
+
tgz = Zlib::GzipWriter.new(File.open(target, "wb"))
|
|
13
|
+
Archive::Tar::Minitar::Output.open(tgz) do |tar|
|
|
14
|
+
Dir["themes/#{options.theme}/**/*"].reject{|file| file == target}.each do |file|
|
|
15
|
+
Archive::Tar::Minitar::pack_file(file, tar)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Dir.chdir(path) do
|
|
21
|
+
# tgz = Zlib::GzipWriter.new(File.open(target, 'wb'))
|
|
22
|
+
# Archive::Tar::Minitar::Output.open(tgz) do |tar|
|
|
23
|
+
# Dir[pattern].reject{|file| file == target}.each do |file|
|
|
24
|
+
# Archive::Tar::Minitar::pack_file(file, tar)
|
|
25
|
+
# end
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
debug("▸ created #{options.theme}.tar.gz")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Copy
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :base_images, theme: "!", pattern: "images/**/*.{jpg,png,gif,svg}" do |args, options|
|
|
9
|
+
pattern = options.pattern.gsub(theme_base_path("", options.theme), "")
|
|
10
|
+
theme_base_glob(pattern, options.theme).each do |file|
|
|
11
|
+
asset = base_theme_asset(file, options.theme)
|
|
12
|
+
debug("▸ created #{asset.logical_path}") if asset.write!
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
task :images, theme: "!", pattern: "images/**/*.{jpg,png,gif,svg}" do |args, options|
|
|
17
|
+
pattern = options.pattern.gsub(theme_path("", options.theme), "")
|
|
18
|
+
theme_glob(pattern, options.theme).each do |file|
|
|
19
|
+
asset = theme_asset(file, options.theme)
|
|
20
|
+
debug("▸ created #{asset.logical_path}") if asset.write!
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
task :thumbs, theme: "!", pattern: "thumbs/**/*.{jpg,png,gif,svg}" do |args, options|
|
|
25
|
+
pattern = options.pattern.gsub(theme_path("", options.theme), "")
|
|
26
|
+
theme_glob(pattern, options.theme).each do |file|
|
|
27
|
+
asset = theme_asset(file, options.theme)
|
|
28
|
+
debug("▸ created #{asset.logical_path}") if asset.write!
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Core
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :validate, theme: "!" do |args, options|
|
|
9
|
+
error! "no theme specified" if !options.theme
|
|
10
|
+
error! "theme #{options.theme} does not exist" if !File.directory?("src/themes/#{options.theme}")
|
|
11
|
+
debug("theme: #{options.theme}")
|
|
12
|
+
debug("environment: #{options.production ? 'production' : 'development'}")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
task :clean, theme: "!" do |args, options|
|
|
16
|
+
theme_clean(options.theme)
|
|
17
|
+
debug("▸ cleaned up theme directory")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Font
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def get_font_styles(font_id, variant, append_dir='')
|
|
7
|
+
font_name = font_id.gsub('-', ' ').titleize
|
|
8
|
+
case variant
|
|
9
|
+
when "regular"
|
|
10
|
+
"@font-face{font-family:'#{font_name}';src:url('#{append_dir}#{font_id}-#{variant}.ttf');}\n"
|
|
11
|
+
when "bold"
|
|
12
|
+
"@font-face{font-family:'#{font_name}';src:url('#{append_dir}#{font_id}-#{variant}.ttf');font-weight:bold;}\n"
|
|
13
|
+
when "italic"
|
|
14
|
+
"@font-face{font-family:'#{font_name}';src:url('#{append_dir}#{font_id}-#{variant}.ttf');font-style:italic;}\n"
|
|
15
|
+
when "bolditalic"
|
|
16
|
+
"@font-face{font-family:'#{font_name}';src:url('#{append_dir}#{font_id}-#{variant}.ttf');font-weight:bold;font-style:italic;}\n"
|
|
17
|
+
when "light"
|
|
18
|
+
"@font-face{font-family:'#{font_name}';src:url('#{append_dir}#{font_id}-#{variant}.ttf');font-weight:300;}\n"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run
|
|
23
|
+
|
|
24
|
+
task :compile, bucket: "cdn.magloft.com", sync: "NO" do |args, options|
|
|
25
|
+
|
|
26
|
+
# clean up
|
|
27
|
+
FileUtils.rm_rf("dist/fonts")
|
|
28
|
+
FileUtils.mkdir_p("dist/fonts")
|
|
29
|
+
|
|
30
|
+
# 1: Build font map
|
|
31
|
+
debug("▸ building font map")
|
|
32
|
+
font_map = {}
|
|
33
|
+
font_files = Dir.glob("src/fonts/*/*.ttf")
|
|
34
|
+
font_files.each do |font_file|
|
|
35
|
+
(root_dir, font_dir, font_id, font_filename) = font_file.split("/")
|
|
36
|
+
font_variant = font_filename.gsub("#{font_id}-", '').gsub(".ttf", '')
|
|
37
|
+
font_map[font_id] = [] if font_map[font_id].nil?
|
|
38
|
+
font_map[font_id].push(font_variant)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# 2: Generate stylesheets
|
|
42
|
+
debug("▸ compiling fonts:")
|
|
43
|
+
FileUtils.touch("dist/fonts/fonts.css")
|
|
44
|
+
open("dist/fonts/fonts.css", 'wb') do |master_file|
|
|
45
|
+
font_map.each do |font_id, variants|
|
|
46
|
+
debug("~▸ compiling font '#{font_id}'")
|
|
47
|
+
|
|
48
|
+
# Create font directory
|
|
49
|
+
FileUtils.mkdir_p("dist/fonts/#{font_id}")
|
|
50
|
+
|
|
51
|
+
# Copy fonts
|
|
52
|
+
variants.each do |variant|
|
|
53
|
+
FileUtils.copy("src/fonts/#{font_id}/#{font_id}-#{variant}.ttf", "dist/fonts/#{font_id}/#{font_id}-#{variant}.ttf")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Create stylesheet
|
|
57
|
+
font_style_file = "dist/fonts/#{font_id}/font.css"
|
|
58
|
+
FileUtils.touch(font_style_file)
|
|
59
|
+
open(font_style_file, 'wb') do |file|
|
|
60
|
+
master_file << "/* #{font_id} (#{variants.join(", ")}) */\n"
|
|
61
|
+
variants.each do |variant|
|
|
62
|
+
file << get_font_styles(font_id, variant)
|
|
63
|
+
master_file << get_font_styles(font_id, variant, "#{font_id}/")
|
|
64
|
+
end
|
|
65
|
+
master_file << "\n"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
debug("▸ all font styles created")
|
|
70
|
+
|
|
71
|
+
if options.sync == "YES"
|
|
72
|
+
system "gsutil -m rsync -d -r dist/fonts gs://#{options.bucket}/fonts"
|
|
73
|
+
debug("▸ all fonts synchronized with bucket '#{options.bucket}'")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Server
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :run, theme: "!" do |args, options|
|
|
9
|
+
info("▸ starting server for theme '#{options.theme}'")
|
|
10
|
+
MagLove::Server.new(options.theme).run!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Sync
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :cdn, theme: "!", bucket: "test-cdn.magloft.com" do |args, options|
|
|
9
|
+
error! "theme '#{options.theme}' does not exist. Did you run theme:compile yet?" if !options.theme or !File.directory?("dist/themes/#{options.theme}")
|
|
10
|
+
info("▸ synchronizing #{options.theme} to #{options.bucket}")
|
|
11
|
+
system "gsutil -m rsync -d -r dist/themes/#{options.theme} gs://#{options.bucket}/themes/#{options.theme}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Theme
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :compile, theme: ENV["THEME"], sync: "NO", bucket: "localhost:3002" do |args, options|
|
|
9
|
+
info("▸ compiling theme #{options.theme}")
|
|
10
|
+
invoke_tasks(["core:validate", "core:clean", "compile:coffee", "compile:less", "compile:yaml", "compile:templates", "copy:base_images", "copy:images", "copy:thumbs", "compress:theme"], options)
|
|
11
|
+
|
|
12
|
+
if options.sync == "YES"
|
|
13
|
+
error!("▸ SYNC error: please specify a bucket to use (cdn.magloft.com, test-cdn.magloft.com)") if options.bucket == "localhost:3001"
|
|
14
|
+
invoke_task("sync:cdn", options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
task :"compile-all", sync: "NO", bucket: "localhost:3002" do |args, options|
|
|
20
|
+
themes = Dir.chdir("src/themes") { Dir.glob("*") }
|
|
21
|
+
themes.each do |theme|
|
|
22
|
+
options.theme = theme
|
|
23
|
+
invoke_task("theme:compile", options)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
task :thumbnails, theme: ENV["THEME"] do |args, options|
|
|
28
|
+
info("▸ Starting Server")
|
|
29
|
+
Thread.new do
|
|
30
|
+
MagLove::Server.new(options.theme, 3000).run!
|
|
31
|
+
end
|
|
32
|
+
sleep 1
|
|
33
|
+
|
|
34
|
+
info("▸ Generating thumbnails for theme '#{options.theme}'")
|
|
35
|
+
|
|
36
|
+
templates = theme_config(:templates, options.theme)
|
|
37
|
+
templates.each do |template|
|
|
38
|
+
debug "▸ processing template #{template}"
|
|
39
|
+
|
|
40
|
+
variables = {}
|
|
41
|
+
variables_yaml = theme_contents("templates/#{template}.yml", options.theme)
|
|
42
|
+
variables = YAML.load(variables_yaml).with_indifferent_access if variables_yaml
|
|
43
|
+
variables[:theme] = options.theme
|
|
44
|
+
|
|
45
|
+
# Render template
|
|
46
|
+
template_file = theme_glob("templates/#{template}.{html,twig,haml}", options.theme).first
|
|
47
|
+
if !template_file.nil?
|
|
48
|
+
asset = MagLove::Asset::Theme.new(template_file, options.theme, variables)
|
|
49
|
+
contents = asset.contents
|
|
50
|
+
else
|
|
51
|
+
contents = "<p style='text-align: center; margin-top: 12px;'>ERROR: Template '#{template}' not found!</p>"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Render thumbnail html
|
|
55
|
+
haml_contents = File.read(File.join(Gem.datadir("maglove"), "thumbnail.haml"))
|
|
56
|
+
html = Hamloft.render(haml_contents, theme: options.theme, contents: contents)
|
|
57
|
+
|
|
58
|
+
# Create thumbnail image
|
|
59
|
+
script = PhantomScript.new('thumbnail')
|
|
60
|
+
html_base64 = Base64.strict_encode64(html)
|
|
61
|
+
contents = script.run(html_base64, "png", "480", "640", "1")
|
|
62
|
+
theme_write_contents("thumbs/#{template}.png", contents, options.theme)
|
|
63
|
+
|
|
64
|
+
# Optimize thumbnail image
|
|
65
|
+
info("▸ Optimize image")
|
|
66
|
+
begin
|
|
67
|
+
image_optim = ImageOptim.new(pngout: false, svgo: false)
|
|
68
|
+
image_optim.optimize_image!(theme_path("thumbs/#{template}.png", options.theme))
|
|
69
|
+
rescue Exception => e
|
|
70
|
+
error(e.message)
|
|
71
|
+
error!("Missing image optimization binaries. Install via: gem install image_optim_pack")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
task :init, theme: ENV["THEME"], base_version: "v1" do |args, options|
|
|
79
|
+
# validate theme
|
|
80
|
+
error! "no theme specified" if !options.theme
|
|
81
|
+
error! "theme #{options.theme} already exists" if File.directory?("src/themes/#{options.theme}")
|
|
82
|
+
debug("theme: #{options.theme}")
|
|
83
|
+
debug("environment: #{options.production ? 'production' : 'development'}")
|
|
84
|
+
|
|
85
|
+
# collect variables
|
|
86
|
+
base_scaffold_dir = File.join(Gem.datadir("maglove"), "scaffold/base")
|
|
87
|
+
base_target_dir = "src/base/#{options.base_version}"
|
|
88
|
+
theme_scaffold_dir = File.join(Gem.datadir("maglove"), "scaffold/theme")
|
|
89
|
+
theme_target_dir = "src/themes/#{options.theme}"
|
|
90
|
+
|
|
91
|
+
# create base repository
|
|
92
|
+
if !File.directory?(base_target_dir)
|
|
93
|
+
FileUtils.mkdir_p("src/base")
|
|
94
|
+
FileUtils.cp_r(base_scaffold_dir, base_target_dir)
|
|
95
|
+
info("▸ created base theme in '#{base_target_dir}'")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# create theme repository
|
|
99
|
+
FileUtils.mkdir_p("src/themes")
|
|
100
|
+
FileUtils.cp_r(theme_scaffold_dir, theme_target_dir)
|
|
101
|
+
|
|
102
|
+
# create yaml file
|
|
103
|
+
yaml_contents = {
|
|
104
|
+
"name" => options.theme.titlecase,
|
|
105
|
+
"base_version" => options.base_version,
|
|
106
|
+
"identifier" => options.theme,
|
|
107
|
+
"description" => "#{options.theme.titlecase} theme created with MagLove",
|
|
108
|
+
"templates" => ['cover', 'toc', 'article-01']
|
|
109
|
+
}
|
|
110
|
+
theme_write_contents("theme.yml", yaml_contents.to_yaml.gsub("---\n", ''), options.theme)
|
|
111
|
+
info("▸ created #{options.theme} theme in '#{theme_target_dir}'")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
task :dev, theme: ENV["THEME"] do |args, options|
|
|
115
|
+
options.production = false
|
|
116
|
+
invoke_task("theme:compile", options)
|
|
117
|
+
invoke_task("font:compile", options)
|
|
118
|
+
options.block = "NO"
|
|
119
|
+
invoke_task("util:watch", options)
|
|
120
|
+
|
|
121
|
+
# browser sync
|
|
122
|
+
options.files = "dist/themes/#{options.theme}/*.css, dist/themes/#{options.theme}/*.js, dist/themes/#{options.theme}/templates/*.html, dist/themes/#{options.theme}/images/**/*"
|
|
123
|
+
options.start_path = theme_config(:templates, options.theme).first
|
|
124
|
+
invoke_task("util:browser_sync", options)
|
|
125
|
+
|
|
126
|
+
invoke_task("server:run", options)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Command
|
|
3
|
+
class Util
|
|
4
|
+
include Commander::Methods
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
|
|
8
|
+
task :cache_clear, bucket: "cdn.magloft.com" do |args, options|
|
|
9
|
+
debug("▸ clearing cache for #{options.bucket}.magloft.com")
|
|
10
|
+
system "gsutil -m setmeta -R -h 'Cache-Control:public, max-age=0, no-transform' gs://#{options.bucket}.magloft.com/themes"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
task :browser_sync, theme: "!", files: "!", port: "3002", proxy_port: "3001", host: "localhost", start_path: "/", log_level: "silent" do |args, options|
|
|
14
|
+
debug("▸ starting browser-sync")
|
|
15
|
+
job = fork do
|
|
16
|
+
begin
|
|
17
|
+
system "browser-sync start --proxy #{options.host}:#{options.proxy_port} --port #{options.port} --files '#{options.files}' --startPath '#{options.start_path}' --logLevel #{options.log_level} --no-ui"
|
|
18
|
+
rescue Exception => e
|
|
19
|
+
info("▸ shutting down browser sync")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
Process.detach(job)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
task :watch, theme: "!", block: "NO" do |args, options|
|
|
26
|
+
info("▸ watching theme #{options.theme}")
|
|
27
|
+
watch_config({
|
|
28
|
+
"compile:coffee" => [theme_path("**/*.{coffee,js}", options.theme), theme_base_path("**/*.{coffee,js}", options.theme)],
|
|
29
|
+
"compile:less" => [theme_path("**/*.{less,css}", options.theme), theme_base_path("**/*.{less,css}", options.theme)],
|
|
30
|
+
"compile:templates" => [theme_path("**/*.{haml,twig,html}", options.theme)],
|
|
31
|
+
"copy:base_images" => theme_base_path("images/**/*.{jpg,jpeg,gif,png,svg}", options.theme),
|
|
32
|
+
"copy:images" => theme_path("images/**/*.{jpg,jpeg,gif,png,svg}", options.theme)
|
|
33
|
+
}, options)
|
|
34
|
+
|
|
35
|
+
if options.block == "YES"
|
|
36
|
+
while true
|
|
37
|
+
sleep 100
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Helper
|
|
3
|
+
module AssetHelper
|
|
4
|
+
|
|
5
|
+
def theme_asset(path, theme=nil, locals={})
|
|
6
|
+
theme ||= ENV["THEME"]
|
|
7
|
+
if not File.exists?("src/themes/#{theme}/#{path}")
|
|
8
|
+
error! "file '#{path}' not found for theme '#{theme}'"
|
|
9
|
+
end
|
|
10
|
+
MagLove::Asset::Theme.new(path, theme, locals.merge(theme: theme))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def base_theme_asset(path, theme=nil, version=nil)
|
|
14
|
+
theme ||= ENV["THEME"]
|
|
15
|
+
version ||= theme_config("base_version", theme)
|
|
16
|
+
if not File.exists?("src/base/#{version}/#{path}")
|
|
17
|
+
error! "file '#{path}' not found for base-theme '#{version}'"
|
|
18
|
+
end
|
|
19
|
+
MagLove::Asset::BaseTheme.new(path, theme, version)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Helper
|
|
3
|
+
module CommandHelper
|
|
4
|
+
|
|
5
|
+
def task(action, option_config={}, &block)
|
|
6
|
+
command "#{library}-#{action}" do |c|
|
|
7
|
+
required_options = []
|
|
8
|
+
c.syntax = "maglove #{library} #{action}"
|
|
9
|
+
c.summary = "#{library} #{action} command"
|
|
10
|
+
option_config.each do |key, value|
|
|
11
|
+
if value == "!"
|
|
12
|
+
required_options.push(key)
|
|
13
|
+
c.option "--#{key} STRING", String, "[required]"
|
|
14
|
+
else
|
|
15
|
+
c.option "--#{key} STRING", String, "[default: #{value}]"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
c.task_action do |args, options|
|
|
19
|
+
Logging.mdc["command"] = "#{library}-#{action}"
|
|
20
|
+
required_options.each do |required_option|
|
|
21
|
+
if !options.__hash__[required_option.to_sym]
|
|
22
|
+
error!("missing required option '#{required_option}'")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
options.default(option_config)
|
|
26
|
+
block.call(args, options)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def library
|
|
32
|
+
self.class.name.split("::").last.underscore
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def invoke_tasks(command_names, *args)
|
|
36
|
+
command_names.each do |command_name|
|
|
37
|
+
invoke_task(command_name, *args)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def invoke_task(command_name, *args)
|
|
42
|
+
command_name = command_name.gsub(":", "-")
|
|
43
|
+
if args.length == 0
|
|
44
|
+
command_args = []
|
|
45
|
+
command_options = Commander::Command::Options.new
|
|
46
|
+
elsif args.length == 1
|
|
47
|
+
if args[0].class == Array
|
|
48
|
+
command_args = args[0]
|
|
49
|
+
command_options = Commander::Command::Options.new
|
|
50
|
+
else
|
|
51
|
+
command_args = []
|
|
52
|
+
command_options = args[0]
|
|
53
|
+
end
|
|
54
|
+
elsif args.length == 2
|
|
55
|
+
command_args = args[0]
|
|
56
|
+
command_options = Commander::Command::Options.new
|
|
57
|
+
else
|
|
58
|
+
error!("invalid arguments specified for invoke_task '#{command_name}'")
|
|
59
|
+
end
|
|
60
|
+
command = Commander::Runner.instance.commands[command_name]
|
|
61
|
+
error!("cannot invoke command '#{command_name}': command not found") if command.nil?
|
|
62
|
+
command.invoke(command_args, command_options)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module MagLove
|
|
2
|
+
module Helper
|
|
3
|
+
module LogHelper
|
|
4
|
+
@@logger = nil
|
|
5
|
+
|
|
6
|
+
def info(message)
|
|
7
|
+
logger.send(:info, message)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def debug(message)
|
|
11
|
+
logger.send(:debug, message)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def error(message)
|
|
15
|
+
logger.send(:error, message)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def error!(message)
|
|
19
|
+
logger.send(:fatal, message)
|
|
20
|
+
Kernel.exit
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def logger
|
|
24
|
+
# reset logger on task change
|
|
25
|
+
if @@logger.nil?
|
|
26
|
+
Logging.color_scheme("bright",
|
|
27
|
+
levels: { debug: :blue, info: :green, warn: :yellow, error: :red, fatal: [:white, :on_red] },
|
|
28
|
+
date: :blue,
|
|
29
|
+
mdc: :cyan,
|
|
30
|
+
logger: :cyan,
|
|
31
|
+
message: :black
|
|
32
|
+
)
|
|
33
|
+
Logging.appenders.stdout("stdout", layout: Logging.layouts.pattern( pattern: '[%d] %-5l %-16X{command} %x %m\n', color_scheme: 'bright' ))
|
|
34
|
+
@@logger = Logging::Logger.new(self.class.name)
|
|
35
|
+
@@logger.level = :info
|
|
36
|
+
@@logger.add_appenders('stdout')
|
|
37
|
+
end
|
|
38
|
+
@@logger
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|