dokno 1.0.0 → 1.3.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -6
  3. data/app/assets/javascripts/dokno.js +79 -27
  4. data/app/assets/stylesheets/dokno/application.css +1 -1
  5. data/app/controllers/dokno/application_controller.rb +3 -0
  6. data/app/controllers/dokno/articles_controller.rb +22 -8
  7. data/app/controllers/dokno/categories_controller.rb +15 -2
  8. data/app/controllers/dokno/user_concern.rb +5 -3
  9. data/app/helpers/dokno/application_helper.rb +1 -3
  10. data/app/models/dokno/article.rb +87 -38
  11. data/app/models/dokno/category.rb +39 -15
  12. data/app/views/dokno/_article_formatting.html.erb +17 -18
  13. data/app/views/dokno/_article_panel.html.erb +16 -18
  14. data/app/views/dokno/_panel_formatting.html.erb +47 -57
  15. data/app/views/dokno/articles/_article_form.html.erb +47 -6
  16. data/app/views/dokno/articles/show.html.erb +45 -39
  17. data/app/views/dokno/categories/_category_form.html.erb +6 -1
  18. data/app/views/dokno/categories/index.html.erb +40 -37
  19. data/app/views/layouts/dokno/application.html.erb +34 -9
  20. data/app/views/partials/_category_header.html.erb +29 -0
  21. data/app/views/partials/_form_errors.html.erb +0 -1
  22. data/app/views/partials/_logs.html.erb +7 -5
  23. data/app/views/partials/_pagination.html.erb +20 -18
  24. data/config/routes.rb +1 -1
  25. data/db/migrate/20201203190330_baseline.rb +4 -4
  26. data/db/migrate/20201211192306_add_review_due_at_to_articles.rb +6 -0
  27. data/db/migrate/20201213165700_add_starred_to_article.rb +5 -0
  28. data/lib/dokno/config/config.rb +53 -40
  29. data/lib/dokno/engine.rb +4 -4
  30. data/lib/dokno/version.rb +1 -1
  31. data/lib/generators/dokno/templates/config/initializers/dokno.rb +18 -5
  32. metadata +87 -17
@@ -1,26 +1,32 @@
1
1
  <%= render 'dokno/article_formatting' %>
2
2
 
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 %>
8
+
9
+ <%= render 'partials/category_header' %>
10
+
11
+ <div class="my-10 no-print"><hr /></div>
12
+
3
13
  <section>
4
14
  <div class="flex">
5
15
  <div id="dokno-article-sidebar" class="w-2/5 pr-10">
6
- <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">
7
- <i data-feather="alert-circle" class="inline-block mr-2"></i> This article is no longer active
8
- </div>
9
-
10
- <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">
17
+ <%= @article.title %>
18
+ <% if @article.starred %><i title="Starred article" data-feather="star" class="inline align-middle"></i><% end %>
19
+ </h1>
11
20
 
12
21
  <div>
13
- <div class="mb-10 no-print">
14
- <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>
15
- <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>
16
-
17
- <% if can_edit? %>
18
- <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>
19
- <% end %>
22
+ <div class="mb-8 no-print">
23
+ <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>
24
+ <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>
25
+ <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>
20
26
  </div>
21
27
 
22
28
  <div class="flex">
23
- <div class="no-print w-8"><i data-feather="clock" class="inline-block h-5"></i></div>
29
+ <div class="no-print w-8"><i data-feather="clock" class="inline-block h-5 mr-2"></i></div>
24
30
  <div class="w-full">
25
31
  Last updated:<br />
26
32
  <%= time_ago_in_words @article.updated_at %> ago
@@ -30,8 +36,8 @@
30
36
  </div>
31
37
  </div>
32
38
 
33
- <div class="mt-5 flex">
34
- <div class="no-print w-8"><i data-feather="eye" class="inline-block h-5"></i></div>
39
+ <div class="mt-5 flex no-print">
40
+ <div class="no-print w-8"><i data-feather="eye" class="inline-block h-5 mr-2"></i></div>
35
41
  <div class="w-full">
