diff --git a/plugins/chat/assets/javascripts/discourse/components/channel-icon/index.gjs b/plugins/chat/assets/javascripts/discourse/components/channel-icon/index.gjs index a014679d985..e704540ce84 100644 --- a/plugins/chat/assets/javascripts/discourse/components/channel-icon/index.gjs +++ b/plugins/chat/assets/javascripts/discourse/components/channel-icon/index.gjs @@ -19,6 +19,10 @@ export default class ChatChannelIcon extends Component { return htmlSafe(`color: #${this.args.channel.chatable.color}`); } + get isThreadsList() { + return this.args.thread ?? false; + } + {{#if @channel.isDirectMessageChannel}} @@ -44,6 +48,19 @@ export default class ChatChannelIcon extends Component { {{/if}} + {{else if this.isThreadsList}} + + + + + {{icon "discourse-threads"}} + + + {{/if}} } diff --git a/plugins/chat/assets/javascripts/discourse/components/chat/thread/header.gjs b/plugins/chat/assets/javascripts/discourse/components/chat/thread/header.gjs index 48181cbb782..c654b0d7605 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat/thread/header.gjs +++ b/plugins/chat/assets/javascripts/discourse/components/chat/thread/header.gjs @@ -24,14 +24,14 @@ export default class ChatThreadHeader extends Component { route = "chat.channel.threads"; title = I18n.t("chat.return_to_threads_list"); models = this.channel?.routeModels; - } else if (!this.currentUser.isInDoNotDisturb() && this.unreadCount > 0) { - route = "chat.channel.threads"; - title = I18n.t("chat.return_to_threads_list"); - models = this.channel?.routeModels; } else if (prevPage === "chat.threads") { route = "chat.threads"; title = I18n.t("chat.my_threads.title"); models = []; + } else if (!this.currentUser.isInDoNotDisturb() && this.unreadCount > 0) { + route = "chat.channel.threads"; + title = I18n.t("chat.return_to_threads_list"); + models = this.channel?.routeModels; } else { route = "chat.channel.index"; title = I18n.t("chat.return_to_channel"); @@ -53,6 +53,12 @@ export default class ChatThreadHeader extends Component { return this.channel?.threadsManager?.unreadThreadCount; } + get showThreadUnreadIndicator() { + return ( + this.backLink.route === "chat.channel.threads" && this.unreadCount > 0 + ); + } + {{#if (and this.channel.threadingEnabled @thread)}} @@ -61,7 +67,9 @@ export default class ChatThreadHeader extends Component { @routeModels={{this.backLink.models}} @title={{this.backLink.title}} > - + {{#if this.showThreadUnreadIndicator}} + + {{/if}} {{icon "chevron-left"}} {{/if}} diff --git a/plugins/chat/assets/javascripts/discourse/components/user-threads/index.gjs b/plugins/chat/assets/javascripts/discourse/components/user-threads/index.gjs index 0227e102255..564f08d26a9 100644 --- a/plugins/chat/assets/javascripts/discourse/components/user-threads/index.gjs +++ b/plugins/chat/assets/javascripts/discourse/components/user-threads/index.gjs @@ -3,15 +3,18 @@ import { cached } from "@glimmer/tracking"; import { service } from "@ember/service"; import i18n from "discourse-common/helpers/i18n"; import { bind } from "discourse-common/utils/decorators"; +import ChannelIcon from "discourse/plugins/chat/discourse/components/channel-icon"; import ChannelTitle from "discourse/plugins/chat/discourse/components/channel-title"; import List from "discourse/plugins/chat/discourse/components/chat/list"; import ThreadIndicator from "discourse/plugins/chat/discourse/components/chat-message-thread-indicator"; import ThreadTitle from "discourse/plugins/chat/discourse/components/thread-title"; +import ThreadPreview from "discourse/plugins/chat/discourse/components/user-threads/preview"; export default class UserThreads extends Component { @service chat; @service chatApi; @service chatChannelsManager; + @service site; @cached get threadsCollection() { @@ -41,14 +44,23 @@ export default class UserThreads extends Component { > - + {{#if this.site.mobileView}} + + {{/if}} + - + + + {{#if this.site.mobileView}} + + {{else}} + + {{/if}} diff --git a/plugins/chat/assets/javascripts/discourse/components/user-threads/preview.gjs b/plugins/chat/assets/javascripts/discourse/components/user-threads/preview.gjs new file mode 100644 index 00000000000..842de10ef19 --- /dev/null +++ b/plugins/chat/assets/javascripts/discourse/components/user-threads/preview.gjs @@ -0,0 +1,23 @@ +import Component from "@glimmer/component"; +import formatDate from "discourse/helpers/format-date"; + +export default class ThreadPreview extends Component { + get lastReplyDate() { + return formatDate(this.args.preview.lastReplyCreatedAt, { leaveAgo: true }); + } + + + + {{this.lastReplyDate}} + + + + {{@preview.lastReplyUser.username}} + + : + + {{@preview.lastReplyExcerpt}} + + + +} diff --git a/plugins/chat/assets/stylesheets/mobile/chat-user-threads.scss b/plugins/chat/assets/stylesheets/mobile/chat-user-threads.scss index 4cfef1bcd77..7532804052a 100644 --- a/plugins/chat/assets/stylesheets/mobile/chat-user-threads.scss +++ b/plugins/chat/assets/stylesheets/mobile/chat-user-threads.scss @@ -1,9 +1,67 @@ -.chat-user-threads { - .chat__thread-title { - justify-content: space-between; +.c-user-thread { + display: grid; + grid-template-areas: + "avatar category timestamp" + "avatar title indicator" + "avatar excerpt excerpt"; + grid-template-columns: auto 1fr auto; + grid-column-gap: 0.75em; + margin-inline: 0; + padding: 0.5rem 1.5rem; + + .chat-channel-icon { + grid-area: avatar; + position: relative; + + .avatar { + margin-top: 4px; + width: var(--channel-list-avatar-size); + height: var(--channel-list-avatar-size); + } + } + + .avatar-flair.--threads { + position: absolute; + top: -4px; + right: -3px; + background: var(--primary-low); + border-radius: 50%; + padding: 0.2em; + line-height: var(--line-height-small); + border: 2px solid var(--secondary-very-high); + color: var(--primary-high); + } + + .chat__thread-title-container { + @include ellipsis; + grid-area: title; + .chat__thread-title { + &__name { + @include ellipsis; + } + } + } + + .chat-channel-title { + grid-area: category; + } + + .chat-message-thread-indicator__last-reply-timestamp { + grid-area: timestamp; + font-size: var(--font-down-2-rem); + align-self: center; + } + + .c-user-thread__excerpt { + @include ellipsis; + grid-area: excerpt; + display: flex; + color: var(--primary-high); + } + + .c-user-thread__excerpt-text { + margin-left: 0.25em; + overflow: hidden; + text-overflow: ellipsis; } } - -.c-user-thread { - margin-inline: 1.5rem; -} diff --git a/plugins/chat/spec/system/user_threads_spec.rb b/plugins/chat/spec/system/user_threads_spec.rb index 6c68554a73d..e421cf2c12c 100644 --- a/plugins/chat/spec/system/user_threads_spec.rb +++ b/plugins/chat/spec/system/user_threads_spec.rb @@ -244,4 +244,22 @@ RSpec.describe "User threads", type: :system do expect(user_threads_page).to have_threads end end + + context "when in mobile", mobile: true do + before do + chat_thread_chain_bootstrap(channel: channel_1, users: [current_user, Fabricate(:user)]) + end + + it "has the expected UI elements" do + chat_page.visit_user_threads + + expect(user_threads_page).to have_threads(count: 1) + expect(user_threads_page).to have_css(".chat-user-avatar") + expect(user_threads_page).to have_css(".chat__thread-title__name") + expect(user_threads_page).to have_css(".chat-channel-name") + expect(user_threads_page).to have_css(".c-user-thread__excerpt") + expect(user_threads_page).to have_css(".c-user-thread__excerpt-poster") + expect(user_threads_page).to have_css(".c-user-thread .relative-date") + end + end end