zlide 0.0.1

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 (53) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +47 -0
  5. data/Rakefile +8 -0
  6. data/bin/zlide +9 -0
  7. data/lib/zlide.rb +9 -0
  8. data/lib/zlide/cli/base.rb +40 -0
  9. data/lib/zlide/deck.rb +56 -0
  10. data/lib/zlide/layouts/deckjs.haml +44 -0
  11. data/lib/zlide/redcarpet/renderers.rb +5 -0
  12. data/lib/zlide/redcarpet/renderers/html.rb +35 -0
  13. data/lib/zlide/redcarpet/renderers/mock.rb +31 -0
  14. data/lib/zlide/redcarpet/renderers/pdf.rb +214 -0
  15. data/lib/zlide/server/base.rb +45 -0
  16. data/lib/zlide/templates/README.md.tt +5 -0
  17. data/lib/zlide/templates/config/deck.yml.tt +1 -0
  18. data/lib/zlide/templates/stylesheets/deck-theme.css +214 -0
  19. data/lib/zlide/templates/stylesheets/highlight-theme.css +127 -0
  20. data/lib/zlide/templates/stylesheets/slides.css +10 -0
  21. data/lib/zlide/version.rb +3 -0
  22. data/spec/spec_helper.rb +3 -0
  23. data/spec/zlide/deck_spec.rb +32 -0
  24. data/spec/zlide/server/base_spec.rb +23 -0
  25. data/vendor/javascripts/deck.js +1 -0
  26. data/vendor/javascripts/deck/deck.core.js +498 -0
  27. data/vendor/javascripts/deck/deck.edit.js +33 -0
  28. data/vendor/javascripts/deck/deck.goto.js +170 -0
  29. data/vendor/javascripts/deck/deck.hash.js +142 -0
  30. data/vendor/javascripts/deck/deck.menu.js +187 -0
  31. data/vendor/javascripts/deck/deck.navigation.js +92 -0
  32. data/vendor/javascripts/deck/deck.scale.js +170 -0
  33. data/vendor/javascripts/deck/deck.status.js +95 -0
  34. data/vendor/javascripts/highlight.js +1 -0
  35. data/vendor/javascripts/jquery-1.7.2.min.js +4 -0
  36. data/vendor/javascripts/modernizr.custom.js +4 -0
  37. data/vendor/stylesheets/deck.css +4 -0
  38. data/vendor/stylesheets/deck/deck.core.css +407 -0
  39. data/vendor/stylesheets/deck/deck.goto.css +41 -0
  40. data/vendor/stylesheets/deck/deck.hash.css +13 -0
  41. data/vendor/stylesheets/deck/deck.menu.css +47 -0
  42. data/vendor/stylesheets/deck/deck.navigation.css +43 -0
  43. data/vendor/stylesheets/deck/deck.scale.css +28 -0
  44. data/vendor/stylesheets/deck/deck.status.css +18 -0
  45. data/vendor/stylesheets/deck/transition/fade.css +43 -0
  46. data/vendor/stylesheets/deck/transition/fade.scss +69 -0
  47. data/vendor/stylesheets/deck/transition/horizontal-slide.css +76 -0
  48. data/vendor/stylesheets/deck/transition/horizontal-slide.scss +90 -0
  49. data/vendor/stylesheets/deck/transition/vertical-slide.css +94 -0
  50. data/vendor/stylesheets/deck/transition/vertical-slide.scss +112 -0
  51. data/vendor/stylesheets/test.css +3 -0
  52. data/zlide.gemspec +27 -0
  53. metadata +229 -0
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ slides
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zlide.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 David Roetzel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,47 @@
1
+ # zlide
2
+
3
+ zlide is a tool to build web-based presentations from markdown files.
4
+
5
+ It currently uses deck.js for handling of slides in the browser.
6
+
7
+ ## Alternatives
8
+
9
+ zlide is currently a work in progress and you are probably better served by one of the many alternatives.
10
+
11
+ If all you want is to generate and dynamically serve up deck.js presentations from markdown files, have a look at deck.rb (https://github.com/alexch/deck.rb).
12
+
13
+ If you want a maximum of flexibility check out the excellent slideshow gem: http://slideshow.rubyforge.org/
14
+
15
+ ## Installation
16
+
17
+ Install via rubygems:
18
+
19
+ $ gem install zlide
20
+
21
+ ## Usage
22
+
23
+ Create a new slide deck:
24
+
25
+ $ zlide new <deck_name>
26
+
27
+ This will scaffold a directory called 'deck_name' with a few files and directories to get you started.
28
+
29
+ Change to the newly created directory, put one or more markdown files in the slides/ folder and you are good to go.
30
+
31
+ Serve up your presentation:
32
+
33
+ $ zlide serve
34
+
35
+ This will start a web server on port 4567. Just navigate to http://localhost:4567 in your web browser.
36
+
37
+ Compile a pdf handout:
38
+
39
+ $ zlide pdf
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "zlide"
4
+
5
+ if File.exist?('config/deck.yml')
6
+ CONFIG = YAML.load(File.read('config/deck.yml'))
7
+ end
8
+
9
+ Zlide::CLI::Base.start
@@ -0,0 +1,9 @@
1
+ require "zlide/version"
2
+ require "zlide/deck"
3
+ require "zlide/server/base"
4
+ require "zlide/cli/base"
5
+ require "zlide/redcarpet/renderers"
6
+
7
+ module Zlide
8
+ # Your code goes here...
9
+ end
@@ -0,0 +1,40 @@
1
+ require 'thor'
2
+
3
+ module Zlide
4
+ module CLI
5
+ class Base < Thor
6
+ include Thor::Actions
7
+
8
+ def self.source_root
9
+ File.expand_path("../../templates", __FILE__)
10
+ end
11
+
12
+ desc "new", "create a new slide deck"
13
+ def new(name)
14
+ empty_directory(name)
15
+ self.destination_root = name
16
+ ["slides", "public", "stylesheets", "config"].each do |subdirectory|
17
+ empty_directory(subdirectory)
18
+ end
19
+ @name = name
20
+ template "config/deck.yml.tt"
21
+ template "README.md.tt"
22
+ copy_file "stylesheets/deck-theme.css"
23
+ copy_file "stylesheets/highlight-theme.css"
24
+ copy_file "stylesheets/slides.css"
25
+ end
26
+
27
+ desc "serve", "serve your slides via http"
28
+ def serve
29
+ Zlide::Server::Base.run!
30
+ end
31
+
32
+ desc "pdf", "create a pdf version of your slides"
33
+ def pdf
34
+ deck = Zlide::Deck.new
35
+ deck.to_pdf
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,56 @@
1
+ require 'haml'
2
+ require 'yaml'
3
+
4
+ module Zlide
5
+
6
+ class Deck
7
+
8
+ def initialize
9
+ files = Dir.glob('slides/*.md')
10
+ @slides = Array.new
11
+ files.sort.each do |f|
12
+ slides = File.read(f).split(/(^!SLIDE.*$)/)[1..-1].each_slice(2).map(&:join)
13
+ slides.each do |slide|
14
+ @slides << {:file => f, :content => slide}
15
+ end
16
+ end
17
+ end
18
+
19
+ def slide(index)
20
+ @slides[index][:content]
21
+ end
22
+
23
+ def update_slide(index, content)
24
+ @slides[index][:content] = content
25
+ file = @slides[index][:file]
26
+ file_slides = @slides.select{|s| s[:file] == file}.map{|s| s[:content]}
27
+ File.open("#{file}.tmp", "w") {|f| f.write(file_slides.join)}
28
+ File.rename("#{file}.tmp", file)
29
+ end
30
+
31
+ def to_html
32
+ slides = markdown_parser(Zlide::Redcarpet::Renderers::HTML).render(full_markdown)
33
+ layout = File.read(File.join(File.dirname(__FILE__), "layouts", "deckjs.haml"))
34
+ layout_renderer = Haml::Engine.new(layout)
35
+ layout_renderer.render { slides }
36
+ end
37
+
38
+ def to_pdf
39
+ pdf = Zlide::Redcarpet::Renderers::PDF.new
40
+ markdown_parser(pdf).render(full_markdown)
41
+ pdf.write_file
42
+ end
43
+
44
+ private
45
+
46
+ def full_markdown
47
+ @slides.map{|s| s[:content]}.join
48
+ end
49
+
50
+ def markdown_parser(renderer)
51
+ ::Redcarpet::Markdown.new(renderer, :fenced_code_blocks => true, :tables => true)
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,44 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta{:charset => "utf-8"}/
5
+ %meta{:content => "IE=edge,chrome=1", "http-equiv" => "X-UA-Compatible"}/
6
+ %meta{:content => "width=1024, user-scalable=no", :name => "viewport"}/
7
+ %title= CONFIG['title']
8
+ / Required stylesheet
9
+ %link{:href => "/stylesheets/deck.css", :rel => "stylesheet"}/
10
+ %link{:href => "/stylesheets/slides.css", :rel => "stylesheet"}/
11
+ / Required Modernizr file
12
+ %script{:src => "/javascripts/modernizr.custom.js"}
13
+ %body.deck-container
14
+ / Begin slides. Just make elements with a class of slide.
15
+ = yield
16
+ / End slides.
17
+ / Begin extension snippets. Add or remove as needed.
18
+ / deck.navigation snippet
19
+ %a.deck-prev-link{:href => "#", :title => "Previous"} ←
20
+ %a.deck-next-link{:href => "#", :title => "Next"} →
21
+ / deck.status snippet
22
+ %p.deck-status
23
+ %span.deck-status-current
24
+ \/
25
+ %span.deck-status-total
26
+ / deck.goto snippet
27
+ %form.goto-form{:action => ".", :method => "get"}
28
+ %label{:for => "goto-slide"} Go to slide:
29
+ %input#goto-slide{:list => "goto-datalist", :name => "slidenum", :type => "text"}/
30
+ %datalist#goto-datalist
31
+ %input{:type => "submit", :value => "Go"}/
32
+ / deck.hash snippet
33
+ %a.deck-permalink{:href => ".", :title => "Permalink to this slide"} #
34
+ / End extension snippets.
35
+ / Required JS files.
36
+ %script{:src => "/javascripts/jquery-1.7.2.min.js"}
37
+ %script{:src => "/javascripts/deck.js"}
38
+ %script{:src => "/javascripts/highlight.js"}
39
+ / Initialize the deck. You can put this in an external file if desired.
40
+ :javascript
41
+ $(function() {
42
+ $.deck('.slide');
43
+ $('pre code').each(function(i, e) {hljs.highlightBlock(e)});
44
+ });
@@ -0,0 +1,5 @@
1
+ require "redcarpet"
2
+
3
+ require "zlide/redcarpet/renderers/mock"
4
+ require "zlide/redcarpet/renderers/html"
5
+ require "zlide/redcarpet/renderers/pdf"
@@ -0,0 +1,35 @@
1
+ module Zlide
2
+ module Redcarpet
3
+ module Renderers
4
+
5
+ class HTML < ::Redcarpet::Render::HTML
6
+
7
+ def initialize(options = {})
8
+ @slide_open = false
9
+ super(options)
10
+ end
11
+
12
+ def paragraph(text)
13
+ result = ""
14
+ if text =~ /^!SLIDE/
15
+ result += "</section>\n" if @slide_open
16
+ result += "<section class=\"slide\">\n"
17
+ @slide_open = true
18
+ else
19
+ result += "<p>#{text}</p>\n"
20
+ end
21
+ result
22
+ end
23
+
24
+ def doc_footer
25
+ if @slide_open
26
+ @slide_open = false
27
+ "</section>"
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ module Zlide
2
+ module Redcarpet
3
+ module Renderers
4
+
5
+ class Mock < ::Redcarpet::Render::HTML #Base
6
+
7
+ def block_html(text)
8
+ puts "block html: #{text}"
9
+ end
10
+
11
+ def paragraph(text)
12
+ if text =~ /!SLIDE/
13
+ puts "p: #{text}"
14
+ else
15
+ puts super(text)
16
+ end
17
+ end
18
+
19
+ def header(text, level)
20
+ puts "header#{level}: #{text}"
21
+ end
22
+
23
+ def entity(text)
24
+ puts "ENTITY: #{text}"
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,214 @@
1
+ # encoding: utf-8
2
+ require 'prawn'
3
+ require 'prawn/measurement_extensions'
4
+
5
+ module Zlide
6
+ module Redcarpet
7
+ module Renderers
8
+
9
+ class PDF < ::Redcarpet::Render::Base
10
+
11
+ class ListData < ::Array ; end
12
+ class TableData < ::Array ; end
13
+
14
+ def initialize
15
+ @pdf = Prawn::Document.new(
16
+ :page_size => "A4",
17
+ :page_layout => :landscape,
18
+ :info => {:Title => CONFIG['title']}
19
+ )
20
+ @pdf.define_grid(:rows => 2, :columns => 2, :gutter => 1.cm)
21
+ @current_row = 0
22
+ @current_column = 0
23
+ @command_queue = []
24
+ @current_box = @pdf.grid(0,0)
25
+ @slide_open = false
26
+ @list_items = []
27
+ @table_cells = []
28
+ @table_rows = []
29
+ @table_cache = []
30
+ super
31
+ end
32
+
33
+ def header(text, level)
34
+ text_size = 17 - level
35
+ @command_queue << Proc.new do
36
+ @pdf.text text, :size => text_size, :style => :bold, :inline_format => true
37
+ if level <= 2
38
+ @pdf.line_width 0.5
39
+ @pdf.horizontal_rule
40
+ @pdf.stroke
41
+ end
42
+ @pdf.move_down text_size
43
+ end
44
+ ""
45
+ end
46
+
47
+ def list(content, type)
48
+ data = ListData.new
49
+ counter = 1
50
+ number_of_items = content.count('.')
51
+ @list_items.pop(number_of_items).each do |item|
52
+ if item.is_a? String
53
+ case type
54
+ when :unordered
55
+ data << ["•", item]
56
+ when :ordered
57
+ data << ["#{counter}.", item]
58
+ counter += 1
59
+ end
60
+ else
61
+ data << [nil, item]
62
+ @command_queue.delete(item)
63
+ end
64
+ end
65
+ index = @table_cache.size
66
+ @command_queue << data
67
+ @table_cache << data
68
+ "__table_#{index}"
69
+ end
70
+
71
+ def list_item(text, type)
72
+ table = nil
73
+ matches = text.scan(/\n__table_\d+/)
74
+ if matches.any?
75
+ table_marker = matches.first
76
+ table = @table_cache[table_marker.sub("\n__table_", '').to_i]
77
+ text.sub!(table_marker, '')
78
+ end
79
+ @list_items << text
80
+ @list_items << table if table
81
+ table ? ".." : "."
82
+ end
83
+
84
+ def table(header, body)
85
+ data = TableData.new
86
+ body_rows = @table_rows.pop(body.count('.'))
87
+ header_rows = @table_rows.pop(body.count('.'))
88
+ data.concat header_rows.map{|row| row.map{|column| tag(:b, column)}}
89
+ data.concat body_rows
90
+ @command_queue << data
91
+ ""
92
+ end
93
+
94
+ def table_row(content)
95
+ @table_rows << @table_cells.pop(content.count('.'))
96
+ "."
97
+ end
98
+
99
+ def table_cell(content, alignment)
100
+ @table_cells << content
101
+ "."
102
+ end
103
+
104
+ def emphasis(text)
105
+ tag :i, text
106
+ end
107
+
108
+ def double_emphasis(text)
109
+ tag :b, text
110
+ end
111
+
112
+ def strikethrough(text)
113
+ tag :strikethrough, text
114
+ end
115
+
116
+ def link(href, title, content)
117
+ "<link href='#{href}'>#{content}</link>"
118
+ end
119
+
120
+ def image(href, title, alt_text)
121
+ @command_queue << Proc.new do
122
+ @pdf.image File.join('public', href), :fit => [@pdf.bounds.width, @pdf.cursor - 5]
123
+ end
124
+ ""
125
+ end
126
+
127
+ def paragraph(text)
128
+ if text =~ /^!SLIDE/
129
+ if @slide_open
130
+ next_box
131
+ else
132
+ @slide_open = true
133
+ end
134
+ else
135
+ @command_queue << Proc.new { @pdf.text(text, :inline_format => true) }
136
+ end
137
+ ""
138
+ end
139
+
140
+ def block_code(code, language)
141
+ code.gsub!(/^(\s+)/m) { |m| "\xC2\xA0" * m.size }
142
+ code_block = Proc.new do
143
+ font = @pdf.font.name
144
+ @pdf.bounding_box([5, @pdf.cursor], :width => @pdf.bounds.width - 10) do
145
+ @pdf.move_down 5
146
+ @pdf.font "Courier"
147
+ @pdf.indent(5) { @pdf.text code, :size => 9 }
148
+ @pdf.line_width 0.1
149
+ @pdf.join_style :round
150
+ @pdf.stroke_bounds
151
+ end
152
+ @pdf.font font
153
+ end
154
+ @command_queue << code_block
155
+ ""
156
+ end
157
+
158
+ def write_file
159
+ @pdf.render_file("#{CONFIG['title']}.pdf")
160
+ end
161
+
162
+ private
163
+
164
+ def next_box
165
+ @current_box.bounding_box do
166
+ @pdf.line_width 0.5
167
+ @pdf.stroke_bounds
168
+ @pdf.bounding_box([5,@pdf.bounds.top - 5], :width => @pdf.bounds.width - 10, :height => @pdf.bounds.height - 10) do
169
+ @command_queue.each do |c|
170
+ if c.is_a? Proc
171
+ c.call
172
+ elsif c.is_a? ListData
173
+ cell_style = {:borders => [], :padding => 2}
174
+ data = c.map do |row|
175
+ row.map do |cell|
176
+ if cell.is_a? Array
177
+ @pdf.make_table cell, :cell_style => cell_style.merge(:inline_format => true), :column_widths => [25, @pdf.bounds.width - 55]
178
+ else
179
+ cell
180
+ end
181
+ end
182
+ end
183
+ @pdf.table data, :cell_style => cell_style, :column_widths => [25, @pdf.bounds.width - 30] do |t|
184
+ t.cells.grep(Prawn::Table::Cell::Text).each {|text| text.style({:inline_format => true})}
185
+ end
186
+ elsif c.is_a? TableData
187
+ @pdf.table c, :cell_style => {:inline_format => true, :border_width => 0.5}
188
+ end
189
+ end
190
+ end
191
+ end
192
+ @command_queue.clear
193
+ if @current_row == 1 and @current_column == 1
194
+ @pdf.start_new_page
195
+ @current_row = 0
196
+ @current_column = 0
197
+ else
198
+ @current_column += 1
199
+ if @current_column > 1
200
+ @current_row += 1
201
+ @current_column = 0
202
+ end
203
+ end
204
+ @current_box = @pdf.grid(@current_row, @current_column)
205
+ end
206
+
207
+ def tag(type, content)
208
+ "<#{type}>#{content}</#{type}>"
209
+ end
210
+ end
211
+
212
+ end
213
+ end
214
+ end