flutterby 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0bfb4189fdcf9b5640df468a2818ae3d2f647c71
4
- data.tar.gz: adb8399cc0fe5f5c8ca452f8570c8b19fd74aacb
3
+ metadata.gz: 83e24d1e73103a5cef7b60efcf5a21951e474c66
4
+ data.tar.gz: f25f5763a2a10b7190e9ea5a827ef716bba729f7
5
5
  SHA512:
6
- metadata.gz: fcdb6900c5bd5aee4c1425bb226b110a151413a27af13f368aa317326521c9a0afe0be656f48413aec7f9bad327642d3ff2c0360c37267b0a271fa83a7e78272
7
- data.tar.gz: 832097dcf92dd891160a04a1d164a392efe316aa6a8d79f92e660b76232fab0bf18d9934ce1f6d09c85fa8edc5b2765ee61a28cb64bb6241d197731b565ff649
6
+ metadata.gz: fc8ecf0efc0a1615d0149b1a94b0eb3fef7cd27db54147de26238646313f2dc679b74335cc69671364f1d04f43c96d72112ff7b596a27c883256808449622aa4
7
+ data.tar.gz: d7ed0d77dde3726cc718c0420f1d1f3a5732c17a9906329d945b7eb607ccce3fa183659a7b92787edcb024bb39883f04cbcf6982a43675da21be31b576ba860d
data/CHANGES.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Version History
2
2
 
3
+ ### 0.4.0 (2017-01-21)
4
+
5
+ - **NEW:** Flutterby views now have a `tag` helper method available that can generate HTML tags programatically.
6
+ - **NEW:** Flutterby views now have a `link_to` helper method available that renders link tags. You can use a URL string as the link target, eg. `link_to "Home", "/"`, or any Flutterby node, eg. `link_to "Blog", blog_node`.
7
+ - **NEW:** Flutterby views now have a `debug` helper that will dump its argument's YAML representation into a `<pre>` HTML tag (similar to Rails.)
8
+
9
+
3
10
  ### 0.3.1 (2017-01-15)
4
11
 
5
12
  - **NEW:** Flutterby now uses ActiveSupport. It's a big dependency, but there's just so much useful goodness in there -- let's ride on the shoulders of that giant! This allows you to use all the neat little ActiveSupport toys you may know from Rails in your Flutterby project.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Flutterby
2
2
 