36
42
  Views:<br />
37
43
  <%= number_with_delimiter(@article.views, delimiter: ',') %>
@@ -40,7 +46,7 @@
40
46
 
41
47
  <% if @article.contributors.present? %>
42
48
  <div class="mt-5 flex">
43
- <div class="no-print w-8"><i data-feather="user-check" class="inline-block h-5"></i></div>
49
+ <div class="no-print w-8"><i data-feather="user-check" class="inline-block h-5 mr-2"></i></div>
44
50
  <div class="w-full">
45
51
  Contributors:<br />
46
52
  <%= @article.contributors %>
@@ -49,8 +55,8 @@
49
55
  <% end %>
50
56
 
51
57
  <% if @article.reading_time.present? %>
52
- <div class="mt-5 flex">
53
- <div class="no-print w-8"><i data-feather="watch" class="inline-block h-5"></i></div>
58
+ <div class="mt-5 flex no-print">
59
+ <div class="no-print w-8"><i data-feather="watch" class="inline-block h-5 mr-2"></i></div>
54
60
  <div class="w-full">
55
61
  Reading time:<br />
56
62
  <%= @article.reading_time %>
@@ -59,7 +65,7 @@
59
65
  <% end %>
60
66
 
61
67
  <div class="mt-5 flex">
62
- <div class="no-print w-8"><i data-feather="link" class="inline-block h-5"></i></div>
68
+ <div class="no-print w-8"><i data-feather="link" class="inline-block h-5 mr-2"></i></div>
63
69
  <div class="w-full">
64
70
  Permalink:<br />
65
71
  <a class="inline-block mt-1 -ml-2 px-2 py-1 bg-blue-100 rounded" title="Copy to clipboard" href="javascript:;" onclick="copyToClipboard('<%= @article.permalink(request.base_url) %>');"><%= @article.permalink(request.base_url) %></a>
@@ -67,8 +73,8 @@
67
73
  </div>
68
74
 
69
75
  <% if can_edit? %>
70
- <div class="mt-5 flex">
71
- <div class="no-print w-8"><i data-feather="crosshair" class="inline-block h-5"></i></div>
76
+ <div class="mt-5 flex no-print">
77
+ <div class="no-print w-8"><i data-feather="crosshair" class="inline-block h-5 mr-2"></i></div>
72
78
  <div class="w-full">
73
79
  Unique slug:<br />
74
80
  <a class="inline-block mt-1 -ml-2 px-2 py-1 bg-blue-100 rounded" title="Copy to clipboard" href="javascript:;" onclick="copyToClipboard('<%= j @article.slug %>');"><%= @article.slug %></a>
@@ -85,12 +91,11 @@
85
91
  </div>
86
92
  <% end %>
87
93
 
88
- <% if @article.categories.exists? %>
89
- <div class="mt-5 flex">
90
- <div class="no-print w-8"><i data-feather="folder" class="inline-block h-5"></i></div>
94
+ <% if (category_name_list = @article.category_name_list(context_category_id: @category&.id)).present? %>
95
+ <div class="mt-5 flex no-print">
96
+ <div class="no-print w-8"><i data-feather="folder" class="inline-block h-5 mr-2"></i></div>
91
97
  <div class="w-full">
92
- <%= 'Category'.pluralize @article.categories.count %>:<br />
93
- <%= @article.category_name_list.split(':').last.html_safe %>
98
+ <%= category_name_list.sub(':', ':<br />').html_safe %>
94
99
  </div>
95
100
  </div>
96
101
  <% end %>
@@ -110,21 +115,22 @@
110
115
  <% if @article.summary.blank? && @article.markdown.blank? %>
111
116
  <div class="mb-10">No content</div>
112
117
  <% end %>
113
-
114
- <% if can_edit? %>
115
- <div class="no-print">
116
- <hr class="mt-5" />
117
- <div class="mt-10 text-right">
118
- <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>
119
- <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>
120
- <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>
121
- </div>
122
- </div>
123
- <% end %>
124
118
  </div>
