trahald 0.0.4 → 0.0.5
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.
- data/.gitignore +2 -1
- data/.travis.yml +16 -0
- data/Gemfile.lock +58 -0
- data/README.md +29 -8
- data/lib/public/lib/markdown/markdown.js +1616 -0
- data/lib/public/lib/masonry/jquery.masonry.min.js +10 -0
- data/lib/public/lib/reveal/markdown.js +151 -0
- data/lib/public/lib/reveal/showdown.js +62 -0
- data/lib/public/lib/reveal/theme/beige.css +142 -0
- data/lib/public/lib/reveal/theme/default.css +150 -0
- data/lib/public/lib/reveal/theme/moon.css +142 -0
- data/lib/public/lib/reveal/theme/night.css +130 -0
- data/lib/public/lib/reveal/theme/serif.css +130 -0
- data/lib/public/lib/reveal/theme/simple.css +132 -0
- data/lib/public/lib/reveal/theme/sky.css +136 -0
- data/lib/public/lib/reveal/theme/solarized.css +142 -0
- data/lib/trahald.rb +90 -11
- data/lib/trahald/.redis-client.rb.swn +0 -0
- data/lib/trahald/article.rb +34 -0
- data/lib/trahald/backend-base.rb +13 -0
- data/lib/trahald/git.rb +46 -1
- data/lib/trahald/markdown-body.rb +44 -0
- data/lib/trahald/redis-client.rb +33 -9
- data/lib/trahald/version.rb +1 -1
- data/lib/views/edit.slim +47 -10
- data/lib/views/fd.scss +22 -0
- data/lib/views/header.slim +13 -0
- data/lib/views/layout.slim +7 -4
- data/lib/views/list.slim +3 -1
- data/lib/views/page.slim +5 -8
- data/lib/views/slide.slim +37 -0
- data/lib/views/style.scss +3 -1
- data/lib/views/summary.slim +36 -0
- data/lib/views/tab.slim +10 -0
- data/lib/views/tab_edit.slim +10 -0
- data/spec/git_spec.rb +3 -23
- data/spec/redis-client_spec.rb +3 -25
- data/spec/spec_helper.rb +2 -1
- data/spec/support/shared_examples_for_backends.rb +38 -0
- data/trahald.gemspec +1 -0
- metadata +44 -4
@@ -0,0 +1,136 @@
|
|
1
|
+
@import url(http://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic);
|
2
|
+
@import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700);
|
3
|
+
/**
|
4
|
+
* Sky theme for reveal.js.
|
5
|
+
*
|
6
|
+
* Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
|
7
|
+
*/
|
8
|
+
/*********************************************
|
9
|
+
* GLOBAL STYLES
|
10
|
+
*********************************************/
|
11
|
+
body {
|
12
|
+
background: #add9e4;
|
13
|
+
background: -moz-radial-gradient(center, circle cover, #f7fbfc 0%, #add9e4 100%);
|
14
|
+
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, #f7fbfc), color-stop(100%, #add9e4));
|
15
|
+
background: -webkit-radial-gradient(center, circle cover, #f7fbfc 0%, #add9e4 100%);
|
16
|
+
background: -o-radial-gradient(center, circle cover, #f7fbfc 0%, #add9e4 100%);
|
17
|
+
background: -ms-radial-gradient(center, circle cover, #f7fbfc 0%, #add9e4 100%);
|
18
|
+
background: radial-gradient(center, circle cover, #f7fbfc 0%, #add9e4 100%);
|
19
|
+
background-color: #f7fbfc; }
|
20
|
+
|
21
|
+
.reveal {
|
22
|
+
font-family: "Open Sans", sans-serif;
|
23
|
+
font-size: 36px;
|
24
|
+
font-weight: 200;
|
25
|
+
letter-spacing: -0.02em;
|
26
|
+
color: #333333; }
|
27
|
+
|
28
|
+
::selection {
|
29
|
+
color: white;
|
30
|
+
background: #134674;
|
31
|
+
text-shadow: none; }
|
32
|
+
|
33
|
+
/*********************************************
|
34
|
+
* HEADERS
|
35
|
+
*********************************************/
|
36
|
+
.reveal h1,
|
37
|
+
.reveal h2,
|
38
|
+
.reveal h3,
|
39
|
+
.reveal h4,
|
40
|
+
.reveal h5,
|
41
|
+
.reveal h6 {
|
42
|
+
margin: 0 0 20px 0;
|
43
|
+
color: #333333;
|
44
|
+
font-family: "Quicksand", sans-serif;
|
45
|
+
line-height: 0.9em;
|
46
|
+
letter-spacing: -0.08em;
|
47
|
+
text-transform: uppercase;
|
48
|
+
text-shadow: none; }
|
49
|
+
|
50
|
+
.reveal h1 {
|
51
|
+
text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2); }
|
52
|
+
|
53
|
+
/*********************************************
|
54
|
+
* LINKS
|
55
|
+
*********************************************/
|
56
|
+
.reveal a:not(.image) {
|
57
|
+
color: #3b759e;
|
58
|
+
text-decoration: none;
|
59
|
+
-webkit-transition: color 0.15s ease;
|
60
|
+
-moz-transition: color 0.15s ease;
|
61
|
+
-ms-transition: color 0.15s ease;
|
62
|
+
-o-transition: color 0.15s ease;
|
63
|
+
transition: color 0.15s ease; }
|
64
|
+
|
65
|
+
.reveal a:not(.image):hover {
|
66
|
+
color: #74a7cb;
|
67
|
+
text-shadow: none;
|
68
|
+
border: none; }
|
69
|
+
|
70
|
+
.reveal .roll span:after {
|
71
|
+
color: #fff;
|
72
|
+
background: #264c66; }
|
73
|
+
|
74
|
+
/*********************************************
|
75
|
+
* IMAGES
|
76
|
+
*********************************************/
|
77
|
+
.reveal section img {
|
78
|
+
margin: 15px 0px;
|
79
|
+
background: rgba(255, 255, 255, 0.12);
|
80
|
+
border: 4px solid #333333;
|
81
|
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
|
82
|
+
-webkit-transition: all 0.2s linear;
|
83
|
+
-moz-transition: all 0.2s linear;
|
84
|
+
-ms-transition: all 0.2s linear;
|
85
|
+
-o-transition: all 0.2s linear;
|
86
|
+
transition: all 0.2s linear; }
|
87
|
+
|
88
|
+
.reveal a:hover img {
|
89
|
+
background: rgba(255, 255, 255, 0.2);
|
90
|
+
border-color: #3b759e;
|
91
|
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); }
|
92
|
+
|
93
|
+
/*********************************************
|
94
|
+
* NAVIGATION CONTROLS
|
95
|
+
*********************************************/
|
96
|
+
.reveal .controls div.navigate-left,
|
97
|
+
.reveal .controls div.navigate-left.enabled {
|
98
|
+
border-right-color: #3b759e; }
|
99
|
+
|
100
|
+
.reveal .controls div.navigate-right,
|
101
|
+
.reveal .controls div.navigate-right.enabled {
|
102
|
+
border-left-color: #3b759e; }
|
103
|
+
|
104
|
+
.reveal .controls div.navigate-up,
|
105
|
+
.reveal .controls div.navigate-up.enabled {
|
106
|
+
border-bottom-color: #3b759e; }
|
107
|
+
|
108
|
+
.reveal .controls div.navigate-down,
|
109
|
+
.reveal .controls div.navigate-down.enabled {
|
110
|
+
border-top-color: #3b759e; }
|
111
|
+
|
112
|
+
.reveal .controls div.navigate-left.enabled:hover {
|
113
|
+
border-right-color: #74a7cb; }
|
114
|
+
|
115
|
+
.reveal .controls div.navigate-right.enabled:hover {
|
116
|
+
border-left-color: #74a7cb; }
|
117
|
+
|
118
|
+
.reveal .controls div.navigate-up.enabled:hover {
|
119
|
+
border-bottom-color: #74a7cb; }
|
120
|
+
|
121
|
+
.reveal .controls div.navigate-down.enabled:hover {
|
122
|
+
border-top-color: #74a7cb; }
|
123
|
+
|
124
|
+
/*********************************************
|
125
|
+
* PROGRESS BAR
|
126
|
+
*********************************************/
|
127
|
+
.reveal .progress {
|
128
|
+
background: rgba(0, 0, 0, 0.2); }
|
129
|
+
|
130
|
+
.reveal .progress span {
|
131
|
+
background: #3b759e;
|
132
|
+
-webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
133
|
+
-moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
134
|
+
-ms-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
135
|
+
-o-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
136
|
+
transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
|
@@ -0,0 +1,142 @@
|
|
1
|
+
@import url(http://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
|
2
|
+
/**
|
3
|
+
* Solarized Light theme for reveal.js.
|
4
|
+
* Author: Achim Staebler
|
5
|
+
*/
|
6
|
+
@font-face {
|
7
|
+
font-family: 'League Gothic';
|
8
|
+
src: url("../../lib/font/league_gothic-webfont.eot");
|
9
|
+
src: url("../../lib/font/league_gothic-webfont.eot?#iefix") format("embedded-opentype"), url("../../lib/font/league_gothic-webfont.woff") format("woff"), url("../../lib/font/league_gothic-webfont.ttf") format("truetype"), url("../../lib/font/league_gothic-webfont.svg#LeagueGothicRegular") format("svg");
|
10
|
+
font-weight: normal;
|
11
|
+
font-style: normal; }
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Solarized colors by Ethan Schoonover
|
15
|
+
*/
|
16
|
+
html * {
|
17
|
+
color-profile: sRGB;
|
18
|
+
rendering-intent: auto; }
|
19
|
+
|
20
|
+
/*********************************************
|
21
|
+
* GLOBAL STYLES
|
22
|
+
*********************************************/
|
23
|
+
body {
|
24
|
+
background: #fdf6e3;
|
25
|
+
background-color: #fdf6e3; }
|
26
|
+
|
27
|
+
.reveal {
|
28
|
+
font-family: "Lato", sans-serif;
|
29
|
+
font-size: 36px;
|
30
|
+
font-weight: 200;
|
31
|
+
letter-spacing: -0.02em;
|
32
|
+
color: #657b83; }
|
33
|
+
|
34
|
+
::selection {
|
35
|
+
color: white;
|
36
|
+
background: #d33682;
|
37
|
+
text-shadow: none; }
|
38
|
+
|
39
|
+
/*********************************************
|
40
|
+
* HEADERS
|
41
|
+
*********************************************/
|
42
|
+
.reveal h1,
|
43
|
+
.reveal h2,
|
44
|
+
.reveal h3,
|
45
|
+
.reveal h4,
|
46
|
+
.reveal h5,
|
47
|
+
.reveal h6 {
|
48
|
+
margin: 0 0 20px 0;
|
49
|
+
color: #586e75;
|
50
|
+
font-family: "League Gothic", Impact, sans-serif;
|
51
|
+
line-height: 0.9em;
|
52
|
+
letter-spacing: 0.02em;
|
53
|
+
text-transform: uppercase;
|
54
|
+
text-shadow: none; }
|
55
|
+
|
56
|
+
.reveal h1 {
|
57
|
+
text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.2); }
|
58
|
+
|
59
|
+
/*********************************************
|
60
|
+
* LINKS
|
61
|
+
*********************************************/
|
62
|
+
.reveal a:not(.image) {
|
63
|
+
color: #268bd2;
|
64
|
+
text-decoration: none;
|
65
|
+
-webkit-transition: color 0.15s ease;
|
66
|
+
-moz-transition: color 0.15s ease;
|
67
|
+
-ms-transition: color 0.15s ease;
|
68
|
+
-o-transition: color 0.15s ease;
|
69
|
+
transition: color 0.15s ease; }
|
70
|
+
|
71
|
+
.reveal a:not(.image):hover {
|
72
|
+
color: #78b9e6;
|
73
|
+
text-shadow: none;
|
74
|
+
border: none; }
|
75
|
+
|
76
|
+
.reveal .roll span:after {
|
77
|
+
color: #fff;
|
78
|
+
background: #1a6091; }
|
79
|
+
|
80
|
+
/*********************************************
|
81
|
+
* IMAGES
|
82
|
+
*********************************************/
|
83
|
+
.reveal section img {
|
84
|
+
margin: 15px 0px;
|
85
|
+
background: rgba(255, 255, 255, 0.12);
|
86
|
+
border: 4px solid #657b83;
|
87
|
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
|
88
|
+
-webkit-transition: all 0.2s linear;
|
89
|
+
-moz-transition: all 0.2s linear;
|
90
|
+
-ms-transition: all 0.2s linear;
|
91
|
+
-o-transition: all 0.2s linear;
|
92
|
+
transition: all 0.2s linear; }
|
93
|
+
|
94
|
+
.reveal a:hover img {
|
95
|
+
background: rgba(255, 255, 255, 0.2);
|
96
|
+
border-color: #268bd2;
|
97
|
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); }
|
98
|
+
|
99
|
+
/*********************************************
|
100
|
+
* NAVIGATION CONTROLS
|
101
|
+
*********************************************/
|
102
|
+
.reveal .controls div.navigate-left,
|
103
|
+
.reveal .controls div.navigate-left.enabled {
|
104
|
+
border-right-color: #268bd2; }
|
105
|
+
|
106
|
+
.reveal .controls div.navigate-right,
|
107
|
+
.reveal .controls div.navigate-right.enabled {
|
108
|
+
border-left-color: #268bd2; }
|
109
|
+
|
110
|
+
.reveal .controls div.navigate-up,
|
111
|
+
.reveal .controls div.navigate-up.enabled {
|
112
|
+
border-bottom-color: #268bd2; }
|
113
|
+
|
114
|
+
.reveal .controls div.navigate-down,
|
115
|
+
.reveal .controls div.navigate-down.enabled {
|
116
|
+
border-top-color: #268bd2; }
|
117
|
+
|
118
|
+
.reveal .controls div.navigate-left.enabled:hover {
|
119
|
+
border-right-color: #78b9e6; }
|
120
|
+
|
121
|
+
.reveal .controls div.navigate-right.enabled:hover {
|
122
|
+
border-left-color: #78b9e6; }
|
123
|
+
|
124
|
+
.reveal .controls div.navigate-up.enabled:hover {
|
125
|
+
border-bottom-color: #78b9e6; }
|
126
|
+
|
127
|
+
.reveal .controls div.navigate-down.enabled:hover {
|
128
|
+
border-top-color: #78b9e6; }
|
129
|
+
|
130
|
+
/*********************************************
|
131
|
+
* PROGRESS BAR
|
132
|
+
*********************************************/
|
133
|
+
.reveal .progress {
|
134
|
+
background: rgba(0, 0, 0, 0.2); }
|
135
|
+
|
136
|
+
.reveal .progress span {
|
137
|
+
background: #268bd2;
|
138
|
+
-webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
139
|
+
-moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
140
|
+
-ms-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
141
|
+
-o-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
142
|
+
transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
|
data/lib/trahald.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
require_relative "trahald/article"
|
2
3
|
require_relative "trahald/backend-base"
|
3
|
-
require_relative "trahald/
|
4
|
-
require_relative "trahald/redis-client"
|
4
|
+
require_relative "trahald/markdown-body"
|
5
5
|
require_relative "trahald/version"
|
6
6
|
|
7
7
|
module Trahald
|
@@ -14,26 +14,86 @@ module Trahald
|
|
14
14
|
|
15
15
|
class App < Sinatra::Base
|
16
16
|
|
17
|
+
configure :test do
|
18
|
+
require_relative "trahald/git"
|
19
|
+
require_relative "trahald/redis-client"
|
20
|
+
end
|
21
|
+
|
17
22
|
configure :production, :development, :git do
|
23
|
+
require_relative "trahald/git"
|
18
24
|
dir = Dir::pwd + "/data"
|
19
25
|
Git::init_repo_if_needed dir
|
20
26
|
DB = Git.new dir
|
21
27
|
end
|
22
28
|
|
23
29
|
configure :redis do
|
24
|
-
|
25
|
-
DB = RedisClient.new
|
30
|
+
require_relative "trahald/redis-client"
|
31
|
+
DB = RedisClient.new ENV["TRAHALD_REDIS_URL"]
|
32
|
+
end
|
33
|
+
|
34
|
+
configure do
|
35
|
+
UPLOAD = "upload"
|
36
|
+
UPLOAD_DIR = "#{Dir::pwd}/lib/public/#{UPLOAD}"
|
37
|
+
UPLOAD_LIMIT_SIZE = 2000000 # 2MB
|
38
|
+
Dir::mkdir UPLOAD_DIR unless FileTest.exist? UPLOAD_DIR
|
39
|
+
end
|
40
|
+
|
41
|
+
helpers do
|
42
|
+
def request_headers
|
43
|
+
env.inject({}){|acc, (k,v) | acc[$1.downcase] = v if k =~ /^http_(.*)/i; acc}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
before do
|
48
|
+
expires 500, :public, :must_revalidate
|
26
49
|
end
|
27
50
|
|
28
51
|
get '/' do
|
29
|
-
redirect 'home'
|
52
|
+
#redirect 'home'
|
53
|
+
redirect 'summary'
|
30
54
|
end
|
31
55
|
|
32
56
|
get '/list' do
|
57
|
+
last_modified DB.last_modified
|
58
|
+
@name = "list"
|
59
|
+
@title = "ページ一覧"
|
33
60
|
@keys = DB.list
|
34
61
|
slim :list
|
35
62
|
end
|
36
63
|
|
64
|
+
get '/summary' do
|
65
|
+
last_modified DB.last_modified
|
66
|
+
@name = "summary" # not used
|
67
|
+
@title = "summary" # not used
|
68
|
+
@data = DB.data.sort_by{|d| d.date}.reverse
|
69
|
+
slim :summary
|
70
|
+
end
|
71
|
+
|
72
|
+
get '/uploads' do
|
73
|
+
@name = "uploads"
|
74
|
+
@title = "添付画像一覧"
|
75
|
+
@keys = Dir::glob("#{UPLOAD_DIR}/**/*.{gif,jpg,jpeg,png}").map{|f| "#{UPLOAD}/#{File.basename(f)}"}
|
76
|
+
slim :list
|
77
|
+
end
|
78
|
+
|
79
|
+
get '/css/fd.css' do
|
80
|
+
scss :fd
|
81
|
+
end
|
82
|
+
|
83
|
+
get %r{^/(.+?)/slide$} do
|
84
|
+
puts "slide"
|
85
|
+
puts params[:captures]
|
86
|
+
@name = params[:captures][0]
|
87
|
+
@body = DB.body(@name)
|
88
|
+
puts @body
|
89
|
+
if @body
|
90
|
+
slim :slide, :layout => :raw_layout
|
91
|
+
else
|
92
|
+
@body = ""
|
93
|
+
slim :edit
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
37
97
|
get %r{^/(.+?)/edit$} do
|
38
98
|
puts "edit"
|
39
99
|
puts params[:captures]
|
@@ -60,12 +120,11 @@ module Trahald
|
|
60
120
|
get %r{^/(.+?)$} do
|
61
121
|
puts params[:captures]
|
62
122
|
@name = params[:captures][0]
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
@body = Kramdown::Document.new(@body).to_html
|
123
|
+
article = DB.article(@name)
|
124
|
+
if article
|
125
|
+
@body = Kramdown::Document.new(article.body).to_html
|
126
|
+
@date = article.date
|
127
|
+
@tab = slim :tab
|
69
128
|
slim :page
|
70
129
|
else
|
71
130
|
@body = ""
|
@@ -91,6 +150,26 @@ module Trahald
|
|
91
150
|
redirect "/#{URI.escape(@name)}"
|
92
151
|
end
|
93
152
|
|
153
|
+
post "/upload" do
|
154
|
+
header = request_headers
|
155
|
+
data = request.body.read
|
156
|
+
name = header["x_file_name"]
|
157
|
+
size = header["x_file_size"].to_i
|
158
|
+
halt(400, "Invalid request. (Maybe filetype is forbidden.)") unless name
|
159
|
+
halt(400, "Only gif, jpg, png file is enable.") unless ['png', 'jpg', 'jpeg', 'gif'].include? name.split('.').last.downcase
|
160
|
+
filepath = UPLOAD_DIR + "/" + name.downcase
|
161
|
+
halt(423, "File has already existed.") if File.exist? filepath
|
162
|
+
halt(413, "File size is too big.") if size > UPLOAD_LIMIT_SIZE
|
163
|
+
begin
|
164
|
+
File.open(filepath, "w") do |f|
|
165
|
+
f.write(data)
|
166
|
+
end
|
167
|
+
rescue Exception
|
168
|
+
halt(403, "File can not be written. ")
|
169
|
+
end
|
170
|
+
halt 200
|
171
|
+
end
|
172
|
+
|
94
173
|
run! if $0 == __FILE__
|
95
174
|
end
|
96
175
|
end
|
Binary file
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Trahald
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class Article
|
6
|
+
attr_reader :name, :body, :date
|
7
|
+
def initialize(name, body, date)
|
8
|
+
@name = name
|
9
|
+
@body = body
|
10
|
+
@date = date
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{
|
15
|
+
:name => @name,
|
16
|
+
:body => @body,
|
17
|
+
:date => @date
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_json
|
22
|
+
JSON.generate to_h
|
23
|
+
end
|
24
|
+
|
25
|
+
def Article.from_json(json)
|
26
|
+
begin
|
27
|
+
h = JSON.parse json
|
28
|
+
Article.new(h["name"], h["body"], h["date"])
|
29
|
+
rescue exception
|
30
|
+
"Json parse error."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|