thredded 0.15.1 → 0.15.2

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/stylesheets/thredded/_thredded.scss +1 -0
  4. data/app/assets/stylesheets/thredded/components/_base.scss +4 -0
  5. data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +2 -2
  6. data/app/assets/stylesheets/thredded/layout/_moderation.scss +8 -7
  7. data/app/assets/stylesheets/thredded/layout/_navigation.scss +61 -26
  8. data/app/assets/stylesheets/thredded/layout/_scoped-navigation.scss +5 -0
  9. data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +4 -2
  10. data/app/controllers/thredded/application_controller.rb +52 -1
  11. data/app/controllers/thredded/topics_controller.rb +41 -39
  12. data/app/helpers/thredded/application_helper.rb +14 -15
  13. data/app/helpers/thredded/nav_helper.rb +12 -0
  14. data/app/helpers/thredded/urls_helper.rb +11 -0
  15. data/app/models/thredded/messageboard.rb +1 -0
  16. data/app/models/thredded/topic.rb +7 -0
  17. data/app/views/thredded/messageboards/_messageboard_actions.html.erb +7 -0
  18. data/app/views/thredded/private_topics/_form.html.erb +1 -1
  19. data/app/views/thredded/shared/_nav.html.erb +5 -0
  20. data/app/views/thredded/shared/nav/_moderation.html.erb +1 -1
  21. data/app/views/thredded/shared/nav/_notification_preferences.html.erb +1 -2
  22. data/app/views/thredded/shared/nav/_private_topics.html.erb +1 -1
  23. data/app/views/thredded/shared/nav/_unread_topics.html.erb +12 -0
  24. data/app/views/thredded/topics/_form.html.erb +1 -1
  25. data/app/views/thredded/topics/index.html.erb +2 -8
  26. data/app/views/thredded/topics/unread.html.erb +33 -0
  27. data/config/locales/de.yml +7 -0
  28. data/config/locales/en.yml +7 -0
  29. data/config/locales/es.yml +7 -0
  30. data/config/locales/fr.yml +7 -0
  31. data/config/locales/it.yml +7 -0
  32. data/config/locales/pl.yml +7 -0
  33. data/config/locales/pt-BR.yml +7 -0
  34. data/config/locales/ru.yml +7 -0
  35. data/config/locales/zh-CN.yml +7 -0
  36. data/config/routes.rb +7 -0
  37. data/lib/thredded/version.rb +1 -1
  38. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8f7ee3eae771c92edf97664c74ebbcb42e403521cc09b9c05e7379dc98956f1
4
- data.tar.gz: 66ac525459c09f1efd65c947a8df0d41dde083166d857664f7163d0ed0b131b0
3
+ metadata.gz: bb521ffdf8a0e754e7e55a856a649913e79295cd33799f29efeab2311f7f0f12
4
+ data.tar.gz: 0c40013b94c70655bb7de0edcb84bae86a6c4a8d66dc9e84a95682f82e568293
5
5
  SHA512:
6
- metadata.gz: 0516e987e201972234778107cff4be78997dd15580ec0b721f21654510049598216d946966dd6a87d11553a47f7d55f7cf78f41e9fc7d07d1e0ecafd57470370
7
- data.tar.gz: 70d7f20e62b6187f1017ceced464e4e0cba2ca2988dd4adc9d1f8e5776f9c0b9b5d75d29ed3d12e7125361e203b549ea44fcfe3fb884a1c9ef25496c03223a5b
6
+ metadata.gz: bf907ac1caa92e8d6362369c13eb0be750f95237c8a4670426f7973346de420bf6e17fa5bbd54ece98a06acad5522eb601838ea0b0c97e4799d926039be3b95d
7
+ data.tar.gz: 626752cbba2144434a985f4af447dcf174dd33bf1dbc8e93a28124d34be5177ddcbae74a7232dbbb821419a49e82da2af670f0dc4de4dad8514fdac06213557e
data/README.md CHANGED
@@ -95,7 +95,7 @@ Then, see the rest of this Readme for more information about using and customizi
95
95
  Add the gem to your Gemfile:
96
96
 
97
97
  ```ruby
98
- gem 'thredded', '~> 0.15.1'
98
+ gem 'thredded', '~> 0.15.2'
99
99
  ```
100
100
 
101
101
  Add the Thredded [initializer] to your parent app by running the install generator.
@@ -7,6 +7,7 @@
7
7
  @import "layout/main-navigation";
8
8
  @import "layout/search-navigation";
9
9
  @import "layout/user-navigation";
10
+ @import "layout/scoped-navigation";
10
11
  @import "layout/navigation";
11
12
  @import "layout/moderation";
12
13
  @import "layout/user";
@@ -23,3 +23,7 @@
23
23
  .thredded--embed-16-by-9 {
24
24
  @extend %thredded--embed-16-by-9;
25
25
  }
26
+
27
+ .thredded--spacer {
28
+ flex-grow: 1;
29
+ }
@@ -9,8 +9,8 @@
9
9
 
10
10
  .thredded--main-navigation {
11
11
  @extend %thredded--list-unstyled;
12
- @include thredded--clearfix;
13
- display: block;
12
+ display: flex;
13
+ flex-wrap: wrap;
14
14
  }
15
15
 
16
16
  .thredded--navigation-breadcrumbs {
@@ -3,14 +3,15 @@
3
3
  @include thredded-media-desktop-and-up {
4
4
  margin-bottom: $thredded-base-spacing;
5
5
  }
6
+ }
6
7
 