125
119
  </div>
126
120
  </section>
127
121
 
128
- <% if @search_term.present? %>
129
- <script>highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight');</script>
122
+ <% if can_edit? %>
123
+ <div class="no-print">
124
+ <hr class="mt-5 mb-10" />
125
+ <div class="text-right">
126
+ <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-2" class="inline h-5"></i> EDIT</button>
127
+
128
+ <% if @article.active %>
129
+ <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="file-minus" class="inline h-5"></i> DEACTIVATE</button>
130
+ <% else %>
131
+ <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="file-plus" class="inline h-5"></i> RE-ACTIVATE</button>
132
+ <% end %>
133
+ <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="slash" class="inline h-5"></i> DELETE</button>
134
+ </div>
135
+ </div>
130
136
  <% end %>
@@ -28,6 +28,11 @@
28
28
 
29
29
  <div class="mt-10">
30
30
  <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 CATEGORY</button>
31
- <span class="text-lg ml-5"><a class="no-underline" href="<%= category.persisted? ? "#{root_path}?id=#{category.id}" : root_path %>">Cancel</a></span>
31
+ <% if category.persisted? %>
32
+ <button type="button" class="bg-red-700 text-gray-300 hover:bg-red-900 hover:text-white rounded py-2 px-3 font-bold ml-5" onclick="deleteCategory('<%= category.id %>');"><i data-feather="trash" class="inline h-5"></i> DELETE</button>
33
+ <% end %>
34
+ <span class="text-lg ml-5"><a class="no-underline" href="<%= category.persisted? ? "#{dokno.article_index_path(category.code)}" : root_path %>">Cancel</a></span>
32
35
  </div>
33
36
  </section>
37
+
38
+ <script> elem('input#name').focus(); </script>
@@ -1,20 +1,12 @@
1
-
2
- <div class="flex items-center mb-10">
3
- <% if Dokno::Category.exists? %>
4
- <div class="w-1/2 pr-5">
5
- <select name="category" id="category" size="1" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full max-w-full" onchange="location.href='<%= article_index_path %>' + this.value + '?search_term=' + elem('#search_term').value + '&order=<%= @order %>';">
6
- <option value="">Select a category</option>
7
- <%= Dokno::Category.select_option_markup(selected_category_codes: [@category&.code]).html_safe %>
8
- </select>
9
- </div>
10
- <% end %>
11
- <div class="w-<%= Dokno::Category.exists? ? '1/2 pl-5' : 'full' %>">
12
- <%= form_with(url: article_index_path(@category&.code), method: :get) do %>
13
- <input type="hidden" name="order" value="<%= @order %>">
14
- <input placeholder="Search article content, titles, and slugs" type="text" name="search_term" id="search_term" value="<%= @search_term %>" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full" />
15
- <% end %>
1
+ <% if @category&.parent.present? %>
2
+ <div class="text-gray-500 mb-5">
3
+ <div><%= @category.breadcrumb %></div>
16
4
  </div>
17
- </div>
5
+ <% end %>
6
+
7
+ <% if !current_page?(up_for_review_path) && (Dokno::Category.exists? || Dokno::Article.exists?) %>
8
+ <%= render 'partials/category_header' %>
9
+ <% end %>
18
10
 
19
11
  <% if @articles.blank? %>
20
12
 
@@ -40,44 +32,55 @@
40
32
  </div>
41
33
  <div class="w-1/3 text-right">
42
34
  <i data-feather="corner-right-down" class="h-5 inline-block" title="Sort order"></i>
43
- <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>
44
- <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>
45
- <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>
46
- <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>
47
39
  </div>
48
40
  </div>
49
41
 
50
42
  <div id="dokno-article-list">
51
- <% @articles.each_with_index do |article, i| %>
43
+ <% @articles.each do |article| %>
52
44
  <section class="border-t border-gray-300 py-10 text-xl flex">
53
45
  <div class="w-1/3 pr-10">
54
46
  <div class="flex">