3
- ### A very, very good static site generator.
3
+ ### A flexible, Ruby-powered static site generator.
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/flutterby.svg)](https://badge.fury.io/rb/flutterby) [![Build Status](https://travis-ci.org/hmans/flutterby.svg?branch=master)](https://travis-ci.org/hmans/flutterby) [![license](https://img.shields.io/github/license/hmans/flutterby.svg)](https://github.com/hmans/flutterby/blob/master/LICENSE.txt) ![Status](https://img.shields.io/badge/status-active-brightgreen.svg)
6
6
 
@@ -18,6 +18,9 @@
18
18
  - [Blog post introducing Flutterby](http://hmans.io/posts/2017/01/11/flutterby.html)
19
19
  - [New project template](https://github.com/hmans/flutterby/tree/master/lib/templates/new_project) (example code)
20
20
  - [Version History](https://github.com/hmans/flutterby/blob/master/CHANGES.md)
21
+ - [Roadmap](https://github.com/hmans/flutterby/projects/1)
22
+ - [Sites built with Flutterby](https://github.com/hmans/flutterby/wiki/Sites-built-with-Flutterby) (add yours!)
23
+
21
24
 
22
25
  ## Installation & Basic Usage
23
26
 
@@ -41,22 +44,6 @@ Flutterby comes with a local development server that will automatically pick up
41
44
  **Note**: by default, both the `build` and `serve` commands assume `./site/` to be the source directory and `./_build/` to be the export directory. Please refer to `flutterby help` to see how you can override these.
42
45
 
43
46
 
44
- ## Examples
45
-
46
- Please refer to the [Sites built with Flutterby](https://github.com/hmans/flutterby/wiki/Sites-built-with-Flutterby) page on the Flutterby Wiki for some examples.
47
-
48
-
49
- ## Roadmap
50
-
51
- Flutterby is young, but already quite functional. Here's a list of changes I'm intending to make in the near future -- if you want to work on any of these, let me know!
52
-
53
- - Performance! Right now, the source file for every node is read into RAM as a whole. Not a big problem when you're building a small site, but add some larger images, and you'll have one.
54
- - Change `flutterby serve` so it doesn't always regenerate the _entire_ site graph when a file is modified.
55
- - Extract filters (like Slim, Sass etc.) to separate gems, to make the core gem more light-weight.
56
- - Improve the template site (`flutterby new`).
57
- - Produce a fun screencast to explain what the heck is going on here!
58
- - Write even more tests!
59
-
60
47
 
61
48
  ## Notes
62
49
 
@@ -60,7 +60,7 @@ module Flutterby
60
60
  root.stage!
61
61
  say color("🌲 Read #{root.tree_size} nodes.", :green, :bold)
62
62
 
63
- say color("🌤 Serving your site on port #{options.port}. Enjoy!", :bold)
63
+ say color("🌤 Serving your Flutterby site on http://localhost:#{options.port} - enjoy! \\o/", :bold)
64
64
  server = Flutterby::Server.new(root, port: options.port)
65
65
  server.run!
66
66
  end
@@ -75,6 +75,7 @@ module Flutterby
75
75
 
76
76
  say color("🏗 Creating a new Flutterby project in #{path}...", :bold)
77
77
  directory("new_project", path)
78
+ chmod("bin/flutterby", 0755)
78
79
  in_root { bundle_install }
79
80
  end
80
81
 
@@ -2,7 +2,8 @@ require 'benchmark'
2
2
 
3
3
  module Flutterby
4
4
  class Node
5
- attr_accessor :name, :ext, :source, :body
5
+ attr_accessor :name, :ext, :source
6
+ attr_writer :body
6
7
  attr_reader :filters, :parent, :fs_path, :children, :paths
7
8
 
8
9
  def initialize(name, parent: nil, fs_path: nil, source: nil)
@@ -23,287 +24,278 @@ module Flutterby
23
24
  reload!
24
25
  end
25
26
 
26
- #
27
- # Children
28
- #
29
-
30
- def register_url!
31
- if file? && should_publish?
32
- root.paths[url] = self
27
+ concerning :Children do
28
+ def register_url!
29
+ if file? && should_publish?
30
+ root.paths[url] = self
31
+ end
33
32
  end
34
- end
35
33
 
36
- def find_child(name)
37
- if name.include?(".")
38
- @children.find { |c| c.full_name == name }
39
- else
40
- @children.find { |c| c.name == name }
41
- end
42
- end
43
-
44
- def tree_size
45
- children.inject(children.length) do |count, child|
46
- count + child.tree_size
34
+ def find_child(name)
35
+ if name.include?(".")
36
+ @children.find { |c| c.full_name == name }
37
+ else
38
+ @children.find { |c| c.name == name }
39
+ end
47
40
  end
48
- end
49
41
 
50
- def parent=(new_parent)
51
- if @parent
52
- @parent.children.delete(self)
42
+ def tree_size
43
+ children.inject(children.length) do |count, child|
44
+ count + child.tree_size
45
+ end
53
46
  end
54
47
 
55
- @parent = new_parent
56
-
57
- @parent.children << self
58
- end
59
-
60
- # Returns all children that will compile to a HTML page.
61
- #
62
- def pages
63
- children.select { |c| c.ext == "html" && c.should_publish? }
64
- end
65
-
66
- #
67
- # Path Algebra
68
- #
69
-
70
- def path
71
- parent ? ::File.join(parent.path, full_name) : full_name
72
- end
73
-
74
- def url
75
- ::File.join(parent ? parent.url : "/", full_name)
76
- end
77
-
78
- def full_fs_path(base:)
79
- ::File.expand_path(::File.join(base, full_name))
80
- end
48
+ def parent=(new_parent)
49
+ if @parent
50
+ @parent.children.delete(self)
51
+ end
81
52
 
53
+ @parent = new_parent
82
54
 
83
- #
84
- # Tree Walking
85
- #
55
+ @parent.children << self
56
+ end
86
57
 
87
- def root
88
- parent ? parent.root : self
58
+ # Returns all children that will compile to a HTML page.
59
+ #
60
+ def pages
61
+ children.select { |c| c.ext == "html" && c.should_publish? }
62
+ end
89
63
  end
90
64
 
91
- def root?
92
- root == self
93
- end
65
+ concerning :Paths do
66
+ def path
67
+ parent ? ::File.join(parent.path, full_name) : full_name
68
+ end
94
69
 
95
- def sibling(name)
96
- parent && parent.find(name)
97
- end
70
+ def url
71
+ ::File.join(parent ? parent.url : "/", full_name)
72
+ end
98
73
 
99
- def siblings
100
- parent && parent.children
74
+ def full_fs_path(base:)
75
+ ::File.expand_path(::File.join(base, full_name))
76
+ end
101
77
  end
102
78
 
103
- def find(path)
104
- return self if path.nil? || path.empty?
105
-
106
- # remove duplicate slashes
107
- path.gsub!(%r{/+}, "/")
108
79
 
109
- case path
110
- when %r{^\./?} then
111
- parent ? parent.find($') : root.find($')
112
- when %r{^/} then
113
- root.find($')
114
- when %r{^([^/]+)/?} then
115
- child = find_child($1)
116
- $'.empty? ? child : child.find($')
80
+ concerning :Tree do
81
+ def root
82
+ parent ? parent.root : self
117
83
  end
118
- end
119
84
 
120
- # Walk the tree up, invoking the passed block for every node
121
- # found on the way, passing the node as its only argument.
122
- #
123
- def walk_up(val = nil, &blk)
124
- val = blk.call(self, val)
125
- parent ? parent.walk_up(val, &blk) : val
126
- end
85
+ def root?
86
+ root == self
87
+ end
127
88
 
128
- # Walk the graph from the root to this node. Just like walk_up,
129
- # except the block will be called on higher level nodes first.
130
- #
131
- def walk_down(val = nil, &blk)
132
- val = parent ? parent.walk_up(val, &blk) : val
133
- blk.call(self, val)
134
- end
89
+ def sibling(name)
90
+ parent && parent.find(name)
91
+ end
135
92
 
136
- # Walk the entire tree, top to bottom.
137
- #
138
- def walk_tree(val = nil, &blk)
139
- val = blk.call(self, val)
140
- children.each do |child|
141
- val = child.walk_tree(val, &blk)
93
+ def siblings
94
+ parent && parent.children
142
95
  end
143
96
 
144
- val
145
- end
97
+ def find(path)
98
+ return self if path.nil? || path.empty?
146
99
 
147
- #
148
- # Reading from filesystem
149
- #
100
+ # remove duplicate slashes
101
+ path.gsub!(%r{/+}, "/")
150
102
 
151
- def reload!
152
- @body = nil
153
- @data = nil
154
- @children = []
155
- @paths = {}
103
+ case path
104
+ when %r{^\./?} then
105
+ parent ? parent.find($') : root.find($')
106
+ when %r{^/} then
107
+ root.find($')
108
+ when %r{^([^/]+)/?} then
109
+ child = find_child($1)
110
+ $'.empty? ? child : child.find($')
111
+ end
112
+ end
156
113
 
157
- load_from_filesystem! if @fs_path
158
- end
114
+ # Walk the tree up, invoking the passed block for every node
115
+ # found on the way, passing the node as its only argument.
116
+ #
117
+ def walk_up(val = nil, &blk)
118
+ val = blk.call(self, val)
119
+ parent ? parent.walk_up(val, &blk) : val
120
+ end
159
121
 
160
- def stage!
161
- # First of all, we want to make sure all nodes have their
162
- # available extensions loaded.
122
+ # Walk the graph from the root to this node. Just like walk_up,
123
+ # except the block will be called on higher level nodes first.
163
124
  #
164
- walk_tree do |node|
165
- node.load_extension! unless node.name == "_node"
125
+ def walk_down(val = nil, &blk)
126
+ val = parent ? parent.walk_up(val, &blk) : val
127
+ blk.call(self, val)
166
128
  end
167
129
 
168
- # Now do another pass, prerendering stuff where necessary,
169
- # extracting data, registering URLs to be exported, etc.
130
+ # Walk the entire tree, top to bottom.
170
131
  #
171
- walk_tree do |node|
172
- node.render_body! if node.should_prerender?
173
- node.register_url! if node.should_publish?
132
+ def walk_tree(val = nil, &blk)
133
+ val = blk.call(self, val)
134
+ children.each do |child|
135
+ val = child.walk_tree(val, &blk)
136
+ end
137
+
138
+ val
174
139
  end
175
140
  end
176
141
 
177
- def should_prerender?
178
- !folder? &&
179
- (["json", "yml", "yaml", "rb", "toml"] & filters).any?
180
- end
142
+ concerning :Reading do
143
+ def reload!
144
+ @body = nil
145
+ @data = nil
146
+ @children = []
147
+ @paths = {}
181
148
 
182
- def load_from_filesystem!
183
- if @fs_path
184
- if ::File.directory?(fs_path)
185
- Dir[::File.join(fs_path, "*")].each do |entry|
186
- name = ::File.basename(entry)
187
- Flutterby::Node.new(name, parent: self, fs_path: entry)
149
+ load_from_filesystem! if @fs_path
150
+ end
151
+
152
+ def load_from_filesystem!
153
+ if @fs_path
154
+ if ::File.directory?(fs_path)
155
+ Dir[::File.join(fs_path, "*")].each do |entry|
156
+ name = ::File.basename(entry)
157
+ Flutterby::Node.new(name, parent: self, fs_path: entry)
158
+ end
159
+ else
160
+ @source = ::File.read(fs_path)
188
161
  end
189
- else
190
- @source = ::File.read(fs_path)
191
162
  end
192
163
  end
193
164
  end
194
165
 
195
- def extract_data!
196
- @data ||= {}
197
-
198
- # Extract date from name
199
- if name =~ %r{^(\d\d\d\d\-\d\d?\-\d\d?)\-}
200
- @data['date'] = Date.parse($1)
166
+ concerning :Data do
167
+ def data
168
+ extract_data! if @data.nil?
169
+ @data
201
170
  end
202
171
 
203
- # Read remaining data from frontmatter. Data in frontmatter
204
- # will always have precedence!
205
- parse_frontmatter!
172
+ def extract_data!
173
+ @data ||= {}
206
174
 
207
- # Do some extra processing depending on extension
208
- meth = "read_#{ext}!"
209
- send(meth) if respond_to?(meth)
210
- end
175
+ # Extract date from name
176
+ if name =~ %r{^(\d\d\d\d\-\d\d?\-\d\d?)\-}
177
+ @data['date'] = Date.parse($1)
178
+ end
211
179
 
212
- def load_extension!
213
- if extension = sibling("_node.rb")
214
- instance_eval(extension.body)
180
+ # Read remaining data from frontmatter. Data in frontmatter
181
+ # will always have precedence!
182
+ parse_frontmatter!
183
+
184
+ # Do some extra processing depending on extension
185
+ meth = "read_#{ext}!"
186
+ send(meth) if respond_to?(meth)
215
187
  end
216
- end
217
188
 
218
- #
219
- # Rendering
220
- #
189
+ def parse_frontmatter!
190
+ @data || {}
221
191
 
222
- def view
223
- @view ||= View.for(self)
224
- end
192
+ if @source
193
+ # YAML Front Matter
194
+ if @source.sub!(/\A\-\-\-\n(.+)\n\-\-\-\n/m, "")
195
+ @data.merge! YAML.load($1)
196
+ end
225
197
 
226
- def render_body!
227
- time = Benchmark.realtime do
228
- Filters.apply!(self)
198
+ # TOML Front Matter
199
+ if @source.sub!(/\A\+\+\+\n(.+)\n\+\+\+\n/m, "")
200
+ @data.merge! TOML.parse($1)
201
+ end
202
+ end
229
203
  end
230
204
 
231
- logger.info "Rendered #{url} in #{sprintf "%.1f", time * 1000}ms"
232
- end
205
+ def read_json!
206
+ @data.merge!(JSON.parse(body))
207
+ end
233
208
 
234
- def body
235
- if @body.nil?
236
- data # make sure data is lazy-loaded
237
- render_body!
209
+ def read_yaml!
210
+ @data.merge!(YAML.load(body))
238
211
  end
239
212
 
240
- @body
241
- end
213
+ def read_yml!
214
+ read_yaml!
215
+ end
242
216
 
243
- def data
244
- extract_data! if @data.nil?
245
- @data
217
+ def read_toml!
218
+ @data.merge!(TOML.parse(body))
219
+ end
246
220
  end
247
221
 
248
- def render(opts = {})
249
- layout = opts[:layout]
250
- view.opts.merge!(opts)
251
- (layout && apply_layout?) ? apply_layout(body) : body
252
- end
222
+ concerning :Staging do
223
+ def stage!
224
+ # First of all, we want to make sure all nodes have their
225
+ # available extensions loaded.
226
+ #
227
+ walk_tree do |node|
228
+ node.load_extension! unless node.name == "_node"
229
+ end
253
230
 
254
- def apply_layout(input)
255
- walk_up(input) do |node, current|
256
- if layout = node.sibling("_layout")
257
- tilt = Flutterby::Filters.tilt(layout.ext, layout.source)
258
- tilt.render(view) { current }.html_safe
259
- else
260
- current
231
+ # Now do another pass, prerendering stuff where necessary,
232
+ # extracting data, registering URLs to be exported, etc.
233
+ #
234
+ walk_tree do |node|
235
+ node.render_body! if node.should_prerender?
236
+ node.register_url! if node.should_publish?
261
237
  end
262
238
  end
263
- end
264
239
 
265
- def apply_layout?
266
- page?
267
- end
240
+ def load_extension!
241
+ if extension = sibling("_node.rb")
242
+ instance_eval(extension.body)
243
+ end
244
+ end
268
245
 
246
+ def should_prerender?
247
+ !folder? &&
248
+ (["json", "yml", "yaml", "rb", "toml"] & filters).any?
249
+ end
250
+ end
269
251
 
270
252
 
253
+ concerning :Rendering do
254
+ def view
255
+ @view ||= View.for(self)
256
+ end
271
257
 
272
- #
273
- # Front Matter Parsing
274
- #
258
+ def render_body!
259
+ time = Benchmark.realtime do
260
+ Filters.apply!(self)
261
+ end
275
262
 
276
- def parse_frontmatter!
277
- @data || {}
263
+ logger.info "Rendered #{url} in #{sprintf "%.1f", time * 1000}ms"
264
+ end
278
265
 
279
- if @source
280
- # YAML Front Matter
281
- if @source.sub!(/\A\-\-\-\n(.+)\n\-\-\-\n/m, "")
282
- @data.merge! YAML.load($1)
266
+ def body
267
+ if @body.nil?
268
+ data # make sure data is lazy-loaded
269
+ render_body!
283
270
  end
284
271
 
285
- # TOML Front Matter
286
- if @source.sub!(/\A\+\+\+\n(.+)\n\+\+\+\n/m, "")
287
- @data.merge! TOML.parse($1)
272
+ @body
273
+ end
274
+
275
+ def render(opts = {})
276
+ layout = opts[:layout]
277
+ view.opts.merge!(opts)
278
+ (layout && apply_layout?) ? apply_layout(body) : body
279
+ end
280
+
281
+ def apply_layout(input)
282
+ walk_up(input) do |node, current|
283
+ if layout = node.sibling("_layout")
284
+ tilt = Flutterby::Filters.tilt(layout.ext, layout.source)
285
+ tilt.render(view) { current }.html_safe
286
+ else
287
+ current
288
+ end
288
289
  end
289
290
  end
290
- end
291
291
 
292
- def read_json!
293
- @data.merge!(JSON.parse(body))
292
+ def apply_layout?
293
+ page?
294
+ end
294
295
  end
295
296
 
296
- def read_yaml!
297
- @data.merge!(YAML.load(body))
298
- end
299
297
 
300
- def read_yml!
301
- read_yaml!
302
- end
303
298
 
304
- def read_toml!
305
- @data.merge!(TOML.parse(body))
306
- end
307
299
 
308
300
 
309
301
  #
@@ -1,3 +1,3 @@
1
1
  module Flutterby
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -35,6 +35,32 @@ module Flutterby
35
35
  node.siblings(*args)
36
36
  end
37
37
 
38
+ def tag(name, attributes)
39
+ ActiveSupport::SafeBuffer.new.tap do |output|
40
+ attributes_str = attributes.keys.sort.map do |k|
41
+ %{#{h k}="#{h attributes[k]}"}
42
+ end.join(" ")
43
+
44
+ opening_tag = "#{h name.downcase} #{attributes_str}".strip
45
+ output << "<#{opening_tag}>".html_safe
46
+ output << yield if block_given?
47
+ output << "</#{h name}>".html_safe
48
+ end
49
+ end
50
+
51
+ def link_to(text, target, attrs = {})
52
+ href = case target
53
+ when Flutterby::Node then target.url
54
+ else target.to_s
55
+ end
56
+
57
+ tag(:a, attrs.merge(href: href)) { text }
58
+ end
59
+
60
+ def debug(obj)
61
+ tag(:pre, class: "debug") { h obj.to_yaml }
62
+ end
63
+
38
64
  class << self
39
65
  # Factory method that returns a newly created view for the given node.
40
66
  # It also makes sure all available _view.rb extensions are loaded.
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  source "https://rubygems.org"
3
3
 
4
- gem "flutterby", "~> 0.3.0"
4
+ gem "flutterby", "~> <%= Flutterby::VERSION %>"
@@ -17,4 +17,4 @@ html
17
17
  = yield
18
18
 
19
19
  footer role="main"
20
- = config["site"]["description"]
20
+ == config["site"]["description"]
@@ -2,5 +2,4 @@ ul.post-list
2
2
  - for post in blog_posts
3
3
  li
4
4
  .post-meta = date_format post.date, "%B %e, %Y"
5
-
6
- a href=post.url = post.title
5
+ = link_to post.title, post
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: Welcome to Flutterby!
3
+ date: <%= Date.today.to_s %>
3
4
  ---
4
5
 
5
6
 
@@ -1,6 +1,6 @@
1
1
  h1 = config["site"]["title"]
2
2
 
3
- p This is my new website! <a href="/about.html">Find out more</a>.
3
+ p This is my new website! #{link_to "Find out more", "/about.html"}.
4
4
 
5
5
  h3 Latest Posts:
6
6
  == render("/blog/_list")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flutterby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hendrik Mans
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-15 00:00:00.000000000 Z
11
+ date: 2017-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -364,18 +364,18 @@ files:
364
364
  - lib/flutterby/version.rb
365
365
  - lib/flutterby/view.rb
366
366
  - lib/templates/new_project/.gitignore
367
- - lib/templates/new_project/Gemfile
367
+ - lib/templates/new_project/Gemfile.tt
368
368
  - lib/templates/new_project/README.md
369
369
  - lib/templates/new_project/bin/flutterby
370
370
  - lib/templates/new_project/site/_config.toml
371
371
  - lib/templates/new_project/site/_layout.slim
372
372
  - lib/templates/new_project/site/_view.rb
373
373
  - lib/templates/new_project/site/about.html.md
374
- - lib/templates/new_project/site/blog/2017-01-01-hello-world.html.md
375
374
  - lib/templates/new_project/site/blog/_layout.slim
376
375
  - lib/templates/new_project/site/blog/_list.html.slim
377
376
  - lib/templates/new_project/site/blog/_node.rb
378
377
  - lib/templates/new_project/site/blog/_view.rb
378
+ - lib/templates/new_project/site/blog/hello-world.html.md.tt
379
379
  - lib/templates/new_project/site/css/styles.css.scss
380
380
  - lib/templates/new_project/site/index.html.slim
381
381
  - lib/templates/new_project/site/js/app.js