rails_pdf 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +135 -9
- data/Rakefile +1 -1
- data/lib/generators/rails_pdf/USAGE +5 -3
- data/lib/generators/rails_pdf/rails_pdf_generator.rb +20 -3
- data/lib/generators/rails_pdf/templates/basic_invoice/invoice.pug.erb +16 -16
- data/lib/generators/rails_pdf/templates/basic_invoice/stylesheets/{invoice1.scss → invoice.scss} +4 -5
- data/lib/generators/rails_pdf/templates/chart1/chart.pug.erb +223 -0
- data/lib/generators/rails_pdf/templates/new/file.pug.erb +1 -0
- data/lib/generators/rails_pdf/templates/shared/stylesheets/bootstrap/bootstrap.print.css +60 -0
- data/lib/generators/rails_pdf/templates/simple_invoice/invoice.pug.erb +96 -0
- data/lib/generators/rails_pdf/templates/simple_invoice/stylesheets/invoice.scss +132 -0
- data/lib/rails_pdf.rb +17 -1
- data/lib/rails_pdf/railtie.rb +2 -14
- data/lib/rails_pdf/renderer.rb +79 -0
- data/lib/rails_pdf/version.rb +2 -2
- metadata +18 -12
- data/lib/rails_pdf/pug_renderer.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b74167d263e811085ad3ee4070f854aaab76ce356759784142723bbde6f103a9
|
4
|
+
data.tar.gz: cba62d372de08e8eaf0bdc70e581af296a307fd39d9a88e62e7b3358a8568d96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0524494b7cfd0dc2f06a7c46174935cb561d397c6d0a1605e158f5339e92fc31ff2f67ac168aa870595743a79dc9a8be607f6adf3d3c6ff582fe5d66c5a50b50
|
7
|
+
data.tar.gz: 156f6f0b3525959e40a5cbecfc219dbdb4106507882bd2d7a2f8afc3485a23099ee29dda2a971a13f49c69ddad3d279da019df86ae0cd48a946943c30d2a3f4a
|
data/README.md
CHANGED
@@ -1,18 +1,93 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# RailsPDF
|
2
|
+
|
3
|
+
Create PDF docs in Rails app with support of HTML/ERB/CSS/SCSS/PUG/Javascript/ChartsJS/Images/SVG/Custom Fonts/etc.
|
4
|
+
|
5
|
+
- Basically, you can create any HTML/CSS/JS/Images page and save into PDF.
|
6
|
+
- With header, footer, page numbers, layout support.
|
7
|
+
- Generate files on the fly or save to disk/tempfiles.
|
8
|
+
- Has few starter templates to help with most popular reports. Just create some and re-edit it.
|
9
|
+
|
10
|
+
## Template starters
|
11
|
+
|
12
|
+
_If you want to contribute and add more templates - it' very easy to do. See #Templates section of this doc._
|
13
|
+
|
14
|
+
<table>
|
15
|
+
<tr align="center">
|
16
|
+
<td width="25%">
|
17
|
+
<a href="https://github.com/igorkasyanchuk/rails_pdf/blob/master/docs/report_1.png">
|
18
|
+
<img src="https://github.com/igorkasyanchuk/rails_pdf/blob/master/docs/report_1_thumb.png?raw=true" />
|
19
|
+
</a>
|
20
|
+
Template: <a href="https://github.com/igorkasyanchuk/rails_pdf/blob/master/lib/generators/rails_pdf/templates/simple_invoice/invoice.pug.erb">simple_invoice</a>
|
21
|
+
</td>
|
22
|
+
<td width="25%">
|
23
|
+
<a href="https://github.com/igorkasyanchuk/rails_pdf/blob/master/docs/report_2.png">
|
24
|
+
<img src="https://github.com/igorkasyanchuk/rails_pdf/blob/master/docs/report_2_thumb.png?raw=true" />
|
25
|
+
</a>
|
26
|
+
Template: <a href="https://github.com/igorkasyanchuk/rails_pdf/blob/master/lib/generators/rails_pdf/templates/basic_invoice/invoice.pug.erb">basic_invoice</a>
|
27
|
+
</td>
|
28
|
+
<td width="50%">
|
29
|
+
<a href="https://github.com/igorkasyanchuk/rails_pdf/blob/master/docs/report_3c.png">
|
30
|
+
<img src="https://github.com/igorkasyanchuk/rails_pdf/blob/master/docs/report_3c_thumb.png?raw=true" />
|
31
|
+
</a>
|
32
|
+
Template: <a href="https://github.com/igorkasyanchuk/rails_pdf/blob/master/lib/generators/rails_pdf/templates/chart1/chart.pug.erb">chart1</a>
|
33
|
+
</td>
|
34
|
+
</tr>
|
35
|
+
</table>
|
3
36
|
|
4
37
|
## Usage
|
5
|
-
|
38
|
+
|
39
|
+
You can use predefined starter templates (and you are welcome to contribute and create additional templates):
|
40
|
+
|
41
|
+
Use template starters:
|
42
|
+
|
43
|
+
- `rails g rails_pdf new invoice_report` (create blank template for PDF)
|
44
|
+
- `rails g rails_pdf basic_invoice report`
|
45
|
+
- `rails g rails_pdf chart1 report`
|
46
|
+
- `rails g rails_pdf simple_invoice report`
|
47
|
+
|
48
|
+
After you've generated PDF template, you can edit it in `app/pdf/<folder>/<file>` file.
|
49
|
+
|
50
|
+
You can use JS/CSS files from `app/pdf/shared` (which includes bootstrap 4, foundation 6, Found Awesome 5, Charts.js).
|
51
|
+
|
52
|
+
This is how you can generate and send PDF files on the fly:
|
53
|
+
|
54
|
+
```
|
55
|
+
def report
|
56
|
+
RailsPDF.template("report2/invoice.pug.erb").render do |data|
|
57
|
+
send_data(data, type: 'application/pdf', disposition: 'inline', filename: 'report.pdf')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
If you need to create PDF file and save to file on drive:
|
63
|
+
|
64
|
+
`RailsPDF.template("report/chart.pug.erb").render_to_file('x.pdf')`
|
65
|
+
|
66
|
+
Same but save PDF into Temfile:
|
67
|
+
|
68
|
+
`RailsPDF.template("report/chart.pug.erb").render_to_tempfile('x.pdf')`
|
69
|
+
|
70
|
+
With ERB files you can use App code (like models, etc). For example you can iterate over @users and output in PDF.
|
6
71
|
|
7
72
|
## Installation
|
8
73
|
|
9
|
-
|
74
|
+
Installation of gem is very simple, it's just requires one additional step to install RelaxedJS tool which is using Chrome headless.
|
75
|
+
|
76
|
+
### Requirements
|
77
|
+
|
78
|
+
- RelaxedJS 0.2.0+ (check with `relaxed --version`)
|
79
|
+
- Chrome headless (bundled with relaxedjs)
|
80
|
+
- Rails 5+ app
|
81
|
+
|
82
|
+
#### Install RelaxedJS
|
10
83
|
|
11
84
|
>git clone https://github.com/RelaxedJS/ReLaXed.git .
|
12
85
|
>npm install
|
13
86
|
>sudo npm link --unsafe-perm=true
|
14
87
|
|
15
|
-
|
88
|
+
Verify it's installed with: `relaxed --version`.
|
89
|
+
|
90
|
+
#### Gemfile
|
16
91
|
|
17
92
|
```ruby
|
18
93
|
gem 'rails_pdf'
|
@@ -23,13 +98,64 @@ And then execute:
|
|
23
98
|
$ bundle
|
24
99
|
```
|
25
100
|
|
26
|
-
|
27
|
-
|
28
|
-
|
101
|
+
## Templates
|
102
|
+
|
103
|
+
## Tips
|
104
|
+
|
105
|
+
- if you want to add a page-break in document: `div(style="page-break-before:always")`
|
106
|
+
- if you are using bootstrap and you want to use columns - include bootstrap.print.css and use styles from it.
|
107
|
+
- if you are using Charts.js and you want to clear and readable text put in options: `devicePixelRatio: 3,`
|
108
|
+
- you can define size of page using in SCSS:
|
109
|
+
```
|
110
|
+
// A4
|
111
|
+
$page-width: 8.27in;
|
112
|
+
$page-height: 11.69in;
|
113
|
+
```
|
114
|
+
- if you want to add header/footer (sample: lib/generators/rails_pdf/templates/simple_invoice/invoice.pug.erb)
|
115
|
+
```
|
116
|
+
h1 My document
|
117
|
+
p some paragraph
|
118
|
+
|
119
|
+
template#page-header
|
120
|
+
p I appear at the top of the page
|
121
|
+
|
122
|
+
template#page-footer
|
123
|
+
p I appear at the bottom of the page
|
29
124
|
```
|
125
|
+
- if you see an error, or something is not generated check TMP folder (e.g. /tmp) tmp/*.html file (see most recent files).
|
126
|
+
- if you have problems with Charts.js you can add setTimeout(...) and execute chart creation in 200-300ms.
|
127
|
+
|
128
|
+
## Development
|
129
|
+
|
130
|
+
- open `test/dummy`
|
131
|
+
- rake db:migrate
|
132
|
+
- `rails s -b 0.0.0.0`
|
133
|
+
- open `localhost:3000/report.pdf`
|
134
|
+
- modify templates in app/pdf
|
135
|
+
|
136
|
+
## Adding a new template
|
137
|
+
|
138
|
+
- add new template in `lib/generators/rails_pdf/templates` and add folder with template (html,css,js)
|
139
|
+
- you can use CSS/JS from `templates/shared` folder
|
140
|
+
- edit `lib/generators/rails_pdf/rails_pdf_generator.rb` add new type of report
|
141
|
+
- create screenshot of template and put in `docs` folder
|
142
|
+
- update docs
|
143
|
+
- create PR
|
144
|
+
|
145
|
+
## TODO
|
146
|
+
|
147
|
+
- more starter templates
|
148
|
+
- add different charts
|
149
|
+
- better way to include JS/CSS/images
|
150
|
+
|
151
|
+
## Production
|
152
|
+
|
153
|
+
Before deploy app to production please don't forget to install Relaxed.JS on it.
|
30
154
|
|
31
155
|
## Contributing
|
32
|
-
|
156
|
+
|
157
|
+
You are welcome to contribute.
|
33
158
|
|
34
159
|
## License
|
160
|
+
|
35
161
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
Description:
|
2
|
-
|
2
|
+
Generate PDF template from starters files. Or create new blank template.
|
3
3
|
|
4
4
|
Example:
|
5
|
-
rails
|
5
|
+
rails g rails_pdf <template_name> <report_name>
|
6
6
|
|
7
7
|
This will create:
|
8
|
-
|
8
|
+
app/pdf/<report_name>/<files from report>
|
9
|
+
|
10
|
+
After generation open templates and start coding.
|
@@ -1,17 +1,34 @@
|
|
1
1
|
class RailsPdfGenerator < Rails::Generators::NamedBase
|
2
2
|
source_root File.expand_path('templates', __dir__)
|
3
3
|
|
4
|
+
TYPES = ["basic_invoice", "chart1", "simple_invoice", "new"]
|
5
|
+
|
4
6
|
def create_helper_file
|
5
7
|
report = args[0]
|
6
8
|
|
7
9
|
if report.nil?
|
8
|
-
puts "Please specify report template which you want to generate."
|
9
|
-
puts "
|
10
|
+
puts "Please specify report starter template which you want to generate or \"new\" to create blank template."
|
11
|
+
puts "Available types: #{TYPES.join(', ')}"
|
12
|
+
puts "rails g rails_pdf <type> <name of report>"
|
13
|
+
puts "sample: rails g rails_pdf #{TYPES[0]} report"
|
10
14
|
exit
|
11
15
|
end
|
12
16
|
|
17
|
+
if !TYPES.include?(file_name)
|
18
|
+
puts "Template not found. You can use any of: #{TYPES.join(', ')} "
|
19
|
+
puts "sample: rails g rails_pdf #{TYPES[0]} report"
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
13
23
|
directory "#{file_name}", "app/pdf/#{report}"
|
14
|
-
|
24
|
+
|
25
|
+
case file_name
|
26
|
+
when 'basic_invoice', 'simple_invoice'
|
27
|
+
gsub_file "app/pdf/#{report}/invoice.pug.erb", '<%= report %>', report
|
28
|
+
when 'chart1'
|
29
|
+
gsub_file "app/pdf/#{report}/chart.pug.erb", '<%= report %>', report
|
30
|
+
end
|
31
|
+
|
15
32
|
directory "mixins", "app/pdf/mixins"
|
16
33
|
directory "shared", "app/pdf/shared"
|
17
34
|
directory "layouts", "app/pdf/layouts"
|
@@ -1,29 +1,29 @@
|
|
1
|
+
link(rel="stylesheet" href="<%= Rails.root %>/app/pdf/shared/stylesheets/font-awesome/style.css")
|
2
|
+
|
1
3
|
style
|
2
|
-
include:scss <%= Rails.root%>/app/pdf/<%= report %>/stylesheets/
|
4
|
+
include:scss <%= Rails.root %>/app/pdf/<%= report %>/stylesheets/invoice.scss
|
3
5
|
|
4
6
|
body
|
5
7
|
header.clearfix
|
6
8
|
div.container
|
7
9
|
figure
|
8
|
-
img.logo(src="")
|
10
|
+
img.logo(src="<%= Rails.root %>/app/pdf/shared/images/rails_pdf.png")
|
9
11
|
.company-address
|
10
12
|
h2.title Company title
|
11
13
|
p
|
12
|
-
| 455
|
14
|
+
| 455 Smart Heights,
|
13
15
|
br
|
14
|
-
| AZ
|
16
|
+
| AZ 85000, US
|
15
17
|
|
16
18
|
.company-contact
|
17
19
|
.phone.left
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
a(href="tel:602-519-0450") (602) 519-0450
|
20
|
+
i(class="fas fa-phone")
|
21
|
+
span.helper
|
22
|
+
a(href="tel:602-519-0450") (602) 555-0450
|
22
23
|
span.helper
|
23
24
|
.email.right
|
24
|
-
|
25
|
-
|
26
|
-
span.helper
|
25
|
+
i(class="fas fa-envelope")
|
26
|
+
span.helper
|
27
27
|
a(href="mailto:company@example.com") company@example.com
|
28
28
|
span.helper
|
29
29
|
|
@@ -32,15 +32,15 @@ body
|
|
32
32
|
.details.clearfix
|
33
33
|
.client.left
|
34
34
|
p INVOICE TO:
|
35
|
-
p.name John
|
36
|
-
p
|
35
|
+
p.name John Smith
|
36
|
+
p 700 Silver Base, TX 79000, US
|
37
37
|
a(href="mailto:john@example.com") john@example.com
|
38
38
|
.data.right
|
39
|
-
.title Invoice
|
39
|
+
.title Invoice #321
|
40
40
|
.date
|
41
|
-
| Date of Invoice: 01/06/
|
41
|
+
| Date of Invoice: 01/06/2012
|
42
42
|
br/
|
43
|
-
| Due Date: 30/06/
|
43
|
+
| Due Date: 30/06/2012
|
44
44
|
table(border="0" cellpadding="0" cellspacing="0")
|
45
45
|
thead
|
46
46
|
tr
|
data/lib/generators/rails_pdf/templates/basic_invoice/stylesheets/{invoice1.scss → invoice.scss}
RENAMED
@@ -111,15 +111,14 @@ html, body, div, span, applet, object, iframe,
|
|
111
111
|
}
|
112
112
|
header figure {
|
113
113
|
float: left;
|
114
|
-
width:
|
115
|
-
height:
|
114
|
+
width: 80px;
|
115
|
+
height: 80px;
|
116
116
|
margin-right: 10px;
|
117
|
-
background-color: #8BC34A;
|
118
|
-
border-radius: 50%;
|
119
117
|
text-align: center;
|
120
118
|
}
|
121
119
|
header figure img {
|
122
|
-
|
120
|
+
max-width: 100%;
|
121
|
+
max-height: 100%;
|
123
122
|
}
|
124
123
|
header .company-address {
|
125
124
|
float: left;
|
@@ -0,0 +1,223 @@
|
|
1
|
+
script(src='<%= Rails.root %>/app/pdf/shared/javascripts/Chart.bundle.min.js')
|
2
|
+
|
3
|
+
link(rel="stylesheet" href="<%= Rails.root %>/app/pdf/shared/stylesheets/bootstrap/bootstrap.min.css")
|
4
|
+
link(rel="stylesheet" href="<%= Rails.root %>/app/pdf/shared/stylesheets/bootstrap/bootstrap.print.css")
|
5
|
+
|
6
|
+
style(lang="css")
|
7
|
+
:scss
|
8
|
+
// A4
|
9
|
+
$page-width: 8.27in;
|
10
|
+
$page-height: 11.69in;
|
11
|
+
@page {
|
12
|
+
size: $page-width $page-height;
|
13
|
+
-relaxed-page-width: $page-width;
|
14
|
+
-relaxed-page-height: $page-height;
|
15
|
+
margin: 0.5in 0.2in;
|
16
|
+
}
|
17
|
+
body {
|
18
|
+
color: #222;
|
19
|
+
}
|
20
|
+
img.logo {
|
21
|
+
height: 100px;
|
22
|
+
}
|
23
|
+
#chartContainer {
|
24
|
+
#componentsChart {
|
25
|
+
margin: 0 auto;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
.container
|
30
|
+
.row
|
31
|
+
.col-sm-10.col-print-10
|
32
|
+
h1.text-center
|
33
|
+
strong Sales Report Analysis
|
34
|
+
br
|
35
|
+
strong.text-success <%= Date.current.year %> (Q1)
|
36
|
+
.col-sm-2.col-print-2
|
37
|
+
img.logo.img-fluid(src="<%= Rails.root %>/app/pdf/shared/images/rails_pdf.png")
|
38
|
+
br
|
39
|
+
|
40
|
+
.container
|
41
|
+
.row
|
42
|
+
.col-md-6.col-print-6
|
43
|
+
.card(style="height: 410px")
|
44
|
+
.card-header Performance
|
45
|
+
.card-body
|
46
|
+
#chartContainer
|
47
|
+
canvas#componentsChart(height="350")
|
48
|
+
.col-md-6.col-print-6
|
49
|
+
.card(style="height: 410px")
|
50
|
+
.card-header Top performers
|
51
|
+
.card-body
|
52
|
+
p List of top performers in Q4:
|
53
|
+
table.table.p-0.m-0
|
54
|
+
tbody
|
55
|
+
tr
|
56
|
+
td 1
|
57
|
+
td
|
58
|
+
a(href='#') John Smith
|
59
|
+
td NY
|
60
|
+
td $50
|
61
|
+
tr
|
62
|
+
td 2
|
63
|
+
td
|
64
|
+
a(href='#') Bob Smith
|
65
|
+
td CA
|
66
|
+
td $120
|
67
|
+
tr
|
68
|
+
td 3
|
69
|
+
td
|
70
|
+
a(href='#') Michael Smith
|
71
|
+
td AZ
|
72
|
+
td.text-success $1,500
|
73
|
+
tr
|
74
|
+
td 4
|
75
|
+
td
|
76
|
+
a(href='#') Adam Johnson
|
77
|
+
td CA
|
78
|
+
td.text-danger -$100
|
79
|
+
tr
|
80
|
+
td 5
|
81
|
+
td
|
82
|
+
a(href='#') Anna Stephanson
|
83
|
+
td TX
|
84
|
+
td.text-danger -$50
|
85
|
+
tr
|
86
|
+
td 6
|
87
|
+
td
|
88
|
+
a(href='#') Nicole Tensor
|
89
|
+
td DE
|
90
|
+
td.text-success $500
|
91
|
+
|
92
|
+
br
|
93
|
+
|
94
|
+
.container
|
95
|
+
.row
|
96
|
+
.col-md-12
|
97
|
+
.card(style="height: 620px")
|
98
|
+
.card-header Sales Trends
|
99
|
+
.card-body
|
100
|
+
#salesChartContainer
|
101
|
+
canvas#salesChart(style="width: 100%")
|
102
|
+
br
|
103
|
+
p.lead
|
104
|
+
small This is a list of 10 working graphs (bar chart, pie chart, line chart, etc.) with colors and data set up to render decent looking charts that you can copy and paste into your own projects.
|
105
|
+
|
106
|
+
div(style="page-break-before:always")
|
107
|
+
|
108
|
+
.container
|
109
|
+
.row
|
110
|
+
.col-md-12
|
111
|
+
h2 Plans & Trends
|
112
|
+
p.lead Our report is a list of 10 working graphs (bar chart, pie chart, line chart, etc.) with colors and data set up to render decent looking charts that you can copy and paste into your own projects, and quickly get going with customizing and fine-tuning to make them fit your style and purpose.
|
113
|
+
|
114
|
+
br
|
115
|
+
|
116
|
+
.container
|
117
|
+
.row
|
118
|
+
.col-md-12
|
119
|
+
.card
|
120
|
+
.card-header Distribution
|
121
|
+
.card-body
|
122
|
+
#radarChartContainer
|
123
|
+
canvas#radarChart(style="width: 100%")
|
124
|
+
|
125
|
+
br
|
126
|
+
|
127
|
+
.clearfix
|
128
|
+
|
129
|
+
script.
|
130
|
+
var canvas = document.getElementById("componentsChart")
|
131
|
+
var container = document.getElementById("chartContainer")
|
132
|
+
var config= {
|
133
|
+
type: 'polarArea',
|
134
|
+
data: {
|
135
|
+
datasets: [{
|
136
|
+
data: [20, 30, 60],
|
137
|
+
backgroundColor: [ "#FF6384AA", "#4BC0C0AA", "#36A2EBAA"],
|
138
|
+
label: 'My dataset' // for legend
|
139
|
+
}],
|
140
|
+
labels: ["Rails", "PDF", "Gem"]
|
141
|
+
},
|
142
|
+
options: {
|
143
|
+
devicePixelRatio: 3,
|
144
|
+
legend: {
|
145
|
+
position: 'bottom'
|
146
|
+
},
|
147
|
+
scale: {
|
148
|
+
ticks: {
|
149
|
+
suggestedMax: 80,
|
150
|
+
stepSize: 20
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
};
|
155
|
+
var ctx = document.getElementById("componentsChart").getContext('2d');
|
156
|
+
var componentsChart = new Chart(ctx, config);
|
157
|
+
|
158
|
+
new Chart(document.getElementById("salesChart"), {
|
159
|
+
type: 'line',
|
160
|
+
data: {
|
161
|
+
labels: [1500,1600,1700,1750,1800,1850,1900,1950,1999,2050],
|
162
|
+
datasets: [{
|
163
|
+
data: [86,114,106,106,107,111,133,221,783,2478],
|
164
|
+
label: "Africa",
|
165
|
+
borderColor: "#3e95cd",
|
166
|
+
fill: false
|
167
|
+
}, {
|
168
|
+
data: [282,350,411,502,635,809,947,1402,3700,5267],
|
169
|
+
label: "Asia",
|
170
|
+
borderColor: "#8e5ea2",
|
171
|
+
fill: false
|
172
|
+
}, {
|
173
|
+
data: [168,170,178,190,203,276,408,547,675,734],
|
174
|
+
label: "Europe",
|
175
|
+
borderColor: "#3cba9f",
|
176
|
+
fill: false
|
177
|
+
}, {
|
178
|
+
data: [40,20,10,16,24,38,74,167,508,784],
|
179
|
+
label: "Latin America",
|
180
|
+
borderColor: "#e8c3b9",
|
181
|
+
fill: false
|
182
|
+
}, {
|
183
|
+
data: [6,3,2,2,7,26,82,172,312,433],
|
184
|
+
label: "North America",
|
185
|
+
borderColor: "#c45850",
|
186
|
+
fill: false
|
187
|
+
}
|
188
|
+
]
|
189
|
+
},
|
190
|
+
options: {
|
191
|
+
devicePixelRatio: 3,
|
192
|
+
}
|
193
|
+
});
|
194
|
+
|
195
|
+
new Chart(document.getElementById("radarChart"), {
|
196
|
+
type: 'radar',
|
197
|
+
data: {
|
198
|
+
labels: ["Africa", "Asia", "Europe", "Latin America", "North America"],
|
199
|
+
datasets: [
|
200
|
+
{
|
201
|
+
label: "1950",
|
202
|
+
fill: true,
|
203
|
+
backgroundColor: "rgba(179,181,198,0.2)",
|
204
|
+
borderColor: "rgba(179,181,198,1)",
|
205
|
+
pointBorderColor: "#fff",
|
206
|
+
pointBackgroundColor: "rgba(179,181,198,1)",
|
207
|
+
data: [8.77,55.61,21.69,6.62,6.82]
|
208
|
+
}, {
|
209
|
+
label: "2050",
|
210
|
+
fill: true,
|
211
|
+
backgroundColor: "rgba(255,99,132,0.2)",
|
212
|
+
borderColor: "rgba(255,99,132,1)",
|
213
|
+
pointBorderColor: "#fff",
|
214
|
+
pointBackgroundColor: "rgba(255,99,132,1)",
|
215
|
+
pointBorderColor: "#fff",
|
216
|
+
data: [25.48,54.16,7.61,8.06,4.45]
|
217
|
+
}
|
218
|
+
]
|
219
|
+
},
|
220
|
+
options: {
|
221
|
+
devicePixelRatio: 3,
|
222
|
+
}
|
223
|
+
});
|
@@ -0,0 +1 @@
|
|
1
|
+
h1 Rails PDF
|
@@ -0,0 +1,60 @@
|
|
1
|
+
// For printing
|
2
|
+
@media print {
|
3
|
+
.col-print-1 {
|
4
|
+
flex: 0 0 8.33333%;
|
5
|
+
max-width: 8.33333%; } }
|
6
|
+
|
7
|
+
@media print {
|
8
|
+
.col-print-2 {
|
9
|
+
flex: 0 0 16.66667%;
|
10
|
+
max-width: 16.66667%; } }
|
11
|
+
|
12
|
+
@media print {
|
13
|
+
.col-print-3 {
|
14
|
+
flex: 0 0 25%;
|
15
|
+
max-width: 25%; } }
|
16
|
+
|
17
|
+
@media print {
|
18
|
+
.col-print-4 {
|
19
|
+
flex: 0 0 33.33333%;
|
20
|
+
max-width: 33.33333%; } }
|
21
|
+
|
22
|
+
@media print {
|
23
|
+
.col-print-5 {
|
24
|
+
flex: 0 0 41.66667%;
|
25
|
+
max-width: 41.66667%; } }
|
26
|
+
|
27
|
+
@media print {
|
28
|
+
.col-print-6 {
|
29
|
+
flex: 0 0 50%;
|
30
|
+
max-width: 50%; } }
|
31
|
+
|
32
|
+
@media print {
|
33
|
+
.col-print-7 {
|
34
|
+
flex: 0 0 58.33333%;
|
35
|
+
max-width: 58.33333%; } }
|
36
|
+
|
37
|
+
@media print {
|
38
|
+
.col-print-8 {
|
39
|
+
flex: 0 0 66.66667%;
|
40
|
+
max-width: 66.66667%; } }
|
41
|
+
|
42
|
+
@media print {
|
43
|
+
.col-print-9 {
|
44
|
+
flex: 0 0 75%;
|
45
|
+
max-width: 75%; } }
|
46
|
+
|
47
|
+
@media print {
|
48
|
+
.col-print-10 {
|
49
|
+
flex: 0 0 83.33333%;
|
50
|
+
max-width: 83.33333%; } }
|
51
|
+
|
52
|
+
@media print {
|
53
|
+
.col-print-11 {
|
54
|
+
flex: 0 0 91.66667%;
|
55
|
+
max-width: 91.66667%; } }
|
56
|
+
|
57
|
+
@media print {
|
58
|
+
.col-print-12 {
|
59
|
+
flex: 0 0 100%;
|
60
|
+
max-width: 100%; } }
|
@@ -0,0 +1,96 @@
|
|
1
|
+
style
|
2
|
+
include:scss <%= Rails.root %>/app/pdf/<%= report %>/stylesheets/invoice.scss
|
3
|
+
|
4
|
+
body
|
5
|
+
header.clearfix
|
6
|
+
#logo
|
7
|
+
img(src="<%= Rails.root %>/app/pdf/shared/images/rails_pdf.png")
|
8
|
+
h1 INVOICE #321
|
9
|
+
#company.clearfix
|
10
|
+
div Company Name
|
11
|
+
div
|
12
|
+
| 455 Foggy Heights,
|
13
|
+
br
|
14
|
+
| AZ 85004, US
|
15
|
+
div (602) 519-0450
|
16
|
+
div
|
17
|
+
a(href="mailto:company@example.com") company@example.com
|
18
|
+
#project
|
19
|
+
div
|
20
|
+
span PROJECT
|
21
|
+
| Website development
|
22
|
+
div
|
23
|
+
span CLIENT
|
24
|
+
| John Doe
|
25
|
+
div
|
26
|
+
span ADDRESS
|
27
|
+
| 796 Silver Harbour, TX 79273, US
|
28
|
+
div
|
29
|
+
span EMAIL
|
30
|
+
a(href="mailto:john@example.com") john@example.com
|
31
|
+
div
|
32
|
+
span DATE
|
33
|
+
| August 17, 2015
|
34
|
+
div
|
35
|
+
span DUE DATE
|
36
|
+
| September 17, 2015
|
37
|
+
main
|
38
|
+
table
|
39
|
+
thead
|
40
|
+
tr
|
41
|
+
th.service SERVICE
|
42
|
+
th.desc DESCRIPTION
|
43
|
+
th PRICE
|
44
|
+
th QTY
|
45
|
+
th TOTAL
|
46
|
+
tbody
|
47
|
+
tr
|
48
|
+
td.service Design
|
49
|
+
td.desc Creating a recognizable design solution based on the company's existing visual identity
|
50
|
+
td.unit $40.00
|
51
|
+
td.qty 26
|
52
|
+
td.total $1,040.00
|
53
|
+
tr
|
54
|
+
td.service Development
|
55
|
+
td.desc Developing a Content Management System-based Website
|
56
|
+
td.unit $40.00
|
57
|
+
td.qty 80
|
58
|
+
td.total $3,200.00
|
59
|
+
tr
|
60
|
+
td.service SEO
|
61
|
+
td.desc Optimize the site for search engines (SEO)
|
62
|
+
td.unit $40.00
|
63
|
+
td.qty 20
|
64
|
+
td.total $800.00
|
65
|
+
tr
|
66
|
+
td.service Training
|
67
|
+
td.desc Initial training sessions for staff responsible for uploading web content
|
68
|
+
td.unit $40.00
|
69
|
+
td.qty 4
|
70
|
+
td.total $160.00
|
71
|
+
tr
|
72
|
+
td(colspan="4") SUBTOTAL
|
73
|
+
td.total $5,200.00
|
74
|
+
tr
|
75
|
+
td(colspan="4") TAX 25%
|
76
|
+
td.total $1,300.00
|
77
|
+
tr
|
78
|
+
td.grand.total(colspan="4") GRAND TOTAL
|
79
|
+
td.grand.total $6,500.00
|
80
|
+
#notices
|
81
|
+
div NOTICE:
|
82
|
+
.notice A finance charge of 1.5% will be made on unpaid balances after 30 days.
|
83
|
+
|
84
|
+
template#page-footer
|
85
|
+
style(type='text/css').
|
86
|
+
.pdf-footer {
|
87
|
+
color: #5D6975;
|
88
|
+
width: 100%;
|
89
|
+
height: 30px;
|
90
|
+
border-top: 1px solid #C1CED9;
|
91
|
+
padding: 8px 0;
|
92
|
+
text-align: center;
|
93
|
+
font-size: 8px;
|
94
|
+
}
|
95
|
+
.pdf-footer
|
96
|
+
| Invoice was created on a computer and is valid without the signature and seal.
|
@@ -0,0 +1,132 @@
|
|
1
|
+
// A4
|
2
|
+
$page-width: 8.27in;
|
3
|
+
$page-height: 11.69in;
|
4
|
+
|
5
|
+
@page {
|
6
|
+
size: $page-width $page-height;
|
7
|
+
-relaxed-page-width: $page-width;
|
8
|
+
-relaxed-page-height: $page-height;
|
9
|
+
margin: 0.1in 0.2in;
|
10
|
+
margin-bottom: 1in;
|
11
|
+
}
|
12
|
+
|
13
|
+
.clearfix:after {
|
14
|
+
content: "";
|
15
|
+
display: table;
|
16
|
+
clear: both;
|
17
|
+
}
|
18
|
+
|
19
|
+
a {
|
20
|
+
color: #5D6975;
|
21
|
+
text-decoration: underline;
|
22
|
+
}
|
23
|
+
|
24
|
+
body {
|
25
|
+
color: #001028;
|
26
|
+
font-family: Arial, sans-serif;
|
27
|
+
font-size: 12px;
|
28
|
+
font-family: Arial;
|
29
|
+
}
|
30
|
+
|
31
|
+
header {
|
32
|
+
padding: 10px 0;
|
33
|
+
margin-bottom: 30px;
|
34
|
+
}
|
35
|
+
|
36
|
+
#logo {
|
37
|
+
text-align: center;
|
38
|
+
margin-bottom: 10px;
|
39
|
+
}
|
40
|
+
|
41
|
+
#logo img {
|
42
|
+
width: 90px;
|
43
|
+
}
|
44
|
+
|
45
|
+
h1 {
|
46
|
+
border-top: 1px solid #5D6975;
|
47
|
+
border-bottom: 1px solid #5D6975;
|
48
|
+
color: #5D6975;
|
49
|
+
font-size: 2.4em;
|
50
|
+
line-height: 1.4em;
|
51
|
+
font-weight: normal;
|
52
|
+
text-align: center;
|
53
|
+
margin: 0 0 20px 0;
|
54
|
+
background: url(dimension.png);
|
55
|
+
}
|
56
|
+
|
57
|
+
#project {
|
58
|
+
float: left;
|
59
|
+
}
|
60
|
+
|
61
|
+
#project span {
|
62
|
+
color: #5D6975;
|
63
|
+
text-align: right;
|
64
|
+
width: 52px;
|
65
|
+
margin-right: 10px;
|
66
|
+
display: inline-block;
|
67
|
+
font-size: 0.8em;
|
68
|
+
}
|
69
|
+
|
70
|
+
#company {
|
71
|
+
float: right;
|
72
|
+
text-align: right;
|
73
|
+
}
|
74
|
+
|
75
|
+
#project div,
|
76
|
+
#company div {
|
77
|
+
white-space: nowrap;
|
78
|
+
}
|
79
|
+
|
80
|
+
table {
|
81
|
+
width: 100%;
|
82
|
+
border-collapse: collapse;
|
83
|
+
border-spacing: 0;
|
84
|
+
margin-bottom: 20px;
|
85
|
+
}
|
86
|
+
|
87
|
+
table tr:nth-child(2n-1) td {
|
88
|
+
background: #F5F5F5;
|
89
|
+
}
|
90
|
+
|
91
|
+
table th,
|
92
|
+
table td {
|
93
|
+
text-align: center;
|
94
|
+
}
|
95
|
+
|
96
|
+
table th {
|
97
|
+
padding: 5px 20px;
|
98
|
+
color: #5D6975;
|
99
|
+
border-bottom: 1px solid #C1CED9;
|
100
|
+
white-space: nowrap;
|
101
|
+
font-weight: normal;
|
102
|
+
}
|
103
|
+
|
104
|
+
table .service,
|
105
|
+
table .desc {
|
106
|
+
text-align: left;
|
107
|
+
}
|
108
|
+
|
109
|
+
table td {
|
110
|
+
padding: 20px;
|
111
|
+
text-align: right;
|
112
|
+
}
|
113
|
+
|
114
|
+
table td.service,
|
115
|
+
table td.desc {
|
116
|
+
vertical-align: top;
|
117
|
+
}
|
118
|
+
|
119
|
+
table td.unit,
|
120
|
+
table td.qty,
|
121
|
+
table td.total {
|
122
|
+
font-size: 1.2em;
|
123
|
+
}
|
124
|
+
|
125
|
+
table td.grand {
|
126
|
+
border-top: 1px solid #5D6975;;
|
127
|
+
}
|
128
|
+
|
129
|
+
#notices .notice {
|
130
|
+
color: #5D6975;
|
131
|
+
font-size: 1.2em;
|
132
|
+
}
|
data/lib/rails_pdf.rb
CHANGED
@@ -6,5 +6,21 @@ if defined?(Rails::Generators)
|
|
6
6
|
require "generators/rails_pdf/rails_pdf_generator.rb"
|
7
7
|
end
|
8
8
|
|
9
|
-
module
|
9
|
+
module RailsPDF
|
10
|
+
class << self
|
11
|
+
delegate :template, :layout, to: :instance
|
12
|
+
end
|
13
|
+
|
14
|
+
def RailsPDF.instance
|
15
|
+
Renderer.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def RailsPDF.relaxed
|
19
|
+
@@relaxed ||= begin
|
20
|
+
result = `which relaxed`.strip
|
21
|
+
raise "RelaxedJS is not installed. Check https://github.com/igorkasyanchuk/rails_pdf#install-relaxedjs" if result.blank?
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
10
26
|
end
|
data/lib/rails_pdf/railtie.rb
CHANGED
@@ -1,21 +1,9 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'renderer.rb'
|
2
2
|
|
3
3
|
require 'pry'
|
4
4
|
|
5
|
-
module
|
5
|
+
module RailsPDF
|
6
6
|
class Railtie < ::Rails::Railtie
|
7
|
-
ActionView::Template.register_template_handler(:pug, RailsPdf::PugRenderer)
|
8
|
-
|
9
|
-
ActionController::Base.prepend_view_path("app/pdf/layout")
|
10
7
|
ActionController::Base.prepend_view_path("app/pdf")
|
11
|
-
ActionController::Base.prepend_view_path("pdf")
|
12
|
-
|
13
|
-
# binding.pry
|
14
|
-
|
15
|
-
# ActionController::Base.paths["app/views"] << "app/pdf/layout"
|
16
|
-
|
17
|
-
unless Mime::Type.lookup_by_extension(:pdf)
|
18
|
-
Mime::Type.register_alias("application/pdf", :pdf)
|
19
|
-
end
|
20
8
|
end
|
21
9
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "open3"
|
2
|
+
|
3
|
+
module RailsPDF
|
4
|
+
class Renderer
|
5
|
+
def template(file)
|
6
|
+
@file = file
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
def layout(layout)
|
11
|
+
@layout = layout
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def render(&block)
|
16
|
+
content = ApplicationController.render(file: @file, layout: @layout)
|
17
|
+
|
18
|
+
logger.debug "RailsPDF ====="
|
19
|
+
logger.debug "RailsPDF content:\n#{content}"
|
20
|
+
logger.debug "RailsPDF ====="
|
21
|
+
|
22
|
+
begin
|
23
|
+
input = BetterTempfile.new("in.pug")
|
24
|
+
output = BetterTempfile.new("out.pdf")
|
25
|
+
|
26
|
+
input.write(content)
|
27
|
+
input.flush
|
28
|
+
|
29
|
+
command = "#{RailsPDF.relaxed} #{input.path.to_s} #{output.path.to_s} --basedir / --build-once"
|
30
|
+
|
31
|
+
logger.debug "RailsPDF ===== #{command}"
|
32
|
+
|
33
|
+
err = Open3.popen3(*command) do |_stdin, _stdout, stderr|
|
34
|
+
logger.debug _stdout.read
|
35
|
+
logger.debug '------'
|
36
|
+
logger.debug stderr.read
|
37
|
+
end
|
38
|
+
|
39
|
+
output.rewind
|
40
|
+
output.binmode
|
41
|
+
|
42
|
+
data = output.read
|
43
|
+
|
44
|
+
yield(data)
|
45
|
+
ensure
|
46
|
+
input&.close!
|
47
|
+
output&.close!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def render_to_file(path_and_filename = "report.pdf")
|
52
|
+
render do |data|
|
53
|
+
File.open(path_and_filename, 'wb') do |f|
|
54
|
+
f.write(data)
|
55
|
+
f.close
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def render_to_tempfile(filename = "report.pdf")
|
61
|
+
render do |data|
|
62
|
+
file = BetterTempfile.new(filename)
|
63
|
+
file.binmode
|
64
|
+
file.write(data)
|
65
|
+
file.flush
|
66
|
+
file
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def logger
|
73
|
+
Rails.logger
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
data/lib/rails_pdf/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = '0.1.
|
1
|
+
module RailsPDF
|
2
|
+
VERSION = '0.1.2'
|
3
3
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Igor Kasyanchuk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.
|
19
|
+
version: 5.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.
|
26
|
+
version: 5.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: better_tempfile
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,7 +52,8 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
description:
|
55
|
+
description: Reliable way to generate PDF files of any complexity. Support HTML/ERB/CSS/SCSS/PUG/Javascript/ChartsJS/Images/SVG/Custom
|
56
|
+
Fonts/etc.
|
56
57
|
email:
|
57
58
|
- igorkasyanchuk@gmail.com
|
58
59
|
executables: []
|
@@ -67,12 +68,15 @@ files:
|
|
67
68
|
- lib/generators/rails_pdf/templates/basic_invoice/images/logo-pdf.jpg
|
68
69
|
- lib/generators/rails_pdf/templates/basic_invoice/invoice.pug.erb
|
69
70
|
- lib/generators/rails_pdf/templates/basic_invoice/javascripts/Chart.bundle.min.js
|
70
|
-
- lib/generators/rails_pdf/templates/basic_invoice/stylesheets/
|
71
|
+
- lib/generators/rails_pdf/templates/basic_invoice/stylesheets/invoice.scss
|
72
|
+
- lib/generators/rails_pdf/templates/chart1/chart.pug.erb
|
71
73
|
- lib/generators/rails_pdf/templates/layouts/application.pug.erb
|
72
74
|
- lib/generators/rails_pdf/templates/mixins/mixin.pug
|
75
|
+
- lib/generators/rails_pdf/templates/new/file.pug.erb
|
73
76
|
- lib/generators/rails_pdf/templates/shared/images/rails_pdf.png
|
74
77
|
- lib/generators/rails_pdf/templates/shared/javascripts/Chart.bundle.min.js
|
75
78
|
- lib/generators/rails_pdf/templates/shared/stylesheets/bootstrap/bootstrap.min.css
|
79
|
+
- lib/generators/rails_pdf/templates/shared/stylesheets/bootstrap/bootstrap.print.css
|
76
80
|
- lib/generators/rails_pdf/templates/shared/stylesheets/font-awesome/style.css
|
77
81
|
- lib/generators/rails_pdf/templates/shared/stylesheets/font-awesome/webfonts/fa-brands-400.eot
|
78
82
|
- lib/generators/rails_pdf/templates/shared/stylesheets/font-awesome/webfonts/fa-brands-400.svg
|
@@ -90,12 +94,14 @@ files:
|
|
90
94
|
- lib/generators/rails_pdf/templates/shared/stylesheets/font-awesome/webfonts/fa-solid-900.woff
|
91
95
|
- lib/generators/rails_pdf/templates/shared/stylesheets/font-awesome/webfonts/fa-solid-900.woff2
|
92
96
|
- lib/generators/rails_pdf/templates/shared/stylesheets/foundation/foundation.min.css
|
97
|
+
- lib/generators/rails_pdf/templates/simple_invoice/invoice.pug.erb
|
98
|
+
- lib/generators/rails_pdf/templates/simple_invoice/stylesheets/invoice.scss
|
93
99
|
- lib/rails_pdf.rb
|
94
|
-
- lib/rails_pdf/pug_renderer.rb
|
95
100
|
- lib/rails_pdf/railtie.rb
|
101
|
+
- lib/rails_pdf/renderer.rb
|
96
102
|
- lib/rails_pdf/version.rb
|
97
103
|
- lib/tasks/rails_pdf_tasks.rake
|
98
|
-
homepage: https://github.com
|
104
|
+
homepage: https://github.com/igorkasyanchuk/rails_pdf
|
99
105
|
licenses:
|
100
106
|
- MIT
|
101
107
|
metadata: {}
|
@@ -114,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
120
|
- !ruby/object:Gem::Version
|
115
121
|
version: '0'
|
116
122
|
requirements: []
|
117
|
-
rubygems_version: 3.0.
|
123
|
+
rubygems_version: 3.0.1
|
118
124
|
signing_key:
|
119
125
|
specification_version: 4
|
120
|
-
summary:
|
126
|
+
summary: Reliable way to generate PDF files of any complexity.
|
121
127
|
test_files: []
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module RailsPdf
|
2
|
-
class PugRenderer
|
3
|
-
# ActionController::Renderers.add :pug do |filename, options|
|
4
|
-
# binding.pry
|
5
|
-
# end
|
6
|
-
|
7
|
-
def render(options = {}, local_assigns = {}, &block)
|
8
|
-
binding.pry
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.call(template)
|
12
|
-
binding.pry
|
13
|
-
%{
|
14
|
-
@filename ||= "\#{controller.action_name}.pdf"
|
15
|
-
if controller.respond_to?(:response) && !controller.response.nil?
|
16
|
-
controller.response.headers['Content-Disposition'] = "inline; filename=\\\"\#{@filename}\\\""
|
17
|
-
end
|
18
|
-
#{template.source.strip}
|
19
|
-
}
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
|