octodmin 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 68161108fbd0f208b9fe379eaefc1638d8a07a40
4
- data.tar.gz: 308e09d4fd3591b47d7a7621837aa12543e6f606
3
+ metadata.gz: 486c254e24ba8ecb343d9153f8a3fa520cc6fcf9
4
+ data.tar.gz: c4d51cf2c335bdeac72e50f7942c68f09b18ef40
5
5
  SHA512:
6
- metadata.gz: a3c62874c57613363f2d4ae5e8bb8e63892ffd50a91e853d2012a19c9a2db48ced8388fc1d8cd8467904df0c89e7c1909048315046cb0b4719af5b7afd57d138
7
- data.tar.gz: 11f6a5edc1cf7e8b057b45dbe9ab9581b00f2755c30e5c5cb5d60c679932d58e323c171bdeafd471dcf8a8b8e939a2508b81e9d206316cb82fa85caf69df7468
6
+ metadata.gz: 99d6b2bc5a38721a1ce9e10f6f270cb9041baf99353ed8a3a1669252266761140f26119d0362991c782ed819c839c1f52726cf946492901286a24caf76289983
7
+ data.tar.gz: de3ea218515c0c77229a62902a8848d570c4817f4b6db587e0bf312777d11b733fecd8dff3fd6cc3177b8533d29aee856a32ec79bdf7e5847d3ce0fb9ba4316e
@@ -5,5 +5,6 @@ before_script:
5
5
  - bower install
6
6
  script: bundle exec rake spec:coverage
7
7
  rvm:
8
+ - 2.0
8
9
  - 2.1
9
10
  - 2.2
@@ -1,3 +1,10 @@
1
+ v0.2.0
2
+ ------
3
+
4
+ * Support Ruby 2.0
5
+ * Disable posts refreshing because of race conditions
6
+ * Various UI fixes
7
+
1
8
  v0.1.0
2
9
  ------
3
10
 
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', '~> 0.1.0'
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
@@ -2,6 +2,7 @@
2
2
  #= require jquery-serialize-object
3
3
  #= require bootstrap
4
4
  #= require bootstrap-markdown
5
+ #= require bootstrap.growl/bootstrap-growl
5
6
  #= require spin.js/spin.js
6
7
  #= require react
7
8
  #= require react-loader
@@ -5,7 +5,7 @@
5
5
  site: React.PropTypes.object.isRequired
6
6
 
7
7
  getInitialState: ->
8
- { alert: null, success: null, loading: false }
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
- @setState(success: response.syncs.join("\n").replace(/\n/g, "<br>"))
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
- @setState(success: response.deploys.join("\n"))
30
- setTimeout(@removeSuccess, 5000)
28
+ $.growl(response.deploys.join("\n"), growlSuccess)
31
29
  $(document).trigger("fetchPosts")
32
30
 
33
31
  handleError: (error) ->
34
- @setState(alert: error.responseJSON?.errors.join("\n").replace(/\n/g, "<br>"))
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} onBlur={@handleBlur}>
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} onBlur={@handleBlur}>
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
- { alert: null, loading: false, posts: null }
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(alert: null, posts: response.posts) if @isMounted()
19
+ @setState(posts: response.posts) if @isMounted()
20
20
 
21
21
  handleError: (error) ->
22
- @setState(alert: "Could not load posts: #{error.statusText} (#{error.status})") if @isMounted()
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
- { alert: null, loading: false }
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
- @setState(alert: error.responseJSON?.errors.join(", "))
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
- { alert: null, loading: false }
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
- @setState(alert: "Could not load post: #{error.statusText} (#{error.status})")
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
- { alert: null, success: null, loading: false, post: null }
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(alert: null, post: response.posts)
231
+ @setState(post: response.posts)
241
232
 
242
233
  handleFormSuccess: (response) ->
243
- @setState(alert: null, success: "Post is updated")
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
- @setState(alert: error.responseJSON?.errors.join(", "))
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
- alert("Could not load site: #{error.statusText} (#{error.status})")
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
@@ -5,6 +5,7 @@
5
5
  "jquery-serialize-object": "~2.4.5",
6
6
  "bootstrap-sass": "~3.3.2",
7
7
  "bootstrap-markdown": "~2.8.0",
8
+ "bootstrap.growl": "~2.0.1",
8
9
  "spin.js": "~2.0.2",
9
10
  "react": "~0.12.0",
10
11
  "react-loader": "~1.1.0",
@@ -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.to_h
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"
@@ -1,3 +1,3 @@
1
1
  module Octodmin
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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.1.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-05 00:00:00.000000000 Z
11
+ date: 2015-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: octopress