octodmin 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +7 -0
- data/README.md +12 -10
- data/app/assets/javascripts/app.js.coffee +1 -0
- data/app/assets/javascripts/components/header.js.cjsx +6 -16
- data/app/assets/javascripts/components/posts.js.cjsx +12 -28
- data/app/assets/javascripts/components/router.js.cjsx +9 -2
- data/app/assets/stylesheets/app.scss +10 -0
- data/bower.json +1 -0
- data/lib/octodmin/post.rb +2 -2
- data/lib/octodmin/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 486c254e24ba8ecb343d9153f8a3fa520cc6fcf9
|
4
|
+
data.tar.gz: c4d51cf2c335bdeac72e50f7942c68f09b18ef40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99d6b2bc5a38721a1ce9e10f6f270cb9041baf99353ed8a3a1669252266761140f26119d0362991c782ed819c839c1f52726cf946492901286a24caf76289983
|
7
|
+
data.tar.gz: de3ea218515c0c77229a62902a8848d570c4817f4b6db587e0bf312777d11b733fecd8dff3fd6cc3177b8533d29aee856a32ec79bdf7e5847d3ce0fb9ba4316e
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,7 @@ Content management for Jekyll blogs
|
|
14
14
|
Add this line to your Jekyll project's Gemfile:
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
gem 'octodmin'
|
17
|
+
gem 'octodmin'
|
18
18
|
```
|
19
19
|
|
20
20
|
And then execute:
|
@@ -76,15 +76,6 @@ post_ext: markdown
|
|
76
76
|
post_layout: post
|
77
77
|
```
|
78
78
|
|
79
|
-
Please note that Octodmin uses Octopress internally, so make sure you
|
80
|
-
there is proper config, for example:
|
81
|
-
|
82
|
-
```yaml
|
83
|
-
# Octopress
|
84
|
-
post_ext: markdown
|
85
|
-
post_layout: post
|
86
|
-
```
|
87
|
-
|
88
79
|
## Deployment
|
89
80
|
|
90
81
|
Since Octodmin is a simple Rack app, use your favorite Ruby application server.
|
@@ -95,6 +86,17 @@ When deploying Octodmin to a remote server, make sure you're able to run
|
|
95
86
|
`git pull`, `git push` and `octopress deploy` (if needed) successfully
|
96
87
|
in the shell of your remote user.
|
97
88
|
|
89
|
+
For basic HTTP authentication, use `Rack::Auth::Basic`.
|
90
|
+
Example for your `config.ru`:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
use Rack::Auth::Basic, "Octodmin" do |username, password|
|
94
|
+
[username, password] == [ENV["USERNAME"], ENV["PASSWORD"]]
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
Just set ENV variables and you're good to go.
|
99
|
+
|
98
100
|
## Development and testing
|
99
101
|
|
100
102
|
You would need `npm` and `bower`. Run `bower install` to install asset
|
@@ -5,7 +5,7 @@
|
|
5
5
|
site: React.PropTypes.object.isRequired
|
6
6
|
|
7
7
|
getInitialState: ->
|
8
|
-
{
|
8
|
+
{ loading: false }
|
9
9
|
|
10
10
|
handleSync: ->
|
11
11
|
return if @state.loading
|
@@ -21,23 +21,15 @@
|
|
21
21
|
@setState(loading: false)
|
22
22
|
|
23
23
|
handleSyncSuccess: (response) ->
|
24
|
-
|
25
|
-
setTimeout(@removeSuccess, 5000)
|
24
|
+
$.growl(response.syncs.join("\n").replace(/\n/g, "<br>"), growlSuccess)
|
26
25
|
$(document).trigger("fetchPosts")
|
27
26
|
|
28
27
|
handleDeploySuccess: (response) ->
|
29
|
-
|
30
|
-
setTimeout(@removeSuccess, 5000)
|
28
|
+
$.growl(response.deploys.join("\n"), growlSuccess)
|
31
29
|
$(document).trigger("fetchPosts")
|
32
30
|
|
33
31
|
handleError: (error) ->
|
34
|
-
|
35
|
-
|
36
|
-
removeSuccess: ->
|
37
|
-
@setState(success: null) if @isMounted()
|
38
|
-
|
39
|
-
handleBlur: ->
|
40
|
-
@setState(alert: null, success: null) if @isMounted()
|
32
|
+
$.growl(error.responseJSON?.errors.join("\n").replace(/\n/g, "<br>"), growlError)
|
41
33
|
|
42
34
|
render: ->
|
43
35
|
<div>
|
@@ -47,13 +39,13 @@
|
|
47
39
|
<Link to="app" className="navbar-brand"><i className="fa fa-fw fa-cog"></i> {@props.site.title}</Link>
|
48
40
|
</div>
|
49
41
|
<div className="navbar-right">
|
50
|
-
<button className="btn btn-primary navbar-btn #{'disabled' if @state.loading}" onClick={@handleSync}
|
42
|
+
<button className="btn btn-primary navbar-btn #{'disabled' if @state.loading}" onClick={@handleSync}>
|
51
43
|
<i className="fa fa-fw fa-refresh"></i> Sync
|
52
44
|
</button>
|
53
45
|
{if @props.site.octodmin.deploys
|
54
46
|
deploy = @props.site.octodmin.deploys[0]
|
55
47
|
|
56
|
-
<button className="btn btn-primary navbar-btn #{'disabled' if @state.loading}" onClick={@handleDeploy}
|
48
|
+
<button className="btn btn-primary navbar-btn #{'disabled' if @state.loading}" onClick={@handleDeploy}>
|
57
49
|
<i className="fa fa-fw fa-ship"></i> Deploy
|
58
50
|
</button>
|
59
51
|
}
|
@@ -63,7 +55,5 @@
|
|
63
55
|
</div>
|
64
56
|
</div>
|
65
57
|
</nav>
|
66
|
-
{<div className="alert alert-danger"><span dangerouslySetInnerHTML={{__html: @state.alert }}></span></div> if @state.alert}
|
67
|
-
{<div className="alert alert-success"><span dangerouslySetInnerHTML={{__html: @state.success }}></span></div> if @state.success}
|
68
58
|
</div>
|
69
59
|
)
|
@@ -5,7 +5,7 @@
|
|
5
5
|
site: React.PropTypes.object.isRequired
|
6
6
|
|
7
7
|
getInitialState: ->
|
8
|
-
{
|
8
|
+
{ loading: false, posts: null }
|
9
9
|
|
10
10
|
fetchPosts: ->
|
11
11
|
return if @state.loading
|
@@ -16,23 +16,20 @@
|
|
16
16
|
@setState(loading: false) if @isMounted()
|
17
17
|
|
18
18
|
handleSuccess: (response) ->
|
19
|
-
@setState(
|
19
|
+
@setState(posts: response.posts) if @isMounted()
|
20
20
|
|
21
21
|
handleError: (error) ->
|
22
|
-
|
22
|
+
$.growl("Could not load posts: #{error.statusText} (#{error.status})", growlError)
|
23
23
|
|
24
24
|
componentWillMount: ->
|
25
25
|
@fetchPosts()
|
26
26
|
$(document).on("fetchPosts", @fetchPosts)
|
27
|
-
@timer = setInterval(@fetchPosts, 5000)
|
28
27
|
|
29
28
|
componentWillUnmount: ->
|
30
29
|
$(document).off("fetchPosts", @fetchPosts)
|
31
|
-
clearInterval(@timer)
|
32
30
|
|
33
31
|
render: ->
|
34
32
|
<div>
|
35
|
-
{<div className="alert alert-danger">{@state.alert}</div> if @state.alert}
|
36
33
|
<NewPostPartial site={@props.site} />
|
37
34
|
|
38
35
|
<Loader loaded={!!@state.posts}>
|
@@ -59,7 +56,7 @@
|
|
59
56
|
site: React.PropTypes.object.isRequired
|
60
57
|
|
61
58
|
getInitialState: ->
|
62
|
-
{
|
59
|
+
{ loading: false }
|
63
60
|
|
64
61
|
form: ->
|
65
62
|
$(@refs.form.getDOMNode())
|
@@ -75,19 +72,16 @@
|
|
75
72
|
@setState(loading: false)
|
76
73
|
|
77
74
|
handleSuccess: (response) ->
|
78
|
-
@setState(alert: null)
|
79
75
|
@form()[0].reset()
|
80
76
|
$(document).trigger("fetchPosts")
|
81
77
|
@transitionTo("post_edit", post_id: response.posts.identifier)
|
82
78
|
|
83
79
|
handleError: (error) ->
|
84
|
-
|
80
|
+
$.growl(error.responseJSON?.errors.join(", "), growlError)
|
85
81
|
|
86
82
|
render: ->
|
87
83
|
<div className="panel panel-default">
|
88
84
|
<div className="panel-body">
|
89
|
-
{<div className="alert alert-danger">{@state.alert}</div> if @state.alert}
|
90
|
-
|
91
85
|
<form ref="form" className="form-inline" onSubmit={@handleSubmit}>
|
92
86
|
<fieldset className="row" disabled={@state.loading}>
|
93
87
|
<div className="col-sm-9 form-group form-group-lg">
|
@@ -110,7 +104,7 @@
|
|
110
104
|
post: React.PropTypes.object.isRequired
|
111
105
|
|
112
106
|
getInitialState: ->
|
113
|
-
{
|
107
|
+
{ loading: false }
|
114
108
|
|
115
109
|
panelClass: ->
|
116
110
|
if @props.post.added
|
@@ -159,23 +153,20 @@
|
|
159
153
|
@setState(loading: false)
|
160
154
|
|
161
155
|
handleSuccess: (response) ->
|
162
|
-
@setState(alert: null)
|
163
156
|
$(document).trigger("fetchPosts")
|
164
157
|
|
165
158
|
handleError: (error) ->
|
166
|
-
|
159
|
+
$.growl("Could not load post: #{error.statusText} (#{error.status})", growlError)
|
167
160
|
|
168
161
|
render: ->
|
169
162
|
<div className="panel panel-#{@panelClass()}">
|
170
163
|
<div className="panel-heading clearfix">
|
171
164
|
<h3 className="panel-title pull-left">{@props.post.title}</h3>
|
172
165
|
<div className="pull-right">
|
173
|
-
{moment((new Date(@props.post.date)).toISOString()).format("LLL")}
|
166
|
+
{moment((new Date(@props.post.date.replace(/-/g, "/"))).toISOString()).format("LLL")}
|
174
167
|
</div>
|
175
168
|
</div>
|
176
169
|
<div className="panel-body">
|
177
|
-
{<div className="alert alert-danger">{@state.alert}</div> if @state.alert}
|
178
|
-
|
179
170
|
<div className="row">
|
180
171
|
<div className="col-sm-9 excerpt" dangerouslySetInnerHTML={{__html: @props.post.excerpt }} />
|
181
172
|
<div className="col-sm-3 buttons">
|
@@ -205,7 +196,7 @@
|
|
205
196
|
site: React.PropTypes.object.isRequired
|
206
197
|
|
207
198
|
getInitialState: ->
|
208
|
-
{
|
199
|
+
{ loading: false, post: null }
|
209
200
|
|
210
201
|
form: ->
|
211
202
|
$(@refs.form.getDOMNode())
|
@@ -237,18 +228,14 @@
|
|
237
228
|
@setState(loading: false)
|
238
229
|
|
239
230
|
handleSuccess: (response) ->
|
240
|
-
@setState(
|
231
|
+
@setState(post: response.posts)
|
241
232
|
|
242
233
|
handleFormSuccess: (response) ->
|
243
|
-
|
244
|
-
setTimeout(@removeSuccess, 5000)
|
234
|
+
$.growl("Post is updated", growlSuccess)
|
245
235
|
@transitionTo("post_edit", post_id: response.posts.identifier)
|
246
236
|
|
247
237
|
handleError: (error) ->
|
248
|
-
|
249
|
-
|
250
|
-
removeSuccess: ->
|
251
|
-
@setState(success: null) if @isMounted()
|
238
|
+
$.growl(error.responseJSON?.errors.join(", "), growlError)
|
252
239
|
|
253
240
|
componentWillMount: ->
|
254
241
|
@fetchPost()
|
@@ -268,9 +255,6 @@
|
|
268
255
|
|
269
256
|
render: ->
|
270
257
|
<Loader loaded={!!@state.post}>
|
271
|
-
{<div className="alert alert-danger">{@state.alert}</div> if @state.alert}
|
272
|
-
{<div className="alert alert-success">{@state.success}</div> if @state.success}
|
273
|
-
|
274
258
|
{if @state.post
|
275
259
|
<form ref="form" className="form-horizontal post-edit" onSubmit={@handleSubmit}>
|
276
260
|
<fieldset disabled={@state.loading}>
|
@@ -7,6 +7,14 @@
|
|
7
7
|
@DefaultRoute = Router.DefaultRoute
|
8
8
|
@RouteHandler = Router.RouteHandler
|
9
9
|
|
10
|
+
@growlSuccess =
|
11
|
+
type: "success"
|
12
|
+
delay: 10000
|
13
|
+
|
14
|
+
@growlError =
|
15
|
+
type: "danger"
|
16
|
+
delay: 60000
|
17
|
+
|
10
18
|
@Container = React.createClass(
|
11
19
|
render: ->
|
12
20
|
<div className="container">
|
@@ -26,7 +34,7 @@
|
|
26
34
|
$("title").text("Octodmin – #{response.sites.title}")
|
27
35
|
|
28
36
|
handleError: (error) ->
|
29
|
-
|
37
|
+
$.growl("Could not load site: #{error.statusText} (#{error.status})", growlError)
|
30
38
|
|
31
39
|
componentWillMount: ->
|
32
40
|
@fetchSite()
|
@@ -50,7 +58,6 @@ routes =
|
|
50
58
|
<DefaultRoute handler={@Posts} />
|
51
59
|
</Route>
|
52
60
|
|
53
|
-
|
54
61
|
Router.run(routes, Router.HistoryLocation, (Handler) ->
|
55
62
|
React.render(<Handler />, document.getElementById("app"))
|
56
63
|
)
|
@@ -13,6 +13,10 @@ body {
|
|
13
13
|
padding-bottom: 20px;
|
14
14
|
}
|
15
15
|
|
16
|
+
.growl-animated {
|
17
|
+
padding: 10px 35px 10px 15px;
|
18
|
+
}
|
19
|
+
|
16
20
|
a, button, input, textarea, *:focus {
|
17
21
|
outline: 0 !important;
|
18
22
|
outline-style: none !important;
|
@@ -31,6 +35,12 @@ a, button, input, textarea, *:focus {
|
|
31
35
|
}
|
32
36
|
|
33
37
|
.panel {
|
38
|
+
&:not(.panel-default) {
|
39
|
+
.panel-heading {
|
40
|
+
color: #fff;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
34
44
|
.panel-heading {
|
35
45
|
line-height: 26px;
|
36
46
|
|
data/bower.json
CHANGED
data/lib/octodmin/post.rb
CHANGED
@@ -68,9 +68,9 @@ module Octodmin
|
|
68
68
|
"force" => true,
|
69
69
|
})
|
70
70
|
|
71
|
-
options = @site.config["octodmin"]["front_matter"].keys.map do |key|
|
71
|
+
options = Hash[@site.config["octodmin"]["front_matter"].keys.map do |key|
|
72
72
|
[key, params[key]]
|
73
|
-
end
|
73
|
+
end]
|
74
74
|
|
75
75
|
content = params["content"].gsub("\r\n", "\n").strip
|
76
76
|
result = "---\n#{options.map { |k, v| "#{k}: \"#{v}\"" }.join("\n")}\n---\n\n#{content}\n"
|
data/lib/octodmin/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: octodmin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Krasnoukhov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: octopress
|