FEATURE: display last message on mobile (#25384)
Direct messages on mobile will now display the last message in the channels list.
This commit is contained in:
parent
4d1ed4a62d
commit
7b173e883f
|
@ -0,0 +1,49 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import ChatUserAvatar from "discourse/plugins/chat/discourse/components/chat-user-avatar";
|
||||
|
||||
export default class ChatChannelIcon extends Component {
|
||||
get firstUser() {
|
||||
return this.args.channel.chatable.users[0];
|
||||
}
|
||||
|
||||
get groupDirectMessage() {
|
||||
return (
|
||||
this.args.channel.isDirectMessageChannel &&
|
||||
this.args.channel.chatable.group
|
||||
);
|
||||
}
|
||||
|
||||
get channelColorStyle() {
|
||||
return htmlSafe(`color: #${this.args.channel.chatable.color}`);
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if @channel.isDirectMessageChannel}}
|
||||
<div class="chat-channel-icon">
|
||||
{{#if this.groupDirectMessage}}
|
||||
<span class="chat-channel-icon --users-count">
|
||||
{{@channel.membershipsCount}}
|
||||
</span>
|
||||
{{else}}
|
||||
<div class="chat-channel-icon --avatar">
|
||||
<ChatUserAvatar @user={{this.firstUser}} @interactive={{false}} />
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else if @channel.isCategoryChannel}}
|
||||
<div class="chat-channel-icon">
|
||||
<span
|
||||
class="chat-channel-icon --category-badge"
|
||||
style={{this.channelColorStyle}}
|
||||
>
|
||||
{{icon "d-chat"}}
|
||||
{{#if @channel.chatable.read_restricted}}
|
||||
{{icon "lock" class="chat-channel-icon__restricted-category-icon"}}
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { get, hash } from "@ember/helper";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import PluginOutlet from "discourse/components/plugin-outlet";
|
||||
import UserStatusMessage from "discourse/components/user-status-message";
|
||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||
|
||||
export default class ChatChannelName extends Component {
|
||||
@service currentUser;
|
||||
|
||||
get firstUser() {
|
||||
return this.args.channel.chatable.users[0];
|
||||
}
|
||||
|
||||
get users() {
|
||||
return this.args.channel.chatable.users;
|
||||
}
|
||||
|
||||
get groupDirectMessage() {
|
||||
return (
|
||||
this.args.channel.isDirectMessageChannel &&
|
||||
this.args.channel.chatable.group
|
||||
);
|
||||
}
|
||||
|
||||
get groupsDirectMessageTitle() {
|
||||
return this.args.channel.title || this.usernames;
|
||||
}
|
||||
|
||||
get usernames() {
|
||||
return this.users.mapBy("username").join(", ");
|
||||
}
|
||||
|
||||
get channelColorStyle() {
|
||||
return htmlSafe(`color: #${this.args.channel.chatable.color}`);
|
||||
}
|
||||
|
||||
get showUserStatus() {
|
||||
return !!(this.users.length === 1 && this.users[0].status);
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="chat-channel-name">
|
||||
{{#if @channel.isDirectMessageChannel}}
|
||||
{{#if this.groupDirectMessage}}
|
||||
<span class="chat-channel-name__label">
|
||||
{{this.groupsDirectMessageTitle}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="chat-channel-name__label">
|
||||
{{this.firstUser.username}}
|
||||
</span>
|
||||
{{#if this.showUserStatus}}
|
||||
<UserStatusMessage
|
||||
@status={{get this.users "0.status"}}
|
||||
@showDescription={{if this.site.mobileView "true"}}
|
||||
class="chat-channel__user-status-message"
|
||||
/>
|
||||
{{/if}}
|
||||
<PluginOutlet
|
||||
@name="after-chat-channel-username"
|
||||
@outletArgs={{hash user=@user}}
|
||||
@tagName=""
|
||||
@connectorTagName=""
|
||||
/>
|
||||
{{/if}}
|
||||
{{else if @channel.isCategoryChannel}}
|
||||
<span class="chat-channel-name__label">
|
||||
{{replaceEmoji @channel.title}}
|
||||
</span>
|
||||
|
||||
{{#if (has-block)}}
|
||||
{{yield}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
}
|
|
@ -1,111 +1,21 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { get, hash } from "@ember/helper";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import PluginOutlet from "discourse/components/plugin-outlet";
|
||||
import UserStatusMessage from "discourse/components/user-status-message";
|
||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import ChatUserAvatar from "discourse/plugins/chat/discourse/components/chat-user-avatar";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import ChannelIcon from "discourse/plugins/chat/discourse/components/channel-icon";
|
||||
import ChannelName from "discourse/plugins/chat/discourse/components/channel-name";
|
||||
|
||||
export default class ChatChannelTitle extends Component {
|
||||
@service currentUser;
|
||||
const ChatChannelTitle = <template>
|
||||
<div
|
||||
class={{concatClass
|
||||
"chat-channel-title"
|
||||
(if @channel.isDirectMessageChannel "is-dm" "is-category")
|
||||
}}
|
||||
>
|
||||
<ChannelIcon @channel={{@channel}} />
|
||||
<ChannelName @channel={{@channel}} />
|
||||
|
||||
get firstUser() {
|
||||
return this.args.channel.chatable.users[0];
|
||||
}
|
||||
|
||||
get users() {
|
||||
return this.args.channel.chatable.users;
|
||||
}
|
||||
|
||||
get groupDirectMessage() {
|
||||
return (
|
||||
this.args.channel.isDirectMessageChannel &&
|
||||
this.args.channel.chatable.group
|
||||
);
|
||||
}
|
||||
|
||||
get groupsDirectMessageTitle() {
|
||||
return this.args.channel.title || this.usernames;
|
||||
}
|
||||
|
||||
get usernames() {
|
||||
return this.users.mapBy("username").join(", ");
|
||||
}
|
||||
|
||||
get channelColorStyle() {
|
||||
return htmlSafe(`color: #${this.args.channel.chatable.color}`);
|
||||
}
|
||||
|
||||
get showUserStatus() {
|
||||
return !!(this.users.length === 1 && this.users[0].status);
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if @channel.isDirectMessageChannel}}
|
||||
<div class="chat-channel-title is-dm">
|
||||
{{#if this.groupDirectMessage}}
|
||||
<span class="chat-channel-title__users-count">
|
||||
{{@channel.membershipsCount}}
|
||||
</span>
|
||||
{{else}}
|
||||
<div class="chat-channel-title__avatar">
|
||||
<ChatUserAvatar @user={{this.firstUser}} @interactive={{false}} />
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="chat-channel-title__user-info">
|
||||
<div class="chat-channel-title__usernames">
|
||||
{{#if this.groupDirectMessage}}
|
||||
<span class="chat-channel-title__name">
|
||||
{{this.groupsDirectMessageTitle}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="chat-channel-title__name">
|
||||
{{this.firstUser.username}}
|
||||
</span>
|
||||
{{#if this.showUserStatus}}
|
||||
<UserStatusMessage
|
||||
@status={{get this.users "0.status"}}
|
||||
@showDescription={{if this.site.mobileView "true"}}
|
||||
class="chat-channel-title__user-status-message"
|
||||
/>
|
||||
{{/if}}
|
||||
<PluginOutlet
|
||||
@name="after-chat-channel-username"
|
||||
@outletArgs={{hash user=@user}}
|
||||
@tagName=""
|
||||
@connectorTagName=""
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if (has-block)}}
|
||||
{{yield}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else if @channel.isCategoryChannel}}
|
||||
<div class="chat-channel-title is-category">
|
||||
<span
|
||||
class="chat-channel-title__category-badge"
|
||||
style={{this.channelColorStyle}}
|
||||
>
|
||||
{{icon "d-chat"}}
|
||||
{{#if @channel.chatable.read_restricted}}
|
||||
{{icon "lock" class="chat-channel-title__restricted-category-icon"}}
|
||||
{{/if}}
|
||||
</span>
|
||||
<span class="chat-channel-title__name">
|
||||
{{replaceEmoji @channel.title}}
|
||||
</span>
|
||||
|
||||
{{#if (has-block)}}
|
||||
{{yield}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if (has-block)}}
|
||||
{{yield}}
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
||||
</div>
|
||||
</template>;
|
||||
|
||||
export default ChatChannelTitle;
|
||||
|
|
|
@ -18,9 +18,9 @@ export default class ChatChannelMetadata extends Component {
|
|||
}
|
||||
|
||||
<template>
|
||||
<div class="chat-channel-metadata">
|
||||
<div class="chat-channel__metadata">
|
||||
{{#if @channel.lastMessage}}
|
||||
<div class="chat-channel-metadata__date">
|
||||
<div class="chat-channel__metadata-date">
|
||||
{{this.lastMessageFormattedDate}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
|
@ -9,13 +9,15 @@ import { inject as service } from "@ember/service";
|
|||
import { htmlSafe } from "@ember/template";
|
||||
import { modifier } from "ember-modifier";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import I18n from "discourse-i18n";
|
||||
import and from "truth-helpers/helpers/and";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
import ChannelTitle from "discourse/plugins/chat/discourse/components/channel-title";
|
||||
import ChannelIcon from "discourse/plugins/chat/discourse/components/channel-icon";
|
||||
import ChannelName from "discourse/plugins/chat/discourse/components/channel-name";
|
||||
import ChatChannelMetadata from "discourse/plugins/chat/discourse/components/chat-channel-metadata";
|
||||
import ToggleChannelMembershipButton from "discourse/plugins/chat/discourse/components/toggle-channel-membership-button";
|
||||
|
||||
|
@ -142,6 +144,14 @@ export default class ChatChannelRow extends Component {
|
|||
return this.args.channel.tracking.unreadCount > 0;
|
||||
}
|
||||
|
||||
get shouldRenderLastMessage() {
|
||||
return (
|
||||
this.site.mobileView &&
|
||||
this.args.channel.isDirectMessageChannel &&
|
||||
this.args.channel.lastMessage
|
||||
);
|
||||
}
|
||||
|
||||
get #firstDirectMessageUser() {
|
||||
return this.args.channel?.chatable?.users?.firstObject;
|
||||
}
|
||||
|
@ -177,6 +187,7 @@ export default class ChatChannelRow extends Component {
|
|||
<div
|
||||
class={{concatClass
|
||||
"chat-channel-row__content"
|
||||
(if @channel.isCategoryChannel "is-category" "is-dm")
|
||||
(if this.shouldReset "-animate-reset")
|
||||
}}
|
||||
{{(if this.shouldHandleSwipe (modifier this.registerSwipableRow))}}
|
||||
|
@ -184,8 +195,19 @@ export default class ChatChannelRow extends Component {
|
|||
{{(if this.shouldReset (modifier this.onReset))}}
|
||||
style={{this.rowStyle}}
|
||||
>
|
||||
<ChannelTitle @channel={{@channel}} />
|
||||
<ChatChannelMetadata @channel={{@channel}} @unreadIndicator={{true}} />
|
||||
<ChannelIcon @channel={{@channel}} />
|
||||
<div class="chat-channel-row__info">
|
||||
<ChannelName @channel={{@channel}} />
|
||||
<ChatChannelMetadata
|
||||
@channel={{@channel}}
|
||||
@unreadIndicator={{true}}
|
||||
/>
|
||||
{{#if this.shouldRenderLastMessage}}
|
||||
<div class="chat-channel__last-message">
|
||||
{{replaceEmoji (htmlSafe @channel.lastMessage.excerpt)}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if
|
||||
(and @options.leaveButton @channel.isFollowing this.site.desktopView)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
.chat-channel-icon {
|
||||
flex-shrink: 0;
|
||||
&.--users-count {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
background: rgba(var(--primary-rgb), 0.1);
|
||||
box-sizing: border-box;
|
||||
color: var(--primary-high);
|
||||
padding: 0;
|
||||
|
||||
.chat-channel-row & {
|
||||
width: var(--channel-list-avatar-size);
|
||||
height: var(--channel-list-avatar-size);
|
||||
font-size: var(--font-up-1);
|
||||
}
|
||||
}
|
||||
|
||||
&.--avatar {
|
||||
.chat-user-avatar {
|
||||
.avatar {
|
||||
.chat-channel-row & {
|
||||
width: var(--channel-list-avatar-size);
|
||||
height: var(--channel-list-avatar-size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.--category-badge {
|
||||
color: var(--primary-medium);
|
||||
display: flex;
|
||||
font-size: var(--font-up-1);
|
||||
position: relative;
|
||||
|
||||
.chat-message-creator & {
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&__restricted-category-icon {
|
||||
background-color: var(--secondary);
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
padding: 2px 2px 3px;
|
||||
color: var(--primary-high);
|
||||
height: 0.5rem;
|
||||
width: 0.5rem;
|
||||
right: -0.5rem;
|
||||
top: -0.1rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
.chat-channel-name {
|
||||
@include ellipsis;
|
||||
color: var(--primary);
|
||||
|
||||
.has-unread & {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&__label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
height: 1.2em;
|
||||
vertical-align: text-bottom;
|
||||
width: 1.2em;
|
||||
}
|
||||
}
|
|
@ -5,15 +5,7 @@
|
|||
justify-content: space-between;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: var(--primary-high);
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
max-width: 100%;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
color: var(--primary);
|
||||
|
||||
@media (hover: none) {
|
||||
&:hover,
|
||||
|
@ -41,7 +33,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.chat-channel-metadata {
|
||||
.chat-channel__metadata {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -49,55 +41,79 @@
|
|||
|
||||
&:hover,
|
||||
&.active {
|
||||
.chat-channel-title {
|
||||
&,
|
||||
.category-chat-name,
|
||||
.dm-usernames {
|
||||
color: var(--primary);
|
||||
}
|
||||
.chat-channel-name {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.d-icon-lock {
|
||||
background-color: var(--primary-low);
|
||||
}
|
||||
.d-icon-lock {
|
||||
background-color: var(--primary-low);
|
||||
}
|
||||
}
|
||||
|
||||
&:visited {
|
||||
color: var(--primary-high);
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
&.muted {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.chat-channel-title {
|
||||
&__content {
|
||||
display: flex;
|
||||
max-width: 100%;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
gap: 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__users-count {
|
||||
width: var(--channel-list-avatar-size);
|
||||
height: var(--channel-list-avatar-size);
|
||||
padding: 0;
|
||||
font-size: var(--font-up-1);
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
&__info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-channel {
|
||||
&__user-info,
|
||||
&__channel-info {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@include ellipsis;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
.chat-user-avatar {
|
||||
img {
|
||||
width: calc(var(--channel-list-avatar-size) - 2px);
|
||||
height: calc(var(--channel-list-avatar-size) - 2px);
|
||||
&__metadata {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
flex-direction: column;
|
||||
margin-left: 0.5em;
|
||||
|
||||
.chat-channel-unread-indicator {
|
||||
@include chat-unread-indicator;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
|
||||
&.-urgent {
|
||||
width: auto;
|
||||
height: auto;
|
||||
min-width: 0.6em;
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__user-info {
|
||||
@include ellipsis;
|
||||
}
|
||||
&__usernames {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
|
||||
&__metadata-date {
|
||||
color: var(--primary-high);
|
||||
font-size: var(--font-down-2);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.user-status-message {
|
||||
display: inline-block;
|
||||
font-size: var(--font-down-2);
|
||||
|
@ -109,35 +125,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.chat-channel-metadata {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
flex-direction: column;
|
||||
margin-left: 0.5em;
|
||||
|
||||
&__date {
|
||||
color: var(--primary-high);
|
||||
font-size: var(--font-down-2);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.chat-channel-unread-indicator {
|
||||
@include chat-unread-indicator;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
|
||||
&.-urgent {
|
||||
width: auto;
|
||||
height: auto;
|
||||
min-width: 0.6em;
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.unfollowing {
|
||||
opacity: 0;
|
||||
}
|
||||
|
@ -146,8 +133,4 @@
|
|||
display: none;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
margin-left: 0.3em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
.chat-channel-title {
|
||||
@include ellipsis;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@include ellipsis;
|
||||
gap: 0.5rem;
|
||||
|
||||
.chat-channel-preview-card & {
|
||||
max-width: 100%;
|
||||
|
@ -20,21 +21,6 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-name,
|
||||
.category-chat-name,
|
||||
&__usernames,
|
||||
.dm-usernames {
|
||||
@include ellipsis;
|
||||
font-size: var(--font-0);
|
||||
margin: 0;
|
||||
|
||||
.emoji {
|
||||
height: 1.2em;
|
||||
vertical-align: text-bottom;
|
||||
width: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.d-icon-lock {
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
|
@ -109,20 +95,3 @@
|
|||
width: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-channel-title__name {
|
||||
@include ellipsis;
|
||||
font-size: var(--font-0);
|
||||
color: var(--primary);
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.channel-info {
|
||||
.chat-channel-title__name {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.has-unread .chat-channel-title__name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
@import "chat-browse";
|
||||
@import "chat-channel";
|
||||
@import "chat-channel-card";
|
||||
@import "chat-channel-icon";
|
||||
@import "chat-channel-info";
|
||||
@import "chat-channel-name";
|
||||
@import "chat-channel-preview-card";
|
||||
@import "chat-channel-title";
|
||||
@import "chat-composer-dropdown";
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
:root {
|
||||
--channel-list-avatar-size: 43px;
|
||||
}
|
||||
.chat-channel-row {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
|
@ -5,8 +8,8 @@
|
|||
transition: height 0.25s ease-in-out, opacity 0.25s ease-out;
|
||||
transform-origin: top center;
|
||||
will-change: height, opacity, left;
|
||||
height: 4em;
|
||||
position: relative;
|
||||
height: 4em;
|
||||
|
||||
&.-fade-out {
|
||||
.chat-channel-row__content {
|
||||
|
@ -20,11 +23,13 @@
|
|||
|
||||
&__content {
|
||||
padding-inline: 1.5rem;
|
||||
padding-block: 0.5rem;
|
||||
z-index: 2;
|
||||
background: var(--primary-very-low);
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
transition: border-radius 0.25s ease-in-out;
|
||||
//for sliding delete animation
|
||||
background: var(--primary-very-low);
|
||||
height: 100%;
|
||||
|
||||
&.-animate-reset {
|
||||
transition: margin-right 0.15s ease-out;
|
||||
|
@ -36,6 +41,28 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
.is-category & {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.is-dm & {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"name metadata"
|
||||
"msg msg";
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
&:has(.chat-channel-unread-indicator) {
|
||||
grid-template-areas:
|
||||
"name metadata"
|
||||
"msg metadata";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__action-btn {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
|
@ -69,13 +96,32 @@
|
|||
}
|
||||
}
|
||||
|
||||
.chat-channel-metadata {
|
||||
.chat-channel-unread-indicator {
|
||||
font-size: var(--font-down-2);
|
||||
margin-top: 0.25rem;
|
||||
.chat-channel {
|
||||
&__user-info,
|
||||
&__channel-info {
|
||||
grid-area: name;
|
||||
}
|
||||
&__date {
|
||||
&__metadata {
|
||||
grid-area: metadata;
|
||||
.chat-channel-unread-indicator {
|
||||
font-size: var(--font-down-2);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
&__metadata-date {
|
||||
font-size: var(--font-down-2);
|
||||
}
|
||||
&__last-message {
|
||||
@include ellipsis;
|
||||
grid-area: msg;
|
||||
font-size: var(--font-down-1-rem);
|
||||
color: var(--primary-high);
|
||||
}
|
||||
}
|
||||
|
||||
.chat-channel-icon {
|
||||
&.--users-count {
|
||||
font-size: var(--font-up-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||
expect(page.find(".c-channel-settings__name")["innerHTML"].strip).to eq(
|
||||
"<script>alert('hello')</script>",
|
||||
)
|
||||
expect(page.find(".chat-channel-title__name")["innerHTML"].strip).to eq(
|
||||
expect(page.find(".chat-channel-name__label")["innerHTML"].strip).to eq(
|
||||
"<script>alert('hello')</script>",
|
||||
)
|
||||
end
|
||||
|
|
|
@ -15,6 +15,20 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
|
|||
context "when category channels" do
|
||||
fab!(:category_channel_1) { Fabricate(:category_channel) }
|
||||
|
||||
it "doesn’t show the last message" do
|
||||
message =
|
||||
Fabricate(
|
||||
:chat_message,
|
||||
chat_channel: category_channel_1,
|
||||
user: current_user,
|
||||
use_service: true,
|
||||
)
|
||||
|
||||
visit("/chat/direct-messages")
|
||||
|
||||
expect(page).to have_no_selector(".chat-channel__last-message", text: message.message)
|
||||
end
|
||||
|
||||
context "when member of the channel" do
|
||||
before { category_channel_1.add(current_user) }
|
||||
|
||||
|
@ -61,6 +75,20 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
|
|||
fab!(:dm_channel_1) { Fabricate(:direct_message_channel, users: [current_user]) }
|
||||
fab!(:inaccessible_dm_channel_1) { Fabricate(:direct_message_channel) }
|
||||
|
||||
it "show the last message" do
|
||||
message =
|
||||
Fabricate(
|
||||
:chat_message,
|
||||
chat_channel: dm_channel_1,
|
||||
user: current_user,
|
||||
use_service: true,
|
||||
)
|
||||
|
||||
visit("/chat/direct-messages")
|
||||
|
||||
expect(page).to have_selector(".chat-channel__last-message", text: message.message)
|
||||
end
|
||||
|
||||
context "when member of the channel" do
|
||||
it "shows the channel in the correct section" do
|
||||
visit("/chat/direct-messages")
|
||||
|
@ -80,6 +108,7 @@ RSpec.describe "List channels | mobile", type: :system, mobile: true do
|
|||
context "when no category channels" do
|
||||
it "hides the section" do
|
||||
visit("/chat/channels")
|
||||
|
||||
expect(page).to have_no_css(".channels-list-container")
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import { render } from "@ember/test-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import ChannelIcon from "discourse/plugins/chat/discourse/components/channel-icon";
|
||||
import fabricators from "discourse/plugins/chat/discourse/lib/fabricators";
|
||||
import { CHATABLE_TYPES } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
|
||||
module("Discourse Chat | Component | <ChannelIcon />", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("category channel - badge", async function (assert) {
|
||||
const channel = fabricators.channel();
|
||||
|
||||
await render(<template><ChannelIcon @channel={{channel}} /></template>);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-channel-icon.--category-badge").getAttribute("style"),
|
||||
`color: #${channel.chatable.color}`
|
||||
);
|
||||
});
|
||||
|
||||
test("category channel - escapes label", async function (assert) {
|
||||
const channel = fabricators.channel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
title: "<div class='xss'>evil</div>",
|
||||
});
|
||||
|
||||
await render(<template><ChannelIcon @channel={{channel}} /></template>);
|
||||
|
||||
assert.false(exists(".xss"));
|
||||
});
|
||||
|
||||
test("category channel - read restricted", async function (assert) {
|
||||
const channel = fabricators.channel({
|
||||
chatable: fabricators.category({ read_restricted: true }),
|
||||
});
|
||||
|
||||
await render(<template><ChannelIcon @channel={{channel}} /></template>);
|
||||
|
||||
assert.true(exists(".d-icon-lock"));
|
||||
});
|
||||
|
||||
test("category channel - not read restricted", async function (assert) {
|
||||
const channel = fabricators.channel({
|
||||
chatable: fabricators.category({ read_restricted: false }),
|
||||
});
|
||||
|
||||
await render(<template><ChannelIcon @channel={{channel}} /></template>);
|
||||
|
||||
assert.false(exists(".d-icon-lock"));
|
||||
});
|
||||
|
||||
test("dm channel - one user", async function (assert) {
|
||||
const channel = fabricators.directMessageChannel({
|
||||
chatable: fabricators.directMessage({
|
||||
users: [fabricators.user()],
|
||||
}),
|
||||
});
|
||||
const user = channel.chatable.users[0];
|
||||
|
||||
await render(<template><ChannelIcon @channel={{channel}} /></template>);
|
||||
|
||||
assert.true(exists(`.chat-user-avatar .avatar[title="${user.username}"]`));
|
||||
});
|
||||
|
||||
test("dm channel - multiple users", async function (assert) {
|
||||
const channel = fabricators.directMessageChannel({
|
||||
users: [fabricators.user(), fabricators.user(), fabricators.user()],
|
||||
});
|
||||
channel.chatable.group = true;
|
||||
const users = channel.chatable.users;
|
||||
|
||||
await render(<template><ChannelIcon @channel={{channel}} /></template>);
|
||||
|
||||
assert.strictEqual(
|
||||
parseInt(query(".chat-channel-icon.--users-count").innerText.trim(), 10),
|
||||
users.length
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,63 @@
|
|||
import { render } from "@ember/test-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import ChannelName from "discourse/plugins/chat/discourse/components/channel-name";
|
||||
import fabricators from "discourse/plugins/chat/discourse/lib/fabricators";
|
||||
import { CHATABLE_TYPES } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
|
||||
const CHANNEL_NAME_LABEL = ".chat-channel-name__label";
|
||||
|
||||
module("Discourse Chat | Component | <ChannelName />", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("category channel - label", async function (assert) {
|
||||
const channel = fabricators.channel();
|
||||
|
||||
await render(<template><ChannelName @channel={{channel}} /></template>);
|
||||
|
||||
assert.strictEqual(query(CHANNEL_NAME_LABEL).innerText, channel.title);
|
||||
});
|
||||
|
||||
test("category channel - escapes label", async function (assert) {
|
||||
const channel = fabricators.channel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
title: "<div class='xss'>evil</div>",
|
||||
});
|
||||
|
||||
await render(<template><ChannelName @channel={{channel}} /></template>);
|
||||
|
||||
assert.false(exists(".xss"));
|
||||
});
|
||||
|
||||
test("dm channel - one user", async function (assert) {
|
||||
const channel = fabricators.directMessageChannel({
|
||||
chatable: fabricators.directMessage({
|
||||
users: [fabricators.user()],
|
||||
}),
|
||||
});
|
||||
const user = channel.chatable.users[0];
|
||||
|
||||
await render(<template><ChannelName @channel={{channel}} /></template>);
|
||||
|
||||
assert.strictEqual(
|
||||
query(CHANNEL_NAME_LABEL).innerText.trim(),
|
||||
user.username
|
||||
);
|
||||
});
|
||||
|
||||
test("dm channel - multiple users", async function (assert) {
|
||||
const channel = fabricators.directMessageChannel({
|
||||
users: [fabricators.user(), fabricators.user(), fabricators.user()],
|
||||
});
|
||||
channel.chatable.group = true;
|
||||
const users = channel.chatable.users;
|
||||
|
||||
await render(<template><ChannelName @channel={{channel}} /></template>);
|
||||
|
||||
assert.strictEqual(
|
||||
query(CHANNEL_NAME_LABEL).innerText.trim(),
|
||||
users.mapBy("username").join(", ")
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
import { render } from "@ember/test-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import ChannelTitle from "discourse/plugins/chat/discourse/components/channel-title";
|
||||
import fabricators from "discourse/plugins/chat/discourse/lib/fabricators";
|
||||
|
||||
module("Discourse Chat | Component | <ChannelTitle />", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("icon", async function (assert) {
|
||||
const channel = fabricators.channel();
|
||||
|
||||
await render(<template><ChannelTitle @channel={{channel}} /></template>);
|
||||
|
||||
assert.dom(".chat-channel-icon").exists();
|
||||
});
|
||||
|
||||
test("label", async function (assert) {
|
||||
const channel = fabricators.channel();
|
||||
|
||||
await render(<template><ChannelTitle @channel={{channel}} /></template>);
|
||||
|
||||
assert.dom(".chat-channel-name").exists();
|
||||
});
|
||||
});
|
|
@ -1,95 +0,0 @@
|
|||
import { render } from "@ember/test-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import fabricators from "discourse/plugins/chat/discourse/lib/fabricators";
|
||||
import { CHATABLE_TYPES } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
|
||||
module("Discourse Chat | Component | <ChannelTitle />", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("category channel", async function (assert) {
|
||||
this.channel = fabricators.channel();
|
||||
|
||||
await render(hbs`<ChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-channel-title__category-badge").getAttribute("style"),
|
||||
`color: #${this.channel.chatable.color}`
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".chat-channel-title__name").innerText,
|
||||
this.channel.title
|
||||
);
|
||||
});
|
||||
|
||||
test("category channel - escapes title", async function (assert) {
|
||||
this.channel = fabricators.channel({
|
||||
chatable_type: CHATABLE_TYPES.categoryChannel,
|
||||
title: "<div class='xss'>evil</div>",
|
||||
});
|
||||
|
||||
await render(hbs`<ChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
assert.false(exists(".xss"));
|
||||
});
|
||||
|
||||
test("category channel - read restricted", async function (assert) {
|
||||
this.channel = fabricators.channel({
|
||||
chatable: fabricators.category({ read_restricted: true }),
|
||||
});
|
||||
|
||||
await render(hbs`<ChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
assert.true(exists(".d-icon-lock"));
|
||||
});
|
||||
|
||||
test("category channel - not read restricted", async function (assert) {
|
||||
this.channel = fabricators.channel({
|
||||
chatable: fabricators.category({ read_restricted: false }),
|
||||
});
|
||||
|
||||
await render(hbs`<ChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
assert.false(exists(".d-icon-lock"));
|
||||
});
|
||||
|
||||
test("direct message channel - one user", async function (assert) {
|
||||
this.channel = fabricators.directMessageChannel({
|
||||
chatable: fabricators.directMessage({
|
||||
users: [fabricators.user()],
|
||||
}),
|
||||
});
|
||||
|
||||
await render(hbs`<ChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
const user = this.channel.chatable.users[0];
|
||||
|
||||
assert.true(exists(`.chat-user-avatar .avatar[title="${user.username}"]`));
|
||||
assert.strictEqual(
|
||||
query(".chat-channel-title__name").innerText.trim(),
|
||||
user.username
|
||||
);
|
||||
});
|
||||
|
||||
test("direct message channel - multiple users", async function (assert) {
|
||||
this.channel = fabricators.directMessageChannel({
|
||||
users: [fabricators.user(), fabricators.user(), fabricators.user()],
|
||||
});
|
||||
this.channel.chatable.group = true;
|
||||
|
||||
await render(hbs`<ChannelTitle @channel={{this.channel}} />`);
|
||||
|
||||
const users = this.channel.chatable.users;
|
||||
|
||||
assert.strictEqual(
|
||||
parseInt(query(".chat-channel-title__users-count").innerText.trim(), 10),
|
||||
users.length
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".chat-channel-title__name").innerText.trim(),
|
||||
users.mapBy("username").join(", ")
|
||||
);
|
||||
});
|
||||
});
|
|
@ -18,14 +18,14 @@ module("Discourse Chat | Component | chat-channel-metadata", function (hooks) {
|
|||
|
||||
await render(hbs`<ChatChannelMetadata @channel={{this.channel}} />`);
|
||||
|
||||
assert.dom(".chat-channel-metadata__date").hasText("Yesterday");
|
||||
assert.dom(".chat-channel__metadata-date").hasText("Yesterday");
|
||||
|
||||
lastMessageSentAt = moment();
|
||||
this.channel.lastMessage.createdAt = lastMessageSentAt;
|
||||
await render(hbs`<ChatChannelMetadata @channel={{this.channel}} />`);
|
||||
|
||||
assert
|
||||
.dom(".chat-channel-metadata__date")
|
||||
.dom(".chat-channel__metadata-date")
|
||||
.hasText(lastMessageSentAt.format("LT"));
|
||||
});
|
||||
|
||||
|
|
|
@ -24,13 +24,13 @@ module(
|
|||
await render(hbs`<ChatChannelPreviewCard @channel={{this.channel}} />`);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-channel-title__name").innerText,
|
||||
query(".chat-channel-name__label").innerText,
|
||||
this.channel.title,
|
||||
"it shows the channel title"
|
||||
);
|
||||
|
||||
assert.true(
|
||||
exists(query(".chat-channel-title__category-badge")),
|
||||
exists(query(".chat-channel-icon.--category-badge")),
|
||||
"it shows the category hashtag badge"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -43,7 +43,9 @@ module("Discourse Chat | Component | chat-channel-row", function (hooks) {
|
|||
test("renders correct channel title", async function (assert) {
|
||||
await render(hbs`<ChatChannelRow @channel={{this.categoryChatChannel}} />`);
|
||||
|
||||
assert.dom(".chat-channel-title").hasText(this.categoryChatChannel.title);
|
||||
assert
|
||||
.dom(".chat-channel-name__label")
|
||||
.hasText(this.categoryChatChannel.title);
|
||||
});
|
||||
|
||||
test("renders correct channel metadata", async function (assert) {
|
||||
|
@ -53,7 +55,7 @@ module("Discourse Chat | Component | chat-channel-row", function (hooks) {
|
|||
await render(hbs`<ChatChannelRow @channel={{this.categoryChatChannel}} />`);
|
||||
|
||||
assert
|
||||
.dom(".chat-channel-metadata")
|
||||
.dom(".chat-channel__metadata-date")
|
||||
.hasText(
|
||||
moment(this.categoryChatChannel.lastMessage.createdAt).format("h:mm A")
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue