dokno 1.1.1 → 1.2.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
  SHA256:
3
- metadata.gz: 43b733c58c27a4d573269c75b1d47ba35aa570796535de91f9619429ce0cc017
4
- data.tar.gz: 199666be242bb2a24a57552d377f4d3c9f84a1d0f5e92e99817c4786a80ba5c6
3
+ metadata.gz: d6832c4cb6bd12af77ec2e917a511ff8e1e321ef075fea55d3fda293d215086d
4
+ data.tar.gz: 031e5cd22170d331739f92304ee740804703cb692839c92b8ddea8dc7aded424
5
5
  SHA512:
6
- metadata.gz: 4a5b2583ecedf613308ac35ce4f55df892ca69593a34698d9cf8584ae61c8f0fa9d0d3444957941c76a9f501b383b49b517d63cac0b18d9012a3fc5201901708
7
- data.tar.gz: a06162fecccb4d41751e8fcbb0f503427f3fe280fbd67fab5af761a3976a4d1646bc1d1861641da7bb9d06299c5e05281cc2a7b97b2a47349537a119eebe3fce
6
+ metadata.gz: 31cc72ec145aadaa3aaa34be3d650387b35c905799b5bf19d38a0effed21db7e51dec651c12e252ea87670a17b6f5439e26cbbacb1b8887dca043dc0eb7602da
7
+ data.tar.gz: 7dafaa4a7431c3216234a2de4551f749874ffb2aaf8f25ec0002e544828002581a74f648fdc8139bb6406eb8fde28a8694600364050de9b0c38b1ad22795a306
data/README.md CHANGED
@@ -119,6 +119,8 @@ $ bundle exec rspec
119
119
  ```
120
120
 
121
121
  ## Hat Tips
122
+ - [tailwindcss](https://tailwindcss.com/)
123
+ - CSS framework
122
124
  - [diffy](https://github.com/samg/diffy)
123
125
  - Text diffing Ruby gem
124
126
  - [Feather Icons](https://github.com/feathericons/feather)
@@ -1,5 +1,23 @@
1
+ const dokno__search_hotkey_listener = function(e) {
2
+ if (e.key === '/') { handleSearchHotKey(); }
3
+ }
4
+
5
+ function handleSearchHotKey() {
6
+ const search_input = elem('input#search_term');
7
+ search_input.focus();
8
+ search_input.select();
9
+ }
10
+
11
+ function enableSearchHotkey() {
12
+ document.addEventListener('keyup', dokno__search_hotkey_listener, false);
13
+ }
14
+
15
+ function disableSearchHotkey() {
16
+ document.removeEventListener('keyup', dokno__search_hotkey_listener, false);
17
+ }
18
+
1
19
  function copyToClipboard(text) {
2
- window.prompt('Copy to clipboard: CTRL+C, Enter', text);
20
+ window.prompt('Copy to clipboard: CTRL + C, Enter', text);
3
21
  }
4
22
 
5
23
  function elem(selector) {
@@ -22,19 +40,20 @@ function selectOption(id, value) {
22
40
  }
23
41
  }
24
42
 
25
- function changeCategory(category_code, term, order) {
43
+ function applyCategoryCriteria(category_code, term, order) {
26
44
  goToPage(dokno__base_path + category_code + '?search_term=' + term + '&order=' + order);
27
45
  }
28
46
 
29
- function search(term, order) {
30
- goToPage('?search_term=' + term + '&order=' + order);
31
- }
32
-
33
47
  function goToPage(url) {
34
48
  var param_join = url.indexOf('?') >= 0 ? '&' : '?';
35
49
  location.href=url + param_join + '_=' + Math.round(new Date().getTime());
36
50
  }
37
51
 
52
+ function reloadPage() {
53
+ window.onbeforeunload = function () { window.scrollTo(0, 0); }
54
+ location.reload();
55
+ }
56
+
38
57
  function sendRequest(url, data, callback, method) {
39
58
  const request = new XMLHttpRequest();
40
59
  request.open(method, url, true);
@@ -55,23 +74,13 @@ function sendRequest(url, data, callback, method) {
55
74
  request.send(JSON.stringify(data));
56
75
  }
57
76
 
58
- function deactiveArticle(slug) {
59
- const callback = function(_data) {
60
- elem('button#article-deactivate-button').classList.add('hidden');
61
- elem('div#article-deprecated-alert').classList.remove('hidden');
62
- elem('button#article-activate-button').classList.remove('hidden');
63
- reloadLogs();
64
- }
77
+ function deactivateArticle(slug) {
78
+ const callback = function(_data) { reloadPage(); }
65
79
  sendRequest(dokno__base_path + 'article_status', { slug: slug, active: false }, callback, 'POST');
66
80
  }
67
81
 
68
- function activeArticle(slug) {
69
- const callback = function(_data) {
70
- elem('button#article-activate-button').classList.add('hidden');
71
- elem('div#article-deprecated-alert').classList.add('hidden');
72
- elem('button#article-deactivate-button').classList.remove('hidden');
73
- reloadLogs();
74
- }
82
+ function activateArticle(slug) {
83
+ const callback = function(_data) { reloadPage(); }
75
84
  sendRequest(dokno__base_path + 'article_status', { slug: slug, active: true }, callback, 'POST');
76
85
  }
77
86
 
@@ -148,18 +157,6 @@ function toggleVisibility(selector_id) {
148
157
  initIcons();
149
158
  }
150
159
 
151
- function reloadLogs() {
152
- var $log_container = elem('div#dokno-article-log-container');
153
- var category_id = $log_container.getAttribute('data-category-id');
154
- var article_id = $log_container.getAttribute('data-article-id');
155
-
156
- const callback = function(markup) {
157
- elem('div#dokno-article-log-container').innerHTML = markup;
158
- initIcons();
159
- }
160
- sendRequest(dokno__base_path + 'article_log', { category_id: category_id, article_id: article_id }, callback, 'POST');
161
- }
162
-
163
160
  // Pass containers_selector as class name (no prefix)
164
161
  function highlightTerm(terms, containers_selector) {
165
162
  var containers = elems(containers_selector);
@@ -8,7 +8,13 @@ module Dokno
8
8
 
9
9
  def show
10
10
  redirect_to root_path if @article.blank?
11
+
11
12
  @search_term = params[:search_term]
13
+ @order = params[:order]
14
+ @category = Category.find_by(code: params[:cat_code].to_s.strip) if params[:cat_code].present?
15
+ @category = @article.categories.first if @category.blank?
16
+
17
+ flash.now[:yellow] = 'This article is no longer active' unless @article.active
12
18
  end
13
19
 
14
20
  def new
@@ -79,12 +85,6 @@ module Dokno
79
85
  render json: {}, layout: false
80
86
  end
81
87
 
82
- # Ajax-fetched article change log
83
- def article_log
84
- render partial: '/partials/logs',
85
- locals: { article: Article.find_by(id: params[:article_id].to_i) }, layout: false
86
- end
87
-
88
88
  private
89
89
 
90
90
  def article_params
@@ -18,6 +18,7 @@ module Dokno
18
18
  before_save :log_changes
19
19
  before_save :track_slug
20
20
 
21
+ scope :active, -> { where(active: true) }
21
22
  scope :alpha_order, -> { order(active: :desc, title: :asc) }
22
23
  scope :view_order, -> { order(active: :desc, views: :desc, title: :asc) }
23
24
  scope :newest_order, -> { order(active: :desc, created_at: :desc, title: :asc) }
@@ -59,7 +59,7 @@ module Dokno
59
59
 
60
60
  # Used to invalidate the fragment cache of the hierarchical category select options
61
61
  def self.cache_key
62
- maximum :updated_at
62
+ [maximum(:updated_at), Article.maximum(:updated_at)].max
63
63
  end
64
64
 
65
65
  # The given Category and all child Categories. Useful for filtering associated articles.
@@ -109,7 +109,8 @@ module Dokno
109
109
  return '' if category.id == exclude_category_id
110
110
 
111
111
  selected = selected_category_codes&.include?(category.code)
112
- %(<option value="#{category.code}" #{'selected="selected"' if selected}>#{('&nbsp;&nbsp;' * level)}#{category.name}</option>)
112
+ article_count = category.articles_in_branch.size
113
+ %(<option value="#{category.code}" #{'selected="selected"' if selected}>#{('&nbsp;&nbsp;' * level)}#{category.name}#{' (' + article_count.to_s + ')' if article_count.positive?}</option>)
113
114
  end
114
115
 
115
116
  # Never allow setting of parent to self
@@ -2,8 +2,8 @@
2
2
  /* Article formatting */
3
3
  .dokno-article-content-markup {
4
4
  font-weight: 400;
5
- line-height: 1.75rem;
6
- font-size: 1rem;
5
+ line-height: 1.75em;
6
+ font-size: 1em;
7
7
  }
8
8
 
9
9
  .dokno-article-content-markup code {
@@ -23,7 +23,7 @@
23
23
  .dokno-article-content-markup ol,
24
24
  .dokno-article-content-markup hr,
25
25
  .dokno-article-content-markup table {
26
- margin-bottom: 1.25rem;
26
+ margin-bottom: 1.25em;
27
27
  }
28
28
 
29
29
  .dokno-article-content-markup h1,
@@ -32,28 +32,28 @@
32
32
  .dokno-article-content-markup h4,
33
33
  .dokno-article-content-markup h5,
34
34
  .dokno-article-content-markup h6 {
35
- margin-bottom: 1.25rem;
35
+ margin-bottom: 1.25em;
36
36
  font-weight: 600;
37
37
  }
38
38
 
39
39
  .dokno-article-content-markup h1 {
40
- font-size: 1.625rem;
40
+ font-size: 1.625em;
41
41
  }
42
42
 
43
43
  .dokno-article-content-markup h2 {
44
- font-size: 1.25rem;
44
+ font-size: 1.25em;
45
45
  }
46
46
 
47
47
  .dokno-article-content-markup h3,
48
48
  .dokno-article-content-markup h4,
49
49
  .dokno-article-content-markup h5,
50
50
  .dokno-article-content-markup h6 {
51
- font-size: 1rem;
51
+ font-size: 1em;
52
52
  }
53
53
 
54
54
  .dokno-article-content-markup blockquote {
55
55
  border-left: 4px solid #edf2f7;
56
- padding-left: 1.25rem;
56
+ padding-left: 1.25em;
57
57
  }
58
58
 
59
59
  .dokno-article-content-markup ul,
@@ -75,10 +75,10 @@
75
75
 
76
76
  .dokno-article-content-markup table th,
77
77
  .dokno-article-content-markup table td {
78
- padding-left: 1rem;
79
- padding-right: 1rem;
80
- padding-top: 0.5rem;
81
- padding-bottom: 0.5rem;
78
+ padding-left: 1em;
79
+ padding-right: 1em;
80
+ padding-top: 0.5em;
81
+ padding-bottom: 0.5em;
82
82
  font-weight: normal;
83
83
  }
84
84
 
@@ -47,14 +47,14 @@
47
47
  <a id="markdown_write_link" href="javascript:;" onclick="writeArticleToggle();" class="float-right hidden"><i data-feather="pen-tool" class="inline"></i> Write</a>
48
48
  <a id="markdown_preview_link" href="javascript:;" onclick="previewArticleToggle();" class="float-right"><i data-feather="eye" class="inline"></i> Preview</a>
49
49
  </div>
50
- <textarea placeholder="Full article content" name="markdown" id="markdown" class="rounded text-xl shadow-inner bg-gray-100 p-3 mt-2 w-full" rows="10"><%= article.persisted? ? article.markdown : (article.markdown.presence || @template) %></textarea>
50
+ <textarea placeholder="Full article content" name="markdown" id="markdown" class="rounded text-xl shadow-inner bg-gray-100 p-3 mt-2 w-full" rows="20"><%= article.persisted? ? article.markdown : (article.markdown.presence || @template) %></textarea>
51
51
  <div id="markdown_preview" class="dokno-article-content-markup hidden text-lg overflow-hidden overflow-y-auto rounded p-10 mt-2 bg-gray-100 shadow-inner"></div>
52
52
  <div class="text-gray-500 mt-2">Detailed documentation of the described topic. Basic HTML &amp; <a target="_blank" href="https://commonmark.org/help/" title="Markdown formatting examples">markdown</a> OK.</div>
53
53
  </div>
54
54
 
55
- <div class="mt-10">
55
+ <div class="mt-10 text-right">
56
+ <span class="text-lg mr-5"><a class="no-underline" href="<%= article.persisted? ? article_path(article.slug) : root_path %>">Cancel</a></span>
56
57
  <button type="submit" class="bg-gray-700 text-gray-300 hover:bg-gray-900 hover:text-white rounded py-2 px-3 font-bold"><i data-feather="check" class="inline h-5"></i> SAVE ARTICLE</button>
57
- <span class="text-lg ml-5"><a class="no-underline" href="<%= article.persisted? ? article_path(article.slug) : root_path %>">Cancel</a></span>
58
58
  </div>
59
59
 
60
60
  </section>
@@ -1,30 +1,25 @@
1
1
  <%= render 'dokno/article_formatting' %>
2
2
 
3
- <section>
4
- <% if @article.categories.present? %>
5
- <div class="text-gray-500 mb-5">
6
- <% @article.categories.each do |category| %>
7
- <div><a href="<%= article_index_path(category.code) %>"><%= category.breadcrumb %></a></div>
8
- <% end %>
9
- </div>
10
- <% end %>
3
+ <% if @category.present? %>
4
+ <div class="no-print text-gray-500 mb-5">
5
+ <div>Category: <a href="<%= article_index_path(@category.code) %>?search_term=<%= CGI.escape(@search_term.to_s) %>&order=<%= @order %>"><%= @category.breadcrumb %></a></div>
6
+ </div>
7
+ <% end %>
11
8
 
9
+ <%= render 'partials/category_header' %>
10
+
11
+ <div class="my-10 no-print"><hr /></div>
12
+
13
+ <section>
12
14
  <div class="flex">
13
15
  <div id="dokno-article-sidebar" class="w-2/5 pr-10">
14
- <div id="article-deprecated-alert" class="<%= 'hidden' if @article.active %> bg-yellow-700 p-4 mb-5 rounded text-lg border-t-4 border-yellow-900 text-white font-base">
15
- <i data-feather="alert-circle" class="inline-block mr-2"></i> This article is no longer active
16
- </div>
17
-
18
- <h1 class="dokno-article-content-highlight text-4xl mb-10 leading-tight font-light"><%= @article.title %></h1>
16
+ <h1 class="dokno-article-content-highlight text-4xl mb-8 leading-tight font-light"><%= @article.title %></h1>
19
17
 
20
18
  <div>
21
- <div class="mb-10 no-print">
22
- <button title="Email article" class="bg-gray-600 text-gray-300 hover:text-white rounded mr-3 py-2 px-3 font-bold text-xs" onclick="window.open('mailto:?subject=<%= CGI.escape(@article.title) %>&body=<%= CGI.escape(article_url(@article.slug)) %>');"><i data-feather="send" class="inline h-4"></i> EMAIL THIS</button>
23
- <button title="Print article" class="bg-gray-600 text-gray-300 hover:text-white rounded mr-3 py-2 px-3 font-bold text-xs" onclick="window.print();"><i data-feather="printer" class="inline h-4"></i> PRINT THIS</button>
24
-
25
- <% if can_edit? %>
26
- <button title="Edit article" class="bg-blue-900 text-gray-300 hover:text-white rounded py-2 px-3 font-bold text-xs" onclick="location.href='<%= edit_article_path(@article.slug) %>';"><i data-feather="edit" class="inline h-4"></i> EDIT THIS</button>
27
- <% end %>
19
+ <div class="mb-8 no-print">
20
+ <button title="Copy link" class="bg-gray-600 text-gray-300 hover:text-white rounded my-2 mr-2 py-2 px-3 font-bold text-sm" onclick="copyToClipboard('<%= @article.permalink(request.base_url) %>');"><i data-feather="clipboard" class="inline h-5"></i> COPY</button>
21
+ <button title="Email article" class="bg-gray-600 text-gray-300 hover:text-white rounded my-2 mr-2 py-2 px-3 font-bold text-sm" onclick="window.open('mailto:?subject=<%= CGI.escape(@article.title.to_s) %>&body=<%= CGI.escape(article_url(@article.slug)) %>');"><i data-feather="send" class="inline h-5"></i> EMAIL</button>
22
+ <button title="Print article" class="bg-gray-600 text-gray-300 hover:text-white rounded my-2 py-2 px-3 font-bold text-sm" onclick="window.print();"><i data-feather="printer" class="inline h-5"></i> PRINT</button>
28
23
  </div>
29
24
 
30
25
  <div class="flex">
@@ -93,12 +88,11 @@
93
88
  </div>
94
89
  <% end %>
95
90
 
96
- <% if @article.categories.exists? %>
91
+ <% if (category_name_list = @article.category_name_list(context_category_id: @category&.id)).present? %>
97
92
  <div class="mt-5 flex no-print">
98
93
  <div class="no-print w-8"><i data-feather="folder" class="inline-block h-5"></i></div>
99
94
  <div class="w-full">
100
- <%= 'Category'.pluralize @article.categories.count %>:<br />
101
- <%= @article.category_name_list.split(':').last.html_safe %>
95
+ <%= category_name_list.sub(':', ':<br />').html_safe %>
102
96
  </div>
103
97
  </div>
104
98
  <% end %>
@@ -118,21 +112,22 @@
118
112
  <% if @article.summary.blank? && @article.markdown.blank? %>
119
113
  <div class="mb-10">No content</div>
120
114
  <% end %>
121
-
122
- <% if can_edit? %>
123
- <div class="no-print">
124
- <hr class="mt-5" />
125
- <div class="mt-10 text-right">
126
- <button title="Deactivate article" id="article-deactivate-button" class="bg-yellow-700 text-gray-300 hover:text-white rounded mr-3 py-2 px-3 font-bold text-xs <% if !@article.active %>hidden<% end %>" onclick="deactiveArticle('<%= @article.slug %>');"><i data-feather="sunset" class="inline h-4"></i> DEACTIVATE THIS</button>
127
- <button title="Re-activate article" id="article-activate-button" class="bg-green-700 text-gray-300 hover:text-white rounded mr-3 py-2 px-3 font-bold text-xs <% if @article.active %>hidden<% end %>" onclick="activeArticle('<%= @article.slug %>');"><i data-feather="sunrise" class="inline h-4"></i> RE-ACTIVATE THIS</button>
128
- <button title="Permanently delete article" class="bg-red-700 text-gray-300 hover:text-white rounded py-2 px-3 font-bold text-xs" onclick="deleteArticle('<%= @article.id %>');"><i data-feather="trash" class="inline h-4"></i> DELETE THIS</button>
129
- </div>
130
- </div>
131
- <% end %>
132
115
  </div>
133
116
  </div>
134
117
  </section>
135
118
 
136
- <% if @search_term.present? %>
137
- <script>highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight');</script>
119
+ <% if can_edit? %>
120
+ <div class="no-print">
121
+ <hr class="mt-5 mb-10" />
122
+ <div class="text-right">
123
+ <button title="Edit article" class="bg-blue-900 text-gray-300 hover:text-white rounded mr-5 py-2 px-3 font-bold text-sm" onclick="location.href='<%= edit_article_path(@article.slug) %>';"><i data-feather="edit" class="inline h-5"></i> EDIT</button>
124
+
125
+ <% if @article.active %>
126
+ <button title="Deactivate article" id="article-deactivate-button" class="bg-yellow-700 text-gray-300 hover:text-white rounded mr-5 py-2 px-3 font-bold text-base" onclick="deactivateArticle('<%= @article.slug %>');"><i data-feather="sunset" class="inline h-5"></i> DEACTIVATE</button>
127
+ <% else %>
128
+ <button title="Re-activate article" id="article-activate-button" class="bg-green-700 text-gray-300 hover:text-white rounded mr-5 py-2 px-3 font-bold text-base" onclick="activateArticle('<%= @article.slug %>');"><i data-feather="sunrise" class="inline h-5"></i> RE-ACTIVATE</button>
129
+ <% end %>
130
+ <button title="Permanently delete article" class="bg-red-700 text-gray-300 hover:text-white rounded py-2 px-3 font-bold text-base" onclick="deleteArticle('<%= @article.id %>');"><i data-feather="trash" class="inline h-5"></i> DELETE</button>
131
+ </div>
132
+ </div>
138
133
  <% end %>
@@ -4,23 +4,9 @@
4
4
  </div>
5
5
  <% end %>
6
6
 
7
- <div class="flex items-center mb-10">
8
- <% if Dokno::Category.exists? %>
9
- <div class="w-1/2 pr-5">
10
-
11
- <select aria-label="Category" name="category" id="category" size="1" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full max-w-full" onchange="changeCategory(this.value, elem('#search_term').value, '<%= @order %>');">
12
- <option value="">Select a category</option>
13
- <% cache Dokno::Category do %>
14
- <%= Dokno::Category.select_option_markup.html_safe %>
15
- <% end %>
16
- </select>
17
-
18
- </div>
19
- <% end %>
20
- <div class="w-<%= Dokno::Category.exists? ? '1/2 pl-5' : 'full' %>">
21
- <input onsearch="search(this.value, '<%= @order %>');" placeholder="Search article content, titles, and slugs" type="search" name="search_term" id="search_term" value="<%= @search_term %>" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full" />
22
- </div>
23
- </div>
7
+ <% if Dokno::Category.exists? || Dokno::Article.exists? %>
8
+ <%= render 'partials/category_header' %>
9
+ <% end %>
24
10
 
25
11
  <% if @articles.blank? %>
26
12
 
@@ -46,10 +32,10 @@
46
32
  </div>
47
33
  <div class="w-1/3 text-right">
48
34
  <i data-feather="corner-right-down" class="h-5 inline-block" title="Sort order"></i>
49
- <a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'updated' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=updated">Updated</a>
50
- <a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'newest' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=newest">Newest</a>
51
- <a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'views' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=views">Views</a>
52
- <a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'alpha' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=alpha">Title</a>
35
+ <a id="dokno-order-link-updated" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'updated' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=updated">Updated</a>
36
+ <a id="dokno-order-link-newest" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'newest' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=newest">Newest</a>
37
+ <a id="dokno-order-link-views" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'views' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=views">Views</a>
38
+ <a id="dokno-order-link-alpha" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'alpha' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=alpha">Title</a>
53
39
  </div>
54
40
  </div>
55
41
 
@@ -60,7 +46,7 @@
60
46
  <div class="flex">
61
47
  <div class="no-print w-10 text-gray-300"><i data-feather="chevron-right" class="inline-block"></i></div>
62
48
  <div class="w-full">
63
- <a class="" href="<%= article_path article.slug %>?search_term=<%= @search_term %>" title="View article"><%= article.title %></a>
49
+ <a class="dokno-article-title <% unless article.active %>text-gray-500 italic<% end %>" href="<%= article_path article.slug %>?search_term=<%= @search_term %>&cat_code=<%= @category&.code %>&order=<%= @order %>" title="View article"><%= article.title %></a>
64
50
  </div>
65
51
  </div>
66
52
  </div>
@@ -71,10 +57,14 @@
71
57
  </div>
72
58
  <% end %>
73
59
 
74
- <span class="dokno-article-content-highlight"><%= article.summary.presence || 'No summary provided' %></span>
60
+ <div class="dokno-article-content-highlight mb-2"><%= article.summary.presence || 'No summary provided' %></div>
61
+
62
+ <div class="text-base text-gray-500">
63
+ <%= article.category_name_list(context_category_id: @category&.id, order: @order, search_term: @search_term) %>
64
+ </div>
75
65
 
76
66
  <% unless @order == 'alpha' %>
77
- <div class="text-base mt-2">
67
+ <div class="text-base">
78
68
  <% if @order == 'views' %>
79
69
  <div class="text-gray-500">Viewed <%= number_with_delimiter(article.views, delimiter: ',') %> <%= 'time'.pluralize(article.views) %></div>
80
70
  <% elsif @order == 'updated' %>
@@ -97,11 +87,6 @@
97
87
  </div>
98
88
  <% end %>
99
89
 
100
- <script>
101
- // Client-side select of cached select list
102
- selectOption('category', '<%= j @category&.code %>');
103
- </script>
104
-
105
- <% if @search_term.present? %>
106
- <script> highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight'); </script>
90
+ <% if @search_term.present? && @articles.blank? %>
91
+ <script> handleSearchHotKey(); </script>
107
92
  <% end %>
@@ -12,7 +12,7 @@
12
12
  var dokno__base_path = '<%= root_path %>';
13
13
  </script>
14
14
  </head>
15
- <body class="bg-white font-sans font-light subpixel-antialiased">
15
+ <body class="bg-white font-sans font-light subpixel-antialiased text-lg">
16
16
 
17
17
  <nav id="dokno-nav-container" class="bg-blue-900 text-white py-10 px-16 text-lg">
18
18
  <div class="flex items-center m-auto w-full max-w-screen-xl">
@@ -40,6 +40,13 @@
40
40
  </div>
41
41
  </nav>
42
42
 
43
+ <% flash.each do |color, msg| %>
44
+ <div class="bg-<%= color %>-700 text-lg text-white font-base py-10 px-16">
45
+ <i data-feather="<%= (color == 'green' ? 'check-circle' : (color == 'yellow' ? 'alert-circle' : 'x-circle')) %>" class="inline mr-2"></i>
46
+ <%= msg %>
47
+ </div>
48
+ <% end %>
49
+
43
50
  <main class="py-10 px-16">
44
51
  <% if @article.blank? && (@category.blank? || @search_term.present?) %>
45
52
  <div class="text-center m-auto mb-10 w-full max-w-screen-xl">
@@ -63,13 +70,6 @@
63
70
  <% end %>
64
71
 
65
72
  <div id="dokno-content-container" class="w-full max-w-screen-xl m-auto print-this">
66
- <% flash.each do |color, msg| %>
67
- <div class="bg-<%= color %>-700 p-4 mb-5 rounded text-lg border-t-4 border-<%= color %>-900 text-white font-base">
68
- <i data-feather="<%= (color == 'green' ? 'check-circle' : (color == 'yellow' ? 'alert-circle' : 'x-circle')) %>" class="inline mr-2"></i>
69
- <%= msg %>
70
- </div>
71
- <% end %>
72
-
73
73
  <%= yield %>
74
74
  </div>
75
75
  </main>
@@ -101,5 +101,9 @@
101
101
  </footer>
102
102
 
103
103
  <%= javascript_include_tag 'init' %>
104
+
105
+ <% if @search_term.present? %>
106
+ <script>highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight');</script>
107
+ <% end %>
104
108
  </body>
105
109
  </html>
@@ -0,0 +1,29 @@
1
+ <div class="no-print flex items-center mb-10">
2
+ <% if Dokno::Category.exists? %>
3
+ <div class="w-1/2 pr-5">
4
+ <select aria-label="Category" name="category" id="category" size="1" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full max-w-full" onchange="applyCategoryCriteria(this.value, elem('#search_term').value, '<%= @order %>');">
5
+ <option value="">Uncategorized</option>
6
+
7
+ <optgroup label="Categories">
8
+ <% cache Dokno::Category do %>
9
+ <%= Dokno::Category.select_option_markup.html_safe %>
10
+ <% end %>
11
+ </optgroup>
12
+ </select>
13
+ </div>
14
+ <% end %>
15
+
16
+ <% if Dokno::Article.exists? %>
17
+ <div class="relative w-<%= Dokno::Category.exists? ? '1/2 pl-5' : 'full' %>">
18
+ <i data-feather="search" class="absolute ml-4 mt-3 inline-block text-gray-300" title="Search"></i>
19
+ <input title="Press / to search" onsearch="applyCategoryCriteria('<%= @category&.code %>', this.value, '<%= @order %>');" onfocus="disableSearchHotkey();" onblur="enableSearchHotkey();" placeholder="Search<%= @category.present? ? ' under this category' : ', hotkey /' %>" type="search" name="search_term" id="search_term" value="<%= @search_term %>" class="pl-12 pr-8 py-2 rounded text-xl shadow-inner bg-gray-100 w-full" />
20
+ <% if @category.present? %><div title="Press / to search" class="absolute -ml-6 mt-2 inline-block text-gray-300 font-semibold">/</div><% end %>
21
+ </div>
22
+ <% end %>
23
+ </div>
24
+
25
+ <script>
26
+ // Client-side select of cached select list
27
+ selectOption('category', '<%= j @category&.code %>');
28
+ enableSearchHotkey();
29
+ </script>
@@ -1,5 +1,4 @@
1
1
  <div id="error_explanation" class="bg-white mb-10">
2
- <i data-feather="alert-octagon" class="float-right"></i>
3
2
  <h2 class="font-semibold">
4
3
  There
5
4
  <% if errors.count == 1 %>
@@ -2,7 +2,7 @@
2
2
  <div class="py-10 px-16 text-gray-200 bg-gray-900">
3
3
  <div class="w-full max-w-screen-xl m-auto">
4
4
  <div class="text-xl text-gray-600 cursor-pointer" onclick="toggleVisibility('change-log');">
5
- Change log for this article
5
+ Change history for this article
6
6
 
7
7
  <div class="inline toggle-visibility-indicator-container change-log">
8
8
  <i data-feather="chevron-left" class="inline toggle-visibility-indicator change-log"></i>
@@ -4,7 +4,6 @@ Dokno::Engine.routes.draw do
4
4
 
5
5
  get '/(:cat_code)', to: 'categories#index', as: :article_index
6
6
  get 'article_panel/(:slug)', to: 'articles#panel', as: :panel
7
- post 'article_log', to: 'articles#article_log', as: :article_log
8
7
  post 'article_preview', to: 'articles#preview', as: :preview
9
8
  post 'article_status', to: 'articles#status', as: :status
10
9
  root 'categories#index'
@@ -1,3 +1,3 @@
1
1
  module Dokno
2
- VERSION = '1.1.1'
2
+ VERSION = '1.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dokno
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Courtney Payne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-06 00:00:00.000000000 Z
11
+ date: 2020-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diffy
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bullet
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '6.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '6.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: capybara
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.34'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.34'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: database_cleaner-active_record
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,20 @@ dependencies:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
82
  version: '1.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faker
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.15'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.15'
55
97
  - !ruby/object:Gem::Dependency
56
98
  name: pg
57
99
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +128,20 @@ dependencies:
86
128
  - - "~>"
87
129
  - !ruby/object:Gem::Version
88
130
  version: '3.9'
131
+ - !ruby/object:Gem::Dependency
132
+ name: puma
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '5.1'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '5.1'
89
145
  - !ruby/object:Gem::Dependency
90
146
  name: rails
91
147
  requirement: !ruby/object:Gem::Requirement
@@ -127,47 +183,59 @@ dependencies:
127
183
  - !ruby/object:Gem::Version
128
184
  version: 4.0.1
129
185
  - !ruby/object:Gem::Dependency
130
- name: simplecov
186
+ name: selenium-webdriver
131
187
  requirement: !ruby/object:Gem::Requirement
132
188
  requirements:
133
189
  - - "~>"
134
190
  - !ruby/object:Gem::Version
135
- version: 0.19.1
191
+ version: '3.142'
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: 3.142.7
136
195
  type: :development
137
196
  prerelease: false
138
197
  version_requirements: !ruby/object:Gem::Requirement
139
198
  requirements:
140
199
  - - "~>"
141
200
  - !ruby/object:Gem::Version
142
- version: 0.19.1
201
+ version: '3.142'
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: 3.142.7
143
205
  - !ruby/object:Gem::Dependency
144
- name: bullet
206
+ name: simplecov
145
207
  requirement: !ruby/object:Gem::Requirement
146
208
  requirements:
147
209
  - - "~>"
148
210
  - !ruby/object:Gem::Version
149
- version: '6.1'
211
+ version: 0.19.1
150
212
  type: :development
151
213
  prerelease: false
152
214
  version_requirements: !ruby/object:Gem::Requirement
153
215
  requirements:
154
216
  - - "~>"
155
217
  - !ruby/object:Gem::Version
156
- version: '6.1'
218
+ version: 0.19.1
157
219
  - !ruby/object:Gem::Dependency
158
- name: faker
220
+ name: webdrivers
159
221
  requirement: !ruby/object:Gem::Requirement
160
222
  requirements:
161
223
  - - "~>"
162
224
  - !ruby/object:Gem::Version
163
- version: '2.15'
225
+ version: '4.4'
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ version: 4.4.1
164
229
  type: :development
165
230
  prerelease: false
166
231
  version_requirements: !ruby/object:Gem::Requirement
167
232
  requirements:
168
233
  - - "~>"
169
234
  - !ruby/object:Gem::Version
170
- version: '2.15'
235
+ version: '4.4'
236
+ - - ">="
237
+ - !ruby/object:Gem::Version
238
+ version: 4.4.1
171
239
  description: Dokno allows you to easily mount a self-contained knowledgebase / wiki
172
240
  / help system to your Rails app.
173
241
  email:
@@ -210,6 +278,7 @@ files:
210
278
  - app/views/dokno/categories/index.html.erb
211
279
  - app/views/dokno/categories/new.html.erb
212
280
  - app/views/layouts/dokno/application.html.erb
281
+ - app/views/partials/_category_header.html.erb
213
282
  - app/views/partials/_form_errors.html.erb
214
283
  - app/views/partials/_logs.html.erb
215
284
  - app/views/partials/_pagination.html.erb