dokno 1.1.1 → 1.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
  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