55
- <div class="no-print w-10 text-gray-300"><i data-feather="chevron-right" class="inline-block"></i></div>
47
+ <div title="<%= 'Starred article' if article.starred %>" class="no-print w-10 text-gray-300"><i data-feather="<%= article.starred ? 'star' : 'chevron-right' %>" class="inline-block"></i></div>
56
48
  <div class="w-full">
57
- <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>
58
50
  </div>
59
51
  </div>
60
52
  </div>
61
53
  <div class="dokno-article-summary w-2/3 <% unless article.active %>text-gray-500 italic<% end %>">
62
54
  <% unless article.active %>
63
55
  <div class="bg-yellow-700 p-4 mb-5 rounded text-lg border-t-4 border-yellow-900 text-white font-base not-italic">
64
- <i data-feather="alert-circle" class="inline-block"></i> This article is no longer active
56
+ <i data-feather="info" class="inline-block"></i> This article is no longer active
65
57
  </div>
66
58
  <% end %>
67
59
 
68
- <span class="dokno-article-content-highlight"><%= article.summary.presence || 'No summary provided' %></span>
69
-
70
- <div class="text-base mt-2">
71
- <div class="text-gray-500"><%= article.category_name_list(context_category_id: @category&.id, order: @order, search_term: @search_term) %></div>
60
+ <div class="dokno-article-content-highlight mb-2"><%= article.summary.presence || 'No summary provided' %></div>
72
61
 
73
- <% if @order == 'views' %>
74
- <div class="text-gray-500">Viewed <%= number_with_delimiter(article.views, delimiter: ',') %> <%= 'time'.pluralize(article.views) %></div>
75
- <% elsif @order == 'updated' %>
76
- <div class="text-gray-500">Last updated <%= time_ago_in_words article.updated_at %> ago</div>
77
- <% elsif @order == 'newest' %>
78
- <div class="text-gray-500">Added <%= time_ago_in_words article.created_at %> ago</div>
79
- <% end %>
62
+ <div class="text-base text-gray-500">
63
+ <%= article.category_name_list(context_category_id: @category&.id, order: @order, search_term: @search_term) %>
80
64
  </div>
65
+
66
+ <% unless @order == 'alpha' %>
67
+ <div class="text-base">
68
+ <% if @order == 'views' %>
69
+ <div class="text-gray-500">This article was viewed <%= number_with_delimiter(article.views, delimiter: ',') %> <%= 'time'.pluralize(article.views) %></div>
70
+ <% elsif @order == 'updated' %>
71
+ <div class="text-gray-500">This article was last updated <%= time_ago_in_words article.updated_at %> ago</div>
72
+ <% elsif @order == 'newest' %>
73
+ <div class="text-gray-500">This article was added <%= time_ago_in_words article.created_at %> ago</div>
74
+ <% end %>
75
+ </div>
76
+ <% end %>
77
+
78
+ <% if article.up_for_review? %>
79
+ <div class="bg-<%= article.review_due_days.negative? ? 'red' : 'gray' %>-800 p-4 mt-5 rounded text-lg border-t-4 border-<%= article.review_due_days.negative? ? 'red' : 'gray' %>-900 text-white font-base not-italic">
80
+ <i data-feather="bell" class="inline-block mr-1"></i> <%= article.review_due_days_string %>
81
+ </div>
82
+ <% end %>
83
+
81
84
  </div>
82
85
  </section>
83
86
  <% end %>
@@ -91,6 +94,6 @@
91
94
  </div>
92
95
  <% end %>
93
96
 
94
- <% if @search_term.present? %>
95
- <script>highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight');</script>
97
+ <% if @search_term.present? && @articles.blank? %>
98
+ <script> handleSearchHotKey(); </script>
96
99
  <% end %>
@@ -2,6 +2,8 @@
2
2
  <html>
3
3
  <head>
4
4
  <title><%= Dokno.config.app_name %> KNOWLEDGEBASE</title>
5
+
6
+ <meta name="viewport" content="width=device-width,initial-scale=1">
5
7
  <%= csrf_meta_tags %>
