zine 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +171 -0
- data/README.md +27 -8
- data/lib/zine.rb +37 -77
- data/lib/zine/cli.rb +16 -0
- data/lib/zine/page.rb +8 -3
- data/lib/zine/post.rb +17 -6
- data/lib/zine/posts_and_headlines.rb +202 -0
- data/lib/zine/server.rb +36 -4
- data/lib/zine/skeleton/source/assets/webicon-rss-m.png +0 -0
- data/lib/zine/skeleton/source/assets/webicon-rss.svg +18 -0
- data/lib/zine/skeleton/source/assets/webicon-twitter-m.png +0 -0
- data/lib/zine/skeleton/source/assets/webicon-twitter.svg +24 -0
- data/lib/zine/skeleton/source/screen.css +1 -1
- data/lib/zine/skeleton/source/styles/screen.scss +291 -0
- data/lib/zine/skeleton/source/templates/footer_partial.erb +16 -4
- data/lib/zine/skeleton/source/templates/home.erb +3 -1
- data/lib/zine/skeleton/zine.yaml +38 -25
- data/lib/zine/style.rb +19 -0
- data/lib/zine/tag.rb +1 -0
- data/lib/zine/upload.rb +161 -0
- data/lib/zine/version.rb +1 -1
- data/lib/zine/watcher.rb +88 -0
- metadata +115 -2
data/lib/zine/page.rb
CHANGED
@@ -12,7 +12,7 @@ module Zine
|
|
12
12
|
# A page on the site where the content comes from a file's markdown, and the
|
13
13
|
# destination's location mirrors its own
|
14
14
|
class Page
|
15
|
-
attr_reader :formatted_data
|
15
|
+
attr_reader :dest_path, :formatted_data, :source_file, :template_bundle
|
16
16
|
# the meta data, passed formatted to the template
|
17
17
|
class FormattedData
|
18
18
|
include ERB::Util
|
@@ -28,6 +28,7 @@ module Zine
|
|
28
28
|
@page = { date_rfc3339: front_matter['date'],
|
29
29
|
date_us: parse_date(front_matter['date']),
|
30
30
|
github_name: site_opt['options']['github_name'],
|
31
|
+
links_array: site_opt['links'],
|
31
32
|
num_items_on_home: site_opt['options']['num_items_on_home'],
|
32
33
|
site_author: site_opt['options']['site_author'],
|
33
34
|
site_description: site_opt['options']['site_description'],
|
@@ -59,8 +60,10 @@ module Zine
|
|
59
60
|
:pageDateUS)
|
60
61
|
|
61
62
|
def initialize(md_file_name, dest, templates, site_options)
|
63
|
+
@source_file = md_file_name
|
62
64
|
file_parts = File.open(md_file_name, 'r').read.split('---')
|
63
|
-
@formatted_data = FormattedData.new(parse_yaml(file_parts[1]
|
65
|
+
@formatted_data = FormattedData.new(parse_yaml(file_parts[1],
|
66
|
+
md_file_name),
|
64
67
|
site_options)
|
65
68
|
@dest_path = dest
|
66
69
|
@raw_text = file_parts[2]
|
@@ -71,6 +74,7 @@ module Zine
|
|
71
74
|
@header_partial = templates.header
|
72
75
|
@footer_partial = templates.footer
|
73
76
|
@template = templates.body
|
77
|
+
@template_bundle = templates
|
74
78
|
end
|
75
79
|
|
76
80
|
def parse_markdown
|
@@ -81,9 +85,10 @@ module Zine
|
|
81
85
|
smart_quotes: %w(apos apos quot quot),
|
82
86
|
syntax_highlighter: 'rouge'
|
83
87
|
).to_html
|
88
|
+
@raw_text = nil
|
84
89
|
end
|
85
90
|
|
86
|
-
def parse_yaml(text)
|
91
|
+
def parse_yaml(text, md_file_name)
|
87
92
|
YAML.safe_load text
|
88
93
|
rescue Psych::Exception
|
89
94
|
puts Rainbow("Could not parse front matter for: #{md_file_name}").red
|
data/lib/zine/post.rb
CHANGED
@@ -4,8 +4,10 @@ module Zine
|
|
4
4
|
# A post - content comes from the markdown, and the destination from the date
|
5
5
|
class Post < Page
|
6
6
|
def initialize(md_file_name, templates, site_options)
|
7
|
+
@source_file = md_file_name
|
7
8
|
file_parts = File.open(md_file_name, 'r').read.split('---')
|
8
|
-
@formatted_data = FormattedData.new(parse_yaml(file_parts[1]
|
9
|
+
@formatted_data = FormattedData.new(parse_yaml(file_parts[1],
|
10
|
+
md_file_name),
|
9
11
|
site_options)
|
10
12
|
@raw_text = file_parts[2]
|
11
13
|
init_templates(templates)
|
@@ -17,16 +19,25 @@ module Zine
|
|
17
19
|
def make_path_from_date(build_dir)
|
18
20
|
page_data = @formatted_data.page
|
19
21
|
date = DateTime.parse(page_data[:date_rfc3339])
|
20
|
-
dest_dir = File.join(build_dir,
|
21
|
-
|
22
|
-
|
23
|
-
FileUtils.mkdir_p dest_dir
|
22
|
+
@dest_dir = File.join(build_dir,
|
23
|
+
date.strftime('%Y'),
|
24
|
+
date.strftime('%-m'))
|
24
25
|
slg = Zine::Page.slug(page_data[:title]) + '.html'
|
25
|
-
@dest_path = File.join(dest_dir, slg)
|
26
|
+
@dest_path = File.join(@dest_dir, slg)
|
26
27
|
end
|
27
28
|
|
28
29
|
def process
|
30
|
+
FileUtils.mkdir_p @dest_dir
|
29
31
|
super
|
32
|
+
tag_and_uri_subprocess
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_without_writing
|
36
|
+
parse_markdown
|
37
|
+
tag_and_uri_subprocess
|
38
|
+
end
|
39
|
+
|
40
|
+
def tag_and_uri_subprocess
|
30
41
|
page_data = @formatted_data.page
|
31
42
|
file_path = rel_path_from_build_dir(@dest_path).to_s
|
32
43
|
@formatted_data.uri = URI.join(page_data[:site_URL], file_path).to_s
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'zine/data_page'
|
2
|
+
require 'zine/post'
|
3
|
+
require 'zine/tag'
|
4
|
+
|
5
|
+
module Zine
|
6
|
+
# The blog posts and their associate headline files (the home page, an
|
7
|
+
# articles index, and RSS feed)
|
8
|
+
class PostsAndHeadlines
|
9
|
+
def initialize(site, options)
|
10
|
+
@options = options
|
11
|
+
@post_array = []
|
12
|
+
@site = site
|
13
|
+
@tags_by_post = []
|
14
|
+
dir = @options['directories']
|
15
|
+
@guard = Zine::Watcher.new self, dir['build'], dir['source']
|
16
|
+
@guard.start
|
17
|
+
read_post_markdown_files
|
18
|
+
sort_posts_by_date
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_page_from_path(file_path)
|
22
|
+
post_to_rebuild = @post_array.detect do |post|
|
23
|
+
File.expand_path(post.source_file) == file_path
|
24
|
+
end
|
25
|
+
index = @post_array.find_index post_to_rebuild
|
26
|
+
{ post: post_to_rebuild, index: index }
|
27
|
+
end
|
28
|
+
|
29
|
+
# The headlines pages - the home page, an articles index, and RSS feed
|
30
|
+
def headline_pages
|
31
|
+
dir = @options['directories']['build']
|
32
|
+
options = @options['options']
|
33
|
+
templates = @options['templates']
|
34
|
+
[{ build_dir: dir, name: 'articles', number: @post_array.size,
|
35
|
+
suffix: '.html', template_name: templates['articles'],
|
36
|
+
title: 'Articles' },
|
37
|
+
{ build_dir: dir, name: 'index',
|
38
|
+
number: options['num_items_on_home'], suffix: '.html',
|
39
|
+
template_name: templates['home'], title: 'Home' },
|
40
|
+
{ build_dir: dir, name: 'rss',
|
41
|
+
number: options['number_items_in_RSS'], suffix: '.xml',
|
42
|
+
template_name: templates['rss'], title: '' }]
|
43
|
+
end
|
44
|
+
|
45
|
+
def one_new_post(source_file)
|
46
|
+
post_name = @options['templates']['post']
|
47
|
+
@post_array << Zine::Post.new(source_file,
|
48
|
+
@site.make_template_bundle(post_name),
|
49
|
+
@options)
|
50
|
+
@tags_by_post << @post_array.last.process
|
51
|
+
# TODO: may need to reorder posts by date, and therefor redo tags
|
52
|
+
write_tags_and_headlines
|
53
|
+
end
|
54
|
+
|
55
|
+
# get build file from post or location, delete build, remove form post_array
|
56
|
+
def preview_delete(file_path)
|
57
|
+
page = find_page_from_path file_path
|
58
|
+
if page[:index].nil?
|
59
|
+
directories = @options['directories']
|
60
|
+
full = Pathname(file_path)
|
61
|
+
relative = full.relative_path_from(
|
62
|
+
Pathname(File.absolute_path(directories['source']))
|
63
|
+
)
|
64
|
+
relative_path = File.dirname(relative)
|
65
|
+
file = File.basename(relative, '.md') + '.html'
|
66
|
+
File.delete(File.join(directories['build'], relative_path, file))
|
67
|
+
else
|
68
|
+
File.delete(page[:post].dest_path)
|
69
|
+
@post_array.delete_at(page[:index])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def preview_rebuild(file_path)
|
74
|
+
page = find_page_from_path file_path
|
75
|
+
if page[:index].nil?
|
76
|
+
if File.dirname(file_path) ==
|
77
|
+
File.absolute_path(@options['directories']['posts'])
|
78
|
+
one_new_post file_path
|
79
|
+
else
|
80
|
+
rebuild_page file_path
|
81
|
+
end
|
82
|
+
else
|
83
|
+
rebuild_post page[:post], page[:index]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# the build folder equivalent of a non Markdown file in the source tree
|
88
|
+
# TODO: move from posts & headlines
|
89
|
+
def preview_relative_equivalent(file)
|
90
|
+
directories = @options['directories']
|
91
|
+
source_dir = Pathname(File.absolute_path(directories['source']))
|
92
|
+
build_dir = Pathname(File.absolute_path(directories['build']))
|
93
|
+
file_dir = Pathname(File.dirname(file))
|
94
|
+
File.join build_dir, file_dir.relative_path_from(source_dir)
|
95
|
+
end
|
96
|
+
|
97
|
+
# copy a non Markdown file, TODO: move form posts & headlines
|
98
|
+
def preview_straight_copy(file)
|
99
|
+
FileUtils.cp(file, preview_relative_equivalent(file))
|
100
|
+
end
|
101
|
+
|
102
|
+
# delete a non Markdown file, TODO: move form posts & headlines
|
103
|
+
def preview_straight_delete(file)
|
104
|
+
FileUtils.rm(File.join(
|
105
|
+
preview_relative_equivalent(file), File.basename(file)
|
106
|
+
))
|
107
|
+
end
|
108
|
+
|
109
|
+
# rebuild a page that's not a post - doesn't create the file structure for a
|
110
|
+
# new file with new parent folders
|
111
|
+
def rebuild_page(file)
|
112
|
+
@site.write_markdown(@options['templates']['default'],
|
113
|
+
File.expand_path(@options['directories']['source']),
|
114
|
+
file)
|
115
|
+
end
|
116
|
+
|
117
|
+
# inserts the new post into the @post_array, builds the file, calls
|
118
|
+
# write_tags_and_headlines to rewrites the headline pages & tags
|
119
|
+
# RSS & home page will be redundant re-builds if not a recent page
|
120
|
+
def rebuild_post(post, index)
|
121
|
+
@post_array[index] = Zine::Post.new post.source_file,
|
122
|
+
post.template_bundle, @options
|
123
|
+
@tags_by_post[index] = @post_array[index].process
|
124
|
+
write_tags_and_headlines
|
125
|
+
# TODO: may need to reorder posts by date... means re-doing tags
|
126
|
+
end
|
127
|
+
|
128
|
+
# Read markdown files in the posts folder into an array of Posts
|
129
|
+
def read_post_markdown_files
|
130
|
+
file_name_array = Dir[File.join(@options['directories']['posts'], '*.md')]
|
131
|
+
post_name = @options['templates']['post']
|
132
|
+
file_name_array.each do |file|
|
133
|
+
@post_array << Zine::Post.new(file,
|
134
|
+
@site.make_template_bundle(post_name),
|
135
|
+
@options)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Sort the Posts array into date order, newest first
|
140
|
+
def sort_posts_by_date
|
141
|
+
@post_array.sort_by! do |post|
|
142
|
+
post.formatted_data.page[:date_rfc3339]
|
143
|
+
end.reverse!
|
144
|
+
# TODO: .freeze -- currently modified during preview
|
145
|
+
end
|
146
|
+
|
147
|
+
# Process each of the headlines pages
|
148
|
+
def wrangle_headlines
|
149
|
+
headline_pages.each do |page|
|
150
|
+
write_headline page
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Write out the Posts, calls write_tags_and_headlines
|
155
|
+
def write
|
156
|
+
@tags_by_post = []
|
157
|
+
@post_array.each do |post|
|
158
|
+
@tags_by_post << post.process
|
159
|
+
end
|
160
|
+
write_tags_and_headlines
|
161
|
+
|
162
|
+
# end point
|
163
|
+
{ posts: @post_array, guard: @guard }
|
164
|
+
end
|
165
|
+
|
166
|
+
# Generate data without writing files (for incremnetal builds & uploads)
|
167
|
+
def writeless
|
168
|
+
@tags_by_post = []
|
169
|
+
@post_array.each do |post|
|
170
|
+
@tags_by_post << post.process_without_writing
|
171
|
+
end
|
172
|
+
|
173
|
+
# end point
|
174
|
+
{ posts: @post_array, guard: @guard }
|
175
|
+
end
|
176
|
+
|
177
|
+
# Pass headline data to the DataPage class to write the files
|
178
|
+
def write_headline(page)
|
179
|
+
data = page
|
180
|
+
data[:post_array] = []
|
181
|
+
@post_array.first(page[:number]).each do |post|
|
182
|
+
post_data = post.formatted_data
|
183
|
+
data[:post_array] << { page: post_data.page, html: post_data.html,
|
184
|
+
uri: post_data.uri }
|
185
|
+
end
|
186
|
+
data_page = DataPage.new(data,
|
187
|
+
@site.make_template_bundle(data[:template_name]),
|
188
|
+
@options, data[:suffix])
|
189
|
+
data_page.write
|
190
|
+
end
|
191
|
+
|
192
|
+
# Write out the tags and headline files
|
193
|
+
def write_tags_and_headlines
|
194
|
+
tag_name = @options['templates']['tag']
|
195
|
+
tag_index_name = @options['templates']['tag_index']
|
196
|
+
tags = Zine::Tag.new @tags_by_post, @site.make_template_bundle(tag_name),
|
197
|
+
@site.make_template_bundle(tag_index_name), @options
|
198
|
+
tags.write_tags
|
199
|
+
wrangle_headlines
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
data/lib/zine/server.rb
CHANGED
@@ -1,18 +1,25 @@
|
|
1
|
+
require 'highline'
|
1
2
|
require 'rainbow'
|
2
3
|
require 'rack'
|
3
4
|
require 'thin'
|
5
|
+
require 'zine/upload'
|
6
|
+
require 'zine/watcher'
|
4
7
|
|
5
8
|
module Zine
|
6
9
|
# Local preview web server
|
7
10
|
class Server
|
8
|
-
def initialize(
|
11
|
+
# def initialize(_posts, rel_path_build, _rel_path_source, upload_options,
|
12
|
+
def initialize(rel_path_build, upload_options, delete_array, upload_array)
|
13
|
+
@delete_array = delete_array
|
14
|
+
@upload_array = upload_array
|
15
|
+
root = File.absolute_path(rel_path_build)
|
9
16
|
motd
|
10
|
-
|
17
|
+
|
18
|
+
@thin = Thin::Server.new('127.0.0.1', 8080) do
|
11
19
|
use Rack::Static,
|
12
20
|
urls: ['/'],
|
13
21
|
index: 'index.html',
|
14
22
|
root: root
|
15
|
-
|
16
23
|
now = Time.now
|
17
24
|
a_long_time = 100**4
|
18
25
|
run lambda { |_env|
|
@@ -26,9 +33,34 @@ module Zine
|
|
26
33
|
'Pragma' => 'no-cache',
|
27
34
|
'Expires' => now - a_long_time
|
28
35
|
},
|
29
|
-
File.open(File.join(root, 'index.html'), File::RDONLY)]
|
36
|
+
[File.open(File.join(root, 'index.html'), File::RDONLY)]]
|
30
37
|
}
|
31
38
|
end
|
39
|
+
@thin.start
|
40
|
+
|
41
|
+
return if upload_options['method'] == 'none' ||
|
42
|
+
(@delete_array.empty? && @upload_array.empty?)
|
43
|
+
cli = HighLine.new
|
44
|
+
answer = cli.ask('Upload files? (Y/n)') { |q| q.default = 'Y' }
|
45
|
+
return if answer != 'Y'
|
46
|
+
file_upload rel_path_build, upload_options
|
47
|
+
end
|
48
|
+
|
49
|
+
# deploy
|
50
|
+
def file_upload(rel_path_build, upload_options)
|
51
|
+
puts Rainbow('Connecting...').green
|
52
|
+
begin
|
53
|
+
upload = Zine::Upload.new rel_path_build, upload_options,
|
54
|
+
# @guard.delete_array, @guard.upload_array
|
55
|
+
@delete_array, @upload_array
|
56
|
+
upload.delete
|
57
|
+
upload.deploy
|
58
|
+
rescue Errno::ENETUNREACH
|
59
|
+
puts Rainbow("Unable to connect to #{upload_options['host']}").red
|
60
|
+
rescue Net::SSH::AuthenticationFailed
|
61
|
+
puts Rainbow("Authentication failed for #{upload_options['host']}").red
|
62
|
+
puts 'Check your credential file, and maybe run ssh-add?'
|
63
|
+
end
|
32
64
|
end
|
33
65
|
|
34
66
|
def motd
|
Binary file
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3
|
+
<svg version="1.1" id="Icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve">
|
4
|
+
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="23.9995" y1="0" x2="23.9995" y2="48.0005">
|
5
|
+
<stop offset="0" style="stop-color:#F2A833"/>
|
6
|
+
<stop offset="1" style="stop-color:#E8621D"/>
|
7
|
+
</linearGradient>
|
8
|
+
<path fill-rule="evenodd" clip-rule="evenodd" fill="url(#SVGID_1_)" d="M48,42c0,3.313-2.687,6-6,6H6c-3.313,0-6-2.687-6-6V6
|
9
|
+
c0-3.313,2.687-6,6-6h36c3.313,0,6,2.687,6,6V42z"/>
|
10
|
+
<path fill="#E8621D" d="M10.016,8.494c0,0,27.276-1.343,29.426,27.41h-5.509c0,0,1.076-20.959-23.917-22.841V8.494z"/>
|
11
|
+
<path fill="#E8621D" d="M10.016,18.034c0,0,15.99-0.538,19.08,17.869h-5.508c0,0-0.671-10.883-13.572-13.302V18.034z"/>
|
12
|
+
<path fill="#E8621D" d="M13.01,30.021c1.928,0,3.494,1.563,3.494,3.494c0,1.928-1.566,3.493-3.494,3.493
|
13
|
+
c-1.93,0-3.494-1.564-3.494-3.493C9.516,31.585,11.08,30.021,13.01,30.021z"/>
|
14
|
+
<path fill="#FFFFFF" d="M10.016,9.597c0,0,27.276-1.343,29.426,27.41h-5.509c0,0,1.076-20.96-23.917-22.842V9.597z"/>
|
15
|
+
<path fill="#FFFFFF" d="M10.016,19.138c0,0,15.99-0.539,19.08,17.869h-5.508c0,0-0.671-10.882-13.572-13.304V19.138z"/>
|
16
|
+
<path fill="#FFFFFF" d="M13.01,31.125c1.928,0,3.494,1.562,3.494,3.494c0,1.928-1.566,3.493-3.494,3.493
|
17
|
+
c-1.93,0-3.494-1.564-3.494-3.493C9.516,32.688,11.08,31.125,13.01,31.125z"/>
|
18
|
+
</svg>
|
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3
|
+
<svg version="1.1" id="Icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve">
|
4
|
+
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="23.9995" y1="0" x2="23.9995" y2="48.0005">
|
5
|
+
<stop offset="0" style="stop-color:#4BD0EF"/>
|
6
|
+
<stop offset="1" style="stop-color:#29AAE1"/>
|
7
|
+
</linearGradient>
|
8
|
+
<path fill-rule="evenodd" clip-rule="evenodd" fill="url(#SVGID_1_)" d="M48,42c0,3.313-2.687,6-6,6H6c-3.313,0-6-2.687-6-6V6
|
9
|
+
c0-3.313,2.687-6,6-6h36c3.313,0,6,2.687,6,6V42z"/>
|
10
|
+
<path fill="#29AAE1" d="M40.231,13.413c-1.12,0.497-2.323,0.833-3.588,0.984c1.291-0.774,2.28-1.998,2.747-3.457
|
11
|
+
c-1.206,0.716-2.543,1.236-3.968,1.516c-1.139-1.214-2.763-1.972-4.56-1.972c-3.449,0-6.246,2.796-6.246,6.247
|
12
|
+
c0,0.49,0.055,0.966,0.161,1.424c-5.192-0.261-9.795-2.749-12.876-6.528c-0.538,0.923-0.846,1.996-0.846,3.141
|
13
|
+
c0,2.167,1.103,4.08,2.779,5.199c-1.024-0.032-1.987-0.313-2.83-0.781c0,0.026,0,0.053,0,0.079c0,3.026,2.153,5.551,5.011,6.125
|
14
|
+
c-0.525,0.143-1.076,0.219-1.646,0.219c-0.403,0-0.794-0.038-1.176-0.11c0.795,2.48,3.102,4.287,5.835,4.338
|
15
|
+
c-2.138,1.675-4.832,2.675-7.758,2.675c-0.504,0-1.002-0.03-1.491-0.089c2.765,1.773,6.048,2.808,9.576,2.808
|
16
|
+
c11.49,0,17.774-9.519,17.774-17.774c0-0.271-0.006-0.54-0.019-0.809C38.334,15.766,39.394,14.666,40.231,13.413z"/>
|
17
|
+
<path fill="#FFFFFF" d="M40.231,14.739c-1.12,0.497-2.323,0.833-3.588,0.984c1.291-0.773,2.28-1.998,2.747-3.456
|
18
|
+
c-1.206,0.716-2.543,1.236-3.968,1.516c-1.139-1.214-2.763-1.972-4.56-1.972c-3.449,0-6.246,2.796-6.246,6.247
|
19
|
+
c0,0.489,0.055,0.966,0.161,1.424c-5.192-0.261-9.795-2.748-12.876-6.527c-0.538,0.923-0.846,1.996-0.846,3.141
|
20
|
+
c0,2.167,1.103,4.079,2.779,5.199c-1.024-0.032-1.987-0.313-2.83-0.781c0,0.026,0,0.052,0,0.079c0,3.027,2.153,5.551,5.011,6.125
|
21
|
+
c-0.525,0.144-1.076,0.219-1.646,0.219c-0.403,0-0.794-0.038-1.176-0.11c0.795,2.481,3.102,4.287,5.835,4.338
|
22
|
+
c-2.138,1.676-4.832,2.675-7.758,2.675c-0.504,0-1.002-0.03-1.491-0.089c2.765,1.773,6.048,2.808,9.576,2.808
|
23
|
+
c11.49,0,17.774-9.519,17.774-17.774c0-0.271-0.006-0.54-0.019-0.808C38.334,17.092,39.394,15.992,40.231,14.739z"/>
|
24
|
+
</svg>
|
@@ -1 +1 @@
|
|
1
|
-
*{margin:0;padding:0}html,body{height:100%}body{background-color:#fff;font-family:GillSansRegular,
|
1
|
+
*{margin:0;padding:0}html,body{height:100%}body{background-color:#fff;font-family:GillSansRegular,"Gill Sans MT","Gill Sans","Century Gothic",Calibri,"Trebuchet MS",sans-serif;line-height:1.618;color:#333;text-align:center;font-weight:300}#skiptocontent{height:1px;width:1px;position:absolute;overflow:hidden;top:-10px}h1,h2,h3,h4,h5,h6{color:#333;letter-spacing:0.1em}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:#414f7c;text-decoration:none}h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover,h6 a:hover{color:#212721}h1{font-weight:300;font-size:2.618em;margin:1.809em 0 0.809em}h2{font-weight:300;font-size:1.618em;margin:1.809em 0 0.809em}h3,h4,h5,h6{font-weight:400;font-size:1em;margin:1.809em 0 0.809em}p,li{margin:1em 0}ul{margin:0}a{color:#414f7c}a:hover{color:#212721}section{margin-bottom:1.618em}section>section{margin-bottom:3.236em}body>header{width:43em;text-align:center;margin:0 auto 0}body>header a{text-decoration:none;margin-left:0.5em;margin-right:0.5em}body>header,body>main,body>footer{display:block}body>header a{color:#414f7c}body>header a:hover{color:#212721}body>header a.extra{color:#414f7c;margin-left:1em}body>header a.extra:hover{color:#212721}body>header nav ul li{display:inline;list-style:none}.button{width:30px;height:30px;display:inline-block;background-size:100%;text-indent:-999em;text-align:left;margin:20px}.twitter{background:url("/assets/webicon-twitter-m.png");background-image:url("/assets/webicon-twitter.svg"),none}.rss{background:url("/assets/webicon-rss-m.png");background-image:url("/assets/webicon-rss.svg"),none}main{text-align:left;width:43em;margin:3em auto 2em}main li{margin-left:2.618em}.meta{color:#667}footer{width:43em;color:#667;border-top:4px solid #ddd;margin:3em auto 2em;overflow:hidden}footer .column{float:left;width:33%;text-align:left}footer .column ul{list-style:none}footer .column a,.tags a{color:#414f7c;text-decoration:none}footer .column a:hover,.tags a:hover{color:#212721;text-decoration:none}.tags ul li{list-style:none;display:inline;font-variant:small-caps;font-size:1.2em}.archive a{text-decoration:none}ul.archive,ul.archive ul{margin-left:0}ul.archive li,ul.archive ul li{list-style:none;margin-left:0}.post pre{border:1px solid #ddd;background-color:#fff;padding:0 .4em}p.date{color:#667}pre{background-color:#eee;padding:1em;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}code{font-family:Consolas,Menlo,Monaco,"Lucida Console","Courier New",monospace,serif;font-size:0.8em}blockquote{margin:2em 2em 2em 1em;padding:0 .75em 0 1.25em;border-left:2px solid #ddd;border-right:0px solid #ddd}@media all and (max-width: 736px){body>header,main,footer{width:86%;margin:0 auto 0;padding:12px 24px 12px}p{margin-bottom:2em}.button{width:50px;height:50px;margin:20px}footer .column{width:100%}}
|
@@ -0,0 +1,291 @@
|
|
1
|
+
$blue: #414f7c;
|
2
|
+
$darkGrey: #333;
|
3
|
+
$mediumGrey: #667;
|
4
|
+
$lightGrey: #ddd;
|
5
|
+
$black: #212721;
|
6
|
+
$white: #fff;
|
7
|
+
$offWhite: #eee;
|
8
|
+
|
9
|
+
$backgroundColour: $white;
|
10
|
+
$codeBackgroundColour: $offWhite;
|
11
|
+
$headingColour: $darkGrey;
|
12
|
+
$textColour: $darkGrey;
|
13
|
+
$linkColour: $blue;
|
14
|
+
$hoverColour: $black;
|
15
|
+
$metaAndFooterColour: $mediumGrey;
|
16
|
+
$borderColour: $lightGrey;
|
17
|
+
|
18
|
+
$desktopWidth: 43em;
|
19
|
+
$lightWeight: 300;
|
20
|
+
$heavyWeight: 400;
|
21
|
+
|
22
|
+
$regularFont: GillSansRegular, 'Gill Sans MT', 'Gill Sans', 'Century Gothic', Calibri, 'Trebuchet MS', sans-serif;
|
23
|
+
$monoFont: Consolas, Menlo, Monaco, 'Lucida Console', 'Courier New', monospace, serif;
|
24
|
+
|
25
|
+
* {
|
26
|
+
margin: 0;
|
27
|
+
padding: 0;
|
28
|
+
}
|
29
|
+
|
30
|
+
html, body { height: 100%; }
|
31
|
+
|
32
|
+
body {
|
33
|
+
background-color: $backgroundColour;
|
34
|
+
font-family: $regularFont;
|
35
|
+
line-height: 1.618;
|
36
|
+
color: $textColour;
|
37
|
+
text-align: center;
|
38
|
+
font-weight: $lightWeight;
|
39
|
+
}
|
40
|
+
|
41
|
+
#skiptocontent {
|
42
|
+
height: 1px;
|
43
|
+
width: 1px;
|
44
|
+
position: absolute;
|
45
|
+
overflow: hidden;
|
46
|
+
top: -10px;
|
47
|
+
}
|
48
|
+
|
49
|
+
h1,h2,h3,h4,h5,h6 {
|
50
|
+
color: $headingColour;
|
51
|
+
letter-spacing: 0.1em;
|
52
|
+
a {
|
53
|
+
color: $linkColour;
|
54
|
+
text-decoration: none;
|
55
|
+
}
|
56
|
+
a:hover {
|
57
|
+
color: $hoverColour;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
h1 {
|
62
|
+
font-weight: $lightWeight;
|
63
|
+
font-size: 2.618em;
|
64
|
+
margin: 1.809em 0 0.809em;
|
65
|
+
}
|
66
|
+
|
67
|
+
h2 {
|
68
|
+
font-weight: $lightWeight;
|
69
|
+
font-size: 1.618em;
|
70
|
+
margin: 1.809em 0 0.809em;
|
71
|
+
}
|
72
|
+
|
73
|
+
h3, h4, h5, h6 {
|
74
|
+
font-weight: $heavyWeight;
|
75
|
+
font-size: 1em;
|
76
|
+
margin: 1.809em 0 0.809em;
|
77
|
+
}
|
78
|
+
|
79
|
+
p, li {
|
80
|
+
margin: 1em 0;
|
81
|
+
}
|
82
|
+
|
83
|
+
ul {
|
84
|
+
margin: 0;
|
85
|
+
}
|
86
|
+
|
87
|
+
a { color:$linkColour; }
|
88
|
+
a:hover { color: $hoverColour; }
|
89
|
+
|
90
|
+
/* Home */
|
91
|
+
section {
|
92
|
+
margin-bottom: 1.618em;
|
93
|
+
}
|
94
|
+
|
95
|
+
section > section {
|
96
|
+
margin-bottom: 3.236em;
|
97
|
+
}
|
98
|
+
|
99
|
+
/* Site */
|
100
|
+
body > header {
|
101
|
+
width: $desktopWidth;
|
102
|
+
text-align: center;
|
103
|
+
margin: 0 auto 0;
|
104
|
+
}
|
105
|
+
|
106
|
+
body > header a {
|
107
|
+
text-decoration: none;
|
108
|
+
margin-left: 0.5em;
|
109
|
+
margin-right: 0.5em;
|
110
|
+
}
|
111
|
+
|
112
|
+
body > header, body > main, body > footer {
|
113
|
+
display: block;
|
114
|
+
}
|
115
|
+
|
116
|
+
body > header a {
|
117
|
+
color: $linkColour;
|
118
|
+
}
|
119
|
+
|
120
|
+
body > header a:hover {
|
121
|
+
color: $hoverColour;
|
122
|
+
}
|
123
|
+
|
124
|
+
body > header a.extra {
|
125
|
+
color: $linkColour;
|
126
|
+
margin-left: 1em;
|
127
|
+
}
|
128
|
+
|
129
|
+
body > header a.extra:hover {
|
130
|
+
color: $hoverColour;
|
131
|
+
}
|
132
|
+
|
133
|
+
body > header nav ul li {
|
134
|
+
display: inline;
|
135
|
+
list-style: none;
|
136
|
+
}
|
137
|
+
|
138
|
+
.button {
|
139
|
+
width: 30px;
|
140
|
+
height: 30px;
|
141
|
+
display: inline-block;
|
142
|
+
background-size: 100%;
|
143
|
+
text-indent: -999em;
|
144
|
+
text-align: left;
|
145
|
+
margin: 20px;
|
146
|
+
}
|
147
|
+
|
148
|
+
.twitter {
|
149
|
+
background: url('/assets/webicon-twitter-m.png');
|
150
|
+
background-image: url('/assets/webicon-twitter.svg'), none;
|
151
|
+
}
|
152
|
+
|
153
|
+
.rss {
|
154
|
+
background: url('/assets/webicon-rss-m.png');
|
155
|
+
background-image: url('/assets/webicon-rss.svg'), none;
|
156
|
+
}
|
157
|
+
|
158
|
+
main {
|
159
|
+
text-align: left;
|
160
|
+
width: $desktopWidth;
|
161
|
+
margin: 3em auto 2em;
|
162
|
+
}
|
163
|
+
|
164
|
+
main li {
|
165
|
+
margin-left: 2.618em;
|
166
|
+
}
|
167
|
+
|
168
|
+
.meta {
|
169
|
+
color: $metaAndFooterColour;
|
170
|
+
}
|
171
|
+
|
172
|
+
footer {
|
173
|
+
width: $desktopWidth;
|
174
|
+
color: $metaAndFooterColour;
|
175
|
+
border-top: 4px solid $borderColour;
|
176
|
+
margin: 3em auto 2em;
|
177
|
+
overflow: hidden;
|
178
|
+
}
|
179
|
+
|
180
|
+
footer .column {
|
181
|
+
float: left;
|
182
|
+
width: 33%;
|
183
|
+
text-align: left;
|
184
|
+
}
|
185
|
+
|
186
|
+
footer .column ul { list-style: none; }
|
187
|
+
footer .column a, .tags a { color:$linkColour; text-decoration: none; }
|
188
|
+
footer .column a:hover, .tags a:hover { color:$hoverColour; text-decoration: none; }
|
189
|
+
|
190
|
+
.tags ul li {
|
191
|
+
list-style: none;
|
192
|
+
display: inline;
|
193
|
+
font-variant: small-caps;
|
194
|
+
font-size:1.2em;
|
195
|
+
}
|
196
|
+
|
197
|
+
.archive a {
|
198
|
+
text-decoration: none;
|
199
|
+
}
|
200
|
+
|
201
|
+
ul.archive, ul.archive ul {
|
202
|
+
margin-left: 0;
|
203
|
+
}
|
204
|
+
|
205
|
+
ul.archive li, ul.archive ul li {
|
206
|
+
list-style: none;
|
207
|
+
margin-left: 0;
|
208
|
+
}
|
209
|
+
|
210
|
+
/*footer .rss {
|
211
|
+
margin-top: 1.1em;
|
212
|
+
margin-right: -.2em;
|
213
|
+
float: right;
|
214
|
+
}
|
215
|
+
|
216
|
+
footer .rss img {
|
217
|
+
border: 0;
|
218
|
+
}*/
|
219
|
+
|
220
|
+
/* Posts */
|
221
|
+
|
222
|
+
/* standard */
|
223
|
+
.post pre {
|
224
|
+
border: 1px solid $borderColour;
|
225
|
+
background-color: $backgroundColour;
|
226
|
+
padding: 0 .4em;
|
227
|
+
}
|
228
|
+
|
229
|
+
|
230
|
+
p.date {
|
231
|
+
color: $mediumGrey;
|
232
|
+
}
|
233
|
+
|
234
|
+
/*.post ul, .post ol {
|
235
|
+
margin-left: 1.35em;
|
236
|
+
}*/
|
237
|
+
|
238
|
+
pre {
|
239
|
+
background-color: $codeBackgroundColour;
|
240
|
+
padding: 1em;
|
241
|
+
white-space: pre-wrap;
|
242
|
+
/* why necessary */
|
243
|
+
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
244
|
+
white-space: -pre-wrap; /* Opera 4-6 */
|
245
|
+
white-space: -o-pre-wrap; /* Opera 7 */
|
246
|
+
word-wrap: break-word;
|
247
|
+
}
|
248
|
+
|
249
|
+
code {
|
250
|
+
font-family: $monoFont;
|
251
|
+
font-size: 0.8em;
|
252
|
+
}
|
253
|
+
|
254
|
+
/* terminal
|
255
|
+
.post pre.terminal {
|
256
|
+
border: 1px solid $borderColour;
|
257
|
+
background-color: $codeBackgroundColour;
|
258
|
+
color: $textColour;
|
259
|
+
}
|
260
|
+
|
261
|
+
.post pre.terminal code {
|
262
|
+
background-color: $codeBackgroundColour;
|
263
|
+
}*/
|
264
|
+
|
265
|
+
/* quotes */
|
266
|
+
blockquote {
|
267
|
+
margin: 2em 2em 2em 1em;
|
268
|
+
padding: 0 .75em 0 1.25em;
|
269
|
+
border-left: 2px solid $borderColour;
|
270
|
+
border-right: 0px solid $borderColour;
|
271
|
+
}
|
272
|
+
|
273
|
+
@media all and (max-width: 736px) {
|
274
|
+
/* was max-device-width: 1242px */
|
275
|
+
body > header, main, footer {
|
276
|
+
width:86%;
|
277
|
+
margin: 0 auto 0;
|
278
|
+
padding: 12px 24px 12px;
|
279
|
+
}
|
280
|
+
p {
|
281
|
+
margin-bottom:2em;
|
282
|
+
}
|
283
|
+
.button {
|
284
|
+
width: 50px;
|
285
|
+
height: 50px;
|
286
|
+
margin: 20px;
|
287
|
+
}
|
288
|
+
footer .column {
|
289
|
+
width: 100%;
|
290
|
+
}
|
291
|
+
}
|