7
- &--items {
8
- @extend %thredded--nav-tabs;
9
- margin-bottom: $thredded-small-spacing;
10
- }
11
- &--item {
12
- @extend %thredded--nav-tabs--item;
13
- }
8
+ .thredded--moderation-navigation--items {
9
+ @extend %thredded--nav-tabs;
10
+ margin-bottom: $thredded-small-spacing;
11
+ }
12
+
13
+ .thredded--moderation-navigation--item {
14
+ @extend %thredded--nav-tabs--item;
14
15
  }
15
16
 
16
17
  .thredded--pending-moderation .thredded--moderation-navigation--pending,
@@ -1,4 +1,6 @@
1
1
  .thredded--navigation {
2
+ display: flex;
3
+ flex-direction: column;
2
4
  position: relative;
3
5
  .thredded--icon {
4
6
  display: none;
@@ -6,7 +8,29 @@
6
8
  }
7
9
 
8
10
  @include thredded-media-tablet-and-down {
9
- $icon-nav-item-width: 2.625rem;
11
+ $icon-nav-item-gutter: 0.5rem;
12
+ $icon-nav-item-width: (2.125rem + $icon-nav-item-gutter);
13
+ %icon-nav-item {
14
+ box-sizing: border-box;
15
+ margin: 0 0 0 $icon-nav-item-gutter;
16
+ padding: 0;
17
+ vertical-align: top;
18
+ a {
19
+ position: relative;
20
+ display: block;
21
+ padding: 0.4375rem 0 0.375rem 0;
22
+ }
23
+ .thredded--icon {
24
+ display: block;
25
+ width: 2rem;
26
+ height: 2rem;
27
+ }
28
+ }
29
+ %icon-counter {
30
+ bottom: 0.3125rem;
31
+ position: absolute;
32
+ right: -0.1875rem;
33
+ }
10
34
  .thredded--navigation {
11
35
  position: relative;
12
36
  width: 100%;
@@ -17,11 +41,18 @@
17
41
  }
18
42
  .thredded--navigation-breadcrumbs {
19
43
  font-size: $thredded-font-size-small;
20
- padding-right: $icon-nav-item-width * 2;
21
- .thredded--is-moderator & {
44
+ padding-right: $icon-nav-item-width * 1;
45
+ .thredded--global-nav-icons-1 & {
46
+ padding-right: $icon-nav-item-width * 2;
47
+ }
48
+ .thredded--global-nav-icons-2 & {
22
49
  padding-right: $icon-nav-item-width * 3;
23
50
  }
51
+ .thredded--global-nav-icons-3 & {
52
+ padding-right: $icon-nav-item-width * 4;
53
+ }
24
54
  }
55
+
25
56
  .thredded--navigation--search-topics {
26
57
  display: none;
27
58
  .thredded--messageboards-index &,
@@ -29,6 +60,7 @@
29
60
  .thredded--topic-search-results & {
30
61
  @media screen {
31
62
  display: block;
63
+ width: 100%;
32
64
  }
33
65
  }
34
66
  }
@@ -42,37 +74,22 @@
42
74
  display: block;
43
75
  margin-bottom: 0;
44
76
  }
45
- %icon-nav-item {
46
- box-sizing: border-box;
47
- display: inline-block;
48
- margin: 0 0 0 ($thredded-small-spacing/2);
49
- padding: 0;
50
- vertical-align: top;
51
- a {
52
- position: relative;
53
- display: block;
54
- padding: 0.4375rem 0 0.375rem 0;
77
+ &--item {
78
+ .thredded--nav-text {
79
+ display: none;
55
80
  }
56
- .thredded--icon {
57
- display: block;
58
- width: 2rem;
59
- height: 2rem;
60
- }
61
- }
62
- %icon-counter {
63
- bottom: 0.3125rem;
64
- position: absolute;
65
- right: -0.1875rem;
66
81
  }
67
- .thredded--nav-text {
68
- display: none;
82
+ &--unread-topics {
83
+ @extend %icon-nav-item;
84
+ &--followed-count {
85
+ @extend %icon-counter;
86
+ }
69
87
  }
70
88
  &--settings {
71
89
  @extend %icon-nav-item;
72
90
  }
73
91
  &--private-topics {
74
92
  @extend %icon-nav-item;
75
- margin-top: 1px;
76
93
  &--unread {
77
94
  @extend %icon-counter;
78
95
  }
@@ -83,5 +100,23 @@
83
100
  @extend %icon-counter
84
101
  }
85
102
  }
103
+ &--moderation.thredded--is-current ~ &--settings,
104
+ &--moderation.thredded--is-current ~ &--private-topics {
105
+ display: none;
106
+ }
107
+ }
108
+ .thredded--scoped-navigation {
109
+ position: absolute;
110
+ top: 0;
111
+ right: 0;
112
+ .thredded--global-nav-icons-1 & {
113
+ right: $icon-nav-item-width;
114
+ }
115
+ .thredded--global-nav-icons-2 & {
116
+ right: $icon-nav-item-width * 2;
117
+ }
118
+ .thredded--global-nav-icons-3 & {
119
+ right: $icon-nav-item-width * 3;
120
+ }
86
121
  }
87
122
  }
@@ -0,0 +1,5 @@
1
+ .thredded--scoped-navigation {
2
+ @extend %thredded--nav-tabs;
3
+ border-bottom: 0;
4
+ display: flex;
5
+ }
@@ -1,6 +1,7 @@
1
1
  .thredded--user-navigation {
2
2
  @extend %thredded--nav-tabs;
3
- text-align: right;
3
+ display: flex;
4
+ justify-content: flex-end;
4
5
  @media print {
5
6
  display: none;
6
7
  }
@@ -15,6 +16,7 @@
15
16
  }
16
17
 
17
18
  .thredded--user-navigation--private-topics--unread,
18
- .thredded--user-navigation--moderation--pending-count {
19
+ .thredded--user-navigation--moderation--pending-count,
20
+ .thredded--user-navigation--unread-topics--followed-count {
19
21
  @extend %thredded--nav-tabs--item--badge;
20
22
  }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Thredded
4
- class ApplicationController < ::ApplicationController
4
+ class ApplicationController < ::ApplicationController # rubocop:disable Metrics/ClassLength
5
5
  layout :thredded_layout
6
6
  include ::Thredded::UrlsHelper
7
7
  include Pundit
@@ -12,6 +12,9 @@ module Thredded
12
12
  :thredded_current_user,
13
13
  :messageboard,
14
14
  :messageboard_or_nil,
15
+ :unread_private_topics_count,
16
+ :unread_followed_topics_count,
17
+ :unread_topics_count,
15
18
  :preferences,
16
19
  :thredded_signed_in?
17
20
 
@@ -124,6 +127,54 @@ module Thredded
124
127
  nil
125
128
  end
126
129
 
130
+ def in_messageboard?
131
+ params.key?(:messageboard_id)
132
+ end
133
+
134
+ # @return [ActiveRecord::Relation]
135
+ def topics_scope
136
+ @topics_scope ||=
137
+ if in_messageboard?
138
+ policy_scope(messageboard.topics)
139
+ else
140
+ policy_scope(Thredded::Topic.all).joins(:messageboard).merge(policy_scope(Thredded::Messageboard.all))
141
+ end
142
+ end
143
+
144
+ def unread_private_topics_count
145
+ @unread_private_topics_count ||=
146
+ if thredded_signed_in?
147
+ Thredded::PrivateTopic
148
+ .for_user(thredded_current_user)
149
+ .unread(thredded_current_user)
150
+ .count
151
+ else
152
+ 0
153
+ end
154
+ end
155
+
156
+ def unread_followed_topics_count
157
+ @unread_followed_topics_count ||=
158
+ if thredded_signed_in?
159
+ scope = topics_scope
160
+ scope = topics_scope.where(messageboard_id: messageboard.id) if in_messageboard?
161
+ scope.unread_followed_by(thredded_current_user).count
162
+ else
163
+ 0
164
+ end
165
+ end
166
+
167
+ def unread_topics_count
168
+ @unread_topics_count ||=
169
+ if thredded_signed_in?
170
+ scope = topics_scope
171
+ scope = topics_scope.where(messageboard_id: messageboard.id) if in_messageboard?
172
+ scope.unread(thredded_current_user).count
173
+ else
174
+ 0
175
+ end
176
+ end
177
+
127
178
  def preferences
128
179
  @preferences ||= thredded_current_user.thredded_user_preference
129
180
  end
@@ -6,67 +6,42 @@ module Thredded
6
6
  include Thredded::NewPostParams
7
7
 
8
8
  before_action :thredded_require_login!,
9
- only: %i[edit new update create destroy follow unfollow]
9
+ only: %i[edit new update create destroy follow unfollow unread]
10
+
11
+ before_action :verify_messageboard,
12
+ only: %i[index search unread]
10
13
 
11
14
  before_action :use_topic_messageboard,
12
15
  only: %i[show edit update destroy follow unfollow]
13
16
 
14
17
  after_action :update_user_activity
15
18
 
16
- after_action :verify_authorized, except: %i[search]
19
+ after_action :verify_authorized, except: %i[search unread]
17
20
  after_action :verify_policy_scoped, except: %i[show new create edit update destroy follow unfollow]
18
21
 
19
22
  def index
20
- authorize_reading messageboard
21
- unless params_match?(canonical_messageboard_params)
22
- skip_policy_scope
23
- return redirect_to(canonical_messageboard_params)
24
- end
25
-
26
23
  page_scope = policy_scope(messageboard.topics)
27
24
  .order_sticky_first.order_recently_posted_first
25
+ .includes(:categories, :last_user, :user)
28
26
  .page(current_page)
29
27
  return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
30
28
  @topics = Thredded::TopicsPageView.new(thredded_current_user, page_scope)
31
- Thredded::TopicForm.new(messageboard: messageboard, user: thredded_current_user).tap do |form|
32
- @new_topic = form if policy(form.topic).create?
33
- end
29
+ @new_topic = init_new_topic
34
30
  end
35
31
 
36
- def show
37
- authorize topic, :read?
38
- return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
39
- page_scope = policy_scope(topic.posts)
40
- .order_oldest_first
41
- .includes(:user, :messageboard, :postable)
32
+ def unread
33
+ page_scope = topics_scope
34
+ .unread(thredded_current_user)
35
+ .order_followed_first(thredded_current_user).order_recently_posted_first
36
+ .includes(:categories, :last_user, :user)
42
37
  .page(current_page)
43
38
  return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
44
- @posts = Thredded::TopicPostsPageView.new(thredded_current_user, topic, page_scope)
45
-
46
- if thredded_signed_in?
47
- Thredded::UserTopicReadState.touch!(thredded_current_user.id, topic.id, page_scope.last)
48
- end
49
-
50
- @new_post = Thredded::PostForm.new(user: thredded_current_user, topic: topic, post_params: new_post_params)
39
+ @topics = Thredded::TopicsPageView.new(thredded_current_user, page_scope)
40
+ @new_topic = init_new_topic
51
41
  end
52
42
 
53
43
  def search
54
- in_messageboard = params.key?(:messageboard_id)
55
- if in_messageboard
56
- authorize_reading messageboard
57
- unless params_match?(canonical_messageboard_params)
58
- skip_policy_scope
59
- return redirect_to(canonical_messageboard_params)
60
- end
61
- end
62
44
  @query = params[:q].to_s
63
- topics_scope = policy_scope(
64
- if in_messageboard
65
- messageboard.topics
66
- else
67
- Thredded::Topic.where(messageboard_id: policy_scope(Thredded::Messageboard.all).pluck(:id))
68
- end
69
- )
70
45
  page_scope = topics_scope
71
46
  .search_query(@query)
72
47
  .order_recently_posted_first
@@ -76,6 +51,19 @@ module Thredded
76
51
  @topics = Thredded::TopicsPageView.new(thredded_current_user, page_scope)
77
52
  end
78
53
 
54
+ def show
55
+ authorize topic, :read?
56
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
57
+ page_scope = policy_scope(topic.posts)
58
+ .order_oldest_first
59
+ .includes(:user, :messageboard, :postable)
60
+ .page(current_page)
61
+ return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
62
+ @posts = Thredded::TopicPostsPageView.new(thredded_current_user, topic, page_scope)
63
+ Thredded::UserTopicReadState.touch!(thredded_current_user.id, topic.id, page_scope.last) if thredded_signed_in?
64
+ @new_post = Thredded::PostForm.new(user: thredded_current_user, topic: topic, post_params: new_post_params)
65
+ end
66
+
79
67
  def new
80
68
  @new_topic = Thredded::TopicForm.new(new_topic_params)
81
69
  authorize_creating @new_topic.topic
@@ -153,6 +141,20 @@ module Thredded
153
141
 
154
142
  private
155
143
 
144
+ def init_new_topic
145
+ return unless in_messageboard?
146
+ form = Thredded::TopicForm.new(messageboard: messageboard, user: thredded_current_user)
147
+ form if policy(form.topic).create?
148
+ end
149
+
150
+ def verify_messageboard
151
+ return unless in_messageboard?
152
+ authorize_reading messageboard
153
+ return if params_match?(canonical_messageboard_params)
154
+ skip_policy_scope
155
+ redirect_to(canonical_messageboard_params)
156
+ end
157
+
156
158
  def canonical_messageboard_params
157
159
  { messageboard_id: messageboard.slug }
158
160
  end
@@ -20,9 +20,20 @@ module Thredded
20
20
  end
21
21
 
22
22
  def thredded_container_classes
23
- ['thredded--main-container', content_for(:thredded_page_id)].tap do |classes|
24
- classes << 'thredded--is-moderator' unless moderatable_messageboards_ids.empty?
25
- end
23
+ [
24
+ 'thredded--main-container',
25
+ content_for(:thredded_page_id),
26
+ "thredded--global-nav-icons-#{global_nav_icons_count}",
27
+ ('thredded--is-moderator' unless moderatable_messageboards_ids.empty?),
28
+ ('thredded--private-messaging-enabled' if Thredded.private_messaging_enabled),
29
+ ].compact
30
+ end
31
+
32
+ def global_nav_icons_count
33
+ result = 1 # Notification Settings
34
+ result += 1 if Thredded.private_messaging_enabled
35
+ result += 1 if moderatable_messageboards_ids.present?
36
+ result
26
37
  end
27
38
 
28
39
  # Render the page container with the supplied block as content.
@@ -104,18 +115,6 @@ module Thredded
104
115
  end
105
116
  end
106
117
 
107
- def unread_private_topics_count
108
- @unread_private_topics_count ||=
109
- if thredded_signed_in?
110
- Thredded::PrivateTopic
111
- .for_user(thredded_current_user)
112
- .unread(thredded_current_user)
113
- .count
114
- else
115
- 0
116
- end
117
- end
118
-
119
118
  def moderatable_messageboards_ids
120
119
  @moderatable_messageboards_ids ||=
121
120
  thredded_current_user.thredded_can_moderate_messageboards.pluck(:id)
@@ -27,6 +27,14 @@ module Thredded
27
27
  ]
28
28
  )
29
29
 
30
+ USER_NAV_UNREAD_TOPICS = Set.new(
31
+ %w[thredded--unread-topics]
32
+ )
33
+
34
+ def current_page_unread_topics?
35
+ USER_NAV_UNREAD_TOPICS.include?(content_for(:thredded_page_id))
36
+ end
37
+
30
38
  def current_page_preferences?
31
39
  USER_NAV_PREFERENCES_PAGES.include?(content_for(:thredded_page_id))
32
40
  end
@@ -38,5 +46,9 @@ module Thredded
38
46
  def current_page_private_topics?
39
47
  USER_NAV_PRIVATE_TOPICS_PAGES.include?(content_for(:thredded_page_id))
40
48
  end
49
+
50
+ def nav_back_path(messageboard = nil)
51
+ messageboard ? messageboard_topics_path(messageboard) : messageboards_path
52
+ end
41
53
  end
42
54
  end
@@ -95,6 +95,17 @@ module Thredded
95
95
  edit_preferences_url(messageboard, params.merge(only_path: true))
96
96
  end
97
97
 
98
+ # @param [Thredded::Messageboard, nil] messageboard
99
+ # @param [Hash] params additional params
100
+ def unread_topics_path(messageboard: nil, **params)
101
+ params[:only_path] = true
102
+ if messageboard
103
+ unread_messageboard_topics_url(messageboard, params)
104
+ else
105
+ unread_topics_url(params)
106
+ end
107
+ end
108
+
98
109
  # @param messageboard [Thredded::Messageboard, nil]
99
110
  # @return [String] the path to the global or messageboard search.
100
111
  def search_path(messageboard = nil)
@@ -16,6 +16,7 @@ module Thredded
16
16
  private-posts
17
17
  private-topics
18
18
  theme-preview
19
+ unread
19
20
  ]