6
8
  <%= csp_meta_tag %>
7
9
 
@@ -12,7 +14,7 @@
12
14
  var dokno__base_path = '<%= root_path %>';
13
15
  </script>
14
16
  </head>
15
- <body class="bg-white font-sans font-light subpixel-antialiased">
17
+ <body class="bg-white font-sans font-light subpixel-antialiased text-lg">
16
18
 
17
19
  <nav id="dokno-nav-container" class="bg-blue-900 text-white py-10 px-16 text-lg">
18
20
  <div class="flex items-center m-auto w-full max-w-screen-xl">
@@ -24,12 +26,12 @@
24
26
  <div class="w-2/3 text-right">
25
27
  <% if can_edit? %>
26
28
  <% if action_name != 'new' %>
27
- <button title="Add a new article" class="bg-gray-700 text-gray-300 hover:text-white hover:bg-gray-900 rounded ml-3 py-2 px-3 font-bold text-base" onclick="location.href='<%= new_article_path %>/?category_code=<%= @category&.code %>';"><i data-feather="plus-circle" class="inline h-5"></i> ARTICLE</button>
28
- <button title="Add a new category" class="bg-gray-700 text-gray-300 hover:text-white hover:bg-gray-900 rounded ml-3 py-2 px-3 font-bold text-base" onclick="location.href='<%= new_category_path %>/?parent_category_code=<%= @category&.code %>';"><i data-feather="plus-circle" class="inline h-5"></i> CATEGORY</button>
29
+ <button title="Add a new article" class="bg-gray-700 text-gray-300 hover:text-white hover:bg-gray-900 rounded ml-3 py-2 px-3 font-bold text-base" onclick="location.href='<%= new_article_path %>/?category_code=<%= @category&.code %>';"><i data-feather="plus" class="inline h-5"></i> ARTICLE</button>
30
+ <button title="Add a new category" class="bg-gray-700 text-gray-300 hover:text-white hover:bg-gray-900 rounded ml-3 py-2 px-3 font-bold text-base" onclick="location.href='<%= new_category_path %>/?parent_category_code=<%= @category&.code %>';"><i data-feather="plus" class="inline h-5"></i> CATEGORY</button>
29
31
  <% end %>
30
32
 
31
33
  <% if @category&.persisted? && action_name != 'edit' %>
32
- <button title="Edit this category" class="bg-gray-700 text-gray-100 hover:text-white hover:bg-gray-900 rounded ml-3 py-2 px-3 font-bold text-base" onclick="location.href='<%= edit_category_path(@category) %>';"><i data-feather="edit" class="inline h-5"></i> CATEGORY</button>
34
+ <button title="Edit this category" class="bg-gray-700 text-gray-100 hover:text-white hover:bg-gray-900 rounded ml-3 py-2 px-3 font-bold text-base" onclick="location.href='<%= edit_category_path(@category) %>';"><i data-feather="edit-2" class="inline h-5"></i> CATEGORY</button>
33
35
  <% end %>
34
36
  <% end %>
35
37
 
@@ -40,12 +42,19 @@
40
42
  </div>
41
43
  </nav>
42
44
 
45
+ <% flash.each do |type, msg| %>
46
+ <div class="bg-<%= type %>-800 text-lg text-white font-base py-10 px-16 text-center">
47
+ <i data-feather="<%= (type == 'green' ? 'smile' : (type == 'yellow' ? 'info' : (type == 'gray' ? 'bell' : 'frown'))) %>" class="inline mr-1"></i>
48
+ <%= sanitize(msg, tags: %w[a], attributes: %w[href class]) %>
49
+ </div>
50
+ <% end %>
51
+
43
52
  <main class="py-10 px-16">
44
- <% if @article.blank? && (@category.blank? || @search_term.present?) %>
53
+ <% if !current_page?(up_for_review_path) && @article.blank? && (@category.blank? || @search_term.present?) %>
45
54
  <div class="text-center m-auto mb-10 w-full max-w-screen-xl">
