thredded 0.15.1 → 0.15.2

Sign up to get free protection for your applications and to get access to all the features.
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