20
21
  )
21
22
 
@@ -14,6 +14,13 @@ module Thredded
14
14
  scope :search_query, ->(query) { ::Thredded::TopicsSearch.new(query, self).search }
15
15
 
16
16
  scope :order_sticky_first, -> { order(sticky: :desc) }
17
+ scope :order_followed_first, lambda { |user|
18
+ user_follows = UserTopicFollow.arel_table
19
+ joins(arel_table.join(user_follows, Arel::Nodes::OuterJoin)
20
+ .on(user_follows[:topic_id].eq(arel_table[:id])
21
+ .and(user_follows[:user_id].eq(user.id))).join_sources)
22
+ .order(Arel::Nodes::Ascending.new(user_follows[:id].eq(nil)))
23
+ }
17
24
 
18
25
  scope :followed_by, lambda { |user|
19
26
  joins(:user_follows)
@@ -0,0 +1,7 @@
1
+ <div class="thredded--messageboards--actions">
2
+ <% if policy(messageboard).update? %>
3
+ <a class="thredded--button" href="<%= edit_messageboard_path(messageboard) %>" rel="nofollow">
4
+ <%= t('thredded.nav.edit_messageboard') %>
5
+ </a>
6
+ <% end %>
7
+ </div>
@@ -11,7 +11,7 @@
11
11
  <ul class="thredded--form-list on-top">
12
12
  <li class="title">
13
13
  <%= form.label :title, t('thredded.private_topics.form.title_label') %>
14
- <%= form.text_field :title, placeholder: placeholder, required: true %>
14
+ <%= form.text_field :title, placeholder: placeholder, required: true, autocomplete: 'off' %>
15
15
  <%= render 'thredded/shared/field_errors', messages: form.object.errors[:title] if form.object.errors.include?(:title) %>
16
16
  </li>
17
17
  <li>
@@ -12,8 +12,13 @@
12
12
  <%= yield :thredded_main_navigation %>
13
13
  <% else %>
14
14
  <div class="thredded--main-navigation">
15
+ <%# Navigation scoped to the current messageboard if any. %>
15
16
  <%= yield :thredded_breadcrumbs %>
16
17
  <%= render 'thredded/search/form', messageboard: messageboard_or_nil %>
18
+ <div class="thredded--spacer"></div>
19
+ <div class="thredded--scoped-navigation">
20
+ <%= render 'thredded/shared/nav/unread_topics', messageboard: messageboard_or_nil %>
21
+ </div>
17
22
  </div>
18
23
  <% end %>
19
24
  </nav>
@@ -1,7 +1,7 @@
1
1
  <% if moderatable_messageboards_ids.present? %>
2
2
  <% current = current_page_moderation? %>
3
3
  <li class="thredded--user-navigation--item thredded--user-navigation--moderation<%= ' thredded--is-current' if current %>">
4
- <%= link_to (current ? messageboards_path : pending_moderation_path), rel: 'nofollow' do %>
4
+ <%= link_to current ? nav_back_path : pending_moderation_path, rel: 'nofollow' do %>
5
5
  <%= inline_svg 'thredded/moderation.svg',
6
6
  class: 'thredded--icon',
7
7
  title: t('thredded.nav.moderation') %>
@@ -1,7 +1,6 @@
1
1
  <% current = current_page_preferences? %>
2
2
  <li class="thredded--user-navigation--settings thredded--user-navigation--item<%= ' thredded--is-current' if current %>">
3
- <%= link_to current ? (messageboard ? messageboard_topics_path(messageboard) : messageboards_path)
4
- : edit_preferences_path(messageboard), rel: 'nofollow' do %>
3
+ <%= link_to current ? nav_back_path(messageboard) : edit_preferences_path(messageboard), rel: 'nofollow' do %>
5
4
  <%= inline_svg 'thredded/settings.svg', class: 'thredded--icon', title: t('thredded.nav.settings') %>
6
5
  <span class="thredded--nav-text"><%= t('thredded.nav.settings') %></span>
7
6
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <% current = current_page_private_topics? %>
2
2
  <li class="thredded--user-navigation--item thredded--user-navigation--private-topics<%= ' thredded--is-current' if current %>">
3
- <%= link_to (current ? messageboards_path : private_topics_path), rel: 'nofollow' do %>
3
+ <%= link_to current ? nav_back_path : private_topics_path, rel: 'nofollow' do %>
4
4
  <%= inline_svg 'thredded/private-messages.svg',
5
5
  class: 'thredded--icon',
6
6
  title: t('thredded.nav.private_topics') %>
@@ -0,0 +1,12 @@
1
+ <% current = current_page_unread_topics? %>
2
+ <% if unread_topics_count > 0 || current %>
3
+ <li class="thredded--user-navigation--unread-topics thredded--user-navigation--item<%= ' thredded--is-current' if current %>">
4
+ <%= link_to current ? nav_back_path(messageboard) : unread_topics_path(messageboard: messageboard), rel: 'nofollow' do %>
5
+ <%= inline_svg 'thredded/follow.svg', class: 'thredded--icon' %>
6
+ <span class="thredded--nav-text"><%= t('thredded.nav.unread_topics') %></span>
7
+ <% if unread_followed_topics_count > 0 -%>
8
+ <span class="thredded--user-navigation--unread-topics--followed-count"><%= unread_followed_topics_count %></span>
9
+ <% end -%>
10
+ <% end %>
11
+ </li>
12
+ <% end %>
@@ -9,7 +9,7 @@
9
9
  <ul class="thredded--form-list on-top">
10
10
  <li class="title">
11
11
  <%= form.label :title, t('thredded.topics.form.title_label') %>
12
- <%= form.text_field :title, placeholder: placeholder, required: true %>
12
+ <%= form.text_field :title, placeholder: placeholder, required: true, autocomplete: 'off' %>
13
13
  <%= render 'thredded/shared/field_errors', messages: form.object.errors[:title] if form.object.errors.include?(:title) %>
14
14
  </li>
15
15
 
@@ -3,7 +3,7 @@
3
3
  <% content_for :thredded_breadcrumbs, render('thredded/shared/breadcrumbs') %>
4
4
 
5
5
  <%= thredded_page do %>
6
- <div class="thredded--svg-definitions ">
6
+ <div class="thredded--svg-definitions">
7
7
  <%= inline_svg 'thredded/follow.svg', id: 'thredded-follow-icon', title: nil %>
8
8
  <%= inline_svg 'thredded/unfollow.svg', id: 'thredded-unfollow-icon' %>
9
9
  </div>
@@ -25,11 +25,5 @@
25
25
  <%= paginate @topics %>
26
26
  </footer>
27
27
 
28
- <div class="thredded--messageboards--actions">
29
- <% if policy(messageboard).update? %>
30
- <a class="thredded--button" href="<%= edit_messageboard_path(messageboard) %>" rel="nofollow">
31
- <%= t('thredded.nav.edit_messageboard') %>
32
- </a>
33
- <% end %>
34
- </div>
28
+ <%= render 'thredded/messageboards/messageboard_actions', messageboard: messageboard %>
35
29
  <% end %>
@@ -0,0 +1,33 @@
1
+ <% content_for :thredded_page_title,
2
+ messageboard_or_nil ?
3
+ t('thredded.unread_topics.page_title_in_messageboard', messageboard: messageboard.name) :
4
+ t('thredded.unread_topics.page_title') %>
5
+ <% content_for :thredded_page_id, 'thredded--unread-topics' %>
6
+ <% content_for :thredded_breadcrumbs, render('thredded/shared/breadcrumbs') %>
7
+
8
+ <%= thredded_page do %>
9
+ <% if @topics.present? %>
10
+ <div class="thredded--svg-definitions ">
11
+ <%= inline_svg 'thredded/follow.svg', id: 'thredded-follow-icon', title: nil %>
12
+ <%= inline_svg 'thredded/unfollow.svg', id: 'thredded-unfollow-icon' %>
13
+ </div>
14
+ <%= content_tag :section, class: 'thredded--main-section thredded--topics', 'data-thredded-topics' => true do %>
15
+ <%= render 'thredded/topics/form',
16
+ topic: @new_topic,
17
+ css_class: 'thredded--is-compact',
18
+ placeholder: t('thredded.topics.form.title_placeholder_start') if @new_topic %>
19
+ <%= render partial: 'thredded/topics/topic',
20
+ collection: @topics,
21
+ locals: { topics: @topics } %>
22
+ <% end %>
23
+ <footer class="thredded--pagination-bottom">
24
+ <%= paginate @topics %>
25
+ </footer>
26
+ <% else %>
27
+ <div class="thredded--empty">
28
+ <h3 class="thredded--empty--title"><%= t 'thredded.unread_topics.empty.title' %></h3>
29
+ <p><%= t 'thredded.unread_topics.empty.content' %></p>
30
+ </div>
31
+ <% end %>
32
+ <%= render 'thredded/messageboards/messageboard_actions', messageboard: messageboard if messageboard_or_nil %>
33
+ <% end %>
@@ -117,6 +117,7 @@ de:
117
117
  moderation_users: Nutzer
118
118
  private_topics: Private Unterhaltungen
119
119
  settings: Benachrichtigungseinstellungen
120
+ unread_topics: Ungelesen
120
121
  null_user_name: Gelöschte Nutzer
121
122
  posts:
122
123
  delete: Beitrag gelöscht
@@ -242,6 +243,12 @@ de:
242
243
  unfollow: Nich mehr folgen
243
244
  unfollowed_notice: Du folgst der Diskussion nicht mehr
244
245
  updated_notice: Beitrag aktualisiert
246
+ unread_topics:
247
+ empty:
248
+ content: Du hast alles gelesen, was es gibt. Komm später wieder für mehr!
249
+ title: Alles gelesen!
250
+ page_title: Ungelesene Themen
251
+ page_title_in_messageboard: "%{messageboard}: Ungelesene Themen"
245
252
  users:
246
253
  currently_online: Zurzeit Online
247
254
  last_active_html: Zuletzt aktiv %{time_ago}
@@ -116,6 +116,7 @@ en:
116
116
  moderation_users: Users
117
117
  private_topics: Private Messages
118
118
  settings: Notification Settings
119
+ unread_topics: Unread
119
120
  null_user_name: Deleted user
120
121
  posts:
121
122
  delete: Delete Post
@@ -238,6 +239,12 @@ en:
238
239
  unfollow: Stop following
239
240
  unfollowed_notice: You are no longer following this topic
240
241
  updated_notice: Topic updated
242
+ unread_topics:
243
+ empty:
244
+ content: You've read all there is. Come back later for more!
245
+ title: All read!
246
+ page_title: Unread topics
247
+ page_title_in_messageboard: "%{messageboard}: Unread topics"
241
248
  users:
242
249
  currently_online: Currently Online
243
250
  last_active_html: Last active %{time_ago}
@@ -118,6 +118,7 @@ es:
118
118
  moderation_users: Usuarios
119
119
  private_topics: Mensajes Privados
120
120
  settings: Ajuste de Notificaciones
121
+ unread_topics: No leído
121
122
  null_user_name: Usuario eliminado
122
123
  posts:
123
124
  delete: Eliminar Mensaje
@@ -242,6 +243,12 @@ es:
242
243
  unfollow: Deja de seguir
243
244
  unfollowed_notice: Has dejado de seguir este tema
244
245
  updated_notice: Tema actualizado
246
+ unread_topics:
247
+ empty:
248
+ content: Has leído todo lo que hay. ¡Vuelve más tarde para más!
249
+ title: "¡Todo leido!"
250
+ page_title: Temas no leídos
251
+ page_title_in_messageboard: "%{messageboard}: temas no leídos"
245
252
  users:
246
253
  currently_online: En línea
247
254
  last_active_html: Última vez activo hace %{time_ago}
@@ -116,6 +116,7 @@ fr:
116
116
  moderation_users: Utilisateurs
117
117
  private_topics: Messages privés
118
118
  settings: Paramètres de notifications
119
+ unread_topics: Non lu
119
120
  null_user_name: Utilisateur effacé
120
121
  posts:
121
122
  delete: Supprimer le commentaire
@@ -240,6 +241,12 @@ fr:
240
241
  unfollow: Arrêter de suivre
241
242
  unfollowed_notice: Vous ne suivez dorénavant plus ce sujet
242
243
  updated_notice: Sujet mis à jour
244
+ unread_topics:
245
+ empty:
246
+ content: Vous avez lu tout ce qu'il y a. Revenez plus tard pour plus!
247
+ title: Tout lire!
248
+ page_title: Sujets non lus
249
+ page_title_in_messageboard: "%{messageboard}: sujets non lus"
243
250
  users:
244
251
  currently_online: En ce moment connecté
245
252
  last_active_html: 'Actif pour la dernière fois : %{time_ago}'
@@ -116,6 +116,7 @@ it:
116
116
  moderation_users: Utenti
117
117
  private_topics: Messaggi Privati
118
118
  settings: Impostazioni Notifiche
119
+ unread_topics: Non letto
119
120
  null_user_name: Utente cancellato
120
121
  posts:
121
122
  delete: Cancella messaggio
@@ -242,6 +243,12 @@ it:
242
243
  unfollow: Non seguire più questa discussione
243
244
  unfollowed_notice: Ora non stai più seguendo questa discussione
244
245
  updated_notice: Discussione aggiornata
246
+ unread_topics:
247
+ empty:
248
+ content: Hai letto tutto quello che c'è. Torna più tardi per di più!
249
+ title: Tutto letto!
250
+ page_title: Argomenti non letti
251
+ page_title_in_messageboard: "%{messageboard}: argomenti non letti"
245
252
  users:
246
253
  currently_online: Attualmente connessi
247
254
  last_active_html: Ultima attività %{time_ago}
@@ -116,6 +116,7 @@ pl:
116
116
  moderation_users: Użytkownicy
117
117
  private_topics: Prywatne wiadomości
118
118
  settings: Ustawienia powiadomień
119
+ unread_topics: Nieprzeczytane
119
120
  null_user_name: Usunięci użytkownicy
120
121
  posts:
121
122
  delete: Usuń post
@@ -238,6 +239,12 @@ pl:
238
239
  unfollow: Przestań obserwować
239
240
  unfollowed_notice: Przestałeś obserwować ten temat
240
241
  updated_notice: Temat zaktualizowany
242
+ unread_topics:
243
+ empty:
244
+ content: Przeczytałeś wszystko, co istnieje. Przyjdź później po więcej!
245
+ title: Wszystko przeczytane!
246
+ page_title: Nieprzeczytane tematy
247
+ page_title_in_messageboard: "%{messageboard}: Nieprzeczytane tematy"
241
248
  users:
242
249
  currently_online: Aktualnie online
243
250
  last_active_html: Ostatnio aktywny %{time_ago}
@@ -118,6 +118,7 @@ pt-BR:
118
118
  moderation_users: Usuários
119
119
  private_topics: Mensagens Privadas
120
120
  settings: Configurações de Notificação
121
+ unread_topics: Não lida
121
122
  null_user_name: Usuário deletado
122
123
  posts:
123
124
  delete: Remover Post
@@ -243,6 +244,12 @@ pt-BR:
243
244
  unfollow: Pare de seguir
244
245
  unfollowed_notice: Você não está mais seguindo este tópico
245
246
  updated_notice: Tópico atualizado
247
+ unread_topics:
248
+ empty:
249
+ content: Você leu tudo o que existe. Volte mais tarde para mais!
250
+ title: Tudo lido!
251
+ page_title: Tópicos não lidos
252
+ page_title_in_messageboard: "%{messageboard}: Tópicos não lidos"
246
253
  users:
247
254
  currently_online: Atualmente Online
248
255
  last_active_html: Última %{time_ago} ativa
@@ -114,6 +114,7 @@ ru:
114
114
  moderation_users: Пользователи
115
115
  private_topics: Личное
116
116
  settings: Настройки
117
+ unread_topics: Непрочитанные
117
118
  null_user_name: Пользователь удален
118
119
  posts:
119
120
  delete: Удалить пост
@@ -236,6 +237,12 @@ ru:
236
237
  unfollow: Не следить за темой
237
238
  unfollowed_notice: Вы не следите за темой
238
239
  updated_notice: Тема обновлена
240
+ unread_topics:
241
+ empty:
242
+ content: Вы все прочитали. Вернитесь позже и может будет еще что-нибудь!
243
+ title: Все прочитано!
244
+ page_title: Непрочитанные темы
245
+ page_title_in_messageboard: "%{messageboard}: непрочитанные темы"
239
246
  users:
240
247
  currently_online: Онлайн
241
248
  last_active_html: Последняя активность %{time_ago}
@@ -111,6 +111,7 @@ zh-CN:
111
111
  moderation_users: 用户
112
112
  private_topics: 私人对话
113
113
  settings: 通知设置
114
+ unread_topics: 未读
114
115
  null_user_name: 删除用户
115
116
  posts:
116
117
  delete: 删除回复
@@ -231,6 +232,12 @@ zh-CN:
231
232
  unfollow: 取消关注
232
233
  unfollowed_notice: 你不再关注该帖子
233
234
  updated_notice: 帖子已更新
235
+ unread_topics:
236
+ empty:
237
+ content: 你已经读完了。稍后再回来获取更多!
238
+ title: 全部阅读!
239
+ page_title: 未读主题
240
+ page_title_in_messageboard: "%{messageboard}:未读主题"
234
241
  users:
235
242
  currently_online: 目前在线
236
243
  last_active_html: 最后活跃%{time_ago}
data/config/routes.rb CHANGED
@@ -52,6 +52,12 @@ Thredded::Engine.routes.draw do # rubocop:disable Metrics/BlockLength
52
52
  end
53
53
  end
54
54
 
55
+ resources :topics, path: '', only: [] do
56
+ collection do
57
+ get '/unread', action: :unread, as: :unread
58
+ end
59
+ end
60
+
55
61
  resource :preferences, only: %i[edit update], as: :global_preferences
56
62
  resource :messageboard, path: 'messageboards', only: [:new]
57
63
  resources :messageboards, only: %i[edit update]
@@ -64,6 +70,7 @@ Thredded::Engine.routes.draw do # rubocop:disable Metrics/BlockLength
64
70
  collection do
65
71
  get '(page-:page)', action: :index, as: '', constraints: page_constraint
66
72
  get '/category/:category_id', action: :category, as: :categories
73
+ get '/unread', action: :unread, as: :unread
67
74
  end
68
75
  member do
69
76
  get '(page-:page)', action: :show, as: '', constraints: page_constraint
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Thredded
4
- VERSION = '0.15.1'
4
+ VERSION = '0.15.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thredded
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 0.15.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Oliveira
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-06-08 00:00:00.000000000 Z
12
+ date: 2018-06-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pundit
@@ -733,6 +733,7 @@ files:
733
733
  - app/assets/stylesheets/thredded/layout/_main-navigation.scss
734
734
  - app/assets/stylesheets/thredded/layout/_moderation.scss
735
735
  - app/assets/stylesheets/thredded/layout/_navigation.scss
736
+ - app/assets/stylesheets/thredded/layout/_scoped-navigation.scss
736
737
  - app/assets/stylesheets/thredded/layout/_search-navigation.scss
737
738
  - app/assets/stylesheets/thredded/layout/_user-navigation.scss
738
739
  - app/assets/stylesheets/thredded/layout/_user.scss
@@ -861,6 +862,7 @@ files:
861
862
  - app/views/thredded/messageboard_groups/new.html.erb
862
863
  - app/views/thredded/messageboards/_form.html.erb
863
864
  - app/views/thredded/messageboards/_messageboard.html.erb
865
+ - app/views/thredded/messageboards/_messageboard_actions.html.erb
864
866
  - app/views/thredded/messageboards/_messageboard_meta.html.erb
865
867
  - app/views/thredded/messageboards/edit.html.erb
866
868
  - app/views/thredded/messageboards/index.html.erb
@@ -945,6 +947,7 @@ files:
945
947
  - app/views/thredded/shared/nav/_private_topics.html.erb
946
948
  - app/views/thredded/shared/nav/_standalone.html.erb
947
949
  - app/views/thredded/shared/nav/_standalone_profile.html.erb
950
+ - app/views/thredded/shared/nav/_unread_topics.html.erb
948
951
  - app/views/thredded/shared/preview.html.erb
949
952
  - app/views/thredded/theme_previews/_section_title.html.erb
950
953
  - app/views/thredded/theme_previews/show.html.erb
@@ -960,6 +963,7 @@ files:
960
963
  - app/views/thredded/topics/new.html.erb
961
964
  - app/views/thredded/topics/search.html.erb
962
965
  - app/views/thredded/topics/show.html.erb
966
+ - app/views/thredded/topics/unread.html.erb
963
967
  - app/views/thredded/users/_link.html.erb
964
968
  - app/views/thredded/users/_post.html.erb
965
969
  - app/views/thredded/users/_posts.html.erb