46
55
  <% if @search_term.present? %>
47
56
  <div class="text-gray-600 text-2xl uppercase">
48
- <%= (article_count = @articles.count).positive? ? "#{article_count} #{'article'.pluralize(article_count)}" : 'No articles' %>
57
+ <%= @total_records.positive? ? "#{@total_records} #{'article'.pluralize(@total_records)}" : 'No articles' %>
49
58
  found containing the search term
50
59
  <div class="text-4xl leading-tight"><span class="font-serif">&ldquo;</span> <%= @search_term %> <span class="font-serif">&rdquo;</span> </div>
51
60
  </div>
@@ -69,16 +78,29 @@
69
78
 
70
79
  <footer id="dokno-footer-container">
71
80
  <% if @article.present? && action_name == 'show' %>
72
- <div id="dokno-article-log-container" data-category-id="<%= @category&.id %>" data-article-id="<%= @article&.id %>">
81
+ <div id="dokno-article-log-container" data-category-id="<%= @category&.id %>" data-article-id="<%= @article.id %>">
73
82
  <%= render 'partials/logs', category: @category, article: @article %>
74
83
  </div>
75
84
  <% end %>
76
85
 
86
+ <% if can_edit? && !current_page?(up_for_review_path) && action_name == 'index' && (up_for_review_count = Dokno::Article.up_for_review.count).positive? %>
87
+ <div id="dokno-articles-up-for-review-container">
88
+ <div class="py-10 px-16 bg-gray-900">
89
+ <div class="w-full max-w-screen-xl m-auto">
90
+ <div class="text-xl text-white cursor-pointer" onclick="location.href='<%= up_for_review_path %>';">
91
+ <i data-feather="bell" class="inline mr-1"></i>
92
+ There <%= "#{up_for_review_count == 1 ? 'is' : 'are'} #{up_for_review_count}" %> <%= 'article'.pluralize(up_for_review_count) %> up for accuracy / relevance review
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ <% end %>
77
98
 
78
99
  <div class="py-10 px-16 text-gray-400 bg-blue-900">
79
100
  <div class="w-full max-w-screen-xl m-auto flex">
80
101
  <div class="w-1/2">
81
- <a target="_blank" href="https://github.com/cpayne624/dokno" title="Knowledgebase">dokno</a>
102
+ <i data-feather="github" class="inline mr-1"></i>
103
+ <a target="_blank" href="https://github.com/cpayne624/dokno" title="Dokno on GitHub">dokno</a>
82
104
  </div>
83
105
  <div class="w-1/2 text-right">
84
106
  <% if user.present? %>
@@ -92,9 +114,12 @@
92
114
  </div>
93
115
  </div>
94
116
  </div>
95
-
96
117
  </footer>
97
118
 
98
119
  <%= javascript_include_tag 'init' %>
120
+
121
+ <% if @search_term.present? %>
122
+ <script>highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight');</script>
123
+ <% end %>
99
124
  </body>
100
125
  </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>
@@ -20,7 +20,7 @@
20
20
  <% end %>
21
21
 
22
22
  <div class="text-gray-500 bg-gray-700 p-5 pr-10 rounded <%= 'cursor-pointer' if log.diff_left != log.diff_right %> flex items-center" onclick="toggleVisibility('article-diff-<%= log.id %>');" title="Show / Hide Diff">
23
- <div class="w-4/5">
23
+ <div class="w-<%= log.diff_left != log.diff_right ? '11/12' : 'full' %>">
24
24
  <%= time_ago_in_words log.created_at %> ago
25
25
  <% if log.username.present? %>
26
26
  by <%= log.username %>
@@ -31,9 +31,11 @@
31
31
  <% end %>
32
32
  </div>
33
33
 
34
- <div class="w-1/5 text-right toggle-visibility-indicator-container article-diff-<%= log.id %>">
35
- <% if log.diff_left != log.diff_right %><i data-feather="chevron-left" class="inline toggle-visibility-indicator article-diff-<%= log.id %>"></i><% end %>
36
- </div>
34
+ <% if log.diff_left != log.diff_right %>
35
+ <div class="w-1/12 text-right toggle-visibility-indicator-container article-diff-<%= log.id %>">
36
+ <i data-feather="chevron-left" class="inline toggle-visibility-indicator article-diff-<%= log.id %>"></i>
37
+ </div>
38
+ <% end %>
37
39
  </div>
38
40
 
39
41
  <% if log.diff_left != log.diff_right %>
@@ -1,29 +1,31 @@
1
- <span class="mr-5">
2
- <% if @page > 1 %>
3
- <span class="mr-1 inline-block"><a href="?search_term=<%= CGI.escape @search_term.to_s %>&order=<%= @order %>&page=<%= (@page - 1) %>"><i data-feather="arrow-left" class="h-5 inline-block" title="Previous page"></i></a></span>
4
- <% end %>
1
+ <% if @total_pages > 1 %>
2
+ <span class="mr-5">
3
+ <% if @page > 1 %>
4
+ <span class="mr-1 inline-block"><a href="?search_term=<%= CGI.escape @search_term.to_s %>&order=<%= @order %>&page=<%= (@page - 1) %>"><i data-feather="arrow-left" class="h-5 inline-block" title="Previous page"></i></a></span>
5
+ <% end %>
5
6
 
6
- <span class="mr-1 inline-block">Page</span>
7
+ <span class="mr-1 inline-block">Page</span>
7
8
 
8
- <%= form_with(url: article_index_path, method: :get, class: 'inline') do %>
9
- <input type="hidden" name="id" value="<%= @category&.id %>">
10
- <input type="hidden" name="search_term" value="<%= @search_term %>">
11
- <input type="hidden" name="order" value="<%= @order %>">
12
- <input type="text" name="page" id="page" value="<%= @page %>" onclick="this.select();" class="w-10 text-center bg-gray-200 rounded" />
9
+ <%= form_with(url: article_index_path(@category&.code), method: :get, class: 'inline') do %>
10
+ <input type="hidden" name="search_term" value="<%= @search_term %>">
11
+ <input type="hidden" name="order" value="<%= @order %>">
12
+ <input aria-label="Page" type="text" name="page" value="<%= @page %>" onclick="this.select();" class="w-10 text-center bg-gray-200 rounded" />
13
13
 
14
- <span class="mx-1 inline-block">of</span>
15
- <span class="text-center inline-block"><%= @total_pages %></span>
16
- <% end %>
14
+ <span class="mx-1 inline-block">of</span>
15
+ <span class="text-center inline-block"><%= @total_pages %></span>
16
+ <% end %>
17
17
 
18
- <% if @page < @total_pages %>
19
- <span class="ml-1 inline-block"><a href="?search_term=<%= CGI.escape @search_term.to_s %>&order=<%= @order %>&page=<%= (@page + 1) %>"><i data-feather="arrow-right" class="h-5 inline-block" title="Next page"></i></a></span>
20
- <% end %>
21
- </span>
18
+ <% if @page < @total_pages %>
19
+ <span class="ml-1 inline-block"><a href="?search_term=<%= CGI.escape @search_term.to_s %>&order=<%= @order %>&page=<%= (@page + 1) %>"><i data-feather="arrow-right" class="h-5 inline-block" title="Next page"></i></a></span>
20
+ <% end %>
21
+ </span>
22
+ <% end %>
22
23
 
23
24
  <span class="text-gray-400">
24
25
  <%= @total_records %>
25
- <%= 'uncategorized' if @category.blank? && @search_term.blank? %>
26
+ <%= 'uncategorized' if !current_page?(up_for_review_path) && @category.blank? && @search_term.blank? %>
26
27
  <%= 'article'.pluralize(@total_records) %>
28
+ <%= 'up for review' if current_page?(up_for_review_path) %>
27
29
 
28
30
  <% if @search_term.present? %>
29
31
  containing <span class="font-serif">&ldquo;</span><%= @search_term %><span class="font-serif">&rdquo